CodeIgniter Forums
DMZ 1.7.1 (DataMapper OverZealous Edition) - 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: DMZ 1.7.1 (DataMapper OverZealous Edition) (/showthread.php?tid=28550)



DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-15-2010

[eluser]someoneinomaha[/eluser]
I've read the documentation on advanced relationships and I'm struggling.

Here is my set up. I have a classifieds area on my site that allows people to submit multiple photos.

I wanted to be able for a classified to have one main image and multiple others.

I was going to do this with just a flag in the join table, but a fellow developer said it might be easier to just directly reference the main photo directly in the classifieds table.

How would I set up the relationships for classifieds and photos where classifieds can have one main photo and multiple other photos?

This is one of several iterations I've tried with the result of unable to relate error messages.

Photo Relationships:

// Insert related models that Photo can have more than one of.
var $has_many = array('classified_all' => array('class' => 'classified', 'other_field' => 'photo'),
'classified_main' => array('class' => 'classified', 'other_field' => 'mainphoto'));

Classified Relationships:

// Insert related models that Classified can have just one of.
var $has_one = array('classifiedtype', 'user', 'mainphoto' => array('class' => 'photo', 'other_field' => 'classified_main'));

// Insert related models that Classified can have more than one of.
var $has_many = array('photo' => array('class' => 'photo', 'other_field' => 'classifield_all'));


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-16-2010

[eluser]OverZealous[/eluser]
@someoneinomaha

Personally, I would use join_fields as you originally intended. This ensures that if you delete all photos, you also delete the primary. The section on join_fields in the manual covers the three basic methods that work with them.

If you want to have multiple relationships instead, then I would do it like this:
Code:
class Classified {
    $has_many => array('photo');
    $has_one => array('mainphoto' => array('class' => 'photo', 'other_field' => 'classified_main');
}

class Photo {
    $has_many => array(
        'classified',
        'classified_main' => array('class' => 'photo', 'other_field' => 'mainphoto')
    );
}

// Table classifieds_photos
id
classified_id
photo_id
classified_main_id
mainphoto_id

Then you have to save the main photo in two ways:
Code:
$classified = new Classified();
// TODO: set fields, save photos, etc.
$relations = array(
    'photo' => array($photo1, $photo2, $photo3),
    'mainphoto' => array($photo1)
);
$classified->save($relations);

Also, if you delete the mainphoto, it has to be deleted twice:
Code:
$classified->delete_mainphoto($photo1);
$classified->delete($photo1);

Some of these problems are alleviated with using the join field. The JF has it's own minor problems, as well.


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-16-2010

[eluser]someoneinomaha[/eluser]
Thanks for the reply Phil... I appreciate it.

So I think one of the areas I have set up incorrectly is I have the database structured like:

Photos:

id
label
path
etc...

classifieds_photos:
id
photo_id
classified_id

classifieds:
id
blah blah...
mainphoto_id


Would there be no way to set up the dual relationship between photos and classifieds with this db setup?

Thanks.


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-16-2010

[eluser]OverZealous[/eluser]
@someoneinomaha

That should work perfectly. If you use the relationship settings I had before, you can safely use mainphoto_id. Honestly, it's how I would configure the tables. It just slipped my mind.

Using a join field still might be better, but it's up to you which you prefer.


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-17-2010

[eluser]j0nxiest[/eluser]
Hi,

This is the first project im working on, where i am using dmz. I tried Doctrine and Rapidmapper, but they didn't quite meet my needs as well as dmz seems to. DMZ has already helped me alot when im working with quite complex relations, but what i didnt find from the user manual, is how to work with collections inside collections inside collections...

Do you always have to go with foreach loops, e.g. if i want to create invoices based on every transaction that has been made in the past 24 hours, and get the related data to this invoice, do i have go like this:

Code:
$transactions = new Transaction();
        
// Get all the transactions created in the past 24h
$transactions->where("HOUR( TIMEDIFF( NOW( ) , `transactions`.`created` )) < 24")->get();
foreach($transactions as $transaction) {

//Get all related data
$transaction->invoice->get(); //Transaction has one invoice
$transaction->invoice->invoice_line->where('gl_account_id',3000)->or_where('gl_account_id',3002)->get(); //Invoice has many invoice_lines

foreach($transaction->invoice->invoice_line as $invoice_line){
$invoice_line->gl_account->get(); //Invoice_line has an gl_account
}

$transaction->person->get(); //..
$transaction->person->some_related_info->get(); //..
$transaction->company->get(); //..
$transaction->company->billing_account->get(); //..

And if thats not all the relations, it just seems like there is a better way to do these things, i just haven't really figured it out. I have tried with the include_related, but e.g. if the invoice table has an in-table foreign key for an transaction, then i cant do this
Code:
$t = new Transaction(); $t->include_related('invoice',null,false,true); // This has all the values as null of related invoice object
$i = new Invoice(); $i->include_related('transaction', null, false, true) // This works

I guess i'm just a bit confused about the correct usage with collections of collection.

Any help or guiding is really appreciated (and i have read the user manual many times already)

Thank you!


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-19-2010

[eluser]someoneinomaha[/eluser]
I did end up deciding the join was the best way to go... but this is the SQL I think is necessary to generate the results I need.

Code:
select c.*, p.id as photo_id, p.label, p.path, p.caption, p.phototype_id from classifieds c
LEFT OUTER JOIN (classifieds_photos cp JOIN photos p ON (cp.photo_id = p.id AND cp.is_main = 1))
ON c.id = cp.classified_id

I want a list of all classifieds along with the main photo (if one exists).

There's no way to generate this via an Active Record / DMZ method, right?


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-19-2010

[eluser]OverZealous[/eluser]
@someoneinomaha
There's no way in ActiveRecord (and DMZ is based on AR) to do compound joins.

You can build the query without the compound join, however, DMZ won't let you select fields from $has_many tables. This might work, however:
Code:
$c = new Classified();
$c->select(...);
$c->select('photos.id as photo_id');
$c->select('photos.label');
// etc
$c->where_join_field('photo', 'is_main', 1);
$c->get();

If that doesn't work, you might need to forcibly include the photo table, like this (which is a really nasty hack):
Code:
$c->where_related('photo', 'id !=', 0);

That should allow classifieds with no photos to work, since id will be NULL in those cases.

This is another case where I think I can change the core of DMZ, and allow include_related even when working with a $has_many join. I'll look into it.


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-20-2010

[eluser]j0nxiest[/eluser]
After reading through my last post a few times i realized it was quite a mess. So now i'm trying to be a bit more clear with my questions.

1. When i am fetching records and have has_many relation, can i include all children for a record somehow? e.g. $parent->include_many_related('child')->get();

2. If i get all parents $parents->get(); //100 parents,
Can i get every parents children without a for loop? e.g. $parents->all->child->get();
or do i always have to go like this: foreach($parents as $parent){$parent->child->get()};
(i know i could go like $children->include_related(parent)->get() but if i have to go the other way?)

3. When i am querying for objects, can i check if in the middle of a query if the object has a related item? e.g. $parent->where_has_related('child')->get();

Thanks in advance.


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-20-2010

[eluser]OverZealous[/eluser]
@j0nxiest

1. No. But you can't really do that with straight SQL, either. However, you can sometimes turn it around, by querying on the many side of the relationship, and grouping or sorting the results.

2. Same as above. You have to loop. (It's only three lines of code!) If you want it in one query, just like above, you have to start from the many side.

3. $parent->distinct()->where_related('child', 'id IS NOT NULL')->get();

DMZ is just a wrapper on SQL. If you can't easily do it in SQL, you can't easily do it in DMZ. (Some things are always a little more difficult in DMZ, too.)


DMZ 1.7.1 (DataMapper OverZealous Edition) - El Forum - 05-20-2010

[eluser]GregX999[/eluser]
Hey all, hopefully a quick question...

I want to retrieve a collection of objects using get(), then access a specific one of them (ie: the first).

I want to do this but it doesn't work. (Assuming there are multiple "red things".)
Code:
$thing = new Thing();
$thing->where('color', 'red')->get();
echo $thing[0]->name;

Is there a way to access specific objects in the collection? Specifically, the first one. I can do a "foreach" on $thing, but I can't do $thing[0].

Greg