Select item by specific property - laravel

I'm working in Laravel 4, I can my models simplify to these:
class DayVariant extends \Eloquent {
public function chod()
{
return $this->belongsTo('Chod', 'chod_id');
}
}
class Chod extends \Eloquent {
public function meals()
{
return $this->belongsToMany('Meal');
}
}
class Meal extends \Eloquent {
public function mealProperties()
{
return $this->hasMany('MealsProperty');
}
}
class MealProperty extends \Eloquent {
public function propertyType()
{
return $this->belongsTo('PropertyType', 'property_type_id');
}
}
And I want select MealProperty by property_type_id. I was doing it this way:
$prop = $dayVariant->chod->meals->first()->mealProperties()->where('property_type_id','=', $foo)->first();
I need in this way get 5 from 70 the same mealsProperties for every meal. It works well, but I don't know how use eager loading for decreasing queries to database.
$dayVariant = DayVariant::with('breakfastChod.meals.mealProperties')->first();
I can do it this way and after it iterate over all mealProperties, but I'm looking for better way.
Maybe with constraints I can get only mealProperties which I will need and iterate over them.
Is there better way to get specific properties? If not, how can use constraints with my models?
I tried this, but it fails.
$dayVariant = DayVariant::whereHas('breakfastChod.meals.mealProperties', function($query)
{
$query->where('property_type_id', '=', $constants['nutr_ids']['kcal']);
})->first();
Thanks for every answer!

You can do it in the context of property or like you tried of dayVariant:
// starting from properties
$properties = MealProperty::whereIn('property_type_id',$foo)
->with('meal.chods.dayVariants')->get();
// or from dayVariant
$dayVariant = DayVariant::with(['chod.meals.mealProperties' => function ($q) use ($foo) {
$q->whereIn('property_type_id', $foo);
}])->first();

Related

How to get data from table related through pivot table?

I have 4 tables: countries, activities, country_activities and packages.
countries and activities are related through pivot table country_activity, and packages is related to country_activity.
Now, How do I eager load all packages related to each activity in a country?
class Country extends Model
{
public function activities() {
return $this->belongsToMany('App\Models\Activity','country_activities')->using('App\Models\CountryActivity')->as('country_activities');
}
}
class Activity extends Model
{
public function countries() {
return $this->belongsToMany('App\Models\Country','country_activities')->using('App\Models\CountryActivity')->as('country_activities');
}
}
class Package extends Model
{
public function country_activities() {
return $this->belongsToMany('App\Models\CountryActivity');
}
}
class CountryActivity extends Pivot
{
protected $table = 'country_activities';
public function packages() {
return $this->hasMany('App\Models\Package');
}
}
So, this worked for me.
class Country extends Model
{
public function activities() {
return $this->belongsToMany('App\Models\Activity','country_activities')->using('App\Models\CountryActivity')->withPivot(['id'])->as('country_activities');
}
Now, In my controller, I do this
$country = Country::with(['activities'=> function($q) {$q->where('name','Trekking');}])->where('name','Nepal')->first(['id','name']);
$country->activities->map(function ($i){
$i->country_activities->load('packages');
return $i;
});
I did something similar in a project i worked on. I'm not sure it will work but it's worth the shot:
$country = Country::find(1);
$country->activities = $contry->activities()->get()->each(function ($i, $k){
$i->packages = $i->pivot->packages;
//$i->makeHidden('pivot'); -> This is useful if you want to hide the pivot table
});
var_dump($country);

Laravel 5.7 getting all the siblings for each child

I wonder how to get all the sibling that a child have in laravel model ?
I know i can use this $siblings = \App\Child::all()->where('parent_id', $parent_id)->where('id', $id); to get all the child siblings, but I want to know if I can do the other way or more cleanest way?
So you can call this in the blade view $child->siblings->full_name something like that.
But I wonder how to use it something like this in the model.php
public function parent()
{
return $this->belongsTo(User::class);
}
with only using the belongsTo or hasMany function maybe if it's possible?
Sorry I'm not good with english so I don't know what it's called so I can search it on google.
Edit:: Adding Child.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Child extends Model
{
protected $guarded = [];
protected $dates = [
'birthdate',
'father_birthdate',
'mother_birthdate',
'guardian_birthdate',
];
public function parent()
{
return $this->belongsTo(User::class);
}
// I want to call this function only using $child->siblings (this one will show all the siblings)
// without passing the parent id
// to make it cleaner
public function siblings($parent_id)
{
return $this->all()->where('parent_id', $parent_id);
}
public function getAgeAttribute()
{
return Carbon::parse($this->attributes['birthdate'])->age;
}
public function getFullNameAttribute()
{
return $this->attributes['first_name'] . ' ' . $this->attributes['last_name'];
}
}
There are 2 ways you could do this.
1 creating the below method:
public function sibling()
{
return $this->belongsTo(User::class)->where('parent_id', $this->parent_id);
}
2 using a single Query:
$siblings = \App\Child::where('parent_id', $parent_id)->get();
Hope this helps
Update
A third way is:
public function scopeSiblings($query, $parent_id) {
return $query->where('parent_id', $parent_id)->get();
}

join table in laravel

I have 3 table in laravel:
class General extends Mode
{
public function populars()
{
return this->hasMany('App\Popular');
}
}
enter code here
and
class Popular extends Model
{
public function general()
{
return this->belongsTo('App\General');
}
}
and
class Specific extends Model
{
public function popular(){
return this->belongsTo('App\Popular');
}
}
...
how to join tables and return this list result:
1. generals
2.popular
3.Specific
I assume Popular has many Specific, you could add another mapping in Popular model as
class Popular extends Model
{
public function general()
{
return this->belongsTo('App\General');
}
public function specific()
{
return this->hasMany('App\Specific');
}
}
Doing with eloquent way you could write it as
$generals = General::with('populars.specific')->get();
Using query builder you could join them as
DB::table('general as g')
->join('popular as p', 'g.id','=','p.general_id')
->join('specific as s', 'p.id','=','p.popular_id')
->get();

Laravel - how to makeVisible an attribute in a Laravel relation?

I use in my model code to get a relation
class User extends Authenticatable
{
// ...
public function extensions()
{
return $this->belongsToMany(Extension::class, 'v_extension_users', 'user_uuid', 'extension_uuid');
}
// ...
}
The Extension has field password hidden.
class Extension extends Model
{
// ...
protected $hidden = [
'password',
];
// ...
}
Under some circumstances I want to makeVisible the password field.
How can I achieve this?
->makeVisible([...]) should work:
$model = \Model::first();
$model->makeVisible(['password']);
$models = \Model::get();
$models = $models->each(function ($i, $k) {
$i->makeVisible(['password']);
});
// belongs to many / has many
$related = $parent->relation->each(function ($i, $k) {
$i->makeVisible(['password']);
});
// belongs to many / has many - with loading
$related = $parent->relation()->get()->each(function ($i, $k) {
$i->makeVisible(['password']);
});
Well, I got the idea from https://stackoverflow.com/a/38297876/518704
Since my relation model Extension::class is called by name in my code return $this->belongsToMany(Extension::class,... I cannot even pass parameter to it's constructor.
So to pass something to the constructor I may use static class variables.
So in my Extension model I add static variables and run makeVisible method.
Later I destruct the variables to be sure next calls and instances use default model settings.
I moved this to a trait, but here I show at my model example.
class Extension extends Model
{
public static $staticMakeVisible;
public function __construct($attributes = array())
{
parent::__construct($attributes);
if (isset(self::$staticMakeVisible)){
$this->makeVisible(self::$staticMakeVisible);
}
}
.....
public function __destruct()
{
self::$staticMakeVisible = null;
}
}
And in my relation I use something like this
class User extends Authenticatable
{
...
public function extensions()
{
$class = Extension::class;
$class::$staticMakeVisible = ['password'];
return $this->belongsToMany(Extension::class, 'v_extension_users', 'user_uuid', 'extension_uuid');
}
...
}
The highest voted answer didn't seem to work for me (the relations attribute seems to be a protected array now so can't be used as a collection in #DevK's answer), I instead used:
$parent->setRelation('child', $parent->child->first()->setVisible(['id']));

Laravel condition for secondary table

Mode Position.php has following code.
class Position extends \Eloquent {
public static function get_position_by_url($url) {
return Position::where('url','=',$url)->where('status','=','0')->with('message')->get();
}
public function message() {
return $this->hasMany('Message');
}
}
The above code works fine, What I need is to get data by condition in messages table, like following:
class Position extends \Eloquent {
public static function get_position_by_url($url,$screenSize) {
return Position::where('url','=',$url)->where('status','=','0')->with('message')->where('screensize','=',$screensize)->get();
}
public function message() {
return $this->hasMany('Message');
}
}
But the both conditions are applied to positions table, which I want to apply second condition to messages table.
You can filter eager loaded models by passing a closure:
return Position::where('url','=',$url)->where('status','=','0')->with(['message' => function($q) use ($screensize){
$q->where('screensize','=',$screensize);
}])->get();
Like documented here under Eager Loading Constraints

Resources