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

DataObjectElasticExtension::doIndex()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 12
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 Elastic\Elasticsearch\Response\Elasticsearch;
16
use Exception;
17
use Firesphere\ElasticSearch\Indexes\ElasticIndex;
18
use Firesphere\ElasticSearch\Services\ElasticCoreService;
19
use Http\Promise\Promise;
20
use Psr\Container\NotFoundExceptionInterface;
21
use Psr\Log\LoggerInterface;
22
use SilverStripe\Core\Injector\Injector;
23
use SilverStripe\ORM\ArrayList;
24
use SilverStripe\ORM\DataExtension;
25
use SilverStripe\ORM\DataObject;
26
use SilverStripe\ORM\ValidationException;
27
use SilverStripe\Versioned\Versioned;
28
29
/**
30
 * Class \Firesphere\ElasticSearch\Extensions\DataObjectElasticExtension
31
 *
32
 * @property DataObject|DataObjectElasticExtension $owner
33
 */
34
class DataObjectElasticExtension extends DataExtension
35
{
36
    /**
37
     * @throws NotFoundExceptionInterface
38
     * @throws ValidationException
39
     */
40
    public function onAfterDelete()
41
    {
42
        parent::onAfterDelete();
43
        $this->deleteFromElastic();
44
    }
45
46
    /**
47
     * Can be called directly, if a DataObject needs to be removed
48
     * immediately.
49
     * @return bool|Elasticsearch|Promise
50
     * @throws NotFoundExceptionInterface
51
     */
52
    public function deleteFromElastic()
53
    {
54
        $result = false;
55
        $service = new ElasticCoreService();
56
        $indexes = $service->getValidIndexes();
57
        foreach ($indexes as $index) {
58
            /** @var ElasticIndex $idx */
59
            $idx = Injector::inst()->get($index);
60
            $config = ElasticIndex::config()->get($idx->getIndexName());
61
            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...
62
                $deleteQuery = $this->getDeleteQuery($index);
63
                $result = $this->executeQuery($service, $deleteQuery);
64
            }
65
        }
66
67
        return $result;
68
    }
69
70
    /**
71
     * @param mixed $index
72
     * @return array
73
     */
74
    private function getDeleteQuery(mixed $index): array
75
    {
76
        return [
77
            'index' => $index,
78
            'body'  => [
79
                'query' => [
80
                    'match' => [
81
                        'id' => sprintf('%s-%s', $this->owner->ClassName, $this->owner->ID)
2 ignored issues
show
Bug introduced by
The property ID does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you mean IDs?
Loading history...
Bug Best Practice introduced by
The property ClassName does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you maybe forget to declare it?
Loading history...
82
                    ]
83
                ]
84
            ]
85
        ];
86
    }
87
88
    /**
89
     * @param ElasticCoreService $service
90
     * @param array $deleteQuery
91
     * @return Elasticsearch|Promise|bool
92
     * @throws NotFoundExceptionInterface
93
     */
94
    protected function executeQuery(ElasticCoreService $service, array $deleteQuery)
95
    {
96
        try {
97
            return $service->getClient()->deleteByQuery($deleteQuery);
98
        } catch (Exception $e) {
99
            // DirtyClass handling is a DataObject Search Core extension
100
            $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

100
            /** @scrutinizer ignore-call */ 
101
            $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...
101
            $ids = json_decode($dirty->IDs ?? '[]');
102
            $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...
103
            $dirty->IDs = json_encode($ids);
104
            $dirty->write();
105
            /** @var LoggerInterface $logger */
106
            $logger = Injector::inst()->get(LoggerInterface::class);
107
            $logger->error($e->getMessage(), $e->getTrace());
108
109
            return false;
110
        }
111
    }
112
113
    /**
114
     * Reindex after write, if it's an indexed new/updated object
115
     * @throws ClientResponseException
116
     * @throws NotFoundExceptionInterface
117
     * @throws ServerResponseException
118
     */
119
    public function onAfterWrite()
120
    {
121
        parent::onAfterWrite();
122
        if (
123
            !$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

123
            !$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...
124
            ($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

124
            ($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...
125
        ) {
126
            $this->pushToElastic();
127
        }
128
129
        // @codeCoverageIgnoreStart Elastic during tests isn't fast enough to pick this up properly
130
        if ($this->owner->hasField('ShowInSearch') &&
1 ignored issue
show
Bug introduced by
The method hasField() 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

130
        if ($this->owner->/** @scrutinizer ignore-call */ hasField('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...
131
            $this->owner->isChanged('ShowInSearch') &&
1 ignored issue
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

131
            $this->owner->/** @scrutinizer ignore-call */ 
132
                          isChanged('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...
132
            !$this->owner->ShowInSearch) {
1 ignored issue
show
Bug Best Practice introduced by
The property ShowInSearch does not exist on Firesphere\ElasticSearch...aObjectElasticExtension. Did you maybe forget to declare it?
Loading history...
133
            $this->deleteFromElastic();
134
        }
135
        // @codeCoverageIgnoreEnd
136
    }
137
138
    /**
139
     * This is a separate method from the delete action, as it's a different route
140
     * and query components.
141
     * It can be called to add an object to the index immediately, without
142
     * requiring a write.
143
     * @return array|void|bool
144
     * @throws ClientResponseException
145
     * @throws NotFoundExceptionInterface
146
     * @throws ServerResponseException
147
     */
148
    public function pushToElastic()
149
    {
150
        $result = false;
151
        $list = ArrayList::create();
152
        $list->push($this->owner);
153
        /** @var ElasticCoreService $service */
154
        $service = Injector::inst()->get(ElasticCoreService::class);
155
        foreach ($service->getValidIndexes() as $indexStr) {
156
            /** @var ElasticIndex $index */
157
            $index = Injector::inst()->get($indexStr);
158
            $idxConfig = ElasticIndex::config()->get($index->getIndexName());
159
            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...
160
                $result = $service->updateIndex($index, $list);
161
            }
162
        }
163
164
        return $result;
165
    }
166
}
167