Passed
Push — master ( 29d5f6...586595 )
by Aimeos
04:48
created

lib/mshoplib/src/MShop/Service/Provider/Base.php (3 issues)

Labels
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), 2015-2018
7
 * @package MShop
8
 * @subpackage Service
9
 */
10
11
12
namespace Aimeos\MShop\Service\Provider;
13
14
15
/**
16
 * Abstract class for all service provider implementations with some default methods.
17
 *
18
 * @package MShop
19
 * @subpackage Service
20
 */
21
abstract class Base
22
{
23
	private $object;
24
	private $context;
25
	private $serviceItem;
26
	private $communication;
0 ignored issues
show
The private property $communication is not used, and could be removed.
Loading history...
27
	private $beGlobalConfig;
28
29
30
	/**
31
	 * Initializes the service provider object.
32
	 *
33
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object with required objects
34
	 * @param \Aimeos\MShop\Service\Item\Iface $serviceItem Service item with configuration for the provider
35
	 */
36
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Service\Item\Iface $serviceItem )
37
	{
38
		$this->context = $context;
39
		$this->serviceItem = $serviceItem;
40
	}
41
42
43
	/**
44
	 * Catch unknown methods
45
	 *
46
	 * @param string $name Name of the method
47
	 * @param array $param List of method parameter
48
	 * @throws \Aimeos\MShop\Common\Manager\Exception If method call failed
49
	 */
50
	public function __call( $name, array $param )
51
	{
52
		throw new \Aimeos\MShop\Service\Exception( sprintf( 'Unable to call method "%1$s"', $name ) );
53
	}
54
55
56
	/**
57
	 * Returns the price when using the provider.
58
	 * Usually, this is the lowest price that is available in the service item but can also be a calculated based on
59
	 * the basket content, e.g. 2% of the value as transaction cost.
60
	 *
61
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
62
	 * @return \Aimeos\MShop\Price\Item\Iface Price item containing the price, shipping, rebate
63
	 */
64
	public function calcPrice( \Aimeos\MShop\Order\Item\Base\Iface $basket )
65
	{
66
		$priceManager = \Aimeos\MShop\Factory::createManager( $this->context, 'price' );
67
		$prices = $this->serviceItem->getRefItems( 'price', 'default', 'default' );
68
69
		if( count( $prices ) > 0 ) {
70
			return $priceManager->getLowestPrice( $prices, 1 );
71
		}
72
73
		return $priceManager->createItem();
74
	}
75
76
77
	/**
78
	 * Checks the backend configuration attributes for validity.
79
	 *
80
	 * @param array $attributes Attributes added by the shop owner in the administraton interface
81
	 * @return array An array with the attribute keys as key and an error message as values for all attributes that are
82
	 * 	known by the provider but aren't valid resp. null for attributes whose values are OK
83
	 */
84
	public function checkConfigBE( array $attributes )
85
	{
86
		return [];
87
	}
88
89
90
	/**
91
	 * Checks the frontend configuration attributes for validity.
92
	 *
93
	 * @param array $attributes Attributes entered by the customer during the checkout process
94
	 * @return array An array with the attribute keys as key and an error message as values for all attributes that are
95
	 * 	known by the provider but aren't valid resp. null for attributes whose values are OK
96
	 */
97
	public function checkConfigFE( array $attributes )
98
	{
99
		return [];
100
	}
101
102
103
	/**
104
	 * Returns the configuration attribute definitions of the provider to generate a list of available fields and
105
	 * rules for the value of each field in the administration interface.
106
	 *
107
	 * @return array List of attribute definitions implementing \Aimeos\MW\Common\Critera\Attribute\Iface
108
	 */
109
	public function getConfigBE()
110
	{
111
		return [];
112
	}
113
114
115
	/**
116
	 * Returns the configuration attribute definitions of the provider to generate a list of available fields and
117
	 * rules for the value of each field in the frontend.
118
	 *
119
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
120
	 * @return array List of attribute definitions implementing \Aimeos\MW\Common\Critera\Attribute\Iface
121
	 */
122
	public function getConfigFE( \Aimeos\MShop\Order\Item\Base\Iface $basket )
123
	{
124
		return [];
125
	}
126
127
128
	/**
129
	 * Returns the service item which also includes the configuration for the service provider.
130
	 *
131
	 * @return \Aimeos\MShop\Service\Item\Iface Service item
132
	 */
133
	public function getServiceItem()
134
	{
135
		return $this->serviceItem;
136
	}
137
138
139
	/**
140
	 * Injects additional global configuration for the backend.
141
	 *
142
	 * It's used for adding additional backend configuration from the application
143
	 * like the URLs to redirect to.
144
	 *
145
	 * Supported redirect URLs are:
146
	 * - payment.url-success
147
	 * - payment.url-failure
148
	 * - payment.url-cancel
149
	 * - payment.url-update
150
	 *
151
	 * @param array $config Associative list of config keys and their value
152
	 */
153
	public function injectGlobalConfigBE( array $config )
154
	{
155
		$this->beGlobalConfig = $config;
156
	}
157
158
159
	/**
160
	 * Checks if payment provider can be used based on the basket content.
161
	 * Checks for country, currency, address, RMS, etc. -> in separate decorators
162
	 *
163
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
164
	 * @return boolean True if payment provider can be used, false if not
165
	 */
166
	public function isAvailable( \Aimeos\MShop\Order\Item\Base\Iface $basket )
167
	{
168
		return true;
169
	}
170
171
172
	/**
173
	 * Checks what features the payment provider implements.
174
	 *
175
	 * @param integer $what Constant from abstract class
176
	 * @return boolean True if feature is available in the payment provider, false if not
177
	 */
178
	public function isImplemented( $what )
179
	{
180
		return false;
181
	}
182
183
184
	/**
185
	 * Queries for status updates for the given order if supported.
186
	 *
187
	 * @param \Aimeos\MShop\Order\Item\Iface $order Order invoice object
188
	 */
189
	public function query( \Aimeos\MShop\Order\Item\Iface $order )
190
	{
191
		throw new \Aimeos\MShop\Service\Exception( sprintf( 'Method "%1$s" for provider not available', 'query' ) );
192
	}
193
194
195
	/**
196
	 * Injects the outer object into the decorator stack
197
	 *
198
	 * @param \Aimeos\MShop\Plugin\Provider\Iface $object First object of the decorator stack
199
	 * @return \Aimeos\MShop\Plugin\Provider\Iface Plugin object for chaining method calls
200
	 */
201
	public function setObject( \Aimeos\MShop\Plugin\Provider\Iface $object )
202
	{
203
		$this->object = $object;
204
		return $this;
205
	}
206
207
208
	/**
209
	 * Looks for new update files and updates the orders for which status updates were received.
210
	 * If batch processing of files isn't supported, this method can be empty.
211
	 *
212
	 * @return boolean True if the update was successful, false if async updates are not supported
213
	 * @throws \Aimeos\MShop\Service\Exception If updating one of the orders failed
214
	 */
215
	public function updateAsync()
216
	{
217
		return false;
218
	}
219
220
221
	/**
222
	 * Updates the order status sent by payment gateway notifications
223
	 *
224
	 * @param \Psr\Http\Message\ServerRequestInterface Request object
225
	 * @return \Psr\Http\Message\ResponseInterface Response object
226
	 */
227
	public function updatePush( \Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response )
228
	{
229
		return $response->withStatus( 501, 'Not implemented' );
230
	}
231
232
233
	/**
234
	 * Updates the orders for whose status updates have been received by the confirmation page
235
	 *
236
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object with parameters and request body
237
	 * @param \Aimeos\MShop\Order\Item\Iface $order Order item that should be updated
238
	 * @return \Aimeos\MShop\Order\Item\Iface Updated order item
239
	 * @throws \Aimeos\MShop\Service\Exception If updating the orders failed
240
	 */
241
	public function updateSync( \Psr\Http\Message\ServerRequestInterface $request, \Aimeos\MShop\Order\Item\Iface $order )
242
	{
243
		return $order;
244
	}
245
246
247
	/**
248
	 * Calculates the last date behind the given timestamp depending on the other paramters.
249
	 *
250
	 * This method is used to calculate the date for comparing the order date to
251
	 * if e.g. credit card payments should be captured or direct debit should be
252
	 * checked after the given amount of days from external payment providers.
253
	 * This method can calculate with business/working days only if requested
254
	 * and use the given list of public holidays to take them into account.
255
	 *
256
	 * @param integer $timestamp Timestamp to use as starting point for the backward calculation
257
	 * @param integer $skipdays Number of days to calculate backwards
258
	 * @param boolean $businessOnly True if only business days should be used for calculation, false if not
259
	 * @param string $publicHolidays Comma separated list of public holidays in YYYY-MM-DD format
260
	 * @return string Date in YYY-MM-DD format to be compared to the order date
261
	 * @throws \Aimeos\MShop\Service\Exception If the given holiday string is in the wrong format and can't be processed
262
	 */
263
	protected function calcDateLimit( $timestamp, $skipdays = 0, $businessOnly = false, $publicHolidays = '' )
264
	{
265
		$holidays = $this->getPublicHolidays( $publicHolidays );
266
267
		if( !empty( $holidays ) )
268
		{
269
			for( $i = 0; $i <= $skipdays; $i++ )
270
			{
271
				$date = date( 'Y-m-d', $timestamp - $i * 86400 );
272
273
				if( isset( $holidays[$date] ) ) {
274
					$skipdays++;
275
				}
276
			}
277
		}
278
279
		if( $businessOnly === true )
280
		{
281
			// adds days for weekends
282
			for( $i = 0; $i <= $skipdays; $i++ )
283
			{
284
				$ts = $timestamp - $i * 86400;
285
286
				if( date( 'N', $ts ) > 5 && !isset( $holidays[date( 'Y-m-d', $ts )] ) ) {
287
					$skipdays++;
288
				}
289
			}
290
		}
291
292
		return date( 'Y-m-d', $timestamp - $skipdays * 86400 );
293
	}
294
295
296
	/**
297
	 * Checks required fields and the types of the config array.
298
	 *
299
	 * @param array $config Config parameters
300
	 * @param array $attributes Attributes for the config array
301
	 * @return array An array with the attribute keys as key and an error message as values for all attributes that are
302
	 * 	known by the provider but aren't valid resp. null for attributes whose values are OK
303
	 */
304
	protected function checkConfig( array $config, array $attributes )
305
	{
306
		$errors = [];
307
308
		foreach( $config as $key => $def )
309
		{
310
			if( $def['required'] === true && ( !isset( $attributes[$key] ) || $attributes[$key] === '' ) )
311
			{
312
				$errors[$key] = sprintf( 'Configuration for "%1$s" is missing', $key );
313
				continue;
314
			}
315
316
			if( isset( $attributes[$key] ) )
317
			{
318
				switch( $def['type'] )
319
				{
320
					case 'boolean':
321
						if( !is_string( $attributes[$key] ) || $attributes[$key] !== '0' && $attributes[$key] !== '1' ) {
322
							$errors[$key] = sprintf( 'Not a true/false value' ); continue 2;
323
						}
324
						break;
325
					case 'string':
326
					case 'text':
327
						if( is_string( $attributes[$key] ) === false ) {
328
							$errors[$key] = sprintf( 'Not a string' ); continue 2;
329
						}
330
						break;
331
					case 'integer':
332
						if( ctype_digit( $attributes[$key] ) === false ) {
333
							$errors[$key] = sprintf( 'Not an integer number' ); continue 2;
334
						}
335
						break;
336
					case 'number':
337
						if( is_numeric( $attributes[$key] ) === false ) {
338
							$errors[$key] = sprintf( 'Not a number' ); continue 2;
339
						}
340
						break;
341
					case 'date':
342
						$pattern = '/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/';
343
						if( !is_string( $attributes[$key] ) || preg_match( $pattern, $attributes[$key] ) !== 1 ) {
344
							$errors[$key] = sprintf( 'Not a date' ); continue 2;
345
						}
346
						break;
347
					case 'datetime':
348
						$pattern = '/^[0-9]{4}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9](:[0-5][0-9])?$/';
349
						if( !is_string( $attributes[$key] ) || preg_match( $pattern, $attributes[$key] ) !== 1 ) {
350
							$errors[$key] = sprintf( 'Not a date and time' ); continue 2;
351
						}
352
						break;
353
					case 'time':
354
						$pattern = '/^([0-2])?[0-9]:[0-5][0-9](:[0-5][0-9])?$/';
355
						if( !is_string( $attributes[$key] ) || preg_match( $pattern, $attributes[$key] ) !== 1 ) {
356
							$errors[$key] = sprintf( 'Not a time' ); continue 2;
357
						}
358
						break;
359
					case 'list':
360
					case 'select':
361
						if( !is_array( $def['default'] ) || !isset( $def['default'][$attributes[$key]] )
362
							&& !in_array( $attributes[$key], $def['default'] )
363
						) {
364
							$errors[$key] = sprintf( 'Not a listed value' ); continue 2;
365
						}
366
						break;
367
					case 'map':
368
						if( !is_array( $attributes[$key] ) ) {
369
							$errors[$key] = sprintf( 'Not a key/value map' ); continue 2;
370
						}
371
						break;
372
					default:
373
						throw new \Aimeos\MShop\Service\Exception( sprintf( 'Invalid type "%1$s"', $def['type'] ) );
374
				}
375
			}
376
377
			$errors[$key] = null;
378
		}
379
380
		return $errors;
381
	}
382
383
384
	/**
385
	 * Returns the criteria attribute items for the backend configuration
386
	 *
387
	 * @return \Aimeos\MW\Criteria\Attribute\Iface[] List of criteria attribute items
388
	 */
389
	protected function getConfigItems( array $configList )
390
	{
391
		$list = [];
392
393
		foreach( $configList as $key => $config ) {
394
			$list[$key] = new \Aimeos\MW\Criteria\Attribute\Standard( $config );
395
		}
396
397
		return $list;
398
	}
399
400
401
	/**
402
	 * Returns the configuration value that matches one of the given keys.
403
	 *
404
	 * The config of the service item and (optionally) the global config
405
	 * is tested in the order of the keys. The first one that matches will
406
	 * be returned.
407
	 *
408
	 * @param array|string $keys Key name or list of key names that should be tested for in the order to test
409
	 * @param mixed $default Returned value if the key wasn't was found
410
	 * @return mixed Value of the first key that matches or null if none was found
411
	 */
412
	protected function getConfigValue( $keys, $default = null )
413
	{
414
		$srvconfig = $this->getServiceItem()->getConfig();
415
416
		foreach( (array) $keys as $key )
417
		{
418
			if( isset( $srvconfig[$key] ) ) {
419
				return $srvconfig[$key];
420
			}
421
422
			if( isset( $this->beGlobalConfig[$key] ) ) {
423
				return $this->beGlobalConfig[$key];
424
			}
425
		}
426
427
		return $default;
428
	}
429
430
431
	/**
432
	 * Returns the context item.
433
	 *
434
	 * @return \Aimeos\MShop\Context\Item\Iface Context item
435
	 */
436
	protected function getContext()
437
	{
438
		return $this->context;
439
	}
440
441
442
	/**
443
	 * Returns the calculated amount of the price item
444
	 *
445
	 * @param \Aimeos\MShop\Price\Item\Iface $price Price item
446
	 * @param boolean $costs Include costs per item
447
	 * @param boolean $tax Include tax
448
	 * @return string Formatted money amount
449
	 */
450
	protected function getAmount( \Aimeos\MShop\Price\Item\Iface $price, $costs = true, $tax = true )
451
	{
452
		$amount = $price->getValue();
453
454
		if( $costs === true ) {
455
			$amount += $price->getCosts();
456
		}
457
458
		if( $tax === true && $price->getTaxFlag() === false )
459
		{
460
			$tmp = clone $price;
461
462
			if( $costs === false )
463
			{
464
				$tmp->clear();
465
				$tmp->setValue( $price->getValue() );
466
				$tmp->setTaxRate( $price->getTaxRate() );
467
				$tmp->setQuantity( $price->getQuantity() );
468
			}
469
470
			$amount += $tmp->getTaxValue();
471
		}
472
473
		return number_format( $amount, 2, '.', '' );
474
	}
475
476
477
	/**
478
	 * Returns the first object of the decorator stack
479
	 *
480
	 * @return \Aimeos\MShop\Plugin\Provider\Iface First object of the decorator stack
481
	 */
482
	protected function getObject()
483
	{
484
		if( $this->object !== null ) {
485
			return $this->object;
486
		}
487
488
		return $this;
489
	}
490
491
492
	/**
493
	 * Returns the order item for the given ID.
494
	 *
495
	 * @param string $id Unique order ID
496
	 * @return \Aimeos\MShop\Order\Item\Iface $item Order object
497
	 */
498
	protected function getOrder( $id )
499
	{
500
		$manager = \Aimeos\MShop\Factory::createManager( $this->context, 'order' );
501
502
		$search = $manager->createSearch( true );
503
		$expr = [
504
			$search->getConditions(),
505
			$search->compare( '==', 'order.id', $id ),
506
			$search->compare( '==', 'order.base.service.code', $this->serviceItem->getCode() ),
507
		];
508
		$search->setConditions( $search->combine( '&&', $expr ) );
509
510
		$result = $manager->searchItems( $search );
511
512
		if( ( $item = reset( $result ) ) === false ) {
513
			throw new \Aimeos\MShop\Service\Exception( sprintf( 'No order for ID "%1$s" found', $id ) );
514
		}
515
516
		return $item;
517
	}
518
519
520
	/**
521
	 * Returns the base order which is equivalent to the basket.
522
	 *
523
	 * @param string $baseId Order base ID stored in the order item
524
	 * @param integer $parts Bitmap of the basket parts that should be loaded
525
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Basket, optional with addresses, products, services and coupons
526
	 */
527
	protected function getOrderBase( $baseId, $parts = \Aimeos\MShop\Order\Item\Base\Base::PARTS_SERVICE )
528
	{
529
		return \Aimeos\MShop\Factory::createManager( $this->context, 'order/base' )->load( $baseId, $parts );
530
	}
531
532
533
	/**
534
	 * Saves the order item.
535
	 *
536
	 * @param \Aimeos\MShop\Order\Item\Iface $item Order object
537
	 * @return \Aimeos\MShop\Order\Item\Iface Order object including the generated ID
538
	 */
539
	protected function saveOrder( \Aimeos\MShop\Order\Item\Iface $item )
540
	{
541
		return \Aimeos\MShop\Factory::createManager( $this->context, 'order' )->saveItem( $item );
542
	}
543
544
545
	/**
546
	 * Returns the service related data from the customer account if available
547
	 *
548
	 * @param string $customerId Unique customer ID the service token belongs to
549
	 * @param string $type Type of the value that should be returned
550
	 * @return string|null Service data or null if none is available
551
	 */
552
	protected function getCustomerData( $customerId, $type )
553
	{
554
		if( $customerId == null ) {
555
			return;
556
		}
557
558
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' );
559
		$item = $manager->getItem( $customerId, ['service'] );
560
		$serviceId = $this->getServiceItem()->getId();
561
562
		if( ( $listItem = $item->getListItem( 'service', 'default', $serviceId ) ) !== null )
1 ignored issue
show
The method getListItem() does not exist on Aimeos\MShop\Common\Item\Iface. It seems like you code against a sub-type of Aimeos\MShop\Common\Item\Iface such as Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Price\Item\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Catalog\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Attribute\Item\Standard or Aimeos\MShop\Catalog\Item\Standard or Aimeos\MShop\Customer\Item\Base or Aimeos\MShop\Media\Item\Standard or Aimeos\MShop\Text\Item\Standard or Aimeos\MShop\Service\Item\Standard or Aimeos\MShop\Common\Item\ListRef\Base or Aimeos\MShop\Price\Item\Base or Aimeos\MShop\Supplier\Item\Standard or Aimeos\MShop\Product\Item\Standard or Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Price\Item\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Catalog\Item\Iface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

562
		if( ( $listItem = $item->/** @scrutinizer ignore-call */ getListItem( 'service', 'default', $serviceId ) ) !== null )
Loading history...
563
		{
564
			$config = $listItem->getConfig();
565
			return ( isset( $config[$type] ) ? $config[$type] : null );
566
		}
567
	}
568
569
570
	/**
571
	 * Saves the base order which is equivalent to the basket and its dependent objects.
572
	 *
573
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $base Order base object with associated items
574
	 * @param integer $parts Bitmap of the basket parts that should be stored
575
	 */
576
	protected function saveOrderBase( \Aimeos\MShop\Order\Item\Base\Iface $base, $parts = \Aimeos\MShop\Order\Item\Base\Base::PARTS_SERVICE )
577
	{
578
		\Aimeos\MShop\Factory::createManager( $this->context, 'order/base' )->store( $base, $parts );
579
	}
580
581
582
	/**
583
	 * Sets the attributes in the given service item.
584
	 *
585
	 * @param \Aimeos\MShop\Order\Item\Base\Service\Iface $orderServiceItem Order service item that will be added to the basket
586
	 * @param array $attributes Attribute key/value pairs entered by the customer during the checkout process
587
	 * @param string $type Type of the configuration values (delivery or payment)
588
	 */
589
	protected function setAttributes( \Aimeos\MShop\Order\Item\Base\Service\Iface $orderServiceItem, array $attributes, $type )
590
	{
591
		$manager = \Aimeos\MShop\Factory::createManager( $this->context, 'order/base/service/attribute' );
592
593
		foreach( $attributes as $key => $value )
594
		{
595
			$item = $manager->createItem();
596
			$item->setCode( $key );
597
			$item->setValue( $value );
598
			$item->setType( $type );
599
600
			$orderServiceItem->setAttributeItem( $item );
601
		}
602
	}
603
604
605
	/**
606
	 * Adds the service data to the customer account if available
607
	 *
608
	 * @param string $customerId Unique customer ID the service token belongs to
609
	 * @param string $type Type of the value that should be added
610
	 * @param string|array $data Service data to store
611
	 */
612
	protected function setCustomerData( $customerId, $type, $data )
613
	{
614
		if( $customerId == null ) {
615
			return;
616
		}
617
618
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' );
619
		$item = $manager->getItem( $customerId, ['service'] );
620
		$serviceId = $this->getServiceItem()->getId();
621
622
		if( ( $listItem = $item->getListItem( 'service', 'default', $serviceId, false ) ) === null )
623
		{
624
			$listManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/lists' );
625
			$listTypeManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/lists/type' );
626
627
			$listItem = $listManager->createItem();
628
			$listItem->setTypeId( $listTypeManager->findItem( 'default', [], 'service' )->getId() );
629
			$listItem->setRefId( $serviceId );
630
		}
631
632
		$listItem->setConfig( array_merge( $listItem->getConfig(), [$type => $data] ) );
633
		$manager->saveItem( $item->addListItem( 'service', $listItem ) );
1 ignored issue
show
The method addListItem() does not exist on Aimeos\MShop\Common\Item\Iface. It seems like you code against a sub-type of Aimeos\MShop\Common\Item\Iface such as Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Price\Item\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Catalog\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Attribute\Item\Standard or Aimeos\MShop\Catalog\Item\Standard or Aimeos\MShop\Customer\Item\Base or Aimeos\MShop\Media\Item\Standard or Aimeos\MShop\Text\Item\Standard or Aimeos\MShop\Service\Item\Standard or Aimeos\MShop\Common\Item\ListRef\Base or Aimeos\MShop\Price\Item\Base or Aimeos\MShop\Supplier\Item\Standard or Aimeos\MShop\Product\Item\Standard or Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Price\Item\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Catalog\Item\Iface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

633
		$manager->saveItem( $item->/** @scrutinizer ignore-call */ addListItem( 'service', $listItem ) );
Loading history...
634
	}
635
636
637
	/**
638
	 * Returns the public holidays in ISO format
639
	 *
640
	 * @param string $list Comma separated list of public holidays in YYYY-MM-DD format
641
	 * @return array List of dates in YYYY-MM-DD format
642
	 * @throws \Aimeos\MShop\Service\Exception If the given holiday string is in the wrong format and can't be processed
643
	 */
644
	private function getPublicHolidays( $list )
645
	{
646
		$holidays = [];
647
648
		if( is_string( $list ) && $list !== '' )
649
		{
650
			$holidays = explode( ',', str_replace( ' ', '', $list ) );
651
652
			if( sort( $holidays ) === false ) {
653
				throw new \Aimeos\MShop\Service\Exception( sprintf( 'Unable to sort public holidays: "%1$s"', $list ) );
654
			}
655
656
			$holidays = array_flip( $holidays );
657
		}
658
659
		return $holidays;
660
	}
661
}
662