The short version
Mage::getModel('catalog/product_attribute_set_api')->attributeRemove($attId, $set->getId());
Your error message isn't popping up due to your delete
method call, it's popping up due to your collection use. For reasons lost to the mystery and smog of Los Angeles, the eav/entity_attribute
resource model class is initialized with the eav/attribute
resource string.
#File: app/code/core/Mage/Eav/Model/Resource/Entity/Attribute.php
protected function _construct()
{
$this->_init('eav/attribute', 'attribute_id');
}
This means the following collection
$collection = Mage::getModel('eav/entity_attribute')->getCollection();
Actually queries the eav_attribute
table.
$sql = $collection->getSelect()->__toString();
echo($sql);
//prints SELECT `main_table`.* FROM `eav_attribute` AS `main_table`
@DavidTay was actually on the right track. Whenever you're in doubt about how to do something in Magento, look at how the core team themselves did it. However, while looking at the admin console code for this will lead you to a method for removing your attribute from a attribute set, it's even better to look at API implementation code. This API code has an implicit promise of doing things in a stable way, where a lot of the early admin console code shows the scars of having been developed rapidly.
If you take a look at the removeAttribute
implementation for the attribute set api class, you'll find your answer.
#File: app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api.php
public function attributeRemove($attributeId, $attributeSetId)
{
// check if attribute with requested id exists
/** @var $attribute Mage_Eav_Model_Entity_Attribute */
$attribute = Mage::getModel('eav/entity_attribute')->load($attributeId);
if (!$attribute->getId()) {
$this->_fault('invalid_attribute_id');
}
// check if attribute set with requested id exists
/** @var $attributeSet Mage_Eav_Model_Entity_Attribute_Set */
$attributeSet = Mage::getModel('eav/entity_attribute_set')->load($attributeSetId);
if (!$attributeSet->getId()) {
$this->_fault('invalid_attribute_set_id');
}
// check if attribute is in set
$attribute->setAttributeSetId($attributeSet->getId())->loadEntityAttributeIdBySet();
if (!$attribute->getEntityAttributeId()) {
$this->_fault('attribute_is_not_in_set');
}
try {
// delete record from eav_entity_attribute
// using entity_attribute_id loaded by loadEntityAttributeIdBySet()
$attribute->deleteEntity();
} catch (Exception $e) {
$this->_fault('remove_attribute_error', $e->getMessage());
}
return true;
}
Parsing this code out from it's API error checking — first you load an eav/entity_attribute
model by it's attribute id.
$attribute = Mage::getModel('eav/entity_attribute')->load($attributeId);
Remember, for reasons we don't know, this actually loads data from the eav_attribute
table because of what's in the resource model _construct
.
Next, we set the attribute set id on the eav/entity_attribute
model.
$attribute->setAttributeSetId($attributeSet->getId())->loadEntityAttributeIdBySet();
Then, we call the object's deleteEntity
method, which actually removes the data from the correct table (eav_entity_attribute
)
// delete record from eav_entity_attribute
// using entity_attribute_id loaded by loadEntityAttributeIdBySet()
$attribute->deleteEntity();
If you trace the deleteEntity
method to the model
#File: app/code/core/Mage/Eav/Model/Entity/Attribute.php
public function deleteEntity()
{
return $this->_getResource()->deleteEntity($this);
}
and then to the resource model
#File: app/code/core/Mage/Eav/Model/Resource/Entity/Attribute.php
public function deleteEntity(Mage_Core_Model_Abstract $object)
{
if (!$object->getEntityAttributeId()) {
return $this;
}
$this->_getWriteAdapter()->delete($this->getTable('eav/entity_attribute'), array(
'entity_attribute_id = ?' => $object->getEntityAttributeId()
));
return $this;
}
you can see that ultimately, Magento is using a DELETE query with the write adapter to remove the row.
Rather than do this yourself every-time, you can just call the API method directly. Not via XML-RPC or SOAP, but by manually instantiating the API implementation class
Mage::getModel('catalog/product_attribute_set_api')->attributeRemove($attributeId, $attributeSetId);
Yes, this is possible.
First, set these keys in your $data array to following values to avoid adding attribute to all attribute sets:
'user_defined' => true,
'group' => ''
Then add attribute to your attribute set:
$attributeSetId = $this->getAttributeSetId($entityTypeId, 'New Attr Set');
$this->addAttributeToSet($entityTypeId, $attributeSetId, 'General', 'new_attr', 10);
Best Answer
I would always suggest doing this sort of thing via a module's set-up scripts. For full details on set-up script see, but for what you need something like the following should work.