1
|
|
|
<?php |
2
|
|
|
namespace ApacheSolrForTypo3\Solr\IndexQueue; |
3
|
|
|
|
4
|
|
|
/*************************************************************** |
5
|
|
|
* Copyright notice |
6
|
|
|
* |
7
|
|
|
* (c) 2009-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\Site; |
28
|
|
|
use TYPO3\CMS\Backend\Utility\BackendUtility; |
29
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Representation of an index queue item, carrying meta data and the record to be |
33
|
|
|
* indexed. |
34
|
|
|
* |
35
|
|
|
* @author Ingo Renner <[email protected]> |
36
|
|
|
*/ |
37
|
|
|
class Item |
38
|
|
|
{ |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* The item's uid in the index queue (tx_solr_indexqueue_item.uid) |
42
|
|
|
* |
43
|
|
|
* @var int |
44
|
|
|
*/ |
45
|
|
|
protected $indexQueueUid; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* The root page uid of the tree the item is located in (tx_solr_indexqueue_item.root) |
49
|
|
|
* |
50
|
|
|
* @var int |
51
|
|
|
*/ |
52
|
|
|
protected $rootPageUid; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* The record's type, usually a table name, but could also be a file type (tx_solr_indexqueue_item.item_type) |
56
|
|
|
* |
57
|
|
|
* @var string |
58
|
|
|
*/ |
59
|
|
|
protected $type; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* The name of the indexing configuration that should be used when indexing (tx_solr_indexqueue_item.indexing_configuration) |
63
|
|
|
* the item. |
64
|
|
|
* |
65
|
|
|
* @var string |
66
|
|
|
*/ |
67
|
|
|
protected $indexingConfigurationName; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* The unix timestamp when the record was last changed (tx_solr_indexqueue_item.changed) |
71
|
|
|
* |
72
|
|
|
* @var int |
73
|
|
|
*/ |
74
|
|
|
protected $changed; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Indexing properties to provide additional information for the item's |
78
|
|
|
* indexer / how to index the item. |
79
|
|
|
* |
80
|
|
|
* @var array |
81
|
|
|
*/ |
82
|
|
|
protected $indexingProperties = array(); |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Flag for lazy loading indexing properties. |
86
|
|
|
* |
87
|
|
|
* @var bool |
88
|
|
|
*/ |
89
|
|
|
protected $indexingPropertiesLoaded = false; |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Flag, whether indexing properties exits for this item. |
93
|
|
|
* |
94
|
|
|
* @var bool |
95
|
|
|
*/ |
96
|
|
|
protected $hasIndexingProperties = false; |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* The record's uid. |
100
|
|
|
* |
101
|
|
|
* @var int |
102
|
|
|
*/ |
103
|
|
|
protected $recordUid = 0; |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* The record itself |
107
|
|
|
* |
108
|
|
|
* @var array |
109
|
|
|
*/ |
110
|
|
|
protected $record; |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Constructor, takes item meta data information and resolves that to the full record. |
114
|
|
|
* |
115
|
|
|
* @param array $itemMetaData Metadata describing the item to index using the index queue. Is expected to contain a record from table tx_solr_indexqueue_item |
116
|
|
|
* @param array $fullRecord Optional full record for the item. If provided, can save some SQL queries. |
117
|
|
|
*/ |
118
|
19 |
|
public function __construct( |
119
|
|
|
array $itemMetaData, |
120
|
|
|
array $fullRecord = array() |
121
|
|
|
) { |
122
|
19 |
|
$this->indexQueueUid = $itemMetaData['uid']; |
123
|
19 |
|
$this->rootPageUid = $itemMetaData['root']; |
124
|
19 |
|
$this->type = $itemMetaData['item_type']; |
125
|
19 |
|
$this->recordUid = $itemMetaData['item_uid']; |
126
|
19 |
|
$this->changed = $itemMetaData['changed']; |
127
|
|
|
|
128
|
19 |
|
$this->indexingConfigurationName = $itemMetaData['indexing_configuration']; |
129
|
19 |
|
$this->hasIndexingProperties = (boolean)$itemMetaData['has_indexing_properties']; |
130
|
|
|
|
131
|
19 |
|
if (!empty($fullRecord)) { |
132
|
15 |
|
$this->record = $fullRecord; |
133
|
|
|
} |
134
|
19 |
|
} |
135
|
|
|
|
136
|
1 |
|
public function getIndexQueueUid() |
137
|
|
|
{ |
138
|
1 |
|
return $this->indexQueueUid; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Gets the item's root page ID (uid) |
143
|
|
|
* |
144
|
|
|
* @return int root page ID |
145
|
|
|
*/ |
146
|
13 |
|
public function getRootPageUid() |
147
|
|
|
{ |
148
|
13 |
|
return $this->rootPageUid; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
public function setRootPageUid($uid) |
152
|
|
|
{ |
153
|
|
|
$this->rootPageUid = intval($uid); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Gets the site the item belongs to. |
158
|
|
|
* |
159
|
|
|
* @return Site Site instance the item belongs to. |
160
|
|
|
*/ |
161
|
14 |
|
public function getSite() |
162
|
|
|
{ |
163
|
14 |
|
return GeneralUtility::makeInstance('ApacheSolrForTypo3\\Solr\\Site', |
164
|
14 |
|
$this->rootPageUid); |
165
|
|
|
} |
166
|
|
|
|
167
|
11 |
|
public function getType() |
168
|
|
|
{ |
169
|
11 |
|
return $this->type; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
public function setType($type) |
173
|
|
|
{ |
174
|
|
|
$this->type = $type; |
175
|
|
|
} |
176
|
|
|
|
177
|
12 |
|
public function getIndexingConfigurationName() |
178
|
|
|
{ |
179
|
12 |
|
return $this->indexingConfigurationName; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
public function setIndexingConfigurationName($indexingConfigurationName) |
183
|
|
|
{ |
184
|
|
|
$this->indexingConfigurationName = $indexingConfigurationName; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
public function getChanged() |
188
|
|
|
{ |
189
|
|
|
return $this->changed; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
public function setChanged($changed) |
193
|
|
|
{ |
194
|
|
|
$this->changed = intval($changed); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Sets the timestamp of when an item has been indexed. |
199
|
|
|
* |
200
|
|
|
* @return void |
201
|
|
|
*/ |
202
|
5 |
|
public function updateIndexedTime() |
203
|
|
|
{ |
204
|
5 |
|
$GLOBALS['TYPO3_DB']->exec_UPDATEquery( |
205
|
5 |
|
'tx_solr_indexqueue_item', |
206
|
5 |
|
'uid = ' . (int)$this->indexQueueUid, |
207
|
5 |
|
array('indexed' => time()) |
208
|
|
|
); |
209
|
5 |
|
} |
210
|
|
|
|
211
|
2 |
|
public function getRecordUid() |
212
|
|
|
{ |
213
|
2 |
|
$this->getRecord(); |
214
|
|
|
|
215
|
2 |
|
return $this->record['uid']; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Gets the item's full record. |
220
|
|
|
* |
221
|
|
|
* Uses lazy loading. |
222
|
|
|
* |
223
|
|
|
* @return array The item's DB record. |
224
|
|
|
*/ |
225
|
11 |
|
public function getRecord() |
226
|
|
|
{ |
227
|
11 |
|
if (empty($this->record)) { |
228
|
|
|
$this->record = BackendUtility::getRecord( |
|
|
|
|
229
|
|
|
$this->type, |
230
|
|
|
$this->recordUid, |
231
|
|
|
'*', |
232
|
|
|
'', |
233
|
|
|
false |
234
|
|
|
); |
235
|
|
|
} |
236
|
|
|
|
237
|
11 |
|
return $this->record; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
public function setRecord(array $record) |
241
|
|
|
{ |
242
|
|
|
$this->record = $record; |
243
|
|
|
} |
244
|
|
|
|
245
|
1 |
|
public function getRecordPageId() |
246
|
|
|
{ |
247
|
1 |
|
$this->getRecord(); |
248
|
|
|
|
249
|
1 |
|
return $this->record['pid']; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Stores the indexing properties. |
254
|
|
|
* |
255
|
|
|
*/ |
256
|
2 |
|
public function storeIndexingProperties() |
257
|
|
|
{ |
258
|
2 |
|
$this->removeIndexingProperties(); |
259
|
|
|
|
260
|
2 |
|
if ($this->hasIndexingProperties()) { |
261
|
2 |
|
$this->writeIndexingProperties(); |
262
|
|
|
} |
263
|
|
|
|
264
|
2 |
|
$this->updateHasIndexingPropertiesFlag(); |
265
|
2 |
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Removes existing indexing properties. |
269
|
|
|
* |
270
|
|
|
* @throws \RuntimeException when an SQL error occurs |
271
|
|
|
*/ |
272
|
2 |
|
protected function removeIndexingProperties() |
273
|
|
|
{ |
274
|
2 |
|
$GLOBALS['TYPO3_DB']->exec_DELETEquery( |
275
|
2 |
|
'tx_solr_indexqueue_indexing_property', |
276
|
2 |
|
'root = ' . intval($this->rootPageUid) |
277
|
2 |
|
. ' AND item_id = ' . intval($this->indexQueueUid) |
278
|
|
|
); |
279
|
|
|
|
280
|
2 |
|
if ($GLOBALS['TYPO3_DB']->sql_error()) { |
281
|
|
|
throw new \RuntimeException( |
282
|
|
|
'Could not remove indexing properties for item ' . $this->indexQueueUid, |
283
|
|
|
1323802532 |
284
|
|
|
); |
285
|
|
|
} |
286
|
2 |
|
} |
287
|
|
|
|
288
|
2 |
|
public function hasIndexingProperties() |
289
|
|
|
{ |
290
|
2 |
|
return $this->hasIndexingProperties; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* Writes all indexing properties. |
295
|
|
|
* |
296
|
|
|
* @throws \RuntimeException when an SQL error occurs |
297
|
|
|
*/ |
298
|
2 |
|
protected function writeIndexingProperties() |
299
|
|
|
{ |
300
|
2 |
|
$properties = array(); |
301
|
2 |
|
foreach ($this->indexingProperties as $propertyKey => $propertyValue) { |
302
|
2 |
|
$properties[] = array( |
303
|
2 |
|
$this->rootPageUid, |
304
|
2 |
|
$this->indexQueueUid, |
305
|
2 |
|
$propertyKey, |
306
|
2 |
|
$propertyValue |
307
|
|
|
); |
308
|
|
|
} |
309
|
|
|
|
310
|
2 |
|
$GLOBALS['TYPO3_DB']->exec_INSERTmultipleRows( |
311
|
2 |
|
'tx_solr_indexqueue_indexing_property', |
312
|
2 |
|
array('root', 'item_id', 'property_key', 'property_value'), |
313
|
|
|
$properties |
314
|
|
|
); |
315
|
|
|
|
316
|
2 |
|
if ($GLOBALS['TYPO3_DB']->sql_error()) { |
317
|
|
|
throw new \RuntimeException( |
318
|
|
|
'Could not insert indexing properties for item ' . $this->indexQueueUid, |
319
|
|
|
1323802570 |
320
|
|
|
); |
321
|
|
|
} |
322
|
2 |
|
} |
323
|
|
|
|
324
|
|
|
/** |
325
|
|
|
* Updates the "has_indexing_properties" flag in the Index Queue. |
326
|
|
|
* |
327
|
|
|
* @throws \RuntimeException when an SQL error occurs |
328
|
|
|
*/ |
329
|
2 |
|
protected function updateHasIndexingPropertiesFlag() |
330
|
|
|
{ |
331
|
2 |
|
$hasIndexingProperties = '0'; |
332
|
2 |
|
if ($this->hasIndexingProperties()) { |
333
|
2 |
|
$hasIndexingProperties = '1'; |
334
|
|
|
} |
335
|
|
|
|
336
|
2 |
|
$GLOBALS['TYPO3_DB']->exec_UPDATEquery( |
337
|
2 |
|
'tx_solr_indexqueue_item', |
338
|
2 |
|
'uid = ' . intval($this->indexQueueUid), |
339
|
2 |
|
array('has_indexing_properties' => $hasIndexingProperties) |
340
|
|
|
); |
341
|
|
|
|
342
|
2 |
|
if ($GLOBALS['TYPO3_DB']->sql_error()) { |
343
|
|
|
throw new \RuntimeException( |
344
|
|
|
'Could not update has_indexing_properties flag in Index Queue for item ' . $this->indexQueueUid, |
345
|
|
|
1323802610 |
346
|
|
|
); |
347
|
|
|
} |
348
|
2 |
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* @param string $key |
352
|
|
|
* @return bool |
353
|
|
|
*/ |
354
|
1 |
|
public function hasIndexingProperty($key) |
355
|
|
|
{ |
356
|
1 |
|
$this->loadIndexingProperties(); |
357
|
|
|
|
358
|
1 |
|
return array_key_exists($key, $this->indexingProperties); |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* Loads the indexing properties for the item - if not already loaded. |
363
|
|
|
* |
364
|
|
|
*/ |
365
|
3 |
|
public function loadIndexingProperties() |
366
|
|
|
{ |
367
|
3 |
|
if (!$this->indexingPropertiesLoaded) { |
368
|
3 |
|
$indexingProperties = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( |
369
|
3 |
|
'property_key, property_value', |
370
|
3 |
|
'tx_solr_indexqueue_indexing_property', |
371
|
3 |
|
'item_id = ' . intval($this->indexQueueUid) |
372
|
|
|
); |
373
|
|
|
|
374
|
3 |
|
if (!empty($indexingProperties)) { |
375
|
|
|
foreach ($indexingProperties as $indexingProperty) { |
376
|
|
|
$this->indexingProperties[$indexingProperty['property_key']] = $indexingProperty['property_value']; |
377
|
|
|
} |
378
|
|
|
} |
379
|
|
|
|
380
|
3 |
|
$this->indexingPropertiesLoaded = true; |
381
|
|
|
} |
382
|
3 |
|
} |
383
|
|
|
|
384
|
|
|
/** |
385
|
|
|
* Sets an indexing property for the item. |
386
|
|
|
* |
387
|
|
|
* @param string $key Indexing property name |
388
|
|
|
* @param string|int|float $value Indexing property value |
389
|
|
|
* @throws \InvalidArgumentException when $value is not string, integer or float |
390
|
|
|
*/ |
391
|
2 |
|
public function setIndexingProperty($key, $value) |
392
|
|
|
{ |
393
|
|
|
|
394
|
|
|
// make sure to not interfere with existing indexing properties |
395
|
2 |
|
$this->loadIndexingProperties(); |
396
|
|
|
|
397
|
2 |
|
$key = (string)$key; // Scalar typehints now! |
398
|
|
|
|
399
|
2 |
|
if (!is_string($value) && !is_int($value) && !is_float($value)) { |
400
|
|
|
throw new \InvalidArgumentException( |
401
|
|
|
'Cannot set indexing property "' . $key |
402
|
|
|
. '", its value must be string, integer or float, ' |
403
|
|
|
. 'type given was "' . gettype($value) . '"', |
404
|
|
|
1323173209 |
405
|
|
|
); |
406
|
|
|
} |
407
|
|
|
|
408
|
2 |
|
$this->indexingProperties[$key] = $value; |
409
|
2 |
|
$this->hasIndexingProperties = true; |
410
|
2 |
|
} |
411
|
|
|
|
412
|
|
|
/** |
413
|
|
|
* Gets a specific indexing property by its name/key. |
414
|
|
|
* |
415
|
|
|
* @param string $key Indexing property name/key. |
416
|
|
|
* @throws \InvalidArgumentException when the given $key does not exist. |
417
|
|
|
* @return string |
418
|
|
|
*/ |
419
|
|
|
public function getIndexingProperty($key) |
420
|
|
|
{ |
421
|
|
|
$this->loadIndexingProperties(); |
422
|
|
|
|
423
|
|
|
if (!array_key_exists($key, $this->indexingProperties)) { |
424
|
|
|
throw new \InvalidArgumentException( |
425
|
|
|
'No indexing property "' . $key . '".', |
426
|
|
|
1323174143 |
427
|
|
|
); |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
return $this->indexingProperties[$key]; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* Gets all indexing properties set for this item. |
435
|
|
|
* |
436
|
|
|
* @return array Array of indexing properties. |
437
|
|
|
*/ |
438
|
|
|
public function getIndexingProperties() |
439
|
|
|
{ |
440
|
|
|
$this->loadIndexingProperties(); |
441
|
|
|
|
442
|
|
|
return $this->indexingProperties; |
443
|
|
|
} |
444
|
|
|
|
445
|
|
|
/** |
446
|
|
|
* Gets the names/keys of the item's indexing properties. |
447
|
|
|
* |
448
|
|
|
* @return array Array of indexing property names/keys |
449
|
|
|
*/ |
450
|
|
|
public function getIndexingPropertyKeys() |
451
|
|
|
{ |
452
|
|
|
$this->loadIndexingProperties(); |
453
|
|
|
|
454
|
|
|
return array_keys($this->indexingProperties); |
455
|
|
|
} |
456
|
|
|
} |
457
|
|
|
|
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.
To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.
The function can be called with either null or an array for the parameter
$needle
but will only accept an array as$haystack
.