Passed
Push — master ( 3cd8c6...9e747f )
by Timo
38:54 queued 16:17
created

AbstractIndexer::resolveFieldValue()   C

Complexity

Conditions 7
Paths 10

Size

Total Lines 73
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 9.1535

Importance

Changes 0
Metric Value
dl 0
loc 73
ccs 22
cts 34
cp 0.6471
rs 6.6896
c 0
b 0
f 0
cc 7
eloc 42
nc 10
nop 3
crap 9.1535

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace ApacheSolrForTypo3\Solr\IndexQueue;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2012-2015 Ingo Renner <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\ContentObject\Multivalue;
28
use ApacheSolrForTypo3\Solr\ContentObject\Relation;
29
use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
32
33
/**
34
 * An abstract indexer class to collect a few common methods shared with other
35
 * indexers.
36
 *
37
 * @author Ingo Renner <[email protected]>
38
 */
39
abstract class AbstractIndexer
40
{
41
42
    /**
43
     * Holds the type of the data to be indexed, usually that is the table name.
44
     *
45
     * @var string
46
     */
47
    protected $type = '';
48
49
    /**
50
     * Holds field names that are denied to overwrite in thy indexing configuration.
51
     *
52
     * @var array
53
     */
54
    protected static $unAllowedOverrideFields = ['type'];
55
56
    /**
57
     * @param string $solrFieldName
58
     * @return bool
59
     */
60 26
    public static function isAllowedToOverrideField($solrFieldName)
61
    {
62 26
        return !in_array($solrFieldName, static::$unAllowedOverrideFields);
63
    }
64
65
    /**
66
     * Adds fields to the document as defined in $indexingConfiguration
67
     *
68
     * @param \Apache_Solr_Document $document base document to add fields to
69
     * @param array $indexingConfiguration Indexing configuration / mapping
70
     * @param array $data Record data
71
     * @return \Apache_Solr_Document Modified document with added fields
72
     */
73 16
    protected function addDocumentFieldsFromTyposcript(
74
        \Apache_Solr_Document $document,
75
        array $indexingConfiguration,
76
        array $data
77
    ) {
78
79
        // mapping of record fields => solr document fields, resolving cObj
80 16
        foreach ($indexingConfiguration as $solrFieldName => $recordFieldName) {
81 16
            if (is_array($recordFieldName)) {
82
                // configuration for a content object, skipping
83 14
                continue;
84
            }
85
86 16
            if (!static::isAllowedToOverrideField($solrFieldName)) {
87
                throw new InvalidFieldNameException(
88
                    'Must not overwrite field .' . $solrFieldName,
89
                    1435441863
90
                );
91
            }
92
93 16
            $fieldValue = $this->resolveFieldValue($indexingConfiguration,
94
                $solrFieldName, $data);
95
96 16
            if (is_array($fieldValue)) {
97
                // multi value
98 6
                foreach ($fieldValue as $multiValue) {
99 6
                    $document->addField($solrFieldName, $multiValue);
100
                }
101
            } else {
102 16
                if ($fieldValue !== '' && $fieldValue !== null) {
103 16
                    $document->setField($solrFieldName, $fieldValue);
104
                }
105
            }
106
        }
107
108 16
        return $document;
109
    }
110
111
    /**
112
     * Resolves a field to its value depending on its configuration.
113
     *
114
     * This enables you to configure the indexer to put the item/record through
115
     * cObj processing if wanted/needed. Otherwise the plain item/record value
116
     * is taken.
117
     *
118
     * @param array $indexingConfiguration Indexing configuration as defined in plugin.tx_solr_index.queue.[indexingConfigurationName].fields
119
     * @param string $solrFieldName A Solr field name that is configured in the indexing configuration
120
     * @param array $data A record or item's data
121
     * @return string The resolved string value to be indexed
122
     */
123 16
    protected function resolveFieldValue(
124
        array $indexingConfiguration,
125
        $solrFieldName,
126
        array $data
127
    ) {
128 16
        $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
129
130 16
        if (isset($indexingConfiguration[$solrFieldName . '.'])) {
131
            // configuration found => need to resolve a cObj
132
133
            // need to change directory to make IMAGE content objects work in BE context
134
            // see http://blog.netzelf.de/lang/de/tipps-und-tricks/tslib_cobj-image-im-backend
135 14
            $backupWorkingDirectory = getcwd();
136 14
            chdir(PATH_site);
137
138 14
            $contentObject->start($data, $this->type);
139 14
            $fieldValue = $contentObject->cObjGetSingle(
140 14
                $indexingConfiguration[$solrFieldName],
141 14
                $indexingConfiguration[$solrFieldName . '.']
142
            );
143
144 14
            chdir($backupWorkingDirectory);
145
146 14
            if ($this->isSerializedValue($indexingConfiguration,
147
                $solrFieldName)
148
            ) {
149 14
                $fieldValue = unserialize($fieldValue);
150
            }
151 16
        } elseif (substr($indexingConfiguration[$solrFieldName], 0,
152 16
                1) === '<'
153
        ) {
154
            $referencedTsPath = trim(substr($indexingConfiguration[$solrFieldName],
155
                1));
156
            $typoScriptParser = GeneralUtility::makeInstance(TypoScriptParser::class);
157
            // $name and $conf is loaded with the referenced values.
158
            list($name, $conf) = $typoScriptParser->getVal($referencedTsPath,
159
                $GLOBALS['TSFE']->tmpl->setup);
160
161
            // need to change directory to make IMAGE content objects work in BE context
162
            // see http://blog.netzelf.de/lang/de/tipps-und-tricks/tslib_cobj-image-im-backend
163
            $backupWorkingDirectory = getcwd();
164
            chdir(PATH_site);
165
166
            $contentObject->start($data, $this->type);
167
            $fieldValue = $contentObject->cObjGetSingle($name, $conf);
168
169
            chdir($backupWorkingDirectory);
170
171
            if ($this->isSerializedValue($indexingConfiguration,
172
                $solrFieldName)
173
            ) {
174
                $fieldValue = unserialize($fieldValue);
175
            }
176
        } else {
177 16
            $fieldValue = $data[$indexingConfiguration[$solrFieldName]];
178
        }
179
180
        // detect and correct type for dynamic fields
181
182
        // find last underscore, substr from there, cut off last character (S/M)
183 16
        $fieldType = substr($solrFieldName, strrpos($solrFieldName, '_') + 1,
184 16
            -1);
185 16
        if (is_array($fieldValue)) {
186 6
            foreach ($fieldValue as $key => $value) {
187 6
                $fieldValue[$key] = $this->ensureFieldValueType($value,
188
                    $fieldType);
189
            }
190
        } else {
191 16
            $fieldValue = $this->ensureFieldValueType($fieldValue, $fieldType);
192
        }
193
194 16
        return $fieldValue;
195
    }
196
197
    // Utility methods
198
199
    /**
200
     * Uses a field's configuration to detect whether its value returned by a
201
     * content object is expected to be serialized and thus needs to be
202
     * unserialized.
203
     *
204
     * @param array $indexingConfiguration Current item's indexing configuration
205
     * @param string $solrFieldName Current field being indexed
206
     * @return bool TRUE if the value is expected to be serialized, FALSE otherwise
207
     */
208 20
    public static function isSerializedValue(
209
        array $indexingConfiguration,
210
        $solrFieldName
211
    ) {
212 20
        $isSerialized = false;
213
214 20
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['detectSerializedValue'])) {
215
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['detectSerializedValue'] as $classReference) {
216
                $serializedValueDetector = GeneralUtility::getUserObj($classReference);
217
218
                if ($serializedValueDetector instanceof SerializedValueDetector) {
219
                    $isSerialized = (boolean)$serializedValueDetector->isSerializedValue($indexingConfiguration,
220
                        $solrFieldName);
221
                    if ($isSerialized) {
222
                        return true;
223
                    }
224
                } else {
225
                    throw new \UnexpectedValueException(
226
                        get_class($serializedValueDetector) . ' must implement interface ' . SerializedValueDetector::class,
227
                        1404471741
228
                    );
229
                }
230
            }
231
        }
232
233
        // SOLR_MULTIVALUE - always returns serialized array
234 20
        if ($indexingConfiguration[$solrFieldName] == Multivalue::CONTENT_OBJECT_NAME) {
235
            $isSerialized = true;
236
        }
237
238
        // SOLR_RELATION - returns serialized array if multiValue option is set
239 20
        if ($indexingConfiguration[$solrFieldName] == Relation::CONTENT_OBJECT_NAME
240 20
            && !empty($indexingConfiguration[$solrFieldName . '.']['multiValue'])
241
        ) {
242 7
            $isSerialized = true;
243
        }
244
245 20
        return $isSerialized;
246
    }
247
248
    /**
249
     * Makes sure a field's value matches a (dynamic) field's type.
250
     *
251
     * @param mixed $value Value to be added to a document
252
     * @param string $fieldType The dynamic field's type
253
     * @return mixed Returns the value in the correct format for the field type
254
     */
255 16
    protected function ensureFieldValueType($value, $fieldType)
256
    {
257
        switch ($fieldType) {
258 16
            case 'int':
259 16
            case 'tInt':
260
                $value = intval($value);
261
                break;
262
263 16
            case 'float':
264 16
            case 'tFloat':
265
                $value = floatval($value);
266
                break;
267
268
            // long and double do not exist in PHP
269
            // simply make sure it somehow looks like a number
270
            // <insert PHP rant here>
271 16
            case 'long':
272 16
            case 'tLong':
273
                // remove anything that's not a number or negative/minus sign
274
                $value = preg_replace('/[^0-9\\-]/', '', $value);
275
                if (trim($value) === '') {
276
                    $value = 0;
277
                }
278
                break;
279 16
            case 'double':
280 16
            case 'tDouble':
281 16
            case 'tDouble4':
282
                // as long as it's numeric we'll take it, int or float doesn't matter
283
                if (!is_numeric($value)) {
284
                    $value = 0;
285
                }
286
                break;
287
288
            default:
289
                // assume things are correct for non-dynamic fields
290
        }
291
292 16
        return $value;
293
    }
294
}
295