Completed
Push — master ( 80e97a...1395b9 )
by Aimeos
11:31
created

Base::copyServices()   A

Complexity

Conditions 4
Paths 10

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2
c 0
b 0
f 0
cc 4
eloc 10
nc 10
nop 2
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2012
6
 * @copyright Aimeos (aimeos.org), 2015-2016
7
 * @package Controller
8
 * @subpackage Frontend
9
 */
10
11
12
namespace Aimeos\Controller\Frontend\Basket;
13
14
15
/**
16
 * Base class for the basket frontend controller
17
 *
18
 * @package Controller
19
 * @subpackage Frontend
20
 */
21
abstract class Base extends \Aimeos\Controller\Frontend\Base implements Iface
22
{
23
	private $listTypeItems = [];
24
25
26
	/**
27
	 * Calculates and returns the current price for the given order product and product prices.
28
	 *
29
	 * @param \Aimeos\MShop\Order\Item\Base\Product\Iface $product Ordered product item
30
	 * @param \Aimeos\MShop\Price\Item\Iface[] $prices List of price items
31
	 * @param integer $quantity New product quantity
32
	 * @return \Aimeos\MShop\Price\Item\Iface Price item with calculated price
33
	 */
34
	protected function calcPrice( \Aimeos\MShop\Order\Item\Base\Product\Iface $product, array $prices, $quantity )
35
	{
36
		$context = $this->getContext();
37
38
		if( empty( $prices ) )
39
		{
40
			$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product' );
41
			$prices = $manager->getItem( $product->getProductId(), array( 'price' ) )->getRefItems( 'price', 'default' );
42
		}
43
44
45
		$priceManager = \Aimeos\MShop\Factory::createManager( $context, 'price' );
46
		$price = $priceManager->getLowestPrice( $prices, $quantity );
47
48
		// customers can pay what they would like to pay
49
		if( ( $attr = $product->getAttributeItem( 'price', 'custom' ) ) !== null )
50
		{
51
			$amount = $attr->getValue();
52
53
			if( preg_match( '/^[0-9]*(\.[0-9]+)?$/', $amount ) !== 1 || ((double) $amount) < 0.01 ) {
54
				throw new \Aimeos\Controller\Frontend\Basket\Exception( sprintf( 'Invalid price value "%1$s"', $amount ) );
55
			}
56
57
			$price->setValue( $amount );
58
		}
59
60
		// add prices of (optional) attributes
61
		foreach( $this->getAttributeItems( $product->getAttributes() ) as $attrItem )
62
		{
63
			$prices = $attrItem->getRefItems( 'price', 'default' );
64
65
			if( count( $prices ) > 0 )
66
			{
67
				$attrPrice = $priceManager->getLowestPrice( $prices, $quantity );
68
				$price->addItem( $attrPrice );
69
			}
70
		}
71
72
		// remove product rebate of original price in favor to rebates granted for the order
73
		$price->setRebate( '0.00' );
74
75
		return $price;
76
	}
77
78
79
	/**
80
	 * Checks if the reference IDs are really associated to the product
81
	 *
82
	 * @param string|array $prodId Unique ID of the product or list of product IDs
83
	 * @param string $domain Domain the references must be of
84
	 * @param array $refMap Associative list of list type codes as keys and lists of reference IDs as values
85
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If one or more of the IDs are not associated
86
	 */
87
	protected function checkListRef( $prodId, $domain, array $refMap )
88
	{
89
		if( empty( $refMap ) ) {
90
			return;
91
		}
92
93
		$productManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product' );
94
		$search = $productManager->createSearch( true );
95
96
		$expr = array(
97
			$search->compare( '==', 'product.id', $prodId ),
98
			$search->getConditions(),
99
		);
100
101
		foreach( $refMap as $listType => $refIds )
102
		{
103
			if( empty( $refIds ) ) {
104
				continue;
105
			}
106
107
			foreach( $refIds as $key => $refId ) {
108
				$refIds[$key] = (string) $refId;
109
			}
110
111
			$param = array( $domain, $this->getProductListTypeItem( $domain, $listType )->getId(), $refIds );
112
			$cmpfunc = $search->createFunction( 'product.contains', $param );
113
114
			$expr[] = $search->compare( '==', $cmpfunc, count( $refIds ) );
115
		}
116
117
		$search->setConditions( $search->combine( '&&', $expr ) );
118
119
		if( count( $productManager->searchItems( $search, [] ) ) === 0 )
120
		{
121
			$msg = sprintf( 'Invalid "%1$s" references for product with ID %2$s', $domain, json_encode( $prodId ) );
122
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg );
123
		}
124
	}
125
126
127
	/**
128
	 * Checks if the IDs of the given items are really associated to the product.
129
	 *
130
	 * @param string|array $prodId Unique ID of the product or list of product IDs
131
	 * @param string $domain Domain the references must be of
132
	 * @param integer $listTypeId ID of the list type the referenced items must be
133
	 * @param array $refIds List of IDs that must be associated to the product
134
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If one or more of the IDs are not associated
135
	 * @deprecated Use checkListRef() instead
136
	 */
137
	protected function checkReferences( $prodId, $domain, $listTypeId, array $refIds )
138
	{
139
		$productManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product' );
140
		$search = $productManager->createSearch( true );
141
142
		$expr = array(
143
			$search->compare( '==', 'product.id', $prodId ),
144
			$search->getConditions(),
145
		);
146
147
		if( count( $refIds ) > 0 )
148
		{
149
			foreach( $refIds as $key => $refId ) {
150
				$refIds[$key] = (string) $refId;
151
			}
152
153
			$param = array( $domain, $listTypeId, $refIds );
154
			$cmpfunc = $search->createFunction( 'product.contains', $param );
155
156
			$expr[] = $search->compare( '==', $cmpfunc, count( $refIds ) );
157
		}
158
159
		$search->setConditions( $search->combine( '&&', $expr ) );
160
161
		if( count( $productManager->searchItems( $search, [] ) ) === 0 )
162
		{
163
			$msg = sprintf( 'Invalid "%1$s" references for product with ID %2$s', $domain, json_encode( $prodId ) );
164
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg );
165
		}
166
	}
167
168
169
	/**
170
	 * Checks for a locale mismatch and migrates the products to the new basket if necessary.
171
	 *
172
	 * @param string $type Basket type
173
	 */
174
	protected function checkLocale( $type )
175
	{
176
		$errors = [];
177
		$context = $this->getContext();
178
		$session = $context->getSession();
179
		$locale = $this->get()->getLocale();
180
181
		$localeStr = $session->get( 'aimeos/basket/locale' );
182
		$localeKey = $locale->getSite()->getCode() . '|' . $locale->getLanguageId() . '|' . $locale->getCurrencyId();
183
184
		if( $localeStr !== null && $localeStr !== $localeKey )
185
		{
186
			$locParts = explode( '|', $localeStr );
187
			$locSite = ( isset( $locParts[0] ) ? $locParts[0] : '' );
188
			$locLanguage = ( isset( $locParts[1] ) ? $locParts[1] : '' );
189
			$locCurrency = ( isset( $locParts[2] ) ? $locParts[2] : '' );
190
191
			$localeManager = \Aimeos\MShop\Factory::createManager( $context, 'locale' );
192
			$locale = $localeManager->bootstrap( $locSite, $locLanguage, $locCurrency, false );
193
194
			$context = clone $context;
195
			$context->setLocale( $locale );
196
197
			$manager = \Aimeos\MShop\Order\Manager\Factory::createManager( $context )->getSubManager( 'base' );
198
			$basket = $manager->getSession( $type );
199
200
			$this->copyAddresses( $basket, $errors, $localeKey );
201
			$this->copyServices( $basket, $errors );
202
			$this->copyProducts( $basket, $errors, $localeKey );
203
			$this->copyCoupons( $basket, $errors, $localeKey );
204
205
			$manager->setSession( $basket, $type );
206
		}
207
208
		$session->set( 'aimeos/basket/locale', $localeKey );
209
	}
210
211
212
	/**
213
	 * Migrates the addresses from the old basket to the current one.
214
	 *
215
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
216
	 * @param array $errors Associative list of previous errors
217
	 * @param string $localeKey Unique identifier of the site, language and currency
218
	 * @return array Associative list of errors occured
219
	 */
220
	protected function copyAddresses( \Aimeos\MShop\Order\Item\Base\Iface $basket, array $errors, $localeKey )
221
	{
222
		foreach( $basket->getAddresses() as $type => $item )
223
		{
224
			try
225
			{
226
				$this->setAddress( $type, $item->toArray() );
227
				$basket->deleteAddress( $type );
228
			}
229
			catch( \Exception $e )
230
			{
231
				$logger = $this->getContext()->getLogger();
232
				$str = 'Error migrating address with type "%1$s" in basket to locale "%2$s": %3$s';
233
				$logger->log( sprintf( $str, $type, $localeKey, $e->getMessage() ), \Aimeos\MW\Logger\Base::INFO );
234
				$errors['address'][$type] = $e->getMessage();
235
			}
236
		}
237
238
		return $errors;
239
	}
240
241
242
	/**
243
	 * Migrates the coupons from the old basket to the current one.
244
	 *
245
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
246
	 * @param array $errors Associative list of previous errors
247
	 * @param string $localeKey Unique identifier of the site, language and currency
248
	 * @return array Associative list of errors occured
249
	 */
250
	protected function copyCoupons( \Aimeos\MShop\Order\Item\Base\Iface $basket, array $errors, $localeKey )
251
	{
252
		foreach( $basket->getCoupons() as $code => $list )
253
		{
254
			try
255
			{
256
				$this->addCoupon( $code );
257
				$basket->deleteCoupon( $code, true );
258
			}
259
			catch( \Exception $e )
260
			{
261
				$logger = $this->getContext()->getLogger();
262
				$str = 'Error migrating coupon with code "%1$s" in basket to locale "%2$s": %3$s';
263
				$logger->log( sprintf( $str, $code, $localeKey, $e->getMessage() ), \Aimeos\MW\Logger\Base::INFO );
264
				$errors['coupon'][$code] = $e->getMessage();
265
			}
266
		}
267
268
		return $errors;
269
	}
270
271
272
	/**
273
	 * Migrates the products from the old basket to the current one.
274
	 *
275
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
276
	 * @param array $errors Associative list of previous errors
277
	 * @param string $localeKey Unique identifier of the site, language and currency
278
	 * @return array Associative list of errors occured
279
	 */
280
	protected function copyProducts( \Aimeos\MShop\Order\Item\Base\Iface $basket, array $errors, $localeKey )
281
	{
282
		foreach( $basket->getProducts() as $pos => $product )
283
		{
284
			if( $product->getFlags() & \Aimeos\MShop\Order\Item\Base\Product\Base::FLAG_IMMUTABLE ) {
285
				continue;
286
			}
287
288
			try
289
			{
290
				$attrIds = [];
291
292
				foreach( $product->getAttributes() as $attrItem ) {
293
					$attrIds[$attrItem->getType()][] = $attrItem->getAttributeId();
294
				}
295
296
				$this->addProduct(
297
					$product->getProductId(),
298
					$product->getQuantity(),
299
					[],
300
					$this->getValue( $attrIds, 'variant', [] ),
301
					$this->getValue( $attrIds, 'config', [] ),
302
					$this->getValue( $attrIds, 'hidden', [] ),
303
					$this->getValue( $attrIds, 'custom', [] ),
304
					$product->getStockType()
305
				);
306
307
				$basket->deleteProduct( $pos );
308
			}
309
			catch( \Exception $e )
310
			{
311
				$code = $product->getProductCode();
312
				$logger = $this->getContext()->getLogger();
313
				$errors['product'][$pos] = $e->getMessage();
314
315
				$str = 'Error migrating product with code "%1$s" in basket to locale "%2$s": %3$s';
316
				$logger->log( sprintf( $str, $code, $localeKey, $e->getMessage() ), \Aimeos\MW\Logger\Base::INFO );
317
			}
318
		}
319
320
		return $errors;
321
	}
322
323
324
	/**
325
	 * Migrates the services from the old basket to the current one.
326
	 *
327
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
328
	 * @param array $errors Associative list of previous errors
329
	 * @return array Associative list of errors occured
330
	 */
331
	protected function copyServices( \Aimeos\MShop\Order\Item\Base\Iface $basket, array $errors )
332
	{
333
		foreach( $basket->getServices() as $type => $item )
334
		{
335
			try
336
			{
337
				$attributes = [];
338
339
				foreach( $item->getAttributes() as $attrItem ) {
340
					$attributes[$attrItem->getCode()] = $attrItem->getValue();
341
				}
342
343
				$this->setService( $type, $item->getServiceId(), $attributes );
344
				$basket->deleteService( $type );
345
			}
346
			catch( \Exception $e ) { ; } // Don't notify the user as appropriate services can be added automatically
347
		}
348
349
		return $errors;
350
	}
351
352
353
	/**
354
	 * Creates the order product attribute items from the given attribute IDs and updates the price item if necessary.
355
	 *
356
	 * @param \Aimeos\MShop\Price\Item\Iface $price Price item of the ordered product
357
	 * @param string|array $prodid Unique product ID or list of product IDs where the given attributes must be attached to
358
	 * @param integer $quantity Number of products that should be added to the basket
359
	 * @param array $attributeIds List of attributes IDs of the given type
360
	 * @param string $type Attribute type
361
	 * @param array $attributeValues Associative list of attribute IDs as keys and their codes as values
362
	 * @return array List of items implementing \Aimeos\MShop\Order\Item\Product\Attribute\Iface
363
	 * @deprecated Use getOrderProductAttributes(), checkReferences() and calcPrice() instead
364
	 */
365
	protected function createOrderProductAttributes( \Aimeos\MShop\Price\Item\Iface $price, $prodid, $quantity,
366
			array $attributeIds, $type, array $attributeValues = [] )
367
	{
368
		if( empty( $attributeIds ) ) {
369
			return [];
370
		}
371
372
		$attrTypeId = $this->getProductListTypeItem( 'attribute', $type )->getId();
373
		$this->checkReferences( $prodid, 'attribute', $attrTypeId, $attributeIds );
0 ignored issues
show
Deprecated Code introduced by
The method Aimeos\Controller\Fronte...Base::checkReferences() has been deprecated with message: Use checkListRef() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
374
375
		$list = [];
376
		$context = $this->getContext();
377
378
		$priceManager = \Aimeos\MShop\Factory::createManager( $context, 'price' );
379
		$orderProductAttributeManager = \Aimeos\MShop\Factory::createManager( $context, 'order/base/product/attribute' );
380
381
		foreach( $this->getAttributes( $attributeIds ) as $id => $attrItem )
382
		{
383
			$prices = $attrItem->getRefItems( 'price', 'default', 'default' );
384
385
			if( !empty( $prices ) ) {
386
				$price->addItem( $priceManager->getLowestPrice( $prices, $quantity ) );
387
			}
388
389
			$item = $orderProductAttributeManager->createItem();
390
			$item->copyFrom( $attrItem );
391
			$item->setType( $type );
392
393
			if( isset( $attributeValues[$id] ) ) {
394
				$item->setValue( $attributeValues[$id] );
395
			}
396
397
			$list[] = $item;
398
		}
399
400
		return $list;
401
	}
402
403
404
	/**
405
	 * Returns the attribute items for the given attribute IDs.
406
	 *
407
	 * @param array $attributeIds List of attribute IDs
408
	 * @param string[] $domains Names of the domain items that should be fetched too
409
	 * @return array List of items implementing \Aimeos\MShop\Attribute\Item\Iface
410
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If the actual attribute number doesn't match the expected one
411
	 */
412
	protected function getAttributes( array $attributeIds, array $domains = array( 'price', 'text' ) )
413
	{
414
		if( empty( $attributeIds ) ) {
415
			return [];
416
		}
417
418
		$attributeManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'attribute' );
419
420
		$search = $attributeManager->createSearch( true );
421
		$expr = array(
422
			$search->compare( '==', 'attribute.id', $attributeIds ),
423
			$search->getConditions(),
424
		);
425
		$search->setConditions( $search->combine( '&&', $expr ) );
426
		$search->setSlice( 0, 0x7fffffff );
427
428
		$attrItems = $attributeManager->searchItems( $search, $domains );
429
430
		if( count( $attrItems ) !== count( $attributeIds ) )
431
		{
432
			$expected = implode( ',', $attributeIds );
433
			$actual = implode( ',', array_keys( $attrItems ) );
434
			$msg = sprintf( 'Available attribute IDs "%1$s" do not match the given attribute IDs "%2$s"', $actual, $expected );
435
436
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg );
437
		}
438
439
		return $attrItems;
440
	}
441
442
443
	/**
444
	 * Returns the attribute items using the given order attribute items.
445
	 *
446
	 * @param \Aimeos\MShop\Order\Item\Base\Product\Attribute\Item[] $orderAttributes List of order product attribute items
447
	 * @return \Aimeos\MShop\Attribute\Item\Iface[] Associative list of attribute IDs as key and attribute items as values
448
	 */
449
	protected function getAttributeItems( array $orderAttributes )
450
	{
451
		if( empty( $orderAttributes ) ) {
452
			return [];
453
		}
454
455
		$attributeManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'attribute' );
456
		$search = $attributeManager->createSearch( true );
457
		$expr = [];
458
459
		foreach( $orderAttributes as $item )
460
		{
461
			$tmp = array(
462
				$search->compare( '==', 'attribute.domain', 'product' ),
463
				$search->compare( '==', 'attribute.code', $item->getValue() ),
464
				$search->compare( '==', 'attribute.type.domain', 'product' ),
465
				$search->compare( '==', 'attribute.type.code', $item->getCode() ),
466
				$search->compare( '>', 'attribute.type.status', 0 ),
467
				$search->getConditions(),
468
			);
469
			$expr[] = $search->combine( '&&', $tmp );
470
		}
471
472
		$search->setConditions( $search->combine( '||', $expr ) );
473
		return $attributeManager->searchItems( $search, array( 'price' ) );
474
	}
475
476
477
	/**
478
	 * Retrieves the domain item specified by the given key and value.
479
	 *
480
	 * @param string $domain Product manager search key
481
	 * @param string $key Domain manager search key
482
	 * @param string $value Unique domain identifier
483
	 * @param string[] $ref List of referenced items that should be fetched too
484
	 * @return \Aimeos\MShop\Common\Item\Iface Domain item object
485
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception
486
	 * @deprecated Use getItem() or findItem() instead
487
	 */
488
	protected function getDomainItem( $domain, $key, $value, array $ref )
489
	{
490
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $domain );
491
492
		$search = $manager->createSearch( true );
493
		$expr = array(
494
			$search->compare( '==', $key, $value ),
495
			$search->getConditions(),
496
		);
497
		$search->setConditions( $search->combine( '&&', $expr ) );
498
499
		$result = $manager->searchItems( $search, $ref );
500
501
		if( ( $item = reset( $result ) ) === false )
502
		{
503
			$msg = sprintf( 'No item for "%1$s" (%2$s) found', $value, $key );
504
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg );
505
		}
506
507
		return $item;
508
	}
509
510
511
	/**
512
	 * Returns the order product attribute items for the given IDs and values
513
	 *
514
	 * @param string $type Attribute type code
515
	 * @param array $attributeIds List of attributes IDs of the given type
516
	 * @param array $attributeValues Associative list of attribute IDs as keys and their codes as values
517
	 * @return array List of items implementing \Aimeos\MShop\Order\Item\Product\Attribute\Iface
518
	 */
519
	protected function getOrderProductAttributes( $type, array $attributeIds, array $attributeValues = [] )
520
	{
521
		if( empty( $attributeIds ) ) {
522
			return [];
523
		}
524
525
		$list = [];
526
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'order/base/product/attribute' );
527
528
		foreach( $this->getAttributes( $attributeIds ) as $id => $attrItem )
529
		{
530
			$item = $manager->createItem();
531
			$item->copyFrom( $attrItem );
532
			$item->setType( $type );
533
534
			if( isset( $attributeValues[$id] ) ) {
535
				$item->setValue( $attributeValues[$id] );
536
			}
537
538
			$list[] = $item;
539
		}
540
541
		return $list;
542
	}
543
544
545
	/**
546
	 * Returns the list type item for the given domain and code.
547
	 *
548
	 * @param string $domain Domain name of the list type
549
	 * @param string $code Code of the list type
550
	 * @return \Aimeos\MShop\Common\Item\Type\Iface List type item
551
	 */
552
	protected function getProductListTypeItem( $domain, $code )
553
	{
554
		if( empty( $this->listTypeItems ) )
555
		{
556
			$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product/lists/type' );
557
558
			foreach( $manager->searchItems( $manager->createSearch( true ) ) as $item ) {
559
				$this->listTypeItems[ $item->getDomain() ][ $item->getCode() ] = $item;
560
			}
561
		}
562
563
		if( !isset( $this->listTypeItems[$domain][$code] ) )
564
		{
565
			$msg = sprintf( 'List type for domain "%1$s" and code "%2$s" not found', $domain, $code );
566
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg );
567
		}
568
569
		return $this->listTypeItems[$domain][$code];
570
	}
571
572
573
	/**
574
	 * Returns the product variants of a selection product that match the given attributes.
575
	 *
576
	 * @param \Aimeos\MShop\Product\Item\Iface $productItem Product item including sub-products
577
	 * @param array $variantAttributeIds IDs for the variant-building attributes
578
	 * @param array $domains Names of the domain items that should be fetched too
579
	 * @return array List of products matching the given attributes
580
	 */
581
	protected function getProductVariants( \Aimeos\MShop\Product\Item\Iface $productItem, array $variantAttributeIds,
582
			array $domains = array( 'attribute', 'media', 'price', 'text' ) )
583
	{
584
		$subProductIds = [];
585
		foreach( $productItem->getRefItems( 'product', 'default', 'default' ) as $item ) {
586
			$subProductIds[] = $item->getId();
587
		}
588
589
		if( count( $subProductIds ) === 0 ) {
590
			return [];
591
		}
592
593
		$productManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product' );
594
		$search = $productManager->createSearch( true );
595
596
		$expr = array(
597
			$search->compare( '==', 'product.id', $subProductIds ),
598
			$search->getConditions(),
599
		);
600
601
		if( count( $variantAttributeIds ) > 0 )
602
		{
603
			foreach( $variantAttributeIds as $key => $id ) {
604
				$variantAttributeIds[$key] = (string) $id;
605
			}
606
607
			$listTypeItem = $this->getProductListTypeItem( 'attribute', 'variant' );
608
609
			$param = array( 'attribute', $listTypeItem->getId(), $variantAttributeIds );
610
			$cmpfunc = $search->createFunction( 'product.contains', $param );
611
612
			$expr[] = $search->compare( '==', $cmpfunc, count( $variantAttributeIds ) );
613
		}
614
615
		$search->setConditions( $search->combine( '&&', $expr ) );
616
617
		return $productManager->searchItems( $search, $domains );
618
	}
619
620
621
	/**
622
	 * Returns the value of an array or the default value if it's not available.
623
	 *
624
	 * @param array $values Associative list of key/value pairs
625
	 * @param string $name Name of the key to return the value for
626
	 * @param mixed $default Default value if no value is available for the given name
627
	 * @return mixed Value from the array or default value
628
	 */
629
	protected function getValue( array $values, $name, $default = null )
630
	{
631
		if( isset( $values[$name] ) ) {
632
			return $values[$name];
633
		}
634
635
		return $default;
636
	}
637
}
638