Passed
Push — hans/logtests ( 76c086...71695d )
by Simon
06:24 queued 02:27
created

DocumentFactory::setDebug()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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