Passed
Branch master (c3c77b)
by Aimeos
02:17
created

Standard   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 202
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 71
dl 0
loc 202
rs 10
c 0
b 0
f 0
wmc 19

4 Methods

Rating   Name   Duplication   Size   Complexity  
A checkEntry() 0 19 6
B process() 0 52 7
A getAttributeItem() 0 19 2
A __construct() 0 56 4
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2018
6
 * @package Controller
7
 * @subpackage Common
8
 */
9
10
11
namespace Aimeos\Controller\Common\Product\Import\Csv\Processor\Attribute;
12
13
14
/**
15
 * Attribute processor for CSV imports
16
 *
17
 * @package Controller
18
 * @subpackage Common
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Common\Product\Import\Csv\Processor\Base
22
	implements \Aimeos\Controller\Common\Product\Import\Csv\Processor\Iface
23
{
24
	/** controller/common/product/import/csv/processor/attribute/name
25
	 * Name of the attribute processor implementation
26
	 *
27
	 * Use "Myname" if your class is named "\Aimeos\Controller\Common\Product\Import\Csv\Processor\Attribute\Myname".
28
	 * The name is case-sensitive and you should avoid camel case names like "MyName".
29
	 *
30
	 * @param string Last part of the processor class name
31
	 * @since 2015.10
32
	 * @category Developer
33
	 */
34
35
	private $cache;
36
	private $listTypes;
37
	private $types = [];
38
39
40
	/**
41
	 * Initializes the object
42
	 *
43
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
44
	 * @param array $mapping Associative list of field position in CSV as key and domain item key as value
45
	 * @param \Aimeos\Controller\Common\Product\Import\Csv\Processor\Iface $object Decorated processor
46
	 */
47
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context, array $mapping,
48
		\Aimeos\Controller\Common\Product\Import\Csv\Processor\Iface $object = null )
49
	{
50
		parent::__construct( $context, $mapping, $object );
51
52
		/** controller/common/product/import/csv/processor/attribute/listtypes
53
		 * Names of the product list types for attributes that are updated or removed
54
		 *
55
		 * If you want to associate attribute items manually via the administration
56
		 * interface to products and don't want these to be touched during the
57
		 * import, you can specify the product list types for these attributes
58
		 * that shouldn't be updated or removed.
59
		 *
60
		 * @param array|null List of product list type names or null for all
61
		 * @since 2015.05
62
		 * @category Developer
63
		 * @category User
64
		 * @see controller/common/product/import/csv/domains
65
		 * @see controller/common/product/import/csv/processor/catalog/listtypes
66
		 * @see controller/common/product/import/csv/processor/media/listtypes
67
		 * @see controller/common/product/import/csv/processor/product/listtypes
68
		 * @see controller/common/product/import/csv/processor/price/listtypes
69
		 * @see controller/common/product/import/csv/processor/text/listtypes
70
		 */
71
		$key = 'controller/common/product/import/csv/processor/attribute/listtypes';
72
		$this->listTypes = $context->getConfig()->get( $key );
73
74
		if( $this->listTypes === null )
75
		{
76
			$this->listTypes = [];
77
			$manager = \Aimeos\MShop::create( $context, 'product/lists/type' );
78
79
			$search = $manager->createSearch()->setSlice( 0, 0x7fffffff );
80
			$search->setConditions( $search->compare( '==', 'product.lists.type.domain', 'attribute' ) );
81
82
			foreach( $manager->searchItems( $search ) as $item ) {
83
				$this->listTypes[$item->getCode()] = $item->getCode();
84
			}
85
		}
86
		else
87
		{
88
			$this->listTypes = array_flip( $this->listTypes );
89
		}
90
91
92
		$manager = \Aimeos\MShop::create( $context, 'attribute/type' );
93
94
		$search = $manager->createSearch()->setSlice( 0, 0x7fffffff );
95
		$search->setConditions( $search->compare( '==', 'attribute.type.domain', 'product' ) );
96
97
		foreach( $manager->searchItems( $search ) as $item ) {
98
			$this->types[$item->getCode()] = $item->getCode();
99
		}
100
101
102
		$this->cache = $this->getCache( 'attribute' );
103
	}
104
105
106
	/**
107
	 * Saves the attribute related data to the storage
108
	 *
109
	 * @param \Aimeos\MShop\Product\Item\Iface $product Product item with associated items
110
	 * @param array $data List of CSV fields with position as key and data as value
111
	 * @return array List of data which hasn't been imported
112
	 */
113
	public function process( \Aimeos\MShop\Product\Item\Iface $product, array $data )
114
	{
115
		$context = $this->getContext();
116
		$listManager = \Aimeos\MShop::create( $context, 'product/lists' );
117
		$separator = $context->getConfig()->get( 'controller/common/product/import/csv/separator', "\n" );
118
119
		$listMap = [];
120
		$map = $this->getMappedChunk( $data, $this->getMapping() );
121
		$listItems = $product->getListItems( 'attribute', $this->listTypes );
122
123
		foreach( $listItems as $listItem )
124
		{
125
			if( ( $refItem = $listItem->getRefItem() ) !== null ) {
126
				$listMap[ $refItem->getCode() ][ $listItem->getType() ] = $listItem;
127
			}
128
		}
129
130
		foreach( $map as $pos => $list )
131
		{
132
			if( $this->checkEntry( $list ) === false ) {
133
				continue;
134
			}
135
136
			$codes = explode( $separator, $this->getValue( $list, 'attribute.code', '' ) );
137
138
			foreach( $codes as $code )
139
			{
140
				$code = trim( $code );
141
				$listtype = $this->getValue( $list, 'product.lists.type', 'default' );
142
143
				if( isset( $listMap[$code][$listtype] ) )
144
				{
145
					$listItem = $listMap[$code][$listtype];
146
					unset( $listItems[ $listItem->getId() ] );
147
				}
148
				else
149
				{
150
					$listItem = $listManager->createItem()->setType( $listtype );
151
				}
152
153
				$listItem = $listItem->setPosition( $pos )->fromArray( $list );
154
155
				$attrItem = $this->getAttributeItem( $code, $this->getValue( $list, 'attribute.type' ) );
156
				$attrItem = $attrItem->setCode( $code )->fromArray( $list );
157
158
				$product->addListItem( 'attribute', $listItem, $attrItem );
159
			}
160
		}
161
162
		$product->deleteListItems( $listItems );
163
164
		return $this->getObject()->process( $product, $data );
165
	}
166
167
168
	/**
169
	 * Checks if the entry from the mapped data is valid
170
	 *
171
	 * @param array $list Associative list of key/value pairs from the mapped data
172
	 * @return boolean True if the entry is valid, false if not
173
	 */
174
	protected function checkEntry( array $list )
175
	{
176
		if( $this->getValue( $list, 'attribute.code' ) === null ) {
177
			return false;
178
		}
179
180
		if( ( $type = $this->getValue( $list, 'product.lists.type' ) ) && !isset( $this->listTypes[$type] ) )
181
		{
182
			$msg = sprintf( 'Invalid type "%1$s" (%2$s)', $type, 'product list' );
183
			throw new \Aimeos\Controller\Common\Exception( $msg );
184
		}
185
186
		if( ( $type = $this->getValue( $list, 'attribute.type' ) ) && !isset( $this->types[$type] ) )
187
		{
188
			$msg = sprintf( 'Invalid type "%1$s" (%2$s)', $type, 'attribute' );
189
			throw new \Aimeos\Controller\Common\Exception( $msg );
190
		}
191
192
		return true;
193
	}
194
195
196
	/**
197
	 * Returns the attribute item for the given code and type
198
	 *
199
	 * @param string $code Attribute code
200
	 * @param string $type Attribute type
201
	 * @return \Aimeos\MShop\Attribute\Item\Iface Attribute item object
202
	 */
203
	protected function getAttributeItem( $code, $type )
204
	{
205
		if( ( $item = $this->cache->get( $code, $type ) ) === null )
206
		{
207
			$manager = \Aimeos\MShop::create( $this->getContext(), 'attribute' );
208
209
			$item = $manager->createItem();
210
			$item->setType( $type );
211
			$item->setDomain( 'product' );
212
			$item->setLabel( $code );
213
			$item->setCode( $code );
214
			$item->setStatus( 1 );
215
216
			$item = $manager->saveItem( $item );
217
218
			$this->cache->set( $item );
219
		}
220
221
		return $item;
222
	}
223
}
224