Страница 1 из 1

hasOne: возвращение объекта, даже если связь отсутствует

Добавлено: 2018.08.10, 11:21
GHopper
Приветствую.

Есть некоторая модель Book, у нее есть связанная модель Discount

Код: Выделить всё

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getDiscount()
    {
        return $this->hasOne(Discount::className(), ['book_id' => 'id']);
    }
Эта связь $book->discount используется в шаблонах для построения форм. Есть один нюанс - у книги не всегда есть скидка, т.е. может быть такое, что модель Discount для какой-то книги просто не существуе.

Вопрос:
Как переписать метод getDiscount, чтобы он всегда возвращал объект Discount (если не найдена модель, то возвращается просто new Discount()). При этом этот метод должен дейстовать предсказуемо, т.е. при вызове $book->getDiscount() мы получаем AR-объект, а $book->discount сам объект Discount.

Re: hasOne: возвращение объекта, даже если связь отсутствует

Добавлено: 2018.08.10, 16:21
futbolim
Неправильная логика. Сделайте так:
$book->getDiscount() или $book->discount всегда указывает на объект связи таблицы discount. В $book->discount должен быть null при отсутствии связи. Там не нужен новый объект.
В зависимости от ситуации лучше создавайте новый объект отдельно, например, $new_discount. Или, если сильно хочется, добавьте поле в Книгу $book->newDiscount.
Управлять новым объектом можно в Book::afterFind(), Book::beforeValidate(), Book::afterSave() и остальных или где угодно (в контроллерах, поведениях, ...)

Re: hasOne: возвращение объекта, даже если связь отсутствует

Добавлено: 2018.08.10, 16:31
GHopper
Дело в том, что это не всегда удобно.

Во-первых, не хочу забивать таблицу discount путыми записями, чтобы всегда возвращался объект Discount по связи. Во-вторых, для формирования формы в представлении не хочу лишние условия "если есть связь, то давай ее, если связь пустая, то бери вот это". Проще переделать hasOne и всегда возвращать объект Discount. Сейчас, собственно, так и сделано, но проблема в том что этот метод вообще не умеет возвращать ActiveRecord-объект. А в оригинальном методе как-то сделано так, что $book->discount возвращает объект, а $book->getDiscount() возвращает ActiveRecord. Вот и я бы хотел сохранить эту логику в своем методе.

Re: hasOne: возвращение объекта, даже если связь отсутствует

Добавлено: 2018.08.10, 16:49
futbolim
"не хочу забивать таблицу discount путыми записями" - не забивайте.
Контроллер Вам в помощь для логики.

Re: hasOne: возвращение объекта, даже если связь отсутствует

Добавлено: 2018.08.10, 18:37
andku83
GHopper писал(а): 2018.08.10, 16:31 ... Во-вторых, для формирования формы в представлении не хочу лишние условия "если есть связь, то давай ее, если связь пустая, то бери вот это". ...
Для формирования подобной формы лучше сделать модель для формы и уже у нее можно прикрутить нужную вам логику, вот вам образец

Для редактирования подготовка выглядит так:

Код: Выделить всё

        $model = new UserForm();
        $model->setUser($this->findModel($id));

Re: hasOne: возвращение объекта, даже если связь отсутствует

Добавлено: 2018.08.10, 21:54
GHopper
andku83 писал(а): 2018.08.10, 18:37
GHopper писал(а): 2018.08.10, 16:31 ... Во-вторых, для формирования формы в представлении не хочу лишние условия "если есть связь, то давай ее, если связь пустая, то бери вот это". ...
Для формирования подобной формы лучше сделать модель для формы и уже у нее можно прикрутить нужную вам логику, вот вам образец

Для редактирования подготовка выглядит так:

Код: Выделить всё

        $model = new UserForm();
        $model->setUser($this->findModel($id));

Код: Выделить всё

    /**
     * @return UserProfile
     */
    public function getUserProfile()
    {
        if ($this->userProfile === null) {
            $this->userProfile = $this->getUser()->userProfile;
        }
        if ($this->userProfile === null) {
            $this->userProfile = new UserProfile();
        }
        return $this->userProfile;
    }
Вот и я так-же делаю сейчас. Но я думал есть более элегантное решение...