Passed
Pull Request — master (#190)
by Robbie
02:51
created

BaseElement::getIcon()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 5
nop 0
dl 0
loc 30
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace DNADesign\Elemental\Models;
4
5
use DNADesign\Elemental\Controllers\ElementController;
6
use DNADesign\Elemental\Forms\ElementalGridFieldHistoryButton;
7
use DNADesign\Elemental\Forms\HistoricalVersionedGridFieldItemRequest;
8
use DNADesign\Elemental\Forms\TextCheckboxGroupField;
9
use Exception;
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\Injector\Injector;
15
use SilverStripe\Forms\CheckboxField;
16
use SilverStripe\Forms\DropdownField;
17
use SilverStripe\Forms\FieldList;
18
use SilverStripe\Forms\GridField\GridField;
19
use SilverStripe\Forms\GridField\GridFieldConfig_RecordViewer;
20
use SilverStripe\Forms\GridField\GridFieldDataColumns;
21
use SilverStripe\Forms\GridField\GridFieldDetailForm;
22
use SilverStripe\Forms\GridField\GridFieldPageCount;
23
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
24
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
25
use SilverStripe\Forms\GridField\GridFieldViewButton;
26
use SilverStripe\Forms\HiddenField;
27
use SilverStripe\Forms\NumericField;
28
use SilverStripe\Forms\TextField;
29
use SilverStripe\ORM\CMSPreviewable;
30
use SilverStripe\ORM\DataObject;
31
use SilverStripe\ORM\FieldType\DBField;
32
use SilverStripe\ORM\FieldType\DBHTMLText;
33
use SilverStripe\Security\Member;
34
use SilverStripe\Security\Permission;
35
use SilverStripe\Versioned\Versioned;
36
use SilverStripe\View\ArrayData;
37
use SilverStripe\View\Parsers\URLSegmentFilter;
38
use SilverStripe\View\Requirements;
39
use Symbiote\GridFieldExtensions\GridFieldTitleHeader;
40
41
/**
42
 * Class BaseElement
43
 * @package DNADesign\Elemental\Models
44
 *
45
 * @property string $Title
46
 * @property bool $ShowTitle
47
 * @property int $Sort
48
 * @property string $ExtraClass
49
 * @property string $Style
50
 *
51
 * @method ElementalArea Parent()
52
 */
53
class BaseElement extends DataObject implements CMSPreviewable
54
{
55
    /**
56
     * Override this on your custom elements to specify a CSS icon class
57
     *
58
     * @var string
59
     */
60
    private static $icon = 'font-icon-block-layout';
0 ignored issues
show
introduced by
The private property $icon is not used, and could be removed.
Loading history...
61
62
    /**
63
     * Describe the purpose of this element
64
     *
65
     * @config
66
     * @var string
67
     */
68
    private static $description = 'Base element class';
0 ignored issues
show
introduced by
The private property $description is not used, and could be removed.
Loading history...
69
70
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
71
        'Title' => 'Varchar(255)',
72
        'ShowTitle' => 'Boolean',
73
        'Sort' => 'Int',
74
        'ExtraClass' => 'Varchar(255)',
75
        'Style' => 'Varchar(255)'
76
    ];
77
78
    private static $has_one = [
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
79
        'Parent' => ElementalArea::class
80
    ];
81
82
    private static $extensions = [
0 ignored issues
show
introduced by
The private property $extensions is not used, and could be removed.
Loading history...
83
        Versioned::class
84
    ];
85
86
    private static $versioned_gridfield_extensions = true;
0 ignored issues
show
introduced by
The private property $versioned_gridfield_extensions is not used, and could be removed.
Loading history...
87
88
    private static $table_name = 'Element';
0 ignored issues
show
introduced by
The private property $table_name is not used, and could be removed.
Loading history...
89
90
    /**
91
     * @var string
92
     */
93
    private static $controller_class = ElementController::class;
94
95
    /**
96
     * @var string
97
     */
98
    private static $controller_template = 'ElementHolder';
0 ignored issues
show
introduced by
The private property $controller_template is not used, and could be removed.
Loading history...
99
100
    /**
101
     * @var ElementController
102
     */
103
    protected $controller;
104
105
    private static $default_sort = 'Sort';
0 ignored issues
show
introduced by
The private property $default_sort is not used, and could be removed.
Loading history...
106
107
    private static $singular_name = 'block';
0 ignored issues
show
introduced by
The private property $singular_name is not used, and could be removed.
Loading history...
108
109
    private static $plural_name = 'blocks';
0 ignored issues
show
introduced by
The private property $plural_name is not used, and could be removed.
Loading history...
110
111
    private static $summary_fields = [
0 ignored issues
show
introduced by
The private property $summary_fields is not used, and could be removed.
Loading history...
112
        'EditorPreview' => 'Summary'
113
    ];
114
115
    /**
116
     * @config
117
     * @var array
118
     */
119
    private static $styles = [];
0 ignored issues
show
introduced by
The private property $styles is not used, and could be removed.
Loading history...
120
121
    private static $searchable_fields = [
0 ignored issues
show
introduced by
The private property $searchable_fields is not used, and could be removed.
Loading history...
122
        'ID' => [
123
            'field' => NumericField::class,
124
        ],
125
        'Title',
126
        'LastEdited'
127
    ];
128
129
    /**
130
     * Enable for backwards compatibility
131
     *
132
     * @var boolean
133
     */
134
    private static $disable_pretty_anchor_name = false;
135
136
    /**
137
     * Store used anchor names, this is to avoid title clashes
138
     * when calling 'getAnchor'
139
     *
140
     * @var array
141
     */
142
    protected static $_used_anchors = [];
143
144
    /**
145
     * For caching 'getAnchor'
146
     *
147
     * @var string
148
     */
149
    protected $_anchor = null;
150
151
    /**
152
     * Basic permissions, defaults to page perms where possible.
153
     *
154
     * @param Member $member
155
     * @return boolean
156
     */
157
    public function canView($member = null)
158
    {
159
        if ($this->hasMethod('getPage')) {
160
            if ($page = $this->getPage()) {
161
                return $page->canView($member);
162
            }
163
        }
164
165
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
166
    }
167
168
    /**
169
     * Basic permissions, defaults to page perms where possible.
170
     *
171
     * @param Member $member
172
     *
173
     * @return boolean
174
     */
175
    public function canEdit($member = null)
176
    {
177
        if ($this->hasMethod('getPage')) {
178
            if ($page = $this->getPage()) {
179
                return $page->canEdit($member);
180
            }
181
        }
182
183
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
184
    }
185
186
    /**
187
     * Basic permissions, defaults to page perms where possible.
188
     *
189
     * Uses archive not delete so that current stage is respected i.e if a
190
     * element is not published, then it can be deleted by someone who doesn't
191
     * have publishing permissions.
192
     *
193
     * @param Member $member
194
     *
195
     * @return boolean
196
     */
197
    public function canDelete($member = null)
198
    {
199
        if ($this->hasMethod('getPage')) {
200
            if ($page = $this->getPage()) {
201
                return $page->canArchive($member);
202
            }
203
        }
204
205
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
206
    }
207
208
    /**
209
     * Basic permissions, defaults to page perms where possible.
210
     *
211
     * @param Member $member
212
     * @param array $context
213
     *
214
     * @return boolean
215
     */
216
    public function canCreate($member = null, $context = array())
217
    {
218
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
219
    }
220
221
    /**
222
     * @throws \SilverStripe\ORM\ValidationException
223
     */
224
    public function onBeforeWrite()
225
    {
226
        parent::onBeforeWrite();
227
228
        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...
229
            if ($elementalArea = ElementalArea::get()->byID($areaID)) {
230
                $elementalArea->write();
231
            }
232
        }
233
234
        if (!$this->Sort) {
235
            $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...
236
237
            $this->Sort = static::get()->max('Sort') + 1;
238
        }
239
    }
240
241
    public function getCMSFields()
242
    {
243
        $this->beforeUpdateCMSFields(function (FieldList $fields) {
244
            // Remove relationship fields
245
            $fields->removeByName('ParentID');
246
            $fields->removeByName('Sort');
247
248
            $fields->addFieldToTab(
249
                'Root.Settings',
250
                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

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

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

283
                $fields->insertBefore($styleDropdown, /** @scrutinizer ignore-type */ 'ExtraClass');
Loading history...
284
285
                $styleDropdown->setEmptyString(_t(__CLASS__.'.CUSTOM_STYLES', 'Select a style..'));
286
            } else {
287
                $fields->removeByName('Style');
288
            }
289
290
            $history = $this->getHistoryFields();
291
292
            if ($history) {
0 ignored issues
show
introduced by
The condition $history can never be true.
Loading history...
293
                $fields->addFieldsToTab('Root.History', $history);
294
            }
295
        });
296
297
        return parent::getCMSFields();
298
    }
299
300
    /**
301
     * Returns the history fields for this element.
302
     *
303
     * @param  bool $checkLatestVersion Whether to check if this is the latest version. Prevents recursion, but can be
304
     *                                  overridden to get the history GridField if required.
305
     * @return FieldList
306
     */
307
    public function getHistoryFields($checkLatestVersion = true)
308
    {
309
        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

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

345
            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

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

411
    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...
412
    {
413
        $templates = $this->getRenderTemplates();
414
415
        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...
416
            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...
417
        }
418
419
        return null;
420
    }
421
422
    /**
423
     * @param string $suffix
424
     *
425
     * @return array
426
     */
427
    public function getRenderTemplates($suffix = '')
428
    {
429
        $classes = ClassInfo::ancestry($this->ClassName);
430
        $classes[static::class] = static::class;
431
        $classes = array_reverse($classes);
432
        $templates = array();
433
434
        foreach ($classes as $key => $value) {
435
            if ($value == BaseElement::class) {
436
                continue;
437
            }
438
439
            if ($value == DataObject::class) {
440
                break;
441
            }
442
443
            $templates[] = $value . $suffix;
444
        }
445
446
        return $templates;
447
    }
448
449
    /**
450
     * Strip all namespaces from class namespace.
451
     *
452
     * @param string $classname e.g. "\Fully\Namespaced\Class"
453
     *
454
     * @return string following the param example, "Class"
455
     */
456
    protected function stripNamespacing($classname)
457
    {
458
        $classParts = explode('\\', $classname);
459
        return array_pop($classParts);
460
    }
461
462
    /**
463
     * @return string
464
     */
465
    public function getSimpleClassName()
466
    {
467
        return strtolower($this->sanitiseClassName($this->ClassName, '__'));
468
    }
469
470
    /**
471
     * @return null|DataObject
472
     * @throws \Psr\Container\NotFoundExceptionInterface
473
     * @throws \SilverStripe\ORM\ValidationException
474
     */
475
    public function getPage()
476
    {
477
        $area = $this->Parent();
478
479
        if ($area instanceof ElementalArea && $area->exists()) {
480
            return $area->getOwnerPage();
481
        }
482
483
        return null;
484
    }
485
486
    /**
487
     * Get a unique anchor name
488
     *
489
     * @return string
490
     */
491
    public function getAnchor()
492
    {
493
        if ($this->_anchor !== null) {
0 ignored issues
show
introduced by
The condition $this->_anchor !== null can never be false.
Loading history...
494
            return $this->_anchor;
495
        }
496
497
        $anchorTitle = '';
498
499
        if (!$this->config()->disable_pretty_anchor_name) {
500
            if ($this->hasMethod('getAnchorTitle')) {
501
                $anchorTitle = $this->getAnchorTitle();
502
            } elseif ($this->config()->enable_title_in_template) {
503
                $anchorTitle = $this->getField('Title');
504
            }
505
        }
506
507
        if (!$anchorTitle) {
508
            $anchorTitle = 'e'.$this->ID;
509
        }
510
511
        $filter = URLSegmentFilter::create();
512
        $titleAsURL = $filter->filter($anchorTitle);
513
514
        // Ensure that this anchor name isn't already in use
515
        // ie. If two elemental blocks have the same title, it'll append '-2', '-3'
516
        $result = $titleAsURL;
517
        $count = 1;
518
        while (isset(self::$_used_anchors[$result]) && self::$_used_anchors[$result] !== $this->ID) {
519
            ++$count;
520
            $result = $titleAsURL.'-'.$count;
521
        }
522
        self::$_used_anchors[$result] = $this->ID;
523
        return $this->_anchor = $result;
524
    }
525
526
    /**
527
     * @param string|null $action
528
     * @return string|null
529
     * @throws \Psr\Container\NotFoundExceptionInterface
530
     * @throws \SilverStripe\ORM\ValidationException
531
     */
532
    public function AbsoluteLink($action = null)
533
    {
534
        if ($page = $this->getPage()) {
535
            $link = $page->AbsoluteLink($action) . '#' . $this->getAnchor();
536
537
            return $link;
538
        }
539
540
        return null;
541
    }
542
543
    /**
544
     * @param string|null $action
545
     * @return string
546
     * @throws \Psr\Container\NotFoundExceptionInterface
547
     * @throws \SilverStripe\ORM\ValidationException
548
     */
549
    public function Link($action = null)
550
    {
551
        if ($page = $this->getPage()) {
552
            $link = $page->Link($action) . '#' . $this->getAnchor();
553
554
            $this->extend('updateLink', $link);
555
556
            return $link;
557
        }
558
559
        return null;
560
    }
561
562
    /**
563
     * @param string|null $action
564
     * @return string
565
     * @throws \Psr\Container\NotFoundExceptionInterface
566
     * @throws \SilverStripe\ORM\ValidationException
567
     */
568
    public function PreviewLink($action = null)
569
    {
570
        $action = $action . '?ElementalPreview=' . mt_rand();
571
        $link = $this->Link($action);
572
        $this->extend('updatePreviewLink', $link);
573
574
        return $link;
575
    }
576
577
    /**
578
     * @return boolean
579
     */
580
    public function isCMSPreview()
581
    {
582
        if (Controller::has_curr()) {
583
            $controller = Controller::curr();
584
585
            if ($controller->getRequest()->requestVar('CMSPreview')) {
586
                return true;
587
            }
588
        }
589
590
        return false;
591
    }
592
593
    /**
594
     * @return null|string
595
     * @throws \Psr\Container\NotFoundExceptionInterface
596
     * @throws \SilverStripe\ORM\ValidationException
597
     */
598
    public function CMSEditLink()
599
    {
600
        $relationName = $this->getAreaRelationName();
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
            return null;
605
        }
606
607
        $link = Controller::join_links(
608
            singleton(CMSPageEditController::class)->Link('EditForm'),
609
            $page->ID,
610
            'field/' . $relationName . '/item/',
611
            $this->ID
612
        );
613
614
        $link = Controller::join_links(
615
            $link,
616
            'edit'
617
        );
618
619
        $this->extend('updateCMSEditLink', $link);
620
621
        return $link;
622
    }
623
624
    /**
625
     * Retrieve a elemental area relation for creating cms links
626
     *
627
     * @return int|string The name of a valid elemental area relation
628
     * @throws \Psr\Container\NotFoundExceptionInterface
629
     * @throws \SilverStripe\ORM\ValidationException
630
     */
631
    public function getAreaRelationName()
632
    {
633
        $page = $this->getPage();
634
635
        if ($page) {
636
            $has_one = $page->config()->get('has_one');
637
            $area = $this->Parent();
638
639
            foreach ($has_one as $relationName => $relationClass) {
640
                if ($relationClass === $area->ClassName) {
641
                    return $relationName;
642
                }
643
            }
644
        }
645
646
        return 'ElementalArea';
647
    }
648
649
    /**
650
     * Sanitise a model class' name for inclusion in a link.
651
     *
652
     * @return string
653
     */
654
    public function sanitiseClassName($class, $delimiter = '-')
655
    {
656
        return str_replace('\\', $delimiter, $class);
657
    }
658
659
    public function unsanitiseClassName($class, $delimiter = '-')
660
    {
661
        return str_replace($delimiter, '\\', $class);
662
    }
663
664
    /**
665
     * @return null|string
666
     * @throws \Psr\Container\NotFoundExceptionInterface
667
     * @throws \SilverStripe\ORM\ValidationException
668
     */
669
    public function getEditLink()
670
    {
671
        return $this->CMSEditLink();
672
    }
673
674
    /**
675
     * @return DBField|null
676
     * @throws \Psr\Container\NotFoundExceptionInterface
677
     * @throws \SilverStripe\ORM\ValidationException
678
     */
679
    public function PageCMSEditLink()
680
    {
681
        if ($page = $this->getPage()) {
682
            return DBField::create_field('HTMLText', sprintf(
683
                '<a href="%s">%s</a>',
684
                $page->CMSEditLink(),
685
                $page->Title
686
            ));
687
        }
688
689
        return null;
690
    }
691
692
    /**
693
     * @return string
694
     */
695
    public function getMimeType()
696
    {
697
        return 'text/html';
698
    }
699
700
    /**
701
     * This can be overridden on child elements to create a summary for display
702
     * in GridFields.
703
     *
704
     * @return string
705
     */
706
    public function getSummary()
707
    {
708
        return '';
709
    }
710
711
712
    /**
713
     * Generate markup for element type icons suitable for use in GridFields.
714
     *
715
     * @return null|DBHTMLText
716
     */
717
    public function getIcon()
718
    {
719
        $data = ArrayData::create([]);
720
721
        $iconClass = $this->config()->get('icon');
722
        if ($iconClass) {
723
            $data->IconClass = $iconClass;
724
725
            // Add versioned states (rendered as a circle over the icon)
726
            if ($this->hasExtension(Versioned::class)) {
727
                $data->IsVersioned = true;
728
                if ($this->isOnDraftOnly()) {
0 ignored issues
show
Bug introduced by
The method isOnDraftOnly() 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

728
                if ($this->/** @scrutinizer ignore-call */ isOnDraftOnly()) {
Loading history...
729
                    $data->VersionState = 'draft';
730
                    $data->VersionStateTitle = _t(
731
                        'SilverStripe\\Versioned\\VersionedGridFieldState\\VersionedGridFieldState.ADDEDTODRAFTHELP',
732
                        'Item has not been published yet'
733
                    );
734
                } elseif ($this->isModifiedOnDraft()) {
0 ignored issues
show
Bug introduced by
The method isModifiedOnDraft() 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

734
                } elseif ($this->/** @scrutinizer ignore-call */ isModifiedOnDraft()) {
Loading history...
735
                    $data->VersionState = 'modified';
736
                    $data->VersionStateTitle = $data->VersionStateTitle = _t(
737
                        'SilverStripe\\Versioned\\VersionedGridFieldState\\VersionedGridFieldState.MODIFIEDONDRAFTHELP',
738
                        'Item has unpublished changes'
739
                    );
740
                }
741
            }
742
743
            return $data->renderWith(__CLASS__ . '/PreviewIcon');
744
        }
745
746
        return null;
747
    }
748
749
    /**
750
     * Get a description for this content element, if available
751
     *
752
     * @return string
753
     */
754
    public function getDescription()
755
    {
756
        $description = $this->config()->uninherited('description');
757
        if ($description) {
758
            return _t(__CLASS__ . '.Description', $description);
759
        }
760
        return '';
761
    }
762
763
    /**
764
     * Generate markup for element type, with description suitable for use in
765
     * GridFields.
766
     *
767
     * @return DBField
768
     */
769
    public function getTypeNice()
770
    {
771
        $description = $this->getDescription();
772
        $desc = ($description) ? ' <span class="element__note"> &mdash; ' . $description . '</span>' : '';
773
774
        return DBField::create_field(
775
            'HTMLVarchar',
776
            $this->getType() . $desc
777
        );
778
    }
779
780
    /**
781
     * @return \SilverStripe\ORM\FieldType\DBHTMLText
782
     */
783
    public function getEditorPreview()
784
    {
785
        $templates = $this->getRenderTemplates('_EditorPreview');
786
        $templates[] = BaseElement::class . '_EditorPreview';
787
788
        return $this->renderWith($templates);
789
    }
790
791
    /**
792
     * @return Member
793
     */
794
    public function getAuthor()
795
    {
796
        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...
797
            return Member::get()->byId($this->AuthorID);
798
        }
799
800
        return null;
801
    }
802
803
    /**
804
     * Get a user defined style variant for this element, if available
805
     *
806
     * @return string
807
     */
808
    public function getStyleVariant()
809
    {
810
        $style = $this->Style;
811
        $styles = $this->config()->get('styles');
812
813
        if (isset($styles[$style])) {
814
            $style = strtolower($style);
815
        } else {
816
            $style = '';
817
        }
818
819
        $this->extend('updateStyleVariant', $style);
820
821
        return $style;
822
    }
823
824
    /**
825
     * @return mixed|null
826
     * @throws \Psr\Container\NotFoundExceptionInterface
827
     * @throws \SilverStripe\ORM\ValidationException
828
     */
829
    public function getPageTitle()
830
    {
831
        $page = $this->getPage();
832
833
        if ($page) {
834
            return $page->Title;
835
        }
836
837
        return null;
838
    }
839
840
    /**
841
     * Get a "nice" label for use in the block history GridField
842
     *
843
     * @return string
844
     */
845
    public function getVersionedStateNice()
846
    {
847
        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...
848
            return _t(__CLASS__ . '.Published', 'Published');
849
        }
850
851
        return _t(__CLASS__ . '.Modified', 'Modified');
852
    }
853
854
    /**
855
     * Return a formatted date for use in the block history GridField
856
     *
857
     * @return string
858
     */
859
    public function getLastEditedNice()
860
    {
861
        return $this->dbObject('LastEdited')->Nice();
862
    }
863
}
864