Passed
Push — master ( b5a62a...377249 )
by Aimeos
02:14
created

Select::getVariantDetails()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 70
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 27
dl 0
loc 70
rs 8.5546
c 0
b 0
f 0
cc 7
nc 7
nop 4

1 Method

Rating   Name   Duplication   Size   Complexity  
B Select::getArticle() 0 51 8

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2017-2018
6
 * @package Controller
7
 * @subpackage Frontend
8
 */
9
10
11
namespace Aimeos\Controller\Frontend\Basket\Decorator;
12
13
14
/**
15
 * Selection product handling
16
 *
17
 * @package Controller
18
 * @subpackage Frontend
19
 */
20
class Select
21
	extends \Aimeos\Controller\Frontend\Basket\Decorator\Base
22
	implements \Aimeos\Controller\Frontend\Basket\Iface, \Aimeos\Controller\Frontend\Common\Decorator\Iface
23
{
24
	/**
25
	 * Adds a product to the basket of the customer stored in the session
26
	 *
27
	 * @param \Aimeos\MShop\Product\Item\Iface $product Product to add including texts, media, prices, attributes, etc.
28
	 * @param integer $quantity Amount of products that should by added
29
	 * @param array $variant List of variant-building attribute IDs that identify an article in a selection product
30
	 * @param array $config List of configurable attribute IDs the customer has chosen from
31
	 * @param array $custom Associative list of attribute IDs as keys and arbitrary values that will be added to the ordered product
32
	 * @param string $stocktype Unique code of the stock type to deliver the products from
33
	 * @param string|null $supplier Unique supplier code the product is from
34
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Basket frontend object for fluent interface
35
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If the product isn't available
36
	 */
37
	public function addProduct( \Aimeos\MShop\Product\Item\Iface $product, $quantity = 1,
38
		array $variant = [], array $config = [], array $custom = [], $stocktype = 'default', $supplier = null )
39
	{
40
		if( $product->getType() !== 'select' )
41
		{
42
			$this->getController()->addProduct( $product, $quantity, $variant, $config, $custom, $stocktype, $supplier );
43
			return $this;
44
		}
45
46
		$attr = [];
47
		$prodId = $product->getId();
48
		$prices = $product->getRefItems( 'price', 'default', 'default' );
49
		$hidden = $product->getRefItems( 'attribute', null, 'hidden' );
50
51
		$orderBaseProductItem = \Aimeos\MShop::create( $this->getContext(), 'order/base/product' )->createItem();
52
		$orderBaseProductItem = $orderBaseProductItem->copyFrom( $product );
0 ignored issues
show
Bug introduced by
The method copyFrom() does not exist on Aimeos\MShop\Attribute\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

52
		/** @scrutinizer ignore-call */ 
53
  $orderBaseProductItem = $orderBaseProductItem->copyFrom( $product );

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...
53
54
		$product = $this->getArticle( $product, $variant );
55
		$orderBaseProductItem->setProductCode( $product->getCode() );
56
57
		$attributeMap = ['custom' => array_keys( $custom ), 'config' => array_keys( $config )];
58
		$this->checkListRef( [$prodId, $product->getId()], 'attribute', $attributeMap );
59
60
		if( ( $subprices = $product->getRefItems( 'price', 'default', 'default' ) ) !== [] ) {
61
			$prices = $subprices;
62
		}
63
64
		if( ( $mediaItems = $product->getRefItems( 'media', 'default', 'default' ) ) !== [] ) {
65
			$orderBaseProductItem->setMediaUrl( current( $mediaItems )->getPreview() );
66
		}
67
68
		$hidden += $product->getRefItems( 'attribute', null, 'hidden' );
69
70
		$orderProductAttrManager = \Aimeos\MShop::create( $this->getContext(), 'order/base/product/attribute' );
71
		$attributes = $product->getRefItems( 'attribute', null, 'variant' );
72
73
		foreach( $this->getAttributes( array_keys( $attributes ), ['text'] ) as $attrItem ) {
74
			$attr[] = $orderProductAttrManager->createItem()->copyFrom( $attrItem )->setType( 'variant' );
75
		}
76
77
		$custAttr = $this->getOrderProductAttributes( 'custom', array_keys( $custom ), $custom );
78
		$confAttr = $this->getOrderProductAttributes( 'config', array_keys( $config ), [], $config );
79
		$hideAttr = $this->getOrderProductAttributes( 'hidden', array_keys( $hidden ) );
80
81
		$orderBaseProductItem = $orderBaseProductItem->setQuantity( $quantity )
82
			->setAttributeItems( array_merge( $attr, $custAttr, $confAttr, $hideAttr ) )
83
			->setPrice( $this->calcPrice( $orderBaseProductItem, $prices, $quantity ) )
84
			->setStockType( $stocktype )->setSupplierCode( $supplier );
85
86
		$this->getController()->get()->addProduct( $orderBaseProductItem );
87
		$this->getController()->save();
88
89
		return $this;
90
	}
91
92
93
	/**
94
	 * Returns the variant attributes and updates the price list if necessary.
95
	 *
96
	 * @param \Aimeos\MShop\Product\Item\Iface $productItem Product item which is replaced if necessary
97
	 * @param array $variantAttributeIds List of product variant attribute IDs
98
	 * @return \Aimeos\MShop\Product\Item\Iface Product variant article
99
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If no product variant is found
100
	 */
101
	protected function getArticle( \Aimeos\MShop\Product\Item\Iface $productItem, array $variant )
102
	{
103
		$items = [];
104
		$context = $this->getContext();
105
106
		/** controller/frontend/basket/require-variant
107
		 * A variant of a selection product must be chosen
108
		 *
109
		 * Selection products normally consist of several article variants and
110
		 * by default exactly one article variant of a selection product can be
111
		 * put into the basket.
112
		 *
113
		 * By setting this option to false, the selection product including the
114
		 * chosen attributes (if any attribute values were selected) can be put
115
		 * into the basket as well. This makes it possible to get all articles
116
		 * or a subset of articles (e.g. all of a color) at once.
117
		 *
118
		 * This option replace the "client/html/basket/require-variant" setting.
119
		 *
120
		 * @param boolean True if a variant must be chosen, false if also the selection product with attributes can be added
121
		 * @since 2018.01
122
		 * @category Developer
123
		 * @category User
124
		 */
125
		$requireVariant = $context->getConfig()->get( 'controller/frontend/basket/require-variant', true );
126
127
		foreach( $productItem->getRefItems( 'product', 'default', 'default' ) as $item )
128
		{
129
			foreach( $variant as $id )
130
			{
131
				if( $item->getListItem( 'attribute', 'variant', $id ) === null ) {
132
					continue 2;
133
				}
134
			}
135
136
			$items[] = $item;
137
		}
138
139
		if( count( $items ) > 1 )
140
		{
141
			$msg = $context->getI18n()->dt( 'controller/frontend', 'No unique article found for selected attributes and product ID "%1$s"' );
142
			throw new \Aimeos\Controller\Frontend\Basket\Exception( sprintf( $msg, $productItem->getId() ) );
143
		}
144
145
		if( empty( $items ) && $requireVariant != false ) // count == 0
146
		{
147
			$msg = $context->getI18n()->dt( 'controller/frontend', 'No article found for selected attributes and product ID "%1$s"' );
148
			throw new \Aimeos\Controller\Frontend\Basket\Exception( sprintf( $msg, $productItem->getId() ) );
149
		}
150
151
		return current( $items ) ?: $productItem;
152
	}
153
}
154