Laravel Function : In controller or in model? - laravel

I'm wondering whats the better solution, to put all the function in my models files using Eloquent Query Builder or directly into the controller.
I've got a Table Donations with :
id, user_id, project_id and amount
A Table Users with :
Many field, but the one important is company_id
So, each employees has one company. But each employees can make several donations to several projects.
For example, I've got this function into my CompaniesController to show all the donation made by the employee of the selected company. :
// Total sum of all donates of the employees
$total_sum = Donation
::join('users', 'donations.user_id', '=', 'users.id')
->where('users.company_id', $id)
->selectRaw('sum(donations.amount) as sum')
->first()
->toArray()['sum'];
It works fine, but I'm not sure how to convert it into a Eloquent Query Builder, I try :
public function total_sum($company_id)
{
return $this->hasMany('App\Donation')
->join('users', 'donations.user_id', '=', 'users.id')
->where('users.company_id', $company_id)
->selectRaw('sum(donations.amount) as sum')
->first()
->toArray()['sum'];
}
But I get only the donation made by myself and not the other employees.
And for the records, whats the best solution ? To put all the function into controllers or into Model ?

You can use scopes in your model to achieve what you want. Example
public function scopeTotalSum($query, $id)
{
return $query->join('users', 'donations.user_id', '=', 'users.id')
->where('users.company_id', $id)
->selectRaw('sum(donations.amount) as sum');
}
then in you controller you can use it like this
$total_sum = Donation::totalSum($id)->first()->toArray()['sum'];
i think you can change the above line to this;
$total_sum = Donation::totalSum($id)->first()->sum;
hope it helps

Related

Laravel Lumen eloquent left join returns joined table data rather than primary able data

I have two tables company and courses table
The table has the following fields
companies table
id, full_name, email, deleted_at
and courses table
courses table
id, company_id, course_name,deleted_at
Now i would like to retrieve all courses which company is not deleted. So in my controller i have added
public function index(Request $request){
$query = Courses::query();
$query = $query->leftJoin('companies','companies.id','=','courses.company_id');
$query->whereNull('companies.deleted_at');
if($request->get('filter_name')){
$query = $query->where('courses.name', 'like', '%' . $request->get('filter_name') . '%');
}
return response()->json($query->paginate($request->get("perPage")));
}
When i run the above it returns companies data rather than courses. Where am i going wrong or what am i missing out?
If you have use eager loading in both of your model, you can use this kind of approach.
$all_course = Courses::with(['company', function($query) {
return $query->whereNotNull('deleted_at');
}])->get();
As you can see, I query in the Courses model to return all the courses but I added some filter in the company relationship. where in I used whereNotNull to get only the company that's not deleted.

Display specific column name in laravel 5.6

I am using laravel 5.6. I've two tables. One is Teachers(id,name,email,salary) another is Students(id,teacher_id,name,email) I have joined 2 tables
$vu_data = Teacher::join('Students', 'teachers.id', '=', 'students.teacher_id')
->where('teachers.id', $id)
->get();
return view('view_full')->with('vu_data',$vu_data);
view_full.blade.php
{{$vu_data[0]->name}}
How can I display sthdent name and teacher nam. There are same column name.
Thanks in advance
The better way is to use laravel Eloquent relationships https://laravel.com/docs/5.7/eloquent-relationships#one-to-many*.
Put on your Teachers model
public function students(){
return $this->hasMany('App\Students', 'teacher_id', 'id');
}
You will call like that:
$vu_data->students()
If you want to use yur select, simple use de 'AS'
->select('Teachers.name as teacher_name', 'Students.name as student_name')
You'll need to specify the columns in a select() clause on the query, and rename the columns. Such as
Teacher::join('Students', 'teachers.id', '=', 'students.teacher_id')
->where('teachers.id', $id)
->select('teachers.name AS teacher_name', 'students.name AS student_name', [ rest of columns])
->get();
However, you might want to look into Eloquent relationships, which will allow you to iterate through a teacher then all of that teacher's students, or vice versa.
You need to add before ->get()
->select('Teachers.name as teacherName', 'Students.name as studentName')
and than you can use
{{$vu_data[0]->teacherName}}
and
{{$vu_data[0]->studentName}}
As per your table structure one teacher has many students. Hence instead of using join you can use laravel relationships with hasMany :
Teacher has many students - Teacher Model :
public function students(){
return $this->hasMany(Students::class);
}
A student belongs to a teacher - Student Model :
public function teacher(){
return $this->belongsTo(Teacher::class);
}
Now you can get relationships like below :
Get all teachers with their students :
$teachers = Teacher::with('students')->get();
Get all students of a particular techer :
$teacher = Teacher::find($teacherId);
$students = $teacher->students;
Finally using this, you can convert this :
$vu_data = Teacher::join('Students', 'teachers.id', '=', 'students.teacher_id')
->where('teachers.id', $id)
->get();
return view('view_full')->with('vu_data',$vu_data);
To this :
$teacher = Teacher::find($id);
return view('view_full', compact('teacher'));
Then inside blade :
You can get teacher details : {{ $teacher->name }}
and students :
#if($teacher->students->count() > 0)
#foreach($teacher->students as $student)
{{ $student->name }}
#endforech
#endif

Eloquent Query with Eager Loading

I want to perform an easy query with Eloquent.
I need to get all open tournament ( tournament->type = 1 ) that are in same country than me. Tournament has no country_id, but I need to do it with
$tournament->owner->country_id == Auth::user()->id
So, In my tournament table, I have a user_id that is the owner, and in my model, I have a working relation that get $tournament->owner
Here is my try ( doesn't work )
openTournaments = App\Tournament::with('owner')
->whereHas('owner', function ($query) {
$query->where('id', Auth::user()->country_id);
})
->where('type', config('constants.OPEN_TOURNAMENT'))
->get();
Any Idea how to fix it???
I'm not sure what your schema looks like, but assuming that the user has a country_id associated with it, and a tournament has an owner associated with it, you should be able to just do this:
openTournaments = App\Tournament::with('owner')
->whereHas('owner', function ($query) {
$query->where('country_id', Auth::user()->country_id);
})
->where('type', config('constants.OPEN_TOURNAMENT'))
->get();
Note country_id instead of id.

Laravel 4/5, order by a foreign column

In Laravel 4/5 how can order a table results based in a field that are connected to this table by a relationship?
My case:
I have the users that only store the e-mail and password fields. But I have an another table called details that store the name, birthday, etc...
How can I get the users table results ordering by the details.name?
P.S.: Since users is a central table that have many others relations and have many items, I can't just make a inverse search like Details::...
I would recommend using join. (Models should be named in the singular form; User; Detail)
$users = User::join('details', 'users.id', '=', 'details.user_id') //'details' and 'users' is the table name; not the model name
->orderBy('details.name', 'asc')
->get();
If you use this query many times, you could save it in a scope in the Model.
class User extends \Eloquent {
public function scopeUserDetails($query) {
return $query->join('details', 'users.id', '=', 'details.user_id')
}
}
Then call the query from your controller.
$users = User::userDetails()->orderBy('details.name', 'asc')->get();

laravel search many to many Relashionship

I am testing eloquent for the first time and I want to see if it suit my application.
I have Product table:
id, name
and model:
class Produit extends Eloquent {
public function eavs()
{
return $this->belongsToMany('Eav')
->withPivot('value_int', 'value_varchar', 'value_date');
}
}
and eav table:
id, name, code, field_type
and pivot table:
product_id, eav_id, value_int, value_varchar, value_date
class Eav extends Eloquent {
public function produitTypes()
{
return $this->belongsToMany(
'ProduitType'
->withPivot('cs_attributs_produits_types_required');
}
All this is working.
But I want to search in that relashionship:
e.g: all product that have eav_id=3 and value_int=3
I have tested this:
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
}))->get();
But I get all the product, and eav data only for these who have id=3 and value_int=3.
I want to get only the product that match this search...
Thank you
I know the question is very old. But added the answer that works in the latest versions of Laravel.
In Laravel 6.x+ versions you can use whereHas method.
So your query will look like this:
Produit::whereHas('eavs', function (Builder $query) {
// Query the pivot table
$query->where('eav_id', 3);
})->get()
My suggestion and something I like to follow is to start with what you know. In this case, we know the eav_id, so let's go from there.
$produits = Eav::find(3)->produits()->where('value_int', '3')->get();
Eager loading in this case isn't going to save you any performance because we are cutting down the 1+n query problem as described in the documentation because we are starting off with using find(). It's also going to be a lot easier to read and understand.
Using query builder for checking multiple eavs
$produits = DB::table('produits')
->join('eav_produit', 'eav_produit.produit_id', '=', 'produits.id')
->join('eavs', 'eavs.id', '=', 'eav_produit.eav_id')
->where(function($query)
{
$query->where('eav_produit.value_int','=','3');
$query->where('eavs.id', '=', '3');
})
->orWhere(function($query)
{
$query->where('eav_produit.value_int','=','1');
$query->where('eavs.id', '=', '1');
})
->select('produits.*')
->get();
Making it work with what you already have...
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
$query->orWhere('id', '1')->where('value_int', '1');
}))->get();
foreach($produits as $produit)
{
if(!produit->eavs)
continue;
// Do stuff
}
From http://four.laravel.com/docs/eloquent:
When accessing the records for a model, you may wish to limit your results based on the existence of a relationship. For example, you wish to pull all blog posts that have at least one comment. To do so, you may use the has method
$posts = Post::has('comments')->get();
Using the "has()" method should give you an array with only products that have EAV that match your criteria.
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
}))->has('eavs')->get();

Resources