Magento EAV: how to hard delete an attribute value?

谁说胖子不能爱 提交于 2019-12-05 19:25:07

I finally had to tackle this, and although @vBuck was close, I always was able to query the old data after the switch in the attribute set and if I switched back I would see the old data when it shouldn't have been there. Today, I have the same need to ensure the random data is removed. Here is how I approached this topic.

In order to programmatically delete attributes when you switch from one set to another you must first look at all the entries for the new set, then get a list of all attributes, check against that list and (this is the important part) remove it from the correct entity table. For example, I want to get rid of a value of 500 GB that is in the sample Magento data when I switch Western Digital 500GB HD - 7200RPM from Hard Drive to Shoes. In order to do that I must remove the entry in the catalog_product_entity_text table it's stored at. This means that I must find that entry where it's equal to the product id and then delete it from it's entity type table.

I was able to do this, and was not able to find the stray data after. This was confirmed by both a DB search and switching back to the old attribute set and looking for the data. you can find it all here

https://gist.github.com/jeremyBass/6581038#file-attribute-clean-switch-md

TESTED in CE 1.7.0.2, 1.8.0.0

So I too would love to have the programmatic answer, but I don't have the time to do it. But this is what I can provide to this chain. You see the desired resulting action happening when you try to remove an attribute by its self from the admin.

Steps:

  1. make sure the attr set has the attr in it's set.
  2. update all products with that attr set to have the attr needing deletion as null.
  3. remove the the attr from the set

Seems when I don't clear all attrs before removal of attr from the set, the result is for the app to leave the rows there. Maybe for safety, I don't know as I have not dived in. What I can tell with as little as I have looked in this it’s that if you don't clear the values before attr removal from the set, when you set the attr to null, the attr remains.

So, then the programmatic solutions will need to follow that pattern. If I get time I'll write it, but I have like 15 other tasks in the queue right now.

Ok, I found it finally, 15 minutes after asking the question (and spending few hours trying to solve it)

Here is the answer:

$product = Mage::getModel('catalog/product')->load(1234); //Let's assume that my bag product ID is 1234
$product->setData('unwanted_attribute',null);    

$resource = $product->getResource();
$resource->saveAttribute($product,'unwanted_attribute');

Edit: This doesn't work. If you re-save the product later by doing a $product->save(), all the attributes reappear.

Rick Buczynski

Looks like this is an old post, but I too was looking for an answer here, and I think I'm onto a solution.

To solve this, I had to work directly with the product resource's write adapter:

$product->getResource()->getWriteConnection()

to delete the attribute values from the table.

I got clues on how to do this after digging through some code. See Mage_Catalog_Model_Resource_Eav_Mysql4_Abstract::_saveAttributeValue:

    $write   = $this->_getWriteAdapter();
    $storeId = Mage::app()->getStore($object->getStoreId())->getId();
    $table   = $attribute->getBackend()->getTable();

    /**
     * If we work in single store mode all values should be saved just
     * for default store id
     * In this case we clear all not default values
     */
    if (Mage::app()->isSingleStoreMode()) {
        $storeId = $this->getDefaultStoreId();
        $write->delete($table, join(' AND ', array(
            $write->quoteInto('attribute_id=?', $attribute->getAttributeId()),
            $write->quoteInto('entity_id=?', $object->getEntityId()),
            $write->quoteInto('store_id<>?', $storeId)
        )));
    }

By using this code in a loop through $product->getAttributes() before changing the attribute set, you are able to "unlink" the values from the attributes of the product without destroying the attributes themselves. Then you can change the attribute set (as done in Flagbit's extension) safely, not leaving behind dead data.

Using the above code, here's a demonstration that I've written to prove my theory:

$product=Mage::getModel('catalog/product')->load(MY_TARGET_PRODUCT_ID);
$write=$product->getResource()->getWriteConnection();

foreach($product->getAttributes() as $attribute) {
  if($attribute->getId()==MY_TARGET_ATTRIBUTE_ID) {
    $write->delete(
      $attribute->getBackend()->getTable(),
      join(' AND ', array(
        $write->quoteInto('attribute_id=?',$attribute->getAttributeId()),
        $write->quoteInto('entity_id=?',$product->getId())
      ))
    );
  }
}

In this example, I'm looking for a specific attribute to clear from the product, but you can remove the IF conditional to delete every attached value.

I haven't fully tested this, but so far it seems alright. I'm running Magento 1.4, by the way. Hope it helps someone!

UPDATE:

Looks like the above is only half correct. You'll still have to be careful not to clear certain attributes that might render the product dead (such as the name, mode, status, and others). So in my case, it looks like I'll have to compare with the default attribute set before removing.

ANOTHER UPDATE:

With the help of this SO post: https://stackoverflow.com/a/8500506/1442685 I was able to compare all attributes linked to a product and delete only the non-default values. This way, when changing sets, I can ensure that basic information about the product is not lost. Check out my Gist for the two classes which make it all happen:

https://gist.github.com/vbuck/5911170

You should be able to unset the value like either of these:

$product->unsetData('unwanted_attribute')
        ->save();

$product->unsUnwantedAttribute()
        ->save();

you need to go to admin>>catalog>>attributes>>manage attribute sets if your trying to manage your product catalog you should first think of your attributes (separate to your product), then your sets(again not actually part of your products). after you have properly established your attributes and sets (of attributes) you can apply them to products with values for each attribute.

or maybe you prefer this kinda thing?

class Mage_catalog_Model_Product_Attribute_Set_Api extends Mage_Api_Model_Resource_Abstract
{
 {
/**
 * Retrieve attribute set list
 *
 * @return array
 */
public function items()
{
    $entityType = Mage::getModel('catalog/product')->getResource()->getEntityType();
    $collection = Mage::getResourceModel('eav/entity_attribute_set_collection')
        ->setEntityTypeFilter($entityType->getId());

    $result = array();
    foreach ($collection as $attributeSet) {
        $result[] = array(
            'set_id' => $attributeSet->getId(),
            'name'   => $attributeSet->getAttributeSetName()
        );

    }

    return $result;
 }
} // Class Mage_Catalog_Model_Product_Attribute_Set_Api End

Once you have associated an attribute set to a product there is no way to change attribute set or remove that attribute set.

The way out is to export product and then modify sheet and import.

This link also explains : https://collaborate.magento.com/magento/topics/how_do_i_change_product_attribute_set

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!