Completed
Pull Request — master (#25)
by
unknown
02:44
created

Standard::process()   B

Complexity

Conditions 8
Paths 48

Size

Total Lines 90
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 40
c 1
b 0
f 0
nc 48
nop 2
dl 0
loc 90
rs 8.0355

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-2020
6
 * @package Controller
7
 * @subpackage Common
8
 */
9
10
11
namespace Aimeos\Controller\Common\Product\Import\Csv\Processor\Supplier;
12
13
14
/**
15
 * Supplier 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/supplier/name
25
	 * Name of the supplier processor implementation
26
	 *
27
	 * Use "Myname" if your class is named "\Aimeos\Controller\Common\Product\Import\Csv\Processor\Supplier\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 2020.07
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/supplier/listtypes
52
		 * Names of the supplier 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 supplier list types for these products
57
		 * that shouldn't be updated or removed.
58
		 *
59
		 * @param array|null List of supplier list type names or null for all
60
		 * @since 2020.07
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
		$key = 'controller/common/product/import/csv/processor/supplier/listtypes';
71
		$this->listTypes = $context->getConfig()->get( $key );
72
73
		if( $this->listTypes === null )
74
		{
75
			$this->listTypes = [];
76
			$manager = \Aimeos\MShop::create( $context, 'supplier/lists/type' );
77
78
			$search = $manager->createSearch()->setSlice( 0, 0x7fffffff );
79
			$search->setConditions( $search->compare( '==', 'supplier.lists.type.domain', 'product' ) );
80
81
			foreach( $manager->searchItems( $search ) as $item ) {
82
				$this->listTypes[$item->getCode()] = $item->getCode();
83
			}
84
		}
85
		else
86
		{
87
			$this->listTypes = array_flip( $this->listTypes );
88
		}
89
90
		$this->cache = $this->getCache( 'supplier' );
91
	}
92
93
94
	/**
95
	 * Saves the product related data to the storage
96
	 *
97
	 * @param \Aimeos\MShop\Product\Item\Iface $product Product item with associated items
98
	 * @param array $data List of CSV fields with position as key and data as value
99
	 * @return array List of data which hasn't been imported
100
	 */
101
	public function process( \Aimeos\MShop\Product\Item\Iface $product, array $data ) : array
102
	{
103
		$context = $this->getContext();
104
		$manager = \Aimeos\MShop::create( $context, 'supplier' );
105
		$listManager = \Aimeos\MShop::create( $context, 'supplier/lists' );
106
107
		/** controller/common/product/import/csv/separator
108
		 * Single separator character for multiple entries in one field of the import file
109
		 *
110
		 * The product importer is able split the content of a field from the import
111
		 * file into several entries based on the given separator character. Thus,
112
		 * you can create more compact import files and handle a variable range
113
		 * of entries better. The default separator character is a new line.
114
		 *
115
		 * '''Caution:''' The separator character must not be part of any entry
116
		 * in the field. Otherwise, you will get invalid entries and the importer
117
		 * may fail!
118
		 *
119
		 * @param string Single separator character
120
		 * @since 2020.07
121
		 * @category User
122
		 * @category Developer
123
		 * @see controller/common/product/import/csv/domains
124
		 */
125
		$separator = $context->getConfig()->get( 'controller/common/product/import/csv/separator', "\n" );
126
127
		$manager->begin();
128
129
		try
130
		{
131
			$listMap = [];
132
			$prodid = $product->getId();
133
			$map = $this->getMappedChunk( $data, $this->getMapping() );
134
			$listItems = $this->getListItems( $prodid, $this->listTypes );
0 ignored issues
show
Bug introduced by
It seems like $this->listTypes can also be of type null; however, parameter $types of Aimeos\Controller\Common...tandard::getListItems() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

134
			$listItems = $this->getListItems( $prodid, /** @scrutinizer ignore-type */ $this->listTypes );
Loading history...
135
136
			foreach( $listItems as $listItem ) {
137
				$listMap[$listItem->getParentId()][$listItem->getType()] = $listItem;
138
			}
139
140
			foreach( $map as $pos => $list )
141
			{
142
				if( $this->checkEntry( $list ) === false ) {
143
					continue;
144
				}
145
146
				$codes = explode( $separator, $this->getValue( $list, 'supplier.code', '' ) );
147
				$listtype = $this->getValue( $list, 'supplier.lists.type', 'default' );
148
				$this->addType( 'supplier/lists/type', 'product', $listtype );
149
150
				foreach( $codes as $code )
151
				{
152
					$code = trim( $code );
153
154
					if( ( $catid = $this->cache->get( $code ) ) === null )
155
					{
156
						$msg = 'No supplier for code "%1$s" available when importing product with code "%2$s"';
157
						throw new \Aimeos\Controller\Jobs\Exception( sprintf( $msg, $code, $product->getCode() ) );
158
					}
159
160
					$list['supplier.lists.parentid'] = $catid;
161
					$list['supplier.lists.refid'] = $prodid;
162
					$list['supplier.lists.domain'] = 'product';
163
164
					if( isset( $listMap[$catid][$listtype] ) )
165
					{
166
						$listItem = $listMap[$catid][$listtype];
167
						unset( $listItems[$listItem->getId()] );
168
					}
169
					else
170
					{
171
						$listItem = $listManager->createItem()->setType( $listtype );
172
					}
173
174
					$listItem = $listItem->setPosition( $pos++ )->fromArray( $list, true );
175
					$listManager->saveItem( $listItem, false );
176
				}
177
			}
178
179
			$listManager->deleteItems( $listItems->toArray() );
180
			$data = $this->getObject()->process( $product, $data );
181
182
			$manager->commit();
183
		}
184
		catch( \Exception $e )
185
		{
186
			$manager->rollback();
187
			throw $e;
188
		}
189
190
		return $data;
191
	}
192
193
194
	/**
195
	 * Adds the list item default values and returns the resulting array
196
	 *
197
	 * @param array $list Associative list of domain item keys and their values, e.g. "supplier.lists.status" => 1
198
	 * @param int $pos Computed position of the list item in the associated list of items
199
	 * @return array Given associative list enriched by default values if they were not already set
200
	 */
201
	protected function addListItemDefaults( array $list, int $pos ) : array
202
	{
203
		if( !isset( $list['supplier.lists.position'] ) ) {
204
			$list['supplier.lists.position'] = $pos;
205
		}
206
207
		if( !isset( $list['supplier.lists.status'] ) ) {
208
			$list['supplier.lists.status'] = 1;
209
		}
210
211
		return $list;
212
	}
213
214
215
	/**
216
	 * Checks if the entry from the mapped data is valid
217
	 *
218
	 * @param array $list Associative list of key/value pairs from the mapped data
219
	 * @return bool True if the entry is valid, false if not
220
	 */
221
	protected function checkEntry( array $list ) : bool
222
	{
223
		if( $this->getValue( $list, 'supplier.code' ) === null ) {
224
			return false;
225
		}
226
227
		if( ( $type = $this->getValue( $list, 'supplier.lists.type' ) ) && !isset( $this->listTypes[$type] ) )
228
		{
229
			$msg = sprintf( 'Invalid type "%1$s" (%2$s)', $type, 'supplier list' );
230
			throw new \Aimeos\Controller\Common\Exception( $msg );
231
		}
232
233
		return true;
234
	}
235
236
237
	/**
238
	 * Returns the supplier list items for the given supplier and product ID
239
	 *
240
	 * @param string $prodid Unique product ID
241
	 * @param array $types List of supplier list types
242
	 * @return array List of supplier list items
243
	 */
244
	protected function getListItems( $prodid, array $types ) : \Aimeos\Map
245
	{
246
		if( empty( $types ) ) {
247
			return [];
248
		}
249
250
		$manager = \Aimeos\MShop::create( $this->getContext(), 'supplier/lists' );
251
		$search = $manager->createSearch()->setSlice( 0, 0x7FFFFFFF );
252
253
		$expr = [
254
			$search->compare( '==', 'supplier.lists.domain', 'product' ),
255
			$search->compare( '==', 'supplier.lists.type', $types ),
256
			$search->compare( '==', 'supplier.lists.refid', $prodid ),
257
		];
258
259
		return $manager->searchItems( $search->setConditions( $search->combine( '&&', $expr ) ) );
260
	}
261
}
262