Magento: правильный способ создания объектов категории

Я пишу модуль, который будет извлекать объекты, такие как веб-сайты, группы, категории и продукты, из одного экземпляра Magento, сериализовывать их свойства и записывать все в текстовый файл, который будет десериализован и на другом сервере. Эти свойства затем используются для программного воссоздания этих объектов на новом сервере. Идея состоит в том, что мы сможем извлечь все объекты, составляющие интернет-магазин Magento, и перенести их на другой сервер. (Нет, мы не хотим перемещать весь экземпляр на другой сервер. Мы просто хотим иметь возможность перемещать магазин и связанные с ним объекты.)

Очевидно, что поскольку мы создаем категории на новом сервере, их entity_id изменится. Я разработал эту часть, а также убедился, что подкатегории имеют правильный родительский идентификатор. Этот проект был в основном простым, пока я не попытался воссоздать объект категории и подкатегории. У меня всевозможные проблемы. Новые объекты категории сохраняют базу данных. Однако иногда они не отображаются в дереве категорий, иногда их parent_id меняется на 0, иногда все дерево категорий исчезает. Я работал над этим около недели. Я прочитал, что вы должны установить свойство 'путь' к пути родительского перед сохранением. Я прочитал, что вы должны использовать метод 'move', чтобы установить категорию, являющуюся дочерней по отношению к ее родителю. Есть много теории, но никто, кажется, не имеет ответа.

Поэтому мой вопрос: как вы создаете записи категорий и подкатегорий, которые на самом деле работают, правильно связаны с родительскими категориями, отображаются в дереве категорий и ничего не изменяют? У меня есть следующие атрибуты из исходной категории источника, хранящиеся в массиве с именем $aryData().

[entity_id] => 127       //This usually changes on new server
[parent_id] => 1         //Lookup NEW entity_id of parent and use it
[path] =>                //Not sure how to properly set this. Tried a few things
[position] => 8          //Leave this alone, hope for the best
[children_count] => 0    //Have to zero this out when you create new category object
[name] => Best Test      
[url_key] => best-test
[is_active] => 1
[include_in_menu] => 1

И вот в общем то, что я делаю, в упрощенном виде:

$objNewCat = Mage::getModel('catalog/category'); //Create new object to populate

$parent_id = getNewParent($data['name'], $data['url-key']; //Get new parent id by name and URL key. (This works)
$objParentCat = Mage::getModel('catalog/category')->load($parent_id);

$aryData(['parent_id']) = $parent_id;  //Update parent ID in data array
$aryData(['children_count']) = 0;  //Must set to 0. Updated as children are added


$objNewCat->setData($data); //Set all data parameters from our save array
$objNewCat->setPath($objParentCat->getPath()); //Is this correct? Read you have to do this  
$objNewCat->save();  //Save object to populate entity_id field

//--- Now assign object to be child of the parent.
$objCat = Mage::getModel('catalog/category')->load($newCat->getId()); //reloading to set 'current category'
Mage::unregister('category');
Mage::unregister('current_category');
Mage::register('category', $objCat);
Mage::register('current_category', $objCat);
$objCat->move($parent_id);
$objCat->save();

Да, часть этого кода довольно грубая. Это упрощено, и я много пробовал, чтобы заставить его работать. Это очень расстраивает. Помоги мне Оби-Ван Кноби. Твоя единственная надежда.

1 ответ

Решение

Дон! Я провел много часов, исследуя и борясь с этой проблемой. В Интернете много ссылок на проблему, но никто до сих пор не нашел надежного решения.

Magento использует объектную модель для обработки всех операций ввода-вывода базы данных. Это должно оградить вас от необходимости выполнять утомительную работу, такую ​​как обновление связанных полей. Например, если вы добавите новую дочернюю категорию, объектная модель Magento автоматически обновит 'children_count' в родительской записи. Объектная модель Magento в основном позволяет вам заботиться о данных, которые вы хотите записать, одновременно заботясь о ведении домашнего хозяйства. Однако, когда объектная модель не делает то, что должна, вещи действительно отстой. Это ситуация с полем parent_id и полем path. Magento просто не обновляет их так, как должно.

Решение состоит в том, чтобы внести необходимые изменения с помощью объектной модели, сохранить объект, а затем СДЕЛАТЬ правильные значения для "parent_id" и "path" с помощью запроса к базе данных. Я обнаружил, что поля 'parent_id' и 'path', похоже, правильно сохраняются при первом создании записи, но затем они портятся, если объект обновляется. Этот код предполагает, что вы обновляете существующий объект категории.

$catId = 127; //ID of category record you wish to edit
$objCat = Mage::getModel('catalog/category')->load($catId); 
if(!is_object($objCat)) {
    throw new Exception("ERROR: Could not find category id: " .$catId);
}

//--- Make sure we have proper parent_id and path values
$parentId = $objCatParent->getId();
$path =  $objCatParent->getPath() ."/" .$objCat->getId();

$objCatParent = $objCat->getParentCategory();  //We will need this parent category
$data = array('name'     => 'My Cool Category',
              'parent_id => $parentId,
              'path'     => $path;
$objCat->addData($data);  //Use 'addData' rather than 'setData'
$objCat->save(); //Save to update record and break parent_id, path fields

//--- Now we get a connection to the database, build a query, and update record
$resource = Mage::getSingleton('core/resource');
$objCon = $resource->getConnection('core_write');
$tableName = "catalog_category_entity";  //Well, it's the name of the Category table
$query = "UPDATE  {$table} SET parent_id = {$parentId}, path = '{$path}' "
       . " WHERE entity_id = " .$catId;
$objCon->query($query); //Force proper values directly into table

Да, да, да, вы должны быть очень осторожны, когда вы обходите объектную модель и вносите изменения непосредственно в записи базы данных. Однако объектная модель Magento, похоже, здесь не работает, поэтому у нас мало выбора. И поскольку мы сохраняем запись с помощью метода объекта save(), прежде чем он выполняет какую-либо "закулисную" работу, которую он должен делать. Мы просто исправляем ошибку.

Я надеюсь, что это помогает вам. Это была неприятная проблема. Хотелось бы, чтобы было лучшее решение, но когда они исправят API, я перестану играть с базой данных. И для тех из вас, кто скажет, что отвечать на свой вопрос в третьем лице - неудобно, я говорю: "ГА!"

Другие вопросы по тегам