Skip to content

Commit

Permalink
New feature: added possibility to move products to a different attrib…
Browse files Browse the repository at this point in the history
…ute set (#111)
  • Loading branch information
fballiano authored Feb 25, 2025
1 parent d3fe7c4 commit cec08d4
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 3 deletions.
22 changes: 21 additions & 1 deletion app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @package Mage_Adminhtml
* @copyright Copyright (c) 2006-2020 Magento, Inc. (https://magento.com)
* @copyright Copyright (c) 2021-2024 The OpenMage Contributors (https://openmage.org)
* @copyright Copyright (c) 2024 Maho (https://mahocommerce.com)
* @copyright Copyright (c) 2024-2025 Maho (https://mahocommerce.com)
* @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/

Expand Down Expand Up @@ -328,6 +328,26 @@ protected function _prepareMassaction()
]);
}

if (Mage::getSingleton('admin/session')->isAllowed('catalog/attributes/sets')) {
$this->getMassactionBlock()->addItem(MassAction::CHANGE_ATTRIBUTE_SET, [
'confirm' => Mage::helper('catalog')->__('Changing the attribute set may result in data loss for attributes that do not exist in the new set. Are you sure?'),
'label' => Mage::helper('catalog')->__('Change Attribute Set'),
'url' => $this->getUrl('*/catalog_product_action_set/save', ['_current' => true]),
'additional' => [
'visibility' => [
'name' => 'attribute_set',
'type' => 'select',
'class' => 'required-entry',
'label' => Mage::helper('catalog')->__('Attribute Set'),
'values' => Mage::getResourceModel('eav/entity_attribute_set_collection')
->setEntityTypeFilter(Mage::getModel('catalog/product')->getResource()->getTypeId())
->setOrder('attribute_set_name', Varien_Data_Collection::SORT_ORDER_ASC)
->toOptionArray(),
],
],
]);
}

Mage::dispatchEvent('adminhtml_catalog_product_grid_prepare_massaction', ['block' => $this]);
return $this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @package Mage_Adminhtml
* @copyright Copyright (c) 2006-2020 Magento, Inc. (https://magento.com)
* @copyright Copyright (c) 2018-2024 The OpenMage Contributors (https://openmage.org)
* @copyright Copyright (c) 2024 Maho (https://mahocommerce.com)
* @copyright Copyright (c) 2024-2025 Maho (https://mahocommerce.com)
* @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/

Expand All @@ -30,6 +30,7 @@ abstract class Mage_Adminhtml_Block_Widget_Grid_Massaction_Abstract extends Mage
public const ASSIGN_GROUP = 'assign_group';
public const ATTRIBUTES = 'attributes';
public const CANCEL_ORDER = 'cancel_order';
public const CHANGE_ATTRIBUTE_SET = 'change_attribute_set';
public const CHANGE_MODE = 'change_mode';
public const ENABLE = 'enable';
public const DELETE = 'delete';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

/**
* Maho
*
* @package Mage_Adminhtml
* @copyright Copyright (c) 2025 Maho (https://mahocommerce.com)
* @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/

class Mage_Adminhtml_Catalog_Product_Action_SetController extends Mage_Adminhtml_Controller_Action
{
/**
* ACL resource
* @see Mage_Adminhtml_Controller_Action::_isAllowed()
*/
public const ADMIN_RESOURCE = 'catalog/attributes/sets';

#[\Override]
protected function _construct()
{
// Define module dependent translate
$this->setUsedModuleName('Mage_Catalog');
}

public function saveAction()
{
try {
$data = $this->getRequest()->getPost();
if (!isset($data['attribute_set']) || !is_array($data['product'])) {
Mage::throwException($this->__('Invalid data'));
}

$collection = Mage::getResourceModel('catalog/product_collection');
$rowCount = $collection->getConnection()->update(
$collection->getTable('catalog/product'),
['attribute_set_id' => $data['attribute_set']],
['entity_id IN (?)' => $data['product']],
);

$this->_getSession()->addSuccess(
$this->__('%d product(s) were updated', $rowCount),
);
} catch (Mage_Core_Exception $e) {
$this->_getSession()->addError($e->getMessage());
} catch (Exception $e) {
$this->_getSession()->addError($this->__('Internal Error'));
}
$this->_redirect('*/catalog_product/', ['_current' => true]);
}
}
3 changes: 2 additions & 1 deletion app/code/core/Mage/Core/Model/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @package Mage_Core
* @copyright Copyright (c) 2006-2020 Magento, Inc. (https://magento.com)
* @copyright Copyright (c) 2019-2024 The OpenMage Contributors (https://openmage.org)
* @copyright Copyright (c) 2024 Maho (https://mahocommerce.com)
* @copyright Copyright (c) 2024-2025 Maho (https://mahocommerce.com)
* @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/

Expand Down Expand Up @@ -231,6 +231,7 @@ public function getEntity($model, $entity)
*
* @param string|array $modelEntity
* @return string
* @throws Mage_Core_Exception
*/
public function getTableName($modelEntity)
{
Expand Down
52 changes: 52 additions & 0 deletions app/code/core/Mage/Eav/Model/Observer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*
* @package Mage_Eav
* @copyright Copyright (c) 2019-2022 The OpenMage Contributors (https://openmage.org)
* @copyright Copyright (c) 2025 Maho (https://mahocommerce.com)
* @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/

Expand All @@ -30,4 +31,55 @@ public function onControllerActionPredispatch($event)
Mage::getSingleton('eav/config')->setCurrentStoreId(Mage::app()->getStore()->getId());
}
}

public function cleanOrphanedRecords()
{
$resource = Mage::getSingleton('core/resource');
$connection = $resource->getConnection('core_write');
$entityAttributeTable = $resource->getTableName('eav_entity_attribute');
$attributeSetTable = $resource->getTableName('eav_attribute_set');
$entityTypes = Mage::getModel('eav/entity_type')->getCollection();
foreach ($entityTypes as $entityType) {
$entityTypeId = $entityType->getEntityTypeId();

try {
$entityTable = $resource->getTableName($entityType->getEntityTable());
} catch (Mage_Core_Exception $e) {
// If the entityTable doesn't exist, it could be an entity created by a module
// that was later removed, simply skip it at the moment
continue;
}

$attributeSets = $connection->fetchCol("SELECT attribute_set_id FROM $attributeSetTable WHERE entity_type_id=$entityTypeId");
$attributeTables = [
"{$entityTable}_char",
"{$entityTable}_datetime",
"{$entityTable}_decimal",
"{$entityTable}_int",
"{$entityTable}_text",
"{$entityTable}_varchar",
];
foreach ($attributeTables as $table) {
if (!$connection->isTableExists($table)) {
continue;
}

foreach ($attributeSets as $attributeSetId) {
try {
$connection->query("
DELETE FROM $table WHERE entity_type_id=$entityTypeId
AND entity_id IN (
SELECT entity_id from $entityTable WHERE entity_type_id=$entityTypeId AND attribute_set_id=$attributeSetId
)
AND attribute_id NOT IN (
SELECT attribute_id FROM eav_entity_attribute WHERE entity_type_id=$entityTypeId AND attribute_set_id=$attributeSetId
)
");
} catch (Exception $e) {
Mage::logException($e);
}
}
}
}
}
}
12 changes: 12 additions & 0 deletions app/code/core/Mage/Eav/etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@
</modules>
</translate>
</frontend>
<crontab>
<jobs>
<eav_clean_orphaned_records>
<schedule>
<cron_expr>0 0 * * *</cron_expr>
</schedule>
<run>
<model>eav/observer::cleanOrphanedRecords</model>
</run>
</eav_clean_orphaned_records>
</jobs>
</crontab>
<default>
<general>
<validator_data>
Expand Down

0 comments on commit cec08d4

Please sign in to comment.