How to add new method chaining for Laravel Eloquent? - php

I try to add new method for simplify and reusable code but I failed
User Model :
public function products()
{
return $this->hasMany('App\Product');
}
public function obsolate()
{
return $this->where('status', 'obsolate');
}
When I try to retrieve like auth()->user()->products()->obsolate() it gives some error like
BadMethodCallException: Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::obsolate()
But If I do like auth()->user()->products()->where('status', 'obsolate')->get() It works.
Please, correct me if I wrong...
UPDATE
Product Model :
public function user()
{
return $this->belongsTo('App\User');
}
public function scopeObsolate($query)
{
return $query->where('status', 'obsolate');
}
I do auth()->user()->products->obsolate()->get() and it works!
But, if I want to use constraint group to solve this problem it will return error
public function scopeObsolate(Builder $builder)
{
return $builder->where(function (Builder $query) {
return $query->where('status', 'obsolate');
});
}
Argument 1 passed to App\Product::App{closure}() must be an instance of App\Builder, instance of Illuminate\Database\Eloquent\Builder given
SOLVED
use Illuminate\Database\Eloquent\Builder

Because products() method return Illuminate\Database\Eloquent\Relations\HasMany object. When you applying where to it, laravel will set the constraints on the relation query(It means Product eloquent builder). So you need to defined the method in Product model.
And change the obsolate method to scope method:
// Product model:
public function scopeObsolate($query)
{
return $query->where('status', 'obsolate');
}
Update:
The second error occurs because the type-hint, laravel cannot find the Builder in model. You need to
use Illuminate\Database\Eloquent\Builder

I am not using Laravel, but:
Your ->where/->hasMany seems to return different (internal) object that does not contain your custom method.
To chain properly, return $this only:
class FooBar extends \Illuminate\Database\Eloquent
{
public function products()
{
$this->hasMany('App\Product');
return $this;
}
public function obsolate()
{
$this->where('status', 'obsolate');
return $this;
}
}

Related

Laravel - Model Eloquent without relationships

i trying to load all rows from a model without the relationship.
The attributes $with it not event set on my Event model but when i do
$events = Event::all();
all my relationship are loaded, and i can see all the query with the dbquerylog.
i don't understand why theses relationship are loaded,
Please help me !
Thanks you.
I'm using Laravel 8.
here's an example.
class Event extends Model {
public function items() {
return $this->hasMany(Item::class);
}
public function items2() {
return $this->hasMany(Item2::class);
}
public function items3() {
return $this->hasMany(Item3::class);
}
public function items4() {
return $this->hasOne(Item4::class);
}
}
$events = Event::all();
If you have a single instance of a model object, you can do:
$obj->withoutRelations();
As laravel documentations says you can use without: https://laravel.com/docs/8.x/eloquent-relationships
Model
protected $with = ['item1','item2','item3','item4'];
Controller
$events = Event::without(['item1','item2','item3','item4'])->get();
I met this problem one day, and it turned out that I was using relation in scope method. Because of this relation values were added to response.
Check out this example:
class Event extends Model {
public function items() {
return $this->hasMany(Item::class);
}
[...]
public function scopeItemsGreen() {
return $this->items->every(function ($item) {
return $item->color == 'green';
});
}

Filtering collection by model custom method

I'm using Laravel for a project and i want to filter a collection based on custom method written in the model:
Controller:
$models= Produs::with('categorie')
->with('poza')
->with('element_extra.extras')
->get()
->where('id_stare', 1)
->where('categorie.id_restaurant', $idRestaurant)
->groupBy('categorie.denumire');
$produse = $models->filter(function ($produs, $key) {
return $produs->isAvailable();
})->values();
Model:
class Produs extends Model
{
protected $table = "elemente";
public $timestamps = false;
public function isAvailable(){
if(...something....){
return false;
}else{
return true;
}
}
This is what i get:
BadMethodCallException
Method Illuminate\Database\Eloquent\Collection::isAvailable does not exist.
You need to add keyword scope to your method
public function scopeIsAvailable($query) {
return $query->where('active', true);
}
and after that call it like this
$models= Produs::isAvailable()...
:: double colon usage is for static functions.
try to use
public static function isAvailable(){}

How to fix the relationship problem of "Property [id] does not exist" problem

I have three model 1. Task.php 2. Project.php 3. User.php.
Task have a one to many relationship with user and project.php.
Task.php
public function project()
{
return $this->belongsTo(Project::class);
}
public function user()
{
return $this->belongsTo(User::class,'member_id');
}
User.php
public function tasks()
{
return $this->hasMany(Task::class);
}
Project.php
public function tasks()
{
return $this->hasMany(Task::class);
}
Nowi want to retrieve all the task that is associated with users where project id is one (Actually not one, id is passed through url).Here is my attempt
public function taskList($id)
{
$project=Project::with('tasks')->find($id);
$tasks=Task::has('user')->whereHas('project',function($project){
$project->where('id',$project->id);
})->get();
dd($tasks);
return view('leader.tasks',compact('project'));
}
In the above either i give the $id which is i get from the url either $project->id, it always through me the error.Please help me to solve this.
public function taskList($id)
{
$project=Project::with('tasks')->find($id);
$tasks=Task::has('user')->whereHas('project', function($query) use ($project) {
$query->where('id', $project->id);
})->get();
dd($tasks);
return view('leader.tasks',compact('project'));
}
You need to use with() method along with has()
public function taskList($id)
{
$project=Project::with('tasks')->find($id);
$tasks=Task::with('user')->has('user')->whereHas('project', function($query) use ($project) {
$query->where('id', $project->id);
})->get();
dd($tasks);
return view('leader.tasks',compact('project'));
}

getRouteByKeyName another model laravel

I have two models:
Categories
CategoriesTranslations
In model categories I writed:
public function getRouteKeyName(){
return 'alias';
}
Column alias belogns model CategoriesTranslations.
How I can return alias from model CategoriesTranslations?
My code is not working.
I tryed:
Add getRouteKeyName on CategoriesTranslations:
public function getRouteKeyName(){
return 'alias';
}
And in Categories add:
public function categoryTranslations() {
return $this->hasOne(CategoriesTranslations::class);
}
public function getRouteKeyName() {
return $this->categoryTranslations->getRouteKeyName();
}
I get error Call to a member function getRouteKeyName() on null When want show category by getRouteKeyName. How fix it?
You must use relationships between Categories and CategoriesTranslations.
In your Categories model:
public function categoriesTranslations()
{
return $this->hasMany(CategoriesTranslations::class);
}
public function getRouteKeyName()
{
$this->categoryTranslations->where('locale', Auth::user()->locale)->first()->getRouteKeyName();
}
Now you can call getRouteKeyName() from any instance of the Categories model and it will pull it from the CategoriesTranslations table.
** The potential fix here was adding in the where() statement and the first() method. Change the Auth::user()->locale to wherever you are storing which locale to use.

Laravel morphedByMany Query Returns NULL

I have this model
class Permission extends Model
{
public function details(): MorphToMany
{
return $this->morphedByMany('App\Models\Details', 'model', 'model_has_permissions', 'permission_id', 'model_id');
}
}
class Details extends Model
{
public function permission()
{
return $this->morphedByMany('App\Models\Permission','model','model_has_permissions','model_id','permission_id');
}
}
I'm execute this query
Details::with('permission')->find(55);
and got empty array
why happen this?and what is the correct query?
You have a typo in your permission() method
change this
return $this->morphedByMany('App\Models\Permission','model','.model_has_permissions','model_id','permission_id');
to this
return $this->morphedByMany('App\Models\Permission','model','model_has_permissions','model_id','permission_id');
I don't think it's possible to chain find after with. Here are your options.
Lazy Loading.
Details::find(55)->load('permissions');
Eager loading with where clause
Details::with('permissions')->where('id', 55)->get();
UPDATE
Shouldn't this be morphToMany?
public function details(): MorphToMany
{
return $this->morphedByMany('App\Models\Details', 'model', 'model_has_permissions', 'permission_id', 'model_id');
}
Or this?
public function permission()
{
return $this->morphedByMany('App\Models\Permission','model','model_has_permissions','model_id','permission_id');
}

Categories