Tuesday 26 June 2018

How to create configurable product with simple products with attributes using controller in Magento 2 Programmatically | Custom | Custom Module

How to create configurable product with simple products in Magento 2


Step 1 : Create Cotroller

<?php

namespace Jaydip\Kansagra\Controller\Jaydip;

use Magento\Framework\App\Action\Context;

class Createproduct extends \Magento\Framework\App\Action\Action {

    protected $_resultpageFactory;
    protected $_eavAttributeFactory;
    protected $eavConfig;
    protected $directoryList;
    protected $file;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $pageFactory,
        \Magento\Framework\App\Filesystem\DirectoryList $directoryList,
        \Magento\Framework\Filesystem\Io\File $file) {

        $this->_resultpageFactory = $pageFactory;
        $this->directoryList = $directoryList;
        $this->file = $file;
        return parent::__construct($context);
    }

    public function execute() {

        /*$postdata = $this->_request->getPost('product');*/
        $postdata = array(
                    'name' => 'Jaydip Kansagra Test product',
                    'magentoid' => 0,
                    'description' => 'description',
                    'categoryid' => 3,
                    'handle'    => 'jaydipkansagra',
                    'image'     => 'https://domain.com/jaydipkansagra.jpg',
                    'variants' => array(
                        '7407003205687' => array(
                            'id' => 7407003205687,
                            'title' => 'Jaydip Kansagra Test product Child 1',
                            'magechildid' => 0,
                            'sku' => 'CASCADETANK-Black',
                            'inventory' => 1,
                            'price' => 31.95,
                            'c_price' => 0,
                            'weight' => 6.8079,
                            'barcode' => 0,
                            'images'    => array(
                                0 => 'https://domain.com/jaydipkansagra.jpg'
                            )

                        ),
                        '7407003238455' => array(
                            'id' => 7407003238455,
                            'title' => 'Jaydip Kansagra Test product child 2',
                            'magechildid' => 0,
                            'sku' => 'CASCADETANK-Rainbow',
                            'inventory' => 1,
                            'price' => 31.95,
                            'c_price' => 0,
                            'weight' => 6.8079,
                            'barcode' => 0,
                            'images'    => array(
                                0 => 'https://domain.com/jaydipkansagra.jpg'
                            )
                        )

                    ),
                    'options'=> array(
                        'name'=>'Color',
                        'value'=>array(
                            0=> 'Red',
                            1=> 'Green'
                        )
                    )
        );

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $productattr = $objectManager->create('Jaydip\Kansagra\Helper\Productattr');
        $channelstore = $objectManager->create('Magento\Customer\Model\Session');
        $channelstore = $channelstore->getChannelStore();

        if($postdata['magentoid'] > 0){

            $productCollection = $objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Collection');
            $productCollection->addAttributeToSelect('*');
            $productCollection->addAttributeToFilter('entity_id', array('eq' => $postdata['magentoid']));
            $productCollection->addAttributeToFilter('type_id', array('eq' => 'configurable'));
            $magentoproduct = array();

            $magentoproduct['child'] = array();
            foreach ($productCollection as $product):
                if($product->getTypeId() == 'configurable'){
                    $_children = $product->getTypeInstance()->getUsedProducts($product);
                    foreach ($_children as $child){
                        $product = $objectManager->create('Magento\Catalog\Model\Product')->load($child->getId());
                        $magentoproduct['child'][] = json_decode(json_encode($product->getData()));
                    }
                }
            endforeach;
        }

        //Remove product from vapejuice which is removed
        if(isset($magentoproduct['child'])){
            foreach ($magentoproduct['child'] as $child):
                if(!isset($postdata['variants'][$child->source_variant_id])){
                    $registry = $objectManager->get('\Magento\Framework\Registry');
                    $registry->register('isSecureArea', true);
                    $removeproduct = $objectManager->create('\Magento\Catalog\Model\Product');
                    $removeproduct->load($child->entity_id);
                    $removeproduct->delete();
                }
            endforeach;
        }

        //Create / or get Attribute detail
        $attributes = $attrgroup = $associatedProductIds = array();
        foreach ($postdata['options'] as $j=>$option):
            $j++;
            foreach ($option['values'] as $value):
                try {
                    $attributes[$j][$value] = $productattr->createOrGetId($option['name'], $value);
                } catch (\Exception $e) {
                    echo $e->getMessage();
                }
            endforeach;

        endforeach;

        foreach ($postdata['variants'] as $variant): //Create Simple product

            $weight = $variant['weight'];
            $weight = ($weight!=0)?$weight:1;
            $price = $variant['price'];
            $inventory = $variant['inventory'];

            $product = $objectManager->create('\Magento\Catalog\Model\Product');
            if(isset($variant['magechildid']) && $variant['magechildid'] > 0){
                $product->load($variant['magechildid']);
            }

            $varianttitle = $variant['title'];
            $title = $postdata['name'].$varianttitle;
            $urltitle = str_replace(' ', '-', $title);
            $urlkey = preg_replace("#[^a-zA-Z0-9]+/[^a-zA-Z0-9]+#", "", strtolower($urltitle));
            $sku = ($variant['sku'] != '')?$variant['sku']:$urltitle;

            $product->setName($title);
            $product->setUrlKey($urlkey);
            $product->setSku($sku);
            $product->setAttributeSetId(4);
            $product->setStatus(1);
            $product->setWebsiteIds(array(1));
            $product->setWeight($weight);
            $product->setVisibility(1);
            $product->setTaxClassId(0);
            $product->setCategoryIds([$postdata['categoryid']]);
            $product->setTypeId('simple');
            $product->setPrice($price);

            //Set attribute value for simple product
            foreach ($attributes as $k=>$attribute):
                $attr = $attribute[$variant['option'.$k]];
                $attrlabel = 'set'.ucfirst(strtolower($attr['attrcode']));
                $product->$attrlabel($attr['optionid']);
                $attrgroup[] = $attr['attrid'];
            endforeach;

            $product->setStockData(
                array(
                    'use_config_manage_stock' => 1,
                    'manage_stock' => 1,
                    'is_in_stock' => 1,
                    'qty' => $inventory
                )
            );

            //Set Images
            foreach ($postdata['images'] as $simage):

                $imagePath = $simage;
                if (@getimagesize($imagePath)) {
                    $this->setImage($product, $imagePath, false, $imageType = ['image', 'small_image', 'thumbnail']);
                }

            endforeach;

            $product->save();

            $associatedProductIds[] = $product->getId();
            //pre(json_decode(json_encode($product->getData())));
        endforeach;

        $postproductnm = $postdata['name'];
        $postproductdesc = $postdata['description'];

        $attrgroup = array_unique($attrgroup);

        $mainurl = str_replace(' ', '-', strtolower($postdata['name']));

        //Create master simple product for make it configurable
        $product = $objectManager->create('\Magento\Catalog\Model\Product');
        if(isset($postdata['magentoid']) && $postdata['magentoid'] > 0){
            $product->load($postdata['magentoid']);
        }
        $product->setName($postproductnm); // Name of Product
        $product->setDescription($postproductdesc); // Description of Product
        $product->setSku($mainurl); // Set your sku here
        $product->setUrlKey($postdata['handle']); // Set your URL here
        $product->setAttributeSetId(4); // Attribute set id
        $product->setStatus(1); // Status on product enabled/ disabled 1/0
        $product->setCategoryIds([$postdata['categoryid']]);
        $product->setWebsiteIds(array(1)); // Website Ids
        $product->setWeight($variant['weight']); // weight of product
        $product->setVisibility(4); // visibilty of product (catalog / search / catalog, search / Not visible individually)
        $product->setTaxClassId(0); // Tax class id
        $product->setTypeId('simple'); // type of product (simple/virtual/downloadable/configurable)

        $product->setStockData(
            array(
                'use_config_manage_stock' => 1,
                'manage_stock' => 1,
                'is_in_stock' => 1,
                'qty' => 1
            )
        );

        if(isset($postdata['image'])){

            $imagePath = $postdata['image'];
            if (@getimagesize($imagePath)) {
                $this->setImage($product, $imagePath, false, $imageType = ['image', 'small_image', 'thumbnail']);
            }    
        }

        $product->save();

        //Create configurable which is Master simple product with assign simple product to Configurable product
        $productId = $product->getId(); // Master simple Product Id
        $product = $objectManager->create('Magento\Catalog\Model\Product')->load($productId); // Load Master simple Product
        $attributeModel = $objectManager->create('Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute');
        $position = 0;
        $attributes = $attrgroup; // Super Attribute Ids Used To Create Configurable Product
        foreach ($attributes as $attributeId) {
            $data = array('attribute_id' => $attributeId, 'product_id' => $productId, 'position' => $position);
            $position++;
            $attributeModel->setData($data)->save();
        }
        $product->setTypeId("configurable"); // Setting Product Type As Configurable
        $product->setAffectConfigurableProductAttributes(4);
        $objectManager->create('Magento\ConfigurableProduct\Model\Product\Type\Configurable')->setUsedProductAttributeIds($attributes, $product);
        $product->setNewVariationsAttributeSetId(4); // Setting Attribute Set Id
        $product->setAssociatedProductIds($associatedProductIds);// Setting Associated Products
        $product->setCanSaveConfigurableAttributes(true);
        $product->save();
        pre(json_encode($product->getData()));exit;
    }

    protected function getMediaDirTmpDir()
    {
        return $this->directoryList->getPath($this->directoryList::MEDIA) . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
    }

    protected function setImage($product, $imageUrl, $visible = false, $imageType = [])
    {
        /** @var string $tmpDir */
        $tmpDir = $this->getMediaDirTmpDir();
        /** create folder if it is not exists */
        $this->file->checkAndCreateFolder($tmpDir);
        /** @var string $newFileName */
        $newFileName = $tmpDir . baseName($imageUrl);

        /** read file from URL and copy it to the new destination */
        $result = $this->file->read($imageUrl, $newFileName);
        if ($result) {
            /** add saved file to the $product gallery */
            $product->addImageToMediaGallery($newFileName, $imageType, true, $visible);
        }
        return $result;
    }

}

Step 2 : Create Helper for attribute



<?php

/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Jaydip\Kansagra\Helper;

use Magento\Framework\Registry;

class Productattr extends \Magento\Framework\App\Helper\AbstractHelper {

    /**
     * @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
     */
    protected $attributeRepository;

    /**
     * @var array
     */
    protected $attributeValues;

    /**
     * @var \Magento\Eav\Model\Entity\Attribute\Source\TableFactory
     */
    protected $tableFactory;

    /**
     * @var \Magento\Eav\Api\AttributeOptionManagementInterface
     */
    protected $attributeOptionManagement;

    /**
     * @var \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory
     */
    protected $optionLabelFactory;

    /**
     * @var \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory
     */
    protected $optionFactory;

    protected $eavAttributeFactory;

    protected $attributeManagement;

    protected $config;

    /**
     * Data constructor.
     *
     * @param \Magento\Framework\App\Helper\Context $context
     * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
     * @param \Magento\Eav\Model\Entity\Attribute\Source\TableFactory $tableFactory
     * @param \Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement
     * @param \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory $optionLabelFactory
     * @param \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory
     */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Catalog\Model\Config $config,
        \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
        \Magento\Eav\Model\Entity\Attribute\Source\TableFactory $tableFactory,
        \Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement,
        \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory $optionLabelFactory,
        \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory,
        \Magento\Eav\Api\AttributeManagementInterface $attributeManagement,
        \Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory $eavAttributeFactory
    ) {
        parent::__construct($context);

        $this->attributeRepository = $attributeRepository;
        $this->tableFactory = $tableFactory;
        $this->attributeOptionManagement = $attributeOptionManagement;
        $this->optionLabelFactory = $optionLabelFactory;
        $this->optionFactory = $optionFactory;
        $this->eavAttributeFactory = $eavAttributeFactory;
        $this->config = $config;
        $this->attributeManagement = $attributeManagement;
    }

    /**
     * Get attribute by code.
     *
     * @param string $attributeCode
     * @return \Magento\Catalog\Api\Data\ProductAttributeInterface
     */
    public function getAttribute($attributeCode) {
        try {
            return $this->attributeRepository->get($attributeCode);
        } catch (\Exception $e) {
            return false;
        }
    }

    public function addAttribute($attributecode, $attributelabel, $attroptions = array()) {

        $attributeData = array(
            'attribute_code' => $attributecode,
            'is_global' => 1,
            'frontend_label' => $attributelabel,
            'frontend_input' => 'select',
            'default_value_text' => '',
            'default_value_yesno' => 0,
            'default_value_date' => '',
            'default_value_textarea' => '',
            'is_unique' => 0,
            'apply_to' => 0,
            'is_required' => 0,
            'is_configurable' => 1,
            'is_searchable' => 1,
            'is_comparable' => 1,
            'is_visible_in_advanced_search' => 0,
            'is_used_for_price_rules' => 0,
            'is_wysiwyg_enabled' => 0,
            'is_html_allowed_on_front' => 0,
            'is_visible_on_front' => 0,
            'used_in_product_listing' => 0,
            'used_for_sort_by' => 0,
            'is_filterable' => 1,
            'is_filterable_in_search' => 0,
            'backend_type' => 'int',
            'is_user_defined' => 1,
            'group' => 'General',
            'option' => array()
        );
        foreach ($attroptions as $key=>$attroption):
            $attributeData['option']['value']['option_'.$key] = array($attroption, $attroption);
        endforeach;

        try {
            $model = $this->eavAttributeFactory->create();
            $model->addData($attributeData);
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $entityTypeID = $objectManager->create('Magento\Eav\Model\Entity')
            ->setType('catalog_product')
            ->getTypeId();
            $model->setEntityTypeId($entityTypeID);
            $model->save();

            $group_id = $this->config->getAttributeGroupId(4, 'Attribute Option');
            $this->attributeManagement->assign('catalog_product', 4, $group_id, $model->getAttributeCode(), null);

            return $model;
        } catch (\Exception $e) {
            return $e->getMessage();
        }       
    }

    /**
     * Find or create a matching attribute option
     *
     * @param string $attributeCode Attribute the option should exist in
     * @param string $label Label to find or add
     * @return int
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function createOrGetId($attributeCode, $label = '') {

        if (strlen($label) < 1) {
            throw new \Magento\Framework\Exception\LocalizedException(
            __('Label for %1 must not be empty.', $attributeCode)
            );
        }

        $label = ucfirst(strtolower($label));
        $attributeLabel = ucfirst(strtolower($attributeCode));
        $attributeCode = preg_replace("/[^a-zA-Z0-9]+/", "", strtolower($attributeCode));

        $attribute = $this->getAttribute($attributeCode);

        if(!$attribute){
            //Create new attribute
            $attribute = $this->addAttribute($attributeCode, $attributeLabel, array($label));
        }

        // Does it already exist?
        $optionId = $this->getOptionId($attributeCode, $label);
        if (!$optionId) {
            // If no, add it.

            /** @var \Magento\Eav\Model\Entity\Attribute\OptionLabel $optionLabel */
            $optionLabel = $this->optionLabelFactory->create();
            $optionLabel->setStoreId(0);
            $optionLabel->setLabel($label);

            $option = $this->optionFactory->create();
            $option->setLabel($optionLabel);
            $option->setStoreLabels([$optionLabel]);
            $option->setSortOrder(0);
            $option->setIsDefault(false);

            $this->attributeOptionManagement->add(
                    \Magento\Catalog\Model\Product::ENTITY, $this->getAttribute($attributeCode)->getAttributeId(), $option
            );

            // Get the inserted ID. Should be returned from the installer, but it isn't.
            $optionId = $this->getOptionId($attributeCode, $label, true);
        }

        return array('attrid'=>$attribute->getAttributeId(), 'attrcode'=>$attributeCode, 'optionid'=>$optionId);
    }

    /**
     * Find the ID of an option matching $label, if any.
     *
     * @param string $attributeCode Attribute code
     * @param string $label Label to find
     * @param bool $force If true, will fetch the options even if they're already cached.
     * @return int|false
     */
    public function getOptionId($attributeCode, $label, $force = false) {
        /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
        $attribute = $this->getAttribute($attributeCode);

        // Build option array if necessary
        if ($force === true || !isset($this->attributeValues[$attribute->getAttributeId()])) {
            $this->attributeValues[$attribute->getAttributeId()] = [];

            // We have to generate a new sourceModel instance each time through to prevent it from
            // referencing its _options cache. No other way to get it to pick up newly-added values.

            /** @var \Magento\Eav\Model\Entity\Attribute\Source\Table $sourceModel */
            $sourceModel = $this->tableFactory->create();
            $sourceModel->setAttribute($attribute);

            foreach ($sourceModel->getAllOptions() as $option) {
                $this->attributeValues[$attribute->getAttributeId()][$option['label']] = $option['value'];
            }
        }

        // Return option ID if exists
        if (isset($this->attributeValues[$attribute->getAttributeId()][$label])) {
            return $this->attributeValues[$attribute->getAttributeId()][$label];
        }

        // Return false if does not exist
        return false;
    }

}