j4mie / paris

A lightweight Active Record implementation for PHP5, built on top of Idiorm.
http://j4mie.github.com/idiormandparis/
996 stars 131 forks source link

Hacking associations #5

Closed jrivero closed 13 years ago

jrivero commented 13 years ago

Hi! i need help...

I modified paris __get magic method with this:

    public function __get($property) {
        if (method_exists($this, $property)) {
            return call_user_func(array($this, $property));
        }
        return $this->orm->get($property);
    }

and the example of profile belong_to to this:

class Profile extends Model {
    public function user() {
        return $this->belongs_to('User')->find_one();
    }
}

This is good for this call $user = $profile->user; echo $user->name; But have problems with this another echo $profile->user->name

Have any idea what could be the problem? syntax looks cool!

Regards, Jordi

jrivero commented 13 years ago

hehehe.... i see my fatal error. This is the corrected code:

public function __get($property) {
    if (method_exists($this, $property)) {
        $this->$property = call_user_func(array($this, $property));
    }
    return $this->orm->get($property);
}
jrivero commented 13 years ago

wow! and added this function to my user class:

public function __toString() {
    return $this->name;
}

and have this $profile->user, very cool, sexy and pythonic ;)

jrivero commented 13 years ago

optimized version of __get for not repeat queries:

    public function __get($property) {
        if (!$value = $this->orm->get($property) and method_exists($this, $property)) {
            return $this->$property = call_user_func(array($this, $property));
        }
        return $value;
    }
j4mie commented 13 years ago

Nice idea - but I'm leaving towards not adding this to Paris.

In Django, you define your model classes and all their properties in Python code. If I'm reading some Django code and I see a call to car.manufacturer, for example, I can go and look in my models.py file at the Car class and immediately see that it has a ForeignKey property called manufacturer.

Paris doesn't know anything about your database tables, so I wouldn't know at a glance if call to $car->manufacturer (using your __get extension) is simply looking up the value of a column (the manufacturer's name might be stored as a string, for example) or whether it's performing a complex database query.

That's one of the reasons I went down the route of implementing associations through method calls - to make it absolutely clear that the call to $car->manufacturer() is actually doing something (running another query) rather than just accessing a property of your object.

The Zen of Python says "Explicit is better than implicit," so I actually think it's more Pythonic without the __get magic.

What do you think? Feel free to disagree!

jrivero commented 13 years ago

Hi j4mie,

With the change is exactly the same of django. If you read the code and see a call to $car->manufacturer, for example, i can go and look in the model Car.php file and immediately see that it has a function property called manufacturer which generates a call to the corresponding model Manufacturer.php file and return find_one or find_many dependent on the relationship.

Elsewere, I use Haanga template engine one of clone django templates and put in my templates {{ car.manufacturer.name }} and haanga compiles $car->manufacturer->name. Twig is another clone of django template and does the same. Not... $car->manufacturer()->name

This is my opinion. I know very well django.

For some time I am using your idiorm and I like a lot, now I love paris. For now, I think is the best orm of the many I've tried. Thank you very much.

j4mie commented 13 years ago

Agreed. I do think it's a nice idea, but it's conceptually a bit different to accessing properties on a Django model instance, and it's a little bit too "magic" for my tastes. Feel free to add it to your own fork or subclass of Paris.

Thanks again for the comments - really glad you like Idiorm and Paris.