Question

I'm making a setupscript in Magento 1.7 CE to move some category data from one attribute to another. The script is working, but somehow it only saves on store view scope (just store view id 1), although I explicitly tell it to save on admin scope.

My current code:

<?php

$installer = $this;

$installer->startSetup();

$categories = Mage::getResourceModel('catalog/category_collection')
    ->addAttributeToSelect('description')
    ->addAttributeToSelect('text_onder')
    ->addAttributeToFilter('description_position', 0)
    ->setStoreId(0)
    ->addFieldToFilter('entity_id', 93)
    ;

$resource = Mage::getModel('catalog/category')->getResource();

foreach ($categories as $category) {
    $object = new Varien_Object(array(
        'entity_id'     => $category->getId(),
        'description'   => '',
        'text_onder'    => $category->getDescription(),
        'store_id'      => 0
    ));

    $resource->saveAttribute($object, 'text_onder');
    $resource->saveAttribute($object, 'description');
}

$installer->endSetup();

The filter on entity id is just for testing of course.

The attribute text_onder was created like this:

$installer->addAttribute('catalog_category', "text_onder", array(
    'group'             => 'General Information',
    'type'              => 'text',
    'input'             => 'textarea',
    'label'             => 'Tekst onder',
    'visible'           => 1, 
    'required'          => 0,
    'user_defined'      => 0,
    'searchable'        => 0,
    'filterable'        => 0,
    'comparable'        => 0,
    'visible_on_front'  => 1,
    'visible_in_advanced_search'    => 1,
    'is_html_allowed_on_front'      => 1,
    'is_configurable'   => 0,
    'global'            => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
    'wysiwyg_enabled'   => true,

));
Was it helpful?

Solution

First of all, I changed your script a bit (while I was looking for a reason why it fails). Here is the result:

<?php

$installer = $this;

$categories = Mage::getModel('catalog/category')
    ->getCollection()
    ->setStoreId(0)
    ->addAttributeToSelect('description')
    ->addAttributeToSelect('text_onder')
    ->load();

foreach ($categories as $category) {
    $category->setTextOnder($category->getDescription());
    $category->setDescription('');
    $category->setStoreId(0);
    $category->save();
}

However, the real problem was somewhere else. Neither your code nor mine will work within an install / upgrade script. You need to put this code in the data script!

In order to do so, move your file from sql/module_name/upgrade-x.x.x-y.y.y.php to data/module_name/data-upgrade-x.x.x-y.y.y.php and it will work like a charm.

Let me know if it did :).

UPDATE I have digged in the Magento Core a little bit and found an answer as to why this happens.

Let's take a look how Magento processes install / upgrade / data scripts.

It all starts in Mage_Core_Model_App::run method. This method calls two Mage_Core_Model_Resource_Setup static methods:

  1. Mage_Core_Model_Resource_Setup::applyAllUpdates() - this is actually called inside _initModules() method which is called in run() method, but listing it here for simplicity [line 343]
  2. Mage_Core_Model_Resource_Setup::applyAllDataUpdates() [line 351]

When you look at those methods in Mage_Core_Model_Resource_Setup (which is a class that Mage_Eav_Model_Entity_Setup extends from as well as any other Resource Setup classes), you can notice that applyAllUpdates() starts with

Mage::app()->setUpdateMode(true);

and applyAllDataUpdates() does not call this function at all.

Now, let's get back to Mage_Core_Model_App class and it's getStore($id) method:

public function getStore($id = null) {
    if (!Mage::isInstalled() || $this->getUpdateMode()) {
        return $this->_getDefaultStore();
    }

So when Magento is not installed or... in update mode set to true - it ignores the $id given as a parameter and ALWAYS returns the default store instance.

Moving forward from there, when you use save() on Mage_Catalog_Model_Category, the request goes like this:

  1. calls save() on Mage_Core_Model_Abstract
  2. Mage_Core_Model_Abstract calls save() on resource class on line 318 (and this is where it gets the resource class and where your code falls into it). In this case it calls save() on Mage_Eav_Model_Entity_Abstract
  3. As a part of save() method, Mage_Eav_Model_Entity_Abstract calls _processSaveData() method on line 1123
  4. That method calls _updateAttribute() method of Mage_Catalog_Model_Resource_Abstract
  5. _updateAttribute() calls _saveAttributeValue() of the same class
  6. And that function has the line that's causing all of this in here (see code below)

Mage_Catalog_Model_Resource_Abstract, line 219

protected function _saveAttributeValue($object, $attribute, $value)
    {
        $write   = $this->_getWriteAdapter();
        $storeId = (int)Mage::app()->getStore($object->getStoreId())->getId();

OTHER TIPS

There are some issue with code.Resource mode does not define at proper area.

please try this

$categories = Mage::getResourceModel('catalog/category_collection')
    ->addAttributeToSelect('description')
    ->addAttributeToSelect('text_onder')
    ->addAttributeToFilter('description_position', 0)
    ->setStoreId(0)
    ->addFieldToFilter('entity_id', 4)
    ;



foreach ($categories as $category) {

        echo $category->getId();
        $object =$category->getDescription().'aaaa';
        $category->setStoreId(0);
        $category->setData('description',$object );
        $category->getResource()->saveAttribute($category, 'description');

}

Note: $category->setStoreId(0) use 0 for global/admin and you can to change 0 to your store according to your code in which store you want to set data

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top