I have two tables linked by a pivot table (with a custom migration):
Interest table:
ID | label
Person table:
ID | label
PersonHasInterest table (custom migration):
InterestID | PersonID | notes
How can I get all records from the pivot table (with persons and interests joined in)? I don't want to get all interests of a person or all persons that have an interest but all entries (with joins) of the pivot table.
Even though Pivot extends Model it is not possible to call the standard model functions on a Pivot-object. Issue on Github.
What I came up is using the DB-Facade to execute a select statement, like so:
DB::table('person_has_interest')
->join('interest', 'person_has_interest.interest_id', '=', 'interest.id')
->join('person', 'person_has_interest.person_id', '=', 'person.id')
->get(); // further manipulation like select possible
Try to define a pivot model like this:
<?php
...
use Illuminate\Database\Eloquent\Relations\Pivot;
...
class PersonHasInterest extends Pivot
{
protected $table = '...'; // table name
}
Then use it: PersonHasInterest::all();
Related
Using Laravel, I'd like to fetch an order status (order_status table) from an order (orders table) based on the
locale relationship stored in the orders table using a pivot table (order_status_locale table).
The pivot table contains the "localised" order status from the order.
Of course, I could fetch the localised order status (order_status_locale) directly from the database, but I'd like to
fetch the localised order status through a Laravel relationship.
Something like this:
$order = Order::find(123);
$order->localisedOrderStatus->label;
This is an example of the database structure:
orders:
id: int
locale_id: int
...other columns
locales:
id: int
...other columns
order_statuses:
id: int
...other columns
order_status_locale:
order_status_id: int
locale_id: int
label: varchar
its sometimes better to make model of your pivot table. like OrderStatusLocale.php
then you can make the relation through it.
lastly if you want to achieve
$order->localisedOrderStatus->label;
you can use laravel has one through. or i think its better to go through the relation like $order->order_status->locale->label
Suppose I have a Laravel 5.5 app with four models:
Class, Student, Assignment and AssignmentSubmission
A Class belongs to many Students, a Student belongs to many Classes and an AssignmentSubmission belongs to an Assignment, a User, and a Class.
So the tables look like this:
classes:
id
name
students:
id
name
class_student:
class_id
student_id
assignments:
id
name
assignment_submissions:
id
class_id
student_id
assignment_id
Now, in a query builder class I need to construct a query that returns the Students that belong to a Class with an extra column called total_assignment_submissions with a tally of how many assignments that student has submitted for that class only.
My first port of call was the following:
$class->students()->withCount('assignmentSubmissions')->get();
But that returns the total assignment submissions for that student for all classes.
The following mySql query returns the right data:
SELECT *,
(SELECT Count(*)
FROM `assignment_submission`
WHERE `student_id` = `students`.`id`
AND `class_id` = ?) AS total_assignment_submissions
FROM `students`
INNER JOIN `class_student`
ON `students`.`id` = `class_student`.`student_id`
WHERE `class_student`.`class_id` = ?
But I can't seem to get the selectSub() addSelect() and raw() calls in the right order to get what I want. It seems that I only do it with raw queries but the event id will be unsanitized or otherwise I can do it but it only returns the assignment_count field and not the rest of the fields for the student.
$class->students()
->selectSub(
AssignmentSubmission::selectRaw('count(*)')
->whereClassId($class->id)->getQuery(),
'total_assignment_submissions'
)->toSql();
There must be a way to do this. What am I missing here?
withCount() can be constrained.
$class->students()->withCount(['assignmentSubmissions' => function($q) use($course_id){
$q->where('course_id', $course_id);
}])->get();
This will limit the count to that particular course.
I have 3 tables: Project, Group, User
and one relation pivot table: project_group with colmuns:
id
project_id
group_id
and pivot field user_id
I know how to take all Groups and Projects:
Project::find(1)->groups()->get();
groups() is belongToMany function inside Project Model.
Problem is I don't know how to get all users for particular project. I need to get project and all users names and ids for that project, any solution for this?
Thanks in advance
You can try on your Project.php model adding a pivot relationship
public function users() {
return $this->hasMany(App\User::class, 'project_group');
}
However this may be misleading as project_group should be a pivot table between the project table and the group table. user_id doesn't belong in there.
Create a second pivot table called group_user with group_id, user_id. Then you can use this on your Group.php model:
public function users() {
return $this->hasMany(App\User::class, 'group_user');
}
An example would then be:
$project = Project::find(1);
foreach($project->groups as $group) {
$users = $group->users; // Now you should have access to all the users for each group
}
Edit 4: Problem solved. The issue arising in edit 3 was only a data error.
Final answer: specifying foreign keys in the belongstomany relationships and clearing my PHP cache afterwards.
Edit 3: I've made the queries come out differently by specifying a foreign key in the belongsToMany relationship. However the query still doesn't return the results I need. Here is the generated query:
select `streams`.*, `followers`.`user_id` as `pivot_user_id`, `followers`.`stream_id` as `pivot_stream_id` from `streams` inner join `followers` on `streams`.`id` = `followers`.`stream_id` where `followers`.`user_id` =
Edit 2: The root problem is that User::following() and Stream::followers() are generating the exact same query despite being different sides of a many to many relationship.
Edit: I captured the query coming from User::following() and it looks like it's basing the query on a stream_id rather than the user_id, I'm not sure how to fix this.
select `users`.*, `followers`.`stream_id` as `pivot_stream_id`, `followers`.`user_id` as `pivot_user_id` from `users` inner join `followers` on `users`.`id` = `followers`.`user_id` where `followers`.`stream_id` = ?
I have a Users table, and A Streams table.
Each User has many Streams
Each Stream also has many Users(followers) in addition to the one User that owns it.
How Do I correctly set up this functionality in Eloquent? Right now I have a belongsToMany relationship in both models, setting up a many-to-many relationship on a pivot table. However this seems to conflict with the hasMany relationship in the User model and the belongsTo relationship in the Streams model that use the foreign key user_id on the Streams table.
To clarify, the final functionality I'm expecting is that a User object can return both a list of the Stream objects it owns, and the Stream objects it is following. A Stream object should be able to return both the one User object that owns it, and the multiple User objects that follow it.
However, right now, when I try to obtain a list of the streams a user is following, using the User::following() method, it returns the same results as the User::streams() method.
Here are how the tables are currently laid out:
Users
| id | name | email | password | token | created_at | updated_at |
|----|------|-------|----------|-------|------------|------------|
Streams
| id | name | user_id | created_at | updated_at |
|----|------|---------|------------|------------|
Pivot "followers"
| id | stream_id | user_id | created_at | updated_at |
|----|-----------|---------|------------|------------|
And here are the two model classes:
Stream
class Stream extends Model {
public function user() {
return $this->belongsTo(User::class);
}
public function followers() {
return $this->belongsToMany(User::class, 'followers');
}
}
User
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $hidden = ['password', 'token'];
public function streams() {
return $this->hasMany(Stream::class);
}
public function following() {
return $this->belongsToMany(Stream::class, 'followers');
}
}
I have subject table that contains
id name
and languages table that contains
id subject_id
and division table
id name
finally subject-division table (pivot table)
id subject_id division_id
now exist one-To-one relationship between subject table and languages table and many-To-many relationship between subject table and division table, i need to pluck only the subjects of subject table without the languages by using the relationship function
now i can get the languages only of the subject table of the relationship function In Division Model as the following
public function langSubject ()
{
return $this->belongsToMany('Subject' , 'subject_division','division_id','subject_id')
->join('lang_subject', 'lang_subject.subject_id' ,'=', 'subject.id')->get();
}
But till now I can't get the subjects only without the languages
Any Suggestions ?
You need to add the clause ->select('tableName1.fieldName1','tableName2.fieldName2','tableName3.fieldName3') to your statement after the join statement to get the tableName.fieldName and you may need to use leftJoin instead of join to get the results whether if there is a match or not.
Check out Eloquent relationship documentation -> sub headline "Querying Relationship Existence". There it mentions ::has method, which you could use in fashion
Division::has('subject.lang', '<', 1)->get()
Or at least that's the theory. Haven't had the need for it yet ;-)
It should be supported by Laravel 4 as well.