Passed
Pull Request — master (#123)
by Robbie
01:57
created

BaseElement::getCMSFields()   B

Complexity

Conditions 4
Paths 1

Size

Total Lines 61
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 61
rs 8.9392
cc 4
eloc 35
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace DNADesign\Elemental\Models;
4
5
use Exception;
6
use DNADesign\Elemental\Forms\ElementalGridFieldHistoryButton;
7
use DNADesign\Elemental\Forms\HistoricalVersionedGridFieldItemRequest;
8
use DNADesign\Elemental\Controllers\ElementController;
9
use SilverStripe\CMS\Controllers\CMSPageEditController;
10
use SilverStripe\Control\Controller;
11
use SilverStripe\Control\Director;
12
use SilverStripe\Core\ClassInfo;
13
use SilverStripe\Core\Config\Config;
14
use SilverStripe\Core\Injector\Injector;
15
use SilverStripe\Core\Manifest\ModuleResourceLoader;
16
use SilverStripe\Forms\CheckboxField;
17
use SilverStripe\Forms\DropdownField;
18
use SilverStripe\Forms\FieldGroup;
19
use SilverStripe\Forms\FieldList;
20
use SilverStripe\Forms\HiddenField;
21
use SilverStripe\Forms\NumericField;
22
use SilverStripe\Forms\ReadonlyField;
23
use SilverStripe\Forms\TextField;
24
use SilverStripe\Forms\GridField\GridField;
25
use SilverStripe\Forms\GridField\GridFieldConfig_RecordViewer;
26
use SilverStripe\Forms\GridField\GridFieldDataColumns;
27
use SilverStripe\Forms\GridField\GridFieldDetailForm;
28
use SilverStripe\Forms\GridField\GridFieldPageCount;
29
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
30
use SilverStripe\Forms\GridField\GridFieldVersionedState;
31
use SilverStripe\Forms\GridField\GridFieldViewButton;
32
use SilverStripe\ORM\ArrayList;
33
use SilverStripe\ORM\CMSPreviewable;
34
use SilverStripe\ORM\DataObject;
35
use SilverStripe\ORM\DB;
36
use SilverStripe\ORM\FieldType\DBField;
37
use SilverStripe\ORM\Search\SearchContext;
38
use SilverStripe\Security\Permission;
39
use SilverStripe\Security\Member;
40
use SilverStripe\SiteConfig\SiteConfig;
41
use SilverStripe\Versioned\Versioned;
42
use SilverStripe\View\Parsers\URLSegmentFilter;
43
use SilverStripe\View\SSViewer;
44
45
class BaseElement extends DataObject implements CMSPreviewable
46
{
47
    /**
48
     * Override this on your custom elements to specify a cms icon
49
     *
50
     * @var string
51
     */
52
    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...
53
54
    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...
55
        'Title' => 'Varchar(255)',
56
        'ShowTitle' => 'Boolean',
57
        'Sort' => 'Int',
58
        'ExtraClass' => 'Varchar(255)',
59
        'Style' => 'Varchar(255)'
60
    ];
61
62
    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...
63
        'Parent' => ElementalArea::class
64
    ];
65
66
    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...
67
        Versioned::class
68
    ];
69
70
    private static $versioned_gridfield_extensions = true;
0 ignored issues
show
Unused Code introduced by
The property $versioned_gridfield_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...
71
72
    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...
73
74
    /**
75
     * @var string
76
     */
77
    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...
78
79
    /**
80
     * @var string
81
     */
82
    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...
83
84
    /**
85
     * @var ElementController
86
     */
87
    protected $controller;
88
89
    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...
90
91
    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...
92
93
    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...
94
95
    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...
96
        'EditorPreview' => 'Summary'
97
    ];
98
99
    /**
100
     * @var array
101
     */
102
    private static $styles = [];
0 ignored issues
show
Unused Code introduced by
The property $styles 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...
103
104
    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...
105
        'ID' => [
106
            'field' => NumericField::class,
107
        ],
108
        'Title',
109
        'LastEdited'
110
    ];
111
112
    /**
113
     * Enable for backwards compatibility
114
     *
115
     * @var boolean
116
     */
117
    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...
118
119
    /**
120
     * Store used anchor names, this is to avoid title clashes
121
     * when calling 'getAnchor'
122
     *
123
     * @var array
124
     */
125
    protected static $_used_anchors = [];
126
127
    /**
128
     * For caching 'getAnchor'
129
     *
130
     * @var string
131
     */
132
    protected $_anchor = null;
133
134
    /**
135
     * Basic permissions, defaults to page perms where possible.
136
     *
137
     * @param Member $member
138
     *
139
     * @return boolean
140
     */
141 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...
142
    {
143
        if ($this->hasMethod('getPage')) {
144
            if ($page = $this->getPage()) {
145
                return $page->canView($member);
146
            }
147
        }
148
149
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
150
    }
151
152
    /**
153
     * Basic permissions, defaults to page perms where possible.
154
     *
155
     * @param Member $member
156
     *
157
     * @return boolean
158
     */
159 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...
160
    {
161
        if ($this->hasMethod('getPage')) {
162
            if ($page = $this->getPage()) {
163
                return $page->canEdit($member);
164
            }
165
        }
166
167
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
168
    }
169
170
    /**
171
     * Basic permissions, defaults to page perms where possible.
172
     *
173
     * Uses archive not delete so that current stage is respected i.e if a
174
     * element is not published, then it can be deleted by someone who doesn't
175
     * have publishing permissions.
176
     *
177
     * @param Member $member
178
     *
179
     * @return boolean
180
     */
181 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...
182
    {
183
        if ($this->hasMethod('getPage')) {
184
            if ($page = $this->getPage()) {
185
                return $page->canArchive($member);
186
            }
187
        }
188
189
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
190
    }
191
192
    /**
193
     * Basic permissions, defaults to page perms where possible.
194
     *
195
     * @param Member $member
196
     * @param array $context
197
     *
198
     * @return boolean
199
     */
200
    public function canCreate($member = null, $context = array())
201
    {
202
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
203
    }
204
205
    /**
206
     *
207
     */
208
    public function onBeforeWrite()
209
    {
210
        parent::onBeforeWrite();
211
212
        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...
213
            if ($elementalArea = ElementalArea::get()->byID($areaID)) {
214
                $elementalArea->write();
215
            }
216
        }
217
218
        if (!$this->Sort) {
219
            $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...
220
221
            $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...
222
        }
223
    }
224
225
    public function getCMSFields()
226
    {
227
        $this->beforeUpdateCMSFields(function (FieldList $fields) {
228
            // Remove relationship fields
229
            $fields->removeByName('ParentID');
230
            $fields->removeByName('Sort');
231
232
            $fields->addFieldToTab(
233
                'Root.Settings',
234
                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

234
                TextField::create(/** @scrutinizer ignore-type */ 'ExtraClass', _t(__CLASS__ . '.ExtraCssClassesLabel', 'Custom CSS classes'))
Loading history...
235
                    ->setAttribute(
236
                        'placeholder',
237
                        _t(__CLASS__ . '.ExtraCssClassesPlaceholder', 'my_class another_class')
238
                    )
239
            );
240
241
            // Add a combined field for "Title" and "Displayed" checkbox in a Bootstrap input group
242
            $fields->removeByName('ShowTitle');
243
            $fields->replaceField(
244
                'Title',
245
                FieldGroup::create(
246
                    TextField::create('Title', ''),
247
                    CheckboxField::create('ShowTitle', _t(__CLASS__ . '.ShowTitleLabel', 'Displayed'))
248
                )
249
                    ->setTemplate(__CLASS__ . '\\FieldGroup')
250
                    ->setTitle(_t(__CLASS__ . '.TitleLabel', 'Title (not displayed unless specified)'))
251
            );
252
253
            // Rename the "Main" tab
254
            $fields->fieldByName('Root.Main')
255
                ->setTitle(_t(__CLASS__ . '.MainTabLabel', 'Content'));
256
257
            // Remove divider lines on all block forms
258
            $fields->fieldByName('Root')->addExtraClass('form--no-dividers');
259
260
            $fields->addFieldsToTab('Root.Main', [
261
                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

261
                HiddenField::create('AbsoluteLink', /** @scrutinizer ignore-type */ false, Director::absoluteURL($this->PreviewLink())),
Loading history...
262
                HiddenField::create('LiveLink', false, Director::absoluteURL($this->Link())),
263
                HiddenField::create('StageLink', false, Director::absoluteURL($this->PreviewLink())),
264
            ]);
265
266
            $styles = $this->config()->get('styles');
267
268
            if ($styles && count($styles) > 0) {
269
                $styleDropdown = DropdownField::create('Style', _t(__CLASS__.'.STYLE', 'Style variation'), $styles);
270
271
                $fields->insertBefore($styleDropdown, 'ExtraClass');
0 ignored issues
show
Bug introduced by
'ExtraClass' of type string is incompatible with the type SilverStripe\Forms\FormField expected by parameter $item of SilverStripe\Forms\FieldList::insertBefore(). ( Ignorable by Annotation )

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

271
                $fields->insertBefore($styleDropdown, /** @scrutinizer ignore-type */ 'ExtraClass');
Loading history...
272
273
                $styleDropdown->setEmptyString(_t(__CLASS__.'.CUSTOM_STYLES', 'Select a style..'));
274
            } else {
275
                $fields->removeByName('Style');
276
            }
277
278
            $history = $this->getHistoryFields();
279
280
            if ($history) {
281
                $fields->addFieldsToTab('Root.History', $history);
0 ignored issues
show
Bug introduced by
$history of type SilverStripe\Forms\FieldList is incompatible with the type array expected by parameter $fields of SilverStripe\Forms\FieldList::addFieldsToTab(). ( Ignorable by Annotation )

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

281
                $fields->addFieldsToTab('Root.History', /** @scrutinizer ignore-type */ $history);
Loading history...
282
            }
283
        });
284
285
        return parent::getCMSFields();
286
    }
287
288
    /**
289
     * Returns the history fields for this element.
290
     *
291
     * @return FieldList
292
     */
293
    public function getHistoryFields()
294
    {
295
        if (!$this->isLatestVersion()) {
0 ignored issues
show
Bug introduced by
The method isLatestVersion() 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

295
        if (!$this->/** @scrutinizer ignore-call */ isLatestVersion()) {
Loading history...
296
            // if viewing the history of the of page then don't show the history
297
            // fields as then we have recursion.
298
            return null;
299
        }
300
301
        $config = GridFieldConfig_RecordViewer::create();
302
        $config->removeComponentsByType(GridFieldPageCount::class);
303
        $config->removeComponentsByType(GridFieldToolbarHeader::class);
304
305
        $config
306
            ->getComponentByType(GridFieldDetailForm::class)
307
            ->setItemRequestClass(HistoricalVersionedGridFieldItemRequest::class);
308
309
        $config->getComponentByType(GridFieldDataColumns::class)
310
            ->setDisplayFields([
311
                'Version' => '#',
312
                'RecordStatus' => _t(__CLASS__ . '.Record', 'Record'),
313
                'getAuthor.Name' => _t(__CLASS__ . '.Author', 'Author')
314
            ])
315
            ->setFieldFormatting([
316
                'RecordStatus' => '$VersionedStateNice <span class=\"element-history__date--small\">on $LastEditedNice</span>',
317
            ]);
318
319
        $config->removeComponentsByType(GridFieldViewButton::class);
320
        $config->addComponent(new ElementalGridFieldHistoryButton());
321
322
        $history = Versioned::get_all_versions(__CLASS__, $this->ID)
323
            ->sort('Version', 'DESC');
324
325
        return FieldList::create(
326
            GridField::create('History', '', $history, $config)
0 ignored issues
show
Bug introduced by
'History' 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

326
            GridField::create(/** @scrutinizer ignore-type */ 'History', '', $history, $config)
Loading history...
Bug introduced by
$history of type SilverStripe\ORM\DataList 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

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

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

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

568
        /** @scrutinizer ignore-call */ 
569
        $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...
569
570
        if (!$page) {
571
            return null;
572
        }
573
574
        $link = Controller::join_links(
575
            singleton(CMSPageEditController::class)->Link('EditForm'),
576
            $page->ID,
577
            'field/' . $relationName . '/item/',
578
            $this->ID
579
        );
580
581
        return Controller::join_links(
582
            $link,
583
            'edit'
584
        );
585
    }
586
587
    /**
588
     * Retrieve a elemental area relation for creating cms links
589
     *
590
     * @return string - the name of a valid elemental area relation
591
     */
592
    public function getAreaRelationName()
593
    {
594
        $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

594
        /** @scrutinizer ignore-call */ 
595
        $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...
595
596
        if ($page) {
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
607
        return 'ElementalArea';
608
    }
609
610
    /**
611
     * Sanitise a model class' name for inclusion in a link.
612
     *
613
     * @return string
614
     */
615
    public function sanitiseClassName($class, $delimiter = '-')
616
    {
617
        return str_replace('\\', $delimiter, $class);
618
    }
619
620
    public function unsanitiseClassName($class, $delimiter = '-')
621
    {
622
        return str_replace($delimiter, '\\', $class);
623
    }
624
625
    /**
626
     * @return string
627
     */
628
    public function getEditLink()
629
    {
630
        return $this->CMSEditLink();
631
    }
632
633
    /**
634
     * @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...
635
     */
636
    public function PageCMSEditLink()
637
    {
638
        if ($page = $this->getPage()) {
639
            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...
640
                '<a href="%s">%s</a>',
641
                $page->CMSEditLink(),
642
                $page->Title
643
            ));
644
        }
645
    }
646
647
    /**
648
     * @return string
649
     */
650
    public function getMimeType()
651
    {
652
        return 'text/html';
653
    }
654
655
    /**
656
     * This can be overridden on child elements to create a summary for display
657
     * in GridFields.
658
     *
659
     * @return string
660
     */
661
    public function getSummary()
662
    {
663
        return '';
664
    }
665
666
667
    /**
668
     * Generate markup for element type icons suitable for use in GridFields.
669
     *
670
     * @return DBField
671
     */
672
    public function getIcon()
673
    {
674
        $icon = $this->config()->get('icon');
675
676
        if ($icon) {
677
            $icon = ModuleResourceLoader::resourceURL($icon);
678
679
            return DBField::create_field('HTMLVarchar', '<img width="16px" src="' . Director::absoluteBaseURL() . $icon . '" alt="" />');
680
        }
681
    }
682
683
    /**
684
     * Generate markup for element type, with description suitable for use in
685
     * GridFields.
686
     *
687
     * @return DBField
688
     */
689
    public function getTypeNice()
690
    {
691
        $description = $this->config()->get('description');
692
        $desc = ($description) ? ' <span class="el-description"> &mdash; ' . $description . '</span>' : '';
693
694
        return DBField::create_field(
695
            'HTMLVarchar',
696
            $this->getType() . $desc
697
        );
698
    }
699
700
    /**
701
     * @return HTMLText
702
     */
703
    public function getEditorPreview()
704
    {
705
        $templates = $this->getRenderTemplates('_EditorPreview');
706
        $templates[] = BaseElement::class . '_EditorPreview';
707
708
        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...
709
    }
710
711
    /**
712
     * @return Member
713
     */
714
    public function getAuthor()
715
    {
716
        if ($this->AuthorID) {
0 ignored issues
show
Bug Best Practice introduced by
The property AuthorID does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
717
            return Member::get()->byId($this->AuthorID);
718
        }
719
    }
720
721
    /**
722
     * Get a user defined style variant for this element, if available
723
     *
724
     * @return string
725
     */
726
    public function getStyleVariant()
727
    {
728
        $style = $this->Style;
0 ignored issues
show
Bug Best Practice introduced by
The property Style does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
729
        $styles = $this->config()->get('styles');
730
731
        if (isset($styles[$style])) {
732
            $style = strtolower($style);
733
        } else {
734
            $style = '';
735
        }
736
737
        $this->extend('updateStyleVariant', $style);
738
739
        return $style;
740
    }
741
742
    /**
743
     *
744
     */
745
    public function getPageTitle()
746
    {
747
        $page = $this->getPage();
748
749
        if ($page) {
750
            return $page->Title;
751
        }
752
753
        return null;
754
    }
755
756
    /**
757
     * Get a "nice" label for use in the block history GridField
758
     *
759
     * @return string
760
     */
761
    public function getVersionedStateNice()
762
    {
763
        if ($this->WasPublished) {
0 ignored issues
show
Bug Best Practice introduced by
The property WasPublished does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
764
            return _t(__CLASS__ . '.Published', 'Published');
765
        }
766
767
        return _t(__CLASS__ . '.Modified', 'Modified');
768
    }
769
770
    /**
771
     * Return a formatted date for use in the block history GridField
772
     *
773
     * @return string
774
     */
775
    public function getLastEditedNice()
776
    {
777
        return $this->dbObject('LastEdited')->Nice();
778
    }
779
}
780