Magento - пользовательская (не eav) модель, загрузка по нескольким полям

15

У меня есть пользовательская модель и модель ресурса. Я хочу загрузить один экземпляр модели, используя более 1 поля.

Модель имеет следующие поля:

id
tag_name
custom_name
group_name

Я хочу загрузить эту модель, основанную на tag_name, custom_name и group_name вместо id.

В настоящее время я использую коллекцию и addFilter для каждого поля. Это работает, но я задавался вопросом, есть ли стандартная стратегия для такого типа вещей в Magento?

РЕДАКТИРОВАТЬ

Кажется, ядро ​​magento не использует коллекции для этого сценария, а вместо этого использует прямые sql-запросы в моделях ресурсов.

Примером этого является:

loadByAccountAndDate() в Mage_Paypal_Model_Resource_Report_Settlement

Есть ли причина для этого, когда коллекции кажутся более краткими с точки зрения количества кода, который будет написан

Я просто не знаю, почему Мадженто решил сделать это таким образом

Марти Уоллес
источник

Ответы:

22

Я думаю, что это хороший подход. Возможно, вам нужно создать оболочку в классе модели, чтобы вы не писали одно и то же снова и снова.
Что-то вроде:

public function loadByMultiple($tag, $customName, $group){
    $collection = $this->getCollection()
            ->addFieldToFilter('tag_name', $tag)
            ->addFieldToFilter('custom_name', $customName)
            ->addFieldToFilter('group_name', $group);
    return $collection->getFirstItem();
}

И вы можете загрузить товар, как это в любом другом месте:

$model = Mage::getModel('model/class_here')->loadByMultiple($tag, $customName, $group);
if ($model->getId()){
   //the instance exists
}
else{
    //not found
}
Мариус
источник
Я обновил свой вопрос своими опасениями по поводу использования коллекций
Марти Уоллес
Если вы действительно хотите исключить коллекции из своей логики, проверьте, что @mageUz написал в своем ответе. Я не проверял это, но швы как хорошая идея. Примечание: я до сих пор не вижу проблем в использовании коллекций.
Мариус
Не то чтобы я хотел их исключить, но я хочу использовать лучшие практики magento. Если основной код делает что-то определенным образом, то обычно это должно быть признаком того, что нужно соблюдать. Но я прошу об этом на форуме, так как в этом случае я действительно не знаю лучшего пути
Марти Уоллес
1
У меня также есть проблемы с использованием коллекций в этом случае. Предположительно, у рассматриваемой коллекции есть _itemObjectClassто же самое, что и модель, которая фактически вызывает loadByMultiple. Таким образом, в результате, не $x = Mage::getModel('some/model')будет ли один экземпляр модели и $x->loadByMultiple($tag, $customName, $group)фактически будет другой / новый экземпляр?
Кодзиро
@kojiro. Да, это будет другой случай, но это так loadByAttribute. См. Этот вопрос для справки: magento.stackexchange.com/q/5926/146
Мариус
7

Модуль / Модель / SomeModel.php

public function loadByAttributes($attributes)
{
    $this->setData($this->getResource()->loadByAttributes($attributes));
    return $this;
}

Модуль / Модель / Resource / SomeModel.php:

public function loadByAttributes($attributes)
    {
        $adapter = $this->_getReadAdapter();
        $where   = array();
        foreach ($attributes as $attributeCode=> $value) {
            $where[] = sprintf('%s=:%s', $attributeCode, $attributeCode);
        }
        $select = $adapter->select()
            ->from($this->getMainTable())
            ->where(implode(' AND ', $where));

        $binds = $attributes;

        return $adapter->fetchRow($select, $binds);
    }

И, наконец, вы можете загрузить следующую модель:

$attributes = array('tag_name'=> 'any', 'custome_name'=> 'some','group_name'=>'some');
$model      = Mage::getModel('module/somemodel')->loadByAttributes($attributes);

обновленный

Кстати, вы можете использовать этот метод (loadByAttributes) проще, чем коллекцию, и это более понятно. Magento также отправляет некоторые события во время загрузки коллекции или объекта, и стороннее расширение может обновлять коллекцию или объект наблюдателем. Если вы загружаете сущность через ресурс (указанный в моем и вашем примере), никакие события / наблюдатели не запускаются, и вы можете получить «чистую» сущность быстрее, чем сбор. Также Magento не использует кэшированную коллекцию таким образом, она загружает ее непосредственно из таблицы БД.
Возможно, это причина использования этого метода базовыми модулями Magento.

mageUz
источник
Я думаю, что вам не хватает getData () в этой строке:, $this->setData($this->getResource()->loadByAttributes($attributes));который должен быть: $this->setData($this->getResource()->loadByAttributes($attributes)->getData()); Верно?
Михай Матей
2

Вы делаете это правильно с addFilter. В Magento вы можете загрузить любой атрибут, но не несколько атрибутов одновременно. Добавляя фильтры, вы получаете тот же эффект без лишних затрат.

user487772
источник
Использование выбора БД не будет лучше, чем использование коллекции?
Марти Уоллес
Как вы думаете, что addFilterделает? :-)
user487772
Можете ли вы посмотреть на loadByAccountAndDate () в Mage_Paypal_Model_Resource_Report_Settlement, так как здесь используется выбор вместо коллекции
Марти Уоллес
И на самом деле эта ситуация в основном коде почти исключительно такая, и я не вижу никаких использующих коллекций
Марти Уоллес
1
Я обновил свой вопрос своими опасениями по поводу использования коллекций
Марти Уоллес
1

Во-первых, ваша стратегия фильтрации коллекции верна. Поскольку коллекции в Magento lazy-load, у вас есть возможность создавать методы в вашей модели ресурсов, чтобы более точно определить требования вашей пользовательской нагрузки.

Без использования вашего кода для примера рассмотрим следующий псевдо-метод в вашей модели ресурсов:

<?php


class Marty_Wallace_Model_Resource_Method extends Mage_Core_Model_Resource_Db_Abstract{

    protected function _construct()
    {
        $this->_init('yourmodel/table', 'entity_id');
    }

    public function loadByCriteria(array $filter)
    {

        //$filter should be array('columnname'=>'value','columname'=>'value')

        $collection = Mage::getModel('yourmodel/class')->getCollection();

        foreach($filter as $column=>$value){
            $collection->addFieldToFilter($column,$value);
        }

        return $collection;

    }
}
philwinkle
источник
Я обновил свой вопрос своими соображениями по поводу использования коллекций для этого конкретного случая использования, но у меня недостаточно знаний, чтобы понять, почему magento делает это таким образом
Марти Уоллес