URLSegmentExtension::AbsoluteLink()   A
last analyzed

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());
0 ignored issues
show
Bug Best Practice introduced by
The expression return SilverStripe\Cont...oluteURL($this->Link()) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
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