Passed
Pull Request — master (#774)
by
unknown
05:46
created

DataExtension::assignTopPage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace DNADesign\Elemental\TopPage;
4
5
use DNADesign\Elemental\Models\BaseElement;
6
use DNADesign\Elemental\Models\ElementalArea;
7
use Page;
0 ignored issues
show
Bug introduced by
The type Page 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...
8
use SilverStripe\ORM\DataExtension as BaseDataExtension;
9
use SilverStripe\ORM\DataObject;
10
use SilverStripe\ORM\ValidationException;
11
use SilverStripe\Versioned\Versioned;
12
13
/**
14
 * Class DataExtension
15
 *
16
 * Top page data cache for improved performance
17
 * intended owners of this extension are @see BaseElement and @see ElementalArea
18
 * applying this extension to just one of these owners will not hinder top page functionality
19
 * but the performance gain will be smaller
20
 * it is recommended to apply this extension to BaseElement and for setups with deeper block nesting
21
 * it is recommended to cover ElementalArea as well
22
 *
23
 * @property int $TopPageID
24
 * @method Page TopPage()
25
 * @property BaseElement|ElementalArea|$this $owner
26
 * @package DNADesign\Elemental\TopPage
27
 */
28
class DataExtension extends BaseDataExtension
29
{
30
    /**
31
     * @config
32
     * @var array
33
     */
34
    private static $has_one = [
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
35
        'TopPage' => Page::class,
36
    ];
37
38
    /**
39
     * @config
40
     * @var array
41
     */
42
    private static $indexes = [
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
43
        'TopPageID' => true,
44
    ];
45
46
    /**
47
     * @var bool
48
     */
49
    private $skipTopPageUpdate = false;
50
51
    /**
52
     * Exension point in @see DataObject::onAfterWrite()
53
     */
54
    public function onAfterWrite(): void
55
    {
56
        $this->setTopPage();
57
    }
58
59
    /**
60
     * Exension point in @see DataObject::duplicate()
61
     */
62
    public function onBeforeDuplicate(): void
63
    {
64
        $this->clearTopPage();
65
    }
66
67
    /**
68
     * Exension point in @see DataObject::duplicate()
69
     */
70
    public function onAfterDuplicate(): void
71
    {
72
        $this->updateTopPage();
73
    }
74
75
    /**
76
     * Find top level page of a block or elemental area
77
     * this is very useful in case blocks are deeply nested
78
     *
79
     * for example:
80
     * page -> elemental area -> block -> elemental area -> block
81
     *
82
     * this lookup is very performant as is safe to use in a template as well
83
     *
84
     * @return Page|null
85
     * @throws ValidationException
86
     */
87
    public function getTopPage(): ?Page
88
    {
89
        $list = [$this->owner];
90
91
        while (count($list) > 0) {
92
            /** @var DataObject|DataExtension $item */
93
            $item = array_shift($list);
94
95
            if ($item instanceof Page) {
96
                // trivial case
97
                return $item;
98
            }
99
100
            if ($item->hasExtension(DataExtension::class) && $item->TopPageID > 0) {
0 ignored issues
show
Bug introduced by
The method hasExtension() does not exist on DNADesign\Elemental\TopPage\DataExtension. ( Ignorable by Annotation )

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

100
            if ($item->/** @scrutinizer ignore-call */ hasExtension(DataExtension::class) && $item->TopPageID > 0) {

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...
101
                // top page is stored inside data object - just fetch it via cached call
102
                $page = Page::get_by_id($item->TopPageID);
103
104
                if ($page !== null && $page->exists()) {
105
                    return $page;
106
                }
107
            }
108
109
            if ($item instanceof BaseElement) {
110
                // parent lookup via block
111
                $parent = $item->Parent();
112
113
                if ($parent !== null && $parent->exists()) {
114
                    array_push($list, $parent);
115
                }
116
117
                continue;
118
            }
119
120
            if ($item instanceof ElementalArea) {
121
                // parent lookup via elemental area
122
                $parent = $item->getOwnerPage();
123
124
                if ($parent !== null && $parent->exists()) {
125
                    array_push($list, $parent);
126
                }
127
128
                continue;
129
            }
130
        }
131
132
        return null;
133
    }
134
135
    /**
136
     * @param Page|null $page
137
     * @throws ValidationException
138
     */
139
    public function setTopPage(?Page $page = null): void
140
    {
141
        if ($this->skipTopPageUpdate) {
142
            return;
143
        }
144
145
        /** @var BaseElement|ElementalArea|Versioned|DataExtension $owner */
146
        $owner = $this->owner;
147
148
        if (!$owner->hasExtension(DataExtension::class)) {
149
            return;
150
        }
151
152
        if ($owner->TopPageID > 0) {
0 ignored issues
show
Bug Best Practice introduced by
The property TopPageID does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property TopPageID does not exist on DNADesign\Elemental\Models\ElementalArea. Since you implemented __get, consider adding a @property annotation.
Loading history...
153
            return;
154
        }
155
156
        $page = $page ?? $owner->getTopPage();
0 ignored issues
show
Bug introduced by
The method getTopPage() 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

156
        $page = $page ?? $owner->/** @scrutinizer ignore-call */ getTopPage();
Loading history...
Bug introduced by
The method getTopPage() does not exist on DNADesign\Elemental\Models\ElementalArea. 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

156
        $page = $page ?? $owner->/** @scrutinizer ignore-call */ getTopPage();
Loading history...
157
158
        if ($page === null) {
159
            return;
160
        }
161
162
        // set the page to properties in case this object is re-used later
163
        $this->assignTopPage($page);
164
165
        if ($owner->hasExtension(Versioned::class)) {
166
            $owner->writeWithoutVersion();
0 ignored issues
show
Bug introduced by
The method writeWithoutVersion() does not exist on DNADesign\Elemental\TopPage\DataExtension. ( Ignorable by Annotation )

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

166
            $owner->/** @scrutinizer ignore-call */ 
167
                    writeWithoutVersion();

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...
Bug introduced by
The method writeWithoutVersion() does not exist on DNADesign\Elemental\Models\ElementalArea. 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

166
            $owner->/** @scrutinizer ignore-call */ 
167
                    writeWithoutVersion();
Loading history...
Bug introduced by
The method writeWithoutVersion() 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

166
            $owner->/** @scrutinizer ignore-call */ 
167
                    writeWithoutVersion();
Loading history...
167
168
            return;
169
        }
170
171
        $owner->write();
0 ignored issues
show
Bug introduced by
The method write() does not exist on DNADesign\Elemental\TopPage\DataExtension. ( Ignorable by Annotation )

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

171
        $owner->/** @scrutinizer ignore-call */ 
172
                write();

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...
172
    }
173
174
    /**
175
     * Use this to wrap any code which is supposed to run without doing any top page updates
176
     *
177
     * @param callable $callback
178
     * @return mixed
179
     */
180
    public function withoutTopPageUpdate(callable $callback)
181
    {
182
        $this->skipTopPageUpdate = true;
183
184
        try {
185
            return $callback();
186
        } finally {
187
            $this->skipTopPageUpdate = false;
188
        }
189
    }
190
191
    /**
192
     * Register the object for top page update
193
     * this is a little bit roundabout way to do it, but it's necessary because when cloned object is written
194
     * the relations are not yet written so it's impossible to do a parent lookup at that time
195
     */
196
    protected function updateTopPage(): void
197
    {
198
        /** @var SiteTreeExtension $extension */
199
        $extension = singleton(SiteTreeExtension::class);
200
        $extension->addDuplicatedObject($this->owner);
0 ignored issues
show
Bug introduced by
It seems like $this->owner can also be of type DNADesign\Elemental\TopPage\DataExtension; however, parameter $object of DNADesign\Elemental\TopP...::addDuplicatedObject() does only seem to accept SilverStripe\ORM\DataObject, maybe add an additional type check? ( Ignorable by Annotation )

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

200
        $extension->addDuplicatedObject(/** @scrutinizer ignore-type */ $this->owner);
Loading history...
201
    }
202
203
    protected function assignTopPage(Page $page): void
204
    {
205
        $this->owner->TopPageID = (int) $page->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property TopPageID does not exist on DNADesign\Elemental\Models\ElementalArea. Since you implemented __set, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property TopPageID does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __set, consider adding a @property annotation.
Loading history...
206
    }
207
208
    /**
209
     * Clears top page relation, this is useful when duplicating object as the new object doesn't necessarily
210
     * belong to the original page
211
     */
212
    protected function clearTopPage(): void
213
    {
214
        $this->owner->TopPageID = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property TopPageID does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __set, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property TopPageID does not exist on DNADesign\Elemental\Models\ElementalArea. Since you implemented __set, consider adding a @property annotation.
Loading history...
215
    }
216
}
217