|
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\Text; |
|
12
|
|
|
|
|
13
|
|
|
|
|
14
|
|
|
/** |
|
15
|
|
|
* Text 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/text/name |
|
25
|
|
|
* Name of the text processor implementation |
|
26
|
|
|
* |
|
27
|
|
|
* Use "Myname" if your class is named "\Aimeos\Controller\Common\Product\Import\Csv\Processor\Text\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 $listTypes; |
|
36
|
|
|
private $types = []; |
|
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/text/listtypes |
|
52
|
|
|
* Names of the product list types for texts that are updated or removed |
|
53
|
|
|
* |
|
54
|
|
|
* If you want to associate text items manually via the administration |
|
55
|
|
|
* interface to products and don't want these to be touched during the |
|
56
|
|
|
* import, you can specify the product list types for these texts |
|
57
|
|
|
* that shouldn't be updated or removed. |
|
58
|
|
|
* |
|
59
|
|
|
* @param array|null List of product 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/catalog/listtypes |
|
66
|
|
|
* @see controller/common/product/import/csv/processor/media/listtypes |
|
67
|
|
|
* @see controller/common/product/import/csv/processor/price/listtypes |
|
68
|
|
|
* @see controller/common/product/import/csv/processor/product/listtypes |
|
69
|
|
|
*/ |
|
70
|
|
|
$key = 'controller/common/product/import/csv/processor/text/listtypes'; |
|
71
|
|
|
$this->listTypes = $context->getConfig()->get( $key ); |
|
72
|
|
|
|
|
73
|
|
|
if( $this->listTypes === null ) |
|
74
|
|
|
{ |
|
75
|
|
|
$this->listTypes = []; |
|
76
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $context, 'product/lists/type' ); |
|
77
|
|
|
|
|
78
|
|
|
$search = $manager->createSearch()->setSlice( 0, 0x7fffffff ); |
|
79
|
|
|
$search->setConditions( $search->compare( '==', 'product.lists.type.domain', 'text' ) ); |
|
80
|
|
|
|
|
81
|
|
|
foreach( $manager->searchItems( $search ) as $item ) { |
|
82
|
|
|
$this->listTypes[$item->getCode()] = $item->getCode(); |
|
83
|
|
|
} |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
|
|
|
|
87
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $context, 'text/type' ); |
|
88
|
|
|
|
|
89
|
|
|
$search = $manager->createSearch()->setSlice( 0, 0x7fffffff ); |
|
90
|
|
|
$search->setConditions( $search->compare( '==', 'text.type.domain', 'product' ) ); |
|
91
|
|
|
|
|
92
|
|
|
foreach( $manager->searchItems( $search ) as $item ) { |
|
93
|
|
|
$this->types[$item->getCode()] = $item->getCode(); |
|
94
|
|
|
} |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* Saves the product related data to the storage |
|
100
|
|
|
* |
|
101
|
|
|
* @param \Aimeos\MShop\Product\Item\Iface $product Product item with associated items |
|
102
|
|
|
* @param array $data List of CSV fields with position as key and data as value |
|
103
|
|
|
* @return array List of data which hasn't been imported |
|
104
|
|
|
*/ |
|
105
|
|
|
public function process( \Aimeos\MShop\Product\Item\Iface $product, array $data ) |
|
106
|
|
|
{ |
|
107
|
|
|
$listManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product/lists' ); |
|
108
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'text' ); |
|
109
|
|
|
|
|
110
|
|
|
$listMap = []; |
|
111
|
|
|
$map = $this->getMappedChunk( $data, $this->getMapping() ); |
|
112
|
|
|
$listItems = $product->getListItems( 'text', $this->listTypes ); |
|
113
|
|
|
|
|
114
|
|
|
foreach( $listItems as $listItem ) |
|
115
|
|
|
{ |
|
116
|
|
|
if( ( $refItem = $listItem->getRefItem() ) !== null ) { |
|
117
|
|
|
$listMap[ $refItem->getContent() ][ $refItem->getType() ][ $listItem->getType() ] = $listItem; |
|
118
|
|
|
} |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
foreach( $map as $pos => $list ) |
|
122
|
|
|
{ |
|
123
|
|
|
if( $this->checkEntry( $list ) === false ) { |
|
124
|
|
|
continue; |
|
125
|
|
|
} |
|
126
|
|
|
|
|
127
|
|
|
$content = trim( $list['text.content'] ); |
|
128
|
|
|
$type = trim( isset( $list['text.type'] ) ? $list['text.type'] : 'name' ); |
|
129
|
|
|
$typecode = trim( isset( $list['product.lists.type'] ) ? $list['product.lists.type'] : 'default' ); |
|
130
|
|
|
|
|
131
|
|
|
if( isset( $listMap[$content][$type][$typecode] ) ) |
|
132
|
|
|
{ |
|
133
|
|
|
$listItem = $listMap[$content][$type][$typecode]; |
|
134
|
|
|
$refItem = $listItem->getRefItem(); |
|
135
|
|
|
unset( $listItems[ $listItem->getId() ] ); |
|
136
|
|
|
} |
|
137
|
|
|
else |
|
138
|
|
|
{ |
|
139
|
|
|
$listItem = $listManager->createItem( $typecode, 'text' ); |
|
|
|
|
|
|
140
|
|
|
$refItem = $manager->createItem( $type, 'product' ); |
|
|
|
|
|
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
$refItem->fromArray( $this->addItemDefaults( $list ) ); |
|
144
|
|
|
$listItem->fromArray( $this->addListItemDefaults( $list, $pos ) ); |
|
145
|
|
|
|
|
146
|
|
|
$product->addListItem( 'text', $listItem, $refItem ); |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
$product->deleteListItems( $listItems, true ); |
|
150
|
|
|
|
|
151
|
|
|
return $this->getObject()->process( $product, $data ); |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* Adds the text item default values and returns the resulting array |
|
157
|
|
|
* |
|
158
|
|
|
* @param array $list Associative list of domain item keys and their values, e.g. "text.status" => 1 |
|
159
|
|
|
* @return array Given associative list enriched by default values if they were not already set |
|
160
|
|
|
*/ |
|
161
|
|
|
protected function addItemDefaults( array $list ) |
|
162
|
|
|
{ |
|
163
|
|
|
if( !isset( $list['text.label'] ) ) { |
|
164
|
|
|
$list['text.label'] = mb_strcut( trim( $list['text.content'] ), 0, 255 ); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
if( !isset( $list['text.status'] ) ) { |
|
168
|
|
|
$list['text.status'] = 1; |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
return $list; |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
|
|
175
|
|
|
/** |
|
176
|
|
|
* Checks if an entry can be used for updating a media item |
|
177
|
|
|
* |
|
178
|
|
|
* @param array $list Associative list of key/value pairs from the mapping |
|
179
|
|
|
* @return boolean True if valid, false if not |
|
180
|
|
|
*/ |
|
181
|
|
|
protected function checkEntry( array $list ) |
|
182
|
|
|
{ |
|
183
|
|
|
if( !isset( $list['text.content'] ) || trim( $list['text.content'] ) === '' ) { |
|
184
|
|
|
return false; |
|
185
|
|
|
} |
|
186
|
|
|
|
|
187
|
|
|
if( isset( $list['product.lists.type'] ) && !in_array( trim( $list['product.lists.type'] ), $this->listTypes ) ) |
|
188
|
|
|
{ |
|
189
|
|
|
$msg = sprintf( 'Invalid type "%1$s" (%2$s)', $list['product.lists.type'], 'product list' ); |
|
190
|
|
|
throw new \Aimeos\Controller\Common\Exception( $msg ); |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
if( isset( $list['text.type'] ) && !in_array( trim( $list['text.type'] ), $this->types ) ) |
|
194
|
|
|
{ |
|
195
|
|
|
$msg = sprintf( 'Invalid type "%1$s" (%2$s)', $list['text.type'], 'text' ); |
|
196
|
|
|
throw new \Aimeos\Controller\Common\Exception( $msg ); |
|
197
|
|
|
} |
|
198
|
|
|
|
|
199
|
|
|
return true; |
|
200
|
|
|
} |
|
201
|
|
|
} |
|
202
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.