<p>I was able to figure almost all of this stuff out by diving through the code. The only exception is triggering the <code>find()</code> method automatically.</p>

<p>The key here was to follow the code in the <code>ElementCriteriaModel</code>. First thing I did was create a method in the <code>MyPluginService</code> class to fetch the data.</p>

<pre><code>public function foo($criteria = false)
{
    return new MyPlugin_MyCriteriaModel($criteria ?: array());
}
</code></pre>

<p>I added a wrapper to my <code>MyPluginVariable</code> class.</p>

<pre><code>public function parcels($criteria = array())
{
    return craft()-&gt;myPlugin-&gt;foo($criteria);
}
</code></pre>

<p>This will allow for the following syntax:</p>

<pre><code>{% set data = craft.myPlugin.foo().limit(5).offset(1).find() %}
</code></pre>

<p>You must define a <code>find()</code> method in your <code>MyPlugin_MyCriteriaModel</code> class that will perform the SQL query to actually fetch your data. You also have to loop through the results set and instantiate <code>MyPlugin_FooModel</code> for each db row if you want to return a <code>Model</code> to the template instead of a <code>stdObject</code> or array.</p>

<p>For example, my find method looks like this:</p>

<pre><code>public function find($attributes = null)
{   
    $this-&gt;setAttributes($attributes);

    if (!isset($this-&gt;_matchedObjects))
    {
        $objects = craft()-&gt;myplugin_foo-&gt;find($this);

        $this-&gt;setMatchedObjects($objects);
    }

    return $this-&gt;_matchedObjects;
}
</code></pre>

<p>Then in <code>MyPlugin_FooService</code> I have this:</p>

<pre><code>public function query(MyPlugin_MyCriteriaModel $criteria)
{
    $record = new MyPlugin_FooRecord();

    $query = craft()-&gt;db-&gt;createCommand()
        -&gt;select('*')
        -&gt;from($record-&gt;getTableName())
        -&gt;limit($criteria-&gt;limit)
        -&gt;offset($criteria-&gt;offset)
        -&gt;order($criteria-&gt;order);

    if($criteria-&gt;id)
    {
        $query-&gt;where('id = :id', array(':id' =&gt; $criteria-&gt;id));
    }

    if($criteria-&gt;uid)
    {
        $query-&gt;where('uid = :uid', array(':uid' =&gt; $criteria-&gt;uid));
    }

    // More conditionals may go here

    return $query;
}

public function find(MyPlugin_MyCriteriaModel $criteria)
{
    $query = $this-&gt;query($criteria);

    return $this-&gt;_populateModelsFromArray($query-&gt;queryAll());
}

protected function _populateModelsFromArray(Array $array)
{
    $models = array();

    foreach($array as $row)
    {
        $models[] = MyPlugin_FooModel::populateModel($row);
    }

    return $models;
}
</code></pre>

CC BY-SA 3.0
2015-01-09T06:24:10.617Z
what does your MyPluginVariable class look like with the wrapper function?
a-am
CC BY-SA 3.0
2015-01-09T17:19:59.833Z
also are you extending ElementCriteriaModel in MyPlugin_MyCriteriaModel?
a-am
CC BY-SA 3.0
2015-01-09T19:38:15.447Z
`MyPlugin_MyCriteriaModel` is a class that extends `BaseModel`. It's just a regular model with some arbitrary attributes. I did base the logic off `ElementCriteriaModel`, but it does not extend it. The `MyPluginVariable` wrapping method looks like this: `public function parcels($criteria = array()) { return craft()->postmaster->parcels($criteria); }`
Justin Kimbrell
CC BY-SA 3.0
2015-01-09T19:42:10.460Z
so where your calling foo above, for your plugin your calling parcels?
a-am
CC BY-SA 3.0
2015-01-09T19:47:46.067Z
That's right. The logic is kinda confusing. You use the variables to call the criteria model, which returns a "chainable" object. Then the `find` method in the criteria model sends the model to the `ParcelService` instance, which actually runs the query.
Justin Kimbrell
CC BY-SA 3.0
2015-01-09T19:49:02.937Z
Feel free to download Postmaster to see the complete code I am referencing. https://github.com/objectivehtml/Postmaster-for-Craft-CMS
Justin Kimbrell
CC BY-SA 3.0
2014-12-10T18:49:23.587Z
2014-12-10T18:49:23.587Z
Justin Kimbrell
<p>My main issue is perhaps not totally understanding the unique idioms of Yii, but I need to output data from my custom data tables in a template. So obviously I have a <code>MyPluginVariables</code> class and a <code>MyPluginService</code> to handle to actual business logic.</p>

<p>Using my <code>MyPlugin_FooRecord</code> I can use ActiveRecord to fetch some data. But this obviously returns the actual record objects, when I really just need a model passed to the template. From what I understand, I should use models not the records themselves. Is this correct?</p>

<p>Also, how exactly should I build a chainable syntax, similar to fetching entries in a template?</p>

<p>For example, I am trying to get this to work:</p>

<pre><code>{% set rows = craft.myPlugin.someMethod().limit(10).order('some_col').sort('asc') %}
</code></pre>

<p>So relating this syntax back to my original question, how would I build this and return an array of models? The <code>ElementCriteriaModel</code> will automatically execute the <code>find()</code> method when it's used an array, should I just overriding the <code>__toArray()</code> method?</p>

<p>I have been searching and looking through the docs, so perhaps I missed something. I have also been looking through the code in Craft, but due to the abstractions and not being familiar with Yii core classes, I am getting a little lost in figuring out how this works.</p>

<plugin-development>
What is the proper way to fetch items from a custom db table and output them in twig?
# What is the proper way to fetch items from a custom db table and output them in twig?

(Asked by: username_0 on 2014-12-06)

My main issue is perhaps not totally understanding the unique idioms of Yii, but I need to output data from my custom data tables in a template. So obviously I have a MyPluginVariables class and a MyPluginService to handle to actual business logic.
Using my MyPlugin_FooRecord I can use ActiveRecord to fetch some data. But this obviously returns the actual record objects, when I really just need a model passed to the template. From what I understand, I should use models not the records themselves. Is this correct?
Also, how exactly should I build a chainable syntax, similar to fetching entries in a template?
For example, I am trying to get this to work:
{% set rows = craft.myPlugin.someMethod().limit(10).order('some_col').sort('asc') %}

So relating this syntax back to my original question, how would I build this and return an array of models? The ElementCriteriaModel will automatically execute the find() method when it's used an array, should I just overriding the __toArray() method?
I have been searching and looking through the docs, so perhaps I missed something. I have also been looking through the code in Craft, but due to the abstractions and not being familiar with Yii core classes, I am getting a little lost in figuring out how this works.

**Tags:** plugin-development

---

## 1 answers

### Answer by username_0 on 2014-12-10. Score: 4 | Accepted answer

I was able to figure almost all of this stuff out by diving through the code. The only exception is triggering the find() method automatically.
The key here was to follow the code in the ElementCriteriaModel. First thing I did was create a method in the MyPluginService class to fetch the data.
public function foo($criteria = false)
{
    return new MyPlugin_MyCriteriaModel($criteria ?: array());
}

I added a wrapper to my MyPluginVariable class.
public function parcels($criteria = array())
{
    return craft()->myPlugin->foo($criteria);
}

This will allow for the following syntax:
{% set data = craft.myPlugin.foo().limit(5).offset(1).find() %}

You must define a find() method in your MyPlugin_MyCriteriaModel class that will perform the SQL query to actually fetch your data. You also have to loop through the results set and instantiate MyPlugin_FooModel for each db row if you want to return a Model to the template instead of a stdObject or array.
For example, my find method looks like this:
public function find($attributes = null)
{   
    $this->setAttributes($attributes);

    if (!isset($this->_matchedObjects))
    {
        $objects = craft()->myplugin_foo->find($this);

        $this->setMatchedObjects($objects);
    }

    return $this->_matchedObjects;
}

Then in MyPlugin_FooService I have this:
public function query(MyPlugin_MyCriteriaModel $criteria)
{
    $record = new MyPlugin_FooRecord();

    $query = craft()->db->createCommand()
        ->select('*')
        ->from($record->getTableName())
        ->limit($criteria->limit)
        ->offset($criteria->offset)
        ->order($criteria->order);

    if($criteria->id)
    {
        $query->where('id = :id', array(':id' => $criteria->id));
    }

    if($criteria->uid)
    {
        $query->where('uid = :uid', array(':uid' => $criteria->uid));
    }

    // More conditionals may go here

    return $query;
}

public function find(MyPlugin_MyCriteriaModel $criteria)
{
    $query = $this->query($criteria);

    return $this->_populateModelsFromArray($query->queryAll());
}

protected function _populateModelsFromArray(Array $array)
{
    $models = array();

    foreach($array as $row)
    {
        $models[] = MyPlugin_FooModel::populateModel($row);
    }

    return $models;
}

> **Comments:**
> **username_1**: what does your MyPluginVariable class look like with the wrapper function?  
> **username_1**: also are you extending ElementCriteriaModel in MyPlugin_MyCriteriaModel?  
> **username_0**: `MyPlugin_MyCriteriaModel` is a class that extends `BaseModel`. It's just a regular model with some arbitrary attributes. I did base the logic off `ElementCriteriaModel`, but it does not extend it. The `MyPluginVariable` wrapping method looks like this: `public function parcels($criteria = array()) { return craft()->postmaster->parcels($criteria); }`  
> **username_1**: so where your calling foo above, for your plugin your calling parcels?  
> **username_0**: That's right. The logic is kinda confusing. You use the variables to call the criteria model, which returns a "chainable" object. Then the `find` method in the criteria model sends the model to the `ParcelService` instance, which actually runs the query.  
> **username_0**: Feel free to download Postmaster to see the complete code I am referencing. https://github.com/objectivehtml/Postmaster-for-Craft-CMS  

---

