0

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,

));

2 Answers 2

6

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();
4
  • Damn what a simple solution. It works perfectly in a datascript, even my own version does. Totally didn't think of the data scripts. Need to read some more about setup scripts to know the why. Thanks a lot! :) Commented Mar 28, 2015 at 6:52
  • Edited the answer to provide you a bit more insight on why this happens :). And you are welcome, of course! :) Commented Mar 28, 2015 at 8:57
  • Sweet, great explanation. It all makes sense now. I wasn't aware there was that difference with data scripts and setup scripts. I just started using such scripts so still discovering new things, which is great. Thanks again, I'm sure this post will be an answer for a lot more people :) Commented Mar 28, 2015 at 9:19
  • I hope so! :) We weren't aware there was a difference for a suprisingly long period of time, too, so I am glad I could help :). And good luck with learning new things, it's always fun! Commented Mar 28, 2015 at 9:39
0

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

3
  • Thanks for your answer. Unfortunately this doesn't work either, it keeps modifieing the data store view scope. I really don't understand this, it seems to ignore the store id completely. Commented Mar 27, 2015 at 7:52
  • what is the scope text_onder field ??.My code was check iwast working perfecly
    – Amit Bera
    Commented Mar 27, 2015 at 7:55
  • Also on store view, it's basically a copy of the description field. See my edited post with the code I used to create it. Commented Mar 27, 2015 at 7:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.