#php #laravel #eloquent
#php #laravel #красноречивый
Вопрос:
У меня есть следующие красноречивые объекты:
- Фильм
- MovieSession
- MovieTheater
- Кинотеатральный зал
Структура таблицы:
Schema::create('movies', function (Blueprint $table) {
$table->increments('id');
});
Schema::create('movie_theaters', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->index();
$table->string('slug')->index()->unique();
$table->string('description')->index()->nullable();
$table->longText('content')->nullable();
$table->unsignedInteger('picture_id')->nullable();
$table->foreign('picture_id')
->references('id')
->on('media');
$table->boolean('activated')->default(true);
$table->timestamps();
});
Schema::create('movie_theater_rooms', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->index();
$table->string('description')->index()->nullable();
$table->longText('content')->nullable();
$table->boolean('activated')->default(true);
$table->unsignedInteger('movie_theater_id');
$table->foreign('movie_theater_id')
->references('id')
->on('movie_theaters')
->onDelete('cascade');
$table->unsignedInteger('picture_id')->nullable();
$table->foreign('picture_id')
->references('id')
->on('media');
$table->timestamps();
});
Schema::create('movie_sessions', function (Blueprint $table) {
$table->increments('id');
$table->dateTime('starts_in');
$table->dateTime('ends_in');
$table->unsignedInteger('movie_theater_room_id');
$table->foreign('movie_theater_room_id')
->references('id')
->on('movie_theater_rooms')
->onDelete('cascade');
$table->unsignedInteger('movie_id');
$table->foreign('movie_id')
->references('id')
->on('movies')
->onDelete('cascade');
$table->boolean('activated')->default(true);
$table->timestamps();
});
там, где в MovieTheater есть множество кинотеатров, в каждом кинотеатре есть множество сеансов фильмов, и каждый сеанс принадлежит фильму.
Что я пытаюсь, так это получить все фильмы, которые воспроизводятся сегодня на MovieTheater, по его $movieTheaterId
данным, но поскольку это длительное отношение, я не могу получить такую коллекцию.
Это то, что я пробовал:
public function scopeGetMoviesShowingTodayOnMovieTheater($movieTheaterId)
{
return Movie::whereHas('sessions', function ($query) use ($movieTheaterId) {
// $query->whereDate('starts_in', Carbon::today());
$query->whereHas('movieTheaterRoom', function ($query) use ($movieTheaterId) {
$query->where('movie_theater_id', $movieTheaterId);
});
});
}
При вызове AppModelsMovie::getMoviesShowingTodayOnMovieTheater(1)->get()
это то, что я получил:
Исправляемая неустранимая ошибка PHP: объект класса Illuminate /Database /Eloquent / Builder не удалось преобразовать в строку в …/vendor/illuminate/support/Str.php в строке 338
Я также пытался использовать этот пакет staudenmeir/eloquent-has-many-deep
следующим образом:
class MovieTheater extends Model {
use HasRelationships;
public function movies()
{
return $this->hasManyDeep(Movie::class, [MovieSession::class, MovieTheaterRoom::class]);
}
}
И при вызове AppModelsMovieTheater::find(1)->movies()->get()
Это результат:
Осветите / Database / QueryException с сообщением ‘SQLSTATE[42S22]: столбец не найден: 1054 неизвестных столбца ‘movie_sessions.movie_theater_id’ в ‘списке полей’ (SQL: выберите
movies
.*,movie_sessions
.movie_theater_id
изmovies
внутреннего соединенияmovie_theater_rooms
наmovie_theater_rooms
.id
=movies
.movie_theater_room_id
внутреннее соединениеmovie_sessions
наmovie_sessions
.id
=movie_theater_rooms
.movie_session_id
гдеmovie_sessions
.movie_theater_id
= 1)’
Где я ошибаюсь?
Комментарии:
1. Как выглядит ваша табличная структура?
2. Я добавил свои миграции к вопросу.
Ответ №1:
Исключение
Объект класса Illuminate /Database /Eloquent /Builder не удалось преобразовать в строку в …/vendor/illuminate/support/Str.php в строке 338
выдается, потому что вы не указали параметр $query в своем определении области видимости. Ваш код попытается преобразовать идентификатор кинотеатра в экземпляр Builder, что завершится неудачей.
Попробуйте реорганизовать свой код в соответствии с этим:
/**
* Scope a query to only select movies that are showing in a certain theater.
*
* @param IlluminateDatabaseEloquentBuilder $query
* @param int $movieTheaterId
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeGetMoviesShowingTodayOnMovieTheater($query, $movieTheaterId)
{
return $query
->whereHas('sessions.movieTheaterRoom', function ($query) use
($movieTheaterId) {
$query->whereMovieTheaterId($movieTheaterId);
});
}
Я также добавил точечную нотацию в whereHas
оператор для запроса вложенного отношения.
Комментарии:
1. Я все еще получаю ошибку:
PHP Recoverable fatal error: Object of class Illuminate/Database/Eloquent/Builder could not be converted to string in .../vendor/illuminate/support/Str.php on line 338
2. Вы получаете это исключение, потому что ваше определение области неверно, оно должно возвращать конструктор запросов. Смотрите обновленный ответ.
3. Но это то, что я возвращаю.
4. Просто следуйте примеру в этом ответе, укажите параметр $query в определении области видимости и определите идентификатор кинотеатра в качестве второго параметра.
5. Сработало как по волшебству! Можете ли вы оформить это как ответ, чтобы я мог пометить вопрос как отвеченный?
Ответ №2:
Если вы хотите использовать staudenmeir/eloquent-has-many-deep
, вы должны сделать порядок следующим образом
class MovieTheater extends Model {
use HasRelationships;
public function movies()
{
return $this->hasManyDeep(Movie::class, [MovieTheaterRoom::class, MovieSession::class]);
}
}