CodeIgniter Forums
DataMapper ORM v1.8.0 - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forumdisplay.php?fid=22)
+--- Thread: DataMapper ORM v1.8.0 (/showthread.php?tid=37531)



DataMapper ORM v1.8.0 - El Forum - 04-13-2011

[eluser]WanWizard[/eluser]
I don't have an example I can share. Maybe someone else?

The user guide contains a general explanation of how nested sets are used to represent a tree structure in a flat structure like a database table. All methods are explained and come with an example of how to use them.

Is there anything specific you would like to know?


DataMapper ORM v1.8.0 - El Forum - 04-13-2011

[eluser]Syahzul[/eluser]
i would like to use it to create nested categories for my apps, but a bit lost even after reading the guide. i'm not an experienced programmer, if there's any sample code i can refer, that would be very helpful. i've check all cms made by CI (pyro, excite, bonfire), if i'm not mistaken, none of them is using nestedsets.


DataMapper ORM v1.8.0 - El Forum - 04-13-2011

[eluser]WanWizard[/eluser]
Difficult to explain, if you don't understand the concept of nested sets.

People have written books about this subject...


DataMapper ORM v1.8.0 - El Forum - 04-14-2011

[eluser]NeilyM[/eluser]
Here's one I've been playing with this week but nothing I try seems to work. It's a huge project I'm working on and sometimes I think I simply can't see the wood for the trees.

What follows is an example of what I'm trying to achieve, not the actual code.

Student has_many Subject
Subject has_many Student

What I need to do is to select all students who are studying both Physics and Chemistry (ie AND not OR).

Like this I guess...

$student = new Student;
$student->save();

$subject1 = new Subject;
$subject1->name = 'physics';
$subject1->save($student);

$subject2 = new Subject;
$subject2->name = 'chemistry';
$subject2->save($student);

...so $student now has 2 related subjects.

And to select all students who are studying both of those subjects:

$student->where_related('subject', 'name', 'physics');
$student->where_related('subject', 'name', 'chemistry);
$student->get();

...doesn't get me anywhere. I know it's wrong but can't seem to move forward with it.

Any assistance gratefully received.

I also want to say great job on DataMapper ORM - it really does help to make complex projects vastly easier and quicker to develop.

Thanks again.

Neil


DataMapper ORM v1.8.0 - El Forum - 04-14-2011

[eluser]WanWizard[/eluser]
How would you code this if you were writing plain SQL?

You would need a GROUP_BY() and a HAVING(), because you need to group multiple rows, and filter the result based on the count of rows in a group. In this case group by subjects.name, and the count should be 2.

Which translates to:
Code:
$student->
    select('students.*')->
    select('COUNT(*) AS count')->
    where_in_related_subject('name', array('physics', 'chemistry'))->
    group_by('id')->
    having('count', 2)->
    get();
Which means include the student record in the result if the student id occurs two times (meaning they follow both subjects).


DataMapper ORM v1.8.0 - El Forum - 04-15-2011

[eluser]NeilyM[/eluser]
Thanks so much WanWizard - I will give it a try.


DataMapper ORM v1.8.0 - El Forum - 04-19-2011

[eluser]rherriman[/eluser]
I'm having some difficulty deciphering the Advanced Relationships documentation. It might be that what I'm trying to do is not possible, so I guess I'll just ask.

My situation is that I have a Product model, and I want it to have a many-to-many relationship with itself for "Related Products." I also don't want to have to worry about upstream versus downstream. I want $product->related->get() to return every product with which the current record is related, regardless of which foreign key field in the join table contains the record's id.

I ALSO don't want to have to save/delete the relationship between two products twice. From what I gather, the 'reciprocal' property does exactly that, albeit automatically. But if a relationship is reciprocal, why would you need or want to? It's an extra record for no compelling reason (that I can see). And when you have a large catalog of products, well, doubling the footprint of product relationships is increasingly unattractive.

Is what I want to do possible? If not, why not?

Thank you!


DataMapper ORM v1.8.0 - El Forum - 04-19-2011

[eluser]WanWizard[/eluser]
Let's start at the back.

If you have a many-to-many relationship, you always need a relationship table. You simply can not create it with only in-table foreign keys.

Reciprocal relations are relations that always exist between two object. For example, in the relationship between a parent and a child, if the child is a child of a specific parent, that parent is always the parent of that child. If you define a relation to be reciprocal, it simply means that if you create one of the relations, the other is created automatically.

You could debate if that is handy if you only ever want to query downstream and not upstream, but if that's the case, don't define the relationship as reciprocal.

However, apart from this particular case, relationships are always one-way. So if "Product B" is a child of "Product A", asking for related objects on A gives you B. Asking for related objects on B does NOT give you A, since that relation does NOT exist. You can query the other relation ( $related->product->get() ), in which case if $related contains B, this will get you A.

You should define your relation like so
Code:
class Product extends DataMapper {
    $has_many = array(
        'related' => array(
            'class' => 'product',
            'other_field' => 'product'
        ),
        'product' => array(
            'other_field' => 'related'
        )
    );
}

This would require a table called 'products_products', containing the fields 'id', 'product_id' and 'related_id'.

disclaimer: I write this from the top of my head, I don't have a test environment handy at the moment


DataMapper ORM v1.8.0 - El Forum - 04-19-2011

[eluser]rherriman[/eluser]
I understand that for the most part, but why must relations be parent-child? I just want to tie two products together, not worry about what "belongs" to what! Is there no "sibling" relationship possible?


DataMapper ORM v1.8.0 - El Forum - 04-19-2011

[eluser]WanWizard[/eluser]
Doesn't matter what you call it.

You have an Object A (with an id as primary key) that needs to be linked to Object B (also with an id as primary key). If you have a many-to-many, you say that A can be linked to multiple other objects, and each of the objects can also be linked to multiple objects. So you need a relationship table (also called junction table, http://en.wikipedia.org/wiki/Junction_table). This is normal database design. If you don't get this, I suggest you study this subject first.

So you have a relationship table record that says contains the id's of both A and B. Since your column names have to be unique, the column for A's id is called different from the column for B's id. In your case product_id and related_id. This also means that a relationship is always one way, but that shouldn't stop you for constructing a query in the other direction.

In plain SQL
Code:
// get all products related to product id 10, product -> related product
SELECT products.* FROM products_projects LEFT JOIN products on products.id = products_products.related_id WHERE products_products.product_id = 10

// DM equivalent
$product = new Product(10);
$product->related->get();
makes it very clear it's not bidirectional.

The other way around it would be
Code:
// get all products related to product id 10, related product -> product
SELECT products.* FROM products_projects LEFT JOIN products on products.id = products_products.product_id WHERE products_products.related_id = 10

// DM equivalent
$related = new Product(10);
$related->product->get();