Magento - modèle personnalisé (non eav), chargement par plusieurs champs

15

J'ai un modèle personnalisé et un modèle de ressource. Je veux charger une seule instance du modèle en utilisant plus d'un champ.

Le modèle comporte les champs suivants:

id
tag_name
custom_name
group_name

Je veux charger ce modèle en fonction de tag_name, custom_name et group_name au lieu de id.

Actuellement, j'utilise une collection et addFilter pour chaque champ. Cela fonctionne, mais je me demandais s'il existe une stratégie standard pour ce type de chose dans Magento?

ÉDITER

Core magento ne semble pas utiliser de collections pour ce scénario, mais utilise plutôt des requêtes SQL directes dans les modèles de ressources.

un exemple de ceci est:

loadByAccountAndDate() dans Mage_Paypal_Model_Resource_Report_Settlement

Y a-t-il une raison à cela, lorsque les collections semblent être un moyen plus concis, en termes de quantité de code à écrire

Je ne sais juste pas pourquoi magento choisit de le faire de cette façon

Marty Wallace
la source

Réponses:

22

Je pense que c'est une bonne approche. Vous devrez peut-être créer un wrapper dans la classe modèle afin d'éviter de répéter la même chose encore et encore.
Quelque chose comme:

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

Et vous pouvez charger l'article comme ceci dans n'importe quel autre endroit:

$model = Mage::getModel('model/class_here')->loadByMultiple($tag, $customName, $group);
if ($model->getId()){
   //the instance exists
}
else{
    //not found
}
Marius
la source
J'ai mis à jour ma question avec mes préoccupations concernant l'utilisation des collections
Marty Wallace
Si vous voulez vraiment exclure des collections de votre logique, vérifiez ce que @mageUz a écrit dans sa réponse. Je ne l'ai pas testé, mais les coutures sont une bonne idée. Remarque: je ne vois toujours aucun problème dans l'utilisation des collections.
Marius
Ce n'est pas que je voudrais les exclure, mais je veux utiliser les meilleures pratiques de magento. Si le code principal fait quelque chose d'une manière particulière, cela devrait généralement être un signe de quelque chose à suivre. Mais je demande des preuves sur ce forum car dans ce cas je ne connais vraiment pas la meilleure façon
Marty Wallace
1
J'ai également des préoccupations concernant l'utilisation des collections dans ce cas. Vraisemblablement, la collection en question a un _itemObjectClassqui est le même que le modèle appelant réellement loadByMultiple. Par conséquent, ne serait-ce pas $x = Mage::getModel('some/model')une instance d'un modèle et en $x->loadByMultiple($tag, $customName, $group)fait une instance différente / nouvelle?
kojiro
@kojiro. Oui, ce sera une instance différente, mais il en va de même loadByAttribute. Voir cette question pour référence: magento.stackexchange.com/q/5926/146
Marius
7

Module / Model / SomeModel.php

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

Module / Modèle / Ressource / 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);
    }

Et enfin, vous pouvez charger le modèle suivant:

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

Mis à jour

Soit dit en passant, vous pouvez utiliser cette méthode (loadByAttributes) facilement plutôt que la collection et c'est plus compréhensible. Magento envoie également certains événements lors du chargement d'une collection ou d'une entité et une extension tierce peut mettre à jour la collection ou l'entité par observateur. Si vous chargez l'entité via une ressource (donnée dans l'exemple du mien et le vôtre), aucun événement / observateur ne se déclenche et vous pouvez obtenir une entité "propre" plus rapidement que la collecte. De plus, Magento n'utilise pas la collection en cache de cette façon, il la charge directement à partir de la table db.
C'est peut-être la raison de l'utilisation de cette méthode par les modules de base de Magento.

mageUz
la source
Je pense qu'il vous manque un getData () sur cette ligne:, $this->setData($this->getResource()->loadByAttributes($attributes));qui devrait être: non $this->setData($this->getResource()->loadByAttributes($attributes)->getData()); ?
Mihai MATEI
2

Vous le faites bien avec addFilter. Dans Magento, vous pouvez charger par n'importe quel attribut mais pas par plusieurs attributs à la fois. En ajoutant des filtres, vous obtenez le même effet sans surcharge supplémentaire.

user487772
la source
Utiliser un db select ne serait-il pas mieux que d'utiliser une collection?
Marty Wallace
Que pensez-vous addFilterfaire? :-)
user487772
Pouvez-vous regarder loadByAccountAndDate () dans Mage_Paypal_Model_Resource_Report_Settlement car cela utilise une sélection au lieu d'une collection
Marty Wallace
Et en fait, cette situation dans le code de base est presque exclusivement comme ça et je ne peux pas voir de collections utilisant
Marty Wallace
1
J'ai mis à jour ma question avec mes préoccupations concernant l'utilisation des collections
Marty Wallace
1

Premièrement, votre stratégie pour filtrer une collection est correcte. Étant donné que les collections dans Magento lazy-load, vous avez la possibilité de créer des méthodes dans votre modèle de ressource pour définir plus précisément les exigences de votre chargement personnalisé.

Sans une partie de votre code à échantillonner, envisagez la pseudo-méthode suivante dans votre modèle de ressource:

<?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
la source
J'ai mis à jour ma question avec mes préoccupations concernant l'utilisation des collections pour ce cas d'utilisation particulier, mais je n'ai pas suffisamment de connaissances pour savoir pourquoi magento le fait de cette façon
Marty Wallace