WanWizard / Datamapper

Maintenance of Datamapper has been transferred to https://github.com/saekort/datamapper in 2012.
27 stars 3 forks source link

collections as relationship (linking to multiple tables) #8

Open WanWizard opened 12 years ago

WanWizard commented 12 years ago

Requested by @jove4015, see http://codeigniter.com/forums/viewreply/951568/:

One feature I’d love to see is the ability to use multiple columns for a foreign key in a relationship.

The idea would be for example, you have an ID column, and a class name column, and you use both together to make a relationship to multiple different models.

Here’s a use case:

You have a group, and a group has members. You have two columns: member_id, and member_class. The member class could be a User object, or another Group object (so it would read out “user”, or “group”), but you can access all of them through the members method. It’s good if you have multiple classes that have similar properties (perhaps implementing the same interface) and can all belong to the same object of another class, but might have some other divergent attributes or methods as well (therefore creating the need for subclasses and separate tables).

Another example is a folder object, which can contain image objects and document objects and video objects, etc, but from the perspective of the folder, they are all just files, and you want to treat them in a uniform way.

WanWizard commented 12 years ago

I’d still like to understand how you see this working though. Normally, the keys that are needed to link two tables (either directly or through a join table) are part of (one of the) table(s). So you will never be able to select a “subset” of the related records.

What you need in that case are conditions or filters, which basically insert a “WHERE foreign_key_2 = ‘condition’” into queries, technically placing a hardcoded filter on the result. And then be able to define multiple relations between two tables, for example one with the condition “FK == ‘user’”, and one with “FK == ‘group’”.

Do I understand your situation correctly?

WanWizard commented 12 years ago

Response by @jove4015:

Well see, in my case the id is not unique. I’m not trying to filter anything - in fact, I’m trying to pull objects from multiple tables at once, so almost the opposite of a filter. But I don’t want my code to have to know what all the models are going to be in advance - so I want to be able to do a call like this:

$folder = new Folder();
$folder->where("id", 123)->get();
$folder->items->get(); 

and then have that $folder->items array contain all the items in that folder, regardless of what class they come from. The obj_class part of the key would tell datamapper which model to instantiate each object with, while the ID indicates what actual instance it is… ideally it would group all the items from each class together and pull those each with separate queries, instantiate them, and recombine into an array. We do all this manually now… I have a few different use cases for it where I wind up writing the same code over again. It’s a neat kind of association that allows you to write more extensible code, since you can have your objects expect an interface and let developers create any amount of other objects to interact with them, without having to know in advance what all they’re going to be.

I don’t know, maybe I’m the only one doing this grin I just know it’s the one thing I always wish I could find in another ORM.

WanWizard commented 12 years ago

As you describe it now, I don’t see that as possible.

$folder->items->get()

should always return a collection of ‘items’ objects, not of different models. That will create a mess when you start iterating over the result of such a query. It would also defeat the purpose of having a uniform interface to your application.

It could be implemented as a separate method, for example

$folder->collection('items')->get;

which would perform the trick you describe, and returns an array of assorted objects, depending on the model they were collected from. A collection could be defined in a new relationship type ‘collections’.

In that case, it could easily be implemented as an extension, so it doesn’t sit in the way of users that don’t need this.

I think that with this approach all other methods (like where_related() for example) would still work.