Passed
Push — master ( 54a54b...20fffd )
by Will
02:22
created

BaseElement::getTitle()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 0
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
    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...
44
        'Title' => 'Varchar(255)',
45
        'ShowTitle' => 'Boolean',
46
        'Sort' => 'Int',
47
        'ExtraClass' => 'Varchar(255)'
48
    ];
49
50
    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...
51
        'Parent' => ElementalArea::class
52
    ];
53
54
    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...
55
        Versioned::class
56
    ];
57
58
    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...
59
60
    /**
61
     * @var string
62
     */
63
    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...
64
65
    /**
66
     * @var string
67
     */
68
    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...
69
70
    /**
71
     * @var ElementController
72
     */
73
    protected $controller;
74
75
    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...
76
77
    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...
78
79
    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...
80
81
    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...
82
        'EditorPreview' => 'Summary'
83
    ];
84
85
    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...
86
        'ID' => [
87
            'field' => NumericField::class,
88
        ],
89
        'Title',
90
        'LastEdited'
91
    ];
92
93
    /**
94
     * Enable for backwards compatibility
95
     *
96
     * @var boolean
97
     */
98
    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...
99
100
    /**
101
     * Store used anchor names, this is to avoid title clashes
102
     * when calling 'getAnchor'
103
     *
104
     * @var array
105
     */
106
    protected static $_used_anchors = [];
107
108
    /**
109
     * For caching 'getAnchor'
110
     *
111
     * @var string
112
     */
113
    protected $_anchor = null;
114
115
    /**
116
     * @return array
117
     */
118
    public function getAllowedElementClasses()
119
    {
120
        $classes = [];
121
122
        foreach (ClassInfo::subclassesFor(DataObject::class) as $className) {
123
            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...
124
                $classes[] = $className;
125
            }
126
        }
127
128
        $allowed = [];
129
130
        foreach ($classes as $className) {
131
            $elements = Config::inst()->get($className, 'allowed_elements');
132
133
            if ($elements) {
134
                $allowed = array_merge($allowed, $elements);
135
            }
136
        }
137
138
        $allowed = array_unique($allowed);
139
140
        $elements = [];
141
142
        foreach ($allowed as $className) {
143
            $elements[$className] = _t($className, Config::inst()->get($className, 'title'));
144
        }
145
146
        $this->invokeWithExtensions('updateAllowedElementClasses', $elements);
147
148
        return $elements;
149
    }
150
151
    /**
152
     * Basic permissions, defaults to page perms where possible.
153
     *
154
     * @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...
155
     *
156
     * @return boolean
157
     */
158 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...
159
    {
160
        if ($this->hasMethod('getPage')) {
161
            if ($page = $this->getPage()) {
162
                return $page->canView($member);
163
            }
164
        }
165
166
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
167
    }
168
169
    /**
170
     * Basic permissions, defaults to page perms where possible.
171
     *
172
     * @param Member $member
173
     *
174
     * @return boolean
175
     */
176 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...
177
    {
178
        if ($this->hasMethod('getPage')) {
179
            if ($page = $this->getPage()) {
180
                return $page->canEdit($member);
181
            }
182
        }
183
184
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
185
    }
186
187
    /**
188
     * Basic permissions, defaults to page perms where possible.
189
     *
190
     * Uses archive not delete so that current stage is respected i.e if a
191
     * element is not published, then it can be deleted by someone who doesn't
192
     * have publishing permissions.
193
     *
194
     * @param Member $member
195
     *
196
     * @return boolean
197
     */
198 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...
199
    {
200
        if ($this->hasMethod('getPage')) {
201
            if ($page = $this->getPage()) {
202
                return $page->canArchive($member);
203
            }
204
        }
205
206
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
207
    }
208
209
    /**
210
     * Basic permissions, defaults to page perms where possible.
211
     *
212
     * @param Member $member
213
     * @param array $context
214
     *
215
     * @return boolean
216
     */
217
    public function canCreate($member = null, $context = array())
218
    {
219
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
220
    }
221
222
    /**
223
     *
224
     */
225
    public function onBeforeWrite()
226
    {
227
        parent::onBeforeWrite();
228
229
        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...
230
            if ($elementalArea = ElementalArea::get()->byID($areaID)) {
231
                $elementalArea->write();
232
            }
233
        }
234
235
        if (!$this->Sort) {
236
            $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...
237
238
            $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...
239
        }
240
    }
241
242
    public function getCMSFields()
243
    {
244
        $this->beforeUpdateCMSFields(function (FieldList $fields) {
245
            // Remove relationship fields
246
            $fields->removeByName('ParentID');
247
            $fields->removeByName('Sort');
248
249
            $fields->addFieldToTab(
250
                'Root.Settings',
251
                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

251
                TextField::create(/** @scrutinizer ignore-type */ 'ExtraClass', _t(__CLASS__ . '.ExtraCssClassesLabel', 'Custom CSS classes'))
Loading history...
252
                    ->setAttribute(
253
                        'placeholder',
254
                        _t(__CLASS__ . '.ExtraCssClassesPlaceholder', 'my_class another_class')
255
                    )
256
            );
257
258
            // Add a combined field for "Title" and "Displayed" checkbox in a Bootstrap input group
259
            $fields->removeByName('ShowTitle');
260
            $fields->replaceField(
261
                'Title',
262
                FieldGroup::create(
263
                    TextField::create('Title', ''),
0 ignored issues
show
Bug introduced by
It seems like SilverStripe\Forms\TextField::create('Title', '') can also be of type object; however, parameter $args of SilverStripe\View\ViewableData::create() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

263
                    /** @scrutinizer ignore-type */ TextField::create('Title', ''),
Loading history...
264
                    CheckboxField::create('ShowTitle', _t(__CLASS__ . '.ShowTitleLabel', 'Displayed'))
265
                )
266
                    ->setTemplate(__CLASS__ . '\\FieldGroup')
267
                    ->setTitle(_t(__CLASS__ . '.TitleLabel', 'Title (not displayed unless specified)'))
268
            );
269
270
            // Rename the "Main" tab
271
            $fields->fieldByName('Root.Main')
272
                ->setTitle(_t(__CLASS__ . '.MainTabLabel', 'Content'));
273
274
            // Remove divider lines on all block forms
275
            $fields->fieldByName('Root')->addExtraClass('form--no-dividers');
276
277
            if ($this->isInDB()) {
278
                if ($this->hasExtension(VersionViewerDataObject::class)) {
279
                    $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

279
                    /** @scrutinizer ignore-call */ 
280
                    $fields = $this->addVersionViewer($fields, $this);
Loading history...
280
                }
281
            }
282
283
            $fields->addFieldsToTab('Root.Main', [
284
                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

284
                HiddenField::create('AbsoluteLink', /** @scrutinizer ignore-type */ false, Director::absoluteURL($this->PreviewLink())),
Loading history...
285
                HiddenField::create('LiveLink', false, Director::absoluteURL($this->Link())),
286
                HiddenField::create('StageLink', false, Director::absoluteURL($this->PreviewLink())),
287
            ]);
288
        });
289
290
        return parent::getCMSFields();
291
    }
292
293
    /**
294
     * Used in ElementalAdmin
295
     */
296
    public function getDefaultSearchContext()
297
    {
298
        $fields = $this->scaffoldSearchFields();
299
        $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

299
        /** @scrutinizer ignore-call */ 
300
        $elements = BaseElement::all_allowed_elements();
Loading history...
300
301
        if (!$elements) {
302
            $elements = ClassInfo::subclassesFor(self::class);
303
        }
304
        foreach ($elements as $key => $value) {
305
            if ($key == self::class) {
306
                unset($elements[$key]);
307
                continue;
308
            }
309
            $elements[$key] = $this->stripNamespacing($value);
310
        }
311
312
        $fields->push(
313
            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

313
            DropdownField::create(/** @scrutinizer ignore-type */ 'ClassName', _t(__CLASS__.'.ELEMENTTYPE', 'Element Type'), $elements)
Loading history...
314
                ->setEmptyString(_t(__CLASS__.'.ALL', 'All types'))
315
        );
316
317
        $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

317
        /** @scrutinizer ignore-call */ 
318
        $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...
318
319
        return new SearchContext(
320
            self::class,
321
            $fields,
322
            $filters
323
        );
324
    }
325
326
    /**
327
     * Get the type of the current block, for use in GridField summaries, block type dropdowns etc. Examples
328
     * are "Content", "File", "Media", etc.
329
     *
330
     * @return string
331
     */
332
    public function getType()
333
    {
334
        return _t(__CLASS__ . '.BlockType', 'Block');
335
    }
336
337
    /**
338
     * @param ElementController
339
     *
340
     * @return $this
341
     */
342
    public function setController($controller)
343
    {
344
        $this->controller = $controller;
345
346
        return $this;
347
    }
348
349
    /**
350
     * @throws Exception
351
     *
352
     * @return ElementController
353
     */
354
    public function getController()
355
    {
356
        if ($this->controller) {
357
            return $this->controller;
358
        }
359
360
        $controllerClass = self::config()->controller_class;
361
362
        if (!class_exists($controllerClass)) {
363
            throw new Exception('Could not find controller class ' . $controllerClass . ' as defined in ' . static::class);
364
        }
365
366
        $this->controller = Injector::inst()->create($controllerClass, $this);
367
        $this->controller->doInit();
368
        return $this->controller;
369
    }
370
371
    /**
372
     * @return Controller
373
     */
374
    public function Top()
375
    {
376
        return (Controller::has_curr()) ? Controller::curr() : null;
377
    }
378
379
    /**
380
     * Default way to render element in templates. Note that all blocks should
381
     * be rendered through their {@link ElementController} class as this
382
     * contains the holder styles.
383
     *
384
     * @return string HTML
385
     */
386
    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

386
    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...
387
    {
388
        $templates = $this->getRenderTemplates();
389
390
        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...
391
            return $this->renderWith($templates);
392
        }
393
    }
394
395
    /**
396
     * @param string $suffix
397
     *
398
     * @return array
399
     */
400
    public function getRenderTemplates($suffix = '')
401
    {
402
        $classes = ClassInfo::ancestry($this->ClassName);
403
        $classes[static::class] = static::class;
404
        $classes = array_reverse($classes);
405
        $templates = array();
406
407
        foreach ($classes as $key => $value) {
408
            if ($value == BaseElement::class) {
409
                continue;
410
            }
411
412
            if ($value == DataObject::class) {
413
                break;
414
            }
415
416
            $templates[] = $value . $suffix;
417
        }
418
419
        return $templates;
420
    }
421
422
    /**
423
     * Strip all namespaces from class namespace
424
     * @param string $classname e.g. "\Fully\Namespaced\Class"
425
     *
426
     * @return string following the param example, "Class"
427
     */
428
    protected function stripNamespacing($classname)
429
    {
430
        $classParts = explode('\\', $classname);
431
        return array_pop($classParts);
432
    }
433
434
    /**
435
     * @return string
436
     */
437
    public function getSimpleClassName()
438
    {
439
        return strtolower($this->sanitiseClassName($this->ClassName, '__'));
440
    }
441
442
    /**
443
     * @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...
444
     */
445
    public function getPage()
446
    {
447
        $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

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

565
            $this->/** @scrutinizer ignore-call */ 
566
                   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...
566
            'field/' . $relationName . '/item/',
567
            $this->ID
568
        );
569
570
        if ($inList) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $inList seems to be never defined.
Loading history...
571
            return $link;
572
        }
573
574
        return Controller::join_links(
575
            $link,
576
            'edit'
577
        );
578
    }
579
580
    /**
581
     * Retrieve a elemental area relation for creating cms links
582
     *
583
     * @return string - the name of a valid elemental area relation
584
     */
585
    public function getAreaRelationName()
586
    {
587
        $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

587
        /** @scrutinizer ignore-call */ 
588
        $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...
588
        $has_one = $page->config()->get('has_one');
589
        $area = $this->Parent();
590
591
        foreach ($has_one as $relationName => $relationClass) {
592
            if ($relationClass === $area->ClassName) {
593
                return $relationName;
594
            }
595
        }
596
597
        return 'ElementalArea';
598
    }
599
600
    /**
601
     * Sanitise a model class' name for inclusion in a link.
602
     *
603
     * @return string
604
     */
605
    protected function sanitiseClassName($class, $delimiter = '-')
606
    {
607
        return str_replace('\\', $delimiter, $class);
608
    }
609
610
    /**
611
     * @return string
612
     */
613
    public function getEditLink()
614
    {
615
        return $this->CMSEditLink();
616
    }
617
618
    /**
619
     * @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...
620
     */
621
    public function PageCMSEditLink()
622
    {
623
        if ($page = $this->getPage()) {
624
            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...
625
                '<a href="%s">%s</a>',
626
                $page->CMSEditLink(),
627
                $page->Title
628
            ));
629
        }
630
    }
631
632
    /**
633
     * @return string
634
     */
635
    public function getMimeType()
636
    {
637
        return 'text/html';
638
    }
639
640
    /**
641
     * This can be overridden on child elements to create a summary for display
642
     * in GridFields.
643
     *
644
     * @return string
645
     */
646
    public function getSummary()
647
    {
648
        return '';
649
    }
650
651
652
    /**
653
     * Generate markup for element type icons suitable for use in GridFields.
654
     *
655
     * @return DBField
656
     */
657
    public function getIcon()
658
    {
659
        $icon = $this->config()->get('icon');
660
661
        if ($icon) {
662
            $icon = ModuleResourceLoader::resourceURL($icon);
663
664
            return DBField::create_field('HTMLVarchar', '<img width="16px" src="' . Director::absoluteBaseURL() . $icon . '" alt="" />');
665
        }
666
    }
667
668
    /**
669
     * Generate markup for element type, with description suitable for use in
670
     * GridFields.
671
     *
672
     * @return DBField
673
     */
674
    public function getTypeNice()
675
    {
676
        $description = $this->config()->get('description');
677
678
        return DBField::create_field(
679
            'HTMLVarchar',
680
            $this->getType() . ' <span class="el-description"> &mdash; ' . $description . '</span>'
681
        );
682
    }
683
684
    /**
685
     * @return HTMLText
686
     */
687
    public function getEditorPreview()
688
    {
689
        $templates = $this->getRenderTemplates('_EditorPreview');
690
        $templates[] = BaseElement::class . '_EditorPreview';
691
692
        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...
693
    }
694
}
695