Query builder on hasMany relation - laravel

Problem
I'm creating an API with Laravel. Every server can have more than one contact, and every contact belongs to one server - as such, contacts are set up with a belongsTo relationship, and servers have a hasMany relationship to the contacts.
A user can have many servers via its hasMany relationship. Thus, when creating a server, we simply invoke $user->server()->create([values]), which works just fine.
The issue is that when we try to invoke it further, as with contacts - we hit a wall where we get:
Call to undefined method Illuminate\Database\Query\Builder::contacts()
When using: $user->server()->contacts()->create([]).
The method does exist in the server model.
We also have a hasManyThrough relationship on the user model, specifying that a user has many contacts through servers.
When calling $user->contact()->create([]), we instead get:
Call to undefined method Illuminate\Database\Query\Builder::create()
Does anyone have a clue what might be causing this? Do query builders not allow for this type of chaining, or am I missing something blatantly obvious? As you can see, I've tried a few different methods but can't seem to produce a working result.
Cheers!

As you said:
A user can have many servers via its hasMany relationship.
so You cannot build another relation on relation that can return many results (becasue at the end we don't know exacly which server id we should set in contact new record).
So what you can do is to itterate over:
foreach ($user->server as $server) {
$server->contacts()->create($values);
}
You see: now you have specific server with id to put into new contact record.

Related

Laravel many-to-many

I've Googled for a while and found multiple threads discussing problems like this, but I just can't get my head around how to do exactly what I want to do, hope someone can point me in the correct direction.
I'm making a learning platform in Laravel. What I want right now is that when lesson A is completed by someone belonging to workplace B a notification should be sent to user C. So I have made a table notification_receivers containing lesson_id, workplace_id, and user_id, pointing to the respective tables.
Of course, I also have the corresponding models (User, Lesson, Workplace) set up, but what I can't understand is exactly how to set up the model relations. I'm currently making the Blade template used for editing the notification receivers belonging to a particular lesson, and I need to make the following: Get all notification receiver users for this lesson and then for every one of those users, get the related workplaces.
My first try was this in the Lesson model:
public function notification_receivers(): BelongsToMany
{
return $this->belongsToMany('App\User', 'notification_receivers')->withPivot(["workplace_id"]);
}
Which of course doesn't work straight off, since some users will be returned multiple times (once for each workplace). How do I do to get every user just once?
And when I have my users, how do I get the workplaces for each user? If I get it to work, the withPivot above will give me the IDs, but how do I get a collection of the Workplaces?

laravel parent child relationship with three tables

i am new to Laravel i need help in building a relation with models, i have coach model which has many clients and client belong to Coach and i can perform operation on clients like this Auth()->user()->clients()->create($request->all()); now i want to add courses in way that i could use something like Auth()->user()->clients()->courses()->create($request->all()); how should i make a relation for this. what will be the best approach.
Actually you can't do ->clients()->courses() because the ->clients() will returns you a lot clients of user so ->courses() doesnt know the course of which client do you want to get.
You can create a relationship between the Couch and Course(add couche_id to courses table) model so then you can do
Auth()->user()->courses()->create($request->all());

How to check if one record is attached to another?

I have defined a many-to-many relationship between Student and Seminar models. How can I find out if one particular student is attending one particular seminar? Non-working example of what I want to achieve is illustrated below:
$seminar->students()->contains($student->id);
The following error is shown when using the above code snippet:
BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::contain()'
Try instead:
$seminar->students->contains($student->id);
Presuming $student contains an instance of the Student model you can simplify it further and just use:
$seminar->students->contains($student);
When you add parentheses you're using the Laravel query builder, and you never completed the query. To do it in the manner you had originally you would need:
$seminar->students()->get()->contains($student->id);
This method could be useful if you wanted to add constraints when fetching your students.
But generally you can omit the parentheses and a Collection will be returned, allowing you to use methods like contains.
This has the additional benefit of not re-querying the database once the relationship is loaded, so will generally be a far more efficient means of fetching relationships.
If you haven't already loaded the students and want a database efficient method of checking you could instead use:
$seminar->students()->where('students.id', $student->id)->exists();
In your case the exception is you are calling 'contains()' function (which is for Laravel Collection) on 'Query Builder'. It should be
$seminar->students->get()->contains($student->id);
but this is inefficient since this will retrieve all the students of the seminar.
so instead,
$seminar->students()->wherePivot('student_id', $student->id)->exists();
this method will check in the intermediate table of many to many relationship for particular seminar-student pair, and will return whether exists or not.
The accepted answer is wrong. $seminar->students()->exists($student->id) does not check if the relationship exists. It only checks if the student exists. The student could belong to any seminar and it would still return true.
The correct way to check if a relationship exists without fetching records from the database would be:
$seminar->students()->whereId($student->id)->exists()
Check using query
$seminar->students()->whereKey($student->getKey())->exists();
Check after query (angry), can have memory problems if you have multiple attachments
$seminar->students->contains($student->getKey());
// or
$seminar->students()->get()->contains($student->getKey());

Three way relationship in Laravel

having a brain failure with a relationship between three objects, hoping someone can help me out.
I have four models: Team, User, ProjectType and Project
Team has many User, has many ProjectType
User belongs to many Team, has many ProjectType
ProjectType belongs to manyUser, belongs to many Team, has many Project
Project belongs to ProjectType
As a single user can belong to many teams, I want to request the ProjectTypes that a User has access to, but only within the Team they are currently logged in with. It may be the case that a User has access to project types across multiple teams, but will only be logged in to one team at any time, so I need just that subset.
I'm hoping this structure makes sense, but I'm struggling to get access to the data I want easily
So I'd like to do $user->projectTypes and get all project types for that user, but only the subset of the team they're currently logged in with.
Equally, once I've got that, I want to be able to get $user->projectTypes->projects within that set.
I'd like to do this whilst maintaining all of the nice relationship methods I get with Laravel, but am struggling to setup the data structure to support this, and get the data in turn.
Worth adding I'm using Laravel 4.2, but am not desparately tied to it, and can upgrade to 5.x if necessary to get this functionality.
Once you've defined the relationships as you've described, you can access the ProjectTypes that belong to a User, that also belong to a certain Team (in your case $teamid should be the id of the Team that the User is currently logged in to) like so:
$projectTypes = $user->projectTypes()->where('team_id', $teamid)->get();
To easily access a collection of all Projects that belong to all ProjectTypes that belong to a User, you would first define the HasManyThrough relationship like so:
class User extends Eloquent {
public function projects()
{
return $this->hasManyThrough('Project', 'ProjectType');
}
}
Then you can access that collection like so:
$projects = $user->projects;
And finally, to access the Projects that belong to the ProjectTypes that belong to a User, that also belong to a certain Team (i.e. what it seems you're looking for), you can use lists() to get a list of relevant ProjectType ids, then whereIn() to filter for those within that list:
$projectTypeIds = $user->projectTypes()->where('team_id', $teamid)->lists('id');
$projects = $user->projects()->whereIn('projecttype_id', $projectTypeIds)->get();

Laravel passing variable from multiple models

I have 2 models
User
Customer
Each user hasMany customers (aka Accounts)
the user model has
public function customer() {
return $this->hasMany('App\Customer', 'id','customer_id');
}
but when i try to output this:
$user->customer->name
i get an error saying:
Undefined property: Illuminate\Database\Eloquent\Collection::$name
When i use this one, i get the entire customers record output in JSON.
$user->customer
So the relationship is working, but obviously i am missing something. I was sure this was the right way to do it. I swear this worked in Laravel4.2 but now that I'm in Laravel 5 it doesn't.
As the error and the below link says, It is returning a collection (hasMany) not a single object, you need to either loop over the collection or do direct access in the collection based on the index.
that is to say... does doing this work?..
$user->customer[0]->name
http://laravel.io/forum/04-10-2014-undefined-property-illuminatedatabaseeloquentcollectionitem
You should loop over customers, if you want display customers in laravel view you can do the following
#foreach
($user->customer as $cust)
{{$cust->name}}
#endforeach

Resources