Laravel 5, How to get a collection of 2nd generation of children? - laravel-5

If I have the Grandparent, how do I get a single collection of its' parents' children?
Grandparent
`Class Grandparent extends Model
{
public function parents()
{
return $this->hasMany('\App\Parent');
}
}`
Parent
`Class Parent extends Model
{
public function grandparent()
{
return $this->belongsTo('\App\Grandparent');
}
public function children()
{
return $this->hasMany('\App\Child');
}
}`
Child
`Class Child extends Model
{
public function parent()
{
return $this->belongsTo('\App\Parent');
}
}`
A Collection of Collections could also work.

Related

Laravel relationship "fallback"

class Price extends Model {
public function priceable() {
return $this->morphTo();
}
}
class Venue extends Model {
public function events() {
return $this->hasMany('App\Event');
}
public function price() {
return $this->morphOne('App\Price', 'priceable');
}
}
class Event extends Model {
public function venue() {
return $this->belongsTo('App\Venue');
}
public function price() {
return $this->morphOne('App\Price', 'priceable');
}
}
What is the best way to have a fallback, if the event doesn't have a price assigned, to get it to use the event's venue price?
Is there a logical way to make this as a relation or should I just do everything in the Controllers?
You can set a default model with optional custom values directly from the relation. This default model can be populated either from an array or an anonymous function:
public function price()
{
return $this->morphOne('App\Price', 'priceable')->withDefault([...]);
}
You can refer to Laravel's documentation about default models for some more explanation.
class Event extends Model {
...
public function getEventPriceAttribute() {
return $this->price > 0 ? $this->price : $this->venue()->price
}
...
}
By doing this, you can call Event object and get the price like this:
$eventObject->eventPrice;

How in laravel to make a deep HasManyThrough?

I created a relationship like this:
Type.City.Street.House.Apartment
In this relation, the apartment must depend on the House and on the Type at the same time, so result sql query must be like this:
select * from `apartments` where `apartments`.`house_id` in ('1', '2', '3') and `type_id` = '777'
The problem is that the HasManyThrough relationship only looks at a two of levels and it's not possible to get to the very first model with it.
Please, advise how this can be done?
My models definations:
class Type extends Model {
public function city() {
return $this->hasMany('App\City');
}
}
class City extends Model {
public function street() {
return $this->hasMany('App\Street');
}
}
class Street extends Model {
public function house() {
return $this->hasMany('App\House');
}
}
class House extends Model {
public function Apartment() {
return $this->hasMany('App\Apartment');
//->where('type_id', '=' type.id) ?????
}
}
class Apartment extends Model {
public $fillable = ['house_id', 'type_id']
}
I would add a mapping for house_id in Apartment model and sets bidirectional mappings among your models
class Apartment extends Model {
public $fillable = ['house_id', 'type_id'];
public function house() {
return $this->belongsTo('App\House', 'house_id');
}
}
class Type extends Model {
public function city() {
return $this->hasMany('App\City');
}
}
class City extends Model {
public function type() {
return $this->belongsTo('App\Type', 'type_id');
}
public function street() {
return $this->hasMany('App\Street');
}
}
class Street extends Model {
public function city() {
return $this->belongsTo('App\City', 'city_id');
}
public function house() {
return $this->hasMany('App\House');
}
}
class House extends Model {
public function street() {
return $this->belongsTo('App\Street', 'street_id');
}
public function Apartment() {
return $this->hasMany('App\Apartment');
//->where('type_id', '=' type.id) ?????
}
}
then you can query apartments as per your criteria like
Apartments::whereHas('house.street.city.type', function ($query) use ($type_id) {
$query->where('id', '=', $type_id);
})
->whereHas('house', function ($query) use ($house_ids) {
$query->whereIn('id', $house_ids);
});
And i guess there is no need for type_id in Apartments model
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class Type extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function Apartment() {
return $this->hasManyDeep(Apartment::class, [City::class, Street::class, House::class])
->where('apartments.type_id', $this->id);
}
}
Unfortunately, this doesn't work with eager loading.

how can I show this combination with select?

models structure it looks like the following
class Attribute extends Model
{
public function products()
{
return $this->belongsToMany(Product::class);
}
public function attribute_options()
{
return $this->hasMany(AttributeOption::class);
}
}
class AttributeOption extends Model
{
public function attribute_option()
{
return $this->hasMany(CombinationDetail::class);
}
public function attribute(){
return $this->belongsTo(Attribute::class);
}
}
class Combination extends Model
{
public function combination_details()
{
return $this->hasMany(CombinationDetail::class);
}
}
class CombinationDetail extends Model
{
protected $fillable = ['attribute_options_id'];
public function attribute_options()
{
return $this->belongsTo(AttributeOption::class);
}
}
Relationship models like this.
combination table
combination_details table
how can i show this with selectbox or div with javascript

Laravel : how to get the list of element by the parent's parent

I have 3 layers of model relationships
the Grandparent Class
class GrandParent extends Model
{
protected $guarded = [];
public function parents()
{
return $this->hasMany('App\Parent');
}
public function childs()
{
return $this->hasManyThrough('App\Childs', 'App\Parent');
}
}
the parent Class
class Parent extends Model
{
public function grandParent() {
return $this->belongsTo('App\GrandParent', 'grandParent_id', 'id');
}
public function child()
{
return $this->hasMany('App\Child');
}
}
The child class
class Child extends Model
{
public function parent() {
return $this->belongsTo('App\Parent', 'parent_id', 'id');
}
}
i want to get list of Child by the grandParent ID
There is any way to get the list by simple Query
i am using laravel 5.5
thanks.
You need to add the grandparent_id and user_id from the user_table like below.
public function childs()
{
return $this->hasManyThrough('App\Childs', 'App\Parent','grandparent_id','parent_id','id','id');
}
In your Controller file.
$data = Grandparent::find($grandparent_id)->childs;

HasManyThrough with polymorphic and many-to-many relations

In my Laravel application I have the following classes:
class Product extends Model
{
public function extended()
{
return $this->morphTo();
}
public function users {
return $this->belongsToMany('App\User', 'products_users', 'product_id');
}
}
class Foo extends Model
{
public function product()
{
return $this->morphOne('App\Product', 'extended');
}
public function bars()
{
return $this->hasMany('App\Bar');
}
}
class Bar extends Model
{
public function product()
{
return $this->morphOne('App\Product', 'extended');
}
public function foo()
{
return $this->belongsTo('App\Foo');
}
}
class User extends Model
{
public function products()
{
return $this->belongsToMany('App\Product', 'products_users', 'user_id');
}
}
I can easily get users of a bar object using Bar::find(1)->product->users and I can also get the bars of a user with User::find(1)->products.
How can I get the users of all bars belonging to a specific foo? That is, Foo::find(1)->users should return all users that have the bars belonging to Foo with id 1. It's basically hasManyThrough with polymorphic and many-to-many relations.
Try something like this:
public function users()
{
$Foo = static::with(['bars', 'bars.products', 'bars.product.users'])->get();
return collect(array_flatten(array_pluck($Foo, 'bars.*.product.users')));
}
This should work for you (code has been tested, but not against the exact same structure as your setup). The first line will return all the users deeply nested through the relationships. The second line will pull out the users, flatten them into an array, then transform the array into a collection.
I created a HasManyThrough relationship for cases like this: Repository on GitHub
After the installation, you can use it like this:
class Foo extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function users() {
return $this->hasManyDeep(
User::class,
[Bar::class, Product::class, 'products_users'],
[null, ['extended_type', 'extended_id']]
);
}
}

Resources