Querying the multiple fields in controller
Created 6 years ago by emergingdzns

I'm probably just missing something but I'm having trouble figuring out how to query the multiple relationship fields I have in my module. Here's hypothetical example. I have a stream called "kids". In the stream I have a multiple relationship field type called "contacts". Each kid in the kids stream can have multiple contacts. So far, so good. Now, for the sake of the example I have a "contacts" stream. Each stream has a single relationship to the users module. The reason being is that the user can log in to manage their contact information.

What I need to be able to do is have the contact open a page that runs a method in the controller, we'll call it "myKids". In that controller method, I fetch the contact record for the authenticated user. Then I do something like this in the controller:

public function myKids(KidRepositoryInterface $kids, ContactRepositoryInterface $contacts)
{
    $user = Auth::user();
    $contact = $contacts->findByUserId($user->id); // this is working and giving me back a contact object from the repository.

    $my_children = $kids->findByContactId($contact->id);
    dd($my_children):
}

I'm having trouble connecting the dots in the KidRepositoryInterface (really the KidRepository.php file) in figuring out how to write the query that will give me all kids that have the authenticated user in their record. Here's my KidRepository function:

public function findByContactId($contactId)
{
    return $this->model->where('contacts',$contactId)->get();
}

Obviously this isn't working but for some reason I'm brain-farting on the solution. In raw laravel I'd just create a model for that kids_contacts table and it'd be an easy query. But it's different with Pyro so I'm just not grasping it. Any help would be appreciated.

emergingdzns  —  6 years ago Best Answer

Figured out the better solution. I used the main KidModel and added some static functions there. Duh.

emergingdzns  —  6 years ago

I think I may have just answered my own question...

return $this->model->contacts()->where('related_id',$contactId)->get();

Sometimes it helps to just write it out...

emergingdzns  —  6 years ago

Nevermind. That solution just gives me a Contacts Collection. I need the Kids collection where the contact is the $contactId. Any thoughts?

emergingdzns  —  6 years ago Best Answer

Figured out the better solution. I used the main KidModel and added some static functions there. Duh.

ryanthompson  —  6 years ago

For each relationship you can have reverse relationships defined accordingly that will give you that $contact->kids flow (if the natural relationship is $kid->contactfor example). Just a matter of looking that up and querying. I would try not to dofindByFooId($id)methods if you can help it and define the relationship and a getter for the relationship (likefoo()andgetFoo()` for example). When at all possible having the relationship clearly defined is best. Rather than relying on whereId stuff.

Hope this helps! Glad you worked it out 😊

emergingdzns  —  6 years ago

Thanks Ryan. I created a getMyKids function like this using old Laravel methods:

    public static function getMyKids($id) {
        return self::with($model)->whereHas($model, function($query) use ($id) {
             $query->where('entry_id', $id);
        })->get();
    }

I'll try your solution. I didn't realize we could do reverse relationships like that.

emergingdzns  —  6 years ago

@ryanthompson I finally got a chance to try your solution (tried both $contact->kids and $contact->kids()). Without the quotes I get nothing at all, and with the () I'm getting an error that tells me that the reverse isn't working.

[2017-05-08 02:52:36] local.ERROR: BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::kids() in /path/to/my/site/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2450

In my example though I'm using a multiple relationship so the flow would be $kid->contacts (not $kid->contact) so I'm thinking maybe because it's multiple it doesn't work the same?

ryanthompson  —  6 years ago

You have to defined the reverse relations yourself: https://laravel.com/docs/5.3/eloquent-relationships

Only the assigned relations are automatically compiled on the model. Reverse is manual. Checkout the TypeModel in pages/posts for example. Pages have type_id so the relation on TypeModel must be an inverse / reverse of the former.

emergingdzns  —  6 years ago

Ooooh ok. Sorry. I thought you were saying it was auto. I'll mess with it. Thanks.

emergingdzns  —  6 years ago

Hmmm. The pages/posts modules have a type_id and entry_id field in the posts/pages model themselves, but that won't work for me because each kid can have multiple contacts. So there's no contact_id field.