Passed
Push — master ( e4a92d...0988af )
by Aimeos
04:33
created

Standard::saveItem()   B

Complexity

Conditions 7
Paths 17

Size

Total Lines 70
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 53
dl 0
loc 70
rs 8.0921
c 0
b 0
f 0
cc 7
nc 17
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2024
6
 * @package MShop
7
 * @subpackage Customer
8
 */
9
10
11
namespace Aimeos\MShop\Customer\Manager\Address;
12
13
14
/**
15
 * Implementation for customer address manager.
16
 *
17
 * @package MShop
18
 * @subpackage Customer
19
 */
20
class Standard
21
	extends \Aimeos\MShop\Common\Manager\Address\Base
22
	implements \Aimeos\MShop\Customer\Manager\Address\Iface
23
{
24
	/**
25
	 * Removes old entries from the storage.
26
	 *
27
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
28
	 * @return \Aimeos\MShop\Customer\Manager\Address\Iface Manager object for chaining method calls
29
	 */
30
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
31
	{
32
		$path = 'mshop/customer/manager/address/submanagers';
33
		foreach( $this->context()->config()->get( $path, [] ) as $domain ) {
34
			$this->object()->getSubManager( $domain )->clear( $siteids );
35
		}
36
37
		return $this->clearBase( $siteids, 'mshop/customer/manager/address/clear' );
38
	}
39
40
41
	/**
42
	 * Creates a new empty item instance
43
	 *
44
	 * @param array $values Values the item should be initialized with
45
	 * @return \Aimeos\MShop\Order\Item\Address\Iface New order address item object
46
	 */
47
	public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
48
	{
49
		$values['customer.address.siteid'] = $values['customer.address.siteid'] ?? $this->context()->locale()->getSiteId();
50
		return new \Aimeos\MShop\Customer\Item\Address\Standard( 'customer.address.', $values );
51
	}
52
53
54
	/**
55
	 * Returns the attributes that can be used for searching.
56
	 *
57
	 * @param bool $withsub Return also attributes of sub-managers if true
58
	 * @return \Aimeos\Base\Criteria\Attribute\Iface[] List of search attribute items
59
	 */
60
	public function getSearchAttributes( bool $withsub = true ) : array
61
	{
62
		return array_replace( parent::getSearchAttributes( $withsub ), $this->createAttributes( [
63
			'customer.address.id' => [
64
				'label' => 'Customer address ID',
65
				'internalcode' => 'id',
66
				'internaldeps' => ['LEFT JOIN "mshop_customer_address" AS mcusad ON ( mcus."id" = mcusad."parentid" )'],
67
				'type' => 'int',
68
				'public' => false,
69
			]
70
		] ) );
71
	}
72
73
74
	/**
75
	 * Deletes items.
76
	 *
77
	 * @param \Aimeos\MShop\Common\Item\Iface|\Aimeos\Map|array|string $items List of item objects or IDs of the items
78
	 * @param string $cfgpath Configuration path to the SQL statement
79
	 * @param bool $siteid If siteid should be used in the statement
80
	 * @param string $name Name of the ID column
81
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
82
	 */
83
	protected function deleteItemsBase( $items, string $cfgpath, bool $siteid = true,
84
		string $name = 'id' ) : \Aimeos\MShop\Common\Manager\Iface
85
	{
86
		if( map( $items )->isEmpty() ) {
87
			return $this;
88
		}
89
90
		$search = $this->object()->filter();
91
		$search->setConditions( $search->compare( '==', $name, $items ) );
92
93
		$types = array( $name => \Aimeos\Base\DB\Statement\Base::PARAM_STR );
94
		$translations = array( $name => '"' . $name . '"' );
95
96
		$cond = $search->getConditionSource( $types, $translations );
97
		$sql = str_replace( ':cond', $cond, $this->getSqlConfig( $cfgpath ) );
98
99
		$context = $this->context();
100
		$conn = $context->db( $this->getResourceName() );
101
102
		$stmt = $conn->create( $sql );
103
104
		if( $siteid )
105
		{
106
			$stmt->bind( 1, $context->locale()->getSiteId() . '%' );
107
			$stmt->bind( 2, $context->user()?->getSiteId() );
108
		}
109
110
		$stmt->execute()->finish();
111
112
		return $this;
113
	}
114
115
116
	/**
117
	 * Returns the config path for retrieving the configuration values.
118
	 *
119
	 * @return string Configuration path
120
	 */
121
	protected function getConfigPath() : string
122
	{
123
		return 'mshop/customer/manager/address/';
124
	}
125
126
127
	/**
128
	 * Returns the prefix for the item properties and search keys.
129
	 *
130
	 * @return string Prefix for the item properties and search keys
131
	 */
132
	protected function prefix() : string
133
	{
134
		return 'customer.address.';
135
	}
136
137
138
	/**
139
	 * Saves a common address item object.
140
	 *
141
	 * @param \Aimeos\MShop\Common\Item\Address\Iface $item common address item object
142
	 * @param bool $fetch True if the new ID should be returned in the item
143
	 * @return \Aimeos\MShop\Common\Item\Address\Iface $item Updated item including the generated ID
144
	 */
145
	protected function saveBase( \Aimeos\MShop\Common\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Common\Item\Iface
146
	{
147
		if( !$item->isModified() ) {
148
			return $item;
149
		}
150
151
		$context = $this->context();
152
		$conn = $context->db( $this->getResourceName() );
153
154
		$id = $item->getId();
155
		$columns = array_column( $this->object()->getSaveAttributes(), null, 'internalcode' );
156
157
		if( $id === null )
158
		{
159
			$path = 'mshop/customer/manager/address/insert';
160
			$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

160
			$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
161
		}
162
		else
163
		{
164
			$path = 'mshop/customer/manager/address/update';
165
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
166
		}
167
168
		$idx = 1;
169
		$values = $item->toArray( true );
170
		$stmt = $this->getCachedStatement( $conn, $path, $sql );
171
172
		foreach( $this->object()->getSaveAttributes() as $name => $entry )
173
		{
174
			$value = $values[$entry->getCode()] ?? null;
175
			$value = $entry->getType() === 'json' ? json_encode( $value, JSON_FORCE_OBJECT ) : $value;
176
			$stmt->bind( $idx++, $value, \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
177
		}
178
179
		$stmt->bind( $idx++, $context->datetime() ); //mtime
180
		$stmt->bind( $idx++, $context->editor() );
181
182
		if( $id !== null ) {
183
			$stmt->bind( $idx++, $context->locale()->getSiteId() . '%' );
184
			$stmt->bind( $idx++, $context->user()?->getSiteId() );
185
			$stmt->bind( $idx++, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
186
		} else {
187
			$stmt->bind( $idx++, $this->siteId( $item->getSiteId(), \Aimeos\MShop\Locale\Manager\Base::SITE_SUBTREE ) );
188
			$stmt->bind( $idx++, $context->datetime() ); // ctime
189
		}
190
191
		$stmt->execute()->finish();
192
193
		if( $id === null && $fetch === true ) {
194
			$id = $this->newId( $conn, 'mshop/common/manager/newid' );
195
		}
196
197
		return $item->setId( $id );
198
	}
199
200
201
	/** mshop/customer/manager/address/name
202
	 * Class name of the used customer address manager implementation
203
	 *
204
	 * Each default customer address manager can be replaced by an alternative imlementation.
205
	 * To use this implementation, you have to set the last part of the class
206
	 * name as configuration value so the manager factory knows which class it
207
	 * has to instantiate.
208
	 *
209
	 * For example, if the name of the default class is
210
	 *
211
	 *  \Aimeos\MShop\Customer\Manager\Address\Standard
212
	 *
213
	 * and you want to replace it with your own version named
214
	 *
215
	 *  \Aimeos\MShop\Customer\Manager\Address\Myaddress
216
	 *
217
	 * then you have to set the this configuration option:
218
	 *
219
	 *  mshop/customer/manager/address/name = Myaddress
220
	 *
221
	 * The value is the last part of your own class name and it's case sensitive,
222
	 * so take care that the configuration value is exactly named like the last
223
	 * part of the class name.
224
	 *
225
	 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
226
	 * characters are possible! You should always start the last part of the class
227
	 * name with an upper case character and continue only with lower case characters
228
	 * or numbers. Avoid chamel case names like "MyAddress"!
229
	 *
230
	 * @param string Last part of the class name
231
	 * @since 2015.10
232
	 */
233
234
	/** mshop/customer/manager/address/decorators/excludes
235
	 * Excludes decorators added by the "common" option from the customer address manager
236
	 *
237
	 * Decorators extend the functionality of a class by adding new aspects
238
	 * (e.g. log what is currently done), executing the methods of the underlying
239
	 * class only in certain conditions (e.g. only for logged in users) or
240
	 * modify what is returned to the caller.
241
	 *
242
	 * This option allows you to remove a decorator added via
243
	 * "mshop/common/manager/decorators/default" before they are wrapped
244
	 * around the customer address manager.
245
	 *
246
	 *  mshop/customer/manager/address/decorators/excludes = array( 'decorator1' )
247
	 *
248
	 * This would remove the decorator named "decorator1" from the list of
249
	 * common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
250
	 * "mshop/common/manager/decorators/default" for the customer address manager.
251
	 *
252
	 * @param array Address of decorator names
253
	 * @since 2015.10
254
	 * @see mshop/common/manager/decorators/default
255
	 * @see mshop/customer/manager/address/decorators/global
256
	 * @see mshop/customer/manager/address/decorators/local
257
	 */
258
259
	/** mshop/customer/manager/address/decorators/global
260
	 * Adds a list of globally available decorators only to the customer address manager
261
	 *
262
	 * Decorators extend the functionality of a class by adding new aspects
263
	 * (e.g. log what is currently done), executing the methods of the underlying
264
	 * class only in certain conditions (e.g. only for logged in users) or
265
	 * modify what is returned to the caller.
266
	 *
267
	 * This option allows you to wrap global decorators
268
	 * ("\Aimeos\MShop\Common\Manager\Decorator\*") around the customer address manager.
269
	 *
270
	 *  mshop/customer/manager/address/decorators/global = array( 'decorator1' )
271
	 *
272
	 * This would add the decorator named "decorator1" defined by
273
	 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the customer
274
	 * address manager.
275
	 *
276
	 * @param array Address of decorator names
277
	 * @since 2015.10
278
	 * @see mshop/common/manager/decorators/default
279
	 * @see mshop/customer/manager/address/decorators/excludes
280
	 * @see mshop/customer/manager/address/decorators/local
281
	 */
282
283
	/** mshop/customer/manager/address/decorators/local
284
	 * Adds a list of local decorators only to the customer address manager
285
	 *
286
	 * Decorators extend the functionality of a class by adding new aspects
287
	 * (e.g. log what is currently done), executing the methods of the underlying
288
	 * class only in certain conditions (e.g. only for logged in users) or
289
	 * modify what is returned to the caller.
290
	 *
291
	 * This option allows you to wrap local decorators
292
	 * ("\Aimeos\MShop\Customer\Manager\Address\Decorator\*") around the customer
293
	 * address manager.
294
	 *
295
	 *  mshop/customer/manager/address/decorators/local = array( 'decorator2' )
296
	 *
297
	 * This would add the decorator named "decorator2" defined by
298
	 * "\Aimeos\MShop\Customer\Manager\Address\Decorator\Decorator2" only to the
299
	 * customer address manager.
300
	 *
301
	 * @param array Address of decorator names
302
	 * @since 2015.10
303
	 * @see mshop/common/manager/decorators/default
304
	 * @see mshop/customer/manager/address/decorators/excludes
305
	 * @see mshop/customer/manager/address/decorators/global
306
	 */
307
308
	/** mshop/customer/manager/address/submanagers
309
	 * List of manager names that can be instantiated by the customer address manager
310
	 *
311
	 * Managers provide a generic interface to the underlying storage.
312
	 * Each manager has or can have sub-managers caring about particular
313
	 * aspects. Each of these sub-managers can be instantiated by its
314
	 * parent manager using the getSubManager() method.
315
	 *
316
	 * The search keys from sub-managers can be normally used in the
317
	 * manager as well. It allows you to search for items of the manager
318
	 * using the search keys of the sub-managers to further limit the
319
	 * retrieved list of items.
320
	 *
321
	 * @param array List of sub-manager names
322
	 * @since 2015.10
323
	 */
324
325
	/** mshop/customer/manager/address/insert/mysql
326
	 * Inserts a new customer address record into the database table
327
	 *
328
	 * @see mshop/customer/manager/address/insert/ansi
329
	 */
330
331
	/** mshop/customer/manager/address/insert/ansi
332
	 * Inserts a new customer address record into the database table
333
	 *
334
	 * Items with no ID yet (i.e. the ID is NULL) will be created in
335
	 * the database and the newly created ID retrieved afterwards
336
	 * using the "newid" SQL statement.
337
	 *
338
	 * The SQL statement must be a string suitable for being used as
339
	 * prepared statement. It must include question marks for binding
340
	 * the values from the customer list item to the statement before they are
341
	 * sent to the database server. The number of question marks must
342
	 * be the same as the number of columns listed in the INSERT
343
	 * statement. The order of the columns must correspond to the
344
	 * order in the save() method, so the correct values are
345
	 * bound to the columns.
346
	 *
347
	 * The SQL statement should conform to the ANSI standard to be
348
	 * compatible with most relational database systems. This also
349
	 * includes using double quotes for table and column names.
350
	 *
351
	 * @param string SQL statement for inserting records
352
	 * @since 2015.10
353
	 * @see mshop/customer/manager/address/update/ansi
354
	 * @see mshop/customer/manager/address/newid/ansi
355
	 * @see mshop/customer/manager/address/delete/ansi
356
	 * @see mshop/customer/manager/address/search/ansi
357
	 * @see mshop/customer/manager/address/count/ansi
358
	 */
359
360
	/** mshop/customer/manager/address/update/mysql
361
	 * Updates an existing customer address record in the database
362
	 *
363
	 * @see mshop/customer/manager/address/update/ansi
364
	 */
365
366
	/** mshop/customer/manager/address/update/ansi
367
	 * Updates an existing customer address record in the database
368
	 *
369
	 * Items which already have an ID (i.e. the ID is not NULL) will
370
	 * be updated in the database.
371
	 *
372
	 * The SQL statement must be a string suitable for being used as
373
	 * prepared statement. It must include question marks for binding
374
	 * the values from the customer list item to the statement before they are
375
	 * sent to the database server. The order of the columns must
376
	 * correspond to the order in the save() method, so the
377
	 * correct values are bound to the columns.
378
	 *
379
	 * The SQL statement should conform to the ANSI standard to be
380
	 * compatible with most relational database systems. This also
381
	 * includes using double quotes for table and column names.
382
	 *
383
	 * @param string SQL statement for updating records
384
	 * @since 2015.10
385
	 * @see mshop/customer/manager/address/insert/ansi
386
	 * @see mshop/customer/manager/address/newid/ansi
387
	 * @see mshop/customer/manager/address/delete/ansi
388
	 * @see mshop/customer/manager/address/search/ansi
389
	 * @see mshop/customer/manager/address/count/ansi
390
	 */
391
392
	/** mshop/customer/manager/address/newid/mysql
393
	 * Retrieves the ID generated by the database when inserting a new record
394
	 *
395
	 * @see mshop/customer/manager/address/newid/ansi
396
	 */
397
398
	/** mshop/customer/manager/address/newid/ansi
399
	 * Retrieves the ID generated by the database when inserting a new record
400
	 *
401
	 * As soon as a new record is inserted into the database table,
402
	 * the database server generates a new and unique identifier for
403
	 * that record. This ID can be used for retrieving, updating and
404
	 * deleting that specific record from the table again.
405
	 *
406
	 * For MySQL:
407
	 *  SELECT LAST_INSERT_ID()
408
	 * For PostgreSQL:
409
	 *  SELECT currval('seq_mcusad_id')
410
	 * For SQL Server:
411
	 *  SELECT SCOPE_IDENTITY()
412
	 * For Oracle:
413
	 *  SELECT "seq_mcusad_id".CURRVAL FROM DUAL
414
	 *
415
	 * There's no way to retrive the new ID by a SQL statements that
416
	 * fits for most database servers as they implement their own
417
	 * specific way.
418
	 *
419
	 * @param string SQL statement for retrieving the last inserted record ID
420
	 * @since 2015.10
421
	 * @see mshop/customer/manager/address/insert/ansi
422
	 * @see mshop/customer/manager/address/update/ansi
423
	 * @see mshop/customer/manager/address/delete/ansi
424
	 * @see mshop/customer/manager/address/search/ansi
425
	 * @see mshop/customer/manager/address/count/ansi
426
	 */
427
428
	/** mshop/customer/manager/address/delete/mysql
429
	 * Deletes the items matched by the given IDs from the database
430
	 *
431
	 * @see mshop/customer/manager/address/delete/ansi
432
	 */
433
434
	/** mshop/customer/manager/address/delete/ansi
435
	 * Deletes the items matched by the given IDs from the database
436
	 *
437
	 * Removes the records specified by the given IDs from the customer database.
438
	 * The records must be from the site that is configured via the
439
	 * context item.
440
	 *
441
	 * The ":cond" placeholder is replaced by the name of the ID column and
442
	 * the given ID or list of IDs while the site ID is bound to the question
443
	 * mark.
444
	 *
445
	 * The SQL statement should conform to the ANSI standard to be
446
	 * compatible with most relational database systems. This also
447
	 * includes using double quotes for table and column names.
448
	 *
449
	 * @param string SQL statement for deleting items
450
	 * @since 2015.10
451
	 * @see mshop/customer/manager/address/insert/ansi
452
	 * @see mshop/customer/manager/address/update/ansi
453
	 * @see mshop/customer/manager/address/newid/ansi
454
	 * @see mshop/customer/manager/address/search/ansi
455
	 * @see mshop/customer/manager/address/count/ansi
456
	 */
457
458
	/** mshop/customer/manager/address/search/mysql
459
	 * Retrieves the records matched by the given criteria in the database
460
	 *
461
	 * @see mshop/customer/manager/address/search/ansi
462
	 */
463
464
	/** mshop/customer/manager/address/search/ansi
465
	 * Retrieves the records matched by the given criteria in the database
466
	 *
467
	 * Fetches the records matched by the given criteria from the customer
468
	 * database. The records must be from one of the sites that are
469
	 * configured via the context item. If the current site is part of
470
	 * a tree of sites, the SELECT statement can retrieve all records
471
	 * from the current site and the complete sub-tree of sites.
472
	 *
473
	 * As the records can normally be limited by criteria from sub-managers,
474
	 * their tables must be joined in the SQL context. This is done by
475
	 * using the "internaldeps" property from the definition of the ID
476
	 * column of the sub-managers. These internal dependencies specify
477
	 * the JOIN between the tables and the used columns for joining. The
478
	 * ":joins" placeholder is then replaced by the JOIN strings from
479
	 * the sub-managers.
480
	 *
481
	 * To limit the records matched, conditions can be added to the given
482
	 * criteria object. It can contain comparisons like column names that
483
	 * must match specific values which can be combined by AND, OR or NOT
484
	 * operators. The resulting string of SQL conditions replaces the
485
	 * ":cond" placeholder before the statement is sent to the database
486
	 * server.
487
	 *
488
	 * If the records that are retrieved should be ordered by one or more
489
	 * columns, the generated string of column / sort direction pairs
490
	 * replaces the ":order" placeholder. Columns of
491
	 * sub-managers can also be used for ordering the result set but then
492
	 * no index can be used.
493
	 *
494
	 * The number of returned records can be limited and can start at any
495
	 * number between the begining and the end of the result set. For that
496
	 * the ":size" and ":start" placeholders are replaced by the
497
	 * corresponding values from the criteria object. The default values
498
	 * are 0 for the start and 100 for the size value.
499
	 *
500
	 * The SQL statement should conform to the ANSI standard to be
501
	 * compatible with most relational database systems. This also
502
	 * includes using double quotes for table and column names.
503
	 *
504
	 * @param string SQL statement for searching items
505
	 * @since 2015.10
506
	 * @see mshop/customer/manager/address/insert/ansi
507
	 * @see mshop/customer/manager/address/update/ansi
508
	 * @see mshop/customer/manager/address/newid/ansi
509
	 * @see mshop/customer/manager/address/delete/ansi
510
	 * @see mshop/customer/manager/address/count/ansi
511
	 */
512
513
	/** mshop/customer/manager/address/count/mysql
514
	 * Counts the number of records matched by the given criteria in the database
515
	 *
516
	 * @see mshop/customer/manager/address/count/ansi
517
	 */
518
519
	/** mshop/customer/manager/address/count/ansi
520
	 * Counts the number of records matched by the given criteria in the database
521
	 *
522
	 * Counts all records matched by the given criteria from the customer
523
	 * database. The records must be from one of the sites that are
524
	 * configured via the context item. If the current site is part of
525
	 * a tree of sites, the statement can count all records from the
526
	 * current site and the complete sub-tree of sites.
527
	 *
528
	 * As the records can normally be limited by criteria from sub-managers,
529
	 * their tables must be joined in the SQL context. This is done by
530
	 * using the "internaldeps" property from the definition of the ID
531
	 * column of the sub-managers. These internal dependencies specify
532
	 * the JOIN between the tables and the used columns for joining. The
533
	 * ":joins" placeholder is then replaced by the JOIN strings from
534
	 * the sub-managers.
535
	 *
536
	 * To limit the records matched, conditions can be added to the given
537
	 * criteria object. It can contain comparisons like column names that
538
	 * must match specific values which can be combined by AND, OR or NOT
539
	 * operators. The resulting string of SQL conditions replaces the
540
	 * ":cond" placeholder before the statement is sent to the database
541
	 * server.
542
	 *
543
	 * Both, the strings for ":joins" and for ":cond" are the same as for
544
	 * the "search" SQL statement.
545
	 *
546
	 * Contrary to the "search" statement, it doesn't return any records
547
	 * but instead the number of records that have been found. As counting
548
	 * thousands of records can be a long running task, the maximum number
549
	 * of counted records is limited for performance reasons.
550
	 *
551
	 * The SQL statement should conform to the ANSI standard to be
552
	 * compatible with most relational database systems. This also
553
	 * includes using double quotes for table and column names.
554
	 *
555
	 * @param string SQL statement for counting items
556
	 * @since 2015.10
557
	 * @see mshop/customer/manager/address/insert/ansi
558
	 * @see mshop/customer/manager/address/update/ansi
559
	 * @see mshop/customer/manager/address/newid/ansi
560
	 * @see mshop/customer/manager/address/delete/ansi
561
	 * @see mshop/customer/manager/address/search/ansi
562
	 */
563
}
564