Passed
Push — sheepy/introspection ( 3c7ef5...e59db3 )
by Simon
07:33
created

DocumentFactory::getNext()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 3
Bugs 2 Features 0
Metric Value
eloc 7
c 3
b 2
f 0
dl 0
loc 15
ccs 5
cts 5
cp 1
rs 10
cc 3
nc 3
nop 2
crap 3

1 Method

Rating   Name   Duplication   Size   Complexity  
A DocumentFactory::isDebug() 0 3 1
1
<?php
2
3
4
namespace Firesphere\SolrSearch\Factories;
5
6
use Exception;
7
use Firesphere\SolrSearch\Extensions\DataObjectExtension;
8
use Firesphere\SolrSearch\Helpers\DataResolver;
9
use Firesphere\SolrSearch\Helpers\SearchIntrospection;
10
use Firesphere\SolrSearch\Helpers\Statics;
11
use Firesphere\SolrSearch\Indexes\BaseIndex;
12
use Firesphere\SolrSearch\Services\SolrCoreService;
13
use Firesphere\SolrSearch\Traits\DocumentFactoryTrait;
14
use Firesphere\SolrSearch\Traits\LoggerTrait;
15
use Psr\Log\LoggerInterface;
16
use SilverStripe\Core\ClassInfo;
17
use SilverStripe\Core\Config\Configurable;
18
use SilverStripe\Core\Injector\Injector;
19
use SilverStripe\ORM\DataObject;
20
use SilverStripe\ORM\FieldType\DBDate;
21
use SilverStripe\ORM\FieldType\DBField;
22
use SilverStripe\ORM\SS_List;
23
use Solarium\QueryType\Update\Query\Document\Document;
24
use Solarium\QueryType\Update\Query\Query;
25
26
class DocumentFactory
27
{
28
    use Configurable;
29
    use DocumentFactoryTrait;
30
    use LoggerTrait;
31
32
    /**
33
     * Numeral types in Solr
34
     * @var array
35
     */
36
    protected static $numerals = [
37
        'tint',
38
        'tfloat',
39
        'tdouble'
40
    ];
41
    /**
42
     * @var bool
43
     */
44
    protected $debug = false;
45
46
    /**
47
     * @var null|LoggerInterface
48
     */
49
    protected $logger;
50
51
    /**
52
     * DocumentFactory constructor, sets up introspection
53
     */
54
    public function __construct()
55
    {
56
        $this->introspection = Injector::inst()->get(SearchIntrospection::class);
57
    }
58
59
    /**
60
     * Note, it can only take one type of class at a time!
61
     * So make sure you properly loop and set $class
62 4
     * @param $fields
63
     * @param BaseIndex $index
64 4
     * @param Query $update
65 4
     * @return array
66
     * @throws Exception
67
     */
68
    public function buildItems($fields, $index, $update): array
69
    {
70
        $class = $this->getClass();
71
        $this->getIntrospection()->setIndex($index);
72
        $boostFields = $index->getBoostedFields();
73
        $docs = [];
74
        $debugString = sprintf('Adding %s to %s%s', $class, $index->getIndexName(), PHP_EOL);
75
        $debugString .= '[';
76 14
        foreach ($this->getItems() as $item) {
77
            if ($item->ShowInSearch === 0) {
78 14
                continue;
79 14
            }
80 14
            $debugString .= "$item->ID, ";
81 14
            /** @var Document $doc */
82 14
            $doc = $update->createDocument();
83 14
            $this->addDefaultFields($doc, $item);
84 14
85 14
            $this->buildField($fields, $doc, $item, $boostFields);
86
            $item->destroy();
87 14
88 14
            $docs[] = $doc;
89
        }
90 14
91 14
        if ($this->debug) {
92
            $this->getLogger()->info(rtrim($debugString, ', ') . ']' . PHP_EOL);
93 14
        }
94
95
        return $docs;
96 14
    }
97 11
98
    /**
99
     * @param Document $doc
100 14
     * @param DataObject|DataObjectExtension $item
101
     */
102 14
    protected function addDefaultFields(Document $doc, DataObject $item)
103
    {
104
        $doc->setKey(SolrCoreService::ID_FIELD, $item->ClassName . '-' . $item->ID);
105
        $doc->addField(SolrCoreService::CLASS_ID_FIELD, $item->ID);
106
        $doc->addField('ClassName', $item->ClassName);
107
        $doc->addField('ClassHierarchy', ClassInfo::ancestry($item));
108 14
        $doc->addField('ViewStatus', $item->getViewStatus());
109
    }
110 14
111
    /**
112
     * @param $fields
113
     * @param Document $doc
114
     * @param DataObject $item
115
     * @param array $boostFields
116
     * @throws Exception
117 14
     */
118
    protected function buildField($fields, Document $doc, DataObject $item, array $boostFields): void
119 14
    {
120
        foreach ($fields as $field) {
121 14
            $fieldData = $this->getIntrospection()->getFieldIntrospection($field);
122
            foreach ($fieldData as $dataField => $options) {
123
                // Only one field per class, so let's take the fieldData. This will override previous additions
124
                $this->addField($doc, $item, $fieldData[$dataField]);
125
                if (array_key_exists($field, $boostFields)) {
126
                    $doc->setFieldBoost($dataField, $boostFields[$field]);
127 15
                }
128
            }
129 15
        }
130
    }
131
132
    /**
133
     * @param Document $doc
134
     * @param          $object
135 14
     * @param          $field
136
     *
137 14
     * @throws Exception
138
     */
139
    protected function addField($doc, $object, $field): void
140
    {
141
        if (!$this->classIs($object, $field['origin'])) {
142
            return;
143
        }
144 14
145
        try {
146 14
            $valuesForField = [DataResolver::identify($object, $field['field'])];
147
        } catch (Exception $e) {
148 14
            $valuesForField = [];
149
        }
150
151
        $typeMap = Statics::getTypeMap();
152
        $type = $typeMap[$field['type']] ?? $typeMap['*'];
153
154
        foreach ($valuesForField as $value) {
155 14
            if ($value === null) {
156
                continue;
157 14
            }
158 14
            $this->addToDoc($doc, $field, $type, $value);
159 14
        }
160 14
    }
161 14
162 14
    /**
163
     * Determine if the given object is one of the given type
164
     * @param string|array $class
165
     * @param array|string $base Class or list of base classes
166
     * @return bool
167
     */
168
    protected function classIs($class, $base): bool
169
    {
170
        $base = is_array($base) ? $base : [$base];
171 14
172
        foreach ($base as $nextBase) {
173 14
            if ($this->classEquals($class, $nextBase)) {
174 14
                return true;
175 14
            }
176
        }
177 14
178 14
        return false;
179 14
    }
180
181
    /**
182
     * Check if a base class is an instance of the expected base group
183 14
     * @param $class
184
     * @param $base
185
     * @return bool
186
     */
187
    protected function classEquals($class, $base): bool
188
    {
189
        return $class === $base || ($class instanceof $base);
190 14
    }
191
192 14
    /**
193 10
     * @param Document $doc
194
     * @param array $field
195
     * @param string $type
196 14
     * @param DBField|string $value
197
     */
198 14
    protected function addToDoc($doc, $field, $type, $value): void
199 14
    {
200
        /* Solr requires dates in the form 1995-12-31T23:59:59Z, so we need to normalize to GMT */
201 14
        if ($type === 'tdate' || $value instanceof DBDate) {
202 14
            $value = gmdate('Y-m-d\TH:i:s\Z', strtotime($value));
203 14
        }
204
205
        $name = $this->sanitiseName($field['name']);
206
207 14
        $doc->addField($name, $value);
208 13
    }
209
210
    /**
211
     * @param string $field
212 14
     * @return string
213
     */
214 14
    public function sanitiseName($field)
215
    {
216 14
        $name = explode('\\', $field);
217
218
        return end($name);
219
    }
220
221
    /**
222
     * @return bool
223
     */
224 14
    public function isDebug(): bool
225
    {
226 14
        return $this->debug;
227
    }
228 14
229 14
    /**
230 14
     * @param bool $debug
231
     * @return DocumentFactory
232
     */
233
    public function setDebug(bool $debug): DocumentFactory
234 10
    {
235
        $this->debug = $debug;
236
237
        return $this;
238
    }
239
}
240