Consider the following entites
Students
Subjects
Exams
and following relationships
Student belongsToMany Subjects (Many-to-Many)
Student hasMany Exams
Subject belongsToMany Students (Many-to-Many)
Subject hasMany Exams
Exam belongsTo Student
Exam belongsTo Subject
So I am writing some test cases for the models and its relationships using ModelFactory (I am new to unit testing). I need to test a case where the Student and Subject for a Exam is related. So I did the following in test and factory.
Test
public function testStudentAndSubjectIsRelated()
{
$exam = factory(Exam::class)->create();
// We need to know whether the student and subject is related
$this->assertTrue($exam->student->subjects()->pluck('id')->contains($exam->student_id));
// And viceversa
$this->assertTrue($exam->subject->students()->pluck('id')->contains($exam->subject_id));
}
Factory
$factory->define(App\Exam::class, function (Faker\Generator $faker) {
return [
'student_id' => function () {
return factory(App\Student::class)->create()->id;
},
'subject_id' => function ($exam) {
$subject = factory(App\Subject::class)->create();
$student = App\Student::find($exam['student_id']);
$subject->students()->save($student);
return $subject->id;
},
....
];
});
Is this the right way of doing it?
Related
I meet this problem: I have model of people and model of their activities and I want to declare relation like latest activity inside of person model but Laravel does not give permission to use 'Limit' or 'Take' inside of Eager Loads
So how it could be done ?
I tried this inside of person model
public function lastActivity()
{
return $this->belongsToMany('App\Models\Activity','activity_job','job_id','activity_id')
->orderByDesc('created_at')->limit(1);
}
But it takes latest activity of one person not for all 🤯
Please Help
Let's say you have a model Person (or People, whatsoever...)
(Person.php)
class Person extends Model {
protected $table = 'persons';
public function activities()
{
return $this->hasMany(Activity::class);
}
...
}
And a model Activity
(Activity.php)
class Activity extends Model {
...
public function person()
{
return $this->belongsTo(Person::class);
}
...
}
Now to get all Persons with their latest activity
Person::with(['activities' => function ($query) {
$query->orderBy('id', 'desc');
}])->get()
->map(function ($person) {
$person->setRelation('activities', $person->activities->take(1));
return $person;
});
Explanation:
We get all Persons with all of their activities. Then we map through the collection and (re)set the activities relationship with only one item of the activities collection. Because we ordered the activities by id in descending order, take(1) will give us the persons latest activity.
I have a relationship on Orders and Customers.
a row from customers table :
customer_id
customer_name
customer_state
customer_city
1
Amin
Yazd
Yazd
a row from orders table :
order_id
customer_id
product_id
factor_id
1
1
3
4
Now I want order rows where customer_state is yazd.
Order.php
public function customer()
{
return $this->belongsToMany(Customer::class, 'orders', 'order_id', 'customer_id');
}
OrdersController.php
$state = "Yazd";
$reportItem = Order::whereHas("customer", function ($query) use ($state) {
$query->where('customer_state', $state)->get();
});
It doesn't work. How I can handle this?
What I understand from the given input you're not using the proper relation here:
The belongsToMany relation is used for many-to-many relations using an allocation table. But you are actually using a one-to-many relation => one customer can have many orders.
In this case you should use a belongsTo relation on Order Model or/and a hasMany relation on Customer Model:
// Order.php
public function customer() {
return $this->belongsTo(Customer::class)
}
// Customer.php
public function orders() {
return $this->hasMany(Order::class)
}
You have put get() at the wrong place. Change this
$reportItem = Order::whereHas("customer", function ($query) use ($state) {
$query->where('customer_state', $state)->get();
});
To
$reportItem = Order::whereHas("customer", function ($query) use ($state) {
$query->where('customer_state', $state);
})->get();
Learn more about laravel relations
I'm learning Laravel, and really OOP in general. I've followed several YouTube tutorial series, that teach you to create a blog in Laravel.
I'm building a task app for a brewery, and I'm trying to define the relationships between the users and the tasks. So I have two models: User.php and Task.php. I had no problem defining the user in a hasMany tasks relationship, and reciprocally, a task belongsTo a user. Where I'm confused is that I'd like to also have a user belong to the task as well. I have two MySQL columns, one with the heading of "user_id" and the other with "user_assigned_id". What I want is that a user has many tasks, but a task also has one assigned user, the idea being that the user that created the task might assign the task to another user. I've found several tutorials on creating relationships between three models, such as a user owning several messages, but only having one address, so I figured that I could just treat two models as if they were three models and connected the User model back to the Task model in a hasOne relationship, but I'm having a really hard time passing that through to the Controller and View.
Here is the relevant code in each file:
User.php
public function tasks()
{
return $this->hasMany('App\Task');
}
Task.php
public function user()
{
return $this->belongsTo('App\User');
}
// Added an user_assigned_id relationship
public function user_assigned()
{
return $this->hasOne('App\User', 'name', 'user_assigned_id');
}
DashboardController.php
public function index()
{
$user_id = auth()->user()->id;
$now = Carbon::now();
$tasks_assigned = Task::orderBy('date', 'asc')->whereDate('date', '>=', $now)->where('user_assigned_id', '=', $user_id)->user_assigned()->where('name', '=', 1)->get();
$tasks_created = Task::orderBy('date', 'asc')->whereDate('date', '>=', $now)->where('user_id', '=', $user_id)->get();
return view('dashboard')->with('tasks_assigned', $tasks_assigned)->with('tasks_created', $tasks_created);
}
I've gotten a bit turned around in the Controller, so I'm not sure if I messed something up there. Basically, I'm getting results from tasks owned by the logged in user, but not assigned to the logged in user.
You can just add a second relationship defined on your Task.php Model and assign a different agent based on user_assigned_id. You can manipulate it as expected via Eloquent.
Task.php
public function user() {
return $this->belongsTo('App\User');
}
public function assignedUser() {
return $this->belongsTo('App\User', 'user_assigned_id');
}
Then on DashboardController.php
$tasks_assigned = Task::orderBy('date', 'asc')->whereDate('date', '>=', $now)->where('user_assigned_id', '=', $user_id)->get();
should work
public function user()
{
return $this->belongsTo('App\User');
}
// Added an user_assigned_id relationship
public function assignee()
{
return $this->belongsTo('App\User', 'user_assigned_id');
}
The relationship is still a belongsTo, you just need to provide the column where the foreign key is held.
Other files:
User.php
public function ownedTasks()
{
return $this->hasMany('App\Task');
}
public function assignedTasks()
{
return $this->hasMany('App\Task', 'user_assigned_id');
}
Dashboard Controller
public function index()
{
$now = Carbon::now();
$tasks_assigned = Auth::user()->assignedTasks()->where('date', '>=', $now)->get();
$tasks_created = Auth::user()->ownedTasks()->where('date', '>=', $now)->get();
return view('dashboard')->with(compact('tasks_assigned', 'tasks_created'));
}
i have two tables
**students :**
id
family_id
name
**family :**
id
father_name
father_civil_id
contact_no
both tables are connected using family_id, i want to get how many Brothers/Sisters each students have(with name of sibling) using eloquent.
can you please help me, with controller/model/view.
Let's say you have a Student and Family model. Then you have several ways to do it.
Here are the two easiest ones I can guess with the information you provided.
Without relationship
Controller
Student::where('family_id', $family_id)->get();
HasMany relationship
Family model
class Family extends Model
{
// Since Laravel will expect your table to be 'families'
protected $table = 'family';
public function students()
{
return $this->hasMany(Student::class);
}
}
Controller
$family = Family::with('students')->inRandomOrder()->first();
$siblings = $family->students;
In Students Model:
public function family() {
return $this->belongsTo('App\Models\Family');
}
public function getSiblings() {
return $this->family->students;
}
So you can call it by your students:
$student->getSiblings();
I'm having a difficult time with this many-to-many relationship in Laravel. I have a many-to-many relationship, projects and persons. I also have a third table, roles (with 2 columns: id, name), which contains roles a person can have on a project (in this case, "actor", "director", etc). The pivot table, person_project, has the columns "person_id", "project_id", and "role_id". I had success getting all the persons associated with a project using
$project = Project::find($id);
$project->persons;
But how can I just get persons with a specific role on a project? And how would I save such a relationship?
Models:
// Project.php
class Project extends Eloquent {
protected $table = 'projects';
public $timestamps = false;
public function persons() {
return $this->belongsToMany('Person');
}
}
// Person.php
class Person extends Eloquent {
protected $table = 'persons';
public $timestamps = false;
public function projects() {
return $this->belongsToMany('Project');
}
}
This article was helpful in figuring out the retrieving of the relationship. Eloquent's withPivot() and join() methods were key in getting it to work.
// In the Project model
public function persons() {
return $this->belongsToMany('Person')
->withPivot('role_id')
->join('roles', 'role_id', '=', 'roles.id');
}
I figured out the insertion part from Laravel's docs: http://laravel.com/docs/eloquent#inserting-related-models
In this example, Input::get('directors') is an array of person_ids selected to be connected to the role of "director". The same deal for Input::get('actors').
// Within the update method of the Projects controller
foreach (Input::get('directors') as $directorId) {
$project->persons()->attach($directorId, array('role_id' => 1)); // roles.id 1 = "director"
}
foreach (Input::get('actors') as $actorId) {
$project->persons()->attach($actorId, array('role_id' => 2)); // roles.id 2 = "actor"
}
Try one of the following:
If you are using Laravel 4.1:
$project = Project::whereHas('persons', function($q)
{
$q->where('role_id', 1);
})->get();
Laravel 4 and 4.1:
$project = Project::with(array('persons' => function($query)
{
$query->where('role_id', 1);
}))->get();