Passed
Push — master ( 5a0518...247ea4 )
by Aimeos
14:19
created

Base::searchItemsBase()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 48
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 26
nc 18
nop 8
dl 0
loc 48
rs 8.8817
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2023
6
 * @package MShop
7
 * @subpackage Common
8
 */
9
10
11
namespace Aimeos\MShop\Common\Manager;
12
13
14
/**
15
 * Provides common methods required by most of the manager classes.
16
 *
17
 * @package MShop
18
 * @subpackage Common
19
 */
20
abstract class Base implements \Aimeos\Macro\Iface
21
{
22
	use \Aimeos\Macro\Macroable;
23
	use Sub\Traits;
24
	use Methods;
25
	use Site;
26
	use DB;
27
28
29
	private \Aimeos\MShop\ContextIface $context;
30
	private ?\Aimeos\Base\Criteria\Iface $search;
31
32
33
	/**
34
	 * Initialization of class.
35
	 *
36
	 * @param \Aimeos\MShop\ContextIface $context Context object
37
	 */
38
	public function __construct( \Aimeos\MShop\ContextIface $context )
39
	{
40
		$this->context = $context;
41
		$this->init(); // init support trait
42
	}
43
44
45
	/**
46
	 * Removes old entries from the storage.
47
	 *
48
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
49
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
50
	 */
51
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
52
	{
53
		foreach( $this->context()->config()->get( $this->getConfigKey( 'submanagers' ), [] ) as $domain ) {
54
			$this->object()->getSubManager( $domain )->clear( $siteids );
55
		}
56
57
		return $this->clearBase( $siteids, $this->getConfigKey( 'delete' ) );
58
	}
59
60
61
	/**
62
	 * Creates a new empty item instance
63
	 *
64
	 * @param array $values Values the item should be initialized with
65
	 * @return \Aimeos\MShop\Attribute\Item\Iface New attribute item object
66
	 */
67
	public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
68
	{
69
		$values['siteid'] = $values['siteid'] ?? $this->context()->locale()->getSiteId();
70
71
		return new \Aimeos\MShop\Common\Item\Base( '', $values );
72
	}
73
74
75
	/**
76
	 * Creates a new cursor based on the filter criteria
77
	 *
78
	 * @param \Aimeos\Base\Criteria\Iface $filter Criteria object with conditions, sortations, etc.
79
	 * @return \Aimeos\MShop\Common\Cursor\Iface Cursor object
80
	 */
81
	public function cursor( \Aimeos\Base\Criteria\Iface $filter ) : \Aimeos\MShop\Common\Cursor\Iface
82
	{
83
		return new \Aimeos\MShop\Common\Cursor\Standard( $filter );
84
	}
85
86
87
	/**
88
	 * Removes multiple items.
89
	 *
90
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
91
	 * @return \Aimeos\MShop\Attribute\Manager\Iface Manager object for chaining method calls
92
	 */
93
	public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
94
	{
95
		return $this->deleteItemsBase( $itemIds, $this->getConfigKey( 'delete' ) );
96
	}
97
98
99
	/**
100
	 * Creates a search critera object
101
	 *
102
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
103
	 * @param bool $site TRUE for adding site criteria to limit items by the site of related items
104
	 * @return \Aimeos\Base\Criteria\Iface New search criteria object
105
	 */
106
	public function filter( ?bool $default = false, bool $site = false ) : \Aimeos\Base\Criteria\Iface
107
	{
108
		$context = $this->context();
109
		$db = $this->getResourceName();
110
		$conn = $context->db( $db );
111
		$config = $context->config();
112
113
		if( ( $adapter = $config->get( 'resource/' . $db . '/adapter' ) ) === null ) {
114
			$adapter = $config->get( 'resource/db/adapter' );
115
		}
116
117
		switch( $adapter )
118
		{
119
			case 'pgsql':
120
				$search = new \Aimeos\Base\Criteria\PgSQL( $conn ); break;
121
			default:
122
				$search = new \Aimeos\Base\Criteria\SQL( $conn ); break;
123
		}
124
125
		return $search;
126
	}
127
128
129
	/**
130
	 * Returns the attributes item specified by its ID.
131
	 *
132
	 * @param string $id Unique ID of the attribute item in the storage
133
	 * @param string[] $ref List of domains to fetch list items and referenced items for
134
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
135
	 * @return \Aimeos\MShop\Attribute\Item\Iface Returns the attribute item of the given id
136
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
137
	 */
138
	public function get( string $id, array $ref = [], ?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
139
	{
140
		return $this->getItemBase( 'id', $id, $ref, $default );
141
	}
142
143
144
	/**
145
	 * Returns the available manager types
146
	 *
147
	 * @param bool $withsub Return also the resource type of sub-managers if true
148
	 * @return string[] Type of the manager and submanagers, subtypes are separated by slashes
149
	 */
150
	public function getResourceType( bool $withsub = true ) : array
151
	{
152
		return $this->getResourceTypeBase( $this->getDomain(), $this->getConfigKey( 'submanagers' ), [], $withsub );
153
	}
154
155
156
	/**
157
	 * Returns the additional column/search definitions
158
	 *
159
	 * @return array Associative list of column names as keys and items implementing \Aimeos\Base\Criteria\Attribute\Iface
160
	 */
161
	public function getSaveAttributes() : array
162
	{
163
		return [];
164
	}
165
166
167
	/**
168
	 * Returns the attributes that can be used for searching.
169
	 *
170
	 * @param bool $withsub Return also attributes of sub-managers if true
171
	 * @return \Aimeos\Base\Criteria\Attribute\Iface[] List of attribute items
172
	 */
173
	public function getSearchAttributes( bool $withsub = true ) : array
174
	{
175
		return $this->createAttributes( [
176
			'id' => [
177
				'label' => 'ID',
178
				'type' => 'int',
179
				'public' => false,
180
			],
181
			'siteid' => [
182
				'label' => 'Site ID',
183
				'public' => false,
184
			],
185
			'ctime' => [
186
				'label' => 'Create date/time',
187
				'type' => 'datetime',
188
				'public' => false,
189
			],
190
			'mtime' => [
191
				'label' => 'Modification date/time',
192
				'type' => 'datetime',
193
				'public' => false,
194
			],
195
			'editor' => [
196
				'label' => 'Editor',
197
				'public' => false,
198
			],
199
		] ) + $this->getSaveAttributes();
200
	}
201
202
203
	/**
204
	 * Returns a new manager for attribute extensions
205
	 *
206
	 * @param string $manager Name of the sub manager type in lower case
207
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
208
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g Type, List's etc.
209
	 */
210
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
211
	{
212
		return $this->getSubManagerBase( $this->getDomain(), $manager, $name );
213
	}
214
215
216
	/**
217
	 * Iterates over all matched items and returns the found ones
218
	 *
219
	 * @param \Aimeos\MShop\Common\Cursor\Iface $cursor Cursor object with filter, domains and cursor
220
	 * @param string[] $ref List of domains whose items should be fetched too
221
	 * @return \Aimeos\Map|null List of items implementing \Aimeos\MShop\Common\Item\Iface with ids as keys
222
	 */
223
	public function iterate( \Aimeos\MShop\Common\Cursor\Iface $cursor, array $ref = [] ) : ?\Aimeos\Map
224
	{
225
		if( $cursor->value() === '' ) {
226
			return null;
227
		}
228
229
		$key = key( $this->getSearchAttributes() );
230
		$filter = $cursor->filter()->add( $key, '>', (int) $cursor->value() )->order( $key );
231
232
		$items = $this->search( $filter, $ref );
233
		$cursor->setValue( $items->lastKey() ?: '' );
234
235
		return !$items->isEmpty() ? $items : null;
236
	}
237
238
239
	/**
240
	 * Adds or updates an item object or a list of them.
241
	 *
242
	 * @param \Aimeos\Map|\Aimeos\MShop\Common\Item\Iface[]|\Aimeos\MShop\Common\Item\Iface $items Item or list of items whose data should be saved
243
	 * @param bool $fetch True if the new ID should be returned in the item
244
	 * @return \Aimeos\Map|\Aimeos\MShop\Common\Item\Iface Saved item or items
245
	 */
246
	public function save( $items, bool $fetch = true )
247
	{
248
		foreach( map( $items ) as $item )
249
		{
250
			if( method_exists( $this, 'saveItem' ) ) {
251
				$this->saveItem( $item, $fetch );
0 ignored issues
show
Bug introduced by
The method saveItem() does not exist on Aimeos\MShop\Common\Manager\Base. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

251
				$this->/** @scrutinizer ignore-call */ 
252
           saveItem( $item, $fetch );
Loading history...
252
			} else {
253
				$this->saveBase( $item, $fetch );
254
			}
255
		}
256
257
		return is_array( $items ) ? map( $items ) : $items;
258
	}
259
260
261
	/**
262
	 * Searches for all items matching the given critera.
263
	 *
264
	 * @param \Aimeos\Base\Criteria\Iface $filter Criteria object with conditions, sortations, etc.
265
	 * @param string[] $ref List of domains to fetch list items and referenced items for
266
	 * @param int &$total Number of items that are available in total
267
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Common\Item\Iface with ids as keys
268
	 */
269
	public function search( \Aimeos\Base\Criteria\Iface $filter, array $ref = [], int &$total = null ) : \Aimeos\Map
270
	{
271
		/** mshop/common/manager/search/mysql
272
		 * Retrieves the records matched by the given criteria in the database
273
		 *
274
		 * @see mshop/common/manager/search/ansi
275
		 */
276
277
		/** mshop/common/manager/search/ansi
278
		 * Retrieves the records matched by the given criteria in the database
279
		 *
280
		 * Fetches the records matched by the given criteria from the
281
		 * database. The records must be from one of the sites that are
282
		 * configured via the context item. If the current site is part of
283
		 * a tree of sites, the SELECT statement can retrieve all records
284
		 * from the current site and the complete sub-tree of sites.
285
		 *
286
		 * As the records can normally be limited by criteria from sub-managers,
287
		 * their tables must be joined in the SQL context. This is done by
288
		 * using the "internaldeps" property from the definition of the ID
289
		 * column of the sub-managers. These internal dependencies specify
290
		 * the JOIN between the tables and the used columns for joining. The
291
		 * ":joins" placeholder is then replaced by the JOIN strings from
292
		 * the sub-managers.
293
		 *
294
		 * To limit the records matched, conditions can be added to the given
295
		 * criteria object. It can contain comparisons like column names that
296
		 * must match specific values which can be combined by AND, OR or NOT
297
		 * operators. The resulting string of SQL conditions replaces the
298
		 * ":cond" placeholder before the statement is sent to the database
299
		 * server.
300
		 *
301
		 * If the records that are retrieved should be ordered by one or more
302
		 * columns, the generated string of column / sort direction pairs
303
		 * replaces the ":order" placeholder. In case no ordering is required,
304
		 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
305
		 * markers is removed to speed up retrieving the records. Columns of
306
		 * sub-managers can also be used for ordering the result set but then
307
		 * no index can be used.
308
		 *
309
		 * The number of returned records can be limited and can start at any
310
		 * number between the begining and the end of the result set. For that
311
		 * the ":size" and ":start" placeholders are replaced by the
312
		 * corresponding values from the criteria object. The default values
313
		 * are 0 for the start and 100 for the size value.
314
		 *
315
		 * The SQL statement should conform to the ANSI standard to be
316
		 * compatible with most relational database systems. This also
317
		 * includes using double quotes for table and column names.
318
		 *
319
		 * @param string SQL statement for searching items
320
		 * @since 2023.10
321
		 * @category Developer
322
		 * @see mshop/common/manager/insert/ansi
323
		 * @see mshop/common/manager/update/ansi
324
		 * @see mshop/common/manager/newid/ansi
325
		 * @see mshop/common/manager/delete/ansi
326
		 * @see mshop/common/manager/count/ansi
327
		 */
328
		$cfgPathSearch = 'mshop/common/manager/search';
329
330
		/** mshop/common/manager/count/mysql
331
		 * Counts the number of records matched by the given criteria in the database
332
		 *
333
		 * @see mshop/common/manager/count/ansi
334
		 */
335
336
		/** mshop/common/manager/count/ansi
337
		 * Counts the number of records matched by the given criteria in the database
338
		 *
339
		 * Counts all records matched by the given criteria from the
340
		 * database. The records must be from one of the sites that are
341
		 * configured via the context item. If the current site is part of
342
		 * a tree of sites, the statement can count all records from the
343
		 * current site and the complete sub-tree of sites.
344
		 *
345
		 * As the records can normally be limited by criteria from sub-managers,
346
		 * their tables must be joined in the SQL context. This is done by
347
		 * using the "internaldeps" property from the definition of the ID
348
		 * column of the sub-managers. These internal dependencies specify
349
		 * the JOIN between the tables and the used columns for joining. The
350
		 * ":joins" placeholder is then replaced by the JOIN strings from
351
		 * the sub-managers.
352
		 *
353
		 * To limit the records matched, conditions can be added to the given
354
		 * criteria object. It can contain comparisons like column names that
355
		 * must match specific values which can be combined by AND, OR or NOT
356
		 * operators. The resulting string of SQL conditions replaces the
357
		 * ":cond" placeholder before the statement is sent to the database
358
		 * server.
359
		 *
360
		 * Both, the strings for ":joins" and for ":cond" are the same as for
361
		 * the "search" SQL statement.
362
		 *
363
		 * Contrary to the "search" statement, it doesn't return any records
364
		 * but instead the number of records that have been found. As counting
365
		 * thousands of records can be a long running task, the maximum number
366
		 * of counted records is limited for performance reasons.
367
		 *
368
		 * The SQL statement should conform to the ANSI standard to be
369
		 * compatible with most relational database systems. This also
370
		 * includes using double quotes for table and column names.
371
		 *
372
		 * @param string SQL statement for counting items
373
		 * @since 2023.10
374
		 * @category Developer
375
		 * @see mshop/common/manager/insert/ansi
376
		 * @see mshop/common/manager/update/ansi
377
		 * @see mshop/common/manager/newid/ansi
378
		 * @see mshop/common/manager/delete/ansi
379
		 * @see mshop/common/manager/search/ansi
380
		 */
381
		$cfgPathCount = 'mshop/common/manager/count';
382
383
		$items = [];
384
		$level = $this->getSiteMode();
385
		$required = [$this->getSearchKey()];
386
		$conn = $this->context()->db( $this->getResourceName() );
387
388
		$results = $this->searchItemsBase( $conn, $filter, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
0 ignored issues
show
Bug introduced by
$level of type string is incompatible with the type integer expected by parameter $sitelevel of Aimeos\MShop\Common\Mana...Base::searchItemsBase(). ( Ignorable by Annotation )

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

388
		$results = $this->searchItemsBase( $conn, $filter, $cfgPathSearch, $cfgPathCount, $required, $total, /** @scrutinizer ignore-type */ $level );
Loading history...
389
390
		while( $row = $results->fetch() )
391
		{
392
			if( $item = $this->applyFilter( $this->create( $row ) ) ) {
393
				$items[$row['id']] = $item;
394
			}
395
		}
396
397
		return map( $items );
398
	}
399
400
401
	/**
402
	 * Starts a database transaction on the connection identified by the given name
403
	 *
404
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
405
	 */
406
	public function begin() : \Aimeos\MShop\Common\Manager\Iface
407
	{
408
		$this->context->db( $this->getResourceName() )->begin();
409
		return $this;
410
	}
411
412
413
	/**
414
	 * Commits the running database transaction on the connection identified by the given name
415
	 *
416
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
417
	 */
418
	public function commit() : \Aimeos\MShop\Common\Manager\Iface
419
	{
420
		$this->context->db( $this->getResourceName() )->commit();
421
		return $this;
422
	}
423
424
425
	/**
426
	 * Rolls back the running database transaction on the connection identified by the given name
427
	 *
428
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
429
	 */
430
	public function rollback() : \Aimeos\MShop\Common\Manager\Iface
431
	{
432
		$this->context->db( $this->getResourceName() )->rollback();
433
		return $this;
434
	}
435
436
437
	/**
438
	 * Returns the context object.
439
	 *
440
	 * @return \Aimeos\MShop\ContextIface Context object
441
	 */
442
	protected function context() : \Aimeos\MShop\ContextIface
443
	{
444
		return $this->context;
445
	}
446
447
448
	/**
449
	 * Returns the site mode constant for inheritance/aggregation
450
	 *
451
	 * @return int Site mode constant (default: SITE_ALL for inheritance and aggregation)
452
	 */
453
	protected function getSiteMode() : string
454
	{
455
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
456
		return $this->context()->config()->get( $this->getConfigKey( 'sitemode' ), $level );
457
	}
458
459
460
	/**
461
	 * Returns a search object singleton
462
	 *
463
	 * @return \Aimeos\Base\Criteria\Iface Search object
464
	 */
465
	protected function getSearch() : \Aimeos\Base\Criteria\Iface
466
	{
467
		if( !isset( $this->search ) ) {
468
			$this->search = $this->filter();
469
		}
470
471
		return $this->search;
472
	}
473
}
474