Passed
Push — master ( 3e2417...b4e8a9 )
by Aimeos
41:27 queued 26:41
created

Typo3::__construct()   B

Complexity

Conditions 11
Paths 1

Size

Total Lines 71
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 32
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 71
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2014-2023
7
 * @package MShop
8
 * @subpackage Customer
9
 */
10
11
12
namespace Aimeos\MShop\Customer\Manager;
13
14
15
/**
16
 * Typo3 implementation of the customer class.
17
 *
18
 * @package MShop
19
 * @subpackage Customer
20
 */
21
class Typo3
22
	extends \Aimeos\MShop\Customer\Manager\Standard
23
{
24
	private array $searchConfig = array(
25
		'customer.id' => array(
26
			'label' => 'Customer ID',
27
			'code' => 'customer.id',
28
			'internalcode' => 'mcus."uid"',
29
			'type' => 'integer',
30
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_INT,
31
			'public' => false,
32
		),
33
		'customer.siteid' => array(
34
			'code' => 'customer.siteid',
35
			'internalcode' => 'mcus."siteid"',
36
			'label' => 'Customer site ID',
37
			'type'=> 'string',
38
			'internaltype'=> \Aimeos\Base\DB\Statement\Base::PARAM_STR,
39
			'public' => false,
40
		),
41
		'customer.code' => array(
42
			'label' => 'Customer username',
43
			'code' => 'customer.code',
44
			'internalcode' => 'mcus."username"',
45
			'type' => 'string',
46
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR
47
		),
48
		'customer.label' => array(
49
			'label' => 'Customer name',
50
			'code' => 'customer.label',
51
			'internalcode' => 'mcus."name"',
52
			'type' => 'string',
53
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR
54
		),
55
		'customer.salutation' => array(
56
			'label' => 'Customer salutation',
57
			'code' => 'customer.salutation',
58
			'internalcode' => 'mcus."gender"',
59
			'type' => 'string',
60
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
61
		),
62
		'customer.company'=> array(
63
			'label' => 'Customer company',
64
			'code' => 'customer.company',
65
			'internalcode' => 'mcus."company"',
66
			'type' => 'string',
67
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
68
		),
69
		'customer.vatid'=> array(
70
			'label' => 'Customer VAT ID',
71
			'code' => 'customer.vatid',
72
			'internalcode' => 'mcus."vatid"',
73
			'type' => 'string',
74
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
75
		),
76
		'customer.title' => array(
77
			'label' => 'Customer title',
78
			'code' => 'customer.title',
79
			'internalcode' => 'mcus."title"',
80
			'type' => 'string',
81
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
82
		),
83
		'customer.firstname' => array(
84
			'label' => 'Customer firstname',
85
			'code' => 'customer.firstname',
86
			'internalcode' => 'mcus."first_name"',
87
			'type' => 'string',
88
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
89
		),
90
		'customer.lastname' => array(
91
			'label' => 'Customer lastname',
92
			'code' => 'customer.lastname',
93
			'internalcode' => 'mcus."last_name"',
94
			'type' => 'string',
95
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
96
		),
97
		'customer.address1' => array(
98
			'label' => 'Customer address part one',
99
			'code' => 'customer.address1',
100
			'internalcode' => 'mcus."address"',
101
			'type' => 'string',
102
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
103
		),
104
		'customer.address2' => array(
105
			'label' => 'Customer address part two',
106
			'code' => 'customer.address2',
107
			'internalcode' => 'mcus."address"',
108
			'type' => 'string',
109
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
110
		),
111
		'customer.address3' => array(
112
			'label' => 'Customer address part three',
113
			'code' => 'customer.address3',
114
			'internalcode' => 'mcus."address"',
115
			'type' => 'string',
116
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
117
		),
118
		'customer.postal' => array(
119
			'label' => 'Customer postal',
120
			'code' => 'customer.postal',
121
			'internalcode' => 'mcus."zip"',
122
			'type' => 'string',
123
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
124
		),
125
		'customer.city' => array(
126
			'label' => 'Customer city',
127
			'code' => 'customer.city',
128
			'internalcode' => 'mcus."city"',
129
			'type' => 'string',
130
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
131
		),
132
		'customer.state' => array(
133
			'label' => 'Customer state',
134
			'code' => 'customer.state',
135
			'internalcode' => 'mcus."zone"',
136
			'type' => 'string',
137
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
138
		),
139
		'customer.languageid' => array(
140
			'label' => 'Customer language',
141
			'code' => 'customer.languageid',
142
			'internalcode' => 'mcus."language"',
143
			'type' => 'string',
144
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
145
		),
146
		'customer.countryid' => array(
147
			'label' => 'Customer country',
148
			'code' => 'customer.countryid',
149
			'internalcode' => 'mcus."static_info_country"',
150
			'type' => 'string',
151
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
152
		),
153
		'customer.telephone' => array(
154
			'label' => 'Customer telephone',
155
			'code' => 'customer.telephone',
156
			'internalcode' => 'mcus."telephone"',
157
			'type' => 'string',
158
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
159
		),
160
		'customer.telefax' => array(
161
			'label' => 'Customer telefax',
162
			'code' => 'customer.telefax',
163
			'internalcode' => 'mcus."fax"',
164
			'type' => 'string',
165
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
166
		),
167
		'customer.mobile' => array(
168
			'label' => 'Customer mobile number',
169
			'code' => 'customer.mobile',
170
			'internalcode' => 'mcus."mobile"',
171
			'type' => 'string',
172
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
173
		),
174
		'customer.email' => array(
175
			'label' => 'Customer email',
176
			'code' => 'customer.email',
177
			'internalcode' => 'mcus."email"',
178
			'type' => 'string',
179
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
180
		),
181
		'customer.website' => array(
182
			'label' => 'Customer website',
183
			'code' => 'customer.website',
184
			'internalcode' => 'mcus."www"',
185
			'type' => 'string',
186
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
187
		),
188
		'customer.longitude' => array(
189
			'label' => 'Customer longitude',
190
			'code' => 'customer.longitude',
191
			'internalcode' => 'mcus."longitude"',
192
			'type' => 'float',
193
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT,
194
		),
195
		'customer.latitude' => array(
196
			'label' => 'Customer latitude',
197
			'code' => 'customer.latitude',
198
			'internalcode' => 'mcus."latitude"',
199
			'type' => 'float',
200
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT,
201
		),
202
		'customer.birthday' => array(
203
			'label' => 'Customer birthday',
204
			'code' => 'customer.birthday',
205
			'internalcode' => 'mcus."date_of_birth"',
206
			'type' => 'date',
207
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
208
		),
209
		'customer.password'=> array(
210
			'label' => 'Customer password',
211
			'code' => 'customer.password',
212
			'internalcode' => 'mcus."password"',
213
			'type' => 'string',
214
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
215
		),
216
		'customer.status'=> array(
217
			'label' => 'Customer status',
218
			'code' => 'customer.status',
219
			'internalcode' => 'mcus."disable"',
220
			'type' => 'integer',
221
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_INT
222
		),
223
		'customer.dateverified'=> array(
224
			'label' => 'Customer verification date',
225
			'code' => 'customer.dateverified',
226
			'internalcode' => 'mcus."vdate"',
227
			'type' => 'date',
228
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
229
		),
230
		'customer.ctime'=> array(
231
			'label' => 'Customer creation time',
232
			'code' => 'customer.ctime',
233
			'internalcode' => 'mcus."crdate"',
234
			'type' => 'datetime',
235
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
236
		),
237
		'customer.mtime'=> array(
238
			'label' => 'Customer modification time',
239
			'code' => 'customer.mtime',
240
			'internalcode' => 'mcus."tstamp"',
241
			'type' => 'datetime',
242
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
243
		),
244
		// not available
245
		'customer.editor'=> array(
246
			'label' => 'Customer editor',
247
			'code' => 'customer.editor',
248
			'internalcode' => null,
249
			'type' => 'string',
250
			'internaltype' => \Aimeos\Base\DB\Statement\Base::PARAM_STR,
251
		),
252
		'customer:has' => array(
253
			'code' => 'customer:has()',
254
			'internalcode' => ':site AND :key AND mcusli."id"',
255
			'internaldeps' => ['LEFT JOIN "fe_users_list" AS mcusli ON ( mcusli."parentid" = mcus."uid" )'],
256
			'label' => 'Customer has list item, parameter(<domain>[,<list type>[,<reference ID>)]]',
257
			'type' => 'null',
258
			'internaltype' => 'null',
259
			'public' => false,
260
		),
261
		'customer:prop' => array(
262
			'code' => 'customer:prop()',
263
			'internalcode' => ':site AND :key AND mcuspr."id"',
264
			'internaldeps' => ['LEFT JOIN "fe_users_property" AS mcuspr ON ( mcuspr."parentid" = mcus."uid" )'],
265
			'label' => 'Customer has property item, parameter(<property type>[,<language code>[,<property value>]])',
266
			'type' => 'null',
267
			'internaltype' => 'null',
268
			'public' => false,
269
		),
270
	);
271
272
273
	private ?\Aimeos\MShop\Common\Helper\Password\Iface $helper = null;
274
	private array $plugins = [];
275
	private int $pid;
276
277
278
279
	/**
280
	 * Initializes a new customer manager object using the given context object.
281
	 *
282
	 * @param \Aimeos\MShop\ContextIface $context Context object with required objects
283
	 */
284
	public function __construct( \Aimeos\MShop\ContextIface $context )
285
	{
286
		parent::__construct( $context );
287
288
		$plugin = new \Aimeos\Base\Criteria\Plugin\T3Salutation();
289
		$this->plugins['customer.salutation'] = $plugin;
290
291
		$plugin = new \Aimeos\Base\Criteria\Plugin\T3Status();
292
		$this->plugins['customer.status'] = $plugin;
293
294
		$plugin = new \Aimeos\Base\Criteria\Plugin\T3Date();
295
		$this->plugins['customer.birthday'] = $plugin;
296
297
		$plugin = new \Aimeos\Base\Criteria\Plugin\T3Datetime();
298
		$this->plugins['customer.ctime'] = $plugin;
299
		$this->plugins['customer.mtime'] = $plugin;
300
301
		/** mshop/customer/manager/typo3/pid-default
302
		 * Page ID the customer records are assigned to
303
		 *
304
		 * In TYPO3, you can assign fe_user records to different sysfolders based
305
		 * on their page ID and for checking user credentials at login, the configured
306
		 * sysfolder is used. Thus, the page ID of the same sysfolder must be assigned
307
		 * to the user records so they are allowed to log in after they are created
308
		 * or modified by Aimeos.
309
		 *
310
		 * @param int TYPO3 page ID
311
		 * @since 2016.10
312
		 * @see mshop/customer/manager/group/typo3/pid-default
313
		 */
314
		$this->pid = $context->config()->get( 'mshop/customer/manager/typo3/pid-default', 0 );
315
316
317
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
318
		$level = $context->config()->get( 'mshop/customer/manager/sitemode', $level );
319
320
321
		$this->searchConfig['customer:has']['function'] = function( &$source, array $params ) use ( $level ) {
322
323
			$keys = [];
324
325
			foreach( (array) ( $params[1] ?? '' ) as $type ) {
326
				foreach( (array) ( $params[2] ?? '' ) as $id ) {
327
					$keys[] = $params[0] . '|' . ( $type ? $type . '|' : '' ) . $id;
328
				}
329
			}
330
331
			$sitestr = $this->siteString( 'mcusli."siteid"', $level );
332
			$keystr = $this->toExpression( 'mcusli."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
333
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
334
335
			return $params;
336
		};
337
338
339
		$this->searchConfig['customer:prop']['function'] = function( &$source, array $params ) use ( $level ) {
340
341
			$keys = [];
342
			$langs = array_key_exists( 1, $params ) ? ( $params[1] ?? 'null' ) : '';
343
344
			foreach( (array) $langs as $lang ) {
345
				foreach( (array) ( $params[2] ?? '' ) as $val ) {
346
					$keys[] = substr( $params[0] . '|' . ( $lang === null ? 'null|' : ( $lang ? $lang . '|' : '' ) ) . $val, 0, 255 );
347
				}
348
			}
349
350
			$sitestr = $this->siteString( 'mcuspr."siteid"', $level );
351
			$keystr = $this->toExpression( 'mcuspr."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
352
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
353
354
			return $params;
355
		};
356
	}
357
358
359
	/**
360
	 * Counts the number items that are available for the values of the given key.
361
	 *
362
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria
363
	 * @param array|string $key Search key or list of key to aggregate items for
364
	 * @param string|null $value Search key for aggregating the value column
365
	 * @param string|null $type Type of the aggregation, empty string for count or "sum" or "avg" (average)
366
	 * @return \Aimeos\Map List of the search keys as key and the number of counted items as value
367
	 */
368
	public function aggregate( \Aimeos\Base\Criteria\Iface $search, $key, string $value = null, string $type = null ) : \Aimeos\Map
369
	{
370
		/** mshop/customer/manager/typo3//aggregate/mysql
371
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
372
		 *
373
		 * @see mshop/customer/manager/typo3//aggregate/ansi
374
		 */
375
376
		/** mshop/customer/manager/typo3//aggregate/ansi
377
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
378
		 *
379
		 * Groups all records by the values in the key column and counts their
380
		 * occurence. The matched records can be limited by the given criteria
381
		 * from the customer database. The records must be from one of the sites
382
		 * that are configured via the context item. If the current site is part
383
		 * of a tree of sites, the statement can count all records from the
384
		 * current site and the complete sub-tree of sites.
385
		 *
386
		 * As the records can normally be limited by criteria from sub-managers,
387
		 * their tables must be joined in the SQL context. This is done by
388
		 * using the "internaldeps" property from the definition of the ID
389
		 * column of the sub-managers. These internal dependencies specify
390
		 * the JOIN between the tables and the used columns for joining. The
391
		 * ":joins" placeholder is then replaced by the JOIN strings from
392
		 * the sub-managers.
393
		 *
394
		 * To limit the records matched, conditions can be added to the given
395
		 * criteria object. It can contain comparisons like column names that
396
		 * must match specific values which can be combined by AND, OR or NOT
397
		 * operators. The resulting string of SQL conditions replaces the
398
		 * ":cond" placeholder before the statement is sent to the database
399
		 * server.
400
		 *
401
		 * This statement doesn't return any records. Instead, it returns pairs
402
		 * of the different values found in the key column together with the
403
		 * number of records that have been found for that key values.
404
		 *
405
		 * The SQL statement should conform to the ANSI standard to be
406
		 * compatible with most relational database systems. This also
407
		 * includes using double quotes for table and column names.
408
		 *
409
		 * @param string SQL statement for aggregating customer items
410
		 * @since 2021.04
411
		 * @category Developer
412
		 * @see mshop/customer/manager/typo3//insert/ansi
413
		 * @see mshop/customer/manager/typo3//update/ansi
414
		 * @see mshop/customer/manager/typo3//newid/ansi
415
		 * @see mshop/customer/manager/typo3//delete/ansi
416
		 * @see mshop/customer/manager/typo3//search/ansi
417
		 * @see mshop/customer/manager/typo3//count/ansi
418
		 */
419
420
		$cfgkey = 'mshop/customer/manager/typo3/aggregate' . $type;
421
		return $this->aggregateBase( $search, $key, $cfgkey, ['customer'], $value );
422
	}
423
424
425
	/**
426
	 * Removes old entries from the storage.
427
	 *
428
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
429
	 * @return \Aimeos\MShop\Common\Manager\Iface Same object for fluent interface
430
	 */
431
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
432
	{
433
		$path = 'mshop/customer/manager/submanagers';
434
		$default = ['address', 'group', 'lists', 'property'];
435
436
		foreach( $this->context()->config()->get( $path, $default ) as $domain ) {
437
			$this->object()->getSubManager( $domain )->clear( $siteids );
438
		}
439
440
		return $this->clearBase( $siteids, 'mshop/customer/manager/typo3/clear' );
441
	}
442
443
444
	/**
445
	 * Creates a new empty item instance
446
	 *
447
	 * @param array $values Values the item should be initialized with
448
	 * @return \Aimeos\MShop\Customer\Item\Iface New site item object
449
	 */
450
	public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
451
	{
452
		$values['customer.siteid'] = $values['customer.siteid'] ?? $this->context()->locale()->getSiteId();
453
		return $this->createItemBase( $values );
454
	}
455
456
457
	/**
458
	 * Removes multiple items.
459
	 *
460
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
461
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
462
	 */
463
	public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
464
	{
465
		$path = 'mshop/customer/manager/typo3/delete';
466
		return $this->deleteItemsBase( $itemIds, $path, true, 'uid' )->deleteRefItems( $itemIds );
467
	}
468
469
470
	/**
471
	 * Returns the list attributes that can be used for searching.
472
	 *
473
	 * @param bool $withsub Return also attributes of sub-managers if true
474
	 * @return array List of attribute items implementing \Aimeos\Base\Criteria\Attribute\Iface
475
	 */
476
	public function getSearchAttributes( bool $withsub = true ) : array
477
	{
478
		$path = 'mshop/customer/manager/submanagers';
479
		return $this->getSearchAttributesBase( $this->searchConfig, $path, ['address'], $withsub );
480
	}
481
482
483
	/**
484
	 * Saves a customer item object.
485
	 *
486
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item object
487
	 * @param bool $fetch True if the new ID should be returned in the item
488
	 * @return \Aimeos\MShop\Customer\Item\Iface $item Updated item including the generated ID
489
	 */
490
	protected function saveItem( \Aimeos\MShop\Customer\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Customer\Item\Iface
491
	{
492
		if( !$item->isModified() )
493
		{
494
			$item = $this->savePropertyItems( $item, 'customer' );
495
			$item = $this->saveAddressItems( $item, 'customer' );
496
			return $this->saveListItems( $item, 'customer' );
497
		}
498
499
		$context = $this->context();
500
		$conn = $context->db( $this->getResourceName() );
501
502
			$id = $item->getId();
503
			$billingAddress = $item->getPaymentAddress();
504
			$columns = $this->object()->getSaveAttributes();
505
506
			if( $id === null )
507
			{
508
				/** mshop/customer/manager/typo3/insert
509
				 * Inserts a new customer record into the database table
510
				 *
511
				 * Items with no ID yet (i.e. the ID is NULL) will be created in
512
				 * the database and the newly created ID retrieved afterwards
513
				 * using the "newid" SQL statement.
514
				 *
515
				 * The SQL statement must be a string suitable for being used as
516
				 * prepared statement. It must include question marks for binding
517
				 * the values from the customer item to the statement before they are
518
				 * sent to the database server. The number of question marks must
519
				 * be the same as the number of columns listed in the INSERT
520
				 * statement. The order of the columns must correspond to the
521
				 * order in the save() method, so the correct values are
522
				 * bound to the columns.
523
				 *
524
				 * The SQL statement should conform to the ANSI standard to be
525
				 * compatible with most relational database systems. This also
526
				 * includes using double quotes for table and column names.
527
				 *
528
				 * @param string SQL statement for inserting records
529
				 * @since 2014.03
530
				 * @category Developer
531
				 * @see mshop/customer/manager/typo3/update
532
				 * @see mshop/customer/manager/typo3/newid
533
				 * @see mshop/customer/manager/typo3/delete
534
				 * @see mshop/customer/manager/typo3/search
535
				 * @see mshop/customer/manager/typo3/count
536
				 */
537
				$path = 'mshop/customer/manager/typo3/insert';
538
				$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

538
				$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
539
			}
540
			else
541
			{
542
				/** mshop/customer/manager/typo3/update
543
				 * Updates an existing customer record in the database
544
				 *
545
				 * Items which already have an ID (i.e. the ID is not NULL) will
546
				 * be updated in the database.
547
				 *
548
				 * The SQL statement must be a string suitable for being used as
549
				 * prepared statement. It must include question marks for binding
550
				 * the values from the customer item to the statement before they are
551
				 * sent to the database server. The order of the columns must
552
				 * correspond to the order in the save() method, so the
553
				 * correct values are bound to the columns.
554
				 *
555
				 * The SQL statement should conform to the ANSI standard to be
556
				 * compatible with most relational database systems. This also
557
				 * includes using double quotes for table and column names.
558
				 *
559
				 * @param string SQL statement for updating records
560
				 * @since 2014.03
561
				 * @category Developer
562
				 * @see mshop/customer/manager/typo3/insert
563
				 * @see mshop/customer/manager/typo3/newid
564
				 * @see mshop/customer/manager/typo3/delete
565
				 * @see mshop/customer/manager/typo3/search
566
				 * @see mshop/customer/manager/typo3/count
567
				 */
568
				$path = 'mshop/customer/manager/typo3/update';
569
				$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
570
			}
571
572
			$address = $billingAddress->getAddress1();
573
574
			if( ( $part = $billingAddress->getAddress2() ) != '' ) {
575
				$address .= ' ' . $part;
576
			}
577
578
			if( ( $part = $billingAddress->getAddress3() ) != '' ) {
579
				$address .= ' ' . $part;
580
			}
581
582
			$idx = 1;
583
			$stmt = $this->getCachedStatement( $conn, $path, $sql );
584
585
			foreach( $columns as $name => $entry ) {
586
				$stmt->bind( $idx++, $item->get( $name ), $entry->getInternalType() );
0 ignored issues
show
Bug introduced by
It seems like $entry->getInternalType() can also be of type string; however, parameter $type of Aimeos\Base\DB\Statement\Iface::bind() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

586
				$stmt->bind( $idx++, $item->get( $name ), /** @scrutinizer ignore-type */ $entry->getInternalType() );
Loading history...
587
			}
588
589
			// TYPO3 fe_users.static_info_country is a three letter ISO code instead a two letter one
590
			$stmt->bind( $idx++, $item->getLabel() );
591
			$stmt->bind( $idx++, $item->getCode() );
592
			$stmt->bind( $idx++, $this->plugins['customer.salutation']->translate( $billingAddress->getSalutation() ), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
593
			$stmt->bind( $idx++, $billingAddress->getCompany() );
594
			$stmt->bind( $idx++, $billingAddress->getVatID() );
595
			$stmt->bind( $idx++, $billingAddress->getTitle() );
596
			$stmt->bind( $idx++, $billingAddress->getFirstname() );
597
			$stmt->bind( $idx++, $billingAddress->getLastname() );
598
			$stmt->bind( $idx++, $address );
599
			$stmt->bind( $idx++, $billingAddress->getPostal() );
600
			$stmt->bind( $idx++, $billingAddress->getCity() );
601
			$stmt->bind( $idx++, $billingAddress->getState() );
602
			$stmt->bind( $idx++, $billingAddress->getLanguageId() );
603
			$stmt->bind( $idx++, $billingAddress->getTelephone() );
604
			$stmt->bind( $idx++, $billingAddress->getMobile() );
605
			$stmt->bind( $idx++, $billingAddress->getEmail() );
606
			$stmt->bind( $idx++, $billingAddress->getTelefax() );
607
			$stmt->bind( $idx++, $billingAddress->getWebsite() );
608
			$stmt->bind( $idx++, $billingAddress->getLongitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
609
			$stmt->bind( $idx++, $billingAddress->getLatitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
610
			$stmt->bind( $idx++, $this->plugins['customer.birthday']->translate( $billingAddress->getBirthday() ), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
611
			$stmt->bind( $idx++, $this->plugins['customer.status']->translate( $item->getStatus() ), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
612
			$stmt->bind( $idx++, $item->getPassword() );
613
			$stmt->bind( $idx++, time(), \Aimeos\Base\DB\Statement\Base::PARAM_INT ); // Modification time
614
			$stmt->bind( $idx++, $billingAddress->getCountryId() );
615
			$stmt->bind( $idx++, implode( ',', $item->getGroups() ) );
616
			$stmt->bind( $idx++, $this->pid, \Aimeos\Base\DB\Statement\Base::PARAM_INT ); // TYPO3 PID value
617
618
			if( $id !== null ) {
619
				$stmt->bind( $idx++, $context->locale()->getSiteId() . '%' );
620
				$stmt->bind( $idx, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
621
				$item->setId( $id );
622
			} else {
623
				$stmt->bind( $idx++, $this->siteId( $item->getSiteId(), \Aimeos\MShop\Locale\Manager\Base::SITE_SUBTREE ) );
624
				$stmt->bind( $idx, time(), \Aimeos\Base\DB\Statement\Base::PARAM_INT ); // Creation time
625
			}
626
627
			$stmt->execute()->finish();
628
629
			if( $id === null && $fetch === true )
630
			{
631
				/** mshop/customer/manager/typo3/newid
632
				 * Retrieves the ID generated by the database when inserting a new record
633
				 *
634
				 * As soon as a new record is inserted into the database table,
635
				 * the database server generates a new and unique identifier for
636
				 * that record. This ID can be used for retrieving, updating and
637
				 * deleting that specific record from the table again.
638
				 *
639
				 * For MySQL:
640
				 *  SELECT LAST_INSERT_ID()
641
				 * For PostgreSQL:
642
				 *  SELECT currval('seq_mcus_id')
643
				 * For SQL Server:
644
				 *  SELECT SCOPE_IDENTITY()
645
				 * For Oracle:
646
				 *  SELECT "seq_mcus_id".CURRVAL FROM DUAL
647
				 *
648
				 * There's no way to retrive the new ID by a SQL statements that
649
				 * fits for most database servers as they implement their own
650
				 * specific way.
651
				 *
652
				 * @param string SQL statement for retrieving the last inserted record ID
653
				 * @since 2014.03
654
				 * @category Developer
655
				 * @see mshop/customer/manager/typo3/insert
656
				 * @see mshop/customer/manager/typo3/update
657
				 * @see mshop/customer/manager/typo3/delete
658
				 * @see mshop/customer/manager/typo3/search
659
				 * @see mshop/customer/manager/typo3/count
660
				 */
661
				$path = 'mshop/customer/manager/typo3/newid';
662
				$item->setId( $this->newId( $conn, $path ) );
663
			}
664
665
		$item = $this->savePropertyItems( $item, 'customer' );
666
		$item = $this->saveAddressItems( $item, 'customer' );
667
		return $this->saveListItems( $item, 'customer' );
668
	}
669
670
671
	/**
672
	 * Returns the item objects matched by the given search criteria.
673
	 *
674
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria object
675
	 * @param int|null &$total Number of items that are available in total
676
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Customer\Item\Iface
677
	 * @throws \Aimeos\MShop\Customer\Exception If creating items failed
678
	 */
679
	public function search( \Aimeos\Base\Criteria\Iface $search, array $ref = [], int &$total = null ) : \Aimeos\Map
680
	{
681
		$conn = $this->context()->db( $this->getResourceName() );
682
		$map = [];
683
684
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
685
		$level = $this->context()->config()->get( 'mshop/customer/manager/sitemode', $level );
686
687
		$cfgPathSearch = 'mshop/customer/manager/typo3/search';
688
		$cfgPathCount = 'mshop/customer/manager/typo3/count';
689
		$required = array( 'customer' );
690
691
		$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level, $this->plugins );
692
693
		while( ( $row = $results->fetch() ) !== null ) {
694
			$map[(string) $row['customer.id']] = $row;
695
		}
696
697
698
		$addrItems = [];
699
		if( in_array( 'customer/address', $ref, true ) ) {
700
			$addrItems = $this->getAddressItems( array_keys( $map ), 'customer' );
701
		}
702
703
		$propItems = []; $name = 'customer/property';
704
		if( isset( $ref[$name] ) || in_array( $name, $ref, true ) )
705
		{
706
			$propTypes = isset( $ref[$name] ) && is_array( $ref[$name] ) ? $ref[$name] : null;
707
			$propItems = $this->getPropertyItems( array_keys( $map ), 'customer', $propTypes );
708
		}
709
710
		return $this->buildItems( $map, $ref, 'customer', $addrItems, $propItems );
711
	}
712
713
714
	/**
715
	 * Returns a new manager for customer extensions
716
	 *
717
	 * @param string $manager Name of the sub manager type in lower case
718
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
719
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g stock, tags, locations, etc.
720
	 */
721
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
722
	{
723
		return $this->getSubManagerBase( 'customer', $manager, ( $name === null ? 'Typo3' : $name ) );
724
	}
725
726
727
	/**
728
	 * Creates a new customer item.
729
	 *
730
	 * @param array $values List of attributes for customer item
731
	 * @param \Aimeos\MShop\Common\Lists\Item\Iface[] $listItems List of list items
732
	 * @param \Aimeos\MShop\Common\Item\Iface[] $refItems List of referenced items
733
	 * @param \Aimeos\MShop\Common\Item\Address\Iface[] $addrItems List of referenced address items
734
	 * @param \Aimeos\MShop\Common\Item\Property\Iface[] $propItems List of property items
735
	 * @return \Aimeos\MShop\Customer\Item\Iface New customer item
736
	 */
737
	protected function createItemBase( array $values = [], array $listItems = [], array $refItems = [],
738
		array $addrItems = [], array $propItems = [] ) : \Aimeos\MShop\Common\Item\Iface
739
	{
740
		$helper = $this->getPasswordHelper();
741
		$values = $this->transform( $values );
742
743
		$address = new \Aimeos\MShop\Common\Item\Address\Standard( 'customer.', $values );
744
745
		return new \Aimeos\MShop\Customer\Item\Standard(
746
			$address, $values, $listItems, $refItems, $addrItems, $propItems, $helper
747
		);
748
	}
749
750
751
	/**
752
	 * Returns a password helper object based on the configuration.
753
	 *
754
	 * @return \Aimeos\MShop\Common\Helper\Password\Iface Password helper object
755
	 * @throws \Aimeos\MShop\Exception If the name is invalid or the class isn't found
756
	 */
757
	protected function getPasswordHelper() : \Aimeos\MShop\Common\Helper\Password\Iface
758
	{
759
		if( $this->helper === null ) {
760
			$this->helper = new \Aimeos\MShop\Common\Helper\Password\Typo3( ['object' => $this->context()->password()] );
761
		}
762
763
		return $this->helper;
764
	}
765
766
767
	/**
768
	 * Transforms the application specific values to Aimeos standard values.
769
	 *
770
	 * @param array $values Associative list of key/value pairs from the storage
771
	 * @return array Associative list of key/value pairs with standard Aimeos values
772
	 */
773
	protected function transform( array $values ) : array
774
	{
775
		if( array_key_exists( 'customer.birthday', $values ) ) {
776
			$values['customer.birthday'] = $this->plugins['customer.birthday']->reverse( $values['customer.birthday'] );
777
		}
778
779
		if( array_key_exists( 'customer.salutation', $values ) ) {
780
			$values['customer.salutation'] = $this->plugins['customer.salutation']->reverse( $values['customer.salutation'] );
781
		}
782
783
		if( array_key_exists( 'customer.status', $values ) ) {
784
			$values['customer.status'] = $this->plugins['customer.status']->reverse( $values['customer.status'] );
785
		}
786
787
		if( array_key_exists( 'customer.mtime', $values ) ) {
788
			$values['customer.mtime'] = $this->plugins['customer.mtime']->reverse( $values['customer.mtime'] );
789
		}
790
791
		if( array_key_exists( 'customer.ctime', $values ) ) {
792
			$values['customer.ctime'] = $this->plugins['customer.ctime']->reverse( $values['customer.ctime'] );
793
		}
794
795
		if( array_key_exists( 'customer.groups', $values ) && $values['customer.groups'] !== '' ) {
796
			$values['customer.groups'] = explode( ',', $values['customer.groups'] );
797
		}
798
799
		return $values;
800
	}
801
}
802