Passed
Pull Request — main (#50)
by Simon
01:10
created

DataObjectElasticExtension::onAfterDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 1
eloc 2
c 2
b 1
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
/**
3
 * class DataObjectExtension|Firesphere\ElasticSearch\Extensions\DataObjectExtension Adds checking if changes should be
4
 * pushed to Elastic
5
 *
6
 * @package Firesphere\Elastic\Search
7
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
8
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
9
 */
10
11
namespace Firesphere\ElasticSearch\Extensions;
12
13
use Elastic\Elasticsearch\Exception\ClientResponseException;
14
use Elastic\Elasticsearch\Exception\ServerResponseException;
15
use Exception;
16
use Firesphere\ElasticSearch\Indexes\ElasticIndex;
17
use Firesphere\ElasticSearch\Services\ElasticCoreService;
18
use Psr\Container\NotFoundExceptionInterface;
19
use Psr\Log\LoggerInterface;
20
use SilverStripe\Core\Injector\Injector;
21
use SilverStripe\ORM\ArrayList;
22
use SilverStripe\ORM\DataExtension;
23
use SilverStripe\ORM\DataObject;
24
use SilverStripe\ORM\ValidationException;
25
use SilverStripe\Versioned\Versioned;
26
27
/**
28
 * Class \Firesphere\ElasticSearch\Extensions\DataObjectElasticExtension
29
 *
30
 * @property DataObject|DataObjectElasticExtension $owner
31
 */
32
class DataObjectElasticExtension extends DataExtension
33
{
34
    /**
35
     * @throws NotFoundExceptionInterface
36
     * @throws ValidationException
37
     */
38
    public function onAfterDelete()
39
    {
40
        parent::onAfterDelete();
41
        $this->deleteFromElastic();
42
    }
43
44
    /**
45
     * Can be called directly, if a DataObject needs to be removed
46
     * immediately.
47
     * @return void
48
     * @throws NotFoundExceptionInterface
49
     */
50
    public function deleteFromElastic(): void
51
    {
52
        $service = new ElasticCoreService();
53
        $indexes = $service->getValidIndexes();
54
        foreach ($indexes as $index) {
55
            /** @var ElasticIndex $idx */
56
            $idx = Injector::inst()->get($index);
57
            $config = ElasticIndex::config()->get($idx->getIndexName());
58
            if (in_array($this->owner->ClassName, $config['Classes'])) {
1 ignored issue
show
Bug Best Practice introduced by
The property ClassName does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you maybe forget to declare it?
Loading history...
59
                $deleteQuery = $this->getDeleteQuery($index);
60
                $this->executeQuery($service, $deleteQuery);
61
            }
62
        }
63
    }
64
65
    /**
66
     * @param mixed $index
67
     * @return array
68
     */
69
    private function getDeleteQuery(mixed $index): array
70
    {
71
        return [
72
            'index' => $index,
73
            'body'  => [
74
                'query' => [
75
                    'match' => [
76
                        'id' => sprintf('%s-%s', $this->owner->ClassName, $this->owner->ID)
2 ignored issues
show
Bug Best Practice introduced by
The property ClassName does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you maybe forget to declare it?
Loading history...
Bug introduced by
The property ID does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you mean IDs?
Loading history...
77
                    ]
78
                ]
79
            ]
80
        ];
81
    }
82
83
    /**
84
     * @throws NotFoundExceptionInterface
85
     */
86
    protected function executeQuery(ElasticCoreService $service, array $deleteQuery): void
87
    {
88
        try {
89
            $service->getClient()->deleteByQuery($deleteQuery);
90
        } catch (Exception $e) {
91
            // DirtyClass handling is a DataObject Search Core extension
92
            $dirty = $this->owner->getDirtyClass('DELETE');
0 ignored issues
show
Bug introduced by
The method getDirtyClass() does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. ( Ignorable by Annotation )

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

92
            /** @scrutinizer ignore-call */ 
93
            $dirty = $this->owner->getDirtyClass('DELETE');

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...
93
            $ids = json_decode($dirty->IDs ?? '[]');
94
            $ids[] = $this->owner->ID;
1 ignored issue
show
Bug introduced by
The property ID does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you mean IDs?
Loading history...
95
            $dirty->IDs = json_encode($ids);
96
            $dirty->write();
97
            /** @var LoggerInterface $logger */
98
            $logger = Injector::inst()->get(LoggerInterface::class);
99
            $logger->error($e->getMessage(), $e->getTrace());
100
        }
101
    }
102
103
    /**
104
     * Reindex after write, if it's an indexed new/updated object
105
     * @throws ClientResponseException
106
     * @throws NotFoundExceptionInterface
107
     * @throws ServerResponseException
108
     */
109
    public function onAfterWrite()
110
    {
111
        parent::onAfterWrite();
112
        if (
113
            !$this->owner->hasExtension(Versioned::class) ||
0 ignored issues
show
Bug introduced by
The method hasExtension() does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. ( Ignorable by Annotation )

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

113
            !$this->owner->/** @scrutinizer ignore-call */ hasExtension(Versioned::class) ||

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...
114
            ($this->owner->hasExtension(Versioned::class) && $this->owner->isPublished())
0 ignored issues
show
Bug introduced by
The method isPublished() does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. ( Ignorable by Annotation )

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

114
            ($this->owner->hasExtension(Versioned::class) && $this->owner->/** @scrutinizer ignore-call */ isPublished())

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...
115
        ) {
116
            $this->doIndex();
117
        }
118
119
        // @codeCoverageIgnoreStart Elastic during tests isn't fast enough to pick this up properly
120
        if ($this->owner->isChanged('ShowInSearch') && !$this->owner->ShowInSearch) {
2 ignored issues
show
Bug introduced by
The method isChanged() does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. ( Ignorable by Annotation )

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

120
        if ($this->owner->/** @scrutinizer ignore-call */ isChanged('ShowInSearch') && !$this->owner->ShowInSearch) {

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 Best Practice introduced by
The property ShowInSearch does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you maybe forget to declare it?
Loading history...
121
            $this->deleteFromElastic();
122
        }
123
        // @codeCoverageIgnoreEnd
124
    }
125
126
    /**
127
     * This is a separate method from the delete action, as it's a different route
128
     * and query components.
129
     * It can be called to add an object to the index immediately, without
130
     * requiring a write.
131
     * @throws NotFoundExceptionInterface
132
     * @throws ClientResponseException
133
     * @throws ServerResponseException
134
     */
135
    public function doIndex()
136
    {
137
        $list = ArrayList::create();
138
        $list->push($this->owner);
139
        /** @var ElasticCoreService $service */
140
        $service = Injector::inst()->get(ElasticCoreService::class);
141
        foreach ($service->getValidIndexes() as $indexStr) {
142
            /** @var ElasticIndex $index */
143
            $index = Injector::inst()->get($indexStr);
144
            $idxConfig = ElasticIndex::config()->get($index->getIndexName());
145
            if (in_array($this->owner->ClassName, $idxConfig['Classes'])) {
1 ignored issue
show
Bug Best Practice introduced by
The property ClassName does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you maybe forget to declare it?
Loading history...
146
                $service->updateIndex($index, $list);
147
            }
148
        }
149
    }
150
}
151