Passed
Push — master ( d17640...0c3f03 )
by Robbie
01:58
created

BaseElement::getCMSFields()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 33
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 21
nc 3
nop 0
1
<?php
2
3
namespace DNADesign\Elemental\Models;
4
5
use Exception;
6
use DNADesign\Elemental\Controllers\ElementController;
7
use SilverStripe\CMS\Controllers\CMSPageEditController;
8
use SilverStripe\Control\Controller;
9
use SilverStripe\Control\Director;
10
use SilverStripe\Core\ClassInfo;
11
use SilverStripe\Core\Config\Config;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Core\Manifest\ModuleResourceLoader;
14
use SilverStripe\Forms\CheckboxField;
15
use SilverStripe\Forms\DropdownField;
16
use SilverStripe\Forms\HiddenField;
17
use SilverStripe\Forms\ReadonlyField;
18
use SilverStripe\Forms\TextField;
19
use SilverStripe\ORM\ArrayList;
20
use SilverStripe\ORM\CMSPreviewable;
21
use SilverStripe\ORM\DataObject;
22
use SilverStripe\ORM\DB;
23
use SilverStripe\ORM\FieldType\DBField;
24
use SilverStripe\ORM\Search\SearchContext;
25
use SilverStripe\Security\Permission;
26
use SilverStripe\SiteConfig\SiteConfig;
27
use SilverStripe\Versioned\Versioned;
28
use SilverStripe\View\Parsers\URLSegmentFilter;
29
use SilverStripe\View\SSViewer;
30
31
class BaseElement extends DataObject implements CMSPreviewable
32
{
33
    /**
34
     * Override this on your custom elements to specify a cms icon
35
     * @var string
36
     */
37
    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...
38
39
    /**
40
     * @var array
41
     */
42
    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...
43
        'Title' => 'Varchar(255)',
44
        'Sort' => 'Int',
45
        'ExtraClass' => 'Varchar(255)'
46
    ];
47
48
    /**
49
     * @var array
50
     */
51
    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...
52
        'Parent' => ElementalArea::class
53
    ];
54
55
    /**
56
     * @var array
57
     */
58
    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...
59
        Versioned::class
60
    ];
61
62
    /**
63
     * @var string
64
     */
65
    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...
66
67
    /**
68
     * @var string
69
     */
70
    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...
71
72
    /**
73
     * @var string
74
     */
75
    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...
76
77
    /**
78
     * @var ElementController
79
     */
80
    protected $controller;
81
82
    /**
83
     * @var string
84
     */
85
    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...
86
87
    /**
88
     * @var string
89
     */
90
    private static $title = 'Content';
0 ignored issues
show
Unused Code introduced by
The property $title 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
    /**
93
     * @var string
94
     */
95
    private static $singular_name = 'Content';
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...
96
97
    /**
98
     * @var array
99
     */
100
    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...
101
        'EditorPreview' => 'Summary'
102
    ];
103
104
    /**
105
     * @var array
106
     */
107
    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...
108
        'ID' => [
109
            'field' => 'SilverStripe\Forms\NumericField'
110
        ],
111
        'Title',
112
        'LastEdited'
113
    ];
114
115
    /**
116
     * Enable for backwards compatibility
117
     *
118
     * @var boolean
119
     */
120
    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...
121
122
    /**
123
     * Store used anchor names, this is to avoid title clashes
124
     * when calling 'getAnchor'
125
     *
126
     * @var array
127
     */
128
    protected static $_used_anchors = [];
129
130
    /**
131
     * For caching 'getAnchor'
132
     *
133
     * @var string
134
     */
135
    protected $_anchor = null;
136
137
    /**
138
     * @return array
139
     */
140
    public function getAllowedElementClasses()
141
    {
142
        $classes = [];
143
144
        foreach (ClassInfo::subclassesFor(DataObject::class) as $className) {
145
            if (Injector::inst()->get($className)->hasExtension(ElementPageExtension::class)) {
0 ignored issues
show
Bug introduced by
The type DNADesign\Elemental\Models\ElementPageExtension 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...
146
                $classes[] = $className;
147
            }
148
        }
149
150
        $allowed = [];
151
152
        foreach ($classes as $className) {
153
            $elements = Config::inst()->get($className, 'allowed_elements');
154
155
            if ($elements) {
156
                $allowed = array_merge($allowed, $elements);
157
            }
158
        }
159
160
        $allowed = array_unique($allowed);
161
162
        $elements = [];
163
164
        foreach ($allowed as $className) {
165
            $elements[$className] = _t($className, Config::inst()->get($className, 'title'));
166
        }
167
168
        $this->invokeWithExtensions('updateAllowedElementClasses', $elements);
169
170
        return $elements;
171
    }
172
173
    /**
174
     * Basic permissions, defaults to page perms where possible.
175
     *
176
     * @param Member $member
0 ignored issues
show
Bug introduced by
The type DNADesign\Elemental\Models\Member 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...
177
     *
178
     * @return boolean
179
     */
180 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...
181
    {
182
        if ($this->hasMethod('getPage')) {
183
            if ($page = $this->getPage()) {
184
                return $page->canView($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
     *
196
     * @return boolean
197
     */
198 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...
199
    {
200
        if ($this->hasMethod('getPage')) {
201
            if ($page = $this->getPage()) {
202
                return $page->canEdit($member);
203
            }
204
        }
205
206
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
207
    }
208
209
    /**
210
     * Basic permissions, defaults to page perms where possible.
211
     *
212
     * Uses archive not delete so that current stage is respected i.e if a
213
     * element is not published, then it can be deleted by someone who doesn't
214
     * have publishing permissions.
215
     *
216
     * @param Member $member
217
     *
218
     * @return boolean
219
     */
220 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...
221
    {
222
        if ($this->hasMethod('getPage')) {
223
            if ($page = $this->getPage()) {
224
                return $page->canArchive($member);
225
            }
226
        }
227
228
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
229
    }
230
231
    /**
232
     * Basic permissions, defaults to page perms where possible.
233
     *
234
     * @param Member $member
235
     * @param array $context
236
     *
237
     * @return boolean
238
     */
239
    public function canCreate($member = null, $context = array())
240
    {
241
        return (Permission::check('CMS_ACCESS', 'any', $member)) ? true : null;
242
    }
243
244
    /**
245
     *
246
     */
247
    public function onBeforeWrite()
248
    {
249
        parent::onBeforeWrite();
250
251
        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...
252
            if ($elementalArea = ElementalArea::get()->byID($areaID)) {
253
                $elementalArea->write();
254
            }
255
        }
256
257
        if (!$this->Sort) {
258
            $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...
259
260
            $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...
261
        }
262
    }
263
264
    /**
265
     * @return FieldList
0 ignored issues
show
Bug introduced by
The type DNADesign\Elemental\Models\FieldList 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...
266
     */
267
    public function getCMSFields()
268
    {
269
        $fields = $this->scaffoldFormFields(array(
270
            'includeRelations' => ($this->ID > 0),
271
            'tabbed' => true,
272
            'ajaxSafe' => true
273
        ));
274
275
        $fields->removeByName('ListID');
276
        $fields->removeByName('ParentID');
277
        $fields->removeByName('Sort');
278
        $fields->removeByName('ExtraClass');
279
280
        $title = $fields->fieldByName('Root.Main.Title');
0 ignored issues
show
Unused Code introduced by
The assignment to $title is dead and can be removed.
Loading history...
281
        $fields->addFieldToTab(
282
            'Root.Settings',
283
            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

283
            TextField::create(/** @scrutinizer ignore-type */ 'ExtraClass', _t(__CLASS__ . '.ExtraCssClassesLabel', 'Custom CSS classes'))
Loading history...
284
                ->setAttribute('placeholder', _t(__CLASS__ . '.ExtraCssClassesPlaceholder', 'my_class another_class'))
285
        );
286
287
        if ($this->IsInDB()) {
288
            if ($this->hasExtension('VersionViewerDataObject')) {
289
                $fields = $this->addVersionViewer($fields, $this);
0 ignored issues
show
Bug introduced by
The method addVersionViewer() 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

289
                $fields = $this->/** @scrutinizer ignore-call */ addVersionViewer($fields, $this);
Loading history...
290
            }
291
        }
292
293
        $fields->push($liveLinkField = new HiddenField('AbsoluteLink', false, Director::absoluteURL($this->PreviewLink())));
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type null|string expected by parameter $title of SilverStripe\Forms\HiddenField::__construct(). ( Ignorable by Annotation )

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

293
        $fields->push($liveLinkField = new HiddenField('AbsoluteLink', /** @scrutinizer ignore-type */ false, Director::absoluteURL($this->PreviewLink())));
Loading history...
294
        $fields->push($liveLinkField = new HiddenField('LiveLink', false, Director::absoluteURL($this->Link())));
295
        $fields->push($stageLinkField = new HiddenField('StageLink', false, Director::absoluteURL($this->PreviewLink())));
296
297
        $this->extend('updateCMSFields', $fields);
298
299
        return $fields;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $fields also could return the type SilverStripe\Forms\FieldList which is incompatible with the documented return type DNADesign\Elemental\Models\FieldList.
Loading history...
300
    }
301
302
    /**
303
     * Used in ElementalAdmin
304
     */
305
    public function getDefaultSearchContext()
306
    {
307
        $fields = $this->scaffoldSearchFields();
308
        $elements = BaseElement::all_allowed_elements();
0 ignored issues
show
Bug introduced by
The method all_allowed_elements() does not exist on DNADesign\Elemental\Models\BaseElement. It seems like you code against a sub-type of DNADesign\Elemental\Models\BaseElement such as DNADesign\Elemental\Models\ElementContent or DNADesign\Elemental\Tests\Src\TestElement. ( Ignorable by Annotation )

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

308
        $elements = BaseElement::/** @scrutinizer ignore-call */ all_allowed_elements();
Loading history...
309
310
        if (!$elements) {
311
            $elements = ClassInfo::subclassesFor(self::class);
312
        }
313
        foreach ($elements as $key => $value) {
314
            if ($key == self::class) {
315
                unset($elements[$key]);
316
                continue;
317
            }
318
            $elements[$key] = $this->stripNamespacing($value);
319
        }
320
321
        $fields->push(
322
            DropdownField::create('ClassName', _t(__CLASS__.'.ELEMENTTYPE', 'Element Type'), $elements)
0 ignored issues
show
Bug introduced by
'ClassName' 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

322
            DropdownField::create(/** @scrutinizer ignore-type */ 'ClassName', _t(__CLASS__.'.ELEMENTTYPE', 'Element Type'), $elements)
Loading history...
323
                ->setEmptyString(_t(__CLASS__.'.ALL', 'All types'))
324
        );
325
326
        $filters = $this->owner->defaultSearchFilters();
0 ignored issues
show
Bug Best Practice introduced by
The property owner does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug introduced by
The method defaultSearchFilters() does not exist on null. ( Ignorable by Annotation )

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

326
        $filters = $this->owner->/** @scrutinizer ignore-call */ defaultSearchFilters();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
327
328
        return new SearchContext(
329
            self::class,
330
            $fields,
331
            $filters
332
        );
333
    }
334
335
    /**
336
     * @return string
337
     */
338
    public function i18n_singular_name()
339
    {
340
        return _t(__CLASS__, $this->config()->title);
341
    }
342
343
    /**
344
     * @return string
345
     */
346
    public function getType()
347
    {
348
        return $this->i18n_singular_name();
349
    }
350
351
    /**
352
     * @return string
353
     */
354
    public function getTitle()
355
    {
356
        if ($title = $this->getField('Title')) {
357
            return $title;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $title also could return the type object which is incompatible with the documented return type string.
Loading history...
358
        } else {
359
            if (!$this->isInDb()) {
360
                return;
361
            }
362
363
            return $this->config()->title;
364
        }
365
    }
366
367
    /**
368
     * @param ElementController
369
     *
370
     * @return $this
371
     */
372
    public function setController($controller)
373
    {
374
        $this->controller = $controller;
375
376
        return $this;
377
    }
378
379
    /**
380
     * @throws Exception
381
     *
382
     * @return ElementController
383
     */
384
    public function getController()
385
    {
386
        if ($this->controller) {
387
            return $this->controller;
388
        }
389
390
        $controllerClass = self::config()->controller_class;
391
392
        if (!class_exists($controllerClass)) {
393
            throw new Exception('Could not find controller class ' . $controllerClass . ' as defined in ' . static::class);
394
        }
395
396
        $this->controller = Injector::inst()->create($controllerClass, $this);
397
        $this->controller->doInit();
398
        return $this->controller;
399
    }
400
401
    /**
402
     * @return Controller
403
     */
404
    public function Top()
405
    {
406
        return (Controller::has_curr()) ? Controller::curr() : null;
407
    }
408
409
    /**
410
     * Default way to render element in templates. Note that all blocks should
411
     * be rendered through their {@link ElementController} class as this
412
     * contains the holder styles.
413
     *
414
     * @return string HTML
415
     */
416
    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

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

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

593
            /** @scrutinizer ignore-call */ $this->getPage(true)->ID,

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...
594
            'field/' . $relationName . '/item/',
595
            $this->ID
596
        );
597
598
        if ($inList) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $inList seems to be never defined.
Loading history...
599
            return $link;
600
        }
601
602
        return Controller::join_links(
603
            $link,
604
            'edit'
605
        );
606
    }
607
608
    /**
609
     * Retrieve a elemental area relation for creating cms links
610
     *
611
     * @return string - the name of a valid elemental area relation
612
     */
613
    public function getAreaRelationName()
614
    {
615
        $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

615
        $page = /** @scrutinizer ignore-call */ $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...
616
        $has_one = $page->config()->get('has_one');
617
        $area = $this->Parent();
618
619
        foreach ($has_one as $relationName => $relationClass) {
620
            if ($relationClass === $area->ClassName) {
621
                return $relationName;
622
            }
623
        }
624
625
        return 'ElementalArea';
626
    }
627
628
    /**
629
     * Sanitise a model class' name for inclusion in a link.
630
     *
631
     * @return string
632
     */
633
    protected function sanitiseClassName($class, $delimiter = '-')
634
    {
635
        return str_replace('\\', $delimiter, $class);
636
    }
637
638
    /**
639
     * @return string
640
     */
641
    public function getEditLink()
642
    {
643
        return $this->CMSEditLink();
644
    }
645
646
    /**
647
     * @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...
648
     */
649
    public function PageCMSEditLink()
650
    {
651
        if ($page = $this->getPage()) {
652
            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...
653
                '<a href="%s">%s</a>',
654
                $page->CMSEditLink(),
655
                $page->Title
656
            ));
657
        }
658
    }
659
660
    /**
661
     * @return string
662
     */
663
    public function getMimeType()
664
    {
665
        return 'text/html';
666
    }
667
668
    /**
669
     * This can be overridden on child elements to create a summary for display
670
     * in GridFields.
671
     *
672
     * @return string
673
     */
674
    public function getSummary()
675
    {
676
        return '';
677
    }
678
679
680
    /**
681
     * Generate markup for element type icons suitable for use in GridFields.
682
     *
683
     * @return DBField
684
     */
685
    public function getIcon()
686
    {
687
        $icon = $this->config()->get('icon');
688
689
        if ($icon) {
690
            $icon = ModuleResourceLoader::resourceURL($icon);
691
692
            return DBField::create_field('HTMLVarchar', '<img width="16px" src="' . Director::absoluteBaseURL() . $icon . '" alt="" />');
693
        }
694
    }
695
696
    /**
697
     * Generate markup for element type, with description suitable for use in
698
     * GridFields.
699
     *
700
     * @return DBField
701
     */
702
    public function getTypeNice()
703
    {
704
        $description = $this->config()->get('description');
705
706
        return DBField::create_field('HTMLVarchar', $this->ElementType .' <span class="el-description"> &mdash; ' . $description . '</span>');
0 ignored issues
show
Bug Best Practice introduced by
The property ElementType does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
707
    }
708
709
    /**
710
     * @return HTMLText
711
     */
712
    public function getEditorPreview()
713
    {
714
        $templates = $this->getRenderTemplates('_EditorPreview');
715
        $templates[] = BaseElement::class . '_EditorPreview';
716
717
        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...
718
    }
719
}
720