14

I have a custom model and resource model. I want to load a single instance of the model using more than 1 field.

The model has the following fields:

id
tag_name
custom_name
group_name

I want to load this model based on on tag_name, custom_name and group_name instead of id.

Currently i am using a collection and addFilter for each field. This works, but i wondered if there is a standard strategy for this type of thing in Magento?

EDIT

Core magento seems not to use collections for this scenario but instead it uses direct sql queries in the resource models.

an example of this is:

loadByAccountAndDate() in Mage_Paypal_Model_Resource_Report_Settlement

Is there a reason for this, when collections seem to be a more concise way, in terms of amount of code to be written

I just dont know why magento chooses to do it this way

20

I think this is a good approach. Maybe you need to create a wrapper in the model class so you will avoid writing the same thing over and over again.
Something like:

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

And you can load the item like this in any other place:

$model = Mage::getModel('model/class_here')->loadByMultiple($tag, $customName, $group);
if ($model->getId()){
   //the instance exists
}
else{
    //not found
}
  • I have updated my question with my concerns over using collections – Marty Wallace Jun 12 '13 at 15:40
  • If you really want to exclude collections from your logic check what @mageUz wrote in his answer. I didn't test it, but seams like a good idea. Note: I still don't see any issues in using collections. – Marius Jun 12 '13 at 16:46
  • It is not that i would like to exclude them, but i want to use magento best practices. If core code is doing something in a particular way then typically that should be a sign of something to follow. But i am asking on this forum for guidence as in this case i really do not know the best way – Marty Wallace Jun 12 '13 at 16:49
  • 1
    I also have concerns using collections in this case. Presumably the collection in question has an _itemObjectClass that is the same as the model actually calling loadByMultiple. So as a result, wouldn't $x = Mage::getModel('some/model') be one instance of a model and $x->loadByMultiple($tag, $customName, $group) actually be a different/new instance? – kojiro Jul 28 '14 at 13:29
  • @kojiro. Yes it will be a different instance but so does loadByAttribute. See this question for reference: magento.stackexchange.com/q/5926/146 – Marius Jul 28 '14 at 13:31
6

Module/Model/SomeModel.php

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

Module/Model/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);
    }

And finally you can load model following:

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

Updated

By the way you can use this (loadByAttributes) method easily rather than collection and it is more understandable. Magento also dispatches some events while loading collection or entity and third party extension can update collection or entity by observer. If you load the entity via resource (given in example of mine and yours) no event/observers fire and you can get "clean" entity faster rather than collection. Also Magento not uses cached collection by this way, it loads it directly from db table.
Maybe that's reason of using this method by Magento core modules.

  • I think you are missing a getData() on this line: $this->setData($this->getResource()->loadByAttributes($attributes));, which should be: $this->setData($this->getResource()->loadByAttributes($attributes)->getData()); Right ? – Mihai MATEI Nov 11 '15 at 14:01
2

You are doing it right with addFilter. In Magento you can load by any attribute but not multiple attributes at once. By adding filters you achieve the same effect with no extra overhead.

  • Using a db select would not be better than using a collection? – Marty Wallace Jun 12 '13 at 13:51
  • What do you think addFilter is doing? :-) – Foo Bar Jun 12 '13 at 14:27
  • Can you look at loadByAccountAndDate() in Mage_Paypal_Model_Resource_Report_Settlement as this is using a select instead of collection – Marty Wallace Jun 12 '13 at 15:36
  • And actually this situation in core code is almost exclusively like this and i can not see any using collections – Marty Wallace Jun 12 '13 at 15:36
  • 1
    I have updated my question with my concerns over using collections – Marty Wallace Jun 12 '13 at 15:39
1

Firstly - your strategy to filter a collection is correct. Because collections in Magento lazy-load you have the ability to create methods in your resource model to more tightly define the requirements of your custom load.

Without some of your code to sample, consider the following pseudo-method in your Resource Model:

<?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;

    }
}
  • I have updated my question with my concerns over using collections for this particular use case but i don't have enough knowledge to know why magento does it this way – Marty Wallace Jun 12 '13 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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