FosUser::delete()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2025
6
 * @package MShop
7
 * @subpackage Customer
8
 */
9
10
11
namespace Aimeos\MShop\Customer\Manager;
12
13
14
/**
15
 * Customer class implementation for Friends of Symfony user bundle.
16
 *
17
 * @package MShop
18
 * @subpackage Customer
19
 */
20
class FosUser
21
	extends \Aimeos\MShop\Customer\Manager\Standard
22
{
23
	/**
24
	 * Removes old entries from the storage.
25
	 *
26
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
27
	 * @return \Aimeos\MShop\Common\Manager\Iface Same object for fluent interface
28
	 */
29
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
30
	{
31
		$path = 'mshop/customer/manager/submanagers';
32
		$default = ['address', 'lists', 'property'];
33
34
		foreach( $this->context()->config()->get( $path, $default ) as $domain ) {
35
			$this->object()->getSubManager( $domain )->clear( $siteids );
36
		}
37
38
		return $this->clearBase( $siteids, 'mshop/customer/manager/fosuser/clear' );
39
	}
40
41
42
	/**
43
	 * Creates a new empty item instance
44
	 *
45
	 * @param array $values Values the item should be initialized with
46
	 * @return \Aimeos\MShop\Customer\Item\Iface New customer item object
47
	 */
48
	public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
49
	{
50
		$values['customer.siteid'] = $values['customer.siteid'] ?? $this->context()->locale()->getSiteId();
51
52
		$address = new \Aimeos\MShop\Common\Item\Address\Standard( 'customer.', $values );
53
		return new \Aimeos\MShop\Customer\Item\FosUser( $address, 'customer.', $values, $this->context()->password() );
54
	}
55
56
57
	/**
58
	 * Removes multiple items.
59
	 *
60
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $items List of item objects or IDs of the items
61
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
62
	 */
63
	public function delete( $items ) : \Aimeos\MShop\Common\Manager\Iface
64
	{
65
		return $this->deleteItemsBase( $items, 'mshop/customer/manager/fosuser/delete' );
66
	}
67
68
69
	/**
70
	 * Returns the list attributes that can be used for searching.
71
	 *
72
	 * @param bool $withsub Return also attributes of sub-managers if true
73
	 * @return array List of attribute items implementing \Aimeos\Base\Criteria\Attribute\Iface
74
	 */
75
	public function getSearchAttributes( bool $withsub = true ) : array
76
	{
77
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
78
		$level = $this->context()->config()->get( 'mshop/customer/manager/sitemode', $level );
79
80
		return array_replace( parent::getSearchAttributes( $withsub ), $this->createAttributes( [
81
			'customer.code' => [
82
				'label' => 'Username',
83
				'internalcode' => 'username',
84
			],
85
			'customer.label' => [
86
				'label' => 'Label',
87
				'internalcode' => 'username_canonical',
88
			],
89
			'customer.status' => [
90
				'label' => 'Status',
91
				'internalcode' => 'enabled',
92
				'type' => 'int',
93
			],
94
			'customer:has' => [
95
				'code' => 'customer:has()',
96
				'internalcode' => ':site AND :key AND mcusli."id"',
97
				'internaldeps' => ['LEFT JOIN "fos_user_list" AS mcusli ON ( mcusli."parentid" = mcus."id" )'],
98
				'label' => 'Customer has list item, parameter(<domain>[,<list type>[,<reference ID>)]]',
99
				'type' => 'null',
100
				'public' => false,
101
				'function' => function( &$source, array $params ) use ( $level ) {
102
					$keys = [];
103
104
					foreach( (array) ( $params[1] ?? '' ) as $type ) {
105
						foreach( (array) ( $params[2] ?? '' ) as $id ) {
106
							$keys[] = $params[0] . '|' . ( $type ? $type . '|' : '' ) . $id;
107
						}
108
					}
109
110
					$sitestr = $this->siteString( 'mcusli."siteid"', $level );
111
					$keystr = $this->toExpression( 'mcusli."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
112
					$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
113
114
					return $params;
115
				}
116
			],
117
			'customer:prop' => [
118
				'code' => 'customer:prop()',
119
				'internalcode' => ':site AND :key AND mcuspr."id"',
120
				'internaldeps' => ['LEFT JOIN "fos_user_property" AS mcuspr ON ( mcuspr."parentid" = mcus."id" )'],
121
				'label' => 'Customer has property item, parameter(<property type>[,<language code>[,<property value>]])',
122
				'type' => 'null',
123
				'public' => false,
124
				'function' => function( &$source, array $params ) use ( $level ) {
125
					$keys = [];
126
					$langs = array_key_exists( 1, $params ) ? ( $params[1] ?? 'null' ) : '';
127
128
					foreach( (array) $langs as $lang ) {
129
						foreach( (array) ( $params[2] ?? '' ) as $val ) {
130
							$keys[] = substr( $params[0] . '|' . ( $lang === null ? 'null|' : ( $lang ? $lang . '|' : '' ) ) . $val, 0, 255 );
131
						}
132
					}
133
134
					$sitestr = $this->siteString( 'mcuspr."siteid"', $level );
135
					$keystr = $this->toExpression( 'mcuspr."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
136
					$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
137
138
					return $params;
139
				}
140
			],
141
		] ) );
142
	}
143
144
145
	/**
146
	 * Saves a customer item object.
147
	 *
148
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item object
149
	 * @param bool $fetch True if the new ID should be returned in the item
150
	 * @return \Aimeos\MShop\Customer\Item\Iface $item Updated item including the generated ID
151
	 */
152
	protected function saveItem( \Aimeos\MShop\Customer\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Customer\Item\Iface
153
	{
154
		$item = $this->addGroups( $item );
155
156
		if( !$item->isModified() ) {
157
			return $this->object()->saveRefs( $item, $fetch );
158
		}
159
160
		$context = $this->context();
161
		$conn = $context->db( $this->getResourceName() );
162
163
		$id = $item->getId();
164
		$billingAddress = $item->getPaymentAddress();
165
		$columns = $this->object()->getSaveAttributes();
166
167
		if( $id === null )
168
		{
169
			/** mshop/customer/manager/fosuser/insert
170
			 * Inserts a new customer record into the database table
171
			 *
172
			 * Items with no ID yet (i.e. the ID is NULL) will be created in
173
			 * the database and the newly created ID retrieved afterwards
174
			 * using the "newid" SQL statement.
175
			 *
176
			 * The SQL statement must be a string suitable for being used as
177
			 * prepared statement. It must include question marks for binding
178
			 * the values from the customer item to the statement before they are
179
			 * sent to the database server. The number of question marks must
180
			 * be the same as the number of columns listed in the INSERT
181
			 * statement. The order of the columns must correspond to the
182
			 * order in the save() method, so the correct values are
183
			 * bound to the columns.
184
			 *
185
			 * The SQL statement should conform to the ANSI standard to be
186
			 * compatible with most relational database systems. This also
187
			 * includes using double quotes for table and column names.
188
			 *
189
			 * @param string SQL statement for inserting records
190
			 * @since 2015.01
191
			 * @category Developer
192
			 * @see mshop/customer/manager/fosuser/update
193
			 * @see mshop/customer/manager/fosuser/newid
194
			 * @see mshop/customer/manager/fosuser/delete
195
			 * @see mshop/customer/manager/fosuser/search
196
			 * @see mshop/customer/manager/fosuser/count
197
			 */
198
			$path = 'mshop/customer/manager/fosuser/insert';
199
			$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

199
			$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
200
		}
201
		else
202
		{
203
			/** mshop/customer/manager/fosuser/update
204
			 * Updates an existing customer record in the database
205
			 *
206
			 * Items which already have an ID (i.e. the ID is not NULL) will
207
			 * be updated in the database.
208
			 *
209
			 * The SQL statement must be a string suitable for being used as
210
			 * prepared statement. It must include question marks for binding
211
			 * the values from the customer item to the statement before they are
212
			 * sent to the database server. The order of the columns must
213
			 * correspond to the order in the save() method, so the
214
			 * correct values are bound to the columns.
215
			 *
216
			 * The SQL statement should conform to the ANSI standard to be
217
			 * compatible with most relational database systems. This also
218
			 * includes using double quotes for table and column names.
219
			 *
220
			 * @param string SQL statement for updating records
221
			 * @since 2015.01
222
			 * @category Developer
223
			 * @see mshop/customer/manager/fosuser/insert
224
			 * @see mshop/customer/manager/fosuser/newid
225
			 * @see mshop/customer/manager/fosuser/delete
226
			 * @see mshop/customer/manager/fosuser/search
227
			 * @see mshop/customer/manager/fosuser/count
228
			 */
229
			$path = 'mshop/customer/manager/fosuser/update';
230
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
231
		}
232
233
		$idx = 1;
234
		$stmt = $this->getCachedStatement( $conn, $path, $sql );
235
236
		foreach( $columns as $name => $entry ) {
237
			$stmt->bind( $idx++, $item->get( $name ), \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
238
		}
239
240
		$stmt->bind( $idx++, $item->getCode() ); // canonical username
241
		$stmt->bind( $idx++, $item->getCode() ); // username
242
		$stmt->bind( $idx++, $billingAddress->getCompany() );
243
		$stmt->bind( $idx++, $billingAddress->getVatID() );
244
		$stmt->bind( $idx++, $billingAddress->getSalutation() );
245
		$stmt->bind( $idx++, $billingAddress->getTitle() );
246
		$stmt->bind( $idx++, $billingAddress->getFirstname() );
247
		$stmt->bind( $idx++, $billingAddress->getLastname() );
248
		$stmt->bind( $idx++, $billingAddress->getAddress1() );
249
		$stmt->bind( $idx++, $billingAddress->getAddress2() );
250
		$stmt->bind( $idx++, $billingAddress->getAddress3() );
251
		$stmt->bind( $idx++, $billingAddress->getPostal() );
252
		$stmt->bind( $idx++, $billingAddress->getCity() );
253
		$stmt->bind( $idx++, $billingAddress->getState() );
254
		$stmt->bind( $idx++, $billingAddress->getCountryId() );
255
		$stmt->bind( $idx++, $billingAddress->getLanguageId() );
256
		$stmt->bind( $idx++, $billingAddress->getTelephone() );
257
		$stmt->bind( $idx++, $billingAddress->getMobile() );
258
		$stmt->bind( $idx++, $billingAddress->getEmail() );
259
		$stmt->bind( $idx++, $billingAddress->getEmail() );
260
		$stmt->bind( $idx++, $billingAddress->getTelefax() );
261
		$stmt->bind( $idx++, $billingAddress->getWebsite() );
262
		$stmt->bind( $idx++, $billingAddress->getLongitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
263
		$stmt->bind( $idx++, $billingAddress->getLatitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
264
		$stmt->bind( $idx++, $billingAddress->getBirthday() );
265
		$stmt->bind( $idx++, ( $item->getStatus() > 0 ? true : false ), \Aimeos\Base\DB\Statement\Base::PARAM_BOOL );
266
		$stmt->bind( $idx++, $item->getDateVerified() );
267
		$stmt->bind( $idx++, $item->getPassword() );
268
		$stmt->bind( $idx++, $context->datetime() ); // Modification time
269
		$stmt->bind( $idx++, $context->editor() );
270
		$stmt->bind( $idx++, serialize( $item->getRoles() ) );
271
		$stmt->bind( $idx++, $item->getSalt() );
272
273
		if( $id !== null ) {
274
			$stmt->bind( $idx++, $context->locale()->getSiteId() . '%' );
275
			$stmt->bind( $idx++, (string) $context->user()?->getSiteId() );
276
			$stmt->bind( $idx, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
277
			$billingAddress->setId( $id ); // enforce ID to be present
278
		} else {
279
			$stmt->bind( $idx++, $this->siteId( $item->getSiteId(), \Aimeos\MShop\Locale\Manager\Base::SITE_SUBTREE ) );
280
			$stmt->bind( $idx, $context->datetime() ); // Creation time
281
		}
282
283
		$stmt->execute()->finish();
284
285
		if( $id === null && $fetch === true )
286
		{
287
			/** mshop/customer/manager/fosuser/newid
288
			 * Retrieves the ID generated by the database when inserting a new record
289
			 *
290
			 * As soon as a new record is inserted into the database table,
291
			 * the database server generates a new and unique identifier for
292
			 * that record. This ID can be used for retrieving, updating and
293
			 * deleting that specific record from the table again.
294
			 *
295
			 * For MySQL:
296
			 *  SELECT LAST_INSERT_ID()
297
			 * For PostgreSQL:
298
			 *  SELECT currval('seq_mcus_id')
299
			 * For SQL Server:
300
			 *  SELECT SCOPE_IDENTITY()
301
			 * For Oracle:
302
			 *  SELECT "seq_mcus_id".CURRVAL FROM DUAL
303
			 *
304
			 * There's no way to retrive the new ID by a SQL statements that
305
			 * fits for most database servers as they implement their own
306
			 * specific way.
307
			 *
308
			 * @param string SQL statement for retrieving the last inserted record ID
309
			 * @since 2015.01
310
			 * @category Developer
311
			 * @see mshop/customer/manager/fosuser/insert
312
			 * @see mshop/customer/manager/fosuser/update
313
			 * @see mshop/customer/manager/fosuser/delete
314
			 * @see mshop/customer/manager/fosuser/search
315
			 * @see mshop/customer/manager/fosuser/count
316
			 */
317
			$path = 'mshop/customer/manager/fosuser/newid';
318
			$id = $this->newId( $conn, $path );
319
		}
320
321
		return $this->object()->saveRefs( $item->setId( $id ), $fetch );
322
	}
323
324
325
	/**
326
	 * Returns the full configuration key for the passed last part
327
	 *
328
	 * @param string $name Configuration last part
329
	 * @return string Full configuration key
330
	 */
331
	protected function getConfigKey( string $name, string $default = '' ) : string
332
	{
333
		if( $this->context()->config()->get( 'mshop/customer/manager/fosuser/' . $name ) ) {
334
			return 'mshop/customer/manager/fosuser/' . $name;
335
		}
336
337
		return parent::getConfigKey( $name, $default );
338
	}
339
340
341
	/**
342
	 * Returns a new manager for customer extensions
343
	 *
344
	 * @param string $manager Name of the sub manager type in lower case
345
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
346
	 * @return mixed Manager for different extensions, e.g stock, tags, locations, etc.
347
	 */
348
	public function getSubManager( string $manager, ?string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
349
	{
350
		return $this->getSubManagerBase( 'customer', $manager, $name ?: 'FosUser' );
351
	}
352
353
354
	/**
355
	 * Returns the name of the used table
356
	 *
357
	 * @return string Table name
358
	 */
359
	protected function table() : string
360
	{
361
		return 'fos_user';
362
	}
363
}
364