Passed
Push — master ( 44c1d8...6b9f69 )
by Aimeos
16:18
created

Standard::createItemBase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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-2023
7
 * @package MShop
8
 * @subpackage Locale
9
 */
10
11
12
namespace Aimeos\MShop\Locale\Manager\Site;
13
14
15
/**
16
 * Default implementation for managing sites.
17
 *
18
 * @package MShop
19
 * @subpackage Locale
20
 */
21
class Standard
22
	extends \Aimeos\MShop\Common\Manager\Base
23
	implements \Aimeos\MShop\Locale\Manager\Site\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
24
{
25
	private array $cache = [];
26
27
	private array $searchConfig = array(
28
		'locale.site.id' => array(
29
			'code' => 'locale.site.id',
30
			'internalcode' => 'mlocsi."id"',
31
			'internaldeps' => ['LEFT JOIN "mshop_locale_site" AS mlocsi ON (mloc."siteid" = mlocsi."siteid")'],
32
			'label' => 'Site ID',
33
			'type' => 'int',
34
			'public' => false,
35
		),
36
		'locale.site.siteid' => array(
37
			'code' => 'locale.site.siteid',
38
			'internalcode' => 'mlocsi."siteid"',
39
			'label' => 'Unique site ID',
40
			'type' => 'string',
41
			'public' => false,
42
		),
43
		'locale.site.label' => array(
44
			'code' => 'locale.site.label',
45
			'internalcode' => 'mlocsi."label"',
46
			'label' => 'Site label',
47
			'type' => 'string',
48
		),
49
		'locale.site.code' => array(
50
			'code' => 'locale.site.code',
51
			'internalcode' => 'mlocsi."code"',
52
			'label' => 'Site code',
53
			'type' => 'string',
54
		),
55
		'locale.site.status' => array(
56
			'code' => 'locale.site.status',
57
			'internalcode' => 'mlocsi."status"',
58
			'label' => 'Site status',
59
			'type' => 'int',
60
		),
61
		'locale.site.position' => array(
62
			'code' => 'locale.site.position',
63
			'internalcode' => 'mlocsi."id"',
64
			'label' => 'Site position',
65
			'type' => 'int',
66
		),
67
		'locale.site.level' => array(
68
			'code' => 'locale.site.level',
69
			'internalcode' => 'mlocsi."level"',
70
			'label' => 'Site tree level',
71
			'type' => 'int',
72
			'public' => false,
73
		),
74
		'locale.site.config' => array(
75
			'code' => 'locale.site.config',
76
			'internalcode' => 'mlocsi."config"',
77
			'label' => 'Site config',
78
			'type' => 'json',
79
			'public' => false,
80
		),
81
		'locale.site.icon' => array(
82
			'code' => 'locale.site.icon',
83
			'internalcode' => 'mlocsi."icon"',
84
			'label' => 'Site icon',
85
			'type' => 'string',
86
			'public' => false,
87
		),
88
		'locale.site.logo' => array(
89
			'code' => 'locale.site.logo',
90
			'internalcode' => 'mlocsi."logo"',
91
			'label' => 'Site logo',
92
			'type' => 'string',
93
			'public' => false,
94
		),
95
		'locale.site.rating' => array(
96
			'code' => 'locale.site.rating',
97
			'internalcode' => 'mlocsi."rating"',
98
			'label' => 'Rating value',
99
			'type' => 'decimal',
100
			'public' => false,
101
		),
102
		'locale.site.ratings' => array(
103
			'code' => 'locale.site.ratings',
104
			'internalcode' => 'mlocsi."ratings"',
105
			'label' => 'Number of ratings',
106
			'type' => 'int',
107
			'public' => false,
108
		),
109
		'locale.site.refid' => array(
110
			'code' => 'locale.site.refid',
111
			'internalcode' => 'mlocsi."refid"',
112
			'label' => 'Site-related supplier ID',
113
			'type' => 'string',
114
			'public' => false,
115
		),
116
		'locale.site.theme' => array(
117
			'code' => 'locale.site.theme',
118
			'internalcode' => 'mlocsi."theme"',
119
			'label' => 'Site theme',
120
			'type' => 'string',
121
			'public' => false,
122
		),
123
		'locale.site.ctime' => array(
124
			'code' => 'locale.site.ctime',
125
			'internalcode' => 'mlocsi."ctime"',
126
			'label' => 'Site create date/time',
127
			'type' => 'datetime',
128
			'public' => false,
129
		),
130
		'locale.site.mtime' => array(
131
			'code' => 'locale.site.mtime',
132
			'internalcode' => 'mlocsi."mtime"',
133
			'label' => 'Site modify date/time',
134
			'type' => 'datetime',
135
			'public' => false,
136
		),
137
		'locale.site.editor' => array(
138
			'code' => 'locale.site.editor',
139
			'internalcode' => 'mlocsi."editor"',
140
			'label' => 'Site editor',
141
			'type' => 'string',
142
			'public' => false,
143
		),
144
		'parentid' => array(
145
			'code' => 'locale.site.parentid',
146
			'internalcode' => 'mlocsi."parentid"',
147
			'label' => 'Parent site ID',
148
			'type' => 'int',
149
			'public' => false,
150
		),
151
	);
152
153
154
	/**
155
	 * Initializes the object.
156
	 *
157
	 * @param \Aimeos\MShop\ContextIface $context Context object
158
	 */
159
	public function __construct( \Aimeos\MShop\ContextIface $context )
160
	{
161
		parent::__construct( $context );
162
163
		/** mshop/locale/manager/resource
164
		 * Name of the database connection resource to use
165
		 *
166
		 * You can configure a different database connection for each data domain
167
		 * and if no such connection name exists, the "db" connection will be used.
168
		 * It's also possible to use the same database connection for different
169
		 * data domains by configuring the same connection name using this setting.
170
		 *
171
		 * @param string Database connection name
172
		 * @since 2023.04
173
		 */
174
		$this->setResourceName( $context->config()->get( 'mshop/locale/manager/resource', 'db-locale' ) );
175
	}
176
177
178
	/**
179
	 * Removes old entries from the storage.
180
	 *
181
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
182
	 * @return \Aimeos\MShop\Locale\Manager\Site\Iface Manager object for chaining method calls
183
	 */
184
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
185
	{
186
		if( empty( $siteids ) ) {
187
			return $this;
188
		}
189
190
		$context = $this->context();
191
		$config = $context->config();
192
193
		/** mshop/locale/manager/site/cleanup/shop/domains
194
		 * List of madmin domains names whose items referring to the same site should be deleted as well
195
		 *
196
		 * As items for each domain can be stored in a separate database, the
197
		 * site manager needs a list of domain names used to connect to the
198
		 * correct database and to remove all items that belong the the deleted
199
		 * site.
200
		 *
201
		 * For each domain the cleanup will be done by the corresponding MShop
202
		 * manager. To keep records for old sites in the database even if the
203
		 * site was already deleted, you can configure a new list with the
204
		 * domains removed you would like to keep, e.g. the "order" domain to
205
		 * keep all orders ever placed.
206
		 *
207
		 * @param array List of domain names in lower case
208
		 * @since 2014.03
209
		 * @category Developer
210
		 * @see mshop/locale/manager/site/cleanup/admin/domains
211
		 */
212
		$path = 'mshop/locale/manager/site/cleanup/shop/domains';
213
214
		foreach( $config->get( $path, [] ) as $domain ) {
215
			\Aimeos\MShop::create( $context, $domain )->clear( $siteids );
216
		}
217
218
		/** mshop/locale/manager/site/cleanup/admin/domains
219
		 * List of mshop domains names whose items referring to the same site should be deleted as well
220
		 *
221
		 * As items for each domain can be stored in a separate database, the
222
		 * site manager needs a list of domain names used to connect to the
223
		 * correct database and to remove all items that belong the the deleted
224
		 * site.
225
		 *
226
		 * For each domain the cleanup will be done by the corresponding MAdmin
227
		 * manager. To keep records for old sites in the database even if the
228
		 * site was already deleted, you can configure a new list with the
229
		 * domains removed you would like to keep, e.g. the "log" domain to
230
		 * keep all log entries ever written.
231
		 *
232
		 * @param array List of domain names in lower case
233
		 * @since 2014.03
234
		 * @category Developer
235
		 * @see mshop/locale/manager/site/cleanup/shop/domains
236
		 */
237
		$path = 'mshop/locale/manager/site/cleanup/admin/domains';
238
239
		foreach( $config->get( $path, [] ) as $domain ) {
240
			\Aimeos\MAdmin::create( $context, $domain )->clear( $siteids );
241
		}
242
243
		return $this;
244
	}
245
246
247
	/**
248
	 * Creates a new empty item instance
249
	 *
250
	 * @param array $values Values the item should be initialized with
251
	 * @return \Aimeos\MShop\Locale\Item\Site\Iface New locale site item object
252
	 */
253
	public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
254
	{
255
		return $this->createItemBase( $values );
256
	}
257
258
259
	/**
260
	 * Adds a new site to the storage or updates an existing one.
261
	 *
262
	 * @param \Aimeos\MShop\Locale\Item\Site\Iface $item New site item for saving to the storage
263
	 * @param bool $fetch True if the new ID should be returned in the item
264
	 * @return \Aimeos\MShop\Locale\Item\Site\Iface $item Updated item including the generated ID
265
	 */
266
	protected function saveItem( \Aimeos\MShop\Locale\Item\Site\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Locale\Item\Site\Iface
267
	{
268
		if( $item->getId() === null )
269
		{
270
			$msg = $this->context()->translate( 'mshop', 'Newly created item can not be saved using method "save()", use "insert()" instead' );
271
			throw new \Aimeos\MShop\Locale\Exception( $msg );
272
		}
273
274
		if( !$item->isModified() ) {
275
			return $item;
276
		}
277
278
		$context = $this->context();
279
		$conn = $context->db( $this->getResourceName() );
280
281
		$id = $item->getId();
282
		$columns = $this->object()->getSaveAttributes();
283
284
		/** mshop/locale/manager/site/update/mysql
285
		 * Updates an existing site record in the database
286
		 *
287
		 * @see mshop/locale/manager/site/update/ansi
288
		 */
289
290
		/** mshop/locale/manager/site/update/ansi
291
		 * Updates an existing site record in the database
292
		 *
293
		 * The SQL statement must be a string suitable for being used as
294
		 * prepared statement. It must include question marks for binding
295
		 * the values from the site item to the statement before they are
296
		 * sent to the database server. The order of the columns must
297
		 * correspond to the order in the save() method, so the
298
		 * correct values are bound to the columns.
299
		 *
300
		 * The SQL statement should conform to the ANSI standard to be
301
		 * compatible with most relational database systems. This also
302
		 * includes using double quotes for table and column names.
303
		 *
304
		 * @param string SQL statement for updating records
305
		 * @since 2014.03
306
		 * @category Developer
307
		 * @see mshop/locale/manager/site/insert/ansi
308
		 * @see mshop/locale/manager/site/delete/ansi
309
		 * @see mshop/locale/manager/site/search/ansi
310
		 * @see mshop/locale/manager/site/count/ansi
311
		 * @see mshop/locale/manager/site/newid/ansi
312
		 */
313
		$path = 'mshop/locale/manager/site/update';
314
		$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
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

314
		$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ), false );
Loading history...
315
316
		$idx = 1;
317
		$stmt = $this->getCachedStatement( $conn, $path, $sql );
318
319
		foreach( $columns as $name => $entry ) {
320
			$stmt->bind( $idx++, $item->get( $name ), \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
321
		}
322
323
		$stmt->bind( $idx++, $item->getSiteId() );
324
		$stmt->bind( $idx++, $item->getCode() );
325
		$stmt->bind( $idx++, $item->getLabel() );
326
		$stmt->bind( $idx++, json_encode( $item->getConfig(), JSON_FORCE_OBJECT ) );
327
		$stmt->bind( $idx++, $item->getStatus(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
328
		$stmt->bind( $idx++, $item->getIcon() );
329
		$stmt->bind( $idx++, json_encode( $item->getLogos(), JSON_FORCE_OBJECT ) );
330
		$stmt->bind( $idx++, $item->getRefId() );
331
		$stmt->bind( $idx++, $item->getTheme() );
332
		$stmt->bind( $idx++, $context->editor() );
333
		$stmt->bind( $idx++, date( 'Y-m-d H:i:s' ) ); // mtime
334
		$stmt->bind( $idx++, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
335
336
		$stmt->execute()->finish();
337
		$item->setId( $id ); // set Modified false
338
339
		return $item;
340
	}
341
342
343
	/**
344
	 * Removes multiple items.
345
	 *
346
	 * @param \Aimeos\MShop\Common\Item\Iface|array|string $items List of item objects or IDs of the items
347
	 * @return \Aimeos\MShop\Locale\Manager\Site\Iface Manager object for chaining method calls
348
	 */
349
	public function delete( $items ) : \Aimeos\MShop\Common\Manager\Iface
350
	{
351
		if( is_map( $items ) ) { $items = $items->toArray(); }
352
		if( !is_array( $items ) ) { $items = [$items]; }
353
		if( empty( $items ) ) { return $this; }
354
355
356
		$filter = $this->object()->filter()
357
			->add( ['locale.site.id' => $items] )
358
			->slice( 0, count( $items ) );
359
360
		$siteIds = $this->object()->search( $filter )->getSiteId()->toArray();
361
		$this->object()->clear( $siteIds );
362
363
364
		/** mshop/locale/manager/site/delete/mysql
365
		 * Deletes the items matched by the given IDs from the database
366
		 *
367
		 * @see mshop/locale/manager/site/delete/ansi
368
		 */
369
370
		/** mshop/locale/manager/site/delete/ansi
371
		 * Deletes the items matched by the given IDs from the database
372
		 *
373
		 * Removes the site records specified by the given IDs from the
374
		 * locale database. The records must be from the site that is configured
375
		 * via the context item.
376
		 *
377
		 * The ":cond" placeholder is replaced by the name of the ID column and
378
		 * the given ID or list of IDs while the site ID is bound to the question
379
		 * mark.
380
		 *
381
		 * The SQL statement should conform to the ANSI standard to be
382
		 * compatible with most relational database systems. This also
383
		 * includes using double quotes for table and column names.
384
		 *
385
		 * @param string SQL statement for deleting items
386
		 * @since 2014.03
387
		 * @category Developer
388
		 * @see mshop/locale/manager/site/insert/ansi
389
		 * @see mshop/locale/manager/site/update/ansi
390
		 * @see mshop/locale/manager/site/search/ansi
391
		 * @see mshop/locale/manager/site/count/ansi
392
		 * @see mshop/locale/manager/site/newid/ansi
393
		 * @see mshop/locale/manager/site/rate/ansi
394
		 */
395
		$path = 'mshop/locale/manager/site/delete';
396
397
		return $this->deleteItemsBase( $items, $path, false );
398
	}
399
400
401
	/**
402
	 * Returns the item specified by its code and domain/type if necessary
403
	 *
404
	 * @param string $code Code of the item
405
	 * @param string[] $ref List of domains to fetch list items and referenced items for
406
	 * @param string|null $domain Domain of the item if necessary to identify the item uniquely
407
	 * @param string|null $type Type code of the item if necessary to identify the item uniquely
408
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
409
	 * @return \Aimeos\MShop\Common\Item\Iface Item object
410
	 */
411
	public function find( string $code, array $ref = [], string $domain = null, string $type = null,
412
		?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
413
	{
414
		return $this->findBase( ['locale.site.code' => $code], $ref, $default );
415
	}
416
417
418
	/**
419
	 * Returns the site item specified by its ID.
420
	 *
421
	 * @param string $id Unique ID of the site data in the storage
422
	 * @param string[] $ref List of domains to fetch list items and referenced items for
423
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
424
	 * @return \Aimeos\MShop\Locale\Item\Site\Iface Returns the site item of the given id
425
	 * @throws \Aimeos\MShop\Exception If the item couldn't be found
426
	 */
427
	public function get( string $id, array $ref = [], ?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
428
	{
429
		return $this->getItemBase( 'locale.site.id', $id, $ref, $default );
430
	}
431
432
433
	/**
434
	 * Returns the available manager types
435
	 *
436
	 * @param bool $withsub Return also the resource type of sub-managers if true
437
	 * @return string Type of the manager and submanagers, subtypes are separated by slashes
438
	 */
439
	public function getResourceType( bool $withsub = true ) : array
440
	{
441
		$path = 'mshop/locale/manager/site/submanagers';
442
443
		return $this->getResourceTypeBase( 'locale/site', $path, [], $withsub );
444
	}
445
446
447
	/**
448
	 * Returns the attributes that can be used for searching.
449
	 *
450
	 * @param bool $withsub Return also attributes of sub-managers if true
451
	 * @return \Aimeos\Base\Criteria\Attribute\Iface[] List of search attribute items
452
	 */
453
	public function getSearchAttributes( bool $withsub = true ) : array
454
	{
455
		/** mshop/locale/manager/site/submanagers
456
		 * List of manager names that can be instantiated by the locale site manager
457
		 *
458
		 * Managers provide a generic interface to the underlying storage.
459
		 * Each manager has or can have sub-managers caring about particular
460
		 * aspects. Each of these sub-managers can be instantiated by its
461
		 * parent manager using the getSubManager() method.
462
		 *
463
		 * The search keys from sub-managers can be normally used in the
464
		 * manager as well. It allows you to search for items of the manager
465
		 * using the search keys of the sub-managers to further limit the
466
		 * retrieved list of items.
467
		 *
468
		 * @param array List of sub-manager names
469
		 * @since 2014.03
470
		 * @category Developer
471
		 */
472
		$path = 'mshop/locale/manager/site/submanagers';
473
474
		return $this->getSearchAttributesBase( $this->searchConfig, $path, [], $withsub );
475
	}
476
477
478
	/**
479
	 * Returns a new sub manager of the given type and name.
480
	 *
481
	 * @param string $manager Name of the sub manager type in lower case
482
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
483
	 * @return \Aimeos\MShop\Common\Manager\Iface Sub manager
484
	 */
485
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
486
	{
487
		/** mshop/locale/manager/site/name
488
		 * Class name of the used locale site manager implementation
489
		 *
490
		 * Each default locale site manager can be replaced by an alternative imlementation.
491
		 * To use this implementation, you have to set the last part of the class
492
		 * name as configuration value so the manager factory knows which class it
493
		 * has to instantiate.
494
		 *
495
		 * For example, if the name of the default class is
496
		 *
497
		 *  \Aimeos\MShop\Locale\Manager\Site\Standard
498
		 *
499
		 * and you want to replace it with your own version named
500
		 *
501
		 *  \Aimeos\MShop\Locale\Manager\Site\Mysite
502
		 *
503
		 * then you have to set the this configuration option:
504
		 *
505
		 *  mshop/locale/manager/site/name = Mysite
506
		 *
507
		 * The value is the last part of your own class name and it's case sensitive,
508
		 * so take care that the configuration value is exactly named like the last
509
		 * part of the class name.
510
		 *
511
		 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
512
		 * characters are possible! You should always start the last part of the class
513
		 * name with an upper case character and continue only with lower case characters
514
		 * or numbers. Avoid chamel case names like "MySite"!
515
		 *
516
		 * @param string Last part of the class name
517
		 * @since 2014.03
518
		 * @category Developer
519
		 */
520
521
		/** mshop/locale/manager/site/decorators/excludes
522
		 * Excludes decorators added by the "common" option from the locale site manager
523
		 *
524
		 * Decorators extend the functionality of a class by adding new aspects
525
		 * (e.g. log what is currently done), executing the methods of the underlying
526
		 * class only in certain conditions (e.g. only for logged in users) or
527
		 * modify what is returned to the caller.
528
		 *
529
		 * This option allows you to remove a decorator added via
530
		 * "mshop/common/manager/decorators/default" before they are wrapped
531
		 * around the locale site manager.
532
		 *
533
		 *  mshop/locale/manager/site/decorators/excludes = array( 'decorator1' )
534
		 *
535
		 * This would remove the decorator named "decorator1" from the list of
536
		 * common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
537
		 * "mshop/common/manager/decorators/default" for the locale site manager.
538
		 *
539
		 * @param array List of decorator names
540
		 * @since 2014.03
541
		 * @category Developer
542
		 * @see mshop/common/manager/decorators/default
543
		 * @see mshop/locale/manager/site/decorators/global
544
		 * @see mshop/locale/manager/site/decorators/local
545
		 */
546
547
		/** mshop/locale/manager/site/decorators/global
548
		 * Adds a list of globally available decorators only to the locale site manager
549
		 *
550
		 * Decorators extend the functionality of a class by adding new aspects
551
		 * (e.g. log what is currently done), executing the methods of the underlying
552
		 * class only in certain conditions (e.g. only for logged in users) or
553
		 * modify what is returned to the caller.
554
		 *
555
		 * This option allows you to wrap global decorators
556
		 * ("\Aimeos\MShop\Common\Manager\Decorator\*") around the locale site
557
		 * manager.
558
		 *
559
		 *  mshop/locale/manager/site/decorators/global = array( 'decorator1' )
560
		 *
561
		 * This would add the decorator named "decorator1" defined by
562
		 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the locale
563
		 * site manager.
564
		 *
565
		 * @param array List of decorator names
566
		 * @since 2014.03
567
		 * @category Developer
568
		 * @see mshop/common/manager/decorators/default
569
		 * @see mshop/locale/manager/site/decorators/excludes
570
		 * @see mshop/locale/manager/site/decorators/local
571
		 */
572
573
		/** mshop/locale/manager/site/decorators/local
574
		 * Adds a list of local decorators only to the locale site manager
575
		 *
576
		 * Decorators extend the functionality of a class by adding new aspects
577
		 * (e.g. log what is currently done), executing the methods of the underlying
578
		 * class only in certain conditions (e.g. only for logged in users) or
579
		 * modify what is returned to the caller.
580
		 *
581
		 * This option allows you to wrap local decorators
582
		 * ("\Aimeos\MShop\Locale\Manager\Site\Decorator\*") around the locale site
583
		 * manager.
584
		 *
585
		 *  mshop/locale/manager/site/decorators/local = array( 'decorator2' )
586
		 *
587
		 * This would add the decorator named "decorator2" defined by
588
		 * "\Aimeos\MShop\Locale\Manager\Site\Decorator\Decorator2" only to the
589
		 * locale site manager.
590
		 *
591
		 * @param array List of decorator names
592
		 * @since 2014.03
593
		 * @category Developer
594
		 * @see mshop/common/manager/decorators/default
595
		 * @see mshop/locale/manager/site/decorators/excludes
596
		 * @see mshop/locale/manager/site/decorators/global
597
		 */
598
599
		return $this->getSubManagerBase( 'locale', 'site/' . $manager, $name );
600
	}
601
602
603
	/**
604
	 * Searches for site items matching the given criteria.
605
	 *
606
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria object
607
	 * @param string[] $ref List of domains to fetch list items and referenced items for
608
	 * @param int|null &$total Number of items that are available in total
609
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Locale\Item\Site\Iface with ids as keys
610
	 */
611
	public function search( \Aimeos\Base\Criteria\Iface $search, array $ref = [], int &$total = null ) : \Aimeos\Map
612
	{
613
		$items = [];
614
		$context = $this->context();
615
		$conn = $context->db( $this->getResourceName() );
616
617
		$required = ['locale.site'];
618
619
		/** mshop/locale/manager/site/search/mysql
620
		 * Retrieves the records matched by the given criteria in the database
621
		 *
622
		 * @see mshop/locale/manager/site/search/ansi
623
		 */
624
625
		/** mshop/locale/manager/site/search/ansi
626
		 * Retrieves the records matched by the given criteria in the database
627
		 *
628
		 * Fetches the records matched by the given criteria from the attribute
629
		 * database. The records must be from one of the sites that are
630
		 * configured via the context item. If the current site is part of
631
		 * a tree of sites, the SELECT statement can retrieve all records
632
		 * from the current site and the complete sub-tree of sites.
633
		 *
634
		 * As the records can normally be limited by criteria from sub-managers,
635
		 * their tables must be joined in the SQL context. This is done by
636
		 * using the "internaldeps" property from the definition of the ID
637
		 * column of the sub-managers. These internal dependencies specify
638
		 * the JOIN between the tables and the used columns for joining. The
639
		 * ":joins" placeholder is then replaced by the JOIN strings from
640
		 * the sub-managers.
641
		 *
642
		 * To limit the records matched, conditions can be added to the given
643
		 * criteria object. It can contain comparisons like column names that
644
		 * must match specific values which can be combined by AND, OR or NOT
645
		 * operators. The resulting string of SQL conditions replaces the
646
		 * ":cond" placeholder before the statement is sent to the database
647
		 * server.
648
		 *
649
		 * If the records that are retrieved should be ordered by one or more
650
		 * columns, the generated string of column / sort direction pairs
651
		 * replaces the ":order" placeholder. In case no ordering is required,
652
		 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
653
		 * markers is removed to speed up retrieving the records. Columns of
654
		 * sub-managers can also be used for ordering the result set but then
655
		 * no index can be used.
656
		 *
657
		 * The number of returned records can be limited and can start at any
658
		 * number between the begining and the end of the result set. For that
659
		 * the ":size" and ":start" placeholders are replaced by the
660
		 * corresponding values from the criteria object. The default values
661
		 * are 0 for the start and 100 for the size value.
662
		 *
663
		 * The SQL statement should conform to the ANSI standard to be
664
		 * compatible with most relational database systems. This also
665
		 * includes using double quotes for table and column names.
666
		 *
667
		 * @param string SQL statement for searching items
668
		 * @since 2014.03
669
		 * @category Developer
670
		 * @see mshop/locale/manager/site/insert/ansi
671
		 * @see mshop/locale/manager/site/update/ansi
672
		 * @see mshop/locale/manager/site/delete/ansi
673
		 * @see mshop/locale/manager/site/count/ansi
674
		 * @see mshop/locale/manager/site/newid/ansi
675
		 * @see mshop/locale/manager/site/rate/ansi
676
		 */
677
		$cfgPathSearch = 'mshop/locale/manager/site/search';
678
679
		/** mshop/locale/manager/site/count/mysql
680
		 * Counts the number of records matched by the given criteria in the database
681
		 *
682
		 * @see mshop/locale/manager/site/count/ansi
683
		 */
684
685
		/** mshop/locale/manager/site/count/ansi
686
		 * Counts the number of records matched by the given criteria in the database
687
		 *
688
		 * Counts all records matched by the given criteria from the attribute
689
		 * database. The records must be from one of the sites that are
690
		 * configured via the context item. If the current site is part of
691
		 * a tree of sites, the statement can count all records from the
692
		 * current site and the complete sub-tree of sites.
693
		 *
694
		 * As the records can normally be limited by criteria from sub-managers,
695
		 * their tables must be joined in the SQL context. This is done by
696
		 * using the "internaldeps" property from the definition of the ID
697
		 * column of the sub-managers. These internal dependencies specify
698
		 * the JOIN between the tables and the used columns for joining. The
699
		 * ":joins" placeholder is then replaced by the JOIN strings from
700
		 * the sub-managers.
701
		 *
702
		 * To limit the records matched, conditions can be added to the given
703
		 * criteria object. It can contain comparisons like column names that
704
		 * must match specific values which can be combined by AND, OR or NOT
705
		 * operators. The resulting string of SQL conditions replaces the
706
		 * ":cond" placeholder before the statement is sent to the database
707
		 * server.
708
		 *
709
		 * Both, the strings for ":joins" and for ":cond" are the same as for
710
		 * the "search" SQL statement.
711
		 *
712
		 * Contrary to the "search" statement, it doesn't return any records
713
		 * but instead the number of records that have been found. As counting
714
		 * thousands of records can be a long running task, the maximum number
715
		 * of counted records is limited for performance reasons.
716
		 *
717
		 * The SQL statement should conform to the ANSI standard to be
718
		 * compatible with most relational database systems. This also
719
		 * includes using double quotes for table and column names.
720
		 *
721
		 * @param string SQL statement for counting items
722
		 * @since 2014.03
723
		 * @category Developer
724
		 * @see mshop/locale/manager/site/insert/ansi
725
		 * @see mshop/locale/manager/site/update/ansi
726
		 * @see mshop/locale/manager/site/delete/ansi
727
		 * @see mshop/locale/manager/site/search/ansi
728
		 * @see mshop/locale/manager/site/newid/ansi
729
		 */
730
		$cfgPathCount = 'mshop/locale/manager/site/count';
731
732
		$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total );
733
734
		while( $row = $results->fetch() )
735
		{
736
			if( ( $row['locale.site.logo'] = json_decode( $row['locale.site.logo'], true ) ) === null ) {
737
				$row['locale.site.logo'] = [];
738
			}
739
740
			if( ( $row['locale.site.config'] = json_decode( $row['locale.site.config'], true ) ) === null ) {
741
				$row['locale.site.config'] = [];
742
			}
743
744
			if( $item = $this->applyFilter( $this->createItemBase( $row ) ) ) {
745
				$items[$row['locale.site.id']] = $item;
746
			}
747
		}
748
749
		return map( $items );
750
	}
751
752
753
	/**
754
	 * Creates a filter object.
755
	 *
756
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
757
	 * @param bool $site TRUE for adding site criteria to limit items by the site of related items
758
	 * @return \Aimeos\Base\Criteria\Iface Returns the filter object
759
	 */
760
	public function filter( ?bool $default = false, bool $site = false ) : \Aimeos\Base\Criteria\Iface
761
	{
762
		$search = $this->filterBase( 'locale.site', $default );
763
764
		$expr = array(
765
			$search->compare( '==', 'locale.site.level', 0 ),
766
			$search->getConditions(),
767
		);
768
769
		$search->setConditions( $search->and( $expr ) );
770
771
		return $search;
772
	}
773
774
775
	/**
776
	 * Returns a list of item IDs, that are in the path of given item ID.
777
	 *
778
	 * @param string $id ID of item to get the path for
779
	 * @param string[] $ref List of domains to fetch list items and referenced items for
780
	 * @return \Aimeos\Map List of IDs as keys and items implementing \Aimeos\MShop\Locale\Item\Site\Iface
781
	 */
782
	public function getPath( string $id, array $ref = [] ) : \Aimeos\Map
783
	{
784
		$item = $this->getTree( $id, $ref, \Aimeos\MW\Tree\Manager\Base::LEVEL_ONE );
785
		return map( [$item->getId() => $item] );
786
	}
787
788
789
	/**
790
	 * Returns a node and its descendants depending on the given resource.
791
	 *
792
	 * @param string|null $id Retrieve nodes starting from the given ID
793
	 * @param string[] $ref List of domains (e.g. text, media, etc.) whose referenced items should be attached to the objects
794
	 * @param int $level One of the level constants from \Aimeos\MW\Tree\Manager\Base
795
	 * @param \Aimeos\Base\Criteria\Iface|null $criteria Optional criteria object with conditions
796
	 * @return \Aimeos\MShop\Locale\Item\Site\Iface Site node, maybe with subnodes
797
	 */
798
	public function getTree( string $id = null, array $ref = [], int $level = \Aimeos\MW\Tree\Manager\Base::LEVEL_TREE,
799
		\Aimeos\Base\Criteria\Iface $criteria = null ) : \Aimeos\MShop\Locale\Item\Site\Iface
800
	{
801
		if( $id !== null )
802
		{
803
			if( count( $ref ) > 0 ) {
804
				return $this->object()->get( $id, $ref );
805
			}
806
807
			if( !isset( $this->cache[$id] ) ) {
808
				$this->cache[$id] = $this->object()->get( $id, $ref );
809
			}
810
811
			return $this->cache[$id];
812
		}
813
814
		$criteria = $criteria ? clone $criteria : $this->object()->filter();
815
		$criteria->add( ['locale.site.code' => 'default'] )->slice( 0, 1 );
816
817
		if( ( $item = $this->object()->search( $criteria, $ref )->first() ) === null )
818
		{
819
			$msg = $this->context()->translate( 'mshop', 'Tree root with code "%1$s" in "%2$s" not found' );
820
			throw new \Aimeos\MShop\Locale\Exception( sprintf( $msg, 'default', 'locale.site.code' ) );
821
		}
822
823
		$this->cache[$item->getId()] = $item;
824
825
		return $item;
826
	}
827
828
829
	/**
830
	 * Adds a new item object.
831
	 *
832
	 * @param \Aimeos\MShop\Locale\Item\Site\Iface $item Item which should be inserted
833
	 * @param string|null $parentId ID of the parent item where the item should be inserted into
834
	 * @param string|null $refId ID of the item where the item should be inserted before (null to append)
835
	 * @return \Aimeos\MShop\Locale\Item\Site\Iface $item Updated item including the generated ID
836
	 */
837
	public function insert( \Aimeos\MShop\Locale\Item\Site\Iface $item, string $parentId = null, string $refId = null ) : \Aimeos\MShop\Locale\Item\Site\Iface
838
	{
839
		$context = $this->context();
840
		$conn = $context->db( $this->getResourceName() );
841
842
			$date = date( 'Y-m-d H:i:s' );
843
			$columns = $this->object()->getSaveAttributes();
844
845
			/** mshop/locale/manager/site/insert/mysql
846
			 * Inserts a new currency record into the database table
847
			 *
848
			 * @see mshop/locale/manager/site/insert/ansi
849
			 */
850
851
			/** mshop/locale/manager/site/insert/ansi
852
			 * Inserts a new currency record into the database table
853
			 *
854
			 * The SQL statement must be a string suitable for being used as
855
			 * prepared statement. It must include question marks for binding
856
			 * the values from the site item to the statement before they are
857
			 * sent to the database server. The number of question marks must
858
			 * be the same as the number of columns listed in the INSERT
859
			 * statement. The order of the columns must correspond to the
860
			 * order in the save() method, so the correct values are
861
			 * bound to the columns.
862
			 *
863
			 * The SQL statement should conform to the ANSI standard to be
864
			 * compatible with most relational database systems. This also
865
			 * includes using double quotes for table and column names.
866
			 *
867
			 * @param string SQL statement for inserting records
868
			 * @since 2014.03
869
			 * @category Developer
870
			 * @see mshop/locale/manager/site/update/ansi
871
			 * @see mshop/locale/manager/site/delete/ansi
872
			 * @see mshop/locale/manager/site/search/ansi
873
			 * @see mshop/locale/manager/site/count/ansi
874
			 * @see mshop/locale/manager/site/newid/ansi
875
			 * @see mshop/locale/manager/site/rate/ansi
876
			 */
877
			$path = 'mshop/locale/manager/site/insert';
878
			$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

878
			$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
879
880
			$idx = 1;
881
			$stmt = $this->getCachedStatement( $conn, $path, $sql );
882
883
			foreach( $columns as $name => $entry ) {
884
				$stmt->bind( $idx++, $item->get( $name ), \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
885
			}
886
887
			$stmt->bind( $idx++, '' ); // site ID
888
			$stmt->bind( $idx++, $item->getCode() );
889
			$stmt->bind( $idx++, $item->getLabel() );
890
			$stmt->bind( $idx++, json_encode( $item->getConfig(), JSON_FORCE_OBJECT ) );
891
			$stmt->bind( $idx++, $item->getStatus(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
892
			$stmt->bind( $idx++, $item->getIcon() );
893
			$stmt->bind( $idx++, json_encode( $item->getLogos(), JSON_FORCE_OBJECT ) );
894
			$stmt->bind( $idx++, $item->getRefId() );
895
			$stmt->bind( $idx++, $item->getTheme() );
896
			$stmt->bind( $idx++, $context->editor() );
897
			$stmt->bind( $idx++, $date ); // mtime
898
			$stmt->bind( $idx++, $date ); // ctime
899
900
			$stmt->execute()->finish();
901
902
			/** mshop/locale/manager/site/newid/mysql
903
			 * Retrieves the ID generated by the database when inserting a new record
904
			 *
905
			 * @see mshop/locale/manager/site/newid/ansi
906
			 */
907
908
			/** mshop/locale/manager/site/newid/ansi
909
			 * Retrieves the ID generated by the database when inserting a new record
910
			 *
911
			 * As soon as a new record is inserted into the database table,
912
			 * the database server generates a new and unique identifier for
913
			 * that record. This ID can be used for retrieving, updating and
914
			 * deleting that specific record from the table again.
915
			 *
916
			 * For MySQL:
917
			 *  SELECT LAST_INSERT_ID()
918
			 * For PostgreSQL:
919
			 *  SELECT currval('seq_matt_id')
920
			 * For SQL Server:
921
			 *  SELECT SCOPE_IDENTITY()
922
			 * For Oracle:
923
			 *  SELECT "seq_matt_id".CURRVAL FROM DUAL
924
			 *
925
			 * There's no way to retrive the new ID by a SQL statements that
926
			 * fits for most database servers as they implement their own
927
			 * specific way.
928
			 *
929
			 * @param string SQL statement for retrieving the last inserted record ID
930
			 * @since 2014.03
931
			 * @category Developer
932
			 * @see mshop/locale/manager/site/insert/ansi
933
			 * @see mshop/locale/manager/site/update/ansi
934
			 * @see mshop/locale/manager/site/delete/ansi
935
			 * @see mshop/locale/manager/site/search/ansi
936
			 * @see mshop/locale/manager/site/count/ansi
937
			 * @see mshop/locale/manager/site/rate/ansi
938
			 */
939
			$path = 'mshop/locale/manager/newid';
940
			$item->setId( $this->newId( $conn, $path ) );
941
942
			// Add unique site identifier
943
			$item = $this->object()->save( $item->setSiteId( $item->getId() . '.' ) );
944
945
		return $item;
946
	}
947
948
949
	/**
950
	 * Moves an existing item to the new parent in the storage.
951
	 *
952
	 * @param string $id ID of the item that should be moved
953
	 * @param string|null $oldParentId ID of the old parent item which currently contains the item that should be removed
954
	 * @param string|null $newParentId ID of the new parent item where the item should be moved to
955
	 * @param string|null $refId ID of the item where the item should be inserted before (null to append)
956
	 * @return \Aimeos\MShop\Locale\Manager\Site\Iface Manager object for chaining method calls
957
	 */
958
	public function move( string $id, string $oldParentId = null, string $newParentId = null,
959
		string $refId = null ) : \Aimeos\MShop\Locale\Manager\Site\Iface
960
	{
961
		$msg = $this->context()->translate( 'mshop', 'Method "%1$s" for locale site manager not available' );
962
		throw new \Aimeos\MShop\Locale\Exception( sprintf( $msg, 'move()' ) );
963
	}
964
965
966
	/**
967
	 * Updates the rating of the item
968
	 *
969
	 * @param string $id ID of the item
970
	 * @param string $rating Decimal value of the rating
971
	 * @param int $ratings Total number of ratings for the item
972
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
973
	 */
974
	public function rate( string $id, string $rating, int $ratings ) : \Aimeos\MShop\Common\Manager\Iface
975
	{
976
		$context = $this->context();
977
		$conn = $context->db( $this->getResourceName() );
978
979
			/** mshop/locale/manager/site/rate/mysql
980
			 * Updates the rating of the product in the database
981
			 *
982
			 * @see mshop/locale/manager/site/rate/ansi
983
			 */
984
985
			/** mshop/locale/manager/site/rate/ansi
986
			 * Updates the rating of the product in the database
987
			 *
988
			 * The SQL statement must be a string suitable for being used as
989
			 * prepared statement. It must include question marks for binding
990
			 * the values for the rating to the statement before they are
991
			 * sent to the database server. The order of the columns must
992
			 * correspond to the order in the rate() method, so the
993
			 * correct values are bound to the columns.
994
			 *
995
			 * The SQL statement should conform to the ANSI standard to be
996
			 * compatible with most relational database systems. This also
997
			 * includes using double quotes for table and column names.
998
			 *
999
			 * @param string SQL statement for update ratings
1000
			 * @since 2022.10
1001
			 * @category Developer
1002
			 * @see mshop/locale/manager/site/update/ansi
1003
			 * @see mshop/locale/manager/site/delete/ansi
1004
			 * @see mshop/locale/manager/site/search/ansi
1005
			 * @see mshop/locale/manager/site/count/ansi
1006
			 * @see mshop/locale/manager/site/newid/ansi
1007
			 */
1008
			$path = 'mshop/locale/manager/site/rate';
1009
1010
			$stmt = $this->getCachedStatement( $conn, $path, $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\Mana...e::getCachedStatement() does only seem to accept null|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

1010
			$stmt = $this->getCachedStatement( $conn, $path, /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
1011
1012
			$stmt->bind( 1, $rating );
1013
			$stmt->bind( 2, $ratings, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
1014
			$stmt->bind( 3, (int) $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
1015
1016
			$stmt->execute()->finish();
1017
1018
		return $this;
1019
	}
1020
1021
1022
	/**
1023
	 * Registers a new item filter for the given name
1024
	 *
1025
	 * Not used for site items but required for trees
1026
	 *
1027
	 * @param string $name Filter name
1028
	 * @param \Closure $fcn Callback function
1029
	 */
1030
	public function registerItemFilter( string $name, \Closure $fcn ) : \Aimeos\MShop\Locale\Manager\Site\Iface
1031
	{
1032
		return $this;
1033
	}
1034
1035
1036
	/**
1037
	 * Create new item object initialized with given parameters.
1038
	 *
1039
	 * @param array $values Associative list of item key/value pairs
1040
	 * @return \Aimeos\MShop\Locale\Item\Site\Iface Site item object
1041
	 */
1042
	protected function createItemBase( array $values = [] ) : \Aimeos\MShop\Locale\Item\Site\Iface
1043
	{
1044
		return new \Aimeos\MShop\Locale\Item\Site\Standard( $values );
1045
	}
1046
1047
1048
	/**
1049
	 * Returns the raw search config array.
1050
	 *
1051
	 * @return array List of search config arrays
1052
	 */
1053
	protected function getSearchConfig() : array
1054
	{
1055
		return $this->searchConfig;
1056
	}
1057
1058
1059
	/**
1060
	 * Returns the site coditions for the search request
1061
	 *
1062
	 * @param string[] $keys Sorted list of criteria keys
1063
	 * @param \Aimeos\Base\Criteria\Attribute\Iface[] $attributes Associative list of search keys and criteria attribute items as values
1064
	 * @param int $sitelevel Site level constant from \Aimeos\MShop\Locale\Manager\Base
1065
	 * @return \Aimeos\Base\Criteria\Expression\Iface[] List of search conditions
1066
	 */
1067
	protected function getSiteConditions( array $keys, array $attributes, int $sitelevel ) : array
1068
	{
1069
		return [];
1070
	}
1071
}
1072