Magento - modelo personalizado (no eav), carga por múltiples campos

15

Tengo un modelo personalizado y un modelo de recursos. Quiero cargar una sola instancia del modelo usando más de 1 campo.

El modelo tiene los siguientes campos:

id
tag_name
custom_name
group_name

Quiero cargar este modelo basado en tag_name, custom_name y group_name en lugar de id.

Actualmente estoy usando una colección y addFilter para cada campo. Esto funciona, pero me preguntaba si hay una estrategia estándar para este tipo de cosas en Magento.

EDITAR

Core magento parece no usar colecciones para este escenario, sino que usa consultas sql directas en los modelos de recursos.

Un ejemplo de esto es:

loadByAccountAndDate() en Mage_Paypal_Model_Resource_Report_Settlement

¿Hay alguna razón para esto, cuando las colecciones parecen ser una forma más concisa, en términos de la cantidad de código que se debe escribir?

Simplemente no sé por qué magento elige hacerlo de esta manera

Marty Wallace
fuente

Respuestas:

22

Creo que este es un buen enfoque. Tal vez necesite crear un contenedor en la clase de modelo para evitar escribir lo mismo una y otra vez.
Algo como:

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

Y puede cargar el artículo como este en cualquier otro lugar:

$model = Mage::getModel('model/class_here')->loadByMultiple($tag, $customName, $group);
if ($model->getId()){
   //the instance exists
}
else{
    //not found
}
Marius
fuente
He actualizado mi pregunta con mis preocupaciones sobre el uso de colecciones
Marty Wallace
Si realmente desea excluir colecciones de su lógica, verifique lo que @mageUz escribió en su respuesta. No lo probé, pero parece una buena idea. Nota: Todavía no veo ningún problema al usar colecciones.
Marius
No es que me gustaría excluirlos, pero quiero utilizar las mejores prácticas de magento. Si el código central está haciendo algo de una manera particular, normalmente eso debería ser una señal de algo a seguir. Pero estoy pidiendo orientación en este foro, ya que en este caso no sé cuál es la mejor manera
Marty Wallace
1
También me preocupa el uso de colecciones en este caso. Presumiblemente, la colección en cuestión tiene _itemObjectClassel mismo aspecto que el modelo que realmente llama loadByMultiple. Como resultado, ¿no $x = Mage::getModel('some/model')sería una instancia de un modelo y en $x->loadByMultiple($tag, $customName, $group)realidad sería una instancia diferente / nueva?
kojiro
@kojiro. Sí, será una instancia diferente, pero también lo hace loadByAttribute. Consulte esta pregunta como referencia: magento.stackexchange.com/q/5926/146
Marius
7

Módulo / Modelo / SomeModel.php

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

Módulo / Modelo / Recurso / 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);
    }

Y finalmente puede cargar el siguiente modelo:

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

Actualizado

Por cierto, puede usar este método (loadByAttributes) fácilmente en lugar de la colección y es más comprensible. Magento también despacha algunos eventos mientras carga la colección o entidad y la extensión de terceros puede actualizar la colección o entidad por observador. Si carga la entidad a través del recurso (dado en el mío y el suyo), no se dispara ningún evento / observador y puede obtener una entidad "limpia" más rápido que la recolección. Además, Magento no utiliza la colección en caché de esta manera, la carga directamente desde la tabla db.
Quizás esa sea la razón de usar este método en los módulos principales de Magento.

mageUz
fuente
Creo que te falta getData () en esta línea: $this->setData($this->getResource()->loadByAttributes($attributes));que debería ser: $this->setData($this->getResource()->loadByAttributes($attributes)->getData()); ¿ verdad ?
Mihai MATEI
2

Lo estás haciendo bien con addFilter. En Magento puede cargar por cualquier atributo pero no por múltiples atributos a la vez. Al agregar filtros se logra el mismo efecto sin sobrecarga adicional.

usuario487772
fuente
¿Usar un db select no sería mejor que usar una colección?
Marty Wallace
¿Qué crees que addFilterestá haciendo? :-)
user487772
¿Puedes mirar loadByAccountAndDate () en Mage_Paypal_Model_Resource_Report_Settlement ya que esto está usando una selección en lugar de una colección
Marty Wallace
Y en realidad esta situación en el código central es casi exclusivamente así y no puedo ver ninguna usando colecciones
Marty Wallace
1
He actualizado mi pregunta con mis preocupaciones sobre el uso de colecciones
Marty Wallace
1

En primer lugar, su estrategia para filtrar una colección es correcta. Debido a que las colecciones en Magento lazy-load tiene la capacidad de crear métodos en su modelo de recursos para definir más estrictamente los requisitos de su carga personalizada.

Sin parte de su código para probar, considere el siguiente pseudo-método en su Modelo de recursos:

<?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
fuente
He actualizado mi pregunta con mis preocupaciones sobre el uso de colecciones para este caso de uso en particular, pero no tengo suficiente conocimiento para saber por qué magento lo hace de esta manera
Marty Wallace