Laravel ORM for Join Multiple Table - php

I have 9 tables that will love to join together all have the foreign key employee_id from employee table. How can I get ORM distribution for it. Below is the DB function that join all the function.
$modelEmployee = \DB::table('employees')
->select('*')
->join('employee_finances', 'employees.id', '=', 'employee_finances.employee_id')
->join('employee_addresses', 'employees.id', '=', 'employee_addresses.employee_id')
->join('employee_jobs', 'employees.id', '=', 'employee_jobs.employee_id')
->join('employee_admins', 'employees.id', '=', 'employee_admins.employee_id')
->join('employee_personals', 'employees.id', '=', 'employee_personals.employee_id')
->join('employee_memberships', 'employees.id', '=', 'employee_memberships.employee_id')
->where('employees.id', $id)
->get();

Step 1
First, create model for you employee table and add various relations to other table models
Eloquent Model for employees table
namespace App\Models;
class Employee extends \Illuminate\Database\Eloquent\Model {
public function employee_finances()
{
return $this->hasMany(\App\Models\EmployeeFinance);
}
public function employee_addresses()
{
return $this->hasMany(\App\Models\EmployeeAddress);
}
public function employee_jobs()
{
return $this->hasMany(\App\Models\EmployeeJob);
}
public function employee_admins()
{
return $this->hasMany(\App\Models\EmployeeAdmin);
}
public function employee_personals()
{
return $this->hasMany(\App\Models\EmployeePersonal);
}
public function employee_memberships()
{
return $this->hasMany(\App\Models\EmployeeMembership);
}
}
Step 2
Now create models for other join tables. Below is an example of employee_finances table. (similarly, create other models)
namespace App\Models;
class EmployeeFinance extends \Illuminate\Database\Eloquent\Model {
...
}
Step 3
Then for your query, you can use relations using with and whereHas functions of query builder. This equivalent to the result of the query mentioned in the question but the structure of the outcome will be different;
\App\Models\Employee::with('employee_finances','employee_addresses','employee_jobs','employee_admins','employee_personals','employee_memberships')
->whereId($employeeid)
->whereHas('employee_finances')
->whereHas('employee_addresses')
->whereHas('employee_jobs')
->whereHas('employee_admins')
->whereHas('employee_personals')
->whereHas('employee_memberships')
->get();
Result
Original Result object
The original resultant will be an object of common builder object where you cannot fire further relation actions which can be defined in Model level.
The original result will also be a flat array of the result and may have less. One example here would be the id column value would be replaced by the primary employee's table column id.
[
0 => [
'id' => 1,
'employee_name' => 'Employee',
'employee_finance_content' => 'finance_content',
'employee_personal_content' => 'personal_content',
'employee_jobs_content' => 'employee_jobs',
'employee_addresses_content' => 'employee_addresses',
'employee_admins_content' => 'employee_admins',
]
....
]
New result using Models
The result would be an instance of Employee model. The final result would be as an associative array where each relation would be an index of the array but the result will be an instance of the related Model, for example, the employee_finances would be an index or represent a column and the value contained within it will be an instance of EmployeeFinance on which you can further do ORM level activities.
[
0 => [
'id' => 1,
'employee_name' => 'Employee'
'employee_finances' => [
'id' => 2,
'employee_id' => 1,
'employee_finance_content' => 'finance_content'
],
'employee_addresses' => [
'id' => 10,
'employee_id' => 1,
'employee_address_content' => 'employee_address'
]
],
.....
]

you can use from this :
$row = $this->model->
where("id",$id)
->with("employee_finances")
->with("employee_addresses")
->with("employee_jobs")
->with("employee_admins")
->with("employee_personals")
->with("employee_memberships")
->with("employee_finances")
->get();
return $row->isEmpty() ? [] : $row->toArray();
plz define relations in your models with these names and use form that, here.

Related

Laravel eloquent query relationship with an added column using selectRaw

I started the query like this:
$students = StudRegProfile::with(['my_campus','work_experience' => function($query) {
$query->selectRaw('*, datediff(dateend, datestart) / 360 as years_of_experience');
}]);
Update:
My query is now like this:
$students = StudRegProfile::with(['my_campus','work_experience'])
->withCount([
'work_experience as years_of_experience' => function($query) {
$query->select(\DB::raw('SUM(datediff(dateend, datestart) / 360)'));
}
]);
Now I have years_of_experience as column in work_experience relationship. My output looks like this:
[
id => 1,
work_experience => [
id => 1,
years_of_experience => 2.4417,
]
]
But when I filter it like this:
$students->whereHas('work_experience', function($query) {
$query->whereRaw('years_of_experience >= 2');
});
It can't find my years_of_experience column.
Query Log:
Update:
My StudRegProfile hasMany work_experience. My work experience has datestart and endstart. I want to get the total difference in datestart and endstart so I can filter it as and input in my form

How to use sync on a 3 model relationship? - Laravel

I have 3 models:
Match Team Player
And i want to create a table with the following structure:
id | match_id | team_id | player_id
So that i can associate the 3 models i refered.
I created a 4th model MatchPlayers for the table i referred and I can use the 'search' functions without a problem. Like this:
$match->matchPlayers()->first()->team()->get()
And it returns the excpected result, but I cant do a
$match->matchPlayers()->sync([])
So, how should i solve this? Is my relationship wrong or the sync method isnt allowed on a 3 model relationship and I shoud use other method?
Thanks in advance
Edit:
Match.php
public function teamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
Team.php
public function matchTeamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
Player.php
public function matchTeamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
MatchPlayer.php
public function player(){
return $this->belongsTo('\Modules\Players\Entities\Player');
}
public function match(){
return $this->belongsTo('\Modules\Matchs\Entities\Match');
}
public function team(){
return $this->belongsTo('\Modules\Teams\Entities\Team');
}
If you've followed the Laravel documentation on Pivot tables and Many-Many relationships found here, and it's still not working, you might have more luck with "Attach". For example;
$matchPlayer = MatchPlayer::create([...]);
$match->matchPlayers()->attach($matchPlayer)
A good example of sync vs attach can be found here
Using a fourth model for this kind of relationship makes sense, as it gives you a navigation property for the third relation on your pivot table. This way you can form more complex queries this way.
For your particular problem, syncing based on match_id and team_id, I would simply do something like this:
$matchId = 123;
$teamId = 234;
$rows = [
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];
// remove all previously stored connections
MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->delete();
// insert the news ones
// (you could also use MatchPlayer::create() per item or
// $matchPlayer->save(), it doesn't matter)
MatchPlayer::insert($rows);
If this operation occurs very frequently, you will potentially burn through a lot of id values of the pivot table. In this case you could also perform a more efficient sync, which is slightly more complex:
$matchId = 123;
$teamId = 234;
$rows = [
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];
// delete all players that are not among the new data anymore
MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->whereNotIn('player_id', array_pluck($rows, 'player_id'))
->delete();
// remove rows from new data that already exist
$exist = MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->pluck('player_id')
->toArray();
$rows = array_filter($rows, function ($value, $key) use ($exist) {
return ! in_array($value['player_id'], $exist);
});
// then we store the remaining data
MatchPlayer::insert($rows);

Add a new column with a value to the select query in Laravel

I would like to know how to create a default variable called "type" and set a value to "car" while doing a select join in Laravel.
Here is my code so far:
$items = DB::table('items')->orderBy('created_at', 'desc')
->join('items_categories', 'items.item_category_id', '=', 'items_categories.category_id')
->select(
'items.id as items___item_id',
'items.item_title as items___item_title',
'items_categories.id as items_categories___category_id',
'items_categories.title as items_categories___category_title',
)
->take(20);
This works nice. However, I need to get/add a custom key and value for each record of this select so I can use it later in the template to filter stuff further.
So, I need to add a key called type with a value of car so in the print_r I will see type => car for every record and I can use this in my code.
How to do that?
Can I put that somhow in the select?
Like:
->select(
'items.id as items___item_id',
'items.item_title as items___item_title',
'items_categories.id as items_categories___category_id',
'items_categories.title as items_categories___category_title',
//something like this?
'type' = 'car'
)
Because right now I am getting this:
Array
(
[0] => stdClass Object
(
[items___item_id] => 10
[items___item_user_id] => 2
[items___item_title] => A new blue truck
[items_categories___category_id] => 1
[items_categories___category_title] => Truck
)
[1] => stdClass Object
(
[items___item_id] => 11
[items___item_user_id] => 2
[items___item_title] => VW Tiguan
[items_categories___category_id] => 1
[items_categories___category_title] => SUV
)
And I want to get this:
Array
(
[0] => stdClass Object
(
[items___item_id] => 10
[items___item_user_id] => 2
[items___item_title] => A new blue truck
[items_categories___category_id] => 1
[items_categories___category_title] => Truck
[type] => car
)
[1] => stdClass Object
(
[items___item_id] => 11
[items___item_user_id] => 2
[items___item_title] => VW Tiguan
[items_categories___category_id] => 1
[items_categories___category_title] => SUV
[type] => car
)
If possible, not in the model file, but during the one query, because it's only one time when I need this modification to be done.
You can use this method:
$data = DB::table('items')
->Select('items.id as items___item_id',
'items.item_title as items___item_title');
# Add fake column you want by this command
$data = $data->addSelect(DB::raw("'fakeValue' as fakeColumn"));
$data = $data->orderBy('items.id')->get();
Enjoy it!
You will want to create a model for your items table and query it that way. Using eloquent, you can create columns on the fly by adding column names to the $appends property and then defining a model attribute.
php artisan make:model Item
Any model automatically looks for a table that is the plural of the model name (Item looks for 'items'). In the Item model, add the following lines
/**
* Append custom columns to the model
*
* #var array
*/
protected $appends = ['type'];
/**
* Define the type column to every Item object instance
*
* #return string
*/
public function getTypeAttribute()
{
return 'car';
}
Now update your query to use the model instead of DB::select. Make sure to use the model at the top of your controller
use App\Item;
....
$items = Item::orderBy('created_at', 'desc')
->join('items_categories', 'items.item_category_id', '=', 'items_categories.category_id')
->select(
'items.id as items___item_id',
'items.item_title as items___item_title',
'items_categories.id as items_categories___category_id',
'items_categories.title as items_categories___category_title',
)
->take(20)->get();
You need to add get() as the final method when using a Model for it to return a collection vs. DB::select.
Here is the solution for this problem, hope it helps somebody else in the future.
$items = DB::table('items')->orderBy('created_at', 'desc')
->join('items_categories', 'items.item_category_id', '=', 'items_categories.category_id')
->select(DB::raw('"car" AS type,
items.id as items___item_id,
items.item_title as items___item_title,
items_categories.id as items_categories___category_id,
items_categories.title as items_categories___category_title
')
)
->take(20);
I came across the same requirement, I know it is late but it might help someone in the future:
Here is my code how to a add a custom field in Laravel eloquent model
$searchResults = Blog::with('categories')
->where('title', 'like', "%{$keyword}%")
->orWhere('description', 'like', "%{$keyword}%")
->select(['*', DB::raw("'{$keyword}' as keyword")])
->get();
Thanks
i implement it sth like this sample
$first = Message::where('from_id', '=', Auth::user()->id)
->where('to_id', '=', $id)->get();
foreach ($first as $f)
$f->is_sent = true;
$second = Message::where('from_id', '=', $id)
->where('to_id', '=', Auth::user()->id)->get();
foreach ($second as $s)
$s->is_sent = false;
$chats = $first->merge($second)
->sortBy('created_at');
return $chats->toJson();
you can do it by for eachafter get() method

Laravel - Order by pivot value in Many to Many table relationship

My application (Laravel 5.0) has a Products table and a Formats table. There's a manyToMany relationship between these two table (format_product). One product can be sold in many formats. Each relationship has a specific price so I have added a "price" column in the format_product table.
Now I'm trying to sort the products by price (being the cheapest format-price of each product the reference value).
One more thing, I need to paginate the results.
class Product extends Model {
public function formats()
{
return $this->belongsToMany('App\Format')->withPivot('price')->orderBy('pivot_price', 'asc');
}
}
class Format extends Model {
public function products()
{
return $this->belongsToMany('App\Product')->withPivot('price');
}
}
This is the format_product_pivot:
Schema::create('format_product', function(Blueprint $table) {
$table->integer('format_id')->unsigned()->index();
$table->foreign('format_id')->references('id')->on('formats')->onDelete('cascade');
$table->integer('product_id')->unsigned()->index();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->decimal('price', 8, 2);
});
In example, having this values:
Product A - Format 1 = 15€
Product A - Format 2 = 10€
Product B - Format 1 = 8€
Product B - Format 2 = 20€
Product C - Format 3 = 5€
Product C - Format 1 = 2€
I want this result:
Product C - 1 ( 2€)
Product B - 1 ( 8€)
Product A - 2 (10€)
Ok so I don't typically put orderBy() in my model, but it shouldn't be too much of an issue. You're going to have to use a join to get the results you want.
You can use the following query in your controller:
public function index() {
$products = Product::join('format_product', 'format_product.product_id', '=', 'products.id')
->select('products.id', 'format_product.format_id', 'format_product.price')
->orderBy('format_product.price', 'asc')
->paginate(25)
->get();
}
The reason you can't sort products by a relationship is the same reason you can't sort a multidimensional array by an inner array.
For example:
$array = [
'key1' => [
'anotherKey' => 'some value'
],
'key2' => [
'anotherKey' => 'some other value',
'anotherKey2' => 'some other value2'
],
'key3' => [
'anotherKey' => 'yet another value'
]
]
You can't sort this array by anotherKey. You have to use a join.
Hope this helps.

Eloquent ORM many to many relationship best practices

I have 2 tables
cars (id, title)
parts (id, title)
and I want to assosiate every car with a lot of parts and the price of this part for the specific car...
I believe the best way is to associate them through a table:
car_parts(id, car_id, part_id, price)
How do I define such a relation in Laravel's Eloquent?
I want to do
$car = Car::find(1);
$parts = $car->parts;
and I want to get an array of objects like so
{
'id' => 1,
'title' => 'rear flash',
'price' => '10.00',
},{
...
}
if I try the
public function parts(){
return $this->belongsToMany('Part', 'car_parts', 'car_id', 'part_id');
}
I dont get the price...
TIA
The price is available on the pivot model if you include it in withPivot:
public function parts ()
{
return $this->belongsToMany('Part', 'car_parts', 'car_id', 'part_id')
->withPivot('price');
}
Then you can map over the parts collection to get the arrays you want:
$parts = Car::find(1)->parts->map(function ($part)
{
return [
'id' => $part->id,
'title' => $part->title,
'car_id' => $part->pivot->car_id,
'part_id' => $part->pivot->part_id,
'price' => $part->pivot->price,
];
});

Categories