Passed
Push — master ( 69c572...92beea )
by Aimeos
05:23
created

Standard::__construct()   B

Complexity

Conditions 10
Paths 1

Size

Total Lines 45
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 24
nc 1
nop 1
dl 0
loc 45
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

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 Media
9
 */
10
11
12
namespace Aimeos\MShop\Media\Manager;
13
14
15
/**
16
 * Default media manager implementation.
17
 *
18
 * @package MShop
19
 * @subpackage Media
20
 */
21
class Standard
22
	extends \Aimeos\MShop\Common\Manager\Base
23
	implements \Aimeos\MShop\Media\Manager\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
24
{
25
	use \Aimeos\MShop\Common\Manager\ListsRef\Traits;
26
	use \Aimeos\MShop\Common\Manager\PropertyRef\Traits;
27
28
29
	private $searchConfig = array(
30
		'media.id' => array(
31
			'label' => 'ID',
32
			'code' => 'media.id',
33
			'internalcode' => 'mmed."id"',
34
			'type' => 'integer',
35
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
36
		),
37
		'media.siteid' => array(
38
			'label' => 'Site ID',
39
			'code' => 'media.siteid',
40
			'internalcode' => 'mmed."siteid"',
41
			'type' => 'string',
42
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
43
			'public' => false,
44
		),
45
		'media.type' => array(
46
			'label' => 'Type',
47
			'code' => 'media.type',
48
			'internalcode' => 'mmed."type"',
49
			'type' => 'string',
50
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
51
		),
52
		'media.label' => array(
53
			'label' => 'Label',
54
			'code' => 'media.label',
55
			'internalcode' => 'mmed."label"',
56
			'type' => 'string',
57
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
58
		),
59
		'media.domain' => array(
60
			'label' => 'Domain',
61
			'code' => 'media.domain',
62
			'internalcode' => 'mmed."domain"',
63
			'type' => 'string',
64
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
65
		),
66
		'media.languageid' => array(
67
			'label' => 'Language code',
68
			'code' => 'media.languageid',
69
			'internalcode' => 'mmed."langid"',
70
			'type' => 'string',
71
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
72
		),
73
		'media.mimetype' => array(
74
			'label' => 'Mime type',
75
			'code' => 'media.mimetype',
76
			'internalcode' => 'mmed."mimetype"',
77
			'type' => 'string',
78
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
79
		),
80
		'media.url' => array(
81
			'label' => 'URL',
82
			'code' => 'media.url',
83
			'internalcode' => 'mmed."link"',
84
			'type' => 'string',
85
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
86
		),
87
		'media.preview' => array(
88
			'label' => 'Preview URLs as JSON encoded string',
89
			'code' => 'media.preview',
90
			'internalcode' => 'mmed."preview"',
91
			'type' => 'string',
92
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
93
		),
94
		'media.filesystem' => array(
95
			'label' => 'File sytem name',
96
			'code' => 'media.filesystem',
97
			'internalcode' => 'mmed."fsname"',
98
			'type' => 'string',
99
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
100
		),
101
		'media.status' => array(
102
			'label' => 'Status',
103
			'code' => 'media.status',
104
			'internalcode' => 'mmed."status"',
105
			'type' => 'integer',
106
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
107
		),
108
		'media.ctime' => array(
109
			'code' => 'media.ctime',
110
			'internalcode' => 'mmed."ctime"',
111
			'label' => 'Create date/time',
112
			'type' => 'datetime',
113
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
114
			'public' => false,
115
		),
116
		'media.mtime' => array(
117
			'code' => 'media.mtime',
118
			'internalcode' => 'mmed."mtime"',
119
			'label' => 'Modify date/time',
120
			'type' => 'datetime',
121
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
122
			'public' => false,
123
		),
124
		'media.editor' => array(
125
			'code' => 'media.editor',
126
			'internalcode' => 'mmed."editor"',
127
			'label' => 'Editor',
128
			'type' => 'string',
129
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
130
			'public' => false,
131
		),
132
		'media:has' => array(
133
			'code' => 'media:has()',
134
			'internalcode' => ':site AND :key AND mmedli."id"',
135
			'internaldeps' => ['LEFT JOIN "mshop_media_list" AS mmedli ON ( mmedli."parentid" = mmed."id" )'],
136
			'label' => 'Media has list item, parameter(<domain>[,<list type>[,<reference ID>)]]',
137
			'type' => 'null',
138
			'internaltype' => 'null',
139
			'public' => false,
140
		),
141
		'media:prop' => array(
142
			'code' => 'media:prop()',
143
			'internalcode' => ':site AND :key AND mmedpr."id"',
144
			'internaldeps' => ['LEFT JOIN "mshop_media_property" AS mmedpr ON ( mmedpr."parentid" = mmed."id" )'],
145
			'label' => 'Media has property item, parameter(<property type>[,<language code>[,<property value>]])',
146
			'type' => 'null',
147
			'internaltype' => 'null',
148
			'public' => false,
149
		),
150
	);
151
152
	private $languageId;
153
154
155
	/**
156
	 * Initializes the object.
157
	 *
158
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
159
	 */
160
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
161
	{
162
		parent::__construct( $context );
163
164
		$this->setResourceName( 'db-media' );
165
		$this->languageId = $context->locale()->getLanguageId();
166
167
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
168
		$level = $context->config()->get( 'mshop/media/manager/sitemode', $level );
169
170
171
		$this->searchConfig['media:has']['function'] = function( &$source, array $params ) use ( $level ) {
172
173
			$keys = [];
174
175
			foreach( (array) ( $params[1] ?? '' ) as $type ) {
176
				foreach( (array) ( $params[2] ?? '' ) as $id ) {
177
					$keys[] = $params[0] . '|' . ( $type ? $type . '|' : '' ) . $id;
178
				}
179
			}
180
181
			$sitestr = $this->getSiteString( 'mmedli."siteid"', $level );
182
			$keystr = $this->toExpression( 'mmedli."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
183
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
184
185
			return $params;
186
		};
187
188
189
		$this->searchConfig['media:prop']['function'] = function( &$source, array $params ) use ( $level ) {
190
191
			$keys = [];
192
			$langs = array_key_exists( 1, $params ) ? ( $params[1] ?? 'null' ) : '';
193
194
			foreach( (array) $langs as $lang ) {
195
				foreach( (array) ( $params[2] ?? '' ) as $val ) {
196
					$keys[] = substr( $params[0] . '|' . ( $lang === null ? 'null|' : ( $lang ? $lang . '|' : '' ) ) . $val, 0, 255 );
197
				}
198
			}
199
200
			$sitestr = $this->getSiteString( 'mmedpr."siteid"', $level );
201
			$keystr = $this->toExpression( 'mmedpr."key"', $keys, '=~' );
202
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
203
204
			return $params;
205
		};
206
	}
207
208
209
	/**
210
	 * Removes old entries from the storage.
211
	 *
212
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
213
	 * @return \Aimeos\MShop\Media\Manager\Iface Manager object for chaining method calls
214
	 */
215
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
216
	{
217
		$path = 'mshop/media/manager/submanagers';
218
		$default = ['lists', 'property', 'type'];
219
220
		foreach( $this->context()->config()->get( $path, $default ) as $domain ) {
221
			$this->object()->getSubManager( $domain )->clear( $siteids );
222
		}
223
224
		return $this->clearBase( $siteids, 'mshop/media/manager/delete' );
225
	}
226
227
228
	/**
229
	 * Creates a new empty item instance
230
	 *
231
	 * @param array $values Values the item should be initialized with
232
	 * @return \Aimeos\MShop\Media\Item\Iface New media item object
233
	 */
234
	public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
235
	{
236
		$values['media.siteid'] = $this->context()->locale()->getSiteId();
237
		return $this->createItemBase( $values );
238
	}
239
240
241
	/**
242
	 * Returns the available manager types
243
	 *
244
	 * @param bool $withsub Return also the resource type of sub-managers if true
245
	 * @return string[] Type of the manager and submanagers, subtypes are separated by slashes
246
	 */
247
	public function getResourceType( bool $withsub = true ) : array
248
	{
249
		$path = 'mshop/media/manager/submanagers';
250
		$default = ['lists', 'property'];
251
252
		return $this->getResourceTypeBase( 'media', $path, $default, $withsub );
253
	}
254
255
256
	/**
257
	 * Returns the attributes that can be used for searching.
258
	 *
259
	 * @param bool $withsub Return also attributes of sub-managers if true
260
	 * @return \Aimeos\MW\Criteria\Attribute\Iface[] List of search attribute items
261
	 */
262
	public function getSearchAttributes( bool $withsub = true ) : array
263
	{
264
		/** mshop/media/manager/submanagers
265
		 * List of manager names that can be instantiated by the media manager
266
		 *
267
		 * Managers provide a generic interface to the underlying storage.
268
		 * Each manager has or can have sub-managers caring about particular
269
		 * aspects. Each of these sub-managers can be instantiated by its
270
		 * parent manager using the getSubManager() method.
271
		 *
272
		 * The search keys from sub-managers can be normally used in the
273
		 * manager as well. It allows you to search for items of the manager
274
		 * using the search keys of the sub-managers to further limit the
275
		 * retrieved list of items.
276
		 *
277
		 * @param array List of sub-manager names
278
		 * @since 2014.03
279
		 * @category Developer
280
		 */
281
		$path = 'mshop/media/manager/submanagers';
282
283
		return $this->getSearchAttributesBase( $this->searchConfig, $path, [], $withsub );
284
	}
285
286
287
	/**
288
	 * Removes multiple items.
289
	 *
290
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
291
	 * @return \Aimeos\MShop\Media\Manager\Iface Manager object for chaining method calls
292
	 */
293
	public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
294
	{
295
		/** mshop/media/manager/delete/mysql
296
		 * Deletes the items matched by the given IDs from the database
297
		 *
298
		 * @see mshop/media/manager/delete/ansi
299
		 */
300
301
		/** mshop/media/manager/delete/ansi
302
		 * Deletes the items matched by the given IDs from the database
303
		 *
304
		 * Removes the records specified by the given IDs from the media database.
305
		 * The records must be from the site that is configured via the
306
		 * context item.
307
		 *
308
		 * The ":cond" placeholder is replaced by the name of the ID column and
309
		 * the given ID or list of IDs while the site ID is bound to the question
310
		 * mark.
311
		 *
312
		 * The SQL statement should conform to the ANSI standard to be
313
		 * compatible with most relational database systems. This also
314
		 * includes using double quotes for table and column names.
315
		 *
316
		 * @param string SQL statement for deleting items
317
		 * @since 2014.03
318
		 * @category Developer
319
		 * @see mshop/media/manager/insert/ansi
320
		 * @see mshop/media/manager/update/ansi
321
		 * @see mshop/media/manager/newid/ansi
322
		 * @see mshop/media/manager/search/ansi
323
		 * @see mshop/media/manager/count/ansi
324
		 */
325
		$path = 'mshop/media/manager/delete';
326
327
		return $this->deleteItemsBase( $itemIds, $path )->deleteRefItems( $itemIds );
328
	}
329
330
331
	/**
332
	 * Returns an item for the given ID.
333
	 *
334
	 * @param string $id ID of the item that should be retrieved
335
	 * @param string[] $ref List of domains to fetch list items and referenced items for
336
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
337
	 * @return \Aimeos\MShop\Media\Item\Iface Returns the media item of the given id
338
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
339
	 */
340
	public function get( string $id, array $ref = [], ?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
341
	{
342
		return $this->getItemBase( 'media.id', $id, $ref, $default );
343
	}
344
345
346
	/**
347
	 * Adds a new item to the storage or updates an existing one.
348
	 *
349
	 * @param \Aimeos\MShop\Media\Item\Iface $item New item that should be saved to the storage
350
	 * @param bool $fetch True if the new ID should be returned in the item
351
	 * @return \Aimeos\MShop\Media\Item\Iface $item Updated item including the generated ID
352
	 */
353
	public function saveItem( \Aimeos\MShop\Media\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Media\Item\Iface
354
	{
355
		if( !$item->isModified() )
356
		{
357
			$item = $this->savePropertyItems( $item, 'media', $fetch );
358
			return $this->saveListItems( $item, 'media', $fetch );
359
		}
360
361
		$context = $this->context();
362
363
		$dbm = $context->db();
364
		$dbname = $this->getResourceName();
365
		$conn = $dbm->acquire( $dbname );
366
367
		try
368
		{
369
			$id = $item->getId();
370
			$date = date( 'Y-m-d H:i:s' );
371
			$columns = $this->object()->getSaveAttributes();
372
373
			if( $id === null )
374
			{
375
				/** mshop/media/manager/insert/mysql
376
				 * Inserts a new media record into the database table
377
				 *
378
				 * @see mshop/media/manager/insert/ansi
379
				 */
380
381
				/** mshop/media/manager/insert/ansi
382
				 * Inserts a new media record into the database table
383
				 *
384
				 * Items with no ID yet (i.e. the ID is NULL) will be created in
385
				 * the database and the newly created ID retrieved afterwards
386
				 * using the "newid" SQL statement.
387
				 *
388
				 * The SQL statement must be a string suitable for being used as
389
				 * prepared statement. It must include question marks for binding
390
				 * the values from the media item to the statement before they are
391
				 * sent to the database server. The number of question marks must
392
				 * be the same as the number of columns listed in the INSERT
393
				 * statement. The order of the columns must correspond to the
394
				 * order in the save() method, so the correct values are
395
				 * bound to the columns.
396
				 *
397
				 * The SQL statement should conform to the ANSI standard to be
398
				 * compatible with most relational database systems. This also
399
				 * includes using double quotes for table and column names.
400
				 *
401
				 * @param string SQL statement for inserting records
402
				 * @since 2014.03
403
				 * @category Developer
404
				 * @see mshop/media/manager/update/ansi
405
				 * @see mshop/media/manager/newid/ansi
406
				 * @see mshop/media/manager/delete/ansi
407
				 * @see mshop/media/manager/search/ansi
408
				 * @see mshop/media/manager/count/ansi
409
				 */
410
				$path = 'mshop/media/manager/insert';
411
				$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ) );
0 ignored issues
show
Bug introduced by
It seems like $this->getSqlConfig($path) can also be of type array; however, parameter $sql of Aimeos\MShop\Common\Manager\Base::addSqlColumns() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

411
				$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
412
			}
413
			else
414
			{
415
				/** mshop/media/manager/update/mysql
416
				 * Updates an existing media record in the database
417
				 *
418
				 * @see mshop/media/manager/update/ansi
419
				 */
420
421
				/** mshop/media/manager/update/ansi
422
				 * Updates an existing media record in the database
423
				 *
424
				 * Items which already have an ID (i.e. the ID is not NULL) will
425
				 * be updated in the database.
426
				 *
427
				 * The SQL statement must be a string suitable for being used as
428
				 * prepared statement. It must include question marks for binding
429
				 * the values from the media item to the statement before they are
430
				 * sent to the database server. The order of the columns must
431
				 * correspond to the order in the save() method, so the
432
				 * correct values are bound to the columns.
433
				 *
434
				 * The SQL statement should conform to the ANSI standard to be
435
				 * compatible with most relational database systems. This also
436
				 * includes using double quotes for table and column names.
437
				 *
438
				 * @param string SQL statement for updating records
439
				 * @since 2014.03
440
				 * @category Developer
441
				 * @see mshop/media/manager/insert/ansi
442
				 * @see mshop/media/manager/newid/ansi
443
				 * @see mshop/media/manager/delete/ansi
444
				 * @see mshop/media/manager/search/ansi
445
				 * @see mshop/media/manager/count/ansi
446
				 */
447
				$path = 'mshop/media/manager/update';
448
				$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
449
			}
450
451
			$idx = 1;
452
			$stmt = $this->getCachedStatement( $conn, $path, $sql );
453
454
			foreach( $columns as $name => $entry ) {
455
				$stmt->bind( $idx++, $item->get( $name ), $entry->getInternalType() );
0 ignored issues
show
Bug introduced by
It seems like $entry->getInternalType() can also be of type string; however, parameter $type of Aimeos\MW\DB\Statement\Iface::bind() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

455
				$stmt->bind( $idx++, $item->get( $name ), /** @scrutinizer ignore-type */ $entry->getInternalType() );
Loading history...
456
			}
457
458
			$stmt->bind( $idx++, $item->getLanguageId() );
459
			$stmt->bind( $idx++, $item->getType() );
460
			$stmt->bind( $idx++, $item->getLabel() );
461
			$stmt->bind( $idx++, $item->getMimeType() );
462
			$stmt->bind( $idx++, $item->getUrl() );
463
			$stmt->bind( $idx++, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
464
			$stmt->bind( $idx++, $item->getFileSystem() );
465
			$stmt->bind( $idx++, $item->getDomain() );
466
			$stmt->bind( $idx++, json_encode( $item->getPreviews(), JSON_FORCE_OBJECT ) );
467
			$stmt->bind( $idx++, $date ); // mtime
468
			$stmt->bind( $idx++, $context->editor() );
469
			$stmt->bind( $idx++, $context->locale()->getSiteId() );
470
471
			if( $id !== null ) {
472
				$stmt->bind( $idx++, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
473
			} else {
474
				$stmt->bind( $idx++, $date ); // ctime
475
			}
476
477
			$stmt->execute()->finish();
478
479
			if( $id === null )
480
			{
481
				/** mshop/media/manager/newid/mysql
482
				 * Retrieves the ID generated by the database when inserting a new record
483
				 *
484
				 * @see mshop/media/manager/newid/ansi
485
				 */
486
487
				/** mshop/media/manager/newid/ansi
488
				 * Retrieves the ID generated by the database when inserting a new record
489
				 *
490
				 * As soon as a new record is inserted into the database table,
491
				 * the database server generates a new and unique identifier for
492
				 * that record. This ID can be used for retrieving, updating and
493
				 * deleting that specific record from the table again.
494
				 *
495
				 * For MySQL:
496
				 *  SELECT LAST_INSERT_ID()
497
				 * For PostgreSQL:
498
				 *  SELECT currval('seq_mmed_id')
499
				 * For SQL Server:
500
				 *  SELECT SCOPE_IDENTITY()
501
				 * For Oracle:
502
				 *  SELECT "seq_mmed_id".CURRVAL FROM DUAL
503
				 *
504
				 * There's no way to retrive the new ID by a SQL statements that
505
				 * fits for most database servers as they implement their own
506
				 * specific way.
507
				 *
508
				 * @param string SQL statement for retrieving the last inserted record ID
509
				 * @since 2014.03
510
				 * @category Developer
511
				 * @see mshop/media/manager/insert/ansi
512
				 * @see mshop/media/manager/update/ansi
513
				 * @see mshop/media/manager/delete/ansi
514
				 * @see mshop/media/manager/search/ansi
515
				 * @see mshop/media/manager/count/ansi
516
				 */
517
				$path = 'mshop/media/manager/newid';
518
				$id = $this->newId( $conn, $path );
519
			}
520
521
			$item->setId( $id );
522
523
			$dbm->release( $conn, $dbname );
524
		}
525
		catch( \Exception $e )
526
		{
527
			$dbm->release( $conn, $dbname );
528
			throw $e;
529
		}
530
531
		$item = $this->savePropertyItems( $item, 'media', $fetch );
532
		return $this->saveListItems( $item, 'media', $fetch );
533
	}
534
535
536
	/**
537
	 * Returns the item objects matched by the given search criteria.
538
	 *
539
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
540
	 * @param string[] $ref List of domains to fetch list items and referenced items for
541
	 * @param int|null &$total Number of items that are available in total
542
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Media\Item\Iface with ids as keys
543
	 */
544
	public function search( \Aimeos\MW\Criteria\Iface $search, array $ref = [], int &$total = null ) : \Aimeos\Map
545
	{
546
		$map = [];
547
		$context = $this->context();
548
549
		$dbm = $context->db();
550
		$dbname = $this->getResourceName();
551
		$conn = $dbm->acquire( $dbname );
552
553
		try
554
		{
555
			$required = array( 'media' );
556
557
			/** mshop/media/manager/sitemode
558
			 * Mode how items from levels below or above in the site tree are handled
559
			 *
560
			 * By default, only items from the current site are fetched from the
561
			 * storage. If the ai-sites extension is installed, you can create a
562
			 * tree of sites. Then, this setting allows you to define for the
563
			 * whole media domain if items from parent sites are inherited,
564
			 * sites from child sites are aggregated or both.
565
			 *
566
			 * Available constants for the site mode are:
567
			 * * 0 = only items from the current site
568
			 * * 1 = inherit items from parent sites
569
			 * * 2 = aggregate items from child sites
570
			 * * 3 = inherit and aggregate items at the same time
571
			 *
572
			 * You also need to set the mode in the locale manager
573
			 * (mshop/locale/manager/sitelevel) to one of the constants.
574
			 * If you set it to the same value, it will work as described but you
575
			 * can also use different modes. For example, if inheritance and
576
			 * aggregation is configured the locale manager but only inheritance
577
			 * in the domain manager because aggregating items makes no sense in
578
			 * this domain, then items wil be only inherited. Thus, you have full
579
			 * control over inheritance and aggregation in each domain.
580
			 *
581
			 * @param int Constant from Aimeos\MShop\Locale\Manager\Base class
582
			 * @category Developer
583
			 * @since 2018.01
584
			 * @see mshop/locale/manager/sitelevel
585
			 */
586
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
587
			$level = $context->config()->get( 'mshop/media/manager/sitemode', $level );
588
589
			/** mshop/media/manager/search/mysql
590
			 * Retrieves the records matched by the given criteria in the database
591
			 *
592
			 * @see mshop/media/manager/search/ansi
593
			 */
594
595
			/** mshop/media/manager/search/ansi
596
			 * Retrieves the records matched by the given criteria in the database
597
			 *
598
			 * Fetches the records matched by the given criteria from the media
599
			 * database. The records must be from one of the sites that are
600
			 * configured via the context item. If the current site is part of
601
			 * a tree of sites, the SELECT statement can retrieve all records
602
			 * from the current site and the complete sub-tree of sites.
603
			 *
604
			 * As the records can normally be limited by criteria from sub-managers,
605
			 * their tables must be joined in the SQL context. This is done by
606
			 * using the "internaldeps" property from the definition of the ID
607
			 * column of the sub-managers. These internal dependencies specify
608
			 * the JOIN between the tables and the used columns for joining. The
609
			 * ":joins" placeholder is then replaced by the JOIN strings from
610
			 * the sub-managers.
611
			 *
612
			 * To limit the records matched, conditions can be added to the given
613
			 * criteria object. It can contain comparisons like column names that
614
			 * must match specific values which can be combined by AND, OR or NOT
615
			 * operators. The resulting string of SQL conditions replaces the
616
			 * ":cond" placeholder before the statement is sent to the database
617
			 * server.
618
			 *
619
			 * If the records that are retrieved should be ordered by one or more
620
			 * columns, the generated string of column / sort direction pairs
621
			 * replaces the ":order" placeholder. In case no ordering is required,
622
			 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
623
			 * markers is removed to speed up retrieving the records. Columns of
624
			 * sub-managers can also be used for ordering the result set but then
625
			 * no index can be used.
626
			 *
627
			 * The number of returned records can be limited and can start at any
628
			 * number between the begining and the end of the result set. For that
629
			 * the ":size" and ":start" placeholders are replaced by the
630
			 * corresponding values from the criteria object. The default values
631
			 * are 0 for the start and 100 for the size value.
632
			 *
633
			 * The SQL statement should conform to the ANSI standard to be
634
			 * compatible with most relational database systems. This also
635
			 * includes using double quotes for table and column names.
636
			 *
637
			 * @param string SQL statement for searching items
638
			 * @since 2014.03
639
			 * @category Developer
640
			 * @see mshop/media/manager/insert/ansi
641
			 * @see mshop/media/manager/update/ansi
642
			 * @see mshop/media/manager/newid/ansi
643
			 * @see mshop/media/manager/delete/ansi
644
			 * @see mshop/media/manager/count/ansi
645
			 */
646
			$cfgPathSearch = 'mshop/media/manager/search';
647
648
			/** mshop/media/manager/count/mysql
649
			 * Counts the number of records matched by the given criteria in the database
650
			 *
651
			 * @see mshop/media/manager/count/ansi
652
			 */
653
654
			/** mshop/media/manager/count/ansi
655
			 * Counts the number of records matched by the given criteria in the database
656
			 *
657
			 * Counts all records matched by the given criteria from the media
658
			 * database. The records must be from one of the sites that are
659
			 * configured via the context item. If the current site is part of
660
			 * a tree of sites, the statement can count all records from the
661
			 * current site and the complete sub-tree of sites.
662
			 *
663
			 * As the records can normally be limited by criteria from sub-managers,
664
			 * their tables must be joined in the SQL context. This is done by
665
			 * using the "internaldeps" property from the definition of the ID
666
			 * column of the sub-managers. These internal dependencies specify
667
			 * the JOIN between the tables and the used columns for joining. The
668
			 * ":joins" placeholder is then replaced by the JOIN strings from
669
			 * the sub-managers.
670
			 *
671
			 * To limit the records matched, conditions can be added to the given
672
			 * criteria object. It can contain comparisons like column names that
673
			 * must match specific values which can be combined by AND, OR or NOT
674
			 * operators. The resulting string of SQL conditions replaces the
675
			 * ":cond" placeholder before the statement is sent to the database
676
			 * server.
677
			 *
678
			 * Both, the strings for ":joins" and for ":cond" are the same as for
679
			 * the "search" SQL statement.
680
			 *
681
			 * Contrary to the "search" statement, it doesn't return any records
682
			 * but instead the number of records that have been found. As counting
683
			 * thousands of records can be a long running task, the maximum number
684
			 * of counted records is limited for performance reasons.
685
			 *
686
			 * The SQL statement should conform to the ANSI standard to be
687
			 * compatible with most relational database systems. This also
688
			 * includes using double quotes for table and column names.
689
			 *
690
			 * @param string SQL statement for counting items
691
			 * @since 2014.03
692
			 * @category Developer
693
			 * @see mshop/media/manager/insert/ansi
694
			 * @see mshop/media/manager/update/ansi
695
			 * @see mshop/media/manager/newid/ansi
696
			 * @see mshop/media/manager/delete/ansi
697
			 * @see mshop/media/manager/search/ansi
698
			 */
699
			$cfgPathCount = 'mshop/media/manager/count';
700
701
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
702
703
			while( ( $row = $results->fetch() ) !== null )
704
			{
705
				if( ( $row['media.previews'] = json_decode( $config = $row['media.previews'], true ) ) === null )
706
				{
707
					$msg = sprintf( 'Invalid JSON as result of search for ID "%2$s" in "%1$s": %3$s', 'mshop_media.previews', $row['media.id'], $config );
708
					$this->context()->logger()->warning( $msg, 'core/media' );
709
				}
710
				$map[$row['media.id']] = $row;
711
			}
712
713
			$dbm->release( $conn, $dbname );
714
		}
715
		catch( \Exception $e )
716
		{
717
			$dbm->release( $conn, $dbname );
718
			throw $e;
719
		}
720
721
		$propItems = []; $name = 'media/property';
722
		if( isset( $ref[$name] ) || in_array( $name, $ref, true ) )
723
		{
724
			$propTypes = isset( $ref[$name] ) && is_array( $ref[$name] ) ? $ref[$name] : null;
725
			$propItems = $this->getPropertyItems( array_keys( $map ), 'media', $propTypes );
726
		}
727
728
		return $this->buildItems( $map, $ref, 'media', $propItems );
729
	}
730
731
732
	/**
733
	 * Creates a filter object.
734
	 *
735
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
736
	 * @param bool $site TRUE for adding site criteria to limit items by the site of related items
737
	 * @return \Aimeos\MW\Criteria\Iface Returns the filter object
738
	 */
739
	public function filter( ?bool $default = false, bool $site = false ) : \Aimeos\MW\Criteria\Iface
740
	{
741
		if( $default !== false )
742
		{
743
			$object = $this->filterBase( 'media', $default );
744
			$langid = $this->context()->locale()->getLanguageId();
745
746
			if( $langid !== null )
747
			{
748
				$temp = array(
749
					$object->compare( '==', 'media.languageid', $langid ),
750
					$object->compare( '==', 'media.languageid', null ),
751
				);
752
753
				$expr = array(
754
					$object->getConditions(),
755
					$object->or( $temp ),
756
				);
757
758
				$object->setConditions( $object->and( $expr ) );
759
			}
760
761
			return $object;
762
		}
763
764
		return parent::filter();
765
	}
766
767
768
	/**
769
	 * Returns a new manager for media extensions
770
	 *
771
	 * @param string $manager Name of the sub manager type in lower case
772
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
773
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g stock, tags, locations, etc.
774
	 */
775
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
776
	{
777
		return $this->getSubManagerBase( 'media', $manager, $name );
778
	}
779
780
781
	/**
782
	 * Creates a new media item instance.
783
	 *
784
	 * @param array $values Associative list of key/value pairs
785
	 * @param \Aimeos\MShop\Common\Item\Lists\Iface[] $listItems List of list items
786
	 * @param \Aimeos\MShop\Common\Item\Iface[] $refItems List of items referenced
787
	 * @param \Aimeos\MShop\Common\Item\Property\Iface[] $propItems List of property items
788
	 * @return \Aimeos\MShop\Media\Item\Iface New media item
789
	 */
790
	protected function createItemBase( array $values = [], array $listItems = [], array $refItems = [],
791
		array $propItems = [] ) : \Aimeos\MShop\Common\Item\Iface
792
	{
793
		$values['.languageid'] = $this->languageId;
794
795
		return new \Aimeos\MShop\Media\Item\Standard( $values, $listItems, $refItems, $propItems );
796
	}
797
}
798