9 use Symfony\Component\Console\Input\InputInterface;
10 use Symfony\Component\Console\Output\OutputInterface;
56 \
Magento\Framework\EntityManager\MetadataPool $metadataPool
62 $this->metadata = $metadataPool->getMetadata(ProductInterface::class);
63 parent::__construct();
71 $this->setName(
'catalog:product:attributes:cleanup');
72 $this->setDescription(
'Removes unused product attributes.');
81 $this->appState->setAreaCode(\
Magento\Framework\
App\Area::AREA_GLOBAL);
82 $connection = $this->attributeResource->getConnection();
83 $attributeTables = $this->getAttributeTables();
85 $progress = new \Symfony\Component\Console\Helper\ProgressBar(
$output, count($attributeTables));
86 $progress->setFormat(
'<comment>%message%</comment> %current%/%max% [%bar%] %percent:3s%% %elapsed%');
88 $this->attributeResource->beginTransaction();
91 foreach ($attributeTables as $attributeTable) {
92 $progress->setMessage($attributeTable .
' ');
93 $affectedIds = $this->getAffectedAttributeIds(
$connection, $attributeTable);
94 if (count($affectedIds) > 0) {
95 $connection->delete($attributeTable, [
'value_id in (?)' => $affectedIds]);
99 $this->attributeResource->commit();
102 $output->writeln(
"<info>Unused product attributes successfully cleaned up:</info>");
103 $output->writeln(
"<comment> " . implode(
"\n ", $attributeTables) .
"</comment>");
104 return \Magento\Framework\Console\Cli::RETURN_SUCCESS;
105 }
catch (\Exception $exception) {
106 $this->attributeResource->rollBack();
109 $output->writeln(
"<error>{$exception->getMessage()}</error>");
111 return \Magento\Framework\Console\Cli::RETURN_FAILURE;
119 private function getAttributeTables()
121 $searchResult = $this->productAttributeRepository->getList($this->searchCriteriaBuilder->create());
122 $attributeTables = [];
125 foreach ($searchResult->getItems() as $productAttribute) {
126 $attributeTable = $productAttribute->getBackend()->getTable();
127 if (!in_array($attributeTable, $attributeTables)
128 && $attributeTable != $this->attributeResource->getTable(
'catalog_product_entity')
130 $attributeTables[] = $attributeTable;
133 return $attributeTables;
142 private function getAffectedAttributeIds(AdapterInterface
$connection, $attributeTableName)
144 $linkField = $this->metadata->getLinkField();
146 $select->from([
'e' => $this->attributeResource->getTable(
'catalog_product_entity')],
'ei.value_id');
148 [
'ei' => $attributeTableName],
149 'ei.' . $linkField .
' = e.' . $linkField .
' AND ei.store_id != 0',
152 $select->join([
's' => $this->attributeResource->getTable(
'store')],
's.store_id = ei.store_id',
'');
153 $select->join([
'sg' => $this->attributeResource->getTable(
'store_group')],
'sg.group_id = s.group_id',
'');
155 [
'pw' => $this->attributeResource->getTable(
'catalog_product_website')],
156 'pw.website_id = sg.website_id AND pw.product_id = e.entity_id',
159 $select->where(
'pw.product_id is null');
execute(InputInterface $input, OutputInterface $output)
$productAttributeRepository
__construct(\Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository, \Magento\Catalog\Model\ResourceModel\Attribute $attributeResource, \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder, \Magento\Framework\App\State $appState, \Magento\Framework\EntityManager\MetadataPool $metadataPool)