Completed
Push — master ( ff1c82...da0740 )
by
unknown
12s
created

src/Models/ElementalArea.php (6 issues)

1
<?php
2
3
namespace DNADesign\Elemental\Models;
4
5
use DNADesign\Elemental\Extensions\ElementalAreasExtension;
6
use SilverStripe\CMS\Model\SiteTree;
7
use SilverStripe\Core\ClassInfo;
8
use SilverStripe\Core\Extensible;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\ORM\ArrayList;
11
use SilverStripe\ORM\DataObject;
12
use SilverStripe\ORM\FieldType\DBField;
13
use SilverStripe\ORM\FieldType\DBHTMLText;
14
use SilverStripe\ORM\HasManyList;
15
use SilverStripe\ORM\UnsavedRelationList;
16
use SilverStripe\Versioned\Versioned;
17
18
/**
19
 * Class ElementalArea
20
 * @package DNADesign\Elemental\Models
21
 *
22
 * @property string $OwnerClassName
23
 *
24
 * @method HasManyList|BaseElement[] Elements()
25
 */
26
class ElementalArea extends DataObject
27
{
28
    private static $db = [
0 ignored issues
show
The private property $db is not used, and could be removed.
Loading history...
29
        'OwnerClassName' => 'Varchar(255)',
30
    ];
31
32
    private static $has_many = [
0 ignored issues
show
The private property $has_many is not used, and could be removed.
Loading history...
33
        'Elements' => BaseElement::class,
34
    ];
35
36
    private static $extensions = [
0 ignored issues
show
The private property $extensions is not used, and could be removed.
Loading history...
37
        Versioned::class,
38
    ];
39
40
    private static $owns = [
0 ignored issues
show
The private property $owns is not used, and could be removed.
Loading history...
41
        'Elements',
42
    ];
43
44
    private static $cascade_deletes = [
0 ignored issues
show
The private property $cascade_deletes is not used, and could be removed.
Loading history...
45
        'Elements',
46
    ];
47
48
    private static $cascade_duplicates = [
49
        'Elements',
50
    ];
51
52
    private static $summary_fields = [
0 ignored issues
show
The private property $summary_fields is not used, and could be removed.
Loading history...
53
        'Title' => 'Title',
54
    ];
55
56
    private static $table_name = 'ElementalArea';
57
58
    /**
59
     * Cache various data to improve CMS load time
60
     *
61
     * @internal
62
     * @var array
63
     */
64
    protected $cacheData = [];
65
66
    /**
67
     * @return array
68
     */
69
    public function supportedPageTypes()
70
    {
71
        $elementalClasses = [];
72
73
        foreach (ClassInfo::getValidSubClasses(SiteTree::class) as $class) {
74
            if (Extensible::has_extension($class, ElementalAreasExtension::class)) {
75
                $elementalClasses[] = $class;
76
            }
77
        }
78
79
        return $elementalClasses;
80
    }
81
82
    /**
83
     * @return DBHTMLText
84
     */
85
    public function forTemplate()
86
    {
87
        return $this->renderWith(static::class);
88
    }
89
90
    /**
91
     * Necessary to display results in CMS site search.
92
     *
93
     * @return DBField
94
     */
95
    public function Breadcrumbs()
96
    {
97
        $ownerClassName = $this->OwnerClassName;
98
99
        if ($owner = $ownerClassName::get()->filter('ElementalAreaID', $this->ID)->first()) {
100
            return DBField::create_field('HTMLText', sprintf(
101
                '<a href="%s">%s</a>',
102
                $owner->CMSEditLink(),
103
                $owner->Title
104
            ));
105
        }
106
107
        return null;
108
    }
109
110
    /**
111
     * Used in template instead of {@link Elements()} to wrap each element in
112
     * its' controller, making it easier to access and process form logic and
113
     * actions stored in {@link ElementController}.
114
     *
115
     * @return ArrayList
116
     * @throws \Exception
117
     */
118
    public function ElementControllers()
119
    {
120
        // Don't try and process unsaved lists
121
        if ($this->Elements() instanceof UnsavedRelationList) {
122
            return ArrayList::create();
123
        }
124
125
        $controllers = ArrayList::create();
126
        $items = $this->Elements()->filterByCallback(function (BaseElement $item) {
127
            return $item->canView();
128
        });
129
130
        if (!is_null($items)) {
131
            foreach ($items as $element) {
132
                $controller = $element->getController();
133
                $controllers->push($controller);
134
            }
135
        }
136
137
        return $controllers;
138
    }
139
140
    /**
141
     * @return null|DataObject
142
     * @throws \Psr\Container\NotFoundExceptionInterface
143
     * @throws \SilverStripe\ORM\ValidationException
144
     */
145
    public function getOwnerPage()
146
    {
147
        // Allow for repeated calls to read from cache
148
        if (isset($this->cacheData['owner_page'])) {
149
            return $this->cacheData['owner_page'];
150
        }
151
152
        if ($this->OwnerClassName) {
153
            $class = $this->OwnerClassName;
154
            $instance = Injector::inst()->get($class);
155
            if (!ClassInfo::hasMethod($instance, 'getElementalRelations')) {
156
                return null;
157
            }
158
            $elementalAreaRelations = $instance->getElementalRelations();
159
160
            foreach ($elementalAreaRelations as $eaRelationship) {
161
                $areaID = $eaRelationship . 'ID';
162
163
                $currentStage = Versioned::get_stage() ?: Versioned::DRAFT;
164
                $page = Versioned::get_by_stage($class, $currentStage)->filter($areaID, $this->ID)->first();
165
166
                if ($page) {
167
                    $this->cacheData['owner_page'] = $page;
168
                    return $page;
169
                }
170
            }
171
        }
172
173
        foreach ($this->supportedPageTypes() as $class) {
174
            $instance = Injector::inst()->get($class);
175
            if (!ClassInfo::hasMethod($instance, 'getElementalRelations')) {
176
                return null;
177
            }
178
            $elementalAreaRelations = $instance->getElementalRelations();
179
180
            foreach ($elementalAreaRelations as $eaRelationship) {
181
                $areaID = $eaRelationship . 'ID';
182
                $page = Versioned::get_by_stage($class, Versioned::DRAFT)->filter($areaID, $this->ID)->first();
183
184
                if ($page) {
185
                    if ($this->OwnerClassName !== $class) {
186
                        $this->OwnerClassName = $class;
187
188
                        // Avoid recursion: only write if it's already in the database
189
                        if ($this->isInDB()) {
190
                            $this->write();
191
                        }
192
                    }
193
194
                    $this->cacheData['area_relation_name'] = $page;
195
                    return $page;
196
                }
197
            }
198
        }
199
200
        return null;
201
    }
202
203
    /**
204
     * @param null $member
205
     * @return bool
206
     * @throws \Psr\Container\NotFoundExceptionInterface
207
     * @throws \SilverStripe\ORM\ValidationException
208
     */
209
    public function canEdit($member = null)
210
    {
211
        if (parent::canEdit($member)) {
212
            return true;
213
        }
214
215
        $ownerPage = $this->getOwnerPage();
216
        if ($ownerPage !== null) {
217
            return $this->getOwnerPage()->canEdit($member);
218
        }
219
220
        return false;
221
    }
222
223
    /**
224
     * @param null $member
225
     * @return bool
226
     * @throws \Psr\Container\NotFoundExceptionInterface
227
     * @throws \SilverStripe\ORM\ValidationException
228
     */
229
    public function canView($member = null)
230
    {
231
        if (parent::canEdit($member)) {
232
            return true;
233
        }
234
235
        $ownerPage = $this->getOwnerPage();
236
        if ($ownerPage !== null) {
237
            return $this->getOwnerPage()->canView($member);
238
        }
239
240
        return false;
241
    }
242
}
243