Completed
Push — 2016.07 ( e051f5...d1403d )
by Aimeos
09:14
created

Typo3   B

Complexity

Total Complexity 35

Size/Duplication

Total Lines 611
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 15

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 35
c 6
b 0
f 0
lcom 2
cbo 15
dl 0
loc 611
rs 8.25

11 Methods

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

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
332
333
			if( $id === null )
334
			{
335
				/** mshop/customer/manager/typo3/insert
336
				 * Inserts a new customer record into the database table
337
				 *
338
				 * Items with no ID yet (i.e. the ID is NULL) will be created in
339
				 * the database and the newly created ID retrieved afterwards
340
				 * using the "newid" SQL statement.
341
				 *
342
				 * The SQL statement must be a string suitable for being used as
343
				 * prepared statement. It must include question marks for binding
344
				 * the values from the customer item to the statement before they are
345
				 * sent to the database server. The number of question marks must
346
				 * be the same as the number of columns listed in the INSERT
347
				 * statement. The order of the columns must correspond to the
348
				 * order in the saveItems() method, so the correct values are
349
				 * bound to the columns.
350
				 *
351
				 * The SQL statement should conform to the ANSI standard to be
352
				 * compatible with most relational database systems. This also
353
				 * includes using double quotes for table and column names.
354
				 *
355
				 * @param string SQL statement for inserting records
356
				 * @since 2014.03
357
				 * @category Developer
358
				 * @see mshop/customer/manager/typo3/update
359
				 * @see mshop/customer/manager/typo3/newid
360
				 * @see mshop/customer/manager/typo3/delete
361
				 * @see mshop/customer/manager/typo3/search
362
				 * @see mshop/customer/manager/typo3/count
363
				 */
364
				$path = 'mshop/customer/manager/typo3/insert';
365
			}
366
			else
367
			{
368
				/** mshop/customer/manager/typo3/update
369
				 * Updates an existing customer record in the database
370
				 *
371
				 * Items which already have an ID (i.e. the ID is not NULL) will
372
				 * be updated in the database.
373
				 *
374
				 * The SQL statement must be a string suitable for being used as
375
				 * prepared statement. It must include question marks for binding
376
				 * the values from the customer item to the statement before they are
377
				 * sent to the database server. The order of the columns must
378
				 * correspond to the order in the saveItems() method, so the
379
				 * correct values are bound to the columns.
380
				 *
381
				 * The SQL statement should conform to the ANSI standard to be
382
				 * compatible with most relational database systems. This also
383
				 * includes using double quotes for table and column names.
384
				 *
385
				 * @param string SQL statement for updating records
386
				 * @since 2014.03
387
				 * @category Developer
388
				 * @see mshop/customer/manager/typo3/insert
389
				 * @see mshop/customer/manager/typo3/newid
390
				 * @see mshop/customer/manager/typo3/delete
391
				 * @see mshop/customer/manager/typo3/search
392
				 * @see mshop/customer/manager/typo3/count
393
				 */
394
				$path = 'mshop/customer/manager/typo3/update';
395
			}
396
397
			$stmt = $this->getCachedStatement( $conn, $path );
398
399
			$address = $billingAddress->getAddress1();
400
401
			if( ( $part = $billingAddress->getAddress2() ) != '' ) {
402
				$address .= ' ' . $part;
403
			}
404
405
			if( ( $part = $billingAddress->getAddress3() ) != '' ) {
406
				$address .= ' ' . $part;
407
			}
408
409
			// TYPO3 fe_users.static_info_country is a three letter ISO code instead a two letter one
410
			$stmt->bind( 1, $item->getLabel() );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\MShop\Common\Item\Iface as the method getLabel() does only exist in the following implementations of said interface: Aimeos\MAdmin\Job\Item\Standard, Aimeos\MShop\Attribute\Item\Standard, Aimeos\MShop\Catalog\Item\Standard, Aimeos\MShop\Common\Item\ListRef\Base, Aimeos\MShop\Common\Item\ListRef\Test, Aimeos\MShop\Common\Item\Type\Standard, Aimeos\MShop\Coupon\Item\Standard, Aimeos\MShop\Customer\Item\Base, Aimeos\MShop\Customer\Item\Group\Standard, Aimeos\MShop\Customer\Item\Standard, Aimeos\MShop\Locale\Item\Currency\Standard, Aimeos\MShop\Locale\Item\Language\Standard, Aimeos\MShop\Locale\Item\Site\Standard, Aimeos\MShop\Media\Item\Standard, Aimeos\MShop\Plugin\Item\Standard, Aimeos\MShop\Price\Item\Base, Aimeos\MShop\Price\Item\Standard, Aimeos\MShop\Product\Item\Standard, Aimeos\MShop\Product\Item\Stock\Warehouse\Standard, Aimeos\MShop\Service\Item\Standard, Aimeos\MShop\Supplier\Item\Standard, Aimeos\MShop\Tag\Item\Standard, Aimeos\MShop\Text\Item\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
411
			$stmt->bind( 2, $item->getCode() );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\MShop\Common\Item\Iface as the method getCode() does only exist in the following implementations of said interface: Aimeos\MShop\Attribute\Item\Standard, Aimeos\MShop\Catalog\Item\Standard, Aimeos\MShop\Common\Item\Type\Standard, Aimeos\MShop\Coupon\Item\Code\Standard, Aimeos\MShop\Customer\Item\Base, Aimeos\MShop\Customer\Item\Group\Standard, Aimeos\MShop\Customer\Item\Standard, Aimeos\MShop\Locale\Item\Currency\Standard, Aimeos\MShop\Locale\Item\Language\Standard, Aimeos\MShop\Locale\Item\Site\Standard, Aimeos\MShop\Order\Item\Base\Coupon\Standard, Aimeos\MShop\Order\Item\...duct\Attribute\Standard, Aimeos\MShop\Order\Item\...vice\Attribute\Standard, Aimeos\MShop\Order\Item\Base\Service\Base, Aimeos\MShop\Order\Item\Base\Service\Standard, Aimeos\MShop\Product\Item\Standard, Aimeos\MShop\Product\Item\Stock\Warehouse\Standard, Aimeos\MShop\Service\Item\Standard, Aimeos\MShop\Supplier\Item\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
412
			$stmt->bind( 3, $this->plugins['customer.salutation']->translate( $billingAddress->getSalutation() ), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
413
			$stmt->bind( 4, $billingAddress->getCompany() );
414
			$stmt->bind( 5, $billingAddress->getVatID() );
415
			$stmt->bind( 6, $billingAddress->getTitle() );
416
			$stmt->bind( 7, $billingAddress->getFirstname() );
417
			$stmt->bind( 8, $billingAddress->getLastname() );
418
			$stmt->bind( 9, $address );
419
			$stmt->bind( 10, $billingAddress->getPostal() );
420
			$stmt->bind( 11, $billingAddress->getCity() );
421
			$stmt->bind( 12, $billingAddress->getState() );
422
			$stmt->bind( 13, $billingAddress->getLanguageId() );
423
			$stmt->bind( 14, $billingAddress->getTelephone() );
424
			$stmt->bind( 15, $billingAddress->getEmail() );
425
			$stmt->bind( 16, $billingAddress->getTelefax() );
426
			$stmt->bind( 17, $billingAddress->getWebsite() );
427
			$stmt->bind( 18, $this->plugins['customer.birthday']->translate( $item->getBirthday() ), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\MShop\Common\Item\Iface as the method getBirthday() does only exist in the following implementations of said interface: Aimeos\MShop\Customer\Item\Base, Aimeos\MShop\Customer\Item\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
428
			$stmt->bind( 19, $this->plugins['customer.status']->translate( $item->getStatus() ), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\MShop\Common\Item\Iface as the method getStatus() does only exist in the following implementations of said interface: Aimeos\MAdmin\Job\Item\Standard, Aimeos\MShop\Attribute\Item\Standard, Aimeos\MShop\Catalog\Item\Standard, Aimeos\MShop\Common\Item\Lists\Standard, Aimeos\MShop\Common\Item\Type\Standard, Aimeos\MShop\Coupon\Item\Standard, Aimeos\MShop\Customer\Item\Base, Aimeos\MShop\Customer\Item\Standard, Aimeos\MShop\Locale\Item\Currency\Standard, Aimeos\MShop\Locale\Item\Language\Standard, Aimeos\MShop\Locale\Item\Site\Standard, Aimeos\MShop\Locale\Item\Standard, Aimeos\MShop\Media\Item\Standard, Aimeos\MShop\Order\Item\Base\Base, Aimeos\MShop\Order\Item\Base\Product\Base, Aimeos\MShop\Order\Item\Base\Product\Standard, Aimeos\MShop\Order\Item\Base\Standard, Aimeos\MShop\Plugin\Item\Standard, Aimeos\MShop\Price\Item\Base, Aimeos\MShop\Price\Item\Standard, Aimeos\MShop\Product\Item\Standard, Aimeos\MShop\Product\Item\Stock\Warehouse\Standard, Aimeos\MShop\Service\Item\Standard, Aimeos\MShop\Supplier\Item\Standard, Aimeos\MShop\Text\Item\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
429
			$stmt->bind( 20, $item->getPassword() );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\MShop\Common\Item\Iface as the method getPassword() does only exist in the following implementations of said interface: Aimeos\MShop\Customer\Item\Base, Aimeos\MShop\Customer\Item\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
430
			$stmt->bind( 21, time(), \Aimeos\MW\DB\Statement\Base::PARAM_INT ); // Modification time
431
			$stmt->bind( 22, $billingAddress->getCountryId() );
432
			$stmt->bind( 23, implode( ',', $item->getGroups() ) );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\MShop\Common\Item\Iface as the method getGroups() does only exist in the following implementations of said interface: Aimeos\MShop\Customer\Item\Base, Aimeos\MShop\Customer\Item\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
433
434
			if( $id !== null ) {
435
				$stmt->bind( 24, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
436
				$item->setId( $id );
437
			} else {
438
				$stmt->bind( 24, time(), \Aimeos\MW\DB\Statement\Base::PARAM_INT ); // Creation time
439
				$stmt->bind( 25, $this->pid, \Aimeos\MW\DB\Statement\Base::PARAM_INT ); // TYPO3 PID value
440
			}
441
442
			$stmt->execute()->finish();
443
444
			if( $id === null && $fetch === true )
445
			{
446
				/** mshop/customer/manager/typo3/newid
447
				 * Retrieves the ID generated by the database when inserting a new record
448
				 *
449
				 * As soon as a new record is inserted into the database table,
450
				 * the database server generates a new and unique identifier for
451
				 * that record. This ID can be used for retrieving, updating and
452
				 * deleting that specific record from the table again.
453
				 *
454
				 * For MySQL:
455
				 *  SELECT LAST_INSERT_ID()
456
				 * For PostgreSQL:
457
				 *  SELECT currval('seq_mcus_id')
458
				 * For SQL Server:
459
				 *  SELECT SCOPE_IDENTITY()
460
				 * For Oracle:
461
				 *  SELECT "seq_mcus_id".CURRVAL FROM DUAL
462
				 *
463
				 * There's no way to retrive the new ID by a SQL statements that
464
				 * fits for most database servers as they implement their own
465
				 * specific way.
466
				 *
467
				 * @param string SQL statement for retrieving the last inserted record ID
468
				 * @since 2014.03
469
				 * @category Developer
470
				 * @see mshop/customer/manager/typo3/insert
471
				 * @see mshop/customer/manager/typo3/update
472
				 * @see mshop/customer/manager/typo3/delete
473
				 * @see mshop/customer/manager/typo3/search
474
				 * @see mshop/customer/manager/typo3/count
475
				 */
476
				$path = 'mshop/customer/manager/typo3/newid';
477
				$item->setId( $this->newId( $conn, $path ) );
478
			}
479
480
			$dbm->release( $conn, $dbname );
481
		}
482
		catch( \Exception $e )
483
		{
484
			$dbm->release( $conn, $dbname );
485
			throw $e;
486
		}
487
	}
488
489
490
	/**
491
	 * Returns the item objects matched by the given search criteria.
492
	 *
493
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
494
	 * @param integer &$total Number of items that are available in total
495
	 * @return array List of items implementing \Aimeos\MShop\Customer\Item\Iface
496
	 * @throws \Aimeos\MShop\Customer\Exception If creating items failed
497
	 */
498
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = array(), &$total = null )
499
	{
500
		$dbm = $this->getContext()->getDatabaseManager();
501
		$dbname = $this->getResourceName();
502
		$conn = $dbm->acquire( $dbname );
503
		$map = array();
504
505
		try
506
		{
507
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
508
			$cfgPathSearch = 'mshop/customer/manager/typo3/search';
509
			$cfgPathCount = 'mshop/customer/manager/typo3/count';
510
			$required = array( 'customer' );
511
512
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level, $this->plugins );
513
			while( ( $row = $results->fetch() ) !== false ) {
514
				$map[ $row['customer.id'] ] = $row;
515
			}
516
517
			$dbm->release( $conn, $dbname );
518
		}
519
		catch( \Exception $e )
520
		{
521
			$dbm->release( $conn, $dbname  );
522
			throw $e;
523
		}
524
525
		return $this->buildItems( $map, $ref, 'customer' );
526
	}
527
528
529
	/**
530
	 * Returns a new manager for customer extensions
531
	 *
532
	 * @param string $manager Name of the sub manager type in lower case
533
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
534
	 * @return mixed Manager for different extensions, e.g stock, tags, locations, etc.
535
	 */
536
	public function getSubManager( $manager, $name = null )
537
	{
538
		return $this->getSubManagerBase( 'customer', $manager, ( $name === null ? 'Typo3' : $name ) );
539
	}
540
541
542
	/**
543
	 * Creates a new customer item.
544
	 *
545
	 * @param array $values List of attributes for customer item
546
	 * @param array $listItems List items associated to the customer item
547
	 * @param array $refItems Items referenced by the customer item via the list items
548
	 * @return \Aimeos\MShop\Customer\Item\Iface New customer item
549
	 */
550
	protected function createItemBase( array $values = array(), array $listItems = array(), array $refItems = array() )
551
	{
552
		$helper = $this->getPasswordHelper();
553
		$address = $this->getAddressManager()->createItem();
554
		$values['customer.siteid'] = $this->getContext()->getLocale()->getSiteId();
555
556
		if( array_key_exists( 'date_of_birth', $values ) ) {
557
			$values['customer.birthday'] = $this->reverse['date_of_birth']->reverse( $values['date_of_birth'] );
558
		}
559
560
		if( array_key_exists( 'gender', $values ) ) {
561
			$values['customer.salutation'] = $this->reverse['gender']->reverse( $values['gender'] );
562
		}
563
564
		if( array_key_exists( 'disable', $values ) ) {
565
			$values['customer.status'] = $this->reverse['disable']->reverse( $values['disable'] );
566
		}
567
568
		if( array_key_exists( 'tstamp', $values ) ) {
569
			$values['customer.mtime'] = $this->reverse['tstamp']->reverse( $values['tstamp'] );
570
		}
571
572
		if( array_key_exists( 'crdate', $values ) ) {
573
			$values['customer.ctime'] = $this->reverse['crdate']->reverse( $values['crdate'] );
574
		}
575
576
		if( array_key_exists( 'groups', $values ) ) {
577
			$values['groups'] = explode( ',', $values['groups'] );
578
		}
579
580
		return new \Aimeos\MShop\Customer\Item\Standard( $address, $values, $listItems, $refItems, null, $helper );
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...
581
	}
582
583
584
	/**
585
	 * Returns the address sub-manager.
586
	 *
587
	 * @return \Aimeos\MShop\Common\Manager\Iface Customer address manager
588
	 */
589
	protected function getAddressManager()
590
	{
591
		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...
592
			$this->addressManager = $this->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...
593
		}
594
595
		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...
596
	}
597
598
599
	/**
600
	 * Returns a password helper object based on the configuration.
601
	 *
602
	 * @return \Aimeos\MShop\Common\Item\Helper\Password\Iface Password helper object
603
	 * @throws \Aimeos\MShop\Exception If the name is invalid or the class isn't found
604
	 */
605
	protected function getPasswordHelper()
606
	{
607
		if( $this->helper ) {
608
			return $this->helper;
609
		}
610
611
		$iface = '\\Aimeos\\MShop\\Common\\Item\\Helper\\Password\\Iface';
612
		$classname = '\\Aimeos\\MShop\\Common\\Item\\Helper\\Password\\Typo3';
613
614
		if( class_exists( $classname ) === false ) {
615
			throw new \Aimeos\MShop\Exception( sprintf( 'Class "%1$s" not available', $classname ) );
616
		}
617
618
		$context = $this->getContext();
619
		$object = ( method_exists( $context, 'getHasherTypo3' ) ? $context->getHasherTypo3() : null );
620
621
		$helper = new $classname( array( 'object' => $object ) );
622
623
		if( !( $helper instanceof $iface ) ) {
624
			throw new \Aimeos\MShop\Exception( sprintf( 'Class "%1$s" does not implement interface "%2$s"', $classname, $iface ) );
625
		}
626
627
		$this->helper = $helper;
628
629
		return $helper;
630
	}
631
}