laravel eloquent relation for many tables - php

I am going to join 4 eloquent models using belongTo, hasMany, .... in laravel.
$result = \DB::select(
'ca.*',
array(DB::expr('CONCAT(u.first_name, " ", u.last_name)'), 'user'),
array(DB::expr('CONCAT(u.first_name, " ", u.last_name)'), 'full_name'),
array('u.id','user_id'),
array('d.name','department_name'),
array('d.clean_name','department_clean_name'),
array('d.id','department_id'),
array('u.extension','user_extension'),
array('u.mobile','user_mobile'),
array('u.email','email')
)
->from(array('case_assignments', 'ca'))
->join(array('departments', 'd'), 'left')->on('d.id','=','ca.department_id')
->join(array('users', 'u'), 'left')->on('u.id','=','ca.user_id')
->where('case_id','=', $case_id)
->get();
How can i change this to laravel eloquent relations?

Try this,
CaseAssignment Model:-
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CaseAssignment extends Model
{
public function department()
{
return $this->BelongsTo('App\Models\Department','department_id');
}
public function user()
{
return $this->BelongsTo('App\User','user_id');
}
}
Department Model:-
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Department extends Model
{
public function caseAssignments()
{
return $this->hasMany('App\Models\CaseAssignment');
}
}
User Model:-
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function caseAssignments()
{
return $this->hasMany('App\Models\CaseAssignment');
}
}
In Controller:-
$result = CaseAssignment::with('department','user')->where('case_id','=', $case_id)
->get();
dump($result->department->name);
dump($result->department->clean_name);
dump($result->department->id);
dump($result->user->extension);
dump($result->user->mobile);
dump($result->user->email);
dump($result->user->first_name.' '.$result->user->last_name);
dd($result);

Use relationships for this.
In CaseAssigment model add these 2 records
public function user() {
return $this->belongsTo(User::class);
}
public function department() {
return $this->belongsTo(Department::class);
}
And the query
$result = CaseAssigment::query()
->with([
'departament' => function($departaments){
$departament->select('id', 'name', 'clean_name');
},
'user' => function($users){
$user->select('id', DB::raw('CONCAT(first_name, last_name) AS full_name'), 'extension', 'mobile', 'email');
}
])
->where('case_id','=', $case_id)
->get();
I think you have one department and one user on CaseAssigment. If there are a lot of them, then tell me I will rewrite the request

Related

cannot retrieve Category model with related items

I have very strange error in my laravel website.
I try to retrieve Category model with related items, but looking at the error I see that laravel tries to retrieve items field from category model and of course it fails. But I am completely cannot understand why it happens, because I have the same code working well in other parts of my website.
routes/web.php
Route::name('gallery.')->prefix('gallery')->group(function () {
Route::get('/', 'GalleryController#index')->name('index');
Route::get('/{slug}', 'GalleryController#item')->name('item');
});
GalleryController
public function item($slug)
{
$category = $this->imageRepository->getCategoryWithPaginatedImages($slug, $perPage = 20);
return view('pages.gallery.item', compact('category'));
}
ImageRepository
namespace App\Repositories;
use Illuminate\Database\Eloquent\Collection;
use App\Models\ImageCategory as Model;
class ImageRepository extends CoreRepository
{
protected function getModelClass()
{
return Model::class;
}
public function getCategoryWithPaginatedImages($slug, $perPage = null)
{
$columns = ['id','title','slug','description','image','published','metatitle','metakey','metadesc'];
$result = $this
->startConditions()
->whereSlug($slug)
->select($columns)
->with('images:id,title,category_id,md,lg')
->firstOrFail()
->toArray();
$result = Arr::arrayToObject($result);
$result->items = collect($result->items)->mypaginate($perPage);
return $result;
}
}
Image
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
protected $guarded = [];
public function category() { return $this->belongsTo(ImageCategory::class); }
}
ImageCategory
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ImageCategory extends Model
{
protected $guarded = [];
public $timestamps = false;
public function images() { return $this->hasMany(ImageCategory::class, 'category_id'); }
}
so when I hit gallery/slug then getCategoryWithPaginatedImages gives me following error
Illuminate\Database\QueryException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'category_id' in 'field list' (SQL: select `id`, `title`, `category_id`, `md`, `lg` from `image_categories` where `image_categories`.`category_id` in (2))
I guess the relationship images on ImageCategory definition has an issue, should be as under
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ImageCategory extends Model
{
protected $guarded = [];
public $timestamps = false;
public function images()
{
return $this->hasMany(Image::class, 'category_id');
}
}

Call to undefined method App\Models\Comment::comments()

I wanted to add comment to every post I make but I keep on getting errors.
Comment Controller:
public function store(Request $request)
{
$comments = new Comment;
$comments->body =$request->get('comment_body');
$comments->user()->associate($request->user());
$blogs = Comment::find(1);
$blogs->comments()->save($comments);
return back();
}
Comment Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
use HasFactory;
protected $guarded =[];
public function blog()
{
return $this->belongsTo(Blog::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
Blog Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Blog extends Model
{
use HasFactory;
protected $fillable = ['user_id' , 'blog_category_id' , 'title' , 'description'];
public function user()
{
return $this->belongsTo(user::class);
}
public function blogcategory()
{
return $this->hasOne(BlogCategory::class)->withDefault(function($user , $post){
$user->name = "Author";
});
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
You are using the wrong model; the Blog model has the comments relationship not the Comment model:
$blog = Blog::find(...);
$blog->comments()->save(...);
Update:
You seem to want to be using a Polymorphic relationship it would seem based on the structure of your comments table since you have the fields commentable_id and commentable_type. If you check the documentation for the Polymorphic One to Many relationship this is the same as the example in the documentation:
Blog model:
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
Comment model:
public function commentable()
{
return $this->morphTo();
}
Laravel 8.x Docs - Eloquent - Relationships - Polymorphic Relationships - One to Many
Having said that, your Comment model doesn't look like you wanted to use a polymorphic relationship since you specifically had a blog relationship method. If you do not have more than 1 entity that needs to be related to Comment I would not be using a polymorphic relationship.

How can I get a pivot on my relationship in Laravel?

I have a relationship in my app. A candidate can have several "candidate_trainings" and each "candidate_training" is associated with a training. I wanted to avoid making "candidate_trainings" the piviot since it's hard to delete the right values when detaching, etc. So, how can I, on my hasMany relationship get the CandidateTraining model with the data from the Training model.
Here are my relationships:
<?php
namespace App;
use App\Traits\SanitizeIds;
use App\Salary;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Candidate extends Model
{
public function saveTraining($data) {
$this->candidateTrainings()->delete();
foreach(json_decode($data['training']) as $training) {
if(Training::find($training->training)->first()) {
$candidateTraining = new CandidateTraining;
$candidateTraining->description = $training->value;
$candidateTraining->training_id = $training->training;
$this->candidateTrainings()->save($candidateTraining);
}
}
}
public function candidateTrainings() {
return $this->hasMany('\App\CandidateTraining');
}
public function trainings() {
return $this->belongsToMany('\App\Training');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Training extends Model
{
protected $fillable = ['name_french', 'name_english'];
public function candidates() {
return $this->belongsToMany('\App\Candidate');
}
public function candidateTrainings() {
return $this->hasMany('\App\CandidateTraining');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CandidateTraining extends Pivot
{
public function candidate() {
return $this->belongsTo('\App\Candidate');
}
public function training() {
return $this->belongsTo('\App\Training');
}
}
Thank you!
For you to be able to update the data directly on the CandidateTraining model, you need to add the $fillable fields to it.
protected $fillable = ['training_id', 'description'];
Your code should work! But if you don't mind, I did a little refactoring. You can accomplish this in another way:
<?php
namespace App;
use App\Traits\SanitizeIds;
use App\Salary;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Candidate extends Model
{
public function saveTraining($data)
{
// remove all relationships
$this->trainings()->detach();
// add new ones
foreach(json_decode($data['training']) as $training)
{
if(Training::find($training->training)->first())
{
$this->trainings()->attach($training->training, [
'description' => $training->value,
]);
}
}
}
public function candidateTrainings()
{
return $this->hasMany(App\CandidateTraining::class);
}
public function trainings()
{
return $this->belongsToMany(App\Training::class)
->withTimestamps()
->using(App\CandidateTraining::class)
->withPivot([
'id',
'training_id',
'description',
]);
}
}
That $training->training stuff is not readable, change it to something like $training->id if you are able to.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Training extends Model
{
protected $fillable = ['name_french', 'name_english'];
public function candidates()
{
return $this->belongsToMany(App\Candidate::class)
->withTimestamps()
->using(App\CandidateTraining::class)
->withPivot([
'id',
'training_id',
'description',
]);;
}
public function candidateTrainings()
{
return $this->hasMany(App\CandidateTraining::class);
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CandidateTraining extends Pivot
{
protected $fillable = ['training_id', 'description'];
public function candidate()
{
return $this->belongsTo(App\Candidate::class);
}
public function training()
{
return $this->belongsTo(App\Training::class);
}
}
If you want to access the pivot object from a controller:
$candidates = Candidate::with(['trainings'])->get();
foreach ($candidates as $candidate)
{
dd($candidate->pivot);
}

Laravel Tables Join

I have three tables:
notes: id, business_id, note
businesses: id, title, description
businessimages : id, business_id, image
I get my customers notes with this:
$customer = Auth::guard('customer-api')->user();
$notes = Note::where('customer_id', $customer->id)->with('business:id')-
>orderBy('id', 'desc')->get();
Now I want to get notes.id, businesses.id, businesses.title, businesses.description, businessimages.image for each notes and show all of them in one json array
How could I do?
Note::where('customer_id',$customer->id)
->join('businesses', 'businesses.id', '=', 'notes.buisness_id')
->join('businessimages', 'businesses.id', '=', 'businessimages.buisness_id')
->select(notes.id, businesses.id, businesses.title, businesses.description,businessimages.image)
->get();
Note model;
public function business() {
return $this->hasOne('App\Business', 'business_id', 'id');
}
Business mode;
public function businessImage()
{
return $this->hasOne('App\BusinessImage', 'business_id', 'id');
}
Your controller;
$notes = Note::where('customer_id', $customer->id)->with('business.businessImage')->orderBy('id', 'desc')->get();
You should consider using API Resources
This is a great way to organize a model(or a collection of models as well).
App\Note
use Illuminate\Database\Eloquent\Model;
class Note extends Model
{
public function business()
{
return $this->belongsTo('App\Business');
}
}
App\Business
namespace App;
use Illuminate\Database\Eloquent\Model;
class Business extends Model
{
public function note()
{
return $this->hasOne('App\Note');
}
public function businessImage()
{
return $this->hasOne('App\BusinessImage');
}
}
App\BusinessImage
namespace App;
use Illuminate\Database\Eloquent\Model;
class BusinessImage extends Model
{
protected $table = 'businessimages';
public function business()
{
return $this->belongsTo('App\Business');
}
}
App\Http\Resources\Note
namespace App\Http\Resources;
class Note
{
public function toArray($request)
{
return [
'noteId' => $this->resource->id,
'businessId' => $this->resource->business->id,
'businessTitle' => $this->resource->business->title,
'businessDescription' => $this->resource->business->description,
'businessImage' => $this->resource->business->businessImage->image
];
}
}
Somewhere in a controller
use App\Http\Resources\Note as NoteResource;
public function foo()
{
$customer = Auth::guard('customer-api')->user();
$notes = Note::where('customer_id', $customer->id)->with(['business','business.businessImage'])->orderBy('id', 'desc')->get();
return NoteResource::collection($notes);
}

Laravel counting multilevel relations

I have Clients, which have Users, which have Surveys with a many-to-many table. So user_surveys.
I'm wondering how I can count some relations deep. I would like to the count of all surveys the users have for that client
What I've tried
Client.php
public function countSurveys()
{
$employees = $this->employees;
// this returns Property [surveys] does not exist on this collection instance.
return $employees->surveys->count();
// Method whereHas does not exist
return $employees->whereHas('surveys')->count();
}
This my employees method, which is a subset of Users
public function employees()
{
return $this->users()->whereHas('roles', function ($q) {
$q->where('name', 'employee');
});
}
And this is the User model
namespace App\Models;
use App\LoginToken;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
public function surveys()
{
return $this->belongsToMany(Survey::class, 'user_surveys', 'user_id', 'survey_id')
->withPivot('completed_on', 'status')
->withTimestamps();
}
public function journey()
{
return $this->belongsTo(Scan::class);
}
public function client()
{
return $this->belongsTo(Client::class);
}
}
It might be late, I might be confused and/or stupid.
Looking forward to your responses!
Another approach would be
$user = App\User::find(1);
return $user->surveys()->count();
Or try
$users = App\User::withCount('surveys')->get();
foreach($users as $user) {
$user->surveys_count;
}
Try this:
return $this->employees()->withCount('surveys')->get();
There is no native relationship for this case.
I created a HasManyThrough relationship with support for BelongsToMany: Repository on GitHub
After the installation, you can use it like this:
class Client extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function surveys() {
return $this->hasManyDeep(Survey::class, [User::class, 'user_surveys']);
}
}
$count = $client->surveys()->count();

Categories