Magento 2.1.3 EE
以下解决方案创建一个 CLI 命令来直接操作数据库并删除商店特定的产品属性信息。它是为 Magento 企业版编写的,因此如果您使用的是社区版,则必须修改此代码以使用 entity_id 而不是 row_id。
请注意这一点。此处提出的解决方案绕过模型类并对默认数据库连接的catalog_product_entity_datetime、catalog_product_entity_decimal、catalog_product_entity_int、catalog_product_entity_text 和catalog_product_entity_varchar 表执行直接删除查询。首先备份您的数据库。
第 1 步:创建模块
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));
;
}
}
第 2 步:启用模块
php -f bin/magento module:enable StackOverflow_Question40177336
第 3 步:使用新的 CLI 命令。
该命令有两个必需的参数,attribute_code 和 store。 Store 可以是 ID 或 Code。由于显而易见的原因,不允许使用管理存储。如果您希望仅针对特定 SKU(省略此参数适用于所有产品),该命令还有一个可选的 SKU 第三个参数。
例如,如果您想从“默认”存储视图中删除所有“名称”值,您的命令如下:
php -f bin/magento catalog:product:attributes:use-default-value name default