Search code examples
phpactiverecordphpactiverecord

How to get an attribute value as Model instance in PHP ActiveRecord?


I am trying to achieve something that should be simple but seems impossible in PHP ActiveRecord.

In the simplified example I created, I have two models, Person and Exchange, and two tables, people(id, name) and exchange(id, user_from_id, user_to_id, comment). exchange.user_from_id and exchange.user_to_id have a foreign key constraint referencing people.id.

So when I run the following code:

$exchange = Exchange::first();
echo $exchange->user_from_id;
echo $exchange->user_from_id->name;

I would expect the first echo to fail and the second one to succeed. Instead, the first one succeeds and prints the litteral value of exchange.user_from_id and then obviously the second one generates a "Trying to get property of non-object" warning.

The result is the same with or without adding the following to Exchange:

static $belongs_to = array(
    array('user_from_id', 'class_name' => 'Person'),
    array('user_to_id', 'class_name' => 'Person')
);

What should I change in my code to make it so that $exchange->user_from_id returns an instance of the Person class?


Solution

  • It turns out I had misunderstood how BelongsTo work. I thought it somehow bound a property of a Model, corresponding to an attribute, to a different Model, but I realise now it creates a new property, which you then have to explicitely associate with an attribute using the foreign_key option.

    Concretely, this is what I had to add to the Exchange:

    static $belongs_to = array(
        array('user_from',
              'class_name' => 'Person',
              'foreign_key' => 'user_from_id'),
        array('user_to',
              'class_name' => 'Person',
              'foreign_key' => 'user_to_id')
    );
    

    Then, using this code:

    $exchange = Exchange::first();
    echo $exchange->user_from;
    echo $exchange->user_from->name;
    

    I finally got what I expected: a fatal error on the first echo and the second one printing people.name where people.id = exchange.user_from_id.

    This also made it possible to use eager loading of the two people objects with:

    $exchange = Exchange::first(array('include' => array('user_from', 'user_to')));