Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Get field from related model in Volt

Hei,

I try to understand related models, so I created a small setup for a gallery. Now I want to get an ID from a related model. But I do not know how to use it in volt.

So I would like to create a menu with links to the categories. Working. And I want to display the pictures; also working. But now I want to display the corresponding category-ID to each picture. How can I get the ID within the loop for the pictures?

This is my database setup:

CREATE TABLE IF NOT EXISTS `gallery_categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `icon` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;

INSERT INTO `gallery_categories` (`id`, `name`, `icon`) VALUES
(1, 'Default', 'fa-bars'),
(2, 'Testcat', 'fa-angle-down');

-- --------------------------------------------------------

CREATE TABLE IF NOT EXISTS `gallery_items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `path` varchar(128) NOT NULL,
  `title` varchar(32) NOT NULL,
  `subtitle` varchar(64) NOT NULL,
  `description` varchar(512) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;

INSERT INTO `gallery_items` (`id`, `path`, `title`, `subtitle`, `description`) VALUES
(1, 'http://lorempixel.com/262/262/technics/', 'Title #1', 'This is a small placeholder', 'This placeholder is holding place. A place that could be filled with some thing else.'),
(2, 'http://lorempixel.com/262/262/technics/', 'Title #1', 'This is a small placeholder', 'This placeholder is holding place. A place that could be filled with some thing else.'),
(3, 'http://lorempixel.com/262/262/technics/', 'Title #1', 'This is a small placeholder', 'This placeholder is holding place. A place that could be filled with some thing else.');

-- --------------------------------------------------------

CREATE TABLE IF NOT EXISTS `gallery_memberships` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `gallery_item_id` int(10) NOT NULL,
  `gallery_category_id` int(10) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `robots_id` (`gallery_item_id`),
  KEY `parts_id` (`gallery_category_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;

INSERT INTO `gallery_memberships` (`id`, `gallery_item_id`, `gallery_category_id`) VALUES
(1, 1, 1),
(2, 1, 2),
(4, 2, 1),
(5, 3, 1);

So here we go with the models:

// GalleryCategories.php
<?php
namespace Vokuro\Models;
use Phalcon\Mvc\Model;


class GalleryCategories extends Model
{
    public $id;

    public $name;

    public $icon;

    public function initialize()
    {
        $this->hasMany("id", "Vokuro\Models\GalleryMemberships", "gallery_category_id", array( "alias" => "GalleryMemberships"));
    }

}

// GalleryItems.php
<?php
namespace Vokuro\Models;
use Phalcon\Mvc\Model;


class GalleryItems extends Model
{
    public $id;

    public $path;

    public $title;

    public $subtitle;

    public $description;

    public function initialize()
    {
        $this->hasMany("id", "Vokuro\Models\GalleryMemberships", "gallery_item_id", array( "alias" => "GalleryMemberships"));
    }

}




// GalleryMemberships.php
<?php
namespace Vokuro\Models;
use Phalcon\Mvc\Model;


class GalleryMemberships extends Model
{
    public $id;

    public $gallery_item_id;

    public $gallery_category_id;

    public function initialize()
    {
        $this->belongsTo("gallery_item_id", "Vokuro\Models\GalleryItems", "id", array( "alias" => "GalleryItems"));
        $this->belongsTo("gallery_category_id", "Vokuro\Models\GalleryCategories", "id", array( "alias" => "GalleryCategories"));
    }

}

And the controller:

<?php
namespace Vokuro\Controllers;
use Vokuro\Models\GalleryItems;
use Vokuro\Models\GalleryCategories;
/**
 * Display the default index page.
 */
class GalleryController extends ControllerBase
{
    public function initialize()
    {
        $this->view->setTemplateBefore('public');
    }

    /**
     * Default action. Set the public layout (layouts/public.volt)
     */
    public function indexAction()
    {
        // Get all categories
        $this->view->setVar("gallery_categories", GalleryCategories::find());
        $this->view->setVar("gallery_items", Galleryitems::find());
    }
}

And here comes the template index.volt

    /////////////////////////////////////////////////////
    {{ codeblock to display a menu based on categories }}
    /////////////////////////////////////////////////////

    {% for gallery_category in gallery_categories %}
    <li>
        <a class="" href="#filter" data-option-value=".category-{{ gallery_category.id }}">
            <i class="fa {{ gallery_category.icon }}"></i>
            <span class="title">{{ gallery_category.name }}</span>
        </a>
    </li> 
    {% endfor  %}


    /////////////////////////////////////////////////////
    {{ codeblock to display pictures }}
    /////////////////////////////////////////////////////

    {% for gallery_item in gallery_items %}

    <div class="col-md-3 col-xs-12 col-sm-6 bottom-30 element category-{{ HERE I NEED THE CATEGORY ID }}" data-my-order="1">
        <div class="portfolio-item white">
            <div class="portfolio-info">
                <h4><a href="#">{{ gallery_item.title }}</a></h4>
                <a href="#">{{ gallery_item.subtitle }}</a>
            </div>
            <div class="portfolio-image">
                <a href="#"><img src="{{ gallery_item.path }}" alt=""></a>
            </div>
            <div class="portfolio-link">
                <a href="#"><i class="fa fa-eye"></i>View Detail</a>
                <a title="{{ gallery_item.description }}" class="image-popup" href="http://placehold.it/800x800"><i class="fa fa-search-plus"></i>Quick View</a>
            </div> 
        </div> 
    </div> 

    {% endfor %}

Hope you get my idea. :)



18.5k

Maybe gallery_item.galleryMemberships.galleryCategories.id?

I thought so, too. But it just spits out this message:

Notice: Undefined property: Phalcon\Mvc\Model\Resultset\Simple::$galleryCategories in /var/www/gallery_index.volt.php on line 51


18.5k

Then, in the controller, search for the related models, assign then to the property I said before, and try again.

Hm this is kinda breaking my logics. Can you explain a bit what is going on and how the models influence each other?

Right now I defined all 3 models in Volt like this:

    public function indexAction()
    {
        // Get all categories
        $this->view->setVar("gallery_categories", GalleryCategories::find());
        $this->view->setVar("gallery_items", GalleryItems::find());
        $this->view->setVar("gallery_memberships", GalleryMemberships::find());
    }

Now in the template I use the property like you wrote:

{% for gallery_item in gallery_items %}
{{ gallery_item.gallery_memberships.gallery_categories.id }}
{% endfor  %}

But the framework just shows up:

Notice: Undefined property: Phalcon\Mvc\Model\Resultset\Simple::$GalleryCategories in /var/www/gallery_index.volt.php on line 4


30.0k
Accepted
answer
edited Dec '14

Hi, you are using many to many relationships, firstly, in GalleryMemberships model definition I would have used singular aliases in relation definitions:

$this->belongsTo("gallery_item_id", "Vokuro\Models\GalleryItems", "id", array( "alias" => "GalleryItem"));
$this->belongsTo("gallery_category_id", "Vokuro\Models\GalleryCategories", "id", array( "alias" => "GalleryCategory"));

so code below won't work

{{ gallery_item.gallery_memberships.gallery_categories.id }}

rather use (for displaying all the categories related to a single image):

{% for gallery_category in gallery_item.GalleryMemberships %} // looping through image related categories as defined in GalleryItems Model
{{ gallery_category.GalleryCategory.id }} // gallery_category is a GalleryMemberships object, so getting the related category id by using alias definition
{% endfor  %}

Super! That worked pretty well. :)

I renamed all aliases to singular. And I changed the index.volt-loop to this:

<simplified code>

{% for gallery_category in gallery_category %}
<li>
    <a class="category-{{ gallery_category.id }}">{{ gallery_category.name }}</a>
</li> 
{% endfor  %}



{% for gallery_item in gallery_item %}
<div class="
{% for gallery_category in gallery_item.GalleryMembership %}
    category-{{ gallery_category.GalleryCategory.id }}
{% endfor  %}
">
    <h1>{{ gallery_item.title }}</h1>
    <a href="#">{{ gallery_item.subtitle }}</a>
    <a href="#"><img src="{{ gallery_item.path }}"></a>
    <a title="{{ gallery_item.description }}" href="http://placehold.it/800x800">Quick View</a>
</div> 
{% endfor %}

So each category is listed to generate a manu. Then, each row of the table "galleryitems" is listed as a separate element. Each loop of "galleryitem" contains another "gallerycategory" loop which is in relation to "galleryitem.GalleryMembership". Thus, each item-loop is assigned with its own cat-id.

Thank you! :)