Laravel Explicit route model binding issue in RouteServiceProvider - php

I am using Explicit route model binding for Slider module in my Laravel (5.6 version )application. Now I am facing an issue when i try to join sliders table with file_uploads table.
RouteServiceProvider
$this->bind('slider', function ($value) {
$slider = new Slider;
return Slider::withTrashed()
->leftjoin('file_uploads','file_uploads.file_code', '=', 'sliders.file_code')
->where('sliders.id', $value)->first();
});
this is the code am using.
Both sliders and file_uploads table have ID column. And in slider edit page am getting ID from file_uploads table. My intended ID will be from sliders table.
I really appreciate any help you can provide.

If you had used Eloquent Relationship it could have saved you having the one id property from a table override another due to joins.
But for the sake of using Joins then you can retrieve the needed id as another property using select() (see Selects) or passing the array parameters to the first() method so your code becomes:
return Slider::withTrashed()
->leftjoin('file_uploads','file_uploads.file_code', '=', 'sliders.file_code')
->where('sliders.id', $value)
->first(['*', 'sliders.id as sliders_id']);
Or:
return Slider::withTrashed()
->leftjoin('file_uploads','file_uploads.file_code', '=', 'sliders.file_code')
->where('sliders.id', $value)
->select('*', 'sliders.id as sliders_id')
->first();
Either way the select statement is passed as query and the id value is returned as sliders_id and you can use that where you needed the id instead.

Related

Laravel Where Clause To Search In Columns Which Are Not In The Database

I have a table organisations with a number of columns, namely id, name, created_at and updated_at.
In my Organisation model, I added a custom attribute by adding the following code in the model:
// Add custom attributes
protected $appends = [
'device_count',
];
and:
public function getDeviceCountAttribute()
{
// Count organisation's devices
$device_count = Device::where('organisation_id', '=', $this->id)->count();
return $device_count;
}
In my controller, I am trying to search (using the where clause) by the device_count attribute, but I'm getting an error since this is not a real column in my database table.
This is how I'm searching:
$organisations = Organisation::query();
$organisations = $organisations->where('device_count', '=', 0);
$organisations = $organisations->get();
This is the error:
[2020-10-14 12:29:27] local.ERROR: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'device_count' in 'field list'...
Is there an alternative to the where clause in order to search by device_count please?
You can't query against attributes like that, they only exist on the model and do not exist in the database. However, you don't need to create a getter for that.
Laravel has a withCount() method you can use instead of that attribute - which is the correct approach of obtaining relational counts.
So a query with that attribute would look like
$organisations = Organisation::withCount('devices')->get();
The resulting models will now have a device_count attribute on them, that you can use in your views.
Then in your query, to filter those records that has at least a certain relational count, you can do
$organisations = Organisation::has('devices', '=', 0)->get();
Since you're looking for those that do not have any relation, you can replace it with doesntHave(). The above snippet is included to show how you can query against a specific set of relational counts.
To query only those that don't have any related devices, simply do
$organisations = Organisation::doesntHave('devices')->get();
This assumes that you have defined a devices relation on your Organisation class.
public function devices() {
return $this->hasMany(App\Models\Device::class); // Or App\Device::class if your models are not in the Models namespace/directory
}
The approaches above are the Laravel-way of doing it - and you should therefor remove your getDeviceCountAttribute() method and the corresponding device_count from $appends.
As per your requirement you want to get those Organisations which doesnot have any devices
For that, you need to use doesntHave method.
Make a relationship in the Organisation model.
public function devices() {
return $this->hasMany('App\Models\Device','organisation_id','id');
}
Now call the mothed in controller/
$organisations = Organisation::doesntHave('devices')->get();
it will return you those organisations which devices are not exists.

Laravel RelationShip (join with where)

I need help with Laravel 5 (using Eloquent)
I have 2 tables...
Model Driver
drivers
id
company
Model DriverOnline
drivers_online
id
name
driver_id
I need to search for a result on (company=1 and driver_id=driver.id).
Please help me!
If you want to only fetch Driver based on a condition, you can just do this:
Driver::with('online')->where('company', 1)->get();
If the clause is on the relationship, use with and specify a query on that.
$company = 1;
$drivers = Driver::with(['online' => function($query) use ($company)
{
$query->where('company', $company);
}]);
See "Eager Load Constraints":
https://laravel.com/docs/5.0/eloquent
Take note of my use. This allows you to include variables from the scope into your Closure instance.
And be aware, if you use either solution, you must set up a relationship. Consult the link I shared with more information on that.
Edit: As per our conversation.
$drivers = Driver::where('company_id','=',1)
->with('driversOnline')
->whereHas('driversOnline', function($query) {
$query->where('online','=',1);
})
->get();

Laravel Eloquent relationship orderby issue

I have a Objective model which has many Action and every Action has one ActionYear. already defined in model.
How to use orderby to sort action in objective through action_year's specific column.
$query = Objective::with('actions.actionYear')
->orderBy('action_year.created_at')
->get();
this through error Undefined table: 7 ERROR: missing FROM-clause entry for table "action_year".
How to solve this. Thank you.
You can order the eager loaded models with a closure:
$query = Objective::with(['actions.actionYear' => function($q){
$q->orderBy('action_year.created_at');
})->get();
If you use function with() then this only makes sure the named relationship is loaded also to avoid extra need for SQL queries later. Othewise it does not introduce any additional changes compared to Objective::all()
One way how to achieve sorted collection is to use sortBy() function after loading the data like this
$query = $query->sortBy(function($objective){
return $objective->actionYear->created_at;
});

Laravel Restful Controller ID

So to explain my issue, whenever i am connecting to the database with Laravel it will default search for the id column as "id".
If i name my column jobID for example, i would like to controller to search for "jobID" instead of just "id". I could just change all of my tables ID columns to "id" however this causes issues when you use Laravel's left joins as it will take the latest id column as the actual id column.
Heres my join:
$jobs = Job::leftJoin('occupational_areas', function($join) {
$join->on('jobs.occupationalArea', '=', 'occupational_areas.id');
})->get();
However Restful controller default to "id" and that is what i'm asking, how do i change the default "id" to becomes something more custom like jobID
Try using this left join
$jobs = Job::select('occupational_areas.id as occ_id', 'jobs.id as jobs_id', your required values)
->leftJoin('occupational_areas', 'jobs.occupationalArea', '=', 'occupational_areas.id')
->get();
comment for errors
Turns out the easiest way to do this is by setting:
protected $primaryKey = 'jobID';
Into your model.
I am pretty sure Ronser also had it right with his method. Either will work.
Thanks Ronser!

Laravel Eloquent: How to get only certain columns from joined tables

I have got 2 joined tables in Eloquent namely themes and users.
theme model:
public function user() {
return $this->belongs_to('User');
}
user model:
public function themes() {
return $this->has_many('Theme');
}
My Eloquent api call looks as below:
return Response::eloquent(Theme::with('user')->get());
Which returns all columns from theme (that's fine), and all columns from user (not fine). I only need the 'username' column from the user model, how can I limit the query to that?
Change your model to specify what columns you want selected:
public function user() {
return $this->belongs_to('User')->select(array('id', 'username'));
}
And don't forget to include the column you're joining on.
For Laravel >= 5.2
Use the ->pluck() method
$roles = DB::table('roles')->pluck('title');
If you would like to retrieve an array containing the values of a single column, you may use the pluck method
For Laravel <= 5.1
Use the ->lists() method
$roles = DB::table('roles')->lists('title');
This method will return an array of role titles. You may also specify a custom key column for the returned array:
You can supply an array of fields in the get parameter like so:
return Response::eloquent(Theme::with('user')->get(array('user.username'));
UPDATE (for Laravel 5.2)
From the docs, you can do this:
$response = DB::table('themes')
->select('themes.*', 'users.username')
->join('users', 'users.id', '=', 'themes.user_id')
->get();
I know, you ask for Eloquent but you can do it with Fluent Query Builder
$data = DB::table('themes')
->join('users', 'users.id', '=', 'themes.user_id')
->get(array('themes.*', 'users.username'));
This is how i do it
$posts = Post::with(['category' => function($query){
$query->select('id', 'name');
}])->get();
First answer by user2317976 did not work for me, i am using laravel 5.1
Using with pagination
$data = DB::table('themes')
->join('users', 'users.id', '=', 'themes.user_id')
->select('themes.*', 'users.username')
->paginate(6);
Another option is to make use of the $hidden property on the model to hide the columns you don't want to display. You can define this property on the fly or set defaults on your model.
public static $hidden = array('password');
Now the users password will be hidden when you return the JSON response.
You can also set it on the fly in a similar manner.
User::$hidden = array('password');
user2317976 has introduced a great static way of selecting related tables' columns.
Here is a dynamic trick I've found so you can get whatever you want when using the model:
return Response::eloquent(Theme::with(array('user' => function ($q) {
$q->addSelect(array('id','username'))
}))->get();
I just found this trick also works well with load() too. This is very convenient.
$queriedTheme->load(array('user'=>function($q){$q->addSelect(..)});
Make sure you also include target table's key otherwise it won't be able to find it.
This Way:
Post::with(array('user'=>function($query){
$query->select('id','username');
}))->get();
I know that this is an old question, but if you are building an API, as the author of the question does, use output transformers to perform such tasks.
Transofrmer is a layer between your actual database query result and a controller. It allows to easily control and modify what is going to be output to a user or an API consumer.
I recommend Fractal as a solid foundation of your output transformation layer. You can read the documentation here.
In Laravel 4 you can hide certain fields from being returned by adding the following in your model.
protected $hidden = array('password','secret_field');
http://laravel.com/docs/eloquent#converting-to-arrays-or-json
On Laravel 5.5, the cleanest way to do this is:
Theme::with('user:userid,name,address')->get()
You add a colon and the fields you wish to select separated by a comma and without a space between them.
Using Model:
Model::where('column','value')->get(['column1','column2','column3',...]);
Using Query Builder:
DB::table('table_name')->where('column','value')->get(['column1','column2','column3',...]);
If I good understood this what is returned is fine except you want to see only one column. If so this below should be much simpler:
return Response::eloquent(Theme::with('user')->get(['username']));
#You can get selected columns from two or three different tables
$users= DB::Table('profiles')->select('users.name','users.status','users.avatar','users.phone','profiles.user_id','profiles.full_name','profiles.email','profiles.experience','profiles.gender','profiles.profession','profiles.dob',)->join('users','profiles.user_id','=','users.id')
->paginate(10);
Check out, http://laravel.com/docs/database/eloquent#to-array
You should be able to define which columns you do not want displayed in your api.

Categories