Passed
Pull Request — master (#135)
by Robbie
02:01
created

BaseElement::setController()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 5
rs 9.4285
c 1
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace DNADesign\Elemental\Models;
4
5
use Exception;
6
use DNADesign\Elemental\Controllers\ElementController;
7
use SilverStripe\CMS\Controllers\CMSPageEditController;
8
use SilverStripe\Control\Controller;
9
use SilverStripe\Control\Director;
10
use SilverStripe\Core\ClassInfo;
11
use SilverStripe\Core\Config\Config;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Core\Manifest\ModuleResourceLoader;
14
use SilverStripe\Forms\CheckboxField;
15
use SilverStripe\Forms\DropdownField;
16
use SilverStripe\Forms\FieldGroup;
17
use SilverStripe\Forms\FieldList;
18
use SilverStripe\Forms\HiddenField;
19
use SilverStripe\Forms\NumericField;
20
use SilverStripe\Forms\ReadonlyField;
21
use SilverStripe\Forms\TextField;
22
use SilverStripe\ORM\ArrayList;
23
use SilverStripe\ORM\CMSPreviewable;
24
use SilverStripe\ORM\DataObject;
25
use SilverStripe\ORM\DB;
26
use SilverStripe\ORM\FieldType\DBField;
27
use SilverStripe\ORM\Search\SearchContext;
28
use SilverStripe\Security\Permission;
29
use SilverStripe\SiteConfig\SiteConfig;
30
use SilverStripe\Versioned\Versioned;
31
use SilverStripe\View\Parsers\URLSegmentFilter;
32
use SilverStripe\View\SSViewer;
33
use VersionViewerDataObject;
0 ignored issues
show
Bug introduced by
The type VersionViewerDataObject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
35
class BaseElement extends DataObject implements CMSPreviewable
36
{
37
    /**
38
     * Override this on your custom elements to specify a cms icon
39
     * @var string
40
     */
41
    private static $icon = 'dnadesign/silverstripe-elemental:images/base.svg';
0 ignored issues
show
Unused Code introduced by
The property $icon is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
42
43
    /**
44
     * Describe the purpose of this element
45
     *
46
     * @config
47
     * @var string
48
     */
49
    private static $description = 'Base element class';
0 ignored issues
show
Unused Code introduced by
The property $description is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
50
51
    private static $db = [
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
52
        'Title' => 'Varchar(255)',
53
        'ShowTitle' => 'Boolean',
54
        'Sort' => 'Int',
55
        'ExtraClass' => 'Varchar(255)'
56
    ];
57
58
    private static $has_one = [
0 ignored issues
show
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
59
        'Parent' => ElementalArea::class
60
    ];
61
62
    private static $extensions = [
0 ignored issues
show
Unused Code introduced by
The property $extensions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
63
        Versioned::class
64
    ];
65
66
    private static $table_name = 'Element';
0 ignored issues
show
Unused Code introduced by
The property $table_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
67
68
    /**
69
     * @var string
70
     */
71
    private static $controller_class = ElementController::class;
0 ignored issues
show
Unused Code introduced by
The property $controller_class is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
72
73
    /**
74
     * @var string
75
     */
76
    private static $controller_template = 'ElementHolder';
0 ignored issues
show
Unused Code introduced by
The property $controller_template is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
77
78
    /**
79
     * @var ElementController
80
     */
81
    protected $controller;
82
83
    private static $default_sort = 'Sort';
0 ignored issues
show
Unused Code introduced by
The property $default_sort is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
84
85
    private static $singular_name = 'block';
0 ignored issues
show
Unused Code introduced by
The property $singular_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
86
87
    private static $plural_name = 'blocks';
0 ignored issues
show
Unused Code introduced by
The property $plural_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
88
89
    private static $summary_fields = [
0 ignored issues
show
Unused Code introduced by
The property $summary_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
90
        'EditorPreview' => 'Summary'
91
    ];
92
93
    private static $searchable_fields = [
0 ignored issues
show
Unused Code introduced by
The property $searchable_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
94
        'ID' => [
95
            'field' => NumericField::class,
96
        ],
97
        'Title',
98
        'LastEdited'
99
    ];
100
101
    /**
102
     * Enable for backwards compatibility
103
     *
104
     * @var boolean
105
     */
106
    private static $disable_pretty_anchor_name = false;
0 ignored issues
show
Unused Code introduced by
The property $disable_pretty_anchor_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
107
108
    /**
109
     * Store used anchor names, this is to avoid title clashes
110
     * when calling 'getAnchor'
111
     *
112
     * @var array
113
     */
114
    protected static $_used_anchors = [];
115
116
    /**
117
     * For caching 'getAnchor'
118
     *
119
     * @var string
120
     */
121
    protected $_anchor = null;
122
123
    /**
124
     * @return array
125
     */
126
    public function getAllowedElementClasses()
127
    {
128
        $classes = [];
129
130
        foreach (ClassInfo::subclassesFor(DataObject::class) as $className) {
131
            if (Injector::inst()->get($className)->hasExtension(ElementPageExtension::class)) {
0 ignored issues
show
Bug introduced by
The type DNADesign\Elemental\Models\ElementPageExtension was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
132
                $classes[] = $className;
133
            }
134
        }
135
136
        $allowed = [];
137
138
        foreach ($classes as $className) {
139
            $elements = Config::inst()->get($className, 'allowed_elements');
140
141
            if ($elements) {
142
                $allowed = array_merge($allowed, $elements);
143
            }
144
        }
145
146
        $allowed = array_unique($allowed);
147
148
        $elements = [];
149
150
        foreach ($allowed as $className) {
151
            $elements[$className] = _t($className, Config::inst()->get($className, 'title'));
152
        }
153
154
        $this->invokeWithExtensions('updateAllowedElementClasses', $elements);
155
156
        return $elements;
157
    }
158
159
    /**
160
     * Basic permissions, defaults to page perms where possible.
161
     *
162
     * @param Member $member
0 ignored issues
show
Bug introduced by
The type DNADesign\Elemental\Models\Member was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
163
     *
164
     * @return boolean
165
     */
166 View Code Duplication
    public function canView($member = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
167
    {
168
        if ($this->hasMethod('getPage')) {
169
            if ($page = $this->getPage()) {
170
                return $page->canView($member);
171
            }
172
        }
173
174
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
175
    }
176
177
    /**
178
     * Basic permissions, defaults to page perms where possible.
179
     *
180
     * @param Member $member
181
     *
182
     * @return boolean
183
     */
184 View Code Duplication
    public function canEdit($member = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
185
    {
186
        if ($this->hasMethod('getPage')) {
187
            if ($page = $this->getPage()) {
188
                return $page->canEdit($member);
189
            }
190
        }
191
192
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
193
    }
194
195
    /**
196
     * Basic permissions, defaults to page perms where possible.
197
     *
198
     * Uses archive not delete so that current stage is respected i.e if a
199
     * element is not published, then it can be deleted by someone who doesn't
200
     * have publishing permissions.
201
     *
202
     * @param Member $member
203
     *
204
     * @return boolean
205
     */
206 View Code Duplication
    public function canDelete($member = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
207
    {
208
        if ($this->hasMethod('getPage')) {
209
            if ($page = $this->getPage()) {
210
                return $page->canArchive($member);
211
            }
212
        }
213
214
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
215
    }
216
217
    /**
218
     * Basic permissions, defaults to page perms where possible.
219
     *
220
     * @param Member $member
221
     * @param array $context
222
     *
223
     * @return boolean
224
     */
225
    public function canCreate($member = null, $context = array())
226
    {
227
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
228
    }
229
230
    /**
231
     *
232
     */
233
    public function onBeforeWrite()
234
    {
235
        parent::onBeforeWrite();
236
237
        if ($areaID = $this->ParentID) {
0 ignored issues
show
Bug Best Practice introduced by
The property ParentID does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
238
            if ($elementalArea = ElementalArea::get()->byID($areaID)) {
239
                $elementalArea->write();
240
            }
241
        }
242
243
        if (!$this->Sort) {
244
            $parentID = ($this->ParentID) ? $this->ParentID : 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $parentID is dead and can be removed.
Loading history...
245
246
            $this->Sort = static::get()->max('Sort') + 1;
0 ignored issues
show
Bug Best Practice introduced by
The property Sort does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
247
        }
248
    }
249
250
    public function getCMSFields()
251
    {
252
        $this->beforeUpdateCMSFields(function (FieldList $fields) {
253
            // Remove relationship fields
254
            $fields->removeByName('ParentID');
255
            $fields->removeByName('Sort');
256
257
            $fields->addFieldToTab(
258
                'Root.Settings',
259
                TextField::create('ExtraClass', _t(__CLASS__ . '.ExtraCssClassesLabel', 'Custom CSS classes'))
0 ignored issues
show
Bug introduced by
'ExtraClass' of type string is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

259
                TextField::create(/** @scrutinizer ignore-type */ 'ExtraClass', _t(__CLASS__ . '.ExtraCssClassesLabel', 'Custom CSS classes'))
Loading history...
260
                    ->setAttribute(
261
                        'placeholder',
262
                        _t(__CLASS__ . '.ExtraCssClassesPlaceholder', 'my_class another_class')
263
                    )
264
            );
265
266
            // Add a combined field for "Title" and "Displayed" checkbox in a Bootstrap input group
267
            $fields->removeByName('ShowTitle');
268
            $fields->replaceField(
269
                'Title',
270
                FieldGroup::create(
271
                    TextField::create('Title', ''),
272
                    CheckboxField::create('ShowTitle', _t(__CLASS__ . '.ShowTitleLabel', 'Displayed'))
273
                )
274
                    ->setName('TitleAndDisplayed')
275
                    ->setTemplate(__CLASS__ . '\\FieldGroup')
276
                    ->setTitle(_t(__CLASS__ . '.TitleLabel', 'Title (not displayed unless specified)'))
277
            );
278
279
            // Rename the "Main" tab
280
            $fields->fieldByName('Root.Main')
281
                ->setTitle(_t(__CLASS__ . '.MainTabLabel', 'Content'));
282
283
            // Remove divider lines on all block forms
284
            $fields->fieldByName('Root')->addExtraClass('form--no-dividers');
285
286
            if ($this->isInDB()) {
287
                if ($this->hasExtension(VersionViewerDataObject::class)) {
288
                    $fields = $this->addVersionViewer($fields, $this);
0 ignored issues
show
Bug introduced by
The method addVersionViewer() does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

288
                    /** @scrutinizer ignore-call */ 
289
                    $fields = $this->addVersionViewer($fields, $this);
Loading history...
289
                }
290
            }
291
292
            $fields->addFieldsToTab('Root.Main', [
293
                HiddenField::create('AbsoluteLink', false, Director::absoluteURL($this->PreviewLink())),
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

293
                HiddenField::create('AbsoluteLink', /** @scrutinizer ignore-type */ false, Director::absoluteURL($this->PreviewLink())),
Loading history...
294
                HiddenField::create('LiveLink', false, Director::absoluteURL($this->Link())),
295
                HiddenField::create('StageLink', false, Director::absoluteURL($this->PreviewLink())),
296
            ]);
297
        });
298
299
        return parent::getCMSFields();
300
    }
301
302
    /**
303
     * Used in ElementalAdmin
304
     */
305
    public function getDefaultSearchContext()
306
    {
307
        $fields = $this->scaffoldSearchFields();
308
        $elements = BaseElement::all_allowed_elements();
0 ignored issues
show
introduced by
The method all_allowed_elements() does not exist on DNADesign\Elemental\Models\BaseElement. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

308
        /** @scrutinizer ignore-call */ 
309
        $elements = BaseElement::all_allowed_elements();
Loading history...
309
310
        if (!$elements) {
311
            $elements = ClassInfo::subclassesFor(self::class);
312
        }
313
        foreach ($elements as $key => $value) {
314
            if ($key == self::class) {
315
                unset($elements[$key]);
316
                continue;
317
            }
318
            $elements[$key] = $this->stripNamespacing($value);
319
        }
320
321
        $fields->push(
322
            DropdownField::create('ClassName', _t(__CLASS__.'.ELEMENTTYPE', 'Element Type'), $elements)
0 ignored issues
show
Bug introduced by
'ClassName' of type string is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

322
            DropdownField::create(/** @scrutinizer ignore-type */ 'ClassName', _t(__CLASS__.'.ELEMENTTYPE', 'Element Type'), $elements)
Loading history...
323
                ->setEmptyString(_t(__CLASS__.'.ALL', 'All types'))
324
        );
325
326
        $filters = $this->owner->defaultSearchFilters();
0 ignored issues
show
Bug Best Practice introduced by
The property owner does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug introduced by
The method defaultSearchFilters() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

326
        /** @scrutinizer ignore-call */ 
327
        $filters = $this->owner->defaultSearchFilters();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
327
328
        return new SearchContext(
329
            self::class,
330
            $fields,
331
            $filters
332
        );
333
    }
334
335
    /**
336
     * Get the type of the current block, for use in GridField summaries, block type dropdowns etc. Examples
337
     * are "Content", "File", "Media", etc.
338
     *
339
     * @return string
340
     */
341
    public function getType()
342
    {
343
        return _t(__CLASS__ . '.BlockType', 'Block');
344
    }
345
346
    /**
347
     * @param ElementController
348
     *
349
     * @return $this
350
     */
351
    public function setController($controller)
352
    {
353
        $this->controller = $controller;
354
355
        return $this;
356
    }
357
358
    /**
359
     * @throws Exception
360
     *
361
     * @return ElementController
362
     */
363
    public function getController()
364
    {
365
        if ($this->controller) {
366
            return $this->controller;
367
        }
368
369
        $controllerClass = self::config()->controller_class;
370
371
        if (!class_exists($controllerClass)) {
372
            throw new Exception('Could not find controller class ' . $controllerClass . ' as defined in ' . static::class);
373
        }
374
375
        $this->controller = Injector::inst()->create($controllerClass, $this);
376
        $this->controller->doInit();
377
        return $this->controller;
378
    }
379
380
    /**
381
     * @return Controller
382
     */
383
    public function Top()
384
    {
385
        return (Controller::has_curr()) ? Controller::curr() : null;
386
    }
387
388
    /**
389
     * Default way to render element in templates. Note that all blocks should
390
     * be rendered through their {@link ElementController} class as this
391
     * contains the holder styles.
392
     *
393
     * @return string HTML
394
     */
395
    public function forTemplate($holder = true)
0 ignored issues
show
Unused Code introduced by
The parameter $holder is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

395
    public function forTemplate(/** @scrutinizer ignore-unused */ $holder = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
396
    {
397
        $templates = $this->getRenderTemplates();
398
399
        if ($templates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $templates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
400
            return $this->renderWith($templates);
401
        }
402
    }
403
404
    /**
405
     * @param string $suffix
406
     *
407
     * @return array
408
     */
409
    public function getRenderTemplates($suffix = '')
410
    {
411
        $classes = ClassInfo::ancestry($this->ClassName);
412
        $classes[static::class] = static::class;
413
        $classes = array_reverse($classes);
414
        $templates = array();
415
416
        foreach ($classes as $key => $value) {
417
            if ($value == BaseElement::class) {
418
                continue;
419
            }
420
421
            if ($value == DataObject::class) {
422
                break;
423
            }
424
425
            $templates[] = $value . $suffix;
426
        }
427
428
        return $templates;
429
    }
430
431
    /**
432
     * Strip all namespaces from class namespace
433
     * @param string $classname e.g. "\Fully\Namespaced\Class"
434
     *
435
     * @return string following the param example, "Class"
436
     */
437
    protected function stripNamespacing($classname)
438
    {
439
        $classParts = explode('\\', $classname);
440
        return array_pop($classParts);
441
    }
442
443
    /**
444
     * @return string
445
     */
446
    public function getSimpleClassName()
447
    {
448
        return strtolower($this->sanitiseClassName($this->ClassName, '__'));
449
    }
450
451
    /**
452
     * @return SiteTree
0 ignored issues
show
Bug introduced by
The type DNADesign\Elemental\Models\SiteTree was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
453
     */
454
    public function getPage()
455
    {
456
        $area = $this->Parent();
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

456
        /** @scrutinizer ignore-call */ 
457
        $area = $this->Parent();
Loading history...
457
458
        if ($area instanceof ElementalArea && $area->exists()) {
459
            return $area->getOwnerPage();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $area->getOwnerPage() could also return false which is incompatible with the documented return type DNADesign\Elemental\Models\SiteTree. 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...
460
        }
461
462
        return null;
463
    }
464
465
    /**
466
     * Get a unique anchor name
467
     *
468
     * @return string
469
     */
470
    public function getAnchor()
471
    {
472
        if ($this->_anchor !== null) {
473
            return $this->_anchor;
474
        }
475
476
        $anchorTitle = '';
477
478
        if (!$this->config()->disable_pretty_anchor_name) {
479
            if ($this->hasMethod('getAnchorTitle')) {
480
                $anchorTitle = $this->getAnchorTitle();
481
            } elseif ($this->config()->enable_title_in_template) {
482
                $anchorTitle = $this->getField('Title');
483
            }
484
        }
485
486
        if (!$anchorTitle) {
487
            $anchorTitle = 'e'.$this->ID;
488
        }
489
490
        $filter = URLSegmentFilter::create();
491
        $titleAsURL = $filter->filter($anchorTitle);
492
493
        // Ensure that this anchor name isn't already in use
494
        // ie. If two elemental blocks have the same title, it'll append '-2', '-3'
495
        $result = $titleAsURL;
496
        $count = 1;
497
        while (isset(self::$_used_anchors[$result]) && self::$_used_anchors[$result] !== $this->ID) {
498
            ++$count;
499
            $result = $titleAsURL.'-'.$count;
500
        }
501
        self::$_used_anchors[$result] = $this->ID;
502
        return $this->_anchor = $result;
503
    }
504
505
    /**
506
     * @param string $action
507
     *
508
     * @return string
509
     */
510
    public function AbsoluteLink($action = null)
511
    {
512
        if ($page = $this->getPage()) {
513
            $link = $page->AbsoluteLink($action) . '#' . $this->getAnchor();
514
515
            return $link;
516
        }
517
    }
518
519
    /**
520
     * @param string $action
521
     *
522
     * @return string
523
     */
524
    public function Link($action = null)
525
    {
526
        if ($page = $this->getPage()) {
527
            $link = $page->Link($action) . '#' . $this->getAnchor();
528
529
            $this->extend('updateLink', $link);
530
531
            return $link;
532
        }
533
    }
534
535
    /**
536
     * @param string $action
537
     *
538
     * @return string
539
     */
540
    public function PreviewLink($action = null)
541
    {
542
        $action = $action . '?ElementalPreview=' . mt_rand();
543
        $link = $this->Link($action);
544
        $this->extend('updatePreviewLink', $link);
545
546
        return $link;
547
    }
548
549
    /**
550
     * @return boolean
551
     */
552
    public function isCMSPreview()
553
    {
554
        if (Controller::has_curr()) {
555
            $c = Controller::curr();
556
557
            if ($c->getRequest()->requestVar('CMSPreview')) {
558
                return true;
559
            }
560
        }
561
562
        return false;
563
    }
564
565
    /**
566
     * @return string
567
     */
568
    public function CMSEditLink()
569
    {
570
        $relationName = $this->getAreaRelationName();
571
572
        $link = Controller::join_links(
573
            singleton(CMSPageEditController::class)->Link('EditForm'),
574
            $this->getPage(true)->ID,
0 ignored issues
show
Unused Code introduced by
The call to DNADesign\Elemental\Models\BaseElement::getPage() has too many arguments starting with true. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

574
            $this->/** @scrutinizer ignore-call */ 
575
                   getPage(true)->ID,

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
575
            'field/' . $relationName . '/item/',
576
            $this->ID
577
        );
578
579
        if ($inList) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $inList seems to be never defined.
Loading history...
580
            return $link;
581
        }
582
583
        return Controller::join_links(
584
            $link,
585
            'edit'
586
        );
587
    }
588
589
    /**
590
     * Retrieve a elemental area relation for creating cms links
591
     *
592
     * @return string - the name of a valid elemental area relation
593
     */
594
    public function getAreaRelationName()
595
    {
596
        $page = $this->getPage(true);
0 ignored issues
show
Unused Code introduced by
The call to DNADesign\Elemental\Models\BaseElement::getPage() has too many arguments starting with true. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

596
        /** @scrutinizer ignore-call */ 
597
        $page = $this->getPage(true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
597
        $has_one = $page->config()->get('has_one');
598
        $area = $this->Parent();
599
600
        foreach ($has_one as $relationName => $relationClass) {
601
            if ($relationClass === $area->ClassName) {
602
                return $relationName;
603
            }
604
        }
605
606
        return 'ElementalArea';
607
    }
608
609
    /**
610
     * Sanitise a model class' name for inclusion in a link.
611
     *
612
     * @return string
613
     */
614
    protected function sanitiseClassName($class, $delimiter = '-')
615
    {
616
        return str_replace('\\', $delimiter, $class);
617
    }
618
619
    /**
620
     * @return string
621
     */
622
    public function getEditLink()
623
    {
624
        return $this->CMSEditLink();
625
    }
626
627
    /**
628
     * @return HTMLText
0 ignored issues
show
Bug introduced by
The type DNADesign\Elemental\Models\HTMLText was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
629
     */
630
    public function PageCMSEditLink()
631
    {
632
        if ($page = $this->getPage()) {
633
            return DBField::create_field('HTMLText', sprintf(
0 ignored issues
show
Bug Best Practice introduced by
The expression return SilverStripe\ORM\...tLink(), $page->Title)) returns the type SilverStripe\ORM\FieldType\DBField which is incompatible with the documented return type DNADesign\Elemental\Models\HTMLText.
Loading history...
634
                '<a href="%s">%s</a>',
635
                $page->CMSEditLink(),
636
                $page->Title
637
            ));
638
        }
639
    }
640
641
    /**
642
     * @return string
643
     */
644
    public function getMimeType()
645
    {
646
        return 'text/html';
647
    }
648
649
    /**
650
     * This can be overridden on child elements to create a summary for display
651
     * in GridFields.
652
     *
653
     * @return string
654
     */
655
    public function getSummary()
656
    {
657
        return '';
658
    }
659
660
661
    /**
662
     * Generate markup for element type icons suitable for use in GridFields.
663
     *
664
     * @return DBField
665
     */
666
    public function getIcon()
667
    {
668
        $icon = $this->config()->get('icon');
669
670
        if ($icon) {
671
            $icon = ModuleResourceLoader::resourceURL($icon);
672
673
            return DBField::create_field('HTMLVarchar', '<img width="16px" src="' . Director::absoluteBaseURL() . $icon . '" alt="" />');
674
        }
675
    }
676
677
    /**
678
     * Get a description for this content element, if available
679
     *
680
     * @return string
681
     */
682
    public function getDescription()
683
    {
684
        $description = $this->config()->uninherited('description');
685
        if ($description) {
686
            return _t(__CLASS__ . '.Description', $description);
687
        }
688
        return '';
689
    }
690
691
    /**
692
     * Generate markup for element type, with description suitable for use in
693
     * GridFields.
694
     *
695
     * @return DBField
696
     */
697
    public function getTypeNice()
698
    {
699
        $description = $this->getDescription();
700
        $desc = ($description) ? ' <span class="element__note"> &mdash; ' . $description . '</span>' : '';
0 ignored issues
show
Unused Code introduced by
The assignment to $desc is dead and can be removed.
Loading history...
701
702
        return DBField::create_field(
703
            'HTMLVarchar',
704
            $this->getType() . ' <span class="el-description"> &mdash; ' . $description . '</span>'
705
        );
706
    }
707
708
    /**
709
     * @return HTMLText
710
     */
711
    public function getEditorPreview()
712
    {
713
        $templates = $this->getRenderTemplates('_EditorPreview');
714
        $templates[] = BaseElement::class . '_EditorPreview';
715
716
        return $this->renderWith($templates);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->renderWith($templates) returns the type SilverStripe\ORM\FieldType\DBHTMLText which is incompatible with the documented return type DNADesign\Elemental\Models\HTMLText.
Loading history...
717
    }
718
}
719