Passed
Pull Request — master (#77)
by Marco
04:31 queued 02:43
created

DataObjectExtension::onAfterWrite()   A

Complexity

Conditions 6
Paths 10

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6.0061

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 18
c 3
b 0
f 0
dl 0
loc 27
ccs 17
cts 18
cp 0.9444
rs 9.0444
cc 6
nc 10
nop 0
crap 6.0061
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
    protected $canViewClasses = [];
44
45
    /**
46
     * @throws ValidationException
47
     */
48 16
    public function onAfterWrite()
49
    {
50 16
        parent::onAfterWrite();
51 16
        if (Controller::curr()->getRequest()->getURL() &&
52 16
            strpos('dev/build', Controller::curr()->getRequest()->getURL()) !== false
53
        ) {
54
            return;
55
        }
56
        /** @var DataObject $owner */
57 16
        $owner = $this->owner;
58 16
        if (!in_array($owner->ClassName, static::$excludedClasses, true)) {
59 16
            $record = $this->getDirtyClass($owner, self::WRITE);
60
61 16
            $ids = json_decode($record->IDs, 1) ?: [];
62
            try {
63 16
                $service = new SolrCoreService();
64 16
                $service->setInDebugMode(false);
65 16
                $service->updateItems(ArrayList::create([$owner]), SolrCoreService::UPDATE_TYPE);
66
                // If we don't get an exception, mark the item as clean
67
                // Added bonus, array_flip removes duplicates
68 16
                $values = array_flip($ids);
69 16
                unset($values[$owner->ID]);
70
71 16
                $record->IDs = json_encode(array_keys($values));
72 16
                $record->write();
73 2
            } catch (Exception $error) {
74 2
                $this->registerException($ids, $record, $error);
75
            }
76
        }
77 16
    }
78
79
    /**
80
     * @param DataObject $owner
81
     * @param string $type
82
     * @return DirtyClass
83
     * @throws ValidationException
84
     */
85 16
    protected function getDirtyClass(DataObject $owner, $type)
86
    {
87
        // Get the DirtyClass object for this item
88
        /** @var null|DirtyClass $record */
89 16
        $record = DirtyClass::get()->filter(['Class' => $owner->ClassName, 'Type' => $type])->first();
90 16
        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...
91 4
            $record = DirtyClass::create([
92 4
                'Class' => $owner->ClassName,
93 4
                'Type'  => $type
94
            ]);
95 4
            $record->write();
96
        }
97
98 16
        return $record;
99
    }
100
101
    /**
102
     * @param array $ids
103
     * @param $record
104
     * @param Exception $e
105
     */
106 2
    protected function registerException(array $ids, $record, Exception $error): void
107
    {
108
        /** @var DataObject $owner */
109 2
        $owner = $this->owner;
110 2
        $ids[] = $owner->ID;
111
        // If we don't get an exception, mark the item as clean
112 2
        $record->IDs = json_encode($ids);
113 2
        $record->write();
114 2
        $logger = Injector::inst()->get(LoggerInterface::class);
115 2
        $logger->warn(
116 2
            sprintf(
117 2
                'Unable to alter %s with ID %s',
118 2
                $owner->ClassName,
119 2
                $owner->ID
120
            )
121
        );
122 2
        $logger->error($error->getMessage());
123 2
    }
124
125
    /**
126
     * @throws ValidationException
127
     */
128
    public function onAfterDelete(): void
129
    {
130
        /** @var DataObject $owner */
131
        $owner = $this->owner;
132
        /** @var DirtyClass $record */
133
        $record = $this->getDirtyClass($owner, self::DELETE);
134
135
        $ids = json_decode($record->IDs, 1) ?: [];
136
        parent::onAfterDelete();
137
        try {
138
            (new SolrCoreService())->updateItems(ArrayList::create([$owner]), SolrCoreService::DELETE_TYPE);
139
            // If successful, remove it from the array
140
            // Added bonus, array_flip removes duplicates
141
            $values = array_flip($ids);
142
            unset($values[$owner->ID]);
143
144
            $record->IDs = json_encode(array_keys($values));
145
            $record->write();
146
        } catch (Exception $error) {
147
            $this->registerException($ids, $record, $error);
148
        }
149
    }
150
151
    /**
152
     * Get the view status for each member in this object
153
     * @return array
154
     */
155 14
    public function getViewStatus(): array
156
    {
157
        // Return empty if it's not allowed to show in search
158
        // The setting needs to be explicitly false, to avoid any possible collision
159
        // with objects not having the setting
160 14
        if ($this->owner->ShowInSearch === false) {
0 ignored issues
show
Bug Best Practice introduced by
The property ShowInSearch does not exist on Firesphere\SolrSearch\Ex...ons\DataObjectExtension. Did you maybe forget to declare it?
Loading history...
161
            return null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return null returns the type null which is incompatible with the type-hinted return array.
Loading history...
162
        }
163
        /** @var DataObject $owner */
164 14
        $owner = $this->owner;
165
        // Add null users if it's publicly viewable
166 14
        if ($owner->canView()) {
167 14
            return ['1-null'];
168
        }
169
170
        $return = [];
171
        if (!self::$members) {
172
            self::$members = Member::get();
173
        }
174
175
        foreach (self::$members as $member) {
176
            $return[] = sprintf('%s-%s', $owner->canView($member), $member->ID);
177
        }
178
179
        return $return;
180
    }
181
}
182