Passing external elements to the model in a select query with Eloquent - php

Trying to transform a query in raw mysql to the eloquent laravel queries. I am stuck on trying to get external elements (from other models) inside it...Mainly the "color" (that comes from the BookingStatus and creating the URL and putting it in as URL.
Could you help me out?
Here is the mysql query:
$booking = DB::table('bookings')
->select('bookings.id as id', 'booking_reference as description', 'booking_status as title', 'color', DB::raw('concat("http://127.0.0.1/blabla/public/profile/Calendar/detail/",bookings.id) as url'),'booking_date as start')
->join('booking_status','booking_status.id','=','bookings.bookingstatus_id')
->where('photographer_id', '=', $photographer->id)
->union(DB::table('bookings')
->select('bookings.id as id', 'booking_reference as description', 'booking_status as title', 'color',DB::raw('concat("http://127.0.0.1/KYMA/public/profile/Calendar/detail/",bookings.id) as url'),'booking_date as start')
->join('booking_status','booking_status.id','=','bookings.bookingstatus_id')
->where('user_client_id', '=', $user->id)
)
->get();
edited: And here is where I have gone so far
$booking_info = Booking::with('bookingStatus')
->where('photographer_id', $photographer->id)
->orWhere('user_client_id', $user->id)
->select(['id as id', 'booking_reference as description','booking_date as start', 'bookingstatus_id as title'])
->get();
I tried a few things with the color and read the docs of Laravel but I just can't get it right... How do I pass it in my select query ? If I simply add 'color' obviously it will not pick it up because it is in the attached array and not the "primary" one...
Thanks a lot for your help!!
///// EDIT /////
Here is a solution I found to be able to pass everything I want, I'm not using the model relations thought since couldn't understand how to pass their array values in my select request...
$booking_info = Booking::where('photographer_id', $photographer->id)
->orWhere('user_client_id', $user->id) //because he could be client of a shoot ;-)
->join('booking_status','booking_status.id','=','bookings.bookingstatus_id')
->join('shooting_types', 'shooting_types.id', '=', 'bookings.stype_id')
->join('users', 'users.id', '=', 'user_client_id')
->join('addresses', 'addresses.id', '=', 'users.address_id')
->select('bookings.id as id', 'first_name', 'phonenumber', 'booking_reference as description', 'stype_name as title', 'color', 'booking_date as start')
->get();

You could use:
$bookings = Booking::with('booking_status')
->where('photographer_id', $photographer->id)
->orWhere('user_client_id', $user->id)
->get();
of course you need to have status relationship between Booking and Status
And if you have color column in your BookingStatus model, you can access it now:
foreach ($bookings as $b) {
echo $b->booking_status->color;
}

Using Raw SQL is not suggested as long as Model core api can be invoked directly in controller by having related associations with other table. I would suggest to use Models core api with relations.
For Example
$bookings = Booking::with('booking_status')
->where('photographer_id', $photographer->id)
->get();
The above sample code is just an example of using laravel eloquent associations in controller. However, you will need to make changes in the above conditions as per your requirement.
Note: The above code will work only if you have defined associations in all relevant models. For example Booking model must have association "hasMany" with BookingStatus model and similarly BookingStatus model should have association "belongsTo" with Booking table. In this way you don't need to write custom queries.

Related

Laravel eloquent update column using relationship column

How can achieve this query?
Sale::with(['catalog'])
->whereIn('id', $ids)
->update(['price' => DB::raw('catalog.price')]);
This is not working, it shows undefined table... I tried to put the name of the table but it's the same.
On the internet I always found the easy query:
Sale::with(['catalog'])
->whereIn('id', $ids)
->update(['price' => 5]);
Okay! When I want to update all rows with the same value is easy, in addition is easy when you want to update with a column of the same table like:
Sale::with(['catalog'])
->whereIn('id', $ids)
->update(['price' => DB::raw('price_alternative')]);
But how about using a column of another table with a relationship? I haven't found the solution.
I know this can be solved using entire raw query, but I wanted to know if it can be achieved by the eloquent way
You probably need to join in the catalog table on your querybuilder. This is different than using with(). Something along the lines of
Sale::whereIn('id', $ids)
->join('catalog', 'sales.catalog_id', '=', 'catalog.id')
->update(['price' => DB::raw('catalog.price')]);
This is not better than answer of #Qirel, but it is Eloquent way, i like this because that's more clearly.
$Sales = Sale::whereIn('sales.id', $ids)
->with('Cat')->get();
$Sales->map(function($q){
$q->price = $q->Cat->price;
$q->save();
});
Assume you have this relation code in Sale model:
public function Cat()
{
return $this->hasOne(CatModel::class, 'id', 'catalog_id');
}

Laravel 5: How to use 'where' or 'orderBy' using eloquent?

First things first, this is not a duplicate of Laravel 4: how to "order by" using Eloquent ORM
I have this model User, then I have this other model Idea. I'm writting a view with the details of the user, and I want to post all the ideas the user has suggested. Now, the ideas have a status, the first status is "DRAFT", that means only the user who posted the idea can review it, the idea should not be shown to other users looking at the profile.
Using eloquent I could do something like:
#foreach($user->idea as $idea)
...display details...
#endforeach
My problem is that this approach would cycle through all ideas AND in the order where they were introduced. I can add an #if to show only what I want, like
#foreach($user->idea as $idea)
#if($idea->status !='DRAFT')
...show the idea...
#endif
#endforeach
But I don't think it's the smart way to do it, I'd like to do something like
$ideas = $user->idea->where('status', '<>', 'DRAFT')
and then cycle through the $ideas variable, or at least, I'd like somtehing like
$ideas = $user->idea->orderBy('created_at', 'desc')
But I have no idea on how to do it.
You can do it like this:
$ideas = $user->idea()
->where('status', '<>', 'DRAFT')
->orderBy('created_at', 'desc')
->get();
When you use ->idea() it will start a query.
For more information about how to query a relationship: https://laravel.com/docs/5.7/eloquent-relationships#querying-relations
You can user where clause like this
DB::table('products_to_categories')
->where('categories_id', $id )
->update([
'categories_id' => $unassigned_cat_id
]);
and you can use orderBy clause like this
DB::table('products_to_categories')
->where('categories_id', $id )
->orderBy('subId','DESC');

Laravel Eloquent: Relationships multiple have issue & Eloquent “select” method not working with using “with” method

I am try to made Eloquent: Relationships for three model. Please have a look on my code.
$account = Account::select(['id', 'is_sign_contract', 'restaurant_name', 'state', 'phone_no', 'email', 'one_time_pick_up', 'sign_contract_date', 'created_at', 'oil_on_hand', 'binsize'])
->with(['completedservice' => function($c) {
//$c->select('id');
}])
->with(['accountService' => function($q) {
$q->with(['serviceProvider' => function($qs) {
$qs->select('id', 'company_name');
}])->select('account_id', 'service_provider_id', 'service_id');
}])
->whereRaw($where)
->orderBy('id', 'ASC')->offset(54)->limit(1)->get();
if i remove that //$c->select('id'); select form above relation then i get data if i am using it display blank relationship block.
below image for response in last image whole function there
In short without select it works fine, but if I am using select then not working.
Laravel loads the relations after the first query is run. In order for it to attach the related model to the parent you need to select the foreign key on the related table so Laravel knows which model to attach the child to after the query is run.
The accountService works because ytou are selecting account_id on that model to attach it to Account and serviceProvider works because you are selecting id on serviceProvider as well as service_provider_id on accountService so after all queries are run Laravel knows which models get attached where.
Your query is not working because you are not selecting the account_id on the child model.
The following will work:
$account = Account::select(['id', 'is_sign_contract', 'restaurant_name', 'state', 'phone_no', 'email', 'one_time_pick_up', 'sign_contract_date', 'created_at', 'oil_on_hand', 'binsize'])
->with(['completedservice' => function($c) {
$c->select('id', 'account_id');
}])
->with(['accountService' => function($q) {
$q->with(['serviceProvider' => function($qs) {
$qs->select('id', 'company_name');
}])
->select('account_id', 'service_provider_id', 'service_id');
}])
->whereRaw($where)
->orderBy('id', 'ASC')->offset(54)->limit(1)->get();
You need to have the foreign key selected along with any other fields you wish to select. Without which you'll get an empty relationship. So it should be something similar to $c->select('id', 'account_id');

Laravel OrderBy Nested Collection

I'm using a Roles package (similar to entrust). I'm trying to sort my User::all() query on roles.id or roles.name
The following is all working
User::with('roles');
This returns a Collection, with a Roles relation that also is a collection.. Like this:
I'm trying to get all users, but ordered by their role ID.
I tried the following without success
maybe because 'roles' returns a collection? And not the first role?
return App\User::with(['roles' => function($query) {
$query->orderBy('roles.id', 'asc');
}])->get();
And this
return App\User::with('roles')->orderBy('roles.id','DESC')->get();
None of them are working. I'm stuck! Can someone point me in the right direction please?
You can take the help of joins like this:
App\User::join('roles', 'users.role_id', '=', 'roles.id')
->orderBy('roles.id', 'desc')
->get();
Hope this helps!
You can make accessor which contains role id or name that you want to sort by.
Assume that the accessor name is roleCode. Then App\User::all()->sortBy('roleCode') will work.
Here's the dirty trick using collections. There might be a better way to achieve this(using Paginator class, I guess). This solution is definitely a disaster for huge tables.
$roles = Role::with('users')->orderBy('id', 'DESC')->get();
$sortedByRoleId = collect();
$roles->each(function ($role) use($sorted) {
$sortedByRoleId->push($role->users);
});
$sortedByRoleId = $sortedByRoleId->flatten()->keyBy('id');
You can sort your relations by using the query builder:
notice the difference with your own example: I don't set roles.id but just id
$users = App\User::with(['roles' => function ($query) {
$query->orderBy('id', 'desc');
}])->get();
See the Official Laravel Docs on Constraining Eager Loading
f you want to order the result based on nested relation column, you must use a chain of joins:
$values = User::query()->leftJoin('model_has_roles', function ($join)
{
$join>on('model_has_roles.model_id', '=', 'users.id')
->where('model_has_roles.model_type', '=', 'app\Models\User');})
->leftJoin('roles', 'roles.id', '=', 'model_has_roles.role_id')
->orderBy('roles.id')->get();
please note that if you want to order by multiple columns you could add 'orderBy' clause as much as you want:
->orderBy('roles.name', 'DESC')->orderby('teams.roles', 'ASC') //... ext
check my answer here:
https://stackoverflow.com/a/61194625/10573560

Complex joins in Eloquent

I have a table of itineraries. An itinerary belongs to a customer and has multiple days. A package is assigned to each of these days. I want to be able to produce a manifest showing which customers are allocated to a package and on which days.
I'm struggling with Eloquent, because you can't do queries beyond a one-to-Many relationship
What i want to do is this:
return $this->package->where('PackageID, $id)->itineraryDay->itinerary->customer->select('CustomerID', 'Date')
But can only really achieve it using the query builder:
return DB::connection($this->connection)
->table('t_package as PA')
->join('t_itinerary_day_map as IDM', 'IDM.PackageID', '=', 'PA.PackageID')
->join('t_itinerary_day as ID', 'IDM.ItineraryDayID', '=', 'ID.ItineraryDayID')
->join('t_itinerary as IT', 'IT.ItineraryID', '=', 'ID.ItineraryID')
->join('t_customer as CC', 'CC.ItineraryID', '=', 'IT.ItineraryID')
->where('PA.PackageID', $id)
->select('CC.CustomerID', 'ID.Date')
->distinct()
->get();
I really want to use Eloquent as I hate hardcoding table names and i've already created relationships for these models, but can't see any way around it
I believe you could do something like this to find customers that have a package with the given ID:
$packageId = 42;
$customers = $customer->whereHas('packages', function($q) use($packageId){
return $q->where('package_id', $packageId);
})->get();
How would that work for what you want?
I'll have to make few assumptions on your relationship but it seems doable.
If one ItineraryDay belongs to one Itinerary. And one Itinerary belongs to one Customer. And one ItineraryDay may have more than one Package.
$packageID = 111;
$itineraryDays = ItineraryDay::with('itinerary.customer')
->whereHas('package', function($q) use($packageID) {
$q->where('PackageID', $packageID);
})
->get();
foreach($itineraryDays as $itineraryDay) {
var_dump($itineraryDay);
var_dump($itineraryDay->itinerary->customer);
}
I'm not sure if i get your relationship method naming correct, but hopefully this works.

Categories