Magento 2 – Creating Product with Custom Options

magento-2.1magento2

I have tried several different ways that to add custom options programmatically to a new product in Magento 2. I am doing this from a CLI command and everything is working well except for the custom options which give me an error:

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (magento_ee.catalog_product_option, CONSTRAINT CATALOG_PRODUCT_OPTION_PRODUCT_ID_CATALOG_PRODUCT_ENTITY_ROW_ID FOREIGN KEY (product_id) REFERENCES catalog_product_entity (row_id) ON), query was: INSERT INTO catalog_product_option (type, is_require, sort_order) VALUES (?, ?, ?)

Here is the stripped down code:

function __construct(
    \Magento\Catalog\Model\Product $product,
    \Magento\Catalog\Model\Product\Option $option,
    \Magento\User\Model\UserFactory $userFactory,
    \Magento\Framework\App\State $state
)
{
    $this->product = $product;
    $this->option = $option;
    parent::__construct();


    /**
     *
     * Bug fix for known Magento issue where product status cannot be changed in custom CLI command without an admin session
     * https://github.com/magento/magento2/issues/5664
     *
     */
    $model = $userFactory->create()->loadByUsername('admin_username_here');

    $state->emulateAreaCode('adminhtml', function ($model) {
        $session = \Magento\Framework\App\ObjectManager::getInstance()->get('Magento\Backend\Model\Auth\Session');
        $session->start();
        $session->setUser($model);
        $session->processLogin();
    }, array($model));


}

// Process some stuff here and call setOptions when necessary

// code goes here


private function setOptions(array $dealArray, $lang) {
    if(count((array) $dealArray['offerItems']) > 1) {
        $this->output->writeln('Multiple Options found, processing...');

        $values = [];
        $i = 1;
        foreach($dealArray['offerItems'] as $item) {
            $this->output->writeln('Setting option: '.$item->$lang->offerItemSKU);

            $values[] = array(
                'title'             => $item->$lang->offerItemValue,
                'price'             => $this->product->getPrice(),
                'price_type'        => "fixed",
                'sku'               => $item->$lang->offerItemSKU,
                'sort_order'        => $i
            );

            $i++;
        }

        $optionArray = array(
                "sort_order"    => 1,
                "title"         => "Options",
                "type"          => "drop_down",
                "is_require"    => 1,
                "values"        => $values
            );

        $this->output->writeln('Setting options for SKU: '.$this->product->getSku().PHP_EOL.print_r($optionArray, true));
        $this->option->addData($optionArray);
        $this->option->save();

        $this->product->setOptions([$this->option]);
        $this->option->clearInstance();

    } else {
        $this->output->writeln('No Options found.');
    }
}

Best Answer

I found the solution:

Instead of calling setProductId like this:

$this->option->setProductId($this->product->getId());

I had to call it like this:

$this->option->setProductId($this->product->getData('row_id'));

It seems to want the row_id instead of the entity_id, which is inconsistent with the rest of Magento2 implementations.

Final code looks like this:

private function setOptions(array $dealArray, $lang) {
    if(count((array) $dealArray['offerItems']) > 1) {
        $this->product->setHasOptions(1);
        $this->product->setCanSaveCustomOptions(true);
        $this->output->writeln('Multiple Options found, processing...');

        $values = [];
        $i = 1;
        foreach($dealArray['offerItems'] as $item) {

            $values[] = array(
                'title'             => $item->$lang->offerItemValue,
                'price'             => $this->product->getPrice(),
                'price_type'        => "fixed",
                'sku'               => $item->$lang->offerItemSKU,
                'sort_order'        => $i
            );

            $i++;
        }

        $this->option->setTitle('Options');
        $this->option->setType('drop_down');
        $this->option->setSku($this->product->getId().'_option');
        $this->option->setProductId($this->product->getData('row_id'));
        $this->option->setProductSku($this->product->getSku());
        $this->option->setIsRequire(true);
        $this->option->setSortOrder(1);
        $this->option->setValues($values);
        $this->option->save();

        $this->product->setOptions([$this->option]);

    } else {
        $this->output->writeln('No Options found.');
    }
}
Related Topic