Passed
Pull Request — master (#144)
by Robbie
01:58
created

BaseElement::getCMSFields()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 57
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 33
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 57
rs 9.0309

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

245
                TextField::create(/** @scrutinizer ignore-type */ 'ExtraClass', _t(__CLASS__ . '.ExtraCssClassesLabel', 'Custom CSS classes'))
Loading history...
246
                    ->setAttribute(
247
                        'placeholder',
248
                        _t(__CLASS__ . '.ExtraCssClassesPlaceholder', 'my_class another_class')
249
                    )
250
            );
251
252
            // Add a combined field for "Title" and "Displayed" checkbox in a Bootstrap input group
253
            $fields->removeByName('ShowTitle');
254
            $fields->replaceField(
255
                'Title',
256
                TextCheckboxGroupField::create(
257
                    TextField::create('Title', _t(__CLASS__ . '.TitleLabel', 'Title (displayed if checked)')),
258
                    CheckboxField::create('ShowTitle', _t(__CLASS__ . '.ShowTitleLabel', 'Displayed'))
259
                )
260
                    ->setName('TitleAndDisplayed')
261
            );
262
263
            // Rename the "Main" tab
264
            $fields->fieldByName('Root.Main')
265
                ->setTitle(_t(__CLASS__ . '.MainTabLabel', 'Content'));
266
267
            $fields->addFieldsToTab('Root.Main', [
268
                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

268
                HiddenField::create('AbsoluteLink', /** @scrutinizer ignore-type */ false, Director::absoluteURL($this->PreviewLink())),
Loading history...
269
                HiddenField::create('LiveLink', false, Director::absoluteURL($this->Link())),
270
                HiddenField::create('StageLink', false, Director::absoluteURL($this->PreviewLink())),
271
            ]);
272
273
            $styles = $this->config()->get('styles');
274
275
            if ($styles && count($styles) > 0) {
276
                $styleDropdown = DropdownField::create('Style', _t(__CLASS__.'.STYLE', 'Style variation'), $styles);
277
278
                $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

278
                $fields->insertBefore($styleDropdown, /** @scrutinizer ignore-type */ 'ExtraClass');
Loading history...
279
280
                $styleDropdown->setEmptyString(_t(__CLASS__.'.CUSTOM_STYLES', 'Select a style..'));
281
            } else {
282
                $fields->removeByName('Style');
283
            }
284
285
            $history = $this->getHistoryFields();
286
287
            if ($history) {
288
                $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

288
                $fields->addFieldsToTab('Root.History', /** @scrutinizer ignore-type */ $history);
Loading history...
289
            }
290
        });
291
292
        return parent::getCMSFields();
293
    }
294
295
    /**
296
     * Returns the history fields for this element.
297
     *
298
     * @param  bool $checkLatestVersion Whether to check if this is the latest version. Prevents recursion, but can be
299
     *                                  overridden to get the history GridField if required.
300
     * @return FieldList
301
     */
302
    public function getHistoryFields($checkLatestVersion = true)
303
    {
304
        if ($checkLatestVersion && !$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

304
        if ($checkLatestVersion && !$this->/** @scrutinizer ignore-call */ isLatestVersion()) {
Loading history...
305
            // if viewing the history of the of page then don't show the history
306
            // fields as then we have recursion.
307
            return null;
308
        }
309
310
        Requirements::javascript('dnadesign/silverstripe-elemental:client/dist/js/bundle.js');
311
312
        $config = GridFieldConfig_RecordViewer::create();
313
        $config->removeComponentsByType(GridFieldPageCount::class);
314
        $config->removeComponentsByType(GridFieldToolbarHeader::class);
315
        // Replace the sortable ID column with a static header component
316
        $config->removeComponentsByType(GridFieldSortableHeader::class);
317
        $config->addComponent(new GridFieldTitleHeader);
318
319
        $config
320
            ->getComponentByType(GridFieldDetailForm::class)
321
            ->setItemRequestClass(HistoricalVersionedGridFieldItemRequest::class);
322
323
        $config->getComponentByType(GridFieldDataColumns::class)
324
            ->setDisplayFields([
325
                'Version' => '#',
326
                'RecordStatus' => _t(__CLASS__ . '.Record', 'Record'),
327
                'getAuthor.Name' => _t(__CLASS__ . '.Author', 'Author')
328
            ])
329
            ->setFieldFormatting([
330
                'RecordStatus' => '$VersionedStateNice <span class=\"element-history__date--small\">on $LastEditedNice</span>',
331
            ]);
332
333
        $config->removeComponentsByType(GridFieldViewButton::class);
334
        $config->addComponent(new ElementalGridFieldHistoryButton());
335
336
        $history = Versioned::get_all_versions(__CLASS__, $this->ID)
337
            ->sort('Version', 'DESC');
338
339
        return FieldList::create(
340
            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

340
            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

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

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

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

583
        /** @scrutinizer ignore-call */ 
584
        $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...
584
585
        if (!$page) {
586
            return null;
587
        }
588
589
        $link = Controller::join_links(
590
            singleton(CMSPageEditController::class)->Link('EditForm'),
591
            $page->ID,
592
            'field/' . $relationName . '/item/',
593
            $this->ID
594
        );
595
596
        return Controller::join_links(
597
            $link,
598
            'edit'
599
        );
600
    }
601
602
    /**
603
     * Retrieve a elemental area relation for creating cms links
604
     *
605
     * @return string - the name of a valid elemental area relation
606
     */
607
    public function getAreaRelationName()
608
    {
609
        $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

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