Passed
Push — master ( 801d58...b615cd )
by Aimeos
05:02
created

Standard::getUser()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 0
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2013
6
 * @copyright Aimeos (aimeos.org), 2015-2023
7
 * @package MShop
8
 * @subpackage Customer
9
 */
10
11
12
namespace Aimeos\MShop\Customer\Manager\Address;
13
14
15
/**
16
 * Implementation for customer address manager.
17
 *
18
 * @package MShop
19
 * @subpackage Customer
20
 */
21
class Standard
22
	extends \Aimeos\MShop\Common\Manager\Address\Base
23
	implements \Aimeos\MShop\Customer\Manager\Address\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
24
{
25
	private array $searchConfig = array(
26
		'customer.address.id' => array(
27
			'label' => 'Address ID',
28
			'code' => 'customer.address.id',
29
			'internalcode' => 'mcusad."id"',
30
			'internaldeps' => array( 'LEFT JOIN "mshop_customer_address" AS mcusad ON ( mcus."id" = mcusad."parentid" )' ),
31
			'type' => 'int',
32
			'public' => false,
33
		),
34
		'customer.address.siteid' => array(
35
			'code' => 'customer.address.siteid',
36
			'internalcode' => 'mcusad."siteid"',
37
			'label' => 'Customer address site ID',
38
			'public' => false,
39
		),
40
		'customer.address.parentid' => array(
41
			'label' => 'Address parent ID',
42
			'code' => 'customer.address.parentid',
43
			'internalcode' => 'mcusad."parentid"',
44
			'type' => 'int',
45
			'public' => false,
46
		),
47
		'customer.address.company' => array(
48
			'label' => 'Address company',
49
			'code' => 'customer.address.company',
50
			'internalcode' => 'mcusad."company"',
51
		),
52
		'customer.address.vatid' => array(
53
			'label' => 'Address Vat ID',
54
			'code' => 'customer.address.vatid',
55
			'internalcode' => 'mcusad."vatid"',
56
		),
57
		'customer.address.salutation' => array(
58
			'label' => 'Address salutation',
59
			'code' => 'customer.address.salutation',
60
			'internalcode' => 'mcusad."salutation"',
61
		),
62
		'customer.address.title' => array(
63
			'label' => 'Address title',
64
			'code' => 'customer.address.title',
65
			'internalcode' => 'mcusad."title"',
66
		),
67
		'customer.address.firstname' => array(
68
			'label' => 'Address firstname',
69
			'code' => 'customer.address.firstname',
70
			'internalcode' => 'mcusad."firstname"',
71
		),
72
		'customer.address.lastname' => array(
73
			'label' => 'Address lastname',
74
			'code' => 'customer.address.lastname',
75
			'internalcode' => 'mcusad."lastname"',
76
		),
77
		'customer.address.address1' => array(
78
			'label' => 'Address address part one',
79
			'code' => 'customer.address.address1',
80
			'internalcode' => 'mcusad."address1"',
81
		),
82
		'customer.address.address2' => array(
83
			'label' => 'Address address part two',
84
			'code' => 'customer.address.address2',
85
			'internalcode' => 'mcusad."address2"',
86
		),
87
		'customer.address.address3' => array(
88
			'label' => 'Address address part three',
89
			'code' => 'customer.address.address3',
90
			'internalcode' => 'mcusad."address3"',
91
		),
92
		'customer.address.postal' => array(
93
			'label' => 'Address postal',
94
			'code' => 'customer.address.postal',
95
			'internalcode' => 'mcusad."postal"',
96
		),
97
		'customer.address.city' => array(
98
			'label' => 'Address city',
99
			'code' => 'customer.address.city',
100
			'internalcode' => 'mcusad."city"',
101
		),
102
		'customer.address.state' => array(
103
			'label' => 'Address state',
104
			'code' => 'customer.address.state',
105
			'internalcode' => 'mcusad."state"',
106
		),
107
		'customer.address.languageid' => array(
108
			'label' => 'Address language',
109
			'code' => 'customer.address.languageid',
110
			'internalcode' => 'mcusad."langid"',
111
		),
112
		'customer.address.countryid' => array(
113
			'label' => 'Address country',
114
			'code' => 'customer.address.countryid',
115
			'internalcode' => 'mcusad."countryid"',
116
		),
117
		'customer.address.telephone' => array(
118
			'label' => 'Address telephone',
119
			'code' => 'customer.address.telephone',
120
			'internalcode' => 'mcusad."telephone"',
121
		),
122
		'customer.address.telefax' => array(
123
			'label' => 'Address telefax',
124
			'code' => 'customer.address.telefax',
125
			'internalcode' => 'mcusad."telefax"',
126
		),
127
		'customer.address.mobile' => array(
128
			'label' => 'Address mobile number',
129
			'code' => 'customer.address.mobile',
130
			'internalcode' => 'mcusad."mobile"',
131
		),
132
		'customer.address.email' => array(
133
			'label' => 'Address email',
134
			'code' => 'customer.address.email',
135
			'internalcode' => 'mcusad."email"',
136
		),
137
		'customer.address.website' => array(
138
			'label' => 'Address website',
139
			'code' => 'customer.address.website',
140
			'internalcode' => 'mcusad."website"',
141
		),
142
		'customer.address.longitude' => array(
143
			'label' => 'Address longitude',
144
			'code' => 'customer.address.longitude',
145
			'internalcode' => 'mcusad."longitude"',
146
			'type' => 'float',
147
			'public' => false,
148
		),
149
		'customer.address.latitude' => array(
150
			'label' => 'Address latitude',
151
			'code' => 'customer.address.latitude',
152
			'internalcode' => 'mcusad."latitude"',
153
			'type' => 'float',
154
			'public' => false,
155
		),
156
		'customer.address.position' => array(
157
			'code' => 'customer.address.position',
158
			'internalcode' => 'mcusad."pos"',
159
			'label' => 'Address position',
160
			'type' => 'int',
161
			'public' => false,
162
		),
163
		'customer.address.birthday' => array(
164
			'code' => 'customer.address.birthday',
165
			'internalcode' => 'mcusad."birthday"',
166
			'label' => 'Address birthday',
167
			'type' => 'date',
168
			'public' => false,
169
		),
170
		'customer.address.ctime' => array(
171
			'code' => 'customer.address.ctime',
172
			'internalcode' => 'mcusad."ctime"',
173
			'label' => 'Address create date/time',
174
			'type' => 'datetime',
175
			'public' => false,
176
		),
177
		'customer.address.mtime' => array(
178
			'code' => 'customer.address.mtime',
179
			'internalcode' => 'mcusad."mtime"',
180
			'label' => 'Address modify date/time',
181
			'type' => 'datetime',
182
			'public' => false,
183
		),
184
		'customer.address.editor' => array(
185
			'code' => 'customer.address.editor',
186
			'internalcode' => 'mcusad."editor"',
187
			'label' => 'Address editor',
188
			'public' => false,
189
		),
190
	);
191
192
	private ?\Aimeos\MShop\Customer\Item\Iface $user = null;
193
194
195
	/**
196
	 * Initializes the object.
197
	 *
198
	 * @param \Aimeos\MShop\ContextIface $context Context object
199
	 */
200
	public function __construct( \Aimeos\MShop\ContextIface $context )
201
	{
202
		parent::__construct( $context );
203
204
		/** mshop/customer/manager/resource
205
		 * Name of the database connection resource to use
206
		 *
207
		 * You can configure a different database connection for each data domain
208
		 * and if no such connection name exists, the "db" connection will be used.
209
		 * It's also possible to use the same database connection for different
210
		 * data domains by configuring the same connection name using this setting.
211
		 *
212
		 * @param string Database connection name
213
		 * @since 2023.04
214
		 */
215
		$this->setResourceName( $context->config()->get( 'mshop/customer/manager/resource', 'db-customer' ) );
216
	}
217
218
219
	/**
220
	 * Removes old entries from the storage.
221
	 *
222
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
223
	 * @return \Aimeos\MShop\Customer\Manager\Address\Iface Manager object for chaining method calls
224
	 */
225
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
226
	{
227
		$path = 'mshop/customer/manager/address/submanagers';
228
		foreach( $this->context()->config()->get( $path, [] ) as $domain ) {
229
			$this->object()->getSubManager( $domain )->clear( $siteids );
230
		}
231
232
		return $this->clearBase( $siteids, 'mshop/customer/manager/address/clear' );
233
	}
234
235
236
	/**
237
	 * Returns the available manager types
238
	 *
239
	 * @param bool $withsub Return also the resource type of sub-managers if true
240
	 * @return string[] Type of the manager and submanagers, subtypes are separated by slashes
241
	 */
242
	public function getResourceType( bool $withsub = true ) : array
243
	{
244
		$path = 'mshop/customer/manager/address/submanagers';
245
246
		return $this->getResourceTypeBase( 'customer/address', $path, [], $withsub );
247
	}
248
249
250
	/**
251
	 * Returns the list attributes that can be used for searching.
252
	 *
253
	 * @param bool $withsub Return also attributes of sub-managers if true
254
	 * @return \Aimeos\Base\Criteria\Attribute\Iface[] List of search attribute items
255
	 */
256
	public function getSearchAttributes( bool $withsub = true ) : array
257
	{
258
		/** mshop/customer/manager/address/submanagers
259
		 * List of manager names that can be instantiated by the customer address manager
260
		 *
261
		 * Managers provide a generic interface to the underlying storage.
262
		 * Each manager has or can have sub-managers caring about particular
263
		 * aspects. Each of these sub-managers can be instantiated by its
264
		 * parent manager using the getSubManager() method.
265
		 *
266
		 * The search keys from sub-managers can be normally used in the
267
		 * manager as well. It allows you to search for items of the manager
268
		 * using the search keys of the sub-managers to further limit the
269
		 * retrieved list of items.
270
		 *
271
		 * @param array List of sub-manager names
272
		 * @since 2014.03
273
		 * @category Developer
274
		 */
275
		$path = 'mshop/customer/manager/address/submanagers';
276
277
		return $this->getSearchAttributesBase( $this->searchConfig, $path, [], $withsub );
278
	}
279
280
281
	/**
282
	 * Returns a new manager for address extensions.
283
	 *
284
	 * @param string $manager Name of the sub manager type in lower case
285
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
286
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g type, etc.
287
	 */
288
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
289
	{
290
		/** mshop/customer/manager/address/name
291
		 * Class name of the used customer address manager implementation
292
		 *
293
		 * Each default customer address manager can be replaced by an alternative imlementation.
294
		 * To use this implementation, you have to set the last part of the class
295
		 * name as configuration value so the manager factory knows which class it
296
		 * has to instantiate.
297
		 *
298
		 * For example, if the name of the default class is
299
		 *
300
		 *  \Aimeos\MShop\Customer\Manager\Address\Standard
301
		 *
302
		 * and you want to replace it with your own version named
303
		 *
304
		 *  \Aimeos\MShop\Customer\Manager\Address\Myaddress
305
		 *
306
		 * then you have to set the this configuration option:
307
		 *
308
		 *  mshop/customer/manager/address/name = Myaddress
309
		 *
310
		 * The value is the last part of your own class name and it's case sensitive,
311
		 * so take care that the configuration value is exactly named like the last
312
		 * part of the class name.
313
		 *
314
		 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
315
		 * characters are possible! You should always start the last part of the class
316
		 * name with an upper case character and continue only with lower case characters
317
		 * or numbers. Avoid chamel case names like "MyAddress"!
318
		 *
319
		 * @param string Last part of the class name
320
		 * @since 2014.03
321
		 * @category Developer
322
		 */
323
324
		/** mshop/customer/manager/address/decorators/excludes
325
		 * Excludes decorators added by the "common" option from the customer address manager
326
		 *
327
		 * Decorators extend the functionality of a class by adding new aspects
328
		 * (e.g. log what is currently done), executing the methods of the underlying
329
		 * class only in certain conditions (e.g. only for logged in users) or
330
		 * modify what is returned to the caller.
331
		 *
332
		 * This option allows you to remove a decorator added via
333
		 * "mshop/common/manager/decorators/default" before they are wrapped
334
		 * around the customer address manager.
335
		 *
336
		 *  mshop/customer/manager/address/decorators/excludes = array( 'decorator1' )
337
		 *
338
		 * This would remove the decorator named "decorator1" from the list of
339
		 * common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
340
		 * "mshop/common/manager/decorators/default" for the customer address manager.
341
		 *
342
		 * @param array Address of decorator names
343
		 * @since 2014.03
344
		 * @category Developer
345
		 * @see mshop/common/manager/decorators/default
346
		 * @see mshop/customer/manager/address/decorators/global
347
		 * @see mshop/customer/manager/address/decorators/local
348
		 */
349
350
		/** mshop/customer/manager/address/decorators/global
351
		 * Adds a list of globally available decorators only to the customer address manager
352
		 *
353
		 * Decorators extend the functionality of a class by adding new aspects
354
		 * (e.g. log what is currently done), executing the methods of the underlying
355
		 * class only in certain conditions (e.g. only for logged in users) or
356
		 * modify what is returned to the caller.
357
		 *
358
		 * This option allows you to wrap global decorators
359
		 * ("\Aimeos\MShop\Common\Manager\Decorator\*") around the customer address manager.
360
		 *
361
		 *  mshop/customer/manager/address/decorators/global = array( 'decorator1' )
362
		 *
363
		 * This would add the decorator named "decorator1" defined by
364
		 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the customer
365
		 * address manager.
366
		 *
367
		 * @param array Address of decorator names
368
		 * @since 2014.03
369
		 * @category Developer
370
		 * @see mshop/common/manager/decorators/default
371
		 * @see mshop/customer/manager/address/decorators/excludes
372
		 * @see mshop/customer/manager/address/decorators/local
373
		 */
374
375
		/** mshop/customer/manager/address/decorators/local
376
		 * Adds a list of local decorators only to the customer address manager
377
		 *
378
		 * Decorators extend the functionality of a class by adding new aspects
379
		 * (e.g. log what is currently done), executing the methods of the underlying
380
		 * class only in certain conditions (e.g. only for logged in users) or
381
		 * modify what is returned to the caller.
382
		 *
383
		 * This option allows you to wrap local decorators
384
		 * ("\Aimeos\MShop\Customer\Manager\Address\Decorator\*") around the customer
385
		 * address manager.
386
		 *
387
		 *  mshop/customer/manager/address/decorators/local = array( 'decorator2' )
388
		 *
389
		 * This would add the decorator named "decorator2" defined by
390
		 * "\Aimeos\MShop\Customer\Manager\Address\Decorator\Decorator2" only to the
391
		 * customer address manager.
392
		 *
393
		 * @param array Address of decorator names
394
		 * @since 2014.03
395
		 * @category Developer
396
		 * @see mshop/common/manager/decorators/default
397
		 * @see mshop/customer/manager/address/decorators/excludes
398
		 * @see mshop/customer/manager/address/decorators/global
399
		 */
400
401
		return $this->getSubManagerBase( 'customer', 'address/' . $manager, $name );
402
	}
403
404
405
	/**
406
	 * Saves a common address item object.
407
	 *
408
	 * @param \Aimeos\MShop\Common\Item\Address\Iface $item common address item object
409
	 * @param bool $fetch True if the new ID should be returned in the item
410
	 * @return \Aimeos\MShop\Common\Item\Address\Iface $item Updated item including the generated ID
411
	 */
412
	protected function saveItem( \Aimeos\MShop\Common\Item\Address\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Common\Item\Address\Iface
413
	{
414
		if( !$item->isModified() ) {
415
			return $item;
416
		}
417
418
		$context = $this->context();
419
		$conn = $context->db( $this->getResourceName() );
420
421
		$id = $item->getId();
422
		$date = date( 'Y-m-d H:i:s' );
423
		$path = $this->getConfigPath();
424
		$columns = $this->object()->getSaveAttributes();
425
426
		if( $id === null ) {
427
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path .= 'insert' ) );
0 ignored issues
show
Bug introduced by
It seems like $this->getSqlConfig(AssignConcatNode) 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

427
			$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path .= 'insert' ) );
Loading history...
428
		} else {
429
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path .= 'update' ), false );
430
		}
431
432
		$idx = 1;
433
		$stmt = $this->getCachedStatement( $conn, $path, $sql );
434
435
		foreach( $columns as $name => $entry ) {
436
			$stmt->bind( $idx++, $item->get( $name ), \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
437
		}
438
439
		$stmt->bind( $idx++, $item->getParentId(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
440
		$stmt->bind( $idx++, $item->getCompany() );
441
		$stmt->bind( $idx++, $item->getVatId() );
442
		$stmt->bind( $idx++, $item->getSalutation() );
443
		$stmt->bind( $idx++, $item->getTitle() );
444
		$stmt->bind( $idx++, $item->getFirstname() );
445
		$stmt->bind( $idx++, $item->getLastname() );
446
		$stmt->bind( $idx++, $item->getAddress1() );
447
		$stmt->bind( $idx++, $item->getAddress2() );
448
		$stmt->bind( $idx++, $item->getAddress3() );
449
		$stmt->bind( $idx++, $item->getPostal() );
450
		$stmt->bind( $idx++, $item->getCity() );
451
		$stmt->bind( $idx++, $item->getState() );
452
		$stmt->bind( $idx++, $item->getCountryId() );
453
		$stmt->bind( $idx++, $item->getLanguageId() );
454
		$stmt->bind( $idx++, $item->getTelephone() );
455
		$stmt->bind( $idx++, $item->getMobile() );
456
		$stmt->bind( $idx++, $item->getEmail() );
457
		$stmt->bind( $idx++, $item->getTelefax() );
458
		$stmt->bind( $idx++, $item->getWebsite() );
459
		$stmt->bind( $idx++, $item->getLongitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
460
		$stmt->bind( $idx++, $item->getLatitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
461
		$stmt->bind( $idx++, $item->getPosition(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
462
		$stmt->bind( $idx++, $item->getBirthday() );
463
		$stmt->bind( $idx++, $date ); //mtime
464
		$stmt->bind( $idx++, $context->editor() );
465
466
		if( $id !== null ) {
467
			$stmt->bind( $idx++, $context->locale()->getSiteId() . '%' );
468
			$stmt->bind( $idx++, $this->getUser()?->getSiteId() );
469
			$stmt->bind( $idx++, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
470
		} else {
471
			$stmt->bind( $idx++, $this->siteId( $item->getSiteId(), \Aimeos\MShop\Locale\Manager\Base::SITE_SUBTREE ) );
472
			$stmt->bind( $idx++, $date ); // ctime
473
		}
474
475
		$stmt->execute()->finish();
476
477
		if( $id === null && $fetch === true ) {
478
			$id = $this->newId( $conn, $this->getConfigPath() . 'newid' );
479
		}
480
481
		return $item->setId( $id );
482
	}
483
484
485
	/**
486
	 * Creates a new address item
487
	 *
488
	 * @param array $values List of attributes for address item
489
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface New address item
490
	 */
491
	protected function createItemBase( array $values = [] ) : \Aimeos\MShop\Common\Item\Address\Iface
492
	{
493
		return new \Aimeos\MShop\Customer\Item\Address\Standard( $this->getPrefix(), $values );
494
	}
495
496
497
	/**
498
	 * Deletes items.
499
	 *
500
	 * @param \Aimeos\MShop\Common\Item\Iface|\Aimeos\Map|array|string $items List of item objects or IDs of the items
501
	 * @param string $cfgpath Configuration path to the SQL statement
502
	 * @param bool $siteid If siteid should be used in the statement
503
	 * @param string $name Name of the ID column
504
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
505
	 */
506
	protected function deleteItemsBase( $items, string $cfgpath, bool $siteid = true,
507
		string $name = 'id' ) : \Aimeos\MShop\Common\Manager\Iface
508
	{
509
		if( map( $items )->isEmpty() ) {
510
			return $this;
511
		}
512
513
		$search = $this->object()->filter();
514
		$search->setConditions( $search->compare( '==', $name, $items ) );
515
516
		$types = array( $name => \Aimeos\Base\DB\Statement\Base::PARAM_STR );
517
		$translations = array( $name => '"' . $name . '"' );
518
519
		$cond = $search->getConditionSource( $types, $translations );
520
		$sql = str_replace( ':cond', $cond, $this->getSqlConfig( $cfgpath ) );
521
522
		$context = $this->context();
523
		$conn = $context->db( $this->getResourceName() );
524
525
		$stmt = $conn->create( $sql );
526
527
		if( $siteid )
528
		{
529
			$stmt->bind( 1, $context->locale()->getSiteId() . '%' );
530
			$stmt->bind( 2, $this->getUser()?->getSiteId() );
531
		}
532
533
		$stmt->execute()->finish();
534
535
		return $this;
536
	}
537
538
539
	/**
540
	 * Returns the config path for retrieving the configuration values.
541
	 *
542
	 * @return string Configuration path
543
	 */
544
	protected function getConfigPath() : string
545
	{
546
		/** mshop/customer/manager/address/insert/mysql
547
		 * Inserts a new customer address record into the database table
548
		 *
549
		 * @see mshop/customer/manager/address/insert/ansi
550
		 */
551
552
		/** mshop/customer/manager/address/insert/ansi
553
		 * Inserts a new customer address record into the database table
554
		 *
555
		 * Items with no ID yet (i.e. the ID is NULL) will be created in
556
		 * the database and the newly created ID retrieved afterwards
557
		 * using the "newid" SQL statement.
558
		 *
559
		 * The SQL statement must be a string suitable for being used as
560
		 * prepared statement. It must include question marks for binding
561
		 * the values from the customer list item to the statement before they are
562
		 * sent to the database server. The number of question marks must
563
		 * be the same as the number of columns listed in the INSERT
564
		 * statement. The order of the columns must correspond to the
565
		 * order in the save() method, so the correct values are
566
		 * bound to the columns.
567
		 *
568
		 * The SQL statement should conform to the ANSI standard to be
569
		 * compatible with most relational database systems. This also
570
		 * includes using double quotes for table and column names.
571
		 *
572
		 * @param string SQL statement for inserting records
573
		 * @since 2014.03
574
		 * @category Developer
575
		 * @see mshop/customer/manager/address/update/ansi
576
		 * @see mshop/customer/manager/address/newid/ansi
577
		 * @see mshop/customer/manager/address/delete/ansi
578
		 * @see mshop/customer/manager/address/search/ansi
579
		 * @see mshop/customer/manager/address/count/ansi
580
		 */
581
582
		/** mshop/customer/manager/address/update/mysql
583
		 * Updates an existing customer address record in the database
584
		 *
585
		 * @see mshop/customer/manager/address/update/ansi
586
		 */
587
588
		/** mshop/customer/manager/address/update/ansi
589
		 * Updates an existing customer address record in the database
590
		 *
591
		 * Items which already have an ID (i.e. the ID is not NULL) will
592
		 * be updated in the database.
593
		 *
594
		 * The SQL statement must be a string suitable for being used as
595
		 * prepared statement. It must include question marks for binding
596
		 * the values from the customer list item to the statement before they are
597
		 * sent to the database server. The order of the columns must
598
		 * correspond to the order in the save() method, so the
599
		 * correct values are bound to the columns.
600
		 *
601
		 * The SQL statement should conform to the ANSI standard to be
602
		 * compatible with most relational database systems. This also
603
		 * includes using double quotes for table and column names.
604
		 *
605
		 * @param string SQL statement for updating records
606
		 * @since 2014.03
607
		 * @category Developer
608
		 * @see mshop/customer/manager/address/insert/ansi
609
		 * @see mshop/customer/manager/address/newid/ansi
610
		 * @see mshop/customer/manager/address/delete/ansi
611
		 * @see mshop/customer/manager/address/search/ansi
612
		 * @see mshop/customer/manager/address/count/ansi
613
		 */
614
615
		/** mshop/customer/manager/address/newid/mysql
616
		 * Retrieves the ID generated by the database when inserting a new record
617
		 *
618
		 * @see mshop/customer/manager/address/newid/ansi
619
		 */
620
621
		/** mshop/customer/manager/address/newid/ansi
622
		 * Retrieves the ID generated by the database when inserting a new record
623
		 *
624
		 * As soon as a new record is inserted into the database table,
625
		 * the database server generates a new and unique identifier for
626
		 * that record. This ID can be used for retrieving, updating and
627
		 * deleting that specific record from the table again.
628
		 *
629
		 * For MySQL:
630
		 *  SELECT LAST_INSERT_ID()
631
		 * For PostgreSQL:
632
		 *  SELECT currval('seq_mcusad_id')
633
		 * For SQL Server:
634
		 *  SELECT SCOPE_IDENTITY()
635
		 * For Oracle:
636
		 *  SELECT "seq_mcusad_id".CURRVAL FROM DUAL
637
		 *
638
		 * There's no way to retrive the new ID by a SQL statements that
639
		 * fits for most database servers as they implement their own
640
		 * specific way.
641
		 *
642
		 * @param string SQL statement for retrieving the last inserted record ID
643
		 * @since 2014.03
644
		 * @category Developer
645
		 * @see mshop/customer/manager/address/insert/ansi
646
		 * @see mshop/customer/manager/address/update/ansi
647
		 * @see mshop/customer/manager/address/delete/ansi
648
		 * @see mshop/customer/manager/address/search/ansi
649
		 * @see mshop/customer/manager/address/count/ansi
650
		 */
651
652
		/** mshop/customer/manager/address/delete/mysql
653
		 * Deletes the items matched by the given IDs from the database
654
		 *
655
		 * @see mshop/customer/manager/address/delete/ansi
656
		 */
657
658
		/** mshop/customer/manager/address/delete/ansi
659
		 * Deletes the items matched by the given IDs from the database
660
		 *
661
		 * Removes the records specified by the given IDs from the customer database.
662
		 * The records must be from the site that is configured via the
663
		 * context item.
664
		 *
665
		 * The ":cond" placeholder is replaced by the name of the ID column and
666
		 * the given ID or list of IDs while the site ID is bound to the question
667
		 * mark.
668
		 *
669
		 * The SQL statement should conform to the ANSI standard to be
670
		 * compatible with most relational database systems. This also
671
		 * includes using double quotes for table and column names.
672
		 *
673
		 * @param string SQL statement for deleting items
674
		 * @since 2014.03
675
		 * @category Developer
676
		 * @see mshop/customer/manager/address/insert/ansi
677
		 * @see mshop/customer/manager/address/update/ansi
678
		 * @see mshop/customer/manager/address/newid/ansi
679
		 * @see mshop/customer/manager/address/search/ansi
680
		 * @see mshop/customer/manager/address/count/ansi
681
		 */
682
683
		/** mshop/customer/manager/address/search/mysql
684
		 * Retrieves the records matched by the given criteria in the database
685
		 *
686
		 * @see mshop/customer/manager/address/search/ansi
687
		 */
688
689
		/** mshop/customer/manager/address/search/ansi
690
		 * Retrieves the records matched by the given criteria in the database
691
		 *
692
		 * Fetches the records matched by the given criteria from the customer
693
		 * database. The records must be from one of the sites that are
694
		 * configured via the context item. If the current site is part of
695
		 * a tree of sites, the SELECT statement can retrieve all records
696
		 * from the current site and the complete sub-tree of sites.
697
		 *
698
		 * As the records can normally be limited by criteria from sub-managers,
699
		 * their tables must be joined in the SQL context. This is done by
700
		 * using the "internaldeps" property from the definition of the ID
701
		 * column of the sub-managers. These internal dependencies specify
702
		 * the JOIN between the tables and the used columns for joining. The
703
		 * ":joins" placeholder is then replaced by the JOIN strings from
704
		 * the sub-managers.
705
		 *
706
		 * To limit the records matched, conditions can be added to the given
707
		 * criteria object. It can contain comparisons like column names that
708
		 * must match specific values which can be combined by AND, OR or NOT
709
		 * operators. The resulting string of SQL conditions replaces the
710
		 * ":cond" placeholder before the statement is sent to the database
711
		 * server.
712
		 *
713
		 * If the records that are retrieved should be ordered by one or more
714
		 * columns, the generated string of column / sort direction pairs
715
		 * replaces the ":order" placeholder. In case no ordering is required,
716
		 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
717
		 * markers is removed to speed up retrieving the records. Columns of
718
		 * sub-managers can also be used for ordering the result set but then
719
		 * no index can be used.
720
		 *
721
		 * The number of returned records can be limited and can start at any
722
		 * number between the begining and the end of the result set. For that
723
		 * the ":size" and ":start" placeholders are replaced by the
724
		 * corresponding values from the criteria object. The default values
725
		 * are 0 for the start and 100 for the size value.
726
		 *
727
		 * The SQL statement should conform to the ANSI standard to be
728
		 * compatible with most relational database systems. This also
729
		 * includes using double quotes for table and column names.
730
		 *
731
		 * @param string SQL statement for searching items
732
		 * @since 2014.03
733
		 * @category Developer
734
		 * @see mshop/customer/manager/address/insert/ansi
735
		 * @see mshop/customer/manager/address/update/ansi
736
		 * @see mshop/customer/manager/address/newid/ansi
737
		 * @see mshop/customer/manager/address/delete/ansi
738
		 * @see mshop/customer/manager/address/count/ansi
739
		 */
740
741
		/** mshop/customer/manager/address/count/mysql
742
		 * Counts the number of records matched by the given criteria in the database
743
		 *
744
		 * @see mshop/customer/manager/address/count/ansi
745
		 */
746
747
		/** mshop/customer/manager/address/count/ansi
748
		 * Counts the number of records matched by the given criteria in the database
749
		 *
750
		 * Counts all records matched by the given criteria from the customer
751
		 * database. The records must be from one of the sites that are
752
		 * configured via the context item. If the current site is part of
753
		 * a tree of sites, the statement can count all records from the
754
		 * current site and the complete sub-tree of sites.
755
		 *
756
		 * As the records can normally be limited by criteria from sub-managers,
757
		 * their tables must be joined in the SQL context. This is done by
758
		 * using the "internaldeps" property from the definition of the ID
759
		 * column of the sub-managers. These internal dependencies specify
760
		 * the JOIN between the tables and the used columns for joining. The
761
		 * ":joins" placeholder is then replaced by the JOIN strings from
762
		 * the sub-managers.
763
		 *
764
		 * To limit the records matched, conditions can be added to the given
765
		 * criteria object. It can contain comparisons like column names that
766
		 * must match specific values which can be combined by AND, OR or NOT
767
		 * operators. The resulting string of SQL conditions replaces the
768
		 * ":cond" placeholder before the statement is sent to the database
769
		 * server.
770
		 *
771
		 * Both, the strings for ":joins" and for ":cond" are the same as for
772
		 * the "search" SQL statement.
773
		 *
774
		 * Contrary to the "search" statement, it doesn't return any records
775
		 * but instead the number of records that have been found. As counting
776
		 * thousands of records can be a long running task, the maximum number
777
		 * of counted records is limited for performance reasons.
778
		 *
779
		 * The SQL statement should conform to the ANSI standard to be
780
		 * compatible with most relational database systems. This also
781
		 * includes using double quotes for table and column names.
782
		 *
783
		 * @param string SQL statement for counting items
784
		 * @since 2014.03
785
		 * @category Developer
786
		 * @see mshop/customer/manager/address/insert/ansi
787
		 * @see mshop/customer/manager/address/update/ansi
788
		 * @see mshop/customer/manager/address/newid/ansi
789
		 * @see mshop/customer/manager/address/delete/ansi
790
		 * @see mshop/customer/manager/address/search/ansi
791
		 */
792
793
		return 'mshop/customer/manager/address/';
794
	}
795
796
797
	/**
798
	 * Returns the search configuration for searching items.
799
	 *
800
	 * @return array Associative list of search keys and search definitions
801
	 */
802
	protected function getSearchConfig() : array
803
	{
804
		return $this->searchConfig;
805
	}
806
807
808
	/**
809
	 * Returns the currently authenticated user
810
	 *
811
	 * @return \Aimeos\MShop\Customer\Item\Iface|null Customer item or NULL if not available
812
	 */
813
	protected function getUser() : ?\Aimeos\MShop\Customer\Item\Iface
814
	{
815
		if( !isset( $this->user ) && ( $userid = $this->context()->user() ) !== null )
816
		{
817
			$manager = \Aimeos\MShop::create( $this->context(), 'customer' );
818
			$this->user = $manager->search( $manager->filter( true )->add( 'customer.id', '==', $userid ) )->first();
819
		}
820
821
		return $this->user;
822
	}
823
}
824