Domanda

A volte è conveniente salvare una categoria direttamente dalla raccolta in cui è stata caricata.Ad esempio, per tutte le categorie in cui l'attributo name inizia con foo, voglio aggiornare l'attributo meta_title con il nome seguito da bar come segue:

/** @var Mage_Catalog_Model_Resource_Category_Collection $categoryCollection */
$categoryCollection = Mage::getResourceModel('catalog/category_collection');
$categoryCollection->setDisableFlat(true);
$categoryCollection->addAttributeToFilter('name', ['like' => 'foo%']);
foreach ($categoryCollection as $category) {
    /** @var Mage_Catalog_Model_Category $category */
    $category->setData('meta_title', $category->getData('name') . ' bar');
    $category->save();
}

Funziona, ma come effetto collaterale: l'attributo include_in_menu viene reimpostato su 1.

Qual è la causa di questo e come può essere aggirato?

È stato utile?

Soluzione

Si scopre che quando si salva un'entità EAV, vengono eseguiti i metodi beforeSave e afterSave dei modelli back-end di tutti gli attributi, anche quando non fanno parte della raccolta: il metodo Mage_Eav_Model_Entity_Abstract::save chiama i metodi _beforeSave e _afterSave, che chiamano il metodo walkAttributescon backend/beforeSave o backend/afterSave come primi argomenti.

Il metodo Mage_Eav_Model_Entity_Attribute_Backend_Abstract::beforeSave, utilizzato dalla maggior parte degli attributi, imposta il valore predefinito dell'attributo sull'oggetto fornito nelle seguenti circostanze:

  1. L'oggetto non ha una voce nella sua matrice $data interna.
  2. Il valore predefinito dell'attributo non è vuoto.

La prima condizione si applica alla maggior parte degli attributi durante il caricamento tramite una raccolta.La seconda condizione si applica solo all'attributo include_in_menu (in una configurazione Magento standard).

Per aggirare questo problema, aggiungi semplicemente l'attributo include_in_menu alla query di raccolta:

$categoryCollection->addAttributeToSelect('include_in_menu');

Un altro problema che non vengono chiamati i metodi afterLoad dei modelli di backend degli attributi (grazie a Mario per l'avviso).Su un'installazione predefinita di Magento, ciò causa problemi con i seguenti attributi:

  • created_at: il valore non viene convertito da UTC al fuso orario corrente del negozio al caricamento.Al salvataggio, il valore viene riconvertito in UTC (che era già), portando a created_at date errate.
  • available_sort_by (se fa parte della collezione e il suo valore non è NULL): il valore separato da virgole non viene sostituito da un array.Al salvataggio, il valore viene ripristinato a NULL.

Per risolvere questo problema, puoi attivare i metodi afterLoad aggiungendo quanto segue al corpo del ciclo:

$category->getResource()->loadAllAttributes($category)->walkAttributes('backend/afterLoad', array($category));

A proposito, questo non sembra danneggiare così tanto le prestazioni: tutti gli attributi di categoria vengono caricati anche durante il salvataggio della categoria e Magento memorizza nella cache le istanze degli attributi nel singleton Mage_Eav_Model_Config.Quindi sembra che quando si caricano e si salvano più categorie, ogni attributo viene caricato solo una volta.

Simile al problema che il metodo beforeLoad non viene chiamato per alcun attributo, il metodo Mage_Eav_Model_Entity_Abstract::_loadModelAttributes non viene chiamato.Questo metodo fa due cose per ogni attributo:

  1. Chiamare $object->setData($attributeCode, $attributeValue) dove $attributeValue viene caricato dal database.
  2. Chiamare $attribute->getBackend()->setEntityValueId($object, $valueId) dove $valueId è la chiave primaria del valore dell'attributo nella tabella degli attributi corrispondente.

Quando si caricano raccolte EAV, viene chiamato il metodo con nome simile Mage_Eav_Model_Entity_Collection_Abstract::_loadAttributes, che esegue il primo ma non il secondo .Di conseguenza, il metodo getEntityValueId corrispondente restituisce sempre un valore vuoto.Ciò causa problemi solo quando si eliminano i valori degli attributi dalla tabella back-end.Per le categorie (e anche i prodotti) ciò accade solo quando si imposta un valore di un attributo con ambito globale su false.

Per evitare problemi con l'impossibilità di eliminare i valori degli attributi con ambito globale, non chiamare $object->setData($attributeCode, false) per tale attributo.Quando è necessario cancellare un attributo, puoi usare null invece di false, che risulta in una query UPDATE sulla tabella back-end degli attributi invece di una query DELETE.

Altri suggerimenti

Non dovresti mai chiamare il save se non hai chiamato il load prima sullo stesso oggetto. Anche se si aggiungono gli attributi alla raccolta, i metodi beforeLoad e afterLoad non vengono chiamati e potrebbero avere un impatto sullo stato dell'oggetto.

Aggiunta

$categoryCollection->addAttributeToSelect('include_in_menu');

potrebbe risolvere il tuo problema per questo caso particolare, ma potrebbe danneggiare qualcos'altro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a magento.stackexchange
scroll top