|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* (c) shopware AG <[email protected]> |
|
4
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
5
|
|
|
* file that was distributed with this source code. |
|
6
|
|
|
*/ |
|
7
|
|
|
|
|
8
|
|
|
namespace ShopwarePlugins\Connect\Components; |
|
9
|
|
|
|
|
10
|
|
|
use Shopware\Components\Model\ModelManager; |
|
11
|
|
|
use Shopware\CustomModels\Connect\Attribute; |
|
12
|
|
|
use Shopware\Models\Article\Article; |
|
13
|
|
|
use Shopware\Models\Article\Detail; |
|
14
|
|
|
use Shopware\Models\Article\Image; |
|
15
|
|
|
use Shopware\Models\Media\Media; |
|
16
|
|
|
use Shopware\Models\Attribute\Media as MediaAttribute; |
|
17
|
|
|
use Shopware\Models\Attribute\ArticleImage as ImageAttribute; |
|
18
|
|
|
use Symfony\Component\HttpFoundation\File\File; |
|
19
|
|
|
use Shopware\Models\Article\Supplier; |
|
20
|
|
|
use Shopware\Components\Thumbnail\Manager as ThumbnailManager; |
|
21
|
|
|
|
|
22
|
|
|
class ImageImport |
|
23
|
|
|
{ |
|
24
|
|
|
/** @var \Shopware\Components\Model\ModelManager */ |
|
25
|
|
|
protected $manager; |
|
26
|
|
|
|
|
27
|
|
|
/** @var Helper */ |
|
28
|
|
|
protected $helper; |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* @var ThumbnailManager |
|
32
|
|
|
*/ |
|
33
|
|
|
protected $thumbnailManager; |
|
34
|
|
|
|
|
35
|
|
|
/** @var \ShopwarePlugins\Connect\Components\Logger */ |
|
36
|
|
|
protected $logger; |
|
37
|
|
|
|
|
38
|
|
|
public function __construct( |
|
39
|
|
|
ModelManager $manager, |
|
40
|
|
|
Helper $helper, |
|
41
|
|
|
ThumbnailManager $thumbnailManager, |
|
42
|
|
|
Logger $logger |
|
43
|
|
|
) { |
|
44
|
|
|
$this->manager = $manager; |
|
45
|
|
|
$this->helper = $helper; |
|
46
|
|
|
$this->thumbnailManager = $thumbnailManager; |
|
47
|
|
|
$this->logger = $logger; |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* Helper to determine, if there is a main image for a given articleId |
|
52
|
|
|
* |
|
53
|
|
|
* @param $articleId |
|
54
|
|
|
* @return bool |
|
55
|
|
|
*/ |
|
56
|
|
|
public function hasArticleMainImage($articleId) |
|
57
|
|
|
{ |
|
58
|
|
|
$builder = $this->manager->createQueryBuilder(); |
|
59
|
|
|
$builder->select(['images']) |
|
60
|
|
|
->from('Shopware\Models\Article\Image', 'images') |
|
61
|
|
|
->where('images.articleId = :articleId') |
|
62
|
|
|
->andWhere('images.parentId IS NULL') |
|
63
|
|
|
->andWhere('images.main = :main') |
|
64
|
|
|
->setParameter('main', 1) |
|
65
|
|
|
->setParameter('articleId', $articleId) |
|
66
|
|
|
->setFirstResult(0) |
|
67
|
|
|
->setMaxResults(1); |
|
68
|
|
|
|
|
69
|
|
|
$result = $builder->getQuery()->getResult(); |
|
70
|
|
|
|
|
71
|
|
|
return !empty($result); |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
/** |
|
75
|
|
|
* Get ids of details that needs an image import |
|
76
|
|
|
* @param null $limit |
|
77
|
|
|
* @return array Ids of products needing an image import |
|
78
|
|
|
*/ |
|
79
|
|
|
public function getDetailIdsNeedingImageImport($limit=null) |
|
80
|
|
|
{ |
|
81
|
|
|
$updateFlags = $this->helper->getUpdateFlags(); |
|
82
|
|
|
$updateFlagsByName = array_flip($updateFlags); |
|
83
|
|
|
|
|
84
|
|
|
$initialImportFlag = $updateFlagsByName['imageInitialImport']; |
|
85
|
|
|
|
|
86
|
|
|
$builder = $this->manager->createQueryBuilder(); |
|
87
|
|
|
$builder->from('Shopware\CustomModels\Connect\Attribute', 'at'); |
|
88
|
|
|
$builder->select('at.articleDetailId'); |
|
89
|
|
|
$builder->andWhere('at.shopId IS NOT NULL') |
|
90
|
|
|
->andWhere('at.lastUpdateFlag IS NOT NULL') |
|
91
|
|
|
->andWhere('BIT_AND(at.lastUpdateFlag, :initialImportFlag) > 0') |
|
92
|
|
|
->setParameter('initialImportFlag', $initialImportFlag); |
|
93
|
|
|
|
|
94
|
|
|
if ($limit) { |
|
95
|
|
|
$builder->setMaxResults($limit); |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
$ids = $builder->getQuery()->getArrayResult(); |
|
99
|
|
|
|
|
100
|
|
|
return array_map('array_pop', $ids); |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
/** |
|
104
|
|
|
* Batch import images for new products without images |
|
105
|
|
|
* |
|
106
|
|
|
* @param int|null $limit |
|
107
|
|
|
*/ |
|
108
|
|
|
public function import($limit = null) |
|
109
|
|
|
{ |
|
110
|
|
|
$detailRepository = $this->manager->getRepository('Shopware\Models\Article\Detail'); |
|
111
|
|
|
|
|
112
|
|
|
$flags = $this->helper->getUpdateFlags(); |
|
113
|
|
|
$flagsByName = array_flip($flags); |
|
114
|
|
|
|
|
115
|
|
|
$ids = $this->getDetailIdsNeedingImageImport($limit); |
|
|
|
|
|
|
116
|
|
|
|
|
117
|
|
|
foreach ($ids as $id) { |
|
118
|
|
|
/** @var \Shopware\Models\Article\Detail $detail */ |
|
119
|
|
|
$detail = $detailRepository->find($id); |
|
120
|
|
|
$connectAttribute = $this->helper->getConnectAttributeByModel($detail); |
|
121
|
|
|
|
|
122
|
|
|
$this->manager->getConnection()->beginTransaction(); |
|
123
|
|
|
try { |
|
124
|
|
|
$lastUpdate = json_decode($connectAttribute->getLastUpdate(), true); |
|
125
|
|
|
$this->importArticleImagesWhenMainDetail($detail, $lastUpdate); |
|
126
|
|
|
$this->importImagesForDetail($lastUpdate['variantImages'], $detail); |
|
127
|
|
|
$connectAttribute->flipLastUpdateFlag($flagsByName['imageInitialImport']); |
|
128
|
|
|
$this->manager->flush(); |
|
129
|
|
|
$this->manager->getConnection()->commit(); |
|
130
|
|
|
} catch (\PDOException $e) { |
|
131
|
|
|
// possible lock with ImageImport from ToShop channel |
|
132
|
|
|
// is thrown before flipping of last update flag |
|
133
|
|
|
// so we should process the detail again in next cron run |
|
134
|
|
|
$this->manager->getConnection()->rollback(); |
|
135
|
|
|
} |
|
136
|
|
|
} |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
/** |
|
140
|
|
|
* Handles the image import of a product. This will: |
|
141
|
|
|
* - delete all images imported from connect before and not in the current import list |
|
142
|
|
|
* - create new images which have not already been imported |
|
143
|
|
|
* - set the main image, if there is no main image, yet |
|
144
|
|
|
* |
|
145
|
|
|
* Images are identified via the URL of the connect image. So we don't need to md5 the |
|
146
|
|
|
* actual image content every time. |
|
147
|
|
|
* |
|
148
|
|
|
* @param array $images |
|
149
|
|
|
* @param $article \Shopware\Models\Article\Article |
|
150
|
|
|
*/ |
|
151
|
|
|
public function importImagesForArticle($images, Article $article) |
|
152
|
|
|
{ |
|
153
|
|
|
$localImagesFromConnect = $this->getImportedImages($article); |
|
154
|
|
|
$remoteImagesFromConnect = array_flip($images); |
|
155
|
|
|
|
|
156
|
|
|
// Build up arrays of images to delete and images to create |
|
157
|
|
|
$imagesToDelete = array_diff_key($localImagesFromConnect, $remoteImagesFromConnect); |
|
158
|
|
|
$imagesToCreate = array_diff_key($remoteImagesFromConnect, $localImagesFromConnect); |
|
159
|
|
|
|
|
160
|
|
|
// Delete old connect images and media objects |
|
161
|
|
|
foreach ($imagesToDelete as $hash => $data) { |
|
162
|
|
|
/** @var \Shopware\Models\Article\Image $image */ |
|
163
|
|
|
$image = $data['image']; |
|
164
|
|
|
// if the image has mapping, it's variant image and shouldn't be deleted |
|
165
|
|
|
if (count($image->getMappings()) > 0) { |
|
166
|
|
|
continue; |
|
167
|
|
|
} |
|
168
|
|
|
$this->manager->remove($data['media']); |
|
169
|
|
|
$this->manager->remove($image); |
|
170
|
|
|
} |
|
171
|
|
|
$this->manager->flush(); |
|
172
|
|
|
|
|
173
|
|
|
try { |
|
174
|
|
|
$this->importImages($imagesToCreate, $article); |
|
175
|
|
|
} catch (\Exception $e) { |
|
176
|
|
|
// log exception message if for some reason |
|
177
|
|
|
// image import fails |
|
178
|
|
|
$this->logger->write(true, 'Import images', $e->getMessage()); |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
$this->manager->flush(); |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* Handles the image import of a product. This will: |
|
186
|
|
|
* - delete all images imported from connect before and not in the current import list |
|
187
|
|
|
* - create new images which have not already been imported |
|
188
|
|
|
* - set the main image, if there is no main image, yet |
|
189
|
|
|
* |
|
190
|
|
|
* Images are identified via the URL of the connect image. So we don't need to md5 the |
|
191
|
|
|
* actual image content every time. |
|
192
|
|
|
* |
|
193
|
|
|
* @param array $variantImages |
|
194
|
|
|
* @param $detail \Shopware\Models\Article\Detail |
|
195
|
|
|
*/ |
|
196
|
|
|
public function importImagesForDetail(array $variantImages, Detail $detail) |
|
197
|
|
|
{ |
|
198
|
|
|
$article = $detail->getArticle(); |
|
199
|
|
|
$articleImages = $article->getImages(); |
|
200
|
|
|
|
|
201
|
|
|
$localImagesFromConnect = $this->getImportedImages($detail); |
|
202
|
|
|
$localArticleImagesFromConnect = $this->getImportedImages($article); |
|
203
|
|
|
|
|
204
|
|
|
$remoteImagesFromConnect = array_flip($variantImages); |
|
205
|
|
|
|
|
206
|
|
|
// Build up arrays of images to delete and images to create |
|
207
|
|
|
$imagesToDelete = array_diff_key($localImagesFromConnect, $remoteImagesFromConnect); |
|
208
|
|
|
$imagesToCreate = array_diff_key($remoteImagesFromConnect, $localImagesFromConnect); |
|
209
|
|
|
|
|
210
|
|
|
$mappingRepository = $this->manager->getRepository('Shopware\Models\Article\Image\Mapping'); |
|
211
|
|
|
// Delete old connect images and media objects |
|
212
|
|
|
foreach ($imagesToDelete as $hash => $data) { |
|
213
|
|
|
/** @var \Shopware\Models\Article\Image $image */ |
|
214
|
|
|
$image = $data['image']; |
|
215
|
|
|
/** @var \Shopware\Models\Article\Image $child */ |
|
216
|
|
|
foreach ($image->getChildren() as $child) { |
|
217
|
|
|
if ($detail->getId() == $child->getArticleDetail()->getId()) { |
|
218
|
|
|
$childAttribute = $child->getAttribute(); |
|
219
|
|
|
if (!$childAttribute) { |
|
220
|
|
|
break; |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
$mapping = $mappingRepository->find($childAttribute->getConnectDetailMappingId()); |
|
224
|
|
|
if (!$mapping) { |
|
225
|
|
|
break; |
|
226
|
|
|
} |
|
227
|
|
|
|
|
228
|
|
|
$this->manager->remove($mapping); |
|
229
|
|
|
$this->manager->remove($child); |
|
230
|
|
|
break; |
|
231
|
|
|
} |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
if (count($image->getChildren()) == 1) { |
|
235
|
|
|
$this->manager->remove($image); |
|
236
|
|
|
$this->manager->remove($data['media']); |
|
237
|
|
|
} |
|
238
|
|
|
} |
|
239
|
|
|
$this->manager->flush(); |
|
240
|
|
|
|
|
241
|
|
|
try { |
|
242
|
|
|
$positions = []; |
|
243
|
|
|
foreach ($article->getImages() as $image) { |
|
244
|
|
|
$positions[] = $image->getPosition(); |
|
245
|
|
|
} |
|
246
|
|
|
$maxPosition = count($positions) > 0 ? max($positions) : 0; |
|
247
|
|
|
|
|
248
|
|
|
/** @var \Shopware\Models\Media\Album $album */ |
|
249
|
|
|
$album = $this->manager->find('Shopware\Models\Media\Album', -1); |
|
250
|
|
|
foreach ($imagesToCreate as $imageUrl => $key) { |
|
251
|
|
|
// check if image already exists in article images |
|
252
|
|
|
// 1) if it exists skip import and it's global image |
|
253
|
|
|
if (array_key_exists($imageUrl, $localArticleImagesFromConnect) |
|
254
|
|
|
&& empty($localArticleImagesFromConnect[$imageUrl]['image']->getMappings())) { |
|
255
|
|
|
// if image doesn't have mappings |
|
256
|
|
|
// it's global for all details |
|
257
|
|
|
// do nothing, just continue |
|
258
|
|
|
continue; |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
// 2) if it has mapping, add new one for current detail |
|
262
|
|
|
if (array_key_exists($imageUrl, $localArticleImagesFromConnect)) { |
|
263
|
|
|
/** @var \Shopware\Models\Article\Image $articleImage */ |
|
264
|
|
|
$articleImage = $localArticleImagesFromConnect[$imageUrl]['image']; |
|
265
|
|
|
$articleMedia = $localArticleImagesFromConnect[$imageUrl]['media']; |
|
266
|
|
|
|
|
267
|
|
|
// add new mapping |
|
268
|
|
|
$mapping = new Image\Mapping(); |
|
269
|
|
|
$mapping->setImage($articleImage); |
|
270
|
|
|
foreach ($detail->getConfiguratorOptions() as $option) { |
|
271
|
|
|
$rule = new Image\Rule(); |
|
272
|
|
|
$rule->setMapping($mapping); |
|
273
|
|
|
$rule->setOption($option); |
|
274
|
|
|
$mapping->getRules()->add($rule); |
|
275
|
|
|
} |
|
276
|
|
|
$this->manager->persist($mapping); |
|
277
|
|
|
// mapping should have id, because it should be stored as child image attribute |
|
278
|
|
|
$this->manager->flush($mapping); |
|
279
|
|
|
$articleImage->getMappings()->add($mapping); |
|
280
|
|
|
|
|
281
|
|
|
// add child image |
|
282
|
|
|
$childImage = new Image(); |
|
283
|
|
|
$childImage->setMain(2); |
|
284
|
|
|
$childImage->setPosition($maxPosition + $key + 1); |
|
285
|
|
|
$childImage->setParent($articleImage); |
|
286
|
|
|
$childImage->setArticleDetail($detail); |
|
287
|
|
|
$childImage->setExtension($articleMedia->getExtension()); |
|
288
|
|
|
$childImageAttribute = $childImage->getAttribute() ?: new ImageAttribute(); |
|
289
|
|
|
$childImageAttribute->setArticleImage($childImage); |
|
290
|
|
|
$childImageAttribute->setConnectDetailMappingId($mapping->getId()); |
|
291
|
|
|
|
|
292
|
|
|
$detail->getImages()->add($childImage); |
|
293
|
|
|
$articleImage->getChildren()->add($childImage); |
|
294
|
|
|
|
|
295
|
|
|
$this->manager->persist($childImage); |
|
296
|
|
|
$this->manager->persist($childImageAttribute); |
|
297
|
|
|
$this->manager->persist($articleImage); |
|
298
|
|
|
|
|
299
|
|
|
continue; |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
// 3) if it doesn't exist, import it |
|
303
|
|
|
$importedImages = $this->importImages([$imageUrl => $key], $article, $maxPosition); |
|
304
|
|
|
$image = reset($importedImages); |
|
305
|
|
|
$media = $image->getMedia(); |
|
306
|
|
|
|
|
307
|
|
|
// add new mapping |
|
308
|
|
|
$mapping = new Image\Mapping(); |
|
309
|
|
|
$mapping->setImage($image); |
|
310
|
|
|
foreach ($detail->getConfiguratorOptions() as $option) { |
|
311
|
|
|
$rule = new Image\Rule(); |
|
312
|
|
|
$rule->setMapping($mapping); |
|
313
|
|
|
$rule->setOption($option); |
|
314
|
|
|
$rules = $mapping->getRules(); |
|
315
|
|
|
$rules->add($rule); |
|
316
|
|
|
$mapping->setRules($rules); |
|
317
|
|
|
$this->manager->persist($rule); |
|
318
|
|
|
} |
|
319
|
|
|
$this->manager->persist($mapping); |
|
320
|
|
|
// mapping should have id, because it should be stored as child image attribute |
|
321
|
|
|
$this->manager->flush($mapping); |
|
322
|
|
|
|
|
323
|
|
|
$mappings = $image->getMappings(); |
|
324
|
|
|
$mappings->add($mapping); |
|
325
|
|
|
$image->setMappings($mappings); |
|
326
|
|
|
|
|
327
|
|
|
// add child image |
|
328
|
|
|
$childImage = new Image(); |
|
329
|
|
|
$childImage->setMain(2); |
|
330
|
|
|
$childImage->setPosition($maxPosition + $key + 1); |
|
331
|
|
|
$childImage->setParent($image); |
|
332
|
|
|
$childImage->setArticleDetail($detail); |
|
333
|
|
|
$childImage->setExtension($media->getExtension()); |
|
334
|
|
|
$childImageAttribute = $childImage->getAttribute() ?: new ImageAttribute(); |
|
335
|
|
|
$childImageAttribute->setArticleImage($childImage); |
|
336
|
|
|
$childImageAttribute->setConnectDetailMappingId($mapping->getId()); |
|
337
|
|
|
$detail->getImages()->add($childImage); |
|
338
|
|
|
|
|
339
|
|
|
$image->getChildren()->add($childImage); |
|
340
|
|
|
|
|
341
|
|
|
$this->manager->persist($childImage); |
|
342
|
|
|
$this->manager->persist($childImageAttribute); |
|
343
|
|
|
$this->manager->persist($image); |
|
344
|
|
|
|
|
345
|
|
|
$this->thumbnailManager->createMediaThumbnail( |
|
346
|
|
|
$media, |
|
347
|
|
|
$this->getThumbnailSize($album), |
|
348
|
|
|
true |
|
349
|
|
|
); |
|
350
|
|
|
} |
|
351
|
|
|
} catch (\Exception $e) { |
|
352
|
|
|
// log exception message if for some reason |
|
353
|
|
|
// image import fails |
|
354
|
|
|
$this->logger->write(true, 'Import images', $e->getMessage()); |
|
355
|
|
|
} |
|
356
|
|
|
|
|
357
|
|
|
$article->setImages($articleImages); |
|
358
|
|
|
$this->manager->persist($article); |
|
359
|
|
|
$this->manager->flush(); |
|
360
|
|
|
} |
|
361
|
|
|
|
|
362
|
|
|
/** |
|
363
|
|
|
* Helper: Read images for a given detail |
|
364
|
|
|
* |
|
365
|
|
|
* @param int $articleDetailId |
|
366
|
|
|
* @return array |
|
367
|
|
|
*/ |
|
368
|
|
|
public function getImagesForDetail($articleDetailId) |
|
369
|
|
|
{ |
|
370
|
|
|
$builder = $this->manager->createQueryBuilder(); |
|
371
|
|
|
$builder->select('media.path') |
|
372
|
|
|
->from('Shopware\Models\Article\Image', 'images') |
|
373
|
|
|
->join('images.media', 'media') |
|
374
|
|
|
->where('images.articleDetailId = :articleDetailId') |
|
375
|
|
|
->andWhere('images.parentId IS NULL') |
|
376
|
|
|
->setParameter('articleDetailId', $articleDetailId) |
|
377
|
|
|
->orderBy('images.main', 'ASC') |
|
378
|
|
|
->addOrderBy('images.position', 'ASC'); |
|
379
|
|
|
|
|
380
|
|
|
return array_map( |
|
381
|
|
|
function ($image) { |
|
382
|
|
|
return $image['path']; |
|
383
|
|
|
}, |
|
384
|
|
|
$builder->getQuery()->getArrayResult() |
|
385
|
|
|
); |
|
386
|
|
|
} |
|
387
|
|
|
|
|
388
|
|
|
/** |
|
389
|
|
|
* Download, import and assign images to article |
|
390
|
|
|
* |
|
391
|
|
|
* @param array $imagesToCreate |
|
392
|
|
|
* @param Article|Detail $model |
|
393
|
|
|
* @param null|int $maxPosition |
|
394
|
|
|
* @throws \Doctrine\ORM\ORMException |
|
395
|
|
|
* @throws \Doctrine\ORM\OptimisticLockException |
|
396
|
|
|
* @throws \Doctrine\ORM\TransactionRequiredException |
|
397
|
|
|
* @throws \Exception |
|
398
|
|
|
* @return \Shopware\Models\Article\Image |
|
399
|
|
|
*/ |
|
400
|
|
|
private function importImages(array $imagesToCreate, $model, $maxPosition = null) |
|
401
|
|
|
{ |
|
402
|
|
|
if (!$maxPosition) { |
|
|
|
|
|
|
403
|
|
|
$positions = []; |
|
404
|
|
|
foreach ($model->getImages() as $image) { |
|
405
|
|
|
$positions[] = $image->getPosition(); |
|
406
|
|
|
} |
|
407
|
|
|
$maxPosition = count($positions) > 0 ? max($positions) : 0; |
|
408
|
|
|
} |
|
409
|
|
|
|
|
410
|
|
|
if ($model instanceof Detail) { |
|
|
|
|
|
|
411
|
|
|
$article = $model->getArticle(); |
|
412
|
|
|
} elseif ($model instanceof Article) { |
|
|
|
|
|
|
413
|
|
|
$article = $model; |
|
414
|
|
|
} else { |
|
415
|
|
|
throw new \RuntimeException('Model must be instance of Article or Detail!'); |
|
416
|
|
|
} |
|
417
|
|
|
|
|
418
|
|
|
// If there is no main image set first image as main image |
|
419
|
|
|
$hasMainImage = $this->hasArticleMainImage($article->getId()); |
|
420
|
|
|
$importedImages = []; |
|
421
|
|
|
/** @var \Shopware\Models\Media\Album $album */ |
|
422
|
|
|
$album = $this->manager->find('Shopware\Models\Media\Album', -1); |
|
423
|
|
|
$tempDir = Shopware()->DocPath('media_temp'); |
|
424
|
|
|
foreach ($imagesToCreate as $imageUrl => $key) { |
|
425
|
|
|
$tempFile = tempnam($tempDir, 'image'); |
|
426
|
|
|
copy($imageUrl, $tempFile); |
|
427
|
|
|
$file = new File($tempFile); |
|
428
|
|
|
|
|
429
|
|
|
// Create the media object |
|
430
|
|
|
$media = new Media(); |
|
431
|
|
|
$media->setAlbum($album); |
|
432
|
|
|
$media->setDescription(''); |
|
433
|
|
|
$media->setCreated(new \DateTime()); |
|
434
|
|
|
$media->setUserId(0); |
|
435
|
|
|
$media->setFile($file); |
|
436
|
|
|
|
|
437
|
|
|
$mediaAttribute = $media->getAttribute() ?: new MediaAttribute(); |
|
438
|
|
|
$mediaAttribute->setConnectHash($imageUrl); |
|
439
|
|
|
$mediaAttribute->setMedia($media); |
|
440
|
|
|
$media->setAttribute($mediaAttribute); |
|
441
|
|
|
$this->manager->persist($media); |
|
442
|
|
|
$this->manager->persist($mediaAttribute); |
|
443
|
|
|
|
|
444
|
|
|
// Create the associated image object |
|
445
|
|
|
$image = new Image(); |
|
446
|
|
|
$image->setMain((!$hasMainImage && $key == 0) ? 1 : 2); |
|
447
|
|
|
$image->setMedia($media); |
|
448
|
|
|
$image->setPosition($maxPosition + $key + 1); |
|
449
|
|
|
$image->setArticle($article); |
|
450
|
|
|
$image->setPath($media->getName()); |
|
451
|
|
|
$image->setExtension($media->getExtension()); |
|
452
|
|
|
|
|
453
|
|
|
$article->getImages()->add($image); |
|
454
|
|
|
|
|
455
|
|
|
$this->manager->persist($image); |
|
456
|
|
|
|
|
457
|
|
|
$this->thumbnailManager->createMediaThumbnail( |
|
458
|
|
|
$media, |
|
459
|
|
|
$this->getThumbnailSize($album), |
|
460
|
|
|
true |
|
461
|
|
|
); |
|
462
|
|
|
|
|
463
|
|
|
$importedImages[] = $image; |
|
464
|
|
|
} |
|
465
|
|
|
|
|
466
|
|
|
return $importedImages; |
|
467
|
|
|
} |
|
468
|
|
|
|
|
469
|
|
|
/** |
|
470
|
|
|
* Returns a list with already imported images from Connect |
|
471
|
|
|
* by given Article or Detail |
|
472
|
|
|
* |
|
473
|
|
|
* @param Article|Detail $model |
|
474
|
|
|
* @return array |
|
475
|
|
|
*/ |
|
476
|
|
|
private function getImportedImages($model) |
|
477
|
|
|
{ |
|
478
|
|
|
if (!$model instanceof Article && !$model instanceof Detail) { |
|
|
|
|
|
|
479
|
|
|
throw new \RuntimeException('Model must be instance of Article or Detail!'); |
|
480
|
|
|
} |
|
481
|
|
|
|
|
482
|
|
|
$localArticleImagesFromConnect = []; |
|
483
|
|
|
|
|
484
|
|
|
/** @var \Shopware\Models\Article\Image $image */ |
|
485
|
|
|
foreach ($model->getImages() as $image) { |
|
486
|
|
|
if ($model instanceof Detail && $model->getId() == $image->getArticleDetail()->getId()) { |
|
|
|
|
|
|
487
|
|
|
$image = $image->getParent(); |
|
488
|
|
|
} |
|
489
|
|
|
$media = $image->getMedia(); |
|
490
|
|
|
|
|
491
|
|
|
try { |
|
492
|
|
|
if (!$media || !$media->getAttribute()) { |
|
493
|
|
|
continue; |
|
494
|
|
|
} |
|
495
|
|
|
$attribute = $media->getAttribute(); |
|
496
|
|
|
} catch (\Doctrine\ORM\EntityNotFoundException $e) { |
|
|
|
|
|
|
497
|
|
|
//is thrown if media was deleted -> simply continue |
|
498
|
|
|
continue; |
|
499
|
|
|
} |
|
500
|
|
|
|
|
501
|
|
|
// If the image was not imported from connect, skip it |
|
502
|
|
|
$connectHash = $attribute->getConnectHash(); |
|
503
|
|
|
if (!$connectHash) { |
|
504
|
|
|
continue; |
|
505
|
|
|
} |
|
506
|
|
|
$localArticleImagesFromConnect[$connectHash] = ['image' => $image, 'media' => $media]; |
|
507
|
|
|
} |
|
508
|
|
|
|
|
509
|
|
|
return $localArticleImagesFromConnect; |
|
510
|
|
|
} |
|
511
|
|
|
|
|
512
|
|
|
/** |
|
513
|
|
|
* @param $imageUrl |
|
514
|
|
|
* @param Supplier $supplier |
|
515
|
|
|
*/ |
|
516
|
|
|
public function importImageForSupplier($imageUrl, Supplier $supplier) |
|
517
|
|
|
{ |
|
518
|
|
|
try { |
|
519
|
|
|
$album = $this->manager->find('Shopware\Models\Media\Album', -12); |
|
520
|
|
|
$tempDir = Shopware()->DocPath('media_temp'); |
|
521
|
|
|
|
|
522
|
|
|
$tempFile = tempnam($tempDir, 'image'); |
|
523
|
|
|
copy($imageUrl, $tempFile); |
|
524
|
|
|
$file = new File($tempFile); |
|
525
|
|
|
|
|
526
|
|
|
$media = new Media(); |
|
527
|
|
|
$media->setAlbum($album); |
|
528
|
|
|
$media->setDescription(''); |
|
529
|
|
|
$media->setCreated(new \DateTime()); |
|
530
|
|
|
$media->setUserId(0); |
|
531
|
|
|
$media->setFile($file); |
|
532
|
|
|
|
|
533
|
|
|
$this->manager->persist($media); |
|
534
|
|
|
|
|
535
|
|
|
$this->thumbnailManager->createMediaThumbnail( |
|
536
|
|
|
$media, |
|
537
|
|
|
$this->getThumbnailSize($album), |
|
538
|
|
|
true |
|
539
|
|
|
); |
|
540
|
|
|
|
|
541
|
|
|
$supplier->setImage($media->getPath()); |
|
542
|
|
|
$this->manager->persist($supplier); |
|
543
|
|
|
|
|
544
|
|
|
$this->manager->flush(); |
|
545
|
|
|
} catch (\Exception $e) { |
|
546
|
|
|
$this->logger->write( |
|
547
|
|
|
true, |
|
548
|
|
|
'import image for supplier', |
|
549
|
|
|
$e->getMessage() . 'imageUrl:' . $imageUrl |
|
550
|
|
|
); |
|
551
|
|
|
} |
|
552
|
|
|
} |
|
553
|
|
|
|
|
554
|
|
|
/** |
|
555
|
|
|
* Returns thumbnails size by album |
|
556
|
|
|
* @param $album \Shopware\Models\Media\Album |
|
557
|
|
|
* @return array |
|
558
|
|
|
*/ |
|
559
|
|
|
protected function getThumbnailSize($album) |
|
560
|
|
|
{ |
|
561
|
|
|
if (!$album->getId()) { |
|
562
|
|
|
return; |
|
563
|
|
|
} |
|
564
|
|
|
|
|
565
|
|
|
$thumbnailSizes = $album->getSettings()->getThumbnailSize(); |
|
566
|
|
|
$sizesArray = []; |
|
567
|
|
|
$requiredSizeExists = false; |
|
568
|
|
|
foreach ($thumbnailSizes as $size) { |
|
569
|
|
|
if (strlen($size) == 0) { |
|
570
|
|
|
continue; |
|
571
|
|
|
} |
|
572
|
|
|
|
|
573
|
|
|
$sizes = explode('x', $size); |
|
574
|
|
|
if ($sizes[0] == 140 && $sizes[1] == 140) { |
|
575
|
|
|
$requiredSizeExists = true; |
|
576
|
|
|
} |
|
577
|
|
|
$sizesArray[] = $size; |
|
578
|
|
|
} |
|
579
|
|
|
|
|
580
|
|
|
if ($requiredSizeExists === false) { |
|
581
|
|
|
$sizesArray[] = '140x140'; |
|
582
|
|
|
} |
|
583
|
|
|
|
|
584
|
|
|
return $sizesArray; |
|
585
|
|
|
} |
|
586
|
|
|
|
|
587
|
|
|
/** |
|
588
|
|
|
* @param $imageUrl string |
|
589
|
|
|
* @param $articleId int |
|
590
|
|
|
*/ |
|
591
|
|
|
public function importMainImage($imageUrl, $articleId) |
|
592
|
|
|
{ |
|
593
|
|
|
$oldMainImageId = $this->manager->getConnection()->fetchColumn( |
|
594
|
|
|
'SELECT id FROM s_articles_img WHERE articleID = ? AND main = 1 AND parent_id IS NULL', |
|
595
|
|
|
[$articleId] |
|
596
|
|
|
); |
|
597
|
|
|
|
|
598
|
|
|
$newMainImageId = $this->manager->getConnection()->fetchColumn( |
|
599
|
|
|
' |
|
600
|
|
|
SELECT s_articles_img.id |
|
601
|
|
|
FROM s_articles_img |
|
602
|
|
|
INNER JOIN s_media ON s_articles_img.media_id = s_media.id |
|
603
|
|
|
INNER JOIN s_media_attributes ON s_media.id = s_media_attributes.mediaID |
|
604
|
|
|
WHERE s_articles_img.articleID = ? AND s_articles_img.parent_id IS NULL AND s_media_attributes.connect_hash = ?', |
|
605
|
|
|
[$articleId, $imageUrl] |
|
606
|
|
|
); |
|
607
|
|
|
|
|
608
|
|
|
if ($newMainImageId && $newMainImageId !== $oldMainImageId) { |
|
609
|
|
|
$this->manager->getConnection()->executeQuery( |
|
610
|
|
|
' |
|
611
|
|
|
UPDATE s_articles_img SET main = ? WHERE id = ?', |
|
612
|
|
|
[0, $oldMainImageId] |
|
613
|
|
|
); |
|
614
|
|
|
$this->manager->getConnection()->executeQuery( |
|
615
|
|
|
' |
|
616
|
|
|
UPDATE s_articles_img SET main = ? WHERE id = ?', |
|
617
|
|
|
[1, $newMainImageId] |
|
618
|
|
|
); |
|
619
|
|
|
} |
|
620
|
|
|
} |
|
621
|
|
|
|
|
622
|
|
|
/** |
|
623
|
|
|
* @param $imageUrl string |
|
624
|
|
|
* @param $articleId int |
|
625
|
|
|
* @return bool |
|
626
|
|
|
*/ |
|
627
|
|
|
public function hasMainImageChanged($imageUrl, $articleId) |
|
628
|
|
|
{ |
|
629
|
|
|
$result = $this->manager->getConnection()->fetchColumn( |
|
630
|
|
|
' |
|
631
|
|
|
SELECT s_articles_img.id |
|
632
|
|
|
FROM s_articles_img |
|
633
|
|
|
INNER JOIN s_media ON s_articles_img.media_id = s_media.id |
|
634
|
|
|
INNER JOIN s_media_attributes ON s_media.id = s_media_attributes.mediaID |
|
635
|
|
|
WHERE s_articles_img.articleID = ? AND s_articles_img.main = 1 AND s_articles_img.parent_id IS NULL AND s_media_attributes.connect_hash = ?', |
|
636
|
|
|
[$articleId, $imageUrl] |
|
637
|
|
|
); |
|
638
|
|
|
|
|
639
|
|
|
return !(bool) $result; |
|
640
|
|
|
} |
|
641
|
|
|
|
|
642
|
|
|
/** |
|
643
|
|
|
* @param Detail $detail |
|
644
|
|
|
* @param array $lastUpdate |
|
645
|
|
|
*/ |
|
646
|
|
|
private function importArticleImagesWhenMainDetail($detail, array $lastUpdate) |
|
647
|
|
|
{ |
|
648
|
|
|
if ($detail->getKind() == 1) { |
|
649
|
|
|
$this->importImagesForArticle(array_diff($lastUpdate['image'], $lastUpdate['variantImages']), $detail->getArticle()); |
|
650
|
|
|
} |
|
651
|
|
|
} |
|
652
|
|
|
} |
|
653
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.