Passed
Push — master ( a07925...935799 )
by Thomas
02:44
created

URLSegmentExtension::AbsoluteLink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 1
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace LeKoala\CommonExtensions;
4
5
use SilverStripe\Control\Director;
6
use SilverStripe\ORM\DataObject;
7
use SilverStripe\Forms\FieldList;
8
use SilverStripe\ORM\DataExtension;
9
use SilverStripe\ORM\ValidationResult;
10
use SilverStripe\View\Parsers\URLSegmentFilter;
11
12
/**
13
 * URL Segment extension
14
 *
15
 * By default link will be applied WITHOUT actions
16
 *
17
 * @property DataObject $owner
18
 * @property string $URLSegment
19
 */
20
class URLSegmentExtension extends DataExtension
21
{
22
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
23
        "URLSegment" => "Varchar(191)",
24
    ];
25
    private static $indexes = [
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
26
        "URLSegmentUnique" => [
27
            "type" => "unique",
28
            "columns" => ["URLSegment"]
29
        ],
30
    ];
31
32
    /**
33
     * Get a class by URLSegment
34
     *
35
     * @param string $class
36
     * @param string $URLSegment
37
     * @return DataObject
38
     */
39
    public static function getByURLSegment($class, $URLSegment)
40
    {
41
        return $class::get()->filter('URLSegment', $URLSegment)->first();
42
    }
43
44
    public function updateCMSFields(FieldList $fields)
45
    {
46
        $URLSegment = $fields->dataFieldByName('URLSegment');
47
        if ($URLSegment) {
48
            $URLSegment->setTitle(_t('URLSegmentExtension.URLSEGMENT', 'URL Segment'));
49
50
            $Title = $fields->dataFieldByName('Title');
51
            if ($Title) {
52
                $fields->insertAfter('Title', $URLSegment);
53
            }
54
        }
55
    }
56
57
    /**
58
     * @return boolean
59
     */
60
    public function isSearchable()
61
    {
62
        return $this->owner->hasMethod('Page');
63
    }
64
65
    /**
66
     * We have this link method by default that allows us to define
67
     * a link for this record
68
     *
69
     * You can define your own methods in your DataObject class
70
     *
71
     * @param string $action
72
     * @return string
73
     */
74
    public function Link($action = null)
75
    {
76
        $url = $this->owner->Page()->Link($this->owner->URLSegment);
77
        if ($action) {
78
            $url .= "/$action";
79
        }
80
        return $url;
81
    }
82
83
    /**
84
     * @return string
85
     */
86
    public function AbsoluteLink()
87
    {
88
        return Director::absoluteURL($this->Link());
89
    }
90
91
    /**
92
     * Cannot use the same url segment
93
     *
94
     * @param ValidationResult $validationResult
95
     * @return void
96
     */
97
    public function validate(ValidationResult $validationResult)
98
    {
99
        $duplicate = $this->getDuplicateRecord();
100
        if ($duplicate) {
0 ignored issues
show
introduced by
$duplicate is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
101
            $validationResult->addFieldError("URLSegment", "Segment already used by record #" . $duplicate->ID);
102
        }
103
    }
104
105
    /**
106
     * Find another record with the same url segment
107
     *
108
     * @param string $segment
109
     * @return DataObject
110
     */
111
    public function getDuplicateRecord($segment = null)
112
    {
113
        if ($segment === null) {
114
            $segment = $this->owner->URLSegment;
115
        }
116
        if (!$segment) {
117
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type SilverStripe\ORM\DataObject.
Loading history...
118
        }
119
        $class = get_class($this->owner);
120
        return $class::get()->exclude('ID', $this->owner->ID)->filter("URLSegment", $segment)->first();
121
    }
122
123
    /**
124
     * This method allows you to customize url segment generation
125
     *
126
     * By default, URL segment is based on page title
127
     *
128
     * @return string
129
     */
130
    public function getBaseURLSegment()
131
    {
132
        $segment = $this->owner->getTitle();
133
        if ($this->owner->hasMethod('updateURLSegment')) {
134
            $this->owner->updateURLSegment($segment);
135
        }
136
        $filter = new URLSegmentFilter();
137
        $baseSegment = $filter->filter($segment);
138
        if (is_numeric($baseSegment)) {
139
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
140
        }
141
        return $baseSegment;
142
    }
143
144
    /**
145
     * Generate a new url segment and checks for duplicates
146
     *
147
     * @return string
148
     */
149
    public function generateURLSegment()
150
    {
151
        $baseSegment = $segment = $this->getBaseURLSegment();
152
        if (!$baseSegment) {
153
            return;
154
        }
155
        $duplicate = $this->getDuplicateRecord($segment);
156
        $i = 0;
157
        while ($duplicate) {
158
            $i++;
159
            $segment = $baseSegment . '-' . $i;
160
            $duplicate = $this->getDuplicateRecord($segment);
161
        }
162
        return $segment;
163
    }
164
165
    public function onBeforeWrite()
166
    {
167
        // Generate segment if no segment
168
        if (!$this->owner->URLSegment && $this->getBaseURLSegment()) {
169
            $this->owner->URLSegment = $this->generateURLSegment();
170
        }
171
    }
172
}
173