Как в ларавеле сделать глубокий HasManyThrough?

Я создал такие отношения:

Type.City.Street.House.Apartment

В этом отношении квартира должна зависеть от Дома и от Типа одновременно, поэтому результат sql-запроса должен быть таким:

select * from `apartments` where `apartments`.`house_id` in ('1', '2', '3') and `type_id` = '777'

Проблема в том, что отношение HasManyThrough рассматривает только два уровня, и с его помощью невозможно добраться до самой первой модели.

Посоветуйте, пожалуйста, как это можно сделать?

Мои определения моделей:

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']
}

Опубликуйте определения вашей модели

M Khalid Junaid 21.05.2018 12:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
0
1
88
2

Ответы 2

Я бы добавил отображение для house_id в модели Apartment и установил двунаправленные сопоставления между вашими моделями.

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) ?????
    }
}

тогда вы можете запросить апартаменты в соответствии с вашими критериями, например

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

И я думаю, что в модели type_id нет необходимости в Apartments.

Спасибо. Не OP, но я не знал о том, где такая цепочка. Вы только что помогли мне упростить кучу кода!

Nick 21.05.2018 23:54

Я создал отношения HasManyThrough с неограниченным количеством уровней: Репозиторий на GitHub

После установки вы можете использовать его так:

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

К сожалению, это не работает с активной загрузкой.

Ух ты! Большой! Я попробую это в ближайшее время

kakero 16.07.2018 14:14

Другие вопросы по теме