Completed
Push — master ( 185f90...87c64b )
by Aimeos
01:41
created

Typo3::saveItem()   F

Complexity

Conditions 10
Paths 350

Size

Total Lines 186

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 186
rs 3.9666
c 0
b 0
f 0
cc 10
nc 350
nop 2

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-2017
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 $searchConfig = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
25
		// customer.siteid is only for informational purpuse, not for filtering
26
		'customer.id' => array(
27
			'label' => 'Customer ID',
28
			'code' => 'customer.id',
29
			'internalcode' => 't3feu."uid"',
30
			'type' => 'integer',
31
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
32
			'public' => false,
33
		),
34
		'customer.code' => array(
35
			'label' => 'Customer username',
36
			'code' => 'customer.code',
37
			'internalcode' => 't3feu."username"',
38
			'type' => 'string',
39
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR
40
		),
41
		'customer.label' => array(
42
			'label' => 'Customer name',
43
			'code' => 'customer.label',
44
			'internalcode' => 't3feu."name"',
45
			'type' => 'string',
46
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR
47
		),
48
		'customer.salutation' => array(
49
			'label' => 'Customer salutation',
50
			'code' => 'customer.salutation',
51
			'internalcode' => 't3feu."gender"',
52
			'type' => 'string',
53
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
54
		),
55
		'customer.company'=> array(
56
			'label' => 'Customer company',
57
			'code' => 'customer.company',
58
			'internalcode' => 't3feu."company"',
59
			'type' => 'string',
60
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
61
		),
62
		'customer.vatid'=> array(
63
			'label' => 'Customer VAT ID',
64
			'code' => 'customer.vatid',
65
			'internalcode' => 't3feu."vatid"',
66
			'type' => 'string',
67
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
68
		),
69
		'customer.title' => array(
70
			'label' => 'Customer title',
71
			'code' => 'customer.title',
72
			'internalcode' => 't3feu."title"',
73
			'type' => 'string',
74
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
75
		),
76
		'customer.firstname' => array(
77
			'label' => 'Customer firstname',
78
			'code' => 'customer.firstname',
79
			'internalcode' => 't3feu."first_name"',
80
			'type' => 'string',
81
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
82
		),
83
		'customer.lastname' => array(
84
			'label' => 'Customer lastname',
85
			'code' => 'customer.lastname',
86
			'internalcode' => 't3feu."last_name"',
87
			'type' => 'string',
88
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
89
		),
90
		'customer.address1' => array(
91
			'label' => 'Customer address part one',
92
			'code' => 'customer.address1',
93
			'internalcode' => 't3feu."address"',
94
			'type' => 'string',
95
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
96
		),
97
		'customer.address2' => array(
98
			'label' => 'Customer address part two',
99
			'code' => 'customer.address2',
100
			'internalcode' => 't3feu."address"',
101
			'type' => 'string',
102
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
103
		),
104
		'customer.address3' => array(
105
			'label' => 'Customer address part three',
106
			'code' => 'customer.address3',
107
			'internalcode' => 't3feu."address"',
108
			'type' => 'string',
109
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
110
		),
111
		'customer.postal' => array(
112
			'label' => 'Customer postal',
113
			'code' => 'customer.postal',
114
			'internalcode' => 't3feu."zip"',
115
			'type' => 'string',
116
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
117
		),
118
		'customer.city' => array(
119
			'label' => 'Customer city',
120
			'code' => 'customer.city',
121
			'internalcode' => 't3feu."city"',
122
			'type' => 'string',
123
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
124
		),
125
		'customer.state' => array(
126
			'label' => 'Customer state',
127
			'code' => 'customer.state',
128
			'internalcode' => 't3feu."zone"',
129
			'type' => 'string',
130
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
131
		),
132
		'customer.languageid' => array(
133
			'label' => 'Customer language',
134
			'code' => 'customer.languageid',
135
			'internalcode' => 't3feu."language"',
136
			'type' => 'string',
137
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
138
		),
139
		'customer.countryid' => array(
140
			'label' => 'Customer country',
141
			'code' => 'customer.countryid',
142
			'internalcode' => 'tsc."cn_iso_2"',
143
			'type' => 'string',
144
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
145
		),
146
		'customer.telephone' => array(
147
			'label' => 'Customer telephone',
148
			'code' => 'customer.telephone',
149
			'internalcode' => 't3feu."telephone"',
150
			'type' => 'string',
151
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
152
		),
153
		'customer.email' => array(
154
			'label' => 'Customer email',
155
			'code' => 'customer.email',
156
			'internalcode' => 't3feu."email"',
157
			'type' => 'string',
158
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
159
		),
160
		'customer.telefax' => array(
161
			'label' => 'Customer telefax',
162
			'code' => 'customer.telefax',
163
			'internalcode' => 't3feu."fax"',
164
			'type' => 'string',
165
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
166
		),
167
		'customer.website' => array(
168
			'label' => 'Customer website',
169
			'code' => 'customer.website',
170
			'internalcode' => 't3feu."www"',
171
			'type' => 'string',
172
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
173
		),
174
		'customer.longitude' => array(
175
			'label' => 'Customer longitude',
176
			'code' => 'customer.longitude',
177
			'internalcode' => 't3feu."longitude"',
178
			'type' => 'string',
179
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
180
		),
181
		'customer.latitude' => array(
182
			'label' => 'Customer latitude',
183
			'code' => 'customer.latitude',
184
			'internalcode' => 't3feu."latitude"',
185
			'type' => 'string',
186
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
187
		),
188
		'customer.birthday' => array(
189
			'label' => 'Customer birthday',
190
			'code' => 'customer.birthday',
191
			'internalcode' => 't3feu."date_of_birth"',
192
			'type' => 'string',
193
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
194
		),
195
		'customer.password'=> array(
196
			'label' => 'Customer password',
197
			'code' => 'customer.password',
198
			'internalcode' => 't3feu."password"',
199
			'type' => 'string',
200
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
201
		),
202
		'customer.status'=> array(
203
			'label' => 'Customer status',
204
			'code' => 'customer.status',
205
			'internalcode' => 't3feu."disable"',
206
			'type' => 'integer',
207
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT
208
		),
209
		'customer.dateverified'=> array(
210
			'label' => 'Customer verification date',
211
			'code' => 'customer.dateverified',
212
			'internalcode' => 't3feu."vdate"',
213
			'type' => 'date',
214
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
215
		),
216
		'customer.ctime'=> array(
217
			'label' => 'Customer creation time',
218
			'code' => 'customer.ctime',
219
			'internalcode' => 't3feu."crdate"',
220
			'type' => 'datetime',
221
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
222
		),
223
		'customer.mtime'=> array(
224
			'label' => 'Customer modification time',
225
			'code' => 'customer.mtime',
226
			'internalcode' => 't3feu."tstamp"',
227
			'type' => 'datetime',
228
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
229
		),
230
		// not available
231
		'customer.editor'=> array(
232
			'label'=>'Customer editor',
233
			'code'=>'customer.editor',
234
			'internalcode'=>'1',
235
			'type'=> 'string',
236
			'internaltype'=> \Aimeos\MW\DB\Statement\Base::PARAM_STR,
237
		),
238
	);
239
240
	private $plugins = [];
241
	private $reverse = [];
242
	private $helper;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
243
	private $pid;
244
245
246
247
	/**
248
	 * Initializes a new customer manager object using the given context object.
249
	 *
250
	 * @param \Aimeos\MShop\Context\Iface $context Context object with required objects
251
	 */
252
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
253
	{
254
		parent::__construct( $context );
255
256
		$plugin = new \Aimeos\MW\Criteria\Plugin\T3Salutation();
257
		$this->plugins['customer.salutation'] = $this->reverse['gender'] = $plugin;
258
259
		$plugin = new \Aimeos\MW\Criteria\Plugin\T3Status();
260
		$this->plugins['customer.status'] = $this->reverse['disable'] = $plugin;
261
262
		$plugin = new \Aimeos\MW\Criteria\Plugin\T3Date();
263
		$this->plugins['customer.birthday'] = $this->reverse['date_of_birth'] = $plugin;
264
265
		$plugin = new \Aimeos\MW\Criteria\Plugin\T3Datetime();
266
		$this->plugins['customer.ctime'] = $this->reverse['crdate'] = $plugin;
267
		$this->plugins['customer.mtime'] = $this->reverse['tstamp'] = $plugin;
268
269
		$this->pid = $context->getConfig()->get( 'mshop/customer/manager/typo3/pid-default', 0 );
270
	}
271
272
273
	/**
274
	 * Returns the list attributes that can be used for searching.
275
	 *
276
	 * @param boolean $withsub Return also attributes of sub-managers if true
277
	 * @return array List of attribute items implementing \Aimeos\MW\Criteria\Attribute\Iface
278
	 */
279
	public function getSearchAttributes( $withsub = true )
280
	{
281
		$path = 'mshop/customer/manager/submanagers';
282
283
		return $this->getSearchAttributesBase( $this->searchConfig, $path, array( 'address', 'lists' ), $withsub );
284
	}
285
286
287
	/**
288
	 * Removes old entries from the storage.
289
	 *
290
	 * @param array $siteids List of IDs for sites whose entries should be deleted
291
	 */
292
	public function cleanup( array $siteids )
293
	{
294
		$path = 'mshop/customer/manager/submanagers';
295
		foreach( $this->getContext()->getConfig()->get( $path, array( 'address', 'lists' ) ) as $domain ) {
296
			$this->getObject()->getSubManager( $domain )->cleanup( $siteids );
297
		}
298
	}
299
300
301
	/**
302
	 * Instantiates a new customer item object.
303
	 *
304
	 * @return \Aimeos\MShop\Customer\Item\Iface New customer item object
305
	 */
306
	public function createItem()
307
	{
308
		$values = ['customer.siteid' => $this->getContext()->getLocale()->getSiteId(), 'typo3.pageid' => $this->pid];
309
		return $this->createItemBase( $values );
310
	}
311
312
313
	/**
314
	 * Deletes a customer item object from the permanent storage.
315
	 *
316
	 * @param array $ids List of customer IDs
317
	 */
318
	public function deleteItems( array $ids )
319
	{
320
		$path = 'mshop/customer/manager/typo3/delete';
321
		$this->deleteItemsBase( $ids, $path, false, 'uid' );
322
	}
323
324
325
	/**
326
	 * Saves a customer item object.
327
	 *
328
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item object
329
	 * @param boolean $fetch True if the new ID should be returned in the item
330
	 * @return \Aimeos\MShop\Common\Item\Iface $item Updated item including the generated ID
331
	 */
332
	public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
333
	{
334
		$iface = '\\Aimeos\\MShop\\Customer\\Item\\Iface';
335
		if( !( $item instanceof $iface ) ) {
336
			throw new \Aimeos\MShop\Customer\Exception( sprintf( 'Object is not of required type "%1$s"', $iface ) );
337
		}
338
339
		if( !$item->isModified() )
340
		{
341
			$item = $this->savePropertyItems( $item, 'customer' );
0 ignored issues
show
Documentation Bug introduced by
The method savePropertyItems does not exist on object<Aimeos\MShop\Customer\Manager\Typo3>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
342
			$item = $this->saveAddressItems( $item, 'customer' );
0 ignored issues
show
Documentation Bug introduced by
The method saveAddressItems does not exist on object<Aimeos\MShop\Customer\Manager\Typo3>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
343
			return $this->saveRefItems( $item, 'customer' );
344
		}
345
346
		$context = $this->getContext();
347
		$dbm = $context->getDatabaseManager();
348
		$dbname = $this->getResourceName();
349
		$conn = $dbm->acquire( $dbname );
350
351
		try
352
		{
353
			$id = $item->getId();
354
			$billingAddress = $item->getPaymentAddress();
355
356
			if( $id === null )
357
			{
358
				/** mshop/customer/manager/typo3/insert
359
				 * Inserts a new customer record into the database table
360
				 *
361
				 * Items with no ID yet (i.e. the ID is NULL) will be created in
362
				 * the database and the newly created ID retrieved afterwards
363
				 * using the "newid" SQL statement.
364
				 *
365
				 * The SQL statement must be a string suitable for being used as
366
				 * prepared statement. It must include question marks for binding
367
				 * the values from the customer item to the statement before they are
368
				 * sent to the database server. The number of question marks must
369
				 * be the same as the number of columns listed in the INSERT
370
				 * statement. The order of the columns must correspond to the
371
				 * order in the saveItems() method, so the correct values are
372
				 * bound to the columns.
373
				 *
374
				 * The SQL statement should conform to the ANSI standard to be
375
				 * compatible with most relational database systems. This also
376
				 * includes using double quotes for table and column names.
377
				 *
378
				 * @param string SQL statement for inserting records
379
				 * @since 2014.03
380
				 * @category Developer
381
				 * @see mshop/customer/manager/typo3/update
382
				 * @see mshop/customer/manager/typo3/newid
383
				 * @see mshop/customer/manager/typo3/delete
384
				 * @see mshop/customer/manager/typo3/search
385
				 * @see mshop/customer/manager/typo3/count
386
				 */
387
				$path = 'mshop/customer/manager/typo3/insert';
388
			}
389
			else
390
			{
391
				/** mshop/customer/manager/typo3/update
392
				 * Updates an existing customer record in the database
393
				 *
394
				 * Items which already have an ID (i.e. the ID is not NULL) will
395
				 * be updated in the database.
396
				 *
397
				 * The SQL statement must be a string suitable for being used as
398
				 * prepared statement. It must include question marks for binding
399
				 * the values from the customer item to the statement before they are
400
				 * sent to the database server. The order of the columns must
401
				 * correspond to the order in the saveItems() method, so the
402
				 * correct values are bound to the columns.
403
				 *
404
				 * The SQL statement should conform to the ANSI standard to be
405
				 * compatible with most relational database systems. This also
406
				 * includes using double quotes for table and column names.
407
				 *
408
				 * @param string SQL statement for updating records
409
				 * @since 2014.03
410
				 * @category Developer
411
				 * @see mshop/customer/manager/typo3/insert
412
				 * @see mshop/customer/manager/typo3/newid
413
				 * @see mshop/customer/manager/typo3/delete
414
				 * @see mshop/customer/manager/typo3/search
415
				 * @see mshop/customer/manager/typo3/count
416
				 */
417
				$path = 'mshop/customer/manager/typo3/update';
418
			}
419
420
			$stmt = $this->getCachedStatement( $conn, $path );
421
422
			$address = $billingAddress->getAddress1();
423
424
			if( ( $part = $billingAddress->getAddress2() ) != '' ) {
425
				$address .= ' ' . $part;
426
			}
427
428
			if( ( $part = $billingAddress->getAddress3() ) != '' ) {
429
				$address .= ' ' . $part;
430
			}
431
432
			// TYPO3 fe_users.static_info_country is a three letter ISO code instead a two letter one
433
			$stmt->bind( 1, $context->getLocale()->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
434
			$stmt->bind( 2, $item->getLabel() );
435
			$stmt->bind( 3, $item->getCode() );
436
			$stmt->bind( 4, $this->plugins['customer.salutation']->translate( $billingAddress->getSalutation() ), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
437
			$stmt->bind( 5, $billingAddress->getCompany() );
438
			$stmt->bind( 6, $billingAddress->getVatID() );
439
			$stmt->bind( 7, $billingAddress->getTitle() );
440
			$stmt->bind( 8, $billingAddress->getFirstname() );
441
			$stmt->bind( 9, $billingAddress->getLastname() );
442
			$stmt->bind( 10, $address );
443
			$stmt->bind( 11, $billingAddress->getPostal() );
444
			$stmt->bind( 12, $billingAddress->getCity() );
445
			$stmt->bind( 13, $billingAddress->getState() );
446
			$stmt->bind( 14, $billingAddress->getLanguageId() );
447
			$stmt->bind( 15, $billingAddress->getTelephone() );
448
			$stmt->bind( 16, $billingAddress->getEmail() );
449
			$stmt->bind( 17, $billingAddress->getTelefax() );
450
			$stmt->bind( 18, $billingAddress->getWebsite() );
451
			$stmt->bind( 19, $billingAddress->getLongitude() );
452
			$stmt->bind( 20, $billingAddress->getLatitude() );
453
			$stmt->bind( 21, $this->plugins['customer.birthday']->translate( $item->getBirthday() ), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
454
			$stmt->bind( 22, $this->plugins['customer.status']->translate( $item->getStatus() ), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
455
			$stmt->bind( 23, $item->getPassword() );
456
			$stmt->bind( 24, time(), \Aimeos\MW\DB\Statement\Base::PARAM_INT ); // Modification time
457
			$stmt->bind( 25, $billingAddress->getCountryId() );
458
			$stmt->bind( 26, implode( ',', $item->getGroups() ) );
459
			$stmt->bind( 27, $item->getPageId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT ); // TYPO3 PID value
460
461
			if( $id !== null ) {
462
				$stmt->bind( 28, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
463
				$item->setId( $id );
464
			} else {
465
				$stmt->bind( 28, time(), \Aimeos\MW\DB\Statement\Base::PARAM_INT ); // Creation time
466
			}
467
468
			$stmt->execute()->finish();
469
470
			if( $id === null && $fetch === true )
471
			{
472
				/** mshop/customer/manager/typo3/newid
473
				 * Retrieves the ID generated by the database when inserting a new record
474
				 *
475
				 * As soon as a new record is inserted into the database table,
476
				 * the database server generates a new and unique identifier for
477
				 * that record. This ID can be used for retrieving, updating and
478
				 * deleting that specific record from the table again.
479
				 *
480
				 * For MySQL:
481
				 *  SELECT LAST_INSERT_ID()
482
				 * For PostgreSQL:
483
				 *  SELECT currval('seq_mcus_id')
484
				 * For SQL Server:
485
				 *  SELECT SCOPE_IDENTITY()
486
				 * For Oracle:
487
				 *  SELECT "seq_mcus_id".CURRVAL FROM DUAL
488
				 *
489
				 * There's no way to retrive the new ID by a SQL statements that
490
				 * fits for most database servers as they implement their own
491
				 * specific way.
492
				 *
493
				 * @param string SQL statement for retrieving the last inserted record ID
494
				 * @since 2014.03
495
				 * @category Developer
496
				 * @see mshop/customer/manager/typo3/insert
497
				 * @see mshop/customer/manager/typo3/update
498
				 * @see mshop/customer/manager/typo3/delete
499
				 * @see mshop/customer/manager/typo3/search
500
				 * @see mshop/customer/manager/typo3/count
501
				 */
502
				$path = 'mshop/customer/manager/typo3/newid';
503
				$item->setId( $this->newId( $conn, $path ) );
504
			}
505
506
			$dbm->release( $conn, $dbname );
507
		}
508
		catch( \Exception $e )
509
		{
510
			$dbm->release( $conn, $dbname );
511
			throw $e;
512
		}
513
514
		$item = $this->savePropertyItems( $item, 'customer' );
0 ignored issues
show
Documentation Bug introduced by
The method savePropertyItems does not exist on object<Aimeos\MShop\Customer\Manager\Typo3>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
515
		$item = $this->saveAddressItems( $item, 'customer' );
0 ignored issues
show
Documentation Bug introduced by
The method saveAddressItems does not exist on object<Aimeos\MShop\Customer\Manager\Typo3>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
516
		return $this->saveRefItems( $item, 'customer' );
517
	}
518
519
520
	/**
521
	 * Returns the item objects matched by the given search criteria.
522
	 *
523
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
524
	 * @param integer &$total Number of items that are available in total
525
	 * @return array List of items implementing \Aimeos\MShop\Customer\Item\Iface
526
	 * @throws \Aimeos\MShop\Customer\Exception If creating items failed
527
	 */
528
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], &$total = null )
529
	{
530
		$dbm = $this->getContext()->getDatabaseManager();
531
		$dbname = $this->getResourceName();
532
		$conn = $dbm->acquire( $dbname );
533
		$map = [];
534
535
		try
536
		{
537
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
538
			$cfgPathSearch = 'mshop/customer/manager/typo3/search';
539
			$cfgPathCount = 'mshop/customer/manager/typo3/count';
540
			$required = array( 'customer' );
541
542
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level, $this->plugins );
543
			while( ( $row = $results->fetch() ) !== false ) {
544
				$map[ $row['customer.id'] ] = $row;
545
			}
546
547
			$dbm->release( $conn, $dbname );
548
		}
549
		catch( \Exception $e )
550
		{
551
			$dbm->release( $conn, $dbname  );
552
			throw $e;
553
		}
554
555
		$addrItems = [];
556
		if( in_array( 'customer/address', $ref, true ) ) {
557
			$addrItems = $this->getAddressItems( array_keys( $map ), 'customer' );
0 ignored issues
show
Unused Code introduced by
The call to Typo3::getAddressItems() has too many arguments starting with 'customer'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
558
		}
559
560
		$propItems = [];
561
		if( in_array( 'customer/property', $ref, true ) ) {
562
			$propItems = $this->getPropertyItems( array_keys( $map ), 'customer' );
0 ignored issues
show
Documentation Bug introduced by
The method getPropertyItems does not exist on object<Aimeos\MShop\Customer\Manager\Typo3>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
563
		}
564
565
		return $this->buildItems( $map, $ref, 'customer', $addrItems, $propItems );
0 ignored issues
show
Unused Code introduced by
The call to Typo3::buildItems() has too many arguments starting with $propItems.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
566
	}
567
568
569
	/**
570
	 * Returns a new manager for customer extensions
571
	 *
572
	 * @param string $manager Name of the sub manager type in lower case
573
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
574
	 * @return mixed Manager for different extensions, e.g stock, tags, locations, etc.
575
	 */
576
	public function getSubManager( $manager, $name = null )
577
	{
578
		return $this->getSubManagerBase( 'customer', $manager, ( $name === null ? 'Typo3' : $name ) );
579
	}
580
581
582
	/**
583
	 * Creates a new customer item.
584
	 *
585
	 * @param array $values List of attributes for customer item
586
	 * @param array $listItems List items associated to the customer item
587
	 * @param array $refItems Items referenced by the customer item via the list items
588
	 * @param array $addresses List of address items of the customer item
589
	 * @param array $propItems List of property items of the customer item
590
	 * @return \Aimeos\MShop\Customer\Item\Iface New customer item
591
	 */
592
	protected function createItemBase( array $values = [], array $listItems = [], array $refItems = [],
593
		array $addresses = [], array $propItems = [] )
594
	{
595
		$helper = $this->getPasswordHelper();
596
		$address = $this->getAddressManager()->createItem();
597
		$values['customer.siteid'] = $this->getContext()->getLocale()->getSiteId();
598
599
		if( array_key_exists( 'date_of_birth', $values ) ) {
600
			$values['customer.birthday'] = $this->reverse['date_of_birth']->reverse( $values['date_of_birth'] );
601
		}
602
603
		if( array_key_exists( 'gender', $values ) ) {
604
			$values['customer.salutation'] = $this->reverse['gender']->reverse( $values['gender'] );
605
		}
606
607
		if( array_key_exists( 'disable', $values ) ) {
608
			$values['customer.status'] = $this->reverse['disable']->reverse( $values['disable'] );
609
		}
610
611
		if( array_key_exists( 'tstamp', $values ) ) {
612
			$values['customer.mtime'] = $this->reverse['tstamp']->reverse( $values['tstamp'] );
613
		}
614
615
		if( array_key_exists( 'crdate', $values ) ) {
616
			$values['customer.ctime'] = $this->reverse['crdate']->reverse( $values['crdate'] );
617
		}
618
619
		if( array_key_exists( 'groups', $values ) ) {
620
			$values['groups'] = explode( ',', $values['groups'] );
621
		}
622
623
		return new \Aimeos\MShop\Customer\Item\Typo3(
624
			$address, $values, $listItems, $refItems,
0 ignored issues
show
Compatibility introduced by
$address of type object<Aimeos\MShop\Common\Item\Iface> is not a sub-type of object<Aimeos\MShop\Common\Item\Address\Iface>. It seems like you assume a child interface of the interface Aimeos\MShop\Common\Item\Iface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
625
			null, $helper, $addresses, $propItems
626
		);
627
	}
628
629
630
	/**
631
	 * Returns the address sub-manager.
632
	 *
633
	 * @return \Aimeos\MShop\Common\Manager\Iface Customer address manager
634
	 */
635
	protected function getAddressManager()
636
	{
637
		if( !isset( $this->addressManager ) ) {
0 ignored issues
show
Bug introduced by
The property addressManager cannot be accessed from this context as it is declared private in class Aimeos\MShop\Customer\Manager\Base.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
638
			$this->addressManager = $this->getObject()->getSubManager( 'address' );
0 ignored issues
show
Bug introduced by
The property addressManager cannot be accessed from this context as it is declared private in class Aimeos\MShop\Customer\Manager\Base.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
639
		}
640
641
		return $this->addressManager;
0 ignored issues
show
Bug introduced by
The property addressManager cannot be accessed from this context as it is declared private in class Aimeos\MShop\Customer\Manager\Base.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
642
	}
643
644
645
	/**
646
	 * Returns a password helper object based on the configuration.
647
	 *
648
	 * @return \Aimeos\MShop\Common\Item\Helper\Password\Iface Password helper object
649
	 * @throws \Aimeos\MShop\Exception If the name is invalid or the class isn't found
650
	 */
651
	protected function getPasswordHelper()
652
	{
653
		if( $this->helper ) {
654
			return $this->helper;
655
		}
656
657
		$iface = '\\Aimeos\\MShop\\Common\\Item\\Helper\\Password\\Iface';
658
		$classname = '\\Aimeos\\MShop\\Common\\Item\\Helper\\Password\\Typo3';
659
660
		if( class_exists( $classname ) === false ) {
661
			throw new \Aimeos\MShop\Exception( sprintf( 'Class "%1$s" not available', $classname ) );
662
		}
663
664
		$context = $this->getContext();
665
		$object = ( method_exists( $context, 'getHasherTypo3' ) ? $context->getHasherTypo3() : null );
666
667
		$helper = new $classname( array( 'object' => $object ) );
668
669
		if( !( $helper instanceof $iface ) ) {
670
			throw new \Aimeos\MShop\Exception( sprintf( 'Class "%1$s" does not implement interface "%2$s"', $classname, $iface ) );
671
		}
672
673
		$this->helper = $helper;
674
675
		return $helper;
676
	}
677
}
678