Context:
Interface
Implementation: \Magento\Catalog\Model\ProductRepository
6a377bb/app/code/Magento/Catalog/Model/ProductRepository.php#L483-L555
/**
* {@inheritdoc}
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveOptions = false)
{
$tierPrices = $product->getData('tier_price');
try {
$existingProduct = $this->get($product->getSku());
$product->setData(
$this->resourceModel->getLinkField(),
$existingProduct->getData($this->resourceModel->getLinkField())
);
} catch (NoSuchEntityException $e) {
$existingProduct = null;
}
$productDataArray = $this->extensibleDataObjectConverter
->toNestedArray($product, [], 'Magento\Catalog\Api\Data\ProductInterface');
$productDataArray = array_replace($productDataArray, $product->getData());
unset($productDataArray['media_gallery']);
$ignoreLinksFlag = $product->getData('ignore_links_flag');
$productLinks = null;
if (!$ignoreLinksFlag && $ignoreLinksFlag !== null) {
$productLinks = $product->getProductLinks();
}
$productDataArray['store_id'] = (int)$this->storeManager->getStore()->getId();
$product = $this->initializeProductData($productDataArray, empty($existingProduct));
$this->processLinks($product, $productLinks);
if (isset($productDataArray['media_gallery_entries'])) {
$this->processMediaGallery($product, $productDataArray['media_gallery_entries']);
}
if (!$product->getOptionsReadonly()) {
$product->setCanSaveCustomOptions(true);
}
$validationResult = $this->resourceModel->validate($product);
if (true !== $validationResult) {
throw new \Magento\Framework\Exception\CouldNotSaveException(
__('Invalid product data: %1', implode(',', $validationResult))
);
}
try {
if ($tierPrices !== null) {
$product->setData('tier_price', $tierPrices);
}
unset($this->instances[$product->getSku()]);
unset($this->instancesById[$product->getId()]);
$this->resourceModel->save($product);
} catch (\Magento\Eav\Model\Entity\Attribute\Exception $exception) {
throw \Magento\Framework\Exception\InputException::invalidFieldValue(
$exception->getAttributeCode(),
$product->getData($exception->getAttributeCode()),
$exception
);
} catch (ValidatorException $e) {
throw new CouldNotSaveException(__($e->getMessage()));
} catch (LocalizedException $e) {
throw $e;
} catch (\Exception $e) {
throw new \Magento\Framework\Exception\CouldNotSaveException(__('Unable to save product'));
}
unset($this->instances[$product->getSku()]);
unset($this->instancesById[$product->getId()]);
return $this->get($product->getSku());
}
Usage
1. From the /V1/products
Web API:
Details: How to create a product programmatically with the /V1/products
Web API?
2. \Magento\Catalog\Model\Product\PriceModifier::removeTierPrice()
3. \Magento\Catalog\Model\Product\TierPriceManagement::add()
4. \Magento\Catalog\Model\Product\Gallery\GalleryManagement::create()
5. \Magento\Catalog\Model\Product\Gallery\GalleryManagement::update()
6. \Magento\Catalog\Model\Product\Gallery\GalleryManagement::remove()
7. \Magento\Catalog\Model\Product\Option\Repository::deleteByIdentifier()
8. \Magento/Catalog/Model/ProductLink/Management::setProductLinks()
9. \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceTest::testReindexEntitiesForConfigurableProduct()
10.
11.
12. \Magento\ConfigurableProduct\Model\Product\Type\ConfigurableTest::testSaveProductRelationsOneChild()
13. \Magento\ConfigurableProduct\Model\Product\Type\ConfigurableTest::testSaveProductRelationsNoChildren()
14. \Magento\ConfigurableProduct\Model\Product\Type\Configurable\PriceTest::testGetFinalPriceWithCustomOption()
15.
6a377bb/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle.php#L36-L150
$productRepository = $objectManager->get(Magento\Catalog\Api\ProductRepositoryInterface::class);
/**
* @var \Magento\Catalog\Model\Product $product
*/
$product = $objectManager->create('Magento\Catalog\Model\Product');
$product
->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE)
->setAttributeSetId(4)
->setWebsiteIds([1])
->setName('Bundle Product')
->setSku('bundle-product')
->setDescription('Description with <b>html tag</b>')
->setShortDescription('Bundle')
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
->setStockData(
[
'use_config_manage_stock' => 0,
'manage_stock' => 0,
'use_config_enable_qty_increments' => 1,
'use_config_qty_increments' => 1,
'is_in_stock' => 0,
]
)
->setBundleOptionsData(
[
[
'title' => 'Bundle Product Items',
'default_title' => 'Bundle Product Items',
'type' => 'checkbox',
'required' => 1,
'delete' => '',
'position' => 0,
'option_id' => '',
],
]
)
->setBundleSelectionsData(
[
[
[
'product_id' => $simpleProducts[0]->getId(),
'selection_qty' => 1,
'selection_can_change_qty' => 1,
'delete' => '',
'position' => 0,
'selection_price_type' => 0,
'selection_price_value' => 0.0,
'option_id' => '',
'selection_id' => '',
'is_default' => 1,
],
[
'product_id' => $simpleProducts[1]->getId(),
'selection_qty' => 1,
'selection_can_change_qty' => 1,
'delete' => '',
'position' => 0,
'selection_price_type' => 0,
'selection_price_value' => 0.0,
'option_id' => '',
'selection_id' => '',
'is_default' => 1,
]
],
]
)->setCustomAttributes([
"price_type" => [
'attribute_code' => 'price_type',
'value' => \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC
],
"price_view" => [
"attribute_code" => "price_view",
"value" => "1",
],
])
->setCanSaveBundleSelections(true)
->setHasOptions(false)
->setAffectBundleProductSelections(true);
if ($product->getBundleOptionsData()) {
$options = [];
foreach ($product->getBundleOptionsData() as $key => $optionData) {
if (!(bool)$optionData['delete']) {
$option = $objectManager->create('Magento\Bundle\Api\Data\OptionInterfaceFactory')
->create(['data' => $optionData]);
$option->setSku($product->getSku());
$option->setOptionId(null);
$links = [];
$bundleLinks = $product->getBundleSelectionsData();
if (!empty($bundleLinks[$key])) {
foreach ($bundleLinks[$key] as $linkData) {
if (!(bool)$linkData['delete']) {
/** @var \Magento\Bundle\Api\Data\LinkInterface$link */
$link = $objectManager->create('Magento\Bundle\Api\Data\LinkInterfaceFactory')
->create(['data' => $linkData]);
$linkProduct = $productRepository->getById($linkData['product_id']);
$link->setSku($linkProduct->getSku());
$link->setQty($linkData['selection_qty']);
if (isset($linkData['selection_can_change_qty'])) {
$link->setCanChangeQuantity($linkData['selection_can_change_qty']);
}
$links[] = $link;
}
}
$option->setProductLinks($links);
$options[] = $option;
}
}
}
$extension = $product->getExtensionAttributes();
$extension->setBundleProductOptions($options);
$product->setExtensionAttributes($extension);
}
$productRepository->save($product);