I have just started using Laravel Eloquent and stuck at retrieving some data. It would be great if someone can guide me.
I have two tables (not mentioning user table)
Institutes:
id |name | user_id
1 |abc |22
2 |xyz |32
Now institute2 (xyz) has following programs
Programs:
id |institute_id| name | admission_open|
1 | 2 |exp1 | 1 |
2 | 2 |exp2 | 0 |
Institute.php
class Institute extends Eloquent
{
protected $table = 'institutes';
public function programs(){
return $this->hasMany('Program');
}
}
Program.php
class Program extends Eloquent
{
protected $table = 'programs';
public function institute()
{
return $this->belongsTo('Institute');
}
}
What I want:
I want to get name of institutes for which admissions (admission_open =1) are open in programs table.
How should I write query for that.do I have to join tables?
$tests = Programs::where('admission','1')->get();
Now after you get object you can loop
foreach($tests as $test) {
$test->institute->name;
}
There are a lot of ways to do this. Like user #ujwal dhakal said or with joins, but I prefer this:
Institute:::whereHas('program', function($query) {
$query->where('admission', '=',1);
})->get();
$institutions = Institute:::whereHas('programs', function($query) {
$query->where('admission_open', '=',1);
})->get();
Hope this helps
You can try
$programs = Program::where('admission_open','1')->with('institute')->get();
OR
$programs = Program::where('admission_open','=','1')->with('institute')->get();
$programs will have Program objects with admission_open = 1 and institute data
foreach($programs as $program){
echo $program->institute->name;
}
Related
Lets assume I have a model for: Race, Participant, Team
And these relations: Race 1-N Participant N-1 Team
See in another way :
races 1 - N participants
teams 1 - N participants
In Laravel terms:
/* Inside Race model */
public function participants()
{
return $this->hasMany(Participant::class);
}
/* Inside Team model */
public function participants()
{
return $this->hasMany(Participant::class);
}
/* Inside Participant model */
public function race()
{
return $this->belongsTo(Race::class);
}
public function team()
{
return $this->belongsTo(Team::class);
}
In the participants table, It looks like this:
id | team_id | race_id | [a lot of other columns...]
------------------------------
1 | 1 | 1 |
2 | 1 | 1 |
3 | 2 | 1 |
4 | 2 | 1 |
In the above example, I know that the race ID 1 has 2 teams.
I can count them by doing this:
$race = Race::find(1);
$number = $race->participants()->distinct()->count('team_id');
The problem
Counting the number of teams is cool, but I want to access to the list of corresponding Team model instances, so that I can use them for further operations (within a foreach loop for example).
I tried a lot of things without success.
Something like this:
$teams = $race->participants()->distinct()->[...] // Don't know what to put here
The working equivalent SQL query is:
SELECT teams.* FROM teams
INNER JOIN participants ON participants.team_id = teams.id
INNER JOIN races ON races.id = participants.race_id
WHERE races.id = 1
GROUP BY teams.id
Resulting in this:
When the participants table contains this:
I want to know if I can do it with Eloquent instead of using Query/Builder DB:: methods directly ?
EDIT 1
My closest result:
$race->participants()->distinct()->get('team_id')
And then using this list of team_id I can access to the teams using Team::find([list of IDs]) but it looks greedy to me.
EDIT 2
I forgot some information:
The participants.team_id column is NULLABLE because:
There are races with teams of participants
There are races with participants (without team)
I don't think you can easily access to it through the $race instance.
But, you can use the whereHas method on the Team model:
$race = Race::find(1);
$teams = Team::whereHas('participants', function ($query) use ($race) {
$query->where('race_id', $race->id);
})->get(); // ->count() also works
See documentation
To get distinct teams from a race model, you could add a many to many relationship between Race and Team with Participant acting as the pivot.
For example,
/* Race */
public function teams()
{
return $this->belongsToMany(Team::class, 'participants', 'race_id', 'team_id');
}
/* Team */
public function races()
{
return $this->belongsToMany(Race::class,'participants', 'team_id', 'race_id');
}
Then, you could just do this
$race = Race::find($id);
$teams = $race->teams()->distinct()->get();
to get a list of distinct teams for the race.
And since we set up the relationship on both models, you can now also get distinct races for each team by doing
$team = Team::find($id);
$teams = $team->races()->distinct()->get();
First, let's improve your eloquent relations.
// Race
public function teams()
{
return $this->hasMany(Team::class);
}
public function withoutTeamParticipants() // change name that suits you
{
return $this->hasMany(Participant::class);
}
// Team
public function participants()
{
return $this->hasMany(Participant::class); // In this case make sure that participant.race_id is null
}
// Participant
public function team()
{
return $this->belongsTo(Team::class); // When no team, then participant.team_id is null
}
public function race()
{
return $this->belongsTo(Race::class);
}
To access list of participants of a given race:
$race = Race::where('id', 1)->with('teams.participants', 'withoutTeamParticipants')->get();
In your blade you can further use this as:
// List of participants without a team
#foreach ($race->withoutTeamParticipants as $participant)
{{ $participant->name }}
#endforeach
// List of participants that are with a team
#foreach ($race->teams as $team)
#foreach ($team->participants as $participant)
{{ $participant->name }}
#endforeach
#endforeach
You can directly use hasManyThrough relationship inside Race model for fetching distinct teams associated with the race.
public function distinctTeams()
{
return $this->hasManyThrough(Team::class, Participant::class, 'race_id', 'id', 'id', 'team_id')->distinct();
}
Now, you can loop over the teams of a race by using $race->distinctTeams
Hopefully this helps.
I'm trying to do a where query on my relation called employee_label.
The table employee_label looks like this:
+----+-------------+----------+
| id | employee_id | label_id |
+----+-------------+----------+
| 1 | 123 | 123 |
| 2 | 456 | 456 |
| 3 | 768 | 768 |
+----+-------------+----------+
The other where() and orWhere() get passed an empty array() by default, but could contain data as for example: ['inactive' => 0].
Expected result:
I expect to only receive the employees with for example label 123 when I provide label 123 as where() for the relation.
Actual result:
All employees are returned, the data is not filtered.
Code:
$employees = Employee::with(['employee_label' => function($query) use ($request) {
$query->where('label_id', '=', $request->get('label'));
}])->where($searchQuery)->orWhere($orQuery)->orderBy('inactive', 'asc')->paginate(20);
What I've tried:
I've tried to change the $query->where('label_id') to $query->where('employee_label.label_id') with no change in the result.
Model Employee
class Employee extends Model
{
protected $table = 'employees';
protected $fillable = [
'name',
'surname',
'inactive',
'entered_into_service'
];
public function employee_label() {
return $this->hasOne('App\EmployeeLabel');
}
}
Model EmployeeLabel
class EmployeeLabel extends Model
{
protected $table = 'employee_label';
protected $fillable = [
'employee_id',
'label_id'
];
public function employee() {
return $this->belongsTo('App\Employee');
}
public function label() {
return $this->belongsTo('App\Label');
}
}
After a long search I've finally found the answer to this weird problem.
Apparently instead of using Employee::with() you have to use Employee::whereHas().
So the final code will be:
$employees = Employee::whereHas('employee_label', function($query) use ($request) {
$query->where('label_id', '=', $request->get('label'));
})->where($searchQuery)->orWhere($orQuery)->orderBy('inactive', 'asc')->paginate(20);
See the documentation for more information.
Thanks all who helped!
Try updating the employee model to:
public function employeeLabel() {
return $this->hasOne('App\EmployeeLabel', 'employee_id', 'id');
}
That binds the relationship automatically so you do not need to in the eloquent call.
Then the method to get all employees and associated labels and return paginated with:
$employees = Employee::all()->with('employeeLabel')
->orderBy('inactive', 'asc')
->paginate(20);
https://laravel.com/docs/6.x/eloquent-relationships#one-to-one
I think you forgot to return your $query object
Instead of
$query->where('label_id', '=', $request->get('label'));
Try returning your $query from a employee_label callback method
return $query->where('label_id', '=', $request->get('label'));
I am using Laravel 5.4. I have 2 tables destination and user and a pivot table destination_user.
destination table
---|------
id | name
---|------
1 | sth
user table
---|------
id | name
---|------
1 | sth
and finally Pivot table
--------------|--------
destination_id| user_id
--------------|--------
1 | 1
2 | 1
3 | 2
I created a model for pivot table named destinationUser.
My destination model looks like this:
<?php
namespace App\models;
use App\Models\User;
use App\Models\DestinationUser;
use App\Models\DestinationImage;
use Illuminate\Database\Eloquent\Model;
class Destination extends Model
{
protected $table = 'destinations';
public function user() {
return $this->belongsToMany('App\Models\User');
}
public function destinationUser() {
return $this->hasMany('App\Models\DestinationUser');
}
}
I want to get all the destinations with their respective user detail using pivot table. I have tried so far is this:
$destinations = $this->destination->with('user', 'destinationUser')
->whereHas('destinationUser', function($query) {
$query->where('user_id', user()->id);})
->paginate(20);
dd($destinations[0]->destinationUser); gives me destination id and user id but I want user detail. How can I achieve this. Thank You for your help
You need a many to many relationship:
class Destination extends Model
{
protected $table = 'destinations';
public function destinationUser() {
return $this->belongsToMany('App\User');
}
}
controller
$destinations = $this->destination->with('destinationUser', function($query) {
$query->where('user.id', user()->id);})
->paginate(20);
As I was searching for faster execution of queries, there was a wrong design of tables. There is more load and time of execution for 3 table with pivot rather than 2 tables without pivot. So, I figured it out and corrected.
Hello i am new here and not a native English speaker so please forgive me for any mistakes on my grammar and on my question formatting.
I am building an app with php using laravel framework 5.4 version.
The web app is very simple its for reviewing articles and users that posts articles.
I would like to learn how i can union the results of the functions within my model.
I want the allReviews function from user model to return the reviews the user has mixed with the reviews his articles have orderby createdtime.
let me explain better.
here is my 3 main tables:
Users | Articles | Reviews
--------- | --------- | ---------
id | id | id
name | user_id | reviewable_id
email | title | reviewable_type
password | body | reviewtext
etc.. | etc.. | created_time
and here is my models code :
class User extends Model{
protected $table = 'users';
public function articles()
{
return $this->hasMany(Article::class,'user_id');
}
public function reviews(){
return $this->morphMany(Review::class,'reviewable');
}
public function allReviews(){
/*
i want union something like this:
$result = $this->reviews() union
foreach ($this->Articles() as $Article) {
union $Article->reviews();
}
orderby created_time ASC or DESC doesn't matter
return $result
*/
}
}
class Article extends Model{
protected $table = 'articles';
public function user()
{
return $this->belongsTo(User::class,'user_id');
}
public function reviews(){
return $this->morphMany(Review::class,'reviewable');
}
}
class Review extends Model{
protected $table = 'reviews';
public function reviewable(){
return $this->morphTo('reviewable');
}
}
So my question is how i can do the function allReviews from user to work ?
Any help is appreciated :)
Thank You
Calling the $user->reviews property will return all reviewable models. You don't have to UNION anything, Eloquent will take care of that for you.
Try this:
public function allReviews(){
$reviews = new \Illuminate\Database\Eloquent\Collection;
foreach($this->articles as $article)
{
$reviews = $reviews->merge($article->reviews);
}
$reviews = $reviews->merge($this->reviews);
return $reviews;
}
I'm really tired now and I have a feeling you might get the N+1 query problem situation here but it should work for you.
I have a table without 'primary ID', ex.
+---------+----------+------------+------------+
| user_id | point_id | created_at | updated_at |
+---------+----------+------------+------------+
And I have records:
1 ..| 200 | (date) | (date)
14 | 300 | (date) | (date)
1 ..| 200 | (date) | (date)
Now I want delete only one record to get:
1 ..| 200 | (date) | (date)
14 | 300 | (date) | (date)
I tryied:
UserPoint::where( 'point_id', $reqId )->where( 'user_id', $userId )->first()->delete();
But it always remove all record with this params ... Anyone can help?
EDIT: My UserPoint model
use Illuminate\Database\Eloquent\Model;
class UserPoint extends Model {
protected $table = 'point_user';
public function scopeUsed($query){
return $query->where('amount', '<', 0);
}
public function scopeEarned($query){
return $query->where('amount', '>', 0);
}
public function about(){
return $this->hasOne('\App\Point', 'id', 'point_id');
}
}
The way you are trying to achieve this deletion is somewhat wrong as it does not follow the rules of data integrity . Deleting a child table in your case would impose what we call an orphaned table.
However the correct way of deleting that record would be to first associate this table to its parent related table in this case as below:
Class User extends Model {
public function points() {
return $this->hasMany(UserPoint::class)
}
}
then in your UserPoint Class or Model you then need to map your relation.
class UserPoint extends Model {
protected $table = 'point_user';
// I have added this part
public function users() {
return $this->belongsTo(User::class)
}
public function scopeUsed($query){
return $query->where('amount', '<', 0);
}
public function scopeEarned($query){
return $query->where('amount', '>', 0);
}
public function about(){
return $this->hasOne('\App\Point', 'id', 'point_id');
}
}
This way you when deleting the Model or Item you can simply do the below:
// Inject your User in the constructor or function - lets say you names it User $user
$user->points->delete();
I suggest you also look at Eloquent's association and sync methods when working with relations this way you always know that the related Models are on sync and there re no orphaned children in the database which in Enterprise Design is a huge problem as accuracy and Data intergrity is everything .