Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Suppose User and Item are two models, and User has many Item. Both models are derived from the parent Model class. In order to retrieve the list of all items a particular user has:

    $user = new User(100);  // User with ID = 100
    $items = $user->getItems();

Now suppose that there are two tables in a database, users and items. In order to find all the items a particular user owns:

    SELECT * FROM users INNER JOIN items ON (users.item_id = items.id) WHERE users.id = 100

I'm trying to implement this functionality as a PHP magic method. Basically what this means is that if you call $users->getItems(), getItems() is not actually a defined method in User. Instead, it will invoke $users->__call('getItems', FUNCTION_ARGS); So basically:

    class Model { 
        ...
        function __call($method_name, $args) { /* ? */ }

How would I go about implementing this?

share|improve this question
add comment

1 Answer 1

up vote 2 down vote accepted

I have the feeling that there is something wrong with your database structure. According your query, user will have exactly one item?

If one user can have many items and the items belongs only to this user, your schema should look like:

User:
ID Name ...

Item
ID Name UserId ...

So your query will look like

SELECT * FROM Item where UserId=100

If the items are shared you need a additional table

UserItemRelation
UserID ItemID

SELECT i.* FROM Item as i, UserItemRelation as r WHERE i.ID=r.ItemID and r.UserID=100

In both cases there is no need to join the User table as you know already the user ID.


Do get this into an abstract method in your model class you have to extract every information related to your concrete class into abstracts methods. Just as a draft:

function __call($method_name, $args) 
{
     if (isRelationGetter($method_name))   
     {
         return getRelatedEntities(extractField($method_name))
     }
     ....
}


function isRelationGetter ($method_name)
{
    $field=extractField($method_name);
    return isRelationField($field)
}

abstract function isRelationField($field);
abstract function getFieldInfo($field);
abstract function getPrimaryKey();

function getRelatedEntities($field)
{
    $fieldInfo=getFieldInfo($field)
    $query="SELECT * FROM "+$fieldInfo['foreignTable]+" where $fieldInfo['foreignKeyField]="+getPrimaryKey();
    //any database abstraction here
    return fetchAll($query)
}

As you see, a lot of magic.

If you write your own ORM let me recommend to automatically generate some abstract classes between your entity classes and your model and add all the getter to this abstract class. The getter itself can then call getRelatedEntities and you get rid of all this name guessing. Of course it would be easier to use an existing ORM.

share|improve this answer
    
Thanks! And yeah I think I made a mistake with my original query, having that join operation in there. –  Ryan Feb 8 '13 at 16:09
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.