Standard::process()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 46
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 27
nc 6
nop 2
dl 0
loc 46
rs 8.8657
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2025
6
 * @package Controller
7
 * @subpackage Common
8
 */
9
10
11
namespace Aimeos\Controller\Jobs\Common\Product\Import\Csv\Processor\Product;
12
13
14
/**
15
 * Product processor for CSV imports
16
 *
17
 * @package Controller
18
 * @subpackage Common
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Jobs\Common\Product\Import\Csv\Processor\Base
22
	implements \Aimeos\Controller\Jobs\Common\Product\Import\Csv\Processor\Iface
23
{
24
	/** controller/jobs/product/import/csv/processor/product/name
25
	 * Name of the product processor implementation
26
	 *
27
	 * Use "Myname" if your class is named "\Aimeos\Controller\Jobs\Common\Product\Import\Csv\Processor\Product\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
	 */
33
34
	private \Aimeos\Controller\Jobs\Common\Product\Import\Csv\Cache\Product\Standard $cache;
35
	private ?array $listTypes = null;
36
37
38
	/**
39
	 * Initializes the object
40
	 *
41
	 * @param \Aimeos\MShop\ContextIface $context Context object
42
	 * @param array $mapping Associative list of field position in CSV as key and domain item key as value
43
	 * @param \Aimeos\Controller\Jobs\Common\Product\Import\Csv\Processor\Iface $object Decorated processor
44
	 */
45
	public function __construct( \Aimeos\MShop\ContextIface $context, array $mapping,
46
		?\Aimeos\Controller\Jobs\Common\Product\Import\Csv\Processor\Iface $object = null )
47
	{
48
		parent::__construct( $context, $mapping, $object );
49
50
		$config = $context->config();
51
52
		/** controller/jobs/product/import/csv/product/listtypes
53
		 * Names of the product list types that are updated or removed
54
		 *
55
		 * Aimeos offers associated items like "bought together" products that
56
		 * are automatically generated by other job controllers. These relations
57
		 * shouldn't normally be overwritten or deleted by default during the
58
		 * import and this confiuration option enables you to specify the list
59
		 * types that should be updated or removed if not available in the import
60
		 * file.
61
		 *
62
		 * Contrary, if you don't generate any relations automatically in the
63
		 * shop and want to import those relations too, you can set the option
64
		 * to null to update all associated items.
65
		 *
66
		 * @param array|null List of product list type names or null for all
67
		 * @since 2015.05
68
		 * @see controller/jobs/product/import/csv/domains
69
		 * @see controller/jobs/product/import/csv/separator
70
		 * @see controller/jobs/product/import/csv/attribute/listtypes
71
		 * @see controller/jobs/product/import/csv/catalog/listtypes
72
		 * @see controller/jobs/product/import/csv/media/listtypes
73
		 * @see controller/jobs/product/import/csv/price/listtypes
74
		 * @see controller/jobs/product/import/csv/supplier/listtypes
75
		 * @see controller/jobs/product/import/csv/text/listtypes
76
		 */
77
		$default = $config->get( 'controller/jobs/product/import/csv/processor/product/listtypes', ['default', 'suggestion'] );
78
		$this->listTypes = $config->get( 'controller/jobs/product/import/csv/product/listtypes', $default );
79
80
		if( $this->listTypes === null )
81
		{
82
			$this->listTypes = [];
83
			$manager = \Aimeos\MShop::create( $context, 'product/lists/type' );
84
			$search = $manager->filter()->slice( 0, 0x7fffffff );
85
86
			foreach( $manager->search( $search ) as $item ) {
87
				$this->listTypes[$item->getCode()] = $item->getCode();
88
			}
89
		}
90
		else
91
		{
92
			$this->listTypes = array_combine( $this->listTypes, $this->listTypes );
93
		}
94
95
		$this->cache = $this->getCache( 'product' );
96
	}
97
98
99
	/**
100
	 * Saves the product related data to the storage
101
	 *
102
	 * @param \Aimeos\MShop\Product\Item\Iface $product Product item with associated items
103
	 * @param array $data List of CSV fields with position as key and data as value
104
	 * @return array List of data which has not been imported
105
	 */
106
	public function process( \Aimeos\MShop\Product\Item\Iface $product, array $data ) : array
107
	{
108
		$context = $this->context();
109
		$logger = $context->logger();
110
		$manager = \Aimeos\MShop::create( $context, 'product' );
111
		$separator = $context->config()->get( 'controller/jobs/product/import/csv/separator', "\n" );
112
113
		$listItems = $product->getListItems( 'product', null, null, false );
114
		$this->cache->set( $product );
115
		$pos = 0;
116
117
		foreach( $this->getMappedChunk( $data, $this->getMapping() ) as $list )
118
		{
119
			if( $this->checkEntry( $list ) === false ) {
120
				continue;
121
			}
122
123
			$listConfig = $this->getListConfig( trim( $this->val( $list, 'product.lists.config', '' ) ) );
124
			$listtype = trim( $this->val( $list, 'product.lists.type', 'default' ) );
125
			$this->addType( 'product/lists/type', 'product', $listtype );
126
127
			foreach( explode( $separator, trim( $this->val( $list, 'product.code', '' ) ) ) as $code )
128
			{
129
				$code = trim( $code );
130
131
				if( ( $prodid = $this->cache->get( $code ) ) === null )
132
				{
133
					$msg = 'No product for code "%1$s" available when importing product with code "%2$s"';
134
					$logger->warning( sprintf( $msg, $code, $product->getCode() ), 'import/csv/product' );
135
					continue;
136
				}
137
138
				if( ( $listItem = $product->getListItem( 'product', $listtype, $prodid ) ) === null ) {
139
					$listItem = $manager->createListItem()->setType( $listtype );
0 ignored issues
show
Bug introduced by
The method createListItem() 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

139
					$listItem = $manager->/** @scrutinizer ignore-call */ createListItem()->setType( $listtype );

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...
140
				} else {
141
					unset( $listItems[$listItem->getId()] );
142
				}
143
144
				$listItem = $listItem->fromArray( $list )->setRefId( $prodid )->setConfig( $listConfig )->setPosition( $pos++ );
145
				$product->addListItem( 'product', $listItem );
146
			}
147
		}
148
149
		$product->deleteListItems( $listItems->toArray() );
150
151
		return $this->object()->process( $product, $data );
152
	}
153
154
155
	/**
156
	 * Checks if an entry can be used for updating a media item
157
	 *
158
	 * @param array $list Associative list of key/value pairs from the mapping
159
	 * @return bool True if valid, false if not
160
	 */
161
	protected function checkEntry( array $list ) : bool
162
	{
163
		if( $this->val( $list, 'product.code' ) === null ) {
164
			return false;
165
		}
166
167
		if( ( $type = trim( $this->val( $list, 'product.lists.type', 'default' ) ) ) && !isset( $this->listTypes[$type] ) )
168
		{
169
			$msg = sprintf( 'Invalid type "%1$s" (%2$s)', $type, 'product list' );
170
			throw new \Aimeos\Controller\Jobs\Exception( $msg );
171
		}
172
173
		return true;
174
	}
175
}
176