1 | <?php |
||
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) |
|
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 | 16 | $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 | 14 | $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 | 6 | $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) |
|
294 | } |
||
295 |