Passed
Pull Request — master (#297)
by Aimeos
10:30
created

Standard::rebuild()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 60
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 60
rs 9.9332
cc 2
nc 2
nop 1

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
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2022
7
 * @package MShop
8
 * @subpackage Index
9
 */
10
11
12
namespace Aimeos\MShop\Index\Manager;
13
14
15
/**
16
 * Index index manager for searching in product tables.
17
 *
18
 * @package MShop
19
 * @subpackage Index
20
 */
21
class Standard
22
	extends \Aimeos\MShop\Index\Manager\DBBase
23
	implements \Aimeos\MShop\Index\Manager\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
24
{
25
	/** mshop/index/manager/name
26
	 * Class name of the used index manager implementation
27
	 *
28
	 * Each default manager can be replace by an alternative imlementation.
29
	 * To use this implementation, you have to set the last part of the class
30
	 * name as configuration value so the manager factory knows which class it
31
	 * has to instantiate.
32
	 *
33
	 * For example, if the name of the default class is
34
	 *
35
	 *  \Aimeos\MShop\Index\Manager\Standard
36
	 *
37
	 * and you want to replace it with your own version named
38
	 *
39
	 *  \Aimeos\MShop\Index\Manager\Mymanager
40
	 *
41
	 * then you have to set the this configuration option:
42
	 *
43
	 *  mshop/index/manager/name = Mymanager
44
	 *
45
	 * The value is the last part of your own class name and it's case sensitive,
46
	 * so take care that the configuration value is exactly named like the last
47
	 * part of the class name.
48
	 *
49
	 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
50
	 * characters are possible! You should always start the last part of the class
51
	 * name with an upper case character and continue only with lower case characters
52
	 * or numbers. Avoid chamel case names like "MyManager"!
53
	 *
54
	 * @param string Last part of the class name
55
	 * @since 2015.11
56
	 * @category Developer
57
	 */
58
59
	/** mshop/index/manager/decorators/excludes
60
	 * Excludes decorators added by the "common" option from the index manager
61
	 *
62
	 * Decorators extend the functionality of a class by adding new aspects
63
	 * (e.g. log what is currently done), executing the methods of the underlying
64
	 * class only in certain conditions (e.g. only for logged in users) or
65
	 * modify what is returned to the caller.
66
	 *
67
	 * This option allows you to remove a decorator added via
68
	 * "mshop/common/manager/decorators/default" before they are wrapped
69
	 * around the index manager.
70
	 *
71
	 *  mshop/index/manager/decorators/excludes = array( 'decorator1' )
72
	 *
73
	 * This would remove the decorator named "decorator1" from the list of
74
	 * common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
75
	 * "mshop/common/manager/decorators/default" for the index manager.
76
	 *
77
	 * @param array List of decorator names
78
	 * @since 2015.11
79
	 * @category Developer
80
	 * @see mshop/common/manager/decorators/default
81
	 * @see mshop/index/manager/decorators/global
82
	 * @see mshop/index/manager/decorators/local
83
	 */
84
85
	/** mshop/index/manager/decorators/global
86
	 * Adds a list of globally available decorators only to the index manager
87
	 *
88
	 * Decorators extend the functionality of a class by adding new aspects
89
	 * (e.g. log what is currently done), executing the methods of the underlying
90
	 * class only in certain conditions (e.g. only for logged in users) or
91
	 * modify what is returned to the caller.
92
	 *
93
	 * This option allows you to wrap global decorators
94
	 * ("\Aimeos\MShop\Common\Manager\Decorator\*") around the index manager.
95
	 *
96
	 *  mshop/index/manager/decorators/global = array( 'decorator1' )
97
	 *
98
	 * This would add the decorator named "decorator1" defined by
99
	 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the index manager.
100
	 *
101
	 * @param array List of decorator names
102
	 * @since 2015.11
103
	 * @category Developer
104
	 * @see mshop/common/manager/decorators/default
105
	 * @see mshop/index/manager/decorators/excludes
106
	 * @see mshop/index/manager/decorators/local
107
	 */
108
109
	/** mshop/index/manager/decorators/local
110
	 * Adds a list of local decorators only to the index manager
111
	 *
112
	 * Decorators extend the functionality of a class by adding new aspects
113
	 * (e.g. log what is currently done), executing the methods of the underlying
114
	 * class only in certain conditions (e.g. only for logged in users) or
115
	 * modify what is returned to the caller.
116
	 *
117
	 * This option allows you to wrap local decorators
118
	 * ("\Aimeos\MShop\Index\Manager\Decorator\*") around the index manager.
119
	 *
120
	 *  mshop/index/manager/decorators/local = array( 'decorator2' )
121
	 *
122
	 * This would add the decorator named "decorator2" defined by
123
	 * "\Aimeos\MShop\Index\Manager\Decorator\Decorator2" only to the index
124
	 * manager.
125
	 *
126
	 * @param array List of decorator names
127
	 * @since 2015.11
128
	 * @category Developer
129
	 * @see mshop/common/manager/decorators/default
130
	 * @see mshop/index/manager/decorators/excludes
131
	 * @see mshop/index/manager/decorators/global
132
	 */
133
134
135
	private $subManagers;
136
137
138
	/**
139
	 * Counts the number products that are available for the values of the given key.
140
	 *
141
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria
142
	 * @param string $key Search key (usually the ID) to aggregate products for
143
	 * @param string|null $value Search key for aggregating the value column
144
	 * @param string|null $type Type of the aggregation, empty string for count or "sum" or "avg" (average)
145
	 * @return \Aimeos\Map List of ID values as key and the number of counted products as value
146
	 */
147
	public function aggregate( \Aimeos\Base\Criteria\Iface $search, $key, string $value = null, string $type = null ) : \Aimeos\Map
148
	{
149
		/** mshop/index/manager/aggregate/mysql
150
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
151
		 *
152
		 * @see mshop/index/manager/aggregate/ansi
153
		 */
154
155
		/** mshop/index/manager/aggregate/ansi
156
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
157
		 *
158
		 * Groups all records by the values in the key column and counts their
159
		 * occurence. The matched records can be limited by the given criteria
160
		 * from the order database. The records must be from one of the sites
161
		 * that are configured via the context item. If the current site is part
162
		 * of a tree of sites, the statement can count all records from the
163
		 * current site and the complete sub-tree of sites.
164
		 *
165
		 * As the records can normally be limited by criteria from sub-managers,
166
		 * their tables must be joined in the SQL context. This is done by
167
		 * using the "internaldeps" property from the definition of the ID
168
		 * column of the sub-managers. These internal dependencies specify
169
		 * the JOIN between the tables and the used columns for joining. The
170
		 * ":joins" placeholder is then replaced by the JOIN strings from
171
		 * the sub-managers.
172
		 *
173
		 * To limit the records matched, conditions can be added to the given
174
		 * criteria object. It can contain comparisons like column names that
175
		 * must match specific values which can be combined by AND, OR or NOT
176
		 * operators. The resulting string of SQL conditions replaces the
177
		 * ":cond" placeholder before the statement is sent to the database
178
		 * server.
179
		 *
180
		 * This statement doesn't return any records. Instead, it returns pairs
181
		 * of the different values found in the key column together with the
182
		 * number of records that have been found for that key values.
183
		 *
184
		 * The SQL statement should conform to the ANSI standard to be
185
		 * compatible with most relational database systems. This also
186
		 * includes using double quotes for table and column names.
187
		 *
188
		 * @param string SQL statement for aggregating order items
189
		 * @since 2014.09
190
		 * @category Developer
191
		 * @see mshop/index/manager/count/ansi
192
		 * @see mshop/index/manager/iterate/ansi
193
		 * @see mshop/index/manager/optimize/ansi
194
		 * @see mshop/index/manager/search/ansi
195
		 */
196
		return $this->aggregateBase( $search, $key, 'mshop/index/manager/aggregate', ['product'], $value, $type );
197
	}
198
199
200
	/**
201
	 * Returns the available manager types
202
	 *
203
	 * @param bool $withsub Return also the resource type of sub-managers if true
204
	 * @return array Type of the manager and submanagers, subtypes are separated by slashes
205
	 */
206
	public function getResourceType( bool $withsub = true ) : array
207
	{
208
		return $this->getResourceTypeBase( 'index', 'mshop/index/manager/submanagers', [], $withsub );
209
	}
210
211
212
	/**
213
	 * Returns a list of objects describing the available criterias for searching.
214
	 *
215
	 * @param bool $withsub Return also attributes of sub-managers if true
216
	 * @return \Aimeos\Base\Criteria\Attribute\Iface[] List of search attribute items
217
	 */
218
	public function getSearchAttributes( bool $withsub = true ) : array
219
	{
220
		$list = parent::getSearchAttributes( $withsub );
221
222
		/** mshop/index/manager/submanagers
223
		 * Replaced by mshop/index/manager/submanagers since 2016.01
224
		 *
225
		 * @see mshop/index/manager/submanagers
226
		 */
227
		$path = 'mshop/index/manager/submanagers';
228
229
		return $list + $this->getSearchAttributesBase( [], $path, [], $withsub );
230
	}
231
232
233
	/**
234
	 * Returns a new manager for product extensions.
235
	 *
236
	 * @param string $manager Name of the sub manager type in lower case
237
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
238
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g stock, tags, locations, etc.
239
	 */
240
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
241
	{
242
		return $this->getSubManagerBase( 'index', $manager, $name );
243
	}
244
245
246
	/**
247
	 * Optimizes the index if necessary.
248
	 * Execution of this operation can take a very long time and shouldn't be
249
	 * called through a web server enviroment.
250
	 *
251
	 * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
252
	 */
253
	public function optimize() : \Aimeos\MShop\Index\Manager\Iface
254
	{
255
		/** mshop/index/manager/optimize/mysql
256
		 * Optimizes the stored product data for retrieving the records faster
257
		 *
258
		 * @see mshop/index/manager/optimize/ansi
259
		 */
260
261
		/** mshop/index/manager/optimize/ansi
262
		 * Optimizes the stored product data for retrieving the records faster
263
		 *
264
		 * The SQL statement should reorganize the data in the DBMS storage to
265
		 * optimize access to the records of the table or tables. Some DBMS
266
		 * offer specialized statements to optimize indexes and records. This
267
		 * statement doesn't return any records.
268
		 *
269
		 * The SQL statement should conform to the ANSI standard to be
270
		 * compatible with most relational database systems. This also
271
		 * includes using double quotes for table and column names.
272
		 *
273
		 * @param string SQL statement for optimizing the stored product data
274
		 * @since 2014.09
275
		 * @category Developer
276
		 * @see mshop/index/manager/count/ansi
277
		 * @see mshop/index/manager/search/ansi
278
		 * @see mshop/index/manager/iterate/ansi
279
		 * @see mshop/index/manager/aggregate/ansi
280
		 */
281
		return $this->optimizeBase( 'mshop/index/manager/optimize' );
282
	}
283
284
285
	/**
286
	 * Removes old entries from the storage.
287
	 *
288
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
289
	 * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
290
	 */
291
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
292
	{
293
		foreach( $this->getSubManagers() as $submanager ) {
294
			$submanager->clear( $siteids );
295
		}
296
297
		return $this;
298
	}
299
300
301
	/**
302
	 * Removes all entries not touched after the given timestamp in the index.
303
	 * This can be a long lasting operation.
304
	 *
305
	 * @param string $timestamp Timestamp in ISO format (YYYY-MM-DD HH:mm:ss)
306
	 * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
307
	 */
308
	public function cleanup( string $timestamp ) : \Aimeos\MShop\Index\Manager\Iface
309
	{
310
		foreach( $this->getSubManagers() as $submanager ) {
311
			$submanager->cleanup( $timestamp );
312
		}
313
314
		return $this;
315
	}
316
317
318
	/**
319
	 * Removes multiple items.
320
	 *
321
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
322
	 * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
323
	 */
324
	public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
325
	{
326
		$this->getManager()->delete( $itemIds );
327
		parent::delete( $itemIds );
328
329
		$this->context()->cache()->deleteByTags( map( $itemIds ) ->prefix( 'product-' )->toArray() );
330
		return $this;
331
	}
332
333
334
	/**
335
	 * Creates a new iterator based on the filter criteria
336
	 *
337
	 * @param \Aimeos\Base\Criteria\Iface $filter Criteria object with conditions, sortations, etc.
338
	 * @return \Aimeos\MShop\Common\Iterator\Iface Iterator object
339
	 */
340
	public function iterator( \Aimeos\Base\Criteria\Iface $filter ) : \Aimeos\MShop\Common\Iterator\Iface
341
	{
342
		/** mshop/index/manager/iterate/ansi
343
		 * Retrieves the records matched by the given criteria in the database
344
		 *
345
		 * Fetches the records matched by the given criteria from the order
346
		 * database. The records must be from one of the sites that are
347
		 * configured via the context item. If the current site is part of
348
		 * a tree of sites, the SELECT statement can retrieve all records
349
		 * from the current site and the complete sub-tree of sites.
350
		 *
351
		 * As the records can normally be limited by criteria from sub-managers,
352
		 * their tables must be joined in the SQL context. This is done by
353
		 * using the "internaldeps" property from the definition of the ID
354
		 * column of the sub-managers. These internal dependencies specify
355
		 * the JOIN between the tables and the used columns for joining. The
356
		 * ":joins" placeholder is then replaced by the JOIN strings from
357
		 * the sub-managers.
358
		 *
359
		 * To limit the records matched, conditions can be added to the given
360
		 * criteria object. It can contain comparisons like column names that
361
		 * must match specific values which can be combined by AND, OR or NOT
362
		 * operators. The resulting string of SQL conditions replaces the
363
		 * ":cond" placeholder before the statement is sent to the database
364
		 * server.
365
		 *
366
		 * If the records that are retrieved should be ordered by one or more
367
		 * columns, the generated string of column / sort direction pairs
368
		 * replaces the ":order" placeholder. In case no ordering is required,
369
		 * the complete ORDER BY part including the ":order"
370
		 * markers is removed to speed up retrieving the records. Columns of
371
		 * sub-managers can also be used for ordering the result set but then
372
		 * no index can be used.
373
		 *
374
		 * The SQL statement should conform to the ANSI standard to be
375
		 * compatible with most relational database systems. This also
376
		 * includes using double quotes for table and column names.
377
		 *
378
		 * @param string SQL statement for iterate over items
379
		 * @since 2022.10
380
		 * @category Developer
381
		 * @see mshop/index/manager/count/ansi
382
		 * @see mshop/index/manager/search/ansi
383
		 * @see mshop/index/manager/optimize/ansi
384
		 * @see mshop/index/manager/aggregate/ansi
385
		 */
386
387
		return $this->iteratorIndexBase( $filter, 'mshop/index/manager/iterate' );
388
	}
389
390
391
	/**
392
	 * Iterates over all matching items and returns the found ones
393
	 *
394
	 * @param \Aimeos\MShop\Common\Iterator\Iface $iterator Iterator object with conditions, sortations, etc.
395
	 * @param string[] $ref List of domains to fetch list items and referenced items for
396
	 * @param int $count Maximum number of items which should be returned
397
	 * @return \Aimeos\Map|null List of items implementing \Aimeos\MShop\Common\Item\Iface with ids as keys
398
	 */
399
	public function iterate( \Aimeos\MShop\Common\Iterator\Iface $iterator, array $ref = [], int $count = 100 ) : ?\Aimeos\Map
400
	{
401
		return $this->iterateIndexBase( $iterator, $ref, $count );
402
	}
403
404
405
	/**
406
	 * Rebuilds the index for searching products or specified list of products.
407
	 * This can be a long lasting operation.
408
	 *
409
	 * @param \Aimeos\MShop\Product\Item\Iface[] $items Associative list of product IDs as keys and items as values
410
	 * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
411
	 */
412
	public function rebuild( iterable $items = [] ) : \Aimeos\MShop\Index\Manager\Iface
413
	{
414
		$context = $this->context();
415
		$config = $context->config();
416
417
		/** mshop/index/manager/chunksize
418
		 * Number of products that should be indexed at once
419
		 *
420
		 * When rebuilding the product index, several products are updated at
421
		 * once within a transaction. This speeds up the time that is needed
422
		 * for reindexing.
423
		 *
424
		 * Usually, the more products are updated in one bunch, the faster the
425
		 * process of rebuilding the index will be up to a certain limit. The
426
		 * downside of big bunches is a higher memory consumption that can
427
		 * exceed the maximum allowed memory of the process.
428
		 *
429
		 * @param int Number of products
430
		 * @since 2014.09
431
		 * @category User
432
		 * @category Developer
433
		 * @see mshop/index/manager/domains
434
		 * @see mshop/index/manager/index
435
		 * @see mshop/index/manager/subdomains
436
		 * @see mshop/index/manager/submanagers
437
		 */
438
		$size = $config->get( 'mshop/index/manager/chunksize', 1000 );
439
440
		/** mshop/index/manager/domains
441
		 * A list of domain names whose items should be retrieved together with the product
442
		 *
443
		 * To speed up the indexing process, items like texts, prices, media,
444
		 * attributes etc. which have been associated to products can be
445
		 * retrieved together with the products.
446
		 *
447
		 * Please note that the index submanagers expect that the items
448
		 * associated to the products are fetched together with the products.
449
		 * Thus, if you leave out a domain, this information won't be part
450
		 * of the indexed product and therefore won't be found when searching
451
		 * the index.
452
		 *
453
		 * @param string List of MShop domain names
454
		 * @since 2014.09
455
		 * @category Developer
456
		 * @see mshop/index/manager/chunksize
457
		 * @see mshop/index/manager/index
458
		 * @see mshop/index/manager/subdomains
459
		 * @see mshop/index/manager/submanagers
460
		 */
461
		$domains = $config->get( 'mshop/index/manager/domains', [] );
462
463
		$manager = \Aimeos\MShop::create( $context, 'product' );
464
		$search = $manager->filter()->order( 'product.id' );
465
466
		if( !( $prodIds = map( $items )->getId() )->isEmpty() ) { // don't rely on array keys
467
			$search->add( 'product.id', '==', $prodIds->toArray() );
468
		}
469
470
		$this->writeIndex( $search, $domains, $size );
471
		return $this;
472
	}
473
474
475
	/**
476
	 * Searches for items matching the given criteria.
477
	 *
478
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria object
479
	 * @param string[] $ref List of domains to fetch list items and referenced items for
480
	 * @param int|null &$total Number of items that are available in total
481
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Product\Item\Iface with ids as keys
482
	 */
483
	public function search( \Aimeos\Base\Criteria\Iface $search, array $ref = [], int &$total = null ) : \Aimeos\Map
484
	{
485
		/** mshop/index/manager/search/mysql
486
		 * Retrieves the records matched by the given criteria in the database
487
		 *
488
		 * @see mshop/index/manager/search/ansi
489
		 */
490
491
		/** mshop/index/manager/search/ansi
492
		 * Retrieves the records matched by the given criteria in the database
493
		 *
494
		 * Fetches the records matched by the given criteria from the order
495
		 * database. The records must be from one of the sites that are
496
		 * configured via the context item. If the current site is part of
497
		 * a tree of sites, the SELECT statement can retrieve all records
498
		 * from the current site and the complete sub-tree of sites.
499
		 *
500
		 * As the records can normally be limited by criteria from sub-managers,
501
		 * their tables must be joined in the SQL context. This is done by
502
		 * using the "internaldeps" property from the definition of the ID
503
		 * column of the sub-managers. These internal dependencies specify
504
		 * the JOIN between the tables and the used columns for joining. The
505
		 * ":joins" placeholder is then replaced by the JOIN strings from
506
		 * the sub-managers.
507
		 *
508
		 * To limit the records matched, conditions can be added to the given
509
		 * criteria object. It can contain comparisons like column names that
510
		 * must match specific values which can be combined by AND, OR or NOT
511
		 * operators. The resulting string of SQL conditions replaces the
512
		 * ":cond" placeholder before the statement is sent to the database
513
		 * server.
514
		 *
515
		 * If the records that are retrieved should be ordered by one or more
516
		 * columns, the generated string of column / sort direction pairs
517
		 * replaces the ":order" placeholder. In case no ordering is required,
518
		 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
519
		 * markers is removed to speed up retrieving the records. Columns of
520
		 * sub-managers can also be used for ordering the result set but then
521
		 * no index can be used.
522
		 *
523
		 * The number of returned records can be limited and can start at any
524
		 * number between the begining and the end of the result set. For that
525
		 * the ":size" and ":start" placeholders are replaced by the
526
		 * corresponding values from the criteria object. The default values
527
		 * are 0 for the start and 100 for the size value.
528
		 *
529
		 * The SQL statement should conform to the ANSI standard to be
530
		 * compatible with most relational database systems. This also
531
		 * includes using double quotes for table and column names.
532
		 *
533
		 * @param string SQL statement for searching items
534
		 * @since 2014.03
535
		 * @category Developer
536
		 * @see mshop/index/manager/count/ansi
537
		 * @see mshop/index/manager/iterate/ansi
538
		 * @see mshop/index/manager/optimize/ansi
539
		 * @see mshop/index/manager/aggregate/ansi
540
		 */
541
		$cfgPathSearch = 'mshop/index/manager/search';
542
543
		/** mshop/index/manager/count/mysql
544
		 * Counts the number of records matched by the given criteria in the database
545
		 *
546
		 * @see mshop/index/manager/count/ansi
547
		 */
548
549
		/** mshop/index/manager/count/ansi
550
		 * Counts the number of records matched by the given criteria in the database
551
		 *
552
		 * Counts all records matched by the given criteria from the order
553
		 * database. The records must be from one of the sites that are
554
		 * configured via the context item. If the current site is part of
555
		 * a tree of sites, the statement can count all records from the
556
		 * current site and the complete sub-tree of sites.
557
		 *
558
		 * As the records can normally be limited by criteria from sub-managers,
559
		 * their tables must be joined in the SQL context. This is done by
560
		 * using the "internaldeps" property from the definition of the ID
561
		 * column of the sub-managers. These internal dependencies specify
562
		 * the JOIN between the tables and the used columns for joining. The
563
		 * ":joins" placeholder is then replaced by the JOIN strings from
564
		 * the sub-managers.
565
		 *
566
		 * To limit the records matched, conditions can be added to the given
567
		 * criteria object. It can contain comparisons like column names that
568
		 * must match specific values which can be combined by AND, OR or NOT
569
		 * operators. The resulting string of SQL conditions replaces the
570
		 * ":cond" placeholder before the statement is sent to the database
571
		 * server.
572
		 *
573
		 * Both, the strings for ":joins" and for ":cond" are the same as for
574
		 * the "search" SQL statement.
575
		 *
576
		 * Contrary to the "search" statement, it doesn't return any records
577
		 * but instead the number of records that have been found. As counting
578
		 * thousands of records can be a long running task, the maximum number
579
		 * of counted records is limited for performance reasons.
580
		 *
581
		 * The SQL statement should conform to the ANSI standard to be
582
		 * compatible with most relational database systems. This also
583
		 * includes using double quotes for table and column names.
584
		 *
585
		 * @param string SQL statement for counting items
586
		 * @since 2014.03
587
		 * @category Developer
588
		 * @see mshop/index/manager/search/ansi
589
		 * @see mshop/index/manager/iterate/ansi
590
		 * @see mshop/index/manager/optimize/ansi
591
		 * @see mshop/index/manager/aggregate/ansi
592
		 */
593
		$cfgPathCount = 'mshop/index/manager/count';
594
595
		return $this->searchItemsIndexBase( $search, $ref, $total, $cfgPathSearch, $cfgPathCount );
596
	}
597
598
599
	/**
600
	 * Re-writes the index entries for all products that are search result of given criteria
601
	 *
602
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria
603
	 * @param string[] $domains List of domains to be
604
	 * @param int $size Size of a chunk of products to handle at a time
605
	 */
606
	protected function writeIndex( \Aimeos\Base\Criteria\Iface $search, array $domains, int $size )
607
	{
608
		$context = $this->context();
609
		$manager = \Aimeos\MShop::create( $context, 'product' );
610
		$submanagers = $this->getSubManagers();
611
		$start = 0;
612
613
		do
614
		{
615
			$search->slice( $start, $size );
616
			$products = $manager->search( $search, $domains );
617
618
			try
619
			{
620
				$this->begin();
621
622
				$this->remove( $products );
0 ignored issues
show
Bug introduced by
$products of type Aimeos\Map is incompatible with the type array|string expected by parameter $ids of Aimeos\MShop\Index\Manager\DBBase::remove(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

622
				$this->remove( /** @scrutinizer ignore-type */ $products );
Loading history...
623
624
				foreach( $submanagers as $submanager ) {
625
					$submanager->rebuild( $products );
626
				}
627
628
				$this->commit();
629
			}
630
			catch( \Exception $e )
631
			{
632
				$this->rollback();
633
				throw $e;
634
			}
635
636
			$context->cache()->deleteByTags( $products->keys()->prefix( 'product-' )->all() );
637
638
			$count = count( $products );
639
			$start += $count;
640
		}
641
		while( $count == $search->getLimit() );
642
	}
643
644
645
	/**
646
	 * Returns the list of sub-managers available for the index attribute manager.
647
	 *
648
	 * @return \Aimeos\MShop\Index\Manager\Iface[] Associative list of the sub-domain as key and the manager object as value
649
	 */
650
	protected function getSubManagers() : array
651
	{
652
		if( $this->subManagers === null )
653
		{
654
			$this->subManagers = [];
655
			$config = $this->context()->config();
656
657
			/** mshop/index/manager/submanagers
658
			 * A list of sub-manager names used for indexing associated items
659
			 *
660
			 * All items referenced by a product (e.g. texts, prices, media,
661
			 * etc.) are added to the product index via specialized index
662
			 * managers. You can add the name of new sub-managers to add more
663
			 * data to the index or remove existing ones if you don't want to
664
			 * index that data at all.
665
			 *
666
			 * Caution: Please note that the list of sub-manager names should
667
			 * correspond to the list of domains that are fetched together with
668
			 * the products as the sub-manager depends on the items being
669
			 * retrieved there and fetching items that won't be indexed is a
670
			 * waste of resources.
671
			 *
672
			 * @param string List of index sub-manager names
673
			 * @since 2016.02
674
			 * @category User
675
			 * @category Developer
676
			 * @see mshop/index/manager/chunksize
677
			 * @see mshop/index/manager/domains
678
			 * @see mshop/index/manager/index
679
			 * @see mshop/index/manager/subdomains
680
			 */
681
			foreach( $config->get( 'mshop/index/manager/submanagers', [] ) as $domain )
682
			{
683
				$name = $config->get( 'mshop/index/manager/' . $domain . '/name' );
684
				$this->subManagers[$domain] = $this->object()->getSubManager( $domain, $name );
685
			}
686
687
			return $this->subManagers;
688
		}
689
690
		return $this->subManagers;
691
	}
692
}
693