We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Relationships in models

Hello, I'm trying to get the advantages of the relationships in Phalcon models. I have two tables which is post and like.

each post has many likes while one like belongs to one post.

here is my models.

Like.php

<?php

namespace FC\Models;

use Phalcon\Mvc\Model\Validator\Email as EmailValidator;
use Phalcon\Mvc\Model\Validator\Uniqueness as UniquenessValidator;
use Phalcon\Mvc\Model;

class Like extends Model
{
    public $id;

    public $postID;

    public $userID;

    public function initialize()
    {
        $this->belongsTo("post_id", "post", "id");
    }
}

Post.php

<?php

namespace FC\Models;

use Phalcon\Mvc\Model\Validator\Email as EmailValidator;
use Phalcon\Mvc\Model\Validator\Uniqueness as UniquenessValidator;
use Phalcon\Mvc\Model;

class Post extends Model
{   
    public $id;

    public $content;

    public $created_at;

    public $likes;

    public $userID;

    public function initialize()
    {
        $this->hasMany("id", "Like", "post_id");
    }
}

UserController.php

<?php

namespace FC\Controllers;

use Phalcon\Mvc\Controller,
    FC\Controllers\ErrorController as Error,
    FC\Models\User,
    FC\Models\Post,
    FC\Models\User_follow,
    FC\Models\Like,
    FC\Models\User_info;

class UserController extends ControllerBase
{
    public function usernameAction($username)
    {
       $user_posts = Post::findFirst();
        foreach($user_posts->likes as $like)
        {
            var_dump($like);
        }
    }
}

It shows me this error: Warning: Invalid argument supplied for foreach().

Please correct me :) thanks.



51.1k

Your structure look fine.

  1. Do you have any records ? If yes, switch to point 2 if no, insert some data first.
  2. Try this:
class Post extends Model 
{
    public function initialize()
    {
        $this->hasMany("id", "Like", "post_id", ['alias' => 'likes']);
    }

    // You can also have a getter if you need to execute some logic or complex code:

    public function getLikes($params = null)
    {
        return $this->getRelated('likes', $params);
    }
}

Yes there is some records for both tables. I have updated my post model as in your reply.

now, it shows me empty page.

<?php

$this->view->disable();
$user_posts = Post::findFirst();

foreach($user_posts->getLikes() as $like)
{
    var_dump($like);
}

$user_posts = Post::findFirst(); shows me one record. but $user_posts->getLikes() is empty

edited May '15

Yes there is some records for both tables. I have updated my post model as in your reply.

now, it shows me empty page.

<?php

$this->view->disable();
$user_posts = Post::findFirst();

foreach($user_posts->getLikes() as $like)
{
  var_dump($like);
}

$user_posts = Post::findFirst(); shows me one record. but $user_posts->getLikes() is empty

This is because dumping big objects with a lot of references inside uses a lot of memory, try var_dump($like->toArray()) or use XDebug, Symfony VarDumper etc

edited May '15

Same result. here is my database:

Like table:

CREATE TABLE IF NOT EXISTS `like` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `postID` int(11) NOT NULL,
  `userID` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `postID` (`postID`),
  KEY `userID` (`userID`),
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

--
-- Dumping data for table `like`
--

INSERT INTO `like` (`id`, `postID`, `userID`) VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 2),
(4, 4, 3);

Post table

CREATE TABLE IF NOT EXISTS `post` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `content` text NOT NULL,
  `created_at` datetime NOT NULL,
  `userID` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `userID` (`userID`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

--
-- Dumping data for table `post`
--

INSERT INTO `post` (`id`, `content`, `created_at`, `userID`) VALUES
(1, 'Hello World!', '2015-05-11 07:39:51', 1),
(2, 'Hi', '2015-05-11 07:43:32', 2),
(3, 'a new post\r\n', '2015-05-20 12:00:37', 1),
(4, 'Test', '2015-05-20 13:08:18', 3),
(5, 'ANother post', '2015-05-20 14:42:35', 1);

Constrains:

ALTER TABLE `like`
  ADD CONSTRAINT `like_ibfk_1` FOREIGN KEY (`postID`) REFERENCES `post` (`id`),
  ADD CONSTRAINT `like_ibfk_2` FOREIGN KEY (`userID`) REFERENCES `user` (`id`);

ALTER TABLE `post`
ADD CONSTRAINT `post_ibfk_1` FOREIGN KEY (`userID`) REFERENCES `user` (`id`);

I might missed something in my database



51.1k

it seems ok. Strange.

try:

$this->hasMany("id", "Like", "post_id", [
    'alias' => 'likes',
    'foreignKey' => true
]);

Then

class UserController extends ControllerBase
{
    public function usernameAction($username)
    {
       $user_posts = Post::findFirst();
       var_dump($user_posts->count());
        foreach($user_posts->likes as $like)
        {
            var_dump( $like->id );
        }
    }
}
edited May '15

here is the result:

string '5' (length=1) // the count result.

Warning: Invalid argument supplied for foreach() 

post.php


<?php

class Post extends Model
{   
    public $id;

    public $content;

    public $created_at;

    public $likes;

    public $userID;

    public function initialize()
    {
        $this->hasMany("id", "Like", "post_id", [
            'alias' => 'likes',
            'foreignKey' => true
        ]);
    }
}

it seems the relationship not working. when I use getLikes() instead of likes it show empty result



51.1k

Hm. If you declare the full namespace ?

    public function initialize()
    {
        $this->hasMany("id", "FC\Models\Like", "post_id", [
            'alias' => 'likes',
            'foreignKey' => true
        ]);
    }

I'm sorry to say it's same result :)



51.1k

Your field name is postID not post_id .

    public function initialize()
    {
        $this->hasMany("id", "FC\Models\Like", "postID", [
            'alias' => 'likes',
            'foreignKey' => true
        ]);
    }

Yes actually I changed that before I post in the fourm, and now I changed to postID but give me same result. I'm using Phalcon 2.0 and hope this is not bug in this version

I set a relationships between user and post models and it works fine. I will try to figure out the problem between post and like :)

I will update this post once I solved :)

Update:

if I use this code it shows me Fatal error: Call to undefined method Phalcon\Mvc\Model\Resultset\Simple::getLikes()


<?php
$post_likes = Post::find(['userID = 1']);
$likes = $post_likes->getLikes();

var_dump($likes->toArray()); return;

but if I changed to the following it works:


<?php
$post_likes = Post::findFirst();
$likes = $post_likes->getLikes();

var_dump($likes->toArray()); return;

What is the reason?



51.1k

Post::find() is returning an instance of Phalcon\Mvc\Model\Resultset\Simple . That is an array of objects (Post object). You need to loop:

<?php
$posts= Post::find(['userID = 1']);

foreach ($posts as $post) {
    foreach ($post->getLikes() as $like) {
        var_dump($like->toArray());
    }
}

Or you can filter:

$posts_likes = Post::find(['userID = 1'])->filter(function($post){
    $likes = [];
    foreach ($post->getLikes() as $like) {
        $likes[] = $like->toArray();
    }

    return $likes;
});

var_dump($post_likes);

Thanks Calin Rada it works now. wish you all the best.