1 <?php
2
3 /* --------------------------------------------------------------
4 ProductWriteService.inc.php 2016-02-09
5 Gambio GmbH
6 http://www.gambio.de
7 Copyright (c) 2016 Gambio GmbH
8 Released under the GNU General Public License (Version 2)
9 [http://www.gnu.org/licenses/gpl-2.0.html]
10 --------------------------------------------------------------
11 */
12
13 /**
14 * Class ProductWriteService
15 *
16 * @category System
17 * @package Product
18 */
19 class ProductWriteService implements ProductWriteServiceInterface
20 {
21 /**
22 * The product repository.
23 *
24 * @var ProductRepositoryInterface
25 */
26 protected $productRepo;
27
28 /**
29 * The product image storage.
30 *
31 * @var AbstractFileStorage
32 */
33 protected $productImageStorage;
34
35 /**
36 * The product category linker.
37 *
38 * @var ProductCategoryLinkerInterface
39 */
40 protected $productLinker;
41
42 /**
43 * EnvProductImagePathsSettings.
44 *
45 * @var ProductImagePathsSettingsInterface
46 */
47 protected $envProductImagePathsSettings;
48
49 /**
50 * Used for fetching the language data.
51 *
52 * @var LanguageProviderInterface
53 */
54 protected $languageProvider;
55
56
57 /**
58 * ProductWriteService constructor.
59 *
60 * @param \ProductRepositoryInterface $productRepo
61 * @param \AbstractFileStorage $productImageStorage
62 * @param \ProductCategoryLinkerInterface $productLinker
63 * @param \ProductImagePathsSettingsInterface $envProductImagePathsSettings
64 * @param \LanguageProviderInterface $languageProvider
65 */
66 public function __construct(ProductRepositoryInterface $productRepo,
67 AbstractFileStorage $productImageStorage,
68 ProductCategoryLinkerInterface $productLinker,
69 ProductImagePathsSettingsInterface $envProductImagePathsSettings,
70 LanguageProviderInterface $languageProvider)
71 {
72 $this->productRepo = $productRepo;
73 $this->productImageStorage = $productImageStorage;
74 $this->productLinker = $productLinker;
75 $this->envProductImagePathsSettings = $envProductImagePathsSettings;
76 $this->languageProvider = $languageProvider;
77 }
78
79
80 /**
81 * Create Product
82 *
83 * Creates a new product and returns the ID of it.
84 *
85 * @param ProductInterface $product The product to create.
86 *
87 * @return int The ID of the created product.
88 *
89 * @throws InvalidArgumentException Through "linkProduct" method.
90 */
91 public function createProduct(ProductInterface $product)
92 {
93 $productId = $this->productRepo->add($product);
94
95 $this->linkProduct(new IdType($productId), new IdType(0)); // 0 is the default category value.
96
97 return $productId;
98 }
99
100
101 /**
102 * Update Product
103 *
104 * Updates a stored product.
105 *
106 * @param StoredProductInterface $product The product to update.
107 *
108 * @return ProductWriteServiceInterface Same instance for chained method calls.
109 */
110 public function updateProduct(StoredProductInterface $product)
111 {
112 $this->productRepo->store($product);
113
114 return $this;
115 }
116
117
118 /**
119 * Delete Product
120 *
121 * Deletes a specific product, depending on the provided product ID.
122 *
123 * @param IdType $productId The product ID of the product to delete.
124 *
125 * @return ProductWriteServiceInterface Same instance for chained method calls.
126 */
127 public function deleteProductById(IdType $productId)
128 {
129 $this->productLinker->deleteProductLinks($productId);
130
131 $product = $this->productRepo->getProductById($productId);
132 $this->productImageStorage->deleteFile(new FilenameStringType($product->getPrimaryImage()->getFilename()));
133 foreach($product->getAdditionalImages()->getArray() as $additionalImage)
134 {
135 $this->productImageStorage->deleteFile(new FilenameStringType($additionalImage->getFilename()));
136 }
137
138 $this->productRepo->deleteProductById($productId);
139
140 return $this;
141 }
142
143
144 /**
145 * Duplicate Product
146 *
147 * Duplicates a product to a category.
148 *
149 * @param IdType $productId The product ID of the product to duplicate.
150 * @param IdType $targetCategoryId The target category ID of the product to be duplicated to.s
151 * @param BoolType $duplicateAttributes Should the attributes be duplicated also?
152 * @param BoolType $duplicateSpecials Should the specials be duplicated also?
153 * @param BoolType $duplicateCrossSelling Should cross selling be duplicated also?
154 *
155 * @return int Returns the ID of the new product.
156 *
157 * @throws InvalidArgumentException If "$newProductId" is not an integer.
158 *
159 * @todo Implement the last three arguments when finished in UML.
160 */
161 public function duplicateProduct(IdType $productId,
162 IdType $targetCategoryId,
163 BoolType $duplicateAttributes = null,
164 BoolType $duplicateSpecials = null,
165 BoolType $duplicateCrossSelling = null)
166 {
167 $storedProduct = $this->productRepo->getProductById($productId);
168 $newProductId = new IdType($this->productRepo->add($storedProduct));
169 $this->linkProduct($newProductId, $targetCategoryId);
170
171 // copy product images
172 $storedProductImageContainer = $storedProduct->getImageContainer();
173 $duplicatedProduct = $this->productRepo->getProductById($newProductId);
174 $duplicatedImageContainer = MainFactory::create('ProductImageContainer');
175
176 // primary image
177 $duplicatedPrimaryImage = $this->duplicateProductImage($storedProductImageContainer->getPrimary());
178 $duplicatedImageContainer->setPrimary($duplicatedPrimaryImage);
179
180 // additional images
181 foreach($storedProductImageContainer->getAdditionals()->getArray() as $additionalImage)
182 {
183 $duplicatedAdditionalImage = $this->duplicateProductImage($additionalImage);
184 $duplicatedImageContainer->addAdditional($duplicatedAdditionalImage);
185 }
186
187 $duplicatedProduct->setImageContainer($duplicatedImageContainer);
188 $this->productRepo->store($duplicatedProduct);
189
190 return $newProductId->asInt();
191 }
192
193
194 /**
195 * Link Product
196 *
197 * Links a product to a category.
198 *
199 * @param IdType $productId The product ID of the product to link.
200 * @param IdType $targetCategoryId The target category ID, of the category to be linked to.
201 *
202 * @return ProductWriteService Same instance for chained method calls.
203 */
204 public function linkProduct(IdType $productId, IdType $targetCategoryId)
205 {
206 $this->productLinker->linkProduct($productId, $targetCategoryId);
207
208 return $this;
209 }
210
211
212 /**
213 * Changes the category link of a product.
214 *
215 * @param IdType $productId The product ID of the product to move.
216 * @param IdType $currentCategoryId Old category ID of the product.
217 * @param IdType $newCategoryId New category ID of the product.
218 *
219 * @return ProductWriteService Same instance for chained method calls.
220 */
221 public function changeProductLink(IdType $productId, IdType $currentCategoryId, IdType $newCategoryId)
222 {
223 $this->productLinker->changeProductLink($productId, $currentCategoryId, $newCategoryId);
224
225 return $this;
226 }
227
228
229 /**
230 * Removes a category link from a product by the given product id.
231 *
232 * @param IdType $productId Id of the product.
233 * @param IdType $categoryId Id of category from where the product is link is to delete.
234 *
235 * @return ProductWriteService Same instance for chained method calls.
236 */
237 public function deleteProductLink(IdType $productId, IdType $categoryId)
238 {
239 $this->productLinker->deleteProductLink($productId, $categoryId);
240
241 return $this;
242 }
243
244
245 /**
246 * Import Product Image File
247 *
248 * Imports an image for the product.
249 *
250 * @param ExistingFile $sourceFile The existing file to import.
251 * @param FilenameStringType $preferredFilename The preferred filename.
252 *
253 * @throws InvalidArgumentException If the provided source file or the preferred filename is not valid.
254 *
255 * @return string The new filename.
256 */
257 public function importProductImageFile(ExistingFile $sourceFile, FilenameStringType $preferredFilename)
258 {
259 return $this->productImageStorage->importFile($sourceFile, $preferredFilename);
260 }
261
262
263 /**
264 * Rename Product Image File
265 *
266 * Renames a product image file.
267 *
268 * @param FilenameStringType $oldName The old name of the product image file.
269 * @param FilenameStringType $newName The new name of the product image file.
270 *
271 * @throws InvalidArgumentException If the provided old name or new name is not valid.
272 *
273 * @return ProductWriteService Same instance for chained method calls.
274 */
275 public function renameProductImage(FilenameStringType $oldName, FilenameStringType $newName)
276 {
277 $this->productImageStorage->renameFile($oldName, $newName);
278
279 return $this;
280 }
281
282
283 /**
284 * Delete Product Image
285 *
286 * Deletes a product image.
287 *
288 * @param FilenameStringType $filename The filename of the product image to delete.
289 *
290 * @return ProductWriteService Same instance for chained method calls.
291 */
292 public function deleteProductImage(FilenameStringType $filename)
293 {
294 $this->productImageStorage->deleteFile($filename);
295
296 return $this;
297 }
298
299
300 /**
301 * Removes all category links from a product by given product ID.
302 *
303 * @param IdType $productId ID of product.
304 *
305 * @return ProductWriteService Same instance for chained method calls.
306 */
307 public function deleteProductLinks(IdType $productId)
308 {
309 $this->productLinker->deleteProductLinks($productId);
310
311 return $this;
312 }
313
314
315 /**
316 * Duplicates a given Product Image and set the properties accordingly to the provided Source Product Image
317 *
318 * @param ProductImageInterface $sourceProductImage The Product Image to duplicate.
319 *
320 * @return ProductImageInterface The duplicated Product Image.
321 */
322 protected function duplicateProductImage(ProductImageInterface $sourceProductImage)
323 {
324 $originalImagesDirectoryPath = $this->envProductImagePathsSettings->getProductOriginalImagesDirPath();
325 $filename = new FilenameStringType($sourceProductImage->getFilename());
326 $filepath = new ExistingFile(new NonEmptyStringType($originalImagesDirectoryPath
327 . $sourceProductImage->getFilename()));
328
329 $duplicatedImageFileName = $this->importProductImageFile($filepath, $filename);
330 $duplicatedImage = MainFactory::create('ProductImage',
331 new FilenameStringType($duplicatedImageFileName));
332
333 $duplicatedImage->setVisible(new BoolType($sourceProductImage->isVisible()));
334 foreach($this->languageProvider->getActiveCodes() as $languageCode)
335 {
336 $duplicatedImage->setAltText(new StringType($sourceProductImage->getAltText($languageCode)), $languageCode);
337 }
338
339 return $duplicatedImage;
340 }
341 }