Standard::addCoupon()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 30
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 30
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
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-2025
7
 * @package Controller
8
 * @subpackage Frontend
9
 */
10
11
12
namespace Aimeos\Controller\Frontend\Basket;
13
14
15
/**
16
 * Default implementation of the basket frontend controller.
17
 *
18
 * @package Controller
19
 * @subpackage Frontend
20
 */
21
class Standard
22
	extends Base
23
	implements Iface, \Aimeos\Controller\Frontend\Common\Iface
24
{
25
	/** controller/frontend/basket/name
26
	 * Class name of the used basket frontend controller implementation
27
	 *
28
	 * Each default frontend controller can be replace by an alternative imlementation.
29
	 * To use this implementation, you have to set the last part of the class
30
	 * name as configuration value so the controller factory knows which class it
31
	 * has to instantiate.
32
	 *
33
	 * For example, if the name of the default class is
34
	 *
35
	 *  \Aimeos\Controller\Frontend\Basket\Standard
36
	 *
37
	 * and you want to replace it with your own version named
38
	 *
39
	 *  \Aimeos\Controller\Frontend\Basket\Mybasket
40
	 *
41
	 * then you have to set the this configuration option:
42
	 *
43
	 *  controller/jobs/frontend/basket/name = Mybasket
44
	 *
45
	 * The value is the last part of your own class name and it's case sensitive,
46
	 * so take care that the configuration value is exactly named like the last
47
	 * part of the class name.
48
	 *
49
	 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
50
	 * characters are possible! You should always start the last part of the class
51
	 * name with an upper case character and continue only with lower case characters
52
	 * or numbers. Avoid chamel case names like "MyBasket"!
53
	 *
54
	 * @param string Last part of the class name
55
	 * @since 2014.03
56
	 * @category Developer
57
	 */
58
59
	/** controller/frontend/basket/decorators/excludes
60
	 * Excludes decorators added by the "common" option from the basket frontend controllers
61
	 *
62
	 * Decorators extend the functionality of a class by adding new aspects
63
	 * (e.g. log what is currently done), executing the methods of the underlying
64
	 * class only in certain conditions (e.g. only for logged in users) or
65
	 * modify what is returned to the caller.
66
	 *
67
	 * This option allows you to remove a decorator added via
68
	 * "controller/frontend/common/decorators/default" before they are wrapped
69
	 * around the frontend controller.
70
	 *
71
	 *  controller/frontend/basket/decorators/excludes = array( 'decorator1' )
72
	 *
73
	 * This would remove the decorator named "decorator1" from the list of
74
	 * common decorators ("\Aimeos\Controller\Frontend\Common\Decorator\*") added via
75
	 * "controller/frontend/common/decorators/default" for the basket frontend controller.
76
	 *
77
	 * @param array List of decorator names
78
	 * @since 2014.03
79
	 * @category Developer
80
	 * @see controller/frontend/common/decorators/default
81
	 * @see controller/frontend/basket/decorators/global
82
	 * @see controller/frontend/basket/decorators/local
83
	 */
84
85
	/** controller/frontend/basket/decorators/global
86
	 * Adds a list of globally available decorators only to the basket frontend controllers
87
	 *
88
	 * Decorators extend the functionality of a class by adding new aspects
89
	 * (e.g. log what is currently done), executing the methods of the underlying
90
	 * class only in certain conditions (e.g. only for logged in users) or
91
	 * modify what is returned to the caller.
92
	 *
93
	 * This option allows you to wrap global decorators
94
	 * ("\Aimeos\Controller\Frontend\Common\Decorator\*") around the frontend controller.
95
	 *
96
	 *  controller/frontend/basket/decorators/global = array( 'decorator1' )
97
	 *
98
	 * This would add the decorator named "decorator1" defined by
99
	 * "\Aimeos\Controller\Frontend\Common\Decorator\Decorator1" only to the frontend controller.
100
	 *
101
	 * @param array List of decorator names
102
	 * @since 2014.03
103
	 * @category Developer
104
	 * @see controller/frontend/common/decorators/default
105
	 * @see controller/frontend/basket/decorators/excludes
106
	 * @see controller/frontend/basket/decorators/local
107
	 */
108
109
	/** controller/frontend/basket/decorators/local
110
	 * Adds a list of local decorators only to the basket frontend controllers
111
	 *
112
	 * Decorators extend the functionality of a class by adding new aspects
113
	 * (e.g. log what is currently done), executing the methods of the underlying
114
	 * class only in certain conditions (e.g. only for logged in users) or
115
	 * modify what is returned to the caller.
116
	 *
117
	 * This option allows you to wrap local decorators
118
	 * ("\Aimeos\Controller\Frontend\Basket\Decorator\*") around the frontend controller.
119
	 *
120
	 *  controller/frontend/basket/decorators/local = array( 'decorator2' )
121
	 *
122
	 * This would add the decorator named "decorator2" defined by
123
	 * "\Aimeos\Controller\Frontend\Basket\Decorator\Decorator2" only to the frontend
124
	 * controller.
125
	 *
126
	 * @param array List of decorator names
127
	 * @since 2014.03
128
	 * @category Developer
129
	 * @see controller/frontend/common/decorators/default
130
	 * @see controller/frontend/basket/decorators/excludes
131
	 * @see controller/frontend/basket/decorators/global
132
	 */
133
134
	private \Aimeos\MShop\Common\Manager\Iface $manager;
135
	private string $type = 'default';
136
	private array $baskets = [];
137
138
139
	/**
140
	 * Initializes the frontend controller.
141
	 *
142
	 * @param \Aimeos\MShop\ContextIface $context Object storing the required instances for manaing databases
143
	 *  connections, logger, session, etc.
144
	 */
145
	public function __construct( \Aimeos\MShop\ContextIface $context )
146
	{
147
		parent::__construct( $context );
148
149
		$this->manager = \Aimeos\MShop::create( $context, 'order' );
150
	}
151
152
153
	/**
154
	 * Adds values like comments to the basket
155
	 *
156
	 * @param array $values Order values like comment
157
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
158
	 */
159
	public function add( array $values ) : Iface
160
	{
161
		$this->baskets[$this->type] = $this->get()->fromArray( $values );
162
		return $this;
163
	}
164
165
166
	/**
167
	 * Empties the basket and removing all products, addresses, services, etc.
168
	 *
169
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
170
	 */
171
	public function clear() : Iface
172
	{
173
		$this->baskets[$this->type] = $this->manager->create();
174
		$this->manager->setSession( $this->baskets[$this->type], $this->type );
175
176
		return $this;
177
	}
178
179
180
	/**
181
	 * Returns the basket object.
182
	 *
183
	 * @return \Aimeos\MShop\Order\Item\Iface Basket holding products, addresses and delivery/payment options
184
	 */
185
	public function get() : \Aimeos\MShop\Order\Item\Iface
186
	{
187
		if( !isset( $this->baskets[$this->type] ) )
188
		{
189
			$this->baskets[$this->type] = $this->manager->getSession( $this->type );
190
			$this->checkLocale( $this->baskets[$this->type]->locale(), $this->type );
191
		}
192
193
		return $this->baskets[$this->type];
194
	}
195
196
197
	/**
198
	 * Explicitly persists the basket content
199
	 *
200
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
201
	 */
202
	public function save() : Iface
203
	{
204
		if( isset( $this->baskets[$this->type] ) && $this->baskets[$this->type]->isModified() )
205
		{
206
			$this->baskets[$this->type]->setCustomerId( (string) $this->context()->user() );
207
			$this->manager->setSession( $this->baskets[$this->type], $this->type );
208
		}
209
210
		return $this;
211
	}
212
213
214
	/**
215
	 * Sets the new basket type
216
	 *
217
	 * @param string $type Basket type
218
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
219
	 */
220
	public function setType( string $type ) : Iface
221
	{
222
		$this->type = $type;
223
		return $this;
224
	}
225
226
227
	/**
228
	 * Creates a new order object from the current basket
229
	 *
230
	 * @return \Aimeos\MShop\Order\Item\Iface Order object including products, addresses and services
231
	 */
232
	public function store() : \Aimeos\MShop\Order\Item\Iface
233
	{
234
		$total = 0;
235
		$context = $this->context();
236
		$config = $context->config();
237
238
		/** controller/frontend/basket/limit-count
239
		 * Maximum number of orders within the time frame
240
		 *
241
		 * Creating new orders is limited to avoid abuse and mitigate denial of
242
		 * service attacks. The number of orders created within the time frame
243
		 * configured by "controller/frontend/basket/limit-seconds" are counted
244
		 * before a new order of the same user (either logged in or identified
245
		 * by the IP address) is created. If the number of orders is higher than
246
		 * the configured value, an error message will be shown to the user
247
		 * instead of creating a new order.
248
		 *
249
		 * @param integer Number of orders allowed within the time frame
250
		 * @since 2017.05
251
		 * @category Developer
252
		 * @see controller/frontend/basket/limit-seconds
253
		 */
254
		$count = $config->get( 'controller/frontend/basket/limit-count', 5 );
255
256
		/** controller/frontend/basket/limit-seconds
257
		 * Order limitation time frame in seconds
258
		 *
259
		 * Creating new orders is limited to avoid abuse and mitigate denial of
260
		 * service attacks. Within the configured time frame, only a limited
261
		 * number of orders can be created. All orders of the current user
262
		 * (either logged in or identified by the IP address) within the last X
263
		 * seconds are counted. If the total value is higher then the number
264
		 * configured in "controller/frontend/basket/limit-count", an error
265
		 * message will be shown to the user instead of creating a new order.
266
		 *
267
		 * @param integer Number of seconds to check orders within
268
		 * @since 2017.05
269
		 * @category Developer
270
		 * @see controller/frontend/basket/limit-count
271
		 */
272
		$seconds = $config->get( 'controller/frontend/basket/limit-seconds', 900 );
273
274
		$search = $this->manager->filter()->slice( 0, 0 );
275
		$expr = [
276
			$search->compare( '==', 'order.editor', $context->editor() ),
277
			$search->compare( '>=', 'order.ctime', date( 'Y-m-d H:i:s', time() - $seconds ) ),
278
		];
279
		$search->add( $search->and( $expr ) );
280
281
		$this->manager->search( $search, [], $total );
282
283
		if( $total >= $count )
284
		{
285
			$msg = $context->translate( 'controller/frontend', 'Temporary order limit reached' );
286
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg );
287
		}
288
289
290
		$basket = $this->get()->setCustomerId( (string) $context->user() )->finish()->check();
291
		$basket->setStatusDelivery( \Aimeos\MShop\Order\Item\Base::STAT_UNFINISHED )->setDateDelivery( null );
292
		$basket->setStatusPayment( \Aimeos\MShop\Order\Item\Base::PAY_UNFINISHED )->setDatePayment( null );
293
294
		$this->manager->begin();
295
		$this->manager->save( $basket );
296
		$this->manager->commit();
297
298
		$this->save(); // for reusing unpaid orders, might have side effects (!)
299
		$this->createSubscriptions( $basket );
300
301
		return $basket;
302
	}
303
304
305
	/**
306
	 * Returns the order object for the given ID
307
	 *
308
	 * @param string $id Unique ID of the order object
309
	 * @param array $ref References items that should be fetched too
310
	 * @param bool $default True to add default criteria (user logged in), false if not
311
	 * @return \Aimeos\MShop\Order\Item\Iface Order object including the given parts
312
	 */
313
	public function load( string $id, array $ref = ['order/address', 'order/coupon', 'order/product', 'order/service'],
314
		bool $default = true ) : \Aimeos\MShop\Order\Item\Iface
315
	{
316
		return $this->manager->get( $id, $ref, $default );
317
	}
318
319
320
	/**
321
	 * Adds a product to the basket of the customer stored in the session
322
	 *
323
	 * @param \Aimeos\MShop\Product\Item\Iface $product Product to add including texts, media, prices, attributes, etc.
324
	 * @param float $quantity Amount of products that should by added
325
	 * @param array $variant List of variant-building attribute IDs that identify an article in a selection product
326
	 * @param array $config List of configurable attribute IDs the customer has chosen from
327
	 * @param array $custom Associative list of attribute IDs as keys and arbitrary values that will be added to the ordered product
328
	 * @param string $stocktype Unique code of the stock type to deliver the products from
329
	 * @param string|null $siteId Unique ID of the site the product should be bought from or NULL for site the product is from
330
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
331
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If the product isn't available
332
	 */
333
	public function addProduct( \Aimeos\MShop\Product\Item\Iface $product, float $quantity = 1,
334
		array $variant = [], array $config = [], array $custom = [], string $stocktype = 'default', ?string $siteId = null ) : Iface
335
	{
336
		$quantity = $this->call( 'checkQuantity', $product, $quantity );
337
		$this->call( 'checkAttributes', [$product], 'custom', array_keys( $custom ) );
338
		$this->call( 'checkAttributes', [$product], 'config', array_keys( $config ) );
339
340
		$prices = $product->getRefItems( 'price', 'default', 'default' );
341
		$hidden = $product->getRefItems( 'attribute', null, 'hidden' );
342
343
		$custAttr = $this->call( 'getOrderProductAttributes', 'custom', array_keys( $custom ), $custom );
344
		$confAttr = $this->call( 'getOrderProductAttributes', 'config', array_keys( $config ), [], $config );
345
		$hideAttr = $this->call( 'getOrderProductAttributes', 'hidden', $hidden->keys()->toArray() );
346
347
		$orderBaseProductItem = \Aimeos\MShop::create( $this->context(), 'order/product' )
348
			->create()
349
			->copyFrom( $product )
350
			->setQuantity( $quantity )
351
			->setStockType( $stocktype )
352
			->setSiteId( $siteId ?: $product->getSiteId() )
353
			->setAttributeItems( array_merge( $custAttr, $confAttr, $hideAttr ) );
354
355
		$price = $this->call( 'calcPrice', $orderBaseProductItem, $prices, $quantity );
356
		$orderBaseProductItem
357
			->setPrice( $price )
358
			->setSiteId( $siteId ?: $price->getSiteId() )
359
			->setVendor( $this->getVendor( $siteId ?: $price->getSiteId() ) );
360
361
		$this->baskets[$this->type] = $this->get()->addProduct( $orderBaseProductItem );
362
		return $this->save();
363
	}
364
365
366
	/**
367
	 * Deletes a product item from the basket.
368
	 *
369
	 * @param int $position Position number (key) of the order product item
370
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
371
	 */
372
	public function deleteProduct( int $position ) : Iface
373
	{
374
		$product = $this->get()->getProduct( $position );
375
376
		if( $product->getFlags() === \Aimeos\MShop\Order\Item\Product\Base::FLAG_IMMUTABLE )
377
		{
378
			$msg = $this->context()->translate( 'controller/frontend', 'Basket item at position "%1$d" cannot be deleted manually' );
379
			throw new \Aimeos\Controller\Frontend\Basket\Exception( sprintf( $msg, $position ) );
380
		}
381
382
		$this->baskets[$this->type] = $this->get()->deleteProduct( $position );
383
		return $this->save();
384
	}
385
386
387
	/**
388
	 * Edits the quantity of a product item in the basket.
389
	 *
390
	 * @param int $position Position number (key) of the order product item
391
	 * @param float $quantity New quantiy of the product item
392
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
393
	 */
394
	public function updateProduct( int $position, float $quantity ) : Iface
395
	{
396
		$context = $this->context();
397
		$orderProduct = $this->get()->getProduct( $position );
398
399
		if( $orderProduct->getFlags() & \Aimeos\MShop\Order\Item\Product\Base::FLAG_IMMUTABLE )
400
		{
401
			$msg = $context->translate( 'controller/frontend', 'Basket item at position "%1$d" cannot be changed' );
402
			throw new \Aimeos\Controller\Frontend\Basket\Exception( sprintf( $msg, $position ) );
403
		}
404
405
		$manager = \Aimeos\MShop::create( $context, 'product' );
406
		$product = $manager->get( $orderProduct->getProductId(), ['attribute', 'catalog', 'price', 'text'], true );
407
		$product = \Aimeos\MShop::create( $context, 'rule' )->apply( $product, 'catalog' );
408
409
		$quantity = $this->call( 'checkQuantity', $product, $quantity );
410
		$price = $this->call( 'calcPrice', $orderProduct, $product->getRefItems( 'price', 'default', 'default' ), $quantity );
411
		$orderProduct = $orderProduct->setQuantity( $quantity )->setPrice( $price );
412
413
		$this->baskets[$this->type] = $this->get()->addProduct( $orderProduct, $position );
414
		return $this->save();
415
	}
416
417
418
	/**
419
	 * Adds the given coupon code and updates the basket.
420
	 *
421
	 * @param string $code Coupon code entered by the user
422
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
423
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception if the coupon code is invalid or not allowed
424
	 */
425
	public function addCoupon( string $code ) : Iface
426
	{
427
		$context = $this->context();
428
429
		/** controller/frontend/basket/coupon/allowed
430
		 * Number of coupon codes a customer is allowed to enter
431
		 *
432
		 * This configuration option enables shop owners to limit the number of coupon
433
		 * codes that can be added by a customer to his current basket. By default, only
434
		 * one coupon code is allowed per order.
435
		 *
436
		 * Coupon codes are valid until a payed order is placed by the customer. The
437
		 * "count" of the codes is decreased afterwards. If codes are not personalized
438
		 * the codes can be reused in the next order until their "count" reaches zero.
439
		 *
440
		 * @param integer Positive number of coupon codes including zero
441
		 * @since 2017.08
442
		 * @category User
443
		 * @category Developer
444
		 */
445
		$allowed = $context->config()->get( 'controller/frontend/basket/coupon/allowed', 1 );
446
447
		if( $allowed <= count( $this->get()->getCoupons() ) )
448
		{
449
			$msg = $context->translate( 'controller/frontend', 'Number of coupon codes exceeds the limit' );
450
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg );
451
		}
452
453
		$this->baskets[$this->type] = $this->get()->addCoupon( $code );
454
		return $this->save();
455
	}
456
457
458
	/**
459
	 * Removes the given coupon code and its effects from the basket.
460
	 *
461
	 * @param string $code Coupon code entered by the user
462
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
463
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception if the coupon code is invalid
464
	 */
465
	public function deleteCoupon( string $code ) : Iface
466
	{
467
		$this->baskets[$this->type] = $this->get()->deleteCoupon( $code );
468
		return $this->save();
469
	}
470
471
472
	/**
473
	 * Adds an address of the customer to the basket
474
	 *
475
	 * @param string $type Address type code like 'payment' or 'delivery'
476
	 * @param array $values Associative list of key/value pairs with address details
477
	 * @param int|null $position Position number (key) of the order address item to replace
478
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
479
	 */
480
	public function addAddress( string $type, array $values = [], ?int $position = null ) : Iface
481
	{
482
		foreach( $values as $key => $value )
483
		{
484
			if( is_scalar( $value ) ) {
485
				$values[$key] = trim( strip_tags( (string) $value ) ); // prevent XSS
486
			}
487
		}
488
489
		$context = $this->context();
490
		$address = \Aimeos\MShop::create( $context, 'order' )->createAddress()->fromArray( $values );
0 ignored issues
show
Bug introduced by
The method createAddress() does not exist on Aimeos\MShop\Common\Manager\Iface. Did you maybe mean create()? ( Ignorable by Annotation )

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

490
		$address = \Aimeos\MShop::create( $context, 'order' )->/** @scrutinizer ignore-call */ createAddress()->fromArray( $values );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
491
		$address->set( 'nostore', ( $values['nostore'] ?? false ) ? true : false );
492
493
		$this->baskets[$this->type] = $this->get()->addAddress( $address, $type, $position );
494
		return $this->save();
495
	}
496
497
498
	/**
499
	 * Removes the address of the given type and position if available
500
	 *
501
	 * @param string $type Address type code like 'payment' or 'delivery'
502
	 * @param int|null $position Position of the address in the list to remove
503
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
504
	 */
505
	public function deleteAddress( string $type, ?int $position = null ) : Iface
506
	{
507
		$this->baskets[$this->type] = $this->get()->deleteAddress( $type, $position );
508
		return $this->save();
509
	}
510
511
512
	/**
513
	 * Adds the delivery/payment service including the given configuration
514
	 *
515
	 * @param \Aimeos\MShop\Service\Item\Iface $service Service item selected by the customer
516
	 * @param array $config Associative list of key/value pairs with the options selected by the customer
517
	 * @param int|null $position Position of the service in the list to replace
518
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
519
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If given service attributes are invalid
520
	 */
521
	public function addService( \Aimeos\MShop\Service\Item\Iface $service, array $config = [], ?int $position = null ) : Iface
522
	{
523
		$basket = $this->get();
524
		$context = $this->context();
525
526
		$type = $service->getType();
527
		$code = $service->getCode();
528
529
		foreach( $basket->getService( $type ) as $pos => $ordService )
530
		{
531
			if( !$position && $ordService->getCode() === $code ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $position of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
532
				$position = $pos;
533
			}
534
		}
535
536
		$manager = \Aimeos\MShop::create( $context, 'service' );
537
		$provider = $manager->getProvider( $service, $type );
538
539
		$errors = $provider->checkConfigFE( $config );
540
		$unknown = array_diff_key( $config, $errors );
541
542
		if( count( $unknown ) > 0 )
543
		{
544
			$msg = $context->translate( 'controller/frontend', 'Unknown service attributes' );
545
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg, -1, null, $unknown );
546
		}
547
548
		if( count( array_filter( $errors ) ) > 0 )
549
		{
550
			$msg = $context->translate( 'controller/frontend', 'Invalid service attributes' );
551
			throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg, -1, null, array_filter( $errors ) );
552
		}
553
554
		// remove service rebate of original price
555
		$price = $provider->calcPrice( $this->get(), $config )->setRebate( '0.00' );
556
557
		$orderManager = \Aimeos\MShop::create( $context, 'order' );
558
559
		$orderServiceItem = $orderManager->createService()->copyFrom( $service )->setPrice( $price );
0 ignored issues
show
Bug introduced by
The method createService() does not exist on Aimeos\MShop\Common\Manager\Iface. Did you maybe mean create()? ( Ignorable by Annotation )

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

559
		$orderServiceItem = $orderManager->/** @scrutinizer ignore-call */ createService()->copyFrom( $service )->setPrice( $price );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
560
		$orderServiceItem = $provider->setConfigFE( $orderServiceItem, $config );
561
562
		$this->baskets[$this->type] = $basket->addService( $orderServiceItem, $type, $position );
563
		return $this->save();
564
	}
565
566
567
	/**
568
	 * Removes the delivery or payment service items from the basket
569
	 *
570
	 * @param string $type Service type code like 'payment' or 'delivery'
571
	 * @param int|null $position Position of the service in the list to remove
572
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
573
	 */
574
	public function deleteService( string $type, ?int $position = null ) : Iface
575
	{
576
		$this->baskets[$this->type] = $this->get()->deleteService( $type, $position );
577
		return $this->save();
578
	}
579
580
581
	/**
582
	 * Returns the manager used by the controller
583
	 *
584
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object
585
	 */
586
	protected function getManager() : \Aimeos\MShop\Common\Manager\Iface
587
	{
588
		return $this->manager;
589
	}
590
}
591