1
\$\begingroup\$

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?

asked Feb 8, 2013 at 4:47
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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.

answered Feb 8, 2013 at 6:49
\$\endgroup\$
1
  • \$\begingroup\$ Thanks! And yeah I think I made a mistake with my original query, having that join operation in there. \$\endgroup\$ Commented Feb 8, 2013 at 16:09

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.