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

BaseElement::isCMSPreview()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

284
                $fields->addFieldsToTab('Root.History', /** @scrutinizer ignore-type */ $history);
Loading history...
285
            }
286
        });
287
288
        return parent::getCMSFields();
289
    }
290
291
    /**
292
     * Returns the history fields for this element.
293
     *
294
     * @return FieldList
295
     */
296
    public function getHistoryFields()
297
    {
298
        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

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

329
                /** @scrutinizer ignore-type */ 'History',
Loading history...
330
                '',
331
                $history,
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

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

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

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

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

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