Passed
Push — master ( 8a2c62...85cfc9 )
by
unknown
02:22
created

BaseElement::getIcon()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 6
rs 9.4285
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
    public function onBeforeWrite()
217
    {
218
        parent::onBeforeWrite();
219
220
        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...
221
            if ($elementalArea = ElementalArea::get()->byID($areaID)) {
222
                $elementalArea->write();
223
            }
224
        }
225
226
        if (!$this->Sort) {
227
            $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...
228
229
            $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...
230
        }
231
    }
232
233
    public function getCMSFields()
234
    {
235
        $this->beforeUpdateCMSFields(function (FieldList $fields) {
236
            // Remove relationship fields
237
            $fields->removeByName('ParentID');
238
            $fields->removeByName('Sort');
239
240
            $fields->addFieldToTab(
241
                'Root.Settings',
242
                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

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

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

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

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

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

337
            GridField::create('History', '', /** @scrutinizer ignore-type */ $history, $config)
Loading history...
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

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

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

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

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

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