Completed
Push — master ( a3e1ac...484d40 )
by Aimeos
02:36
created

Standard::process()   C

Complexity

Conditions 9
Paths 68

Size

Total Lines 89
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 89
rs 5.2228
c 0
b 0
f 0
cc 9
eloc 40
nc 68
nop 2

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), 2015-2016
6
 * @package Controller
7
 * @subpackage Common
8
 */
9
10
11
namespace Aimeos\Controller\Common\Product\Import\Csv\Processor\Catalog;
12
13
14
/**
15
 * Catalog 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
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
Coding Style introduced by
Expected 0 spaces between "Base" and comma; 1 found
Loading history...
22
	implements \Aimeos\Controller\Common\Product\Import\Csv\Processor\Iface
0 ignored issues
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
23
{
24
	/** controller/common/product/import/csv/processor/catalog/name
25
	 * Name of the catalog processor implementation
26
	 *
27
	 * Use "Myname" if your class is named "\Aimeos\Controller\Common\Product\Import\Csv\Processor\Catalog\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
38
39
	/**
40
	 * Initializes the object
41
	 *
42
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
43
	 * @param array $mapping Associative list of field position in CSV as key and domain item key as value
44
	 * @param \Aimeos\Controller\Common\Product\Import\Csv\Processor\Iface $object Decorated processor
45
	 */
46
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context, array $mapping,
47
		\Aimeos\Controller\Common\Product\Import\Csv\Processor\Iface $object = null )
48
	{
49
		parent::__construct( $context, $mapping, $object );
50
51
		/** controller/common/product/import/csv/processor/catalog/listtypes
52
		 * Names of the catalog list types that are updated or removed
53
		 *
54
		 * If you want to associate product items to categories manually via the
55
		 * administration interface and don't want these to be touched during the
56
		 * import, you can specify the catalog list types for these products
57
		 * that shouldn't be updated or removed.
58
		 *
59
		 * @param array|null List of catalog list type names or null for all
60
		 * @since 2015.05
61
		 * @category Developer
62
		 * @category User
63
		 * @see controller/common/product/import/csv/domains
64
		 * @see controller/common/product/import/csv/processor/attribute/listtypes
65
		 * @see controller/common/product/import/csv/processor/media/listtypes
66
		 * @see controller/common/product/import/csv/processor/price/listtypes
67
		 * @see controller/common/product/import/csv/processor/product/listtypes
68
		 * @see controller/common/product/import/csv/processor/text/listtypes
69
		 */
70
		$this->listTypes = $context->getConfig()->get( 'controller/common/product/import/csv/processor/catalog/listtypes' );
71
72
		$this->cache = $this->getCache( 'catalog' );
73
	}
74
75
76
	/**
77
	 * Saves the product related data to the storage
78
	 *
79
	 * @param \Aimeos\MShop\Product\Item\Iface $product Product item with associated items
80
	 * @param array $data List of CSV fields with position as key and data as value
81
	 * @return array List of data which hasn't been imported
82
	 */
83
	public function process( \Aimeos\MShop\Product\Item\Iface $product, array $data )
84
	{
85
		$context = $this->getContext();
86
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'catalog' );
87
		$listManager = \Aimeos\MShop\Factory::createManager( $context, 'catalog/lists' );
88
89
		/** controller/common/product/import/csv/separator
90
		 * Single separator character for multiple entries in one field of the import file
91
		 *
92
		 * The product importer is able split the content of a field from the import
93
		 * file into several entries based on the given separator character. Thus,
94
		 * you can create more compact import files and handle a variable range
95
		 * of entries better. The default separator character is a new line.
96
		 *
97
		 * '''Caution:''' The separator character must not be part of any entry
98
		 * in the field. Otherwise, you will get invalid entries and the importer
99
		 * may fail!
100
		 *
101
		 * @param string Single separator character
102
		 * @since 2015.07
103
		 * @category User
104
		 * @category Developer
105
		 * @see controller/common/product/import/csv/domains
106
		 */
107
		$separator = $context->getConfig()->get( 'controller/common/product/import/csv/separator', "\n" );
108
109
		$manager->begin();
110
111
		try
112
		{
113
			$listMap = array();
114
			$prodid = $product->getId();
115
			$map = $this->getMappedChunk( $data );
116
			$listItems = $this->getListItems( $prodid, $this->listTypes );
117
118
			foreach( $listItems as $listItem ) {
119
				$listMap[ $listItem->getParentId() ][ $listItem->getType() ] = $listItem;
120
			}
121
122
			foreach( $map as $pos => $list )
123
			{
124
				if( $this->checkEntry( $list ) === false ) {
125
					continue;
126
				}
127
128
				$codes = explode( $separator, $list['catalog.code'] );
129
				$type = ( isset( $list['catalog.lists.type'] ) ? $list['catalog.lists.type'] : 'default' );
130
131
				foreach( $codes as $code )
132
				{
133
					if( ( $catid = $this->cache->get( $code ) ) === null )
134
					{
135
						$msg = 'No category for code "%1$s" available when importing product with code "%2$s"';
136
						throw new \Aimeos\Controller\Jobs\Exception( sprintf( $msg, $code, $product->getCode() ) );
137
					}
138
139
					$list['catalog.lists.typeid'] = $this->getTypeId( 'catalog/lists/type', 'product', $type );
140
					$list['catalog.lists.parentid'] = $catid;
141
					$list['catalog.lists.refid'] = $prodid;
142
					$list['catalog.lists.domain'] = 'product';
143
144
					if( isset( $listMap[$catid][$type] ) )
145
					{
146
						$listItem = $listMap[$catid][$type];
147
						unset( $listItems[ $listItem->getId() ] );
148
					}
149
					else
150
					{
151
						$listItem = $listManager->createItem();
152
					}
153
154
					$listItem->fromArray( $this->addListItemDefaults( $list, $pos++ ) );
155
					$listManager->saveItem( $listItem );
156
				}
157
			}
158
159
			$listManager->deleteItems( array_keys( $listItems ) );
160
			$remaining = $this->getObject()->process( $product, $data );
161
162
			$manager->commit();
163
		}
164
		catch( \Exception $e )
165
		{
166
			$manager->rollback();
167
			throw $e;
168
		}
169
170
		return $remaining;
171
	}
172
173
174
	/**
175
	 * Adds the list item default values and returns the resulting array
176
	 *
177
	 * @param array $list Associative list of domain item keys and their values, e.g. "catalog.lists.status" => 1
178
	 * @param integer $pos Computed position of the list item in the associated list of items
179
	 * @return array Given associative list enriched by default values if they were not already set
180
	 */
181
	protected function addListItemDefaults( array $list, $pos )
182
	{
183
		if( !isset( $list['catalog.lists.position'] ) ) {
184
			$list['catalog.lists.position'] = $pos;
185
		}
186
187
		if( !isset( $list['catalog.lists.status'] ) ) {
188
			$list['catalog.lists.status'] = 1;
189
		}
190
191
		return $list;
192
	}
193
194
195
	/**
196
	 * Checks if the entry from the mapped data is valid
197
	 *
198
	 * @param array $list Associative list of key/value pairs from the mapped data
199
	 * @return boolean True if the entry is valid, false if not
200
	 */
201
	protected function checkEntry( array $list )
202
	{
203
		if( !isset( $list['catalog.code'] ) || $list['catalog.code'] === '' || isset( $list['catalog.lists.type'] )
204
			&& $this->listTypes !== null && !in_array( $list['catalog.lists.type'], (array) $this->listTypes )
205
		) {
206
			return false;
207
		}
208
209
		return true;
210
	}
211
212
213
	/**
214
	 * Returns the catalog list items for the given category and product ID
215
	 *
216
	 * @param string $prodid Unique product ID
217
	 * @param array|null $types List of catalog list types
218
	 * @return array List of catalog list items
219
	 */
220
	protected function getListItems( $prodid, $types )
221
	{
222
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog/lists' );
223
		$search = $manager->createSearch();
224
225
		$expr = array(
226
			$search->compare( '==', 'catalog.lists.domain', 'product' ),
227
			$search->compare( '==', 'catalog.lists.refid', $prodid ),
228
		);
229
230
		if( $types !== null ) {
231
			$expr[] = $search->compare( '==', 'catalog.lists.type.code', $types );
232
		}
233
234
		$search->setConditions( $search->combine( '&&', $expr ) );
235
		$search->setSortations( array( $search->sort( '+', 'catalog.lists.position' ) ) );
236
		$search->setSlice( 0, 0x7FFFFFFF );
237
238
		return $manager->searchItems( $search );
239
	}
240
}
241