Filtering collection by model custom method - php

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(){}

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';
});
}

How to add new method chaining for Laravel Eloquent?

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;
}
}

How can I filter this with eloquent

I try to filter SurveyQuestionnaire which have Answer = 'poor' and their Questionnaire have step = 'rating'.
I've tried to look through the documentation of Eloquent and I've found nothing help.
This is my models.
class Questionnaire extends Model {
...
public function surveysQuestionnaires() {
return $this->hasMany(SurveyQuestionnaire::class, 'question_id');
}
public function answers() {
return $this->hasMany(Answer::class, 'question_id');
}
public function questionnaires() {
return $this->hasMany(QuestionnaireTranslation::class, 'question_id' );
}
}
class SurveyQuestionnaire extends Model {
public function survey() {
return $this->belongsTo(Survey::class ,'survey_id');
}
public function questionnaires() {
return $this->belongsTo(Questionnaire::class, 'question_id');
}
public function answer() {
return $this->belongsTo(Answer::class, 'answer_id');
}
}
Well, the hasMany method returns query builder, so you can simply add some conditions:
public function surveysQuestionnaires() {
return $this->hasMany(SurveyQuestionnaire::class, 'question_id')->where('Answer', 'poor');
}
Also, you can read this link Constraining Eager Loads and add your conditions manually after taking an instance of your model:
$items = App\Questionnaire::with(['surveysQuestionnaires' => function ($query) {
$query->where('Answer', 'poor');
}])->get();

Retriving two models and order them by date

I'm trying to retrive the 20 most recent elements from two differents models Post and Link and rank them by the field created_at in descending order.
Here is the link class
class Link extends \Illuminate\Database\Eloquent\Model {
public $incrementing = false;
public function author() {
return $this->belongsTo('App\Models\Author');
}
public function category() {
return $this->belongsTo('App\Models\Category');
}
}
And here the post class
class Post extends \Illuminate\Database\Eloquent\Model {
public $incrementing = false;
public function author() {
return $this->belongsTo('App\Models\Author');
}
public function category() {
return $this->belongsTo('App\Models\Category');
}
}
How can I do that with eloquent (I'm using it outside Laravel, with Slim)?
use the below code to get recent records
orderBy('created_at', 'DESC')->get();
The merge method was the answer :
$posts = \App\Models\Post::where('draft', false)->orderBy('created_at', 'desc')->take(20)->get();
$links = \App\Models\Link::orderBy('created_at', 'desc')->take(20)->get();
$result = $posts->merge($links)->sortByDesc('created_at')->take(20);

Laravel return Illegal offset type when I trie return a model

I'm working with a large json that returns several data from the database and I need to return an integer model that does not have any kind of relationship, I just need to return all the records that LampModels model with this great json. But Laravel always returns me Illegal offset type.
Controller
public function showAllUdiJson()
{
$allLamps = LampModels::all();
return Ilumination::with('street')
->with('neighborhood')
->with('iluminationinfo')
->with('economyplan')
->with('lamp')
->with('reactor')
->with('aluminumcable')
->with('steelconduit')
->with('alllamps', $allLamps)
->with('ticket')->get();
}
LampModels
<?php
class LampModels extends \Eloquent {
protected $fillable = [];
protected $table = 'lampmodel';
}
Illumination
<?php
class Ilumination extends \Eloquent {
protected $fillable = [];
protected $table = 'ilumination';
public function street()
{
return $this->belongsTo('street');
}
public function neighborhood()
{
return $this->hasOne('neighborhood', 'id');
}
public function iluminationinfo()
{
return $this->hasOne('iluminationinfo');
}
public function ticket()
{
return $this->hasMany('ticket');
}
public function economyplan()
{
return $this->hasOne('economyplan', 'id' ,'street_id');
}
public function lamp()
{
return $this->hasOne('lamp', 'id');
}
public function reactor()
{
return $this->hasOne('reactor', 'id');
}
public function aluminumcable()
{
return $this->hasOne('aluminumcable', 'id');
}
public function steelconduit()
{
return $this->hasOne('steelconduit', 'id');
}
}
See the error
Your error report is quite bad, but seems that your Ilumination model doesnt have an alllamps method.
You should attacth LampModels to your Ilumination model with a relationship, insted of doing what you doing, cause is a wrong approach.
I think you access somewhere ticket method which was created in Illumination Model that offset error encountered..
public function ticket()
{
return $this->hasMany('ticket');
}
if you want to access illumination->ticket, you must use this method with loop.
foreach(illumination->tickets as ticket) {
$field1 = ticket->field1;
}
If your still facing any issue than share your error log page here..

Categories