Eloquent collide column names - php

I have the following tables:
users: id, name, ...
companies: id, name, ...
I have a scope with a LIKE operator, And I use it to search in both users.name and companies.name as follows:
public function scopeSearch(Builder $query, string $term = null)
{
$query->join('companies', 'companies.id', '=', 'users.company_id');
$term = $term.'%';
$query->where('users.name', 'like', $term)
->orWhere('companies.name', 'like', $term);
}
Action:
$users = User::query()
->search($request->input('q'))
->with('company')
->paginate();
// ...
Since name was used in both tables, Laravel can't distinguish between them, so it ends up filling the users.name with a companies.name:
The view looks like this:
#foreach($users as $user)
// ...
<th scope="row">{{ $user->id }}</th>
<td>{{ $user->name }}</td> // wrong: this gives the company.name
<td>{{ $user->company->name }}</td>
<td>{{ $user->email }}</td>
// ...
#endforeach
One solution to solve this is by using select and some aliases, but that would be a nasty solution.
Any good solution?
Update 1: I don't want to use whereHas since it's slower than joining when it comes to using the LIKE operator.
Update 2: another solution is to alias the companies.name and the users.name as follows:
public function scopeSearch(Builder $query, string $term = null)
{
$query->join('companies', 'companies.id', '=', 'users.company_id')
->select(['*', 'companies.name as company_name', 'users.name as user_name']);
}
<td>{{ $user->user_name }}</td>
<td>{{ $user->company_name }}</td>
This works fine, but if (for any reason) I want to get rid of the searching capability, I also need to modify the view, so a dependency has been introduced here.

I would probably rewrite the search-scope to search for the company name through relations and using whereHas(), instead of joining it in. That way you never have ambiguous column names when using that scope.
It would generate a different query, but you would end up with the same result.
public function scopeSearch(Builder $query, string $term = null)
{
$term = $term.'%';
return $query->where('name', 'like', $term)
->orWhereHas('company', function($query) use ($term) {
return $query->where('name', 'like', $term);
});
}

After doing some experiments, I found that using the whereIn clause is faster and more convenient than using join/whereHas:
$query->where('name', 'like', $term)
->orWhereIn('company_id', function($query) use ($term) {
$query->select('id')->from('companies')->where('name', 'like', $term);
});
The action remains the same:
<td>{{ $user->name }}</td>
<td>{{ $user->company->name }}</td>
And as I said it's much faster than joining and whereHas.
Here is my benchmark:
600ms: whereHas.
500ms: join.
130ms: whereIn.

Related

If there are multiple expenses in a project, how can I sum them together and make a single row?

I have two table as you can see that relations each other.
I want to see this table
How to do that in my blade file or controller.
this is my blade file;
#foreach ($costs as $cost)
#foreach ($projects as $project)
#if($project->id == $cost->project_id)
<tr class="odd">
<td>{{ $project->id }}</td>
<td>{{ $cost->price }}</td>
</tr>
#endif
#endforeach
#endforeach
public function tablo1()
{
$costs = DB::table('cost_manages')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('projects')
->whereColumn('projects.id', 'cost_manages.project_id')->groupBy('project_id');
})
->get();
$projects = DB::table('projects')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('cost_manages')
->whereColumn('cost_manages.project_id', 'projects.id');
})
->get();
return view('home.muhasebe_Tablo1', [
'costs' => $costs,
'projects' => $projects
]);
}
That one is my controller.
There are 2 costs for project number 11. I want to write a single record by collecting them.
Please help me
Use join:
DB::table('projects')
->leftjoin('cost_manages', 'projects.id','const_manages.project_id')
->select('projects.id as id', 'projects.name as name', 'cost_manages.cost as cost')->get()
and then loop through this.

Array returning only the first item in Laravel

I'm facing a problem that I can't solve, I have an array that only returns the first value and obviously, I need them all, the code in the controller is like this:
public function OnGoing(Request $request)
{
$user = Auth::user();
$tickets = $this->chamadosCad
->where('status', '=', 2)
->OrderBy('id', 'asc')
->paginate(30);
$chamado = TiChamadosCadastro::all();
//dd($chamado->setor);
$SetorNome = Setores::where('id', '=', $chamado->pluck('setor'))
->get();
//dd($SetorNome);
return view('portal.TI.chamados.ematendimento', compact('user', 'tickets', 'chamado', 'SetorNome'));
}
If i change the line:
$SetorNome = Setores::where('id', '=', $chamado->pluck('setor'))
->get();
To:
$SetorNome = Setores::where('id', '=', $chamado->setor)
->get();
I get the error
Property [setor] does not exist on this collection instance.
The same happens if I try to dump $chamado.
The bit of my view that regards this error is like this now:
<div style="display: none">
#if($chamado->prioridade == 0)
{{$prioridade = 'Baixa', $corTabela = 'info'}}
#elseif($chamado->prioridade == 1)
{{$prioridade = 'Média', $corTabela = 'warning'}}
#elseif($chamado->prioridade == 2)
{{$prioridade = 'Alta', $corTabela = 'danger'}}
#endif
</div>
<tr class="{{$corTabela}}">
<td>{{$chamado->id}}</td>
<td>{{ $SetorNome->pluck('nome') }}</td>
<td>{{ $prioridade}}</td>
<td>{{$chamado->solicitante}}</td>
<td>{{date('d/m/Y H:m', strtotime($chamado->created_at))}}</td>
That's actually a lot more but is to much code, this bit is inside a forelse.
If i let this piece of code like it is, i get the same value on every rows and, if i change the line:
<td>{{ $SetorNome->pluck('nome') }}</td>
To:
<td>{{ $SetorNome->nome' }}</td>
I get the same error as before.
If I try to loop this same line as:
#foreach($SetorNome as $SetorNome)
<td>{{ $SetorNome->pluck('nome') }}</td>
#endForeach
I get:
Call to a member function pluck() on bool (View:
If a take all the pluck() out, that other error returns.
I'm really don't know exactly what I'm doing wrong, I'm still learning and any help will be appreciated.
I already search in a lot of places but didn't find anything that helped me, or at least that I could understand.
If there is any question or if I couldn't explain this right feel free to ask.
Also, if there is another question about this issue please let me know.
Thank you all in advance.

Laravel Eloquent: How to select from multiple tables

I'm using Laravel and the Eloquent ORM that it provides but I'm struggling to select the data I need. I have 3 Models
House
Occupants
Job
A house can have multiple occupants and I can easily get these using the following.
$house= House::find($house_id);
$occupants = $house->occupants()->where('active', 1)->get();
This works nicely but I also want to select the job of each occupant. I've got this as a one to one relationship but the jobs are in a seperate table.
Is there a way to also select the related job for each occupant from the jobs table efficiently? I'm guessing it would be something like this
$occupants_and_jobs = $house->occupants()->where('active', 1)->job()->get();
You could just try what you are suggesting and see what happens.
You can also do some eager loading of the relationships
$house = House::with(["occupants","occupants.job"])->find($house_id);
foreach ($house->occupants as $occupant) {
print_r($occupant->job);
}
As #AlexeyMezenin if you need to constrain the relationship then you need to (as the docs suggest under Constraining Eager Loads) do:
$house = House::with(["occupants" => function ($query) {
$query->where("active","=",1);
},"occupants.job"])->find($house_id);
foreach ($house->occupants as $occupant) {
print_r($occupant->job);
}
Now the fine-print: Laravel will include "with" relationships in the order it finds them and also include all intermediate relationships of the nesting, e.g. ::with("occupants.job") implies ::with(["occupants","occupants.job"]) however if you already have set a previous relationship then it is maintained (which is how this works). occupants will not be overwritten when occupants.job is set.
This query will load all occupants with active = 1 and their jobs:
House::with(['occupants' => function($q) {
$q->where('active', 1);
}, 'occupants.job'])->find($house_id);
Complete way to to search data from different tables in laravel:
Route:
Route::get('/systems/search', 'SearchController#search')->name('project-search');
Try this way in your searchController:
public function search(Request $request)
{
$data = DB::table('projects as p')->select('p.*','u.first_name', 'u.last_name')
->join('users as u','p.user_id','=','u.id');
if( $request->input('search')){
$data = $data->where('p.title', 'LIKE', "%" . $request->search . "%")
->orWhere('p.description', 'LIKE', "%" . $request->search . "%")
->orWhere('u.first_name', 'LIKE', "%" . $request->search . "%")
->orderBy('p.created_at', 'desc');
}
$data = $data->paginate(16);
return view('systems.search', compact('data'));
}
And receive those data in your blade like this way:
<div class="col-md-8">
<h3>List of Results</h3>
<table class="table table-striped">
<tr>
<th>title</th>
<th>description</th>
<th>creator</th>
<th>category</th>
</tr>
#foreach($data as $search)
<tr>
<td>{{ $search->title }}</td>
<td>{{ $search->description }}</td>
<td>{{ $search->first_name }}</td>
</tr>
#endforeach
</table>
{{ $data->appends(request()->except('page'))->links() }}
</div>
search box input field:
<div class="input-group input_search" style="width: 100%">
<input style="border-radius: 20px" type="text" class="form-control search"
placeholder="Search" aria-describedby="basic-addon2" name="search" id="search"
value="{{Request::get('title')}}">

calling data from database from controller to view using laravel

Controller:
public function index() {
$data = DB::table('tusers','tbills','tpackages')
->join('tbills', 'tusers.user_id', '=', 'tbills.user_id')
->join('tpackages', 'tbills.package_id', '=', 'tpackages.package_id')
->select('tusers.user_id','tusers.company_name','tusers.first_name', 'tbills.account_no', 'tpackages.package_name','tbills.start_date','tbills.end_date','tbills.bill_status')
->get();
return View::make('account')->with('data',$data);
}
`
view:
#forelse($data as $value)
<td>{{ $value->user_id }}</td>
<td>{{ $value->company_name }}</td>
<td>{{ $value->first_name }}</td>
<td>{{ $value->account_no }}</td>
<td>{{ $value->package_name }}</td>
<td>{{ $value->start_date }}</td>
<td>{{ $value->end_date }}</td>
<td>{{ $value->bill_status }}
I want to call $data from packagecontroller to account.blade but there is an error
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "tusers" does not exist
LINE 1: ... "tbills"."end_date", "tbills"."bill_status" from "tusers" i...
^ (SQL: select "tusers"."user_id", "tusers"."company_name", "tusers"."first_name", "tbills"."account_no", "tpackages"."package_name", "tbills"."start_date", "tbills"."end_date", "tbills"."bill_status" from "tusers" inner join "tbills" on "tusers"."user_id" = "tbills"."user_id" inner join "tpackages" on "tbills"."package_id" = "tpackages"."package_id")
Thanks for your help.
Remove the other 2 table names from table(). Something like this.
public function index() {
$data = DB::table('users','bills','packages')
->join('bills', 'users.id', '=', 'bills.user_id')
->join('packages', 'bills.package_id', '=', 'packages.id')
->select('users.id','users.company_name','users.first_name', 'bills.account_no', 'packages.package_name', 'bills.start_date', 'bills.end_date', 'bills.bill_status')
->get();
return view('account', ['data' => $data]);
}
Mind column naming please. I may have changed some names, so you have to make sure you have the correct names.
In your view do
#foreach( $data as $value )
<td>{{ $value->company_name }}</td>
...
#endforeach
It seems you are skipping some steps. Learn properly through this free video series how to work with Laravel: https://laracasts.com/series/laravel-from-scratch-2017

Laravel pagination at leftjoin

I want to create leftjoin with pagination on laravel.
how to create pagination with leftjoin ?
Here my code :
$news = News::leftJoin('categories','news.category_id', '=', 'categories.id')
->select('news.*' ,'categories.category')
->get()->sortByDesc('created_at');
Previously, i use $news = News::paginate(10); and its works, but it without leftjoin.
and here my html code to create pagination
{{$news->links('vendor.pagination.pagination')}}
The paginate function should be done on the Query Builder object, not on the collection returned by get().
$news = News::leftJoin('categories','news.category_id', '=', 'categories.id')
->select('news.*' ,'categories.category')
->paginate(10);
The same goes for sorting. When you call get()->sortByDesc(), you are getting a Collection then sorting the collection through PHP. Normally, you would want to use orderBy() in the query builder to sort through SQL.
$news = News::leftJoin('categories','news.category_id', '=', 'categories.id')
->select('news.*' ,'categories.category')
->orderBy('created_at', 'DESC')
->paginate(10);
Use Eloquent: Relationships
For example:
News.php model
class News extends Model
{
protected $primaryKey = 'id';
function withCategories() {
return $this->hasOne('App\Categories', 'id', 'category_id');
}
public function list(){
News::with('withCategories')->orderBy('created_at', 'DESC')
->paginate(10);
}
}
in news.blade.php (example)
<table>
<tbody>
#foreach ($news as $news)
<tr>
<th>{{ $news->id }}</th>
<td>{{ $news->title }}</td>
<td>{{ $news->withCategories->title }}</td> <!-- Category name-->
</tr>
#endforeach
</tbody>
</table>
</div>

Categories