konika
konika

Reputation: 113

Magento 2 - Set product attribute to use default values

I want to check Use as Default for all product for a particular store view

I use this code

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$collection = $this->_productCollectionFactory->create();
foreach($collection as $data){
$product=$this->_product->setStoreId(1)->load($data->getEntityId()); 
$product->setData('name',false);
$product->save(); 
}  

But this is removing product from categories. Can you please let me know how I can check Use as default checkbox programmatically.

Upvotes: 1

Views: 9745

Answers (1)

Darren Felton
Darren Felton

Reputation: 2299

Magento 2.1.3 EE

The following solution creates a CLI command to directly manipulate the database and delete store specific product attribute information. It was written for Magento Enterprise edition, so if you're using Community Edition you'll have to modify this code to utilize entity_id instead of row_id.

Please be careful with this. The solution laid forth here bypasses model classes and performs direct delete queries on the default database connection's catalog_product_entity_datetime, catalog_product_entity_decimal, catalog_product_entity_int, catalog_product_entity_text, and catalog_product_entity_varchar tables. Back up your database first.

Step 1: Create the module

app/code/StackOverflow/Question40177336/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'StackOverflow_Question40177336',
    __DIR__
);

app/code/StackOverflow/Question40177336/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="StackOverflow_Question40177336" setup_version="0.0.1"/>
</config>

app/code/StackOverflow/Question40177336/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Console\CommandListInterface">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="stackoverflow_question40177336" xsi:type="object">StackOverflow\Question40177336\Console\Command\Product\UseDefaultValue</item>
            </argument>
        </arguments>
    </type>
</config>

app/code/StackOverflow/Question40177336/Console/Command/Product/UseDefaultValue.php

<?php

namespace StackOverflow\Question40177336\Console\Command\Product;

use Magento\Catalog\Model\Product;
use Magento\Eav\Setup\EavSetup;
use Magento\Framework\App\ResourceConnection;
use Magento\Store\Model\StoreManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class UseDefaultValue extends Command
{
    /**
     * flag indicating if the command has been initialized yet
     *
     * @var bool
     */
    protected $initialized = false;

    /**
     * The attribute_id to use for the current command.
     *
     * @var int
     */
    protected $attributeId;

    /**
     * The row_id values(s) to use for the command (if any).
     *
     * @var array|bool
     */
    protected $rowIds;

    /**
     * The store_id to use for the current command.
     *
     * @var int
     */
    protected $storeId;

    /**
     * The table name to use for the current command.
     *
     * @var string
     */
    protected $tableName;

    /**
     * @var \Magento\Framework\DB\Adapter\AdapterInterface
     */
    protected $connection;

    /**
     * @var EavSetup
     */
    protected $eavSetup;

    /**
     * @var StoreManagerInterface
     */
    protected $storeManager;

    public function __construct(
        EavSetup $eavSetup,
        ResourceConnection $resourceConnection,
        StoreManagerInterface $storeManager
    ) {
        $this->connection = $resourceConnection->getConnection();
        $this->eavSetup = $eavSetup;
        $this->storeManager = $storeManager;
        parent::__construct();
    }

    /**
     * Configures the current command.
     */
    protected function configure()
    {
        $this
            ->setName('catalog:product:attributes:use-default-value')
            ->setDescription('Removes store specific data from a product(s) of given attribute code.')
            ->addArgument(
                'attribute_code',
                InputArgument::REQUIRED,
                'Attribute Code'
            )
            ->addArgument(
                'store',
                InputArgument::REQUIRED,
                'Store code or store_id (cannot be \'admin\' or \'0\')'
            )
            ->addArgument(
                'sku',
                InputArgument::OPTIONAL,
                'Sku (omit to apply to all products)'
            )
        ;
    }

    /**
     * Executes the current command.
     *
     * @param InputInterface  $input  An InputInterface instance
     * @param OutputInterface $output An OutputInterface instance
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->init($input);
        $conn = $this->connection;
        $bind = [
            $conn->quoteInto('store_id = ?', $this->getStoreId()),
            $conn->quoteInto('attribute_id = ?', $this->getAttributeId())
        ];
        if ($this->getRowIds()) {
            $bind[] = $conn->quoteInto('row_id IN (?)', $this->getRowIds());
        }
        $rows = $conn->delete($this->getTableName(), $bind);
        $output->writeln($rows.' rows deleted.');
    }

    /**
     * Return the row_id value(s) to use for the command (if any).
     *
     * @return array|boolean
     */
    protected function getRowIds()
    {
        if (!$this->initialized) {
            $this->errorInit(__METHOD__);
        }
        return $this->rowIds;
    }

    /**
     * Initializes some class properties.
     *
     * @param InputInterface $input
     */
    protected function init(InputInterface $input)
    {
        if (!$this->initialized) {
            $attributeCode = trim($input->getArgument('attribute_code'));
            if ($attributeCode == '') {
                throw new \RuntimeException(__('attribute_code is required.'));
            } elseif (is_numeric($attributeCode)) {
                throw new \RuntimeException(__('attribute_code cannot be numeric.'));
            }
            $attribute = $this->eavSetup->getAttribute(
                Product::ENTITY,
                $attributeCode
            );
            if (!$attribute) {
                throw new \RuntimeException(__('Invalid attribute_code "%1"', $attributeCode));
            }
            $backendType = $attribute['backend_type'];
            $allowedTypes = ['datetime','decimal','int','text','varchar'];
            if (!in_array($backendType, $allowedTypes)) {
                throw new \RuntimeException(__(
                    'backend_type "%1" is not allowed. Allowed types include: %2',
                    $backendType,
                    implode(', ', $allowedTypes)
                ));
            }
            $this->tableName = $this->connection->getTableName('catalog_product_entity_'.$backendType);
            $this->attributeId = (int) $attribute['attribute_id'];

            $store = $this->storeManager->getStore($input->getArgument('store'));
            if ($store->getCode() == 'admin') {
                throw new \RuntimeException(__('Admin Store is not allowed for this command.'));
            }
            $this->storeId = (int) $store->getId();

            $sku = trim($input->getArgument('sku'));
            if ($sku != '') {
                $sql = $this->connection->select()
                    ->from($this->connection->getTableName('catalog_product_entity'), 'row_id')
                    ->where('sku = ?', $sku)
                ;
                $rowIds = $this->connection->fetchCol($sql);
                if (!$rowIds) {
                    throw new \RuntimeException(__('Invalid Sku "%1"', $sku));
                }
                foreach ($rowIds as $k => $v) {
                    $rowIds[$k] = (int) $v;
                }
                $this->rowIds = $rowIds;
            } else {
                $this->rowIds = false;
            }

            $this->initialized = true;
        }
    }

    /**
     * Returns the attribute_id to use for the current command.
     *
     * @return int
     */
    protected function getAttributeId()
    {
        if (!$this->attributeId) {
            $this->errorInit(__METHOD__);
        }
        return $this->attributeId;
    }

    /**
     * Return the store id to use for the current command.
     *
     * @param InputInterface $input
     */
    protected function getStoreId()
    {
        if (!$this->storeId) {
            $this->errorInit(__METHOD__);
        }
        return $this->storeId;
    }

    /**
     * Return the qualified table name to use for the current command.
     *
     * @param InputInterface $input
     */
    protected function getTableName()
    {
        if (!$this->tableName) {
            $this->errorInit(__METHOD__);
        }
        return $this->tableName;
    }

    /**
     * Throws an exception.
     *
     * @param string $methodName
     * @throws \LogicException
     */
    protected function errorInit($methodName)
    {
        throw new \LogicException(
            __('Command has not been intialized. Call UseDefaultValue::init() before calling '.$methodName));
        ;
    }
}

Step 2: Enable the module

php -f bin/magento module:enable StackOverflow_Question40177336

Step 3: Utilize your new CLI command.

The command has two required arguments, attribute_code and store. Store can be either the ID or Code. Admin store is not allowed for obvious reasons. The command also has an optional third parameter of SKU if you wish to only target a specific SKU (omitting this applies to all products).

For example, if you wanted to delete all "name" values from the "default" store view your command would be as follows:

php -f bin/magento catalog:product:attributes:use-default-value name default

Upvotes: 4

Related Questions