Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
LinkManagement.php
Go to the documentation of this file.
1 <?php
8 namespace Magento\Bundle\Model;
9 
16 
21 {
25  protected $productRepository;
26 
30  protected $linkFactory;
31 
35  protected $bundleFactory;
36 
40  protected $bundleSelection;
41 
45  protected $optionCollection;
46 
50  protected $dataObjectHelper;
51 
55  private $metadataPool;
56 
66  public function __construct(
68  \Magento\Bundle\Api\Data\LinkInterfaceFactory $linkFactory,
69  \Magento\Bundle\Model\SelectionFactory $bundleSelection,
70  \Magento\Bundle\Model\ResourceModel\BundleFactory $bundleFactory,
71  \Magento\Bundle\Model\ResourceModel\Option\CollectionFactory $optionCollection,
73  \Magento\Framework\Api\DataObjectHelper $dataObjectHelper
74  ) {
75  $this->productRepository = $productRepository;
76  $this->linkFactory = $linkFactory;
77  $this->bundleFactory = $bundleFactory;
78  $this->bundleSelection = $bundleSelection;
79  $this->optionCollection = $optionCollection;
80  $this->storeManager = $storeManager;
81  $this->dataObjectHelper = $dataObjectHelper;
82  }
83 
87  public function getChildren($productSku, $optionId = null)
88  {
89  $product = $this->productRepository->get($productSku, true);
90  if ($product->getTypeId() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
91  throw new InputException(__('This is implemented for bundle products only.'));
92  }
93 
94  $childrenList = [];
95  foreach ($this->getOptions($product) as $option) {
96  if (!$option->getSelections() || ($optionId !== null && $option->getOptionId() != $optionId)) {
97  continue;
98  }
100  foreach ($option->getSelections() as $selection) {
101  $childrenList[] = $this->buildLink($selection, $product);
102  }
103  }
104  return $childrenList;
105  }
106 
110  public function addChildByProductSku($sku, $optionId, \Magento\Bundle\Api\Data\LinkInterface $linkedProduct)
111  {
113  $product = $this->productRepository->get($sku, true);
114  return $this->addChild($product, $optionId, $linkedProduct);
115  }
116 
122  public function saveChild(
123  $sku,
124  \Magento\Bundle\Api\Data\LinkInterface $linkedProduct
125  ) {
126  $product = $this->productRepository->get($sku, true);
127  if ($product->getTypeId() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
128  throw new InputException(
129  __('The product with the "%1" SKU isn\'t a bundle product.', [$product->getSku()])
130  );
131  }
132 
134  $linkProductModel = $this->productRepository->get($linkedProduct->getSku());
135  if ($linkProductModel->isComposite()) {
136  throw new InputException(__('The bundle product can\'t contain another composite product.'));
137  }
138 
139  if (!$linkedProduct->getId()) {
140  throw new InputException(__('The product link needs an ID field entered. Enter and try again.'));
141  }
142 
144  $selectionModel = $this->bundleSelection->create();
145  $selectionModel->load($linkedProduct->getId());
146  if (!$selectionModel->getId()) {
147  throw new InputException(
148  __(
149  'The product link with the "%1" ID field wasn\'t found. Verify the ID and try again.',
150  [$linkedProduct->getId()]
151  )
152  );
153  }
154  $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
155  $selectionModel = $this->mapProductLinkToSelectionModel(
156  $selectionModel,
158  $linkProductModel->getId(),
159  $product->getData($linkField)
160  );
161 
162  try {
163  $selectionModel->save();
164  } catch (\Exception $e) {
165  throw new CouldNotSaveException(__('Could not save child: "%1"', $e->getMessage()), $e);
166  }
167 
168  return true;
169  }
170 
180  protected function mapProductLinkToSelectionModel(
181  \Magento\Bundle\Model\Selection $selectionModel,
182  \Magento\Bundle\Api\Data\LinkInterface $productLink,
183  $linkedProductId,
184  $parentProductId
185  ) {
186  $selectionModel->setProductId($linkedProductId);
187  $selectionModel->setParentProductId($parentProductId);
188  if ($productLink->getSelectionId() !== null) {
189  $selectionModel->setSelectionId($productLink->getSelectionId());
190  }
191  if ($productLink->getOptionId() !== null) {
192  $selectionModel->setOptionId($productLink->getOptionId());
193  }
194  if ($productLink->getPosition() !== null) {
195  $selectionModel->setPosition($productLink->getPosition());
196  }
197  if ($productLink->getQty() !== null) {
198  $selectionModel->setSelectionQty($productLink->getQty());
199  }
200  if ($productLink->getPriceType() !== null) {
201  $selectionModel->setSelectionPriceType($productLink->getPriceType());
202  }
203  if ($productLink->getPrice() !== null) {
204  $selectionModel->setSelectionPriceValue($productLink->getPrice());
205  }
206  if ($productLink->getCanChangeQuantity() !== null) {
207  $selectionModel->setSelectionCanChangeQty($productLink->getCanChangeQuantity());
208  }
209  if ($productLink->getIsDefault() !== null) {
210  $selectionModel->setIsDefault($productLink->getIsDefault());
211  }
212 
213  return $selectionModel;
214  }
215 
220  public function addChild(
221  \Magento\Catalog\Api\Data\ProductInterface $product,
222  $optionId,
223  \Magento\Bundle\Api\Data\LinkInterface $linkedProduct
224  ) {
225  if ($product->getTypeId() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
226  throw new InputException(
227  __('The product with the "%1" SKU isn\'t a bundle product.', $product->getSku())
228  );
229  }
230 
231  $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
232 
233  $options = $this->optionCollection->create();
234 
235  $options->setIdFilter($optionId);
236  $options->setProductLinkFilter($product->getData($linkField));
237 
238  $existingOption = $options->getFirstItem();
239 
240  if (!$existingOption->getId()) {
241  throw new InputException(
242  __(
243  'Product with specified sku: "%1" does not contain option: "%2"',
244  [$product->getSku(), $optionId]
245  )
246  );
247  }
248 
249  /* @var $resource \Magento\Bundle\Model\ResourceModel\Bundle */
250  $resource = $this->bundleFactory->create();
251  $selections = $resource->getSelectionsData($product->getData($linkField));
253  $linkProductModel = $this->productRepository->get($linkedProduct->getSku());
254  if ($linkProductModel->isComposite()) {
255  throw new InputException(__('The bundle product can\'t contain another composite product.'));
256  }
257 
258  if ($selections) {
259  foreach ($selections as $selection) {
260  if ($selection['option_id'] == $optionId &&
261  $selection['product_id'] == $linkProductModel->getEntityId() &&
262  $selection['parent_product_id'] == $product->getData($linkField)) {
263  if (!$product->getCopyFromView()) {
264  throw new CouldNotSaveException(
265  __(
266  'Child with specified sku: "%1" already assigned to product: "%2"',
267  [$linkedProduct->getSku(), $product->getSku()]
268  )
269  );
270  } else {
271  return $this->bundleSelection->create()->load($linkProductModel->getEntityId());
272  }
273  }
274  }
275  }
276 
277  $selectionModel = $this->bundleSelection->create();
278  $selectionModel = $this->mapProductLinkToSelectionModel(
279  $selectionModel,
281  $linkProductModel->getEntityId(),
282  $product->getData($linkField)
283  );
284  $selectionModel->setOptionId($optionId);
285 
286  try {
287  $selectionModel->save();
288  $resource->addProductRelation($product->getData($linkField), $linkProductModel->getEntityId());
289  } catch (\Exception $e) {
290  throw new CouldNotSaveException(__('Could not save child: "%1"', $e->getMessage()), $e);
291  }
292 
293  return $selectionModel->getId();
294  }
295 
299  public function removeChild($sku, $optionId, $childSku)
300  {
301  $product = $this->productRepository->get($sku, true);
302 
303  if ($product->getTypeId() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
304  throw new InputException(__('The product with the "%1" SKU isn\'t a bundle product.', $sku));
305  }
306 
307  $excludeSelectionIds = [];
308  $usedProductIds = [];
309  $removeSelectionIds = [];
310  foreach ($this->getOptions($product) as $option) {
312  foreach ($option->getSelections() as $selection) {
313  if ((strcasecmp($selection->getSku(), $childSku) == 0) && ($selection->getOptionId() == $optionId)) {
314  $removeSelectionIds[] = $selection->getSelectionId();
315  $usedProductIds[] = $selection->getProductId();
316  continue;
317  }
318  $excludeSelectionIds[] = $selection->getSelectionId();
319  }
320  }
321  if (empty($removeSelectionIds)) {
322  throw new \Magento\Framework\Exception\NoSuchEntityException(
323  __("The bundle product doesn't exist. Review your request and try again.")
324  );
325  }
326  $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
327  /* @var $resource \Magento\Bundle\Model\ResourceModel\Bundle */
328  $resource = $this->bundleFactory->create();
329  $resource->dropAllUnneededSelections($product->getData($linkField), $excludeSelectionIds);
330  $resource->removeProductRelations($product->getData($linkField), array_unique($usedProductIds));
331 
332  return true;
333  }
334 
340  private function buildLink(\Magento\Catalog\Model\Product $selection, \Magento\Catalog\Model\Product $product)
341  {
342  $selectionPriceType = $selectionPrice = null;
343 
345  if ($product->getPriceType()) {
346  $selectionPriceType = $selection->getSelectionPriceType();
347  $selectionPrice = $selection->getSelectionPriceValue();
348  }
349 
351  $link = $this->linkFactory->create();
352  $this->dataObjectHelper->populateWithArray(
353  $link,
354  $selection->getData(),
355  \Magento\Bundle\Api\Data\LinkInterface::class
356  );
357  $link->setIsDefault($selection->getIsDefault())
358  ->setId($selection->getSelectionId())
359  ->setQty($selection->getSelectionQty())
360  ->setCanChangeQuantity($selection->getSelectionCanChangeQty())
361  ->setPrice($selectionPrice)
362  ->setPriceType($selectionPriceType);
363  return $link;
364  }
365 
370  private function getOptions(\Magento\Catalog\Api\Data\ProductInterface $product)
371  {
373  $productTypeInstance = $product->getTypeInstance();
374  $productTypeInstance->setStoreFilter(
375  $product->getStoreId(),
376  $product
377  );
378 
379  $optionCollection = $productTypeInstance->getOptionsCollection($product);
380 
381  $selectionCollection = $productTypeInstance->getSelectionsCollection(
382  $productTypeInstance->getOptionsIds($product),
383  $product
384  );
385 
386  $options = $optionCollection->appendSelections($selectionCollection, true);
387  return $options;
388  }
389 
394  private function getMetadataPool()
395  {
396  if (!$this->metadataPool) {
397  $this->metadataPool = ObjectManager::getInstance()->get(MetadataPool::class);
398  }
399  return $this->metadataPool;
400  }
401 }
$storeManager
__()
Definition: __.php:13
$resource
Definition: bulk.php:12
$linkedProduct
$selectionCollection