Passed
Push — master ( cbb785...7ebf0b )
by Aimeos
04:56
created

Base   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 278
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 15
eloc 53
c 0
b 0
f 0
dl 0
loc 278
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getUser() 0 3 1
A aggregate() 0 53 1
A deleteItemsBase() 0 30 3
A createItemBase() 0 8 1
A getPasswordHelper() 0 45 3
A filter() 0 3 1
A find() 0 4 1
A addGroups() 0 20 3
A get() 0 3 1
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2024
6
 * @package MShop
7
 * @subpackage Customer
8
 */
9
10
11
namespace Aimeos\MShop\Customer\Manager;
12
13
14
/**
15
 * Base class with common methods for all customer implementations.
16
 *
17
 * @package MShop
18
 * @subpackage Customer
19
 */
20
abstract class Base
21
	extends \Aimeos\MShop\Common\Manager\Base
22
{
23
	use \Aimeos\MShop\Common\Manager\ListsRef\Traits;
24
	use \Aimeos\MShop\Common\Manager\AddressRef\Traits;
25
	use \Aimeos\MShop\Common\Manager\PropertyRef\Traits;
26
27
28
	/* @deprecated 2025.01 Use $this->context()->password() instead */
29
	private ?\Aimeos\MShop\Common\Helper\Password\Iface $helper = null;
30
31
32
	/**
33
	 * Counts the number items that are available for the values of the given key.
34
	 *
35
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria
36
	 * @param array|string $key Search key or list of key to aggregate items for
37
	 * @param string|null $value Search key for aggregating the value column
38
	 * @param string|null $type Type of the aggregation, empty string for count or "sum" or "avg" (average)
39
	 * @return \Aimeos\Map List of the search keys as key and the number of counted items as value
40
	 */
41
	public function aggregate( \Aimeos\Base\Criteria\Iface $search, $key, string $value = null, string $type = null ) : \Aimeos\Map
42
	{
43
		/** mshop/customer/manager/aggregate/mysql
44
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
45
		 *
46
		 * @see mshop/customer/manager/aggregate/ansi
47
		 */
48
49
		/** mshop/customer/manager/aggregate/ansi
50
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
51
		 *
52
		 * Groups all records by the values in the key column and counts their
53
		 * occurence. The matched records can be limited by the given criteria
54
		 * from the customer database. The records must be from one of the sites
55
		 * that are configured via the context item. If the current site is part
56
		 * of a tree of sites, the statement can count all records from the
57
		 * current site and the complete sub-tree of sites.
58
		 *
59
		 * As the records can normally be limited by criteria from sub-managers,
60
		 * their tables must be joined in the SQL context. This is done by
61
		 * using the "internaldeps" property from the definition of the ID
62
		 * column of the sub-managers. These internal dependencies specify
63
		 * the JOIN between the tables and the used columns for joining. The
64
		 * ":joins" placeholder is then replaced by the JOIN strings from
65
		 * the sub-managers.
66
		 *
67
		 * To limit the records matched, conditions can be added to the given
68
		 * criteria object. It can contain comparisons like column names that
69
		 * must match specific values which can be combined by AND, OR or NOT
70
		 * operators. The resulting string of SQL conditions replaces the
71
		 * ":cond" placeholder before the statement is sent to the database
72
		 * server.
73
		 *
74
		 * This statement doesn't return any records. Instead, it returns pairs
75
		 * of the different values found in the key column together with the
76
		 * number of records that have been found for that key values.
77
		 *
78
		 * The SQL statement should conform to the ANSI standard to be
79
		 * compatible with most relational database systems. This also
80
		 * includes using double quotes for table and column names.
81
		 *
82
		 * @param string SQL statement for aggregating customer items
83
		 * @since 2021.04
84
		 * @see mshop/customer/manager/insert/ansi
85
		 * @see mshop/customer/manager/update/ansi
86
		 * @see mshop/customer/manager/newid/ansi
87
		 * @see mshop/customer/manager/delete/ansi
88
		 * @see mshop/customer/manager/search/ansi
89
		 * @see mshop/customer/manager/count/ansi
90
		 */
91
92
		$cfgkey = 'mshop/customer/manager/aggregate';
93
		return $this->aggregateBase( $search, $key, $cfgkey, ['customer'], $value, $type );
94
	}
95
96
97
	/**
98
	 * Creates a filter object.
99
	 *
100
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
101
	 * @param bool $site TRUE for adding site criteria to limit items by the site of related items
102
	 * @return \Aimeos\Base\Criteria\Iface Returns the filter object
103
	 */
104
	public function filter( ?bool $default = false, bool $site = false ) : \Aimeos\Base\Criteria\Iface
105
	{
106
		return $this->filterBase( 'customer', $default );
107
	}
108
109
110
	/**
111
	 * Returns the item specified by its code and domain/type if necessary
112
	 *
113
	 * @param string $code Code of the item
114
	 * @param string[] $ref List of domains to fetch list items and referenced items for
115
	 * @param string|null $domain Domain of the item if necessary to identify the item uniquely
116
	 * @param string|null $type Type code of the item if necessary to identify the item uniquely
117
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
118
	 * @return \Aimeos\MShop\Customer\Item\Iface Item object
119
	 */
120
	public function find( string $code, array $ref = [], string $domain = null, string $type = null,
121
		?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
122
	{
123
		return $this->findBase( ['customer.code' => $code], $ref, $default );
124
	}
125
126
127
	/**
128
	 * Returns the customer item object specificed by its ID.
129
	 *
130
	 * @param string $id Unique customer ID referencing an existing customer
131
	 * @param string[] $ref List of domains to fetch list items and referenced items for
132
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
133
	 * @return \Aimeos\MShop\Customer\Item\Iface Returns the customer item of the given id
134
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
135
	 */
136
	public function get( string $id, array $ref = [], ?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
137
	{
138
		return $this->getItemBase( 'customer.id', $id, $ref, $default );
139
	}
140
141
142
	/**
143
	 * Adds the customer to the groups listed in the customer item
144
	 *
145
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item
146
	 * @return \Aimeos\MShop\Customer\Item\Iface $item Modified customer item
147
	 */
148
	protected function addGroups( \Aimeos\MShop\Customer\Item\Iface $item ): \Aimeos\MShop\Customer\Item\Iface
149
	{
150
		$pos = 0;
151
		$groupIds = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $groupIds is dead and can be removed.
Loading history...
152
153
		$manager = $this->object()->getSubManager( 'lists' );
154
		$listItems = $item->getListItems( 'group', 'default', null, false );
155
156
		foreach( $item->getGroups() as $refId => $code )
157
		{
158
			if( ( $litem = $item->getListItem( 'group', 'default', $refId, false ) ) !== null ) {
159
				unset( $listItems[$litem->getId()], $listItems['__group_default_' . $refId] );
160
			} else {
161
				$litem = $manager->create()->setType( 'default' );
162
			}
163
164
			$item->addListItem( 'group', $litem->setRefId( $refId )->setPosition( $pos++ ) );
165
		}
166
167
		return $item->deleteListItems( $listItems );
168
	}
169
170
171
	/**
172
	 * Creates a new customer item.
173
	 *
174
	 * @param array $values List of attributes for customer item
175
	 * @param \Aimeos\MShop\Common\Item\Lists\Iface[] $listItems List of list items
176
	 * @param \Aimeos\MShop\Common\Item\Iface[] $refItems List of referenced items
177
	 * @param \Aimeos\MShop\Common\Item\Address\Iface[] $addrItems List of address items
178
	 * @param \Aimeos\MShop\Common\Item\Property\Iface[] $propItems List of property items
179
	 * @return \Aimeos\MShop\Customer\Item\Iface New customer item
180
	 */
181
	protected function createItemBase( array $values = [], array $listItems = [], array $refItems = [],
182
		array $addrItems = [], array $propItems = [] ) : \Aimeos\MShop\Common\Item\Iface
183
	{
184
		$values['.listitems'] = $listItems;
185
		$values['.propitems'] = $propItems;
186
		$values['.addritems'] = $addrItems;
187
188
		return $this->create( $values );
189
	}
190
191
192
	/**
193
	 * Deletes items.
194
	 *
195
	 * @param \Aimeos\MShop\Common\Item\Iface|\Aimeos\Map|array|string $items List of item objects or IDs of the items
196
	 * @param string $cfgpath Configuration path to the SQL statement
197
	 * @param bool $siteid If siteid should be used in the statement
198
	 * @param string $name Name of the ID column
199
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
200
	 */
201
	protected function deleteItemsBase( $items, string $cfgpath, bool $siteid = true,
202
		string $name = 'id' ) : \Aimeos\MShop\Common\Manager\Iface
203
	{
204
		if( map( $items )->isEmpty() ) {
205
			return $this;
206
		}
207
208
		$search = $this->object()->filter();
209
		$search->setConditions( $search->compare( '==', $name, $items ) );
210
211
		$types = array( $name => \Aimeos\Base\DB\Statement\Base::PARAM_STR );
212
		$translations = array( $name => '"' . $name . '"' );
213
214
		$cond = $search->getConditionSource( $types, $translations );
215
		$sql = str_replace( ':cond', $cond, $this->getSqlConfig( $cfgpath ) );
216
217
		$context = $this->context();
218
		$conn = $context->db( $this->getResourceName() );
219
220
		$stmt = $conn->create( $sql );
221
222
		if( $siteid )
223
		{
224
			$stmt->bind( 1, $context->locale()->getSiteId() . '%' );
225
			$stmt->bind( 2, $context->user()?->getSiteId() );
226
		}
227
228
		$stmt->execute()->finish();
229
230
		return $this;
231
	}
232
233
234
	/**
235
	 * Returns a password helper object based on the configuration.
236
	 *
237
	 * @return \Aimeos\MShop\Common\Helper\Password\Iface Password helper object
238
	 * @throws \LogicException If the name is invalid or the class isn't found
239
	 * @deprecated 2025.01 Use $this->context()->password() instead
240
	 */
241
	protected function getPasswordHelper() : \Aimeos\MShop\Common\Helper\Password\Iface
242
	{
243
		if( $this->helper ) {
244
			return $this->helper;
245
		}
246
247
		$config = $this->context()->config();
248
249
		/** mshop/customer/manager/password/name
250
		 * Last part of the name for building the password helper item
251
		 *
252
		 * The password helper encode given passwords and salts using the
253
		 * implemented hashing method in the required format. String format and
254
		 * hash algorithm needs to be the same when comparing the encoded
255
		 * password to the one provided by the user after login.
256
		 *
257
		 * @param string Name of the password helper implementation
258
		 * @since 2015.01
259
		 * @see mshop/customer/manager/salt
260
		 * @see mshop/customer/manager/password/options
261
		 */
262
		$name = $config->get( 'mshop/customer/manager/password/name', 'Standard' );
263
264
		/** mshop/customer/manager/password/options
265
		 * List of options used by the password helper classes
266
		 *
267
		 * Each hash method may need an arbitrary number of options specific
268
		 * for the hash method. This may include the number of iterations the
269
		 * method is applied or the separator between salt and password.
270
		 *
271
		 * @param string Associative list of key/value pairs
272
		 * @since 2015.01
273
		 * @see mshop/customer/manager/password/name
274
		 * @sse mshop/customer/manager/salt
275
		 */
276
		$options = $config->get( 'mshop/customer/manager/password/options', [] );
277
278
		if( ctype_alnum( $name ) === false ) {
279
			throw new \LogicException( sprintf( 'Invalid characters in class name "%1$s"', $name ), 400 );
280
		}
281
282
		$classname = '\Aimeos\MShop\Common\Helper\Password\\' . $name;
283
		$interface = \Aimeos\MShop\Common\Helper\Password\Iface::class;
284
285
		return $this->helper = \Aimeos\Utils::create( $classname, [$options], $interface );
286
	}
287
288
289
	/**
290
	 * Returns the currently authenticated user
291
	 *
292
	 * @return \Aimeos\MShop\Customer\Item\Iface|null Customer item or NULL if not available
293
	 * @deprecated 2025.01 Use $this->context()->user() instead
294
	 */
295
	protected function getUser() : ?\Aimeos\MShop\Customer\Item\Iface
296
	{
297
		return $this->context()->user();
298
	}
299
}
300