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

Phalcon 3.0 Model Relationships

Just in case full source to stackoverflow question: https://stackoverflow.com/questions/40817270/phalcon-3-0-model-relationships

I'm building a tiny project using Phalcon 3.0.1 just to learn how to use ORM model relationships between two tables and just on the start encountered first problem with joining data from related tables. Here's my SQL code for those tables:

  CREATE TABLE `jobs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(100) NOT NULL,
  `categories_id` int(11) unsigned NOT NULL,
  `location` varchar(255) NOT NULL,
  `description` text NOT NULL,
  `how_to_apply` text NOT NULL,
  `author` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  KEY `fk_categories` (`categories_id`),
  CONSTRAINT `jobs_ibfk_1` FOREIGN KEY (`categories_id`) REFERENCES `categories` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='utf8_general_ci'
CREATE TABLE `categories` (
      `id` int(11) unsigned NOT NULL,
      `category_name` varchar(100) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='utf8_general_ci'

Jobs has a foreign key for categories (categories_id). Now, trying to init relationship in my categories model like:

public function initialize()
    {
        $this->hasMany('id', 'Jobs', 'categories_id', ['alias' => 'Jobs']);
    }

Also I've tried put full namespace (App\Core\Models\Jobs) for hasMany and still is the same.

Now when calling find method Categories::find() is not returning related data from Jobs table. I've also notice that I can put anything stupid inside hasMany() method and it even won't catch exception. It looks like it is completely ignored. I can even do something like below and it won't crash.

public function initialize()
    {
        $this->hasMany('stupid', 'Doesnt_exist_table', 'more_stupid', ['alias' => 'Jobs']);
    }

I would like to also outline that all properties in my models are public. I've gone trough all the docs, other stackoverflow questions, github examples and I believe that should work. Any help will be appreciated as I'm going mad about it.

HasMany means resultset. Categories should have. It means you want to select all records assosciated with certain record. So in this case you want to select from categories all jobs. So:

Jobs model:

public function intialize()
{
    $this->belongsTo('categories_id', 'App\Core\Models\Categories', 'id', ['alias' => 'categories']);
}

And cateogires model:

public function initialize()
{
    $this->hasMany('id', 'App\Core\Models\Jobs', 'categories_id', ['alias' => 'jobs']);
}


2.1k

@Wojciech,

I've tried it already and is still the same. I've added hasMany and belongsTo to models as above, but when doing:

$result = Categories::find(); var_dump($result->toArray());

I'm getting this:

array(5) { [0]=> array(2) { ["id"]=> string(1) "1" ["category_name"]=> string(11) "Hospitality" } [1]=> array(2) { ["id"]=> string(1) "2" ["category_name"]=> string(11) "Programming" } [2]=> array(2) { ["id"]=> string(1) "3" ["category_name"]=> string(6) "Design" } [3]=> array(2) { ["id"]=> string(1) "4" ["category_name"]=> string(12) "Construction" } [4]=> array(2) { ["id"]=> string(1) "5" ["category_name"]=> string(5) "Other" } } 1

Jobs table has 8 rows where categories_id = 1.

edited Nov '16

Because ::find method doesn't return relationships obviously. Check docs. You need to use query builder and join.

first example "Jobs" does not match a namespace or a model etc

edited Nov '16

Phalcon does not fetch related records, it does only by demand. And you must call it for each result from $result. You can use eagerLoading for it: https://github.com/stibiumz/phalcon.eager-loading

by the wayt, would be great if Eager Loading is added to Phalcon (already on incubator). There is a real need of it to avoid multiple db calls, or defining PHSQL queries across the code for this repeated task.



2.1k

Thank You for all Your responses. I just realized as per @Erik and @Wojciech comment that I need to iterate over resultset and call related method. I believe that my issue is sorted now. Thank You guys!

THIS IS VERY BAD SOLUTION. You should use query builder and join table.

edited Nov '16

Wich one, the eager loading? And using caps. Like no arguments but caps could make a sentence more true. I don't try to be rude, but its always the same on the phalcon forums when the orm is in doubt. Query builder and join table are a pain... They are good on low level, of course, but there is always a need of bigger abstraction. You are forced to write database queries instead of domain logic, you are forced to rewrite the same boring lines multiple times, you are forced to create a service-repository class to insert them if you want to abstract better... you are forced to manually change queries when you make changes to your data....etc, etc, etc

Instead, the eager loading, not only solved the N+1 problem (endemic on the phalcon ORM with the default lazy loading) but it encapsulates well on the ORM (still an active record and not a data mapper, anyway), make it easier to avoid code repetition and multiple points of failure, since the tedious task is created on a higher level.

But I already discussed this on many places at the forum no need to repeat myself again.

Edit: rage off :p I think that Wojciech was talking about the iteration. That is a bad idea because you will end with multiple database calls, easily avoided with the join proposed by Wojciech.

THIS IS VERY BAD SOLUTION. You should use query builder and join table.

Yes i was talking about the iteration. Eager loading is just discusionable, indeed, it's nice feature. Good to have one, but it isn't necessary - some people don't need it at all, query builder is enough for them, and making extension size bigger is not so great idea i think.