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 ORM getter

I have model:

class Product extends \Phalcon\Mvc\Model{
    /** 
    (...)
    */

    public function initialize(){
     $this->belongsTo('tax_id', 'Tax', 'tax_id', array(
            'foreignKey' => true,
            'alias' => 'tax'
        ));
    }
}

class Tax extends \Phalcon\Mvc\Model{
    /** 
    (...)
    */
}

now when i do:

    $prod = new Product();
    $prod->tax = new Tax();
    $this->assertInstanceOf('Tax', $prod->tax); // this passes

     $prod->setTax(new Tax());
     $this->assertInstanceOf('Tax', $prod->getTax()); // this fails

note that i'm not saving any entities.

What i expect is that both $prod->tax and $prod->getTax() to return same object instance:

$prod = new Product();
$prod->tax = new Tax();

spl_object_hash($prod->tax) == spl_object_hash($prod->getTax())

There should be no diference between using direct property access and setter.

Phalcon v1.3.5



5.7k
edited Jul '15

When you call $obj->getRelatedObject(), it will return a Simple Resultset Object Phalcon\Mvc\Model\Resultset\Simple

Within that resultset, you will see there is this: ["_model":protected]=> object(Tax)

So when you do this:

$prod = new Product();
    $prod->tax = new Tax();
    $this->assertInstanceOf('Tax', $prod->tax); // this passes

you are telling Phalcon to first check to see if there is a property "tax" within the Product Object. If not, look for a related object called Tax. When a property or related Object was found, set the value of it so that on save, the magic happens and everything is linked together in a nice transaction.

When you are checking this part:

    $prod->setTax(new Tax());
    $this->assertInstanceOf('Tax', $prod->getTax()); // this fails

there are two things happening here:

The first line $prod->setTax(new Tax()); is telling the product object to look for a setTax() function within the Product Object. Chances are, this does not exist and will throw an error (as my test case just did on my local machine).

On the second line $this->assertInstanceOf("Tax", $prod->getTax());, you are telling the database to find the related [Tax] record(s) that belong to the Product that is issuing the call. This operation results in a query to the database to get what you're looking for.

You are trying to use the Framework outside of how it was intended to be used.

This is based off my experience and understand after working with phalcon for the last year. @andresgutierrez If I'm wrong, please let me know!



616

Ok, i assumed that if there is magic getter , then tere will be magic setter - my bad. But still

 $prod->tax = new Tax();
 $this->assertInstanceOf('Domain\Entities\Tax', $prod->getTax()); // this fails and shouldn't!

fails... but this will pass...

 $prod->tax = new Tax();
 $prod->save();
 $this->assertInstanceOf('Domain\Entities\Tax', $prod->getTax()); // this fails and shouldn't!

You don't have to save this object to know it's there! I's simply

public function getTax(){
    if($this->tax instanceof Tax)
        return $this->tax;
    reuturn $this->getRelated('tax');
}

What i'm expecting from ORM is transparent, fluent flow. You should know nothing about DB implementation, and your entities should not depend on MYSQL. Were Phalcon ORM won't work without mysql ( event there are no read/writes on db - we simpy set variable and then want it back ...). Things get more complicated and fucked up when you are trying to use 1 to m and m to m relationships...

Great example of good, transparent ORM is doctrine 2, and Phalcon ORM should take this path...



616

TL;DR: Phalcon ORM magic getters shouldn't be just aliases to "select from related where related_id = id" ...