Passed
Push — sheepy/introspection ( 851cdd...69e16c )
by Marco
06:22
created

DataObjectExtension::getMemberPermissions()   A

Complexity

Conditions 6
Paths 13

Size

Total Lines 24
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
c 1
b 0
f 0
dl 0
loc 24
rs 9.2222
ccs 0
cts 0
cp 0
cc 6
nc 13
nop 1
crap 42
1
<?php
2
3
4
namespace Firesphere\SolrSearch\Extensions;
5
6
use Exception;
7
use Firesphere\SolrSearch\Models\DirtyClass;
8
use Firesphere\SolrSearch\Services\SolrCoreService;
9
use Psr\Log\LoggerInterface;
10
use SilverStripe\Assets\File;
11
use SilverStripe\CMS\Model\SiteTree;
12
use SilverStripe\Control\Controller;
13
use SilverStripe\Core\Injector\Injector;
14
use SilverStripe\ORM\ArrayList;
15
use SilverStripe\ORM\DataExtension;
16
use SilverStripe\ORM\DataList;
17
use SilverStripe\ORM\DataObject;
18
use SilverStripe\ORM\ValidationException;
19
use SilverStripe\Security\Group;
20
use SilverStripe\Security\Member;
21
use SilverStripe\SiteConfig\SiteConfig;
22
use SilverStripe\Versioned\ChangeSet;
23
use SilverStripe\Versioned\ChangeSetItem;
24
25
/**
26
 * Class \Firesphere\SolrSearch\Compat\DataObjectExtension
27
 *
28
 * @property File|SiteConfig|SiteTree|Group|Member|DataObjectExtension $owner
29
 */
30
class DataObjectExtension extends DataExtension
31
{
32
    public const WRITE = 'write';
33
    public const DELETE = 'delete';
34
    /**
35
     * @var DataList
36
     */
37
    protected static $members;
38
    protected static $excludedClasses = [
39
        DirtyClass::class,
40
        ChangeSet::class,
41
        ChangeSetItem::class,
42
    ];
43
    /**
44
     * @var array
45
     */
46
    protected static $canViewClasses = [];
47
48 17
    /**
49
     * @throws ValidationException
50 17
     */
51 17
    public function onAfterWrite()
52 17
    {
53
        parent::onAfterWrite();
54
        if (Controller::curr()->getRequest()->getURL() &&
55
            strpos('dev/build', Controller::curr()->getRequest()->getURL()) !== false
56
        ) {
57 17
            return;
58 17
        }
59 17
        /** @var DataObject $owner */
60
        $owner = $this->owner;
61 17
        if (!in_array($owner->ClassName, static::$excludedClasses, true)) {
62
            $record = $this->getDirtyClass($owner, self::WRITE);
63 17
64 17
            $ids = json_decode($record->IDs, 1) ?: [];
65 17
            try {
66
                $service = new SolrCoreService();
67
                $service->setInDebugMode(false);
68 17
                $service->updateItems(ArrayList::create([$owner]), SolrCoreService::UPDATE_TYPE);
69 17
                // If we don't get an exception, mark the item as clean
70
                // Added bonus, array_flip removes duplicates
71 17
                $values = array_flip($ids);
72 17
                unset($values[$owner->ID]);
73 2
74 2
                $record->IDs = json_encode(array_keys($values));
75
                $record->write();
76
            } catch (Exception $error) {
77 17
                $this->registerException($ids, $record, $error);
78
            }
79
        }
80
    }
81
82
    /**
83
     * @param DataObject $owner
84
     * @param string $type
85 17
     * @return DirtyClass
86
     * @throws ValidationException
87
     */
88
    protected function getDirtyClass(DataObject $owner, $type)
89 17
    {
90 17
        // Get the DirtyClass object for this item
91 4
        /** @var null|DirtyClass $record */
92 4
        $record = DirtyClass::get()->filter(['Class' => $owner->ClassName, 'Type' => $type])->first();
93 4
        if (!$record || !$record->exists()) {
1 ignored issue
show
introduced by
$record is of type Firesphere\SolrSearch\Models\DirtyClass, thus it always evaluated to true.
Loading history...
94
            $record = DirtyClass::create([
95 4
                'Class' => $owner->ClassName,
96
                'Type'  => $type
97
            ]);
98 17
            $record->write();
99
        }
100
101
        return $record;
102
    }
103
104
    /**
105
     * @param array $ids
106 2
     * @param $record
107
     * @param Exception $e
108
     */
109 2
    protected function registerException(array $ids, $record, Exception $error): void
110 2
    {
111
        /** @var DataObject $owner */
112 2
        $owner = $this->owner;
113 2
        $ids[] = $owner->ID;
114 2
        // If we don't get an exception, mark the item as clean
115 2
        $record->IDs = json_encode($ids);
116 2
        $record->write();
117 2
        $logger = Injector::inst()->get(LoggerInterface::class);
118 2
        $logger->warn(
119 2
            sprintf(
120
                'Unable to alter %s with ID %s',
121
                $owner->ClassName,
122 2
                $owner->ID
123 2
            )
124
        );
125
        $logger->error($error->getMessage());
126
    }
127
128
    /**
129
     * @throws ValidationException
130
     */
131
    public function onAfterDelete(): void
132
    {
133
        /** @var DataObject $owner */
134
        $owner = $this->owner;
135
        /** @var DirtyClass $record */
136
        $record = $this->getDirtyClass($owner, self::DELETE);
137
138
        $ids = json_decode($record->IDs, 1) ?: [];
139
        parent::onAfterDelete();
140
        try {
141
            (new SolrCoreService())->updateItems(ArrayList::create([$owner]), SolrCoreService::DELETE_TYPE);
142
            // If successful, remove it from the array
143
            // Added bonus, array_flip removes duplicates
144
            $values = array_flip($ids);
145
            unset($values[$owner->ID]);
146
147
            $record->IDs = json_encode(array_keys($values));
148
            $record->write();
149
        } catch (Exception $error) {
150
            $this->registerException($ids, $record, $error);
151
        }
152
    }
153
154
    /**
155 14
     * Get the view status for each member in this object
156
     * @return array
157
     */
158
    public function getViewStatus(): array
159
    {
160 14
        // Return empty if it's not allowed to show in search
161
        // The setting needs to be explicitly false, to avoid any possible collision
162
        // with objects not having the setting
163
        /** @var DataObject|SiteTree $owner */
164 14
        $owner = $this->owner;
165
        // Return immediately if the owner has ShowInSearch not being `null`
166 14
        if ($owner->ShowInSearch === false || $owner->ShowInSearch === 0) {
167 14
            return [];
168
        }
169
170
        if (isset(self::$canViewClasses[$owner->ClassName]) && !$owner->hasField('ShowInSearch')) {
171
            return self::$canViewClasses[$owner->ClassName];
172
        }
173
174
        return $this->getMemberPermissions($owner);
175
    }
176
177
    /**
178
     * @param DataObject|SiteTree $owner
179
     * @return array
180
     */
181
    protected function getMemberPermissions($owner): array
182
    {
183
        $return = [];
184
185
        // Add null users if it's publicly viewable
186
        if ($owner->canView()) {
187
            return ['1-null'];
188
        }
189
190
        if (!self::$members) {
191
            self::$members = Member::get();
192
        }
193
194
        foreach (self::$members as $member) {
195
            if ($owner->canView($member)) {
196
                $return[] = sprintf('1-%s', $member->ID);
197
            }
198
        }
199
200
        if (!$owner->hasField('ShowInSearch')) {
201
            self::$canViewClasses[$owner->ClassName] = $return;
202
        }
203
204
        return $return;
205
    }
206
}
207