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

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
GHopper
Сообщения: 75
Зарегистрирован: 2017.06.05, 10:53

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

Сообщение GHopper » 2018.08.10, 11:21

Приветствую.

Есть некоторая модель 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.

Аватара пользователя
futbolim
Сообщения: 1951
Зарегистрирован: 2012.07.08, 19:28
Откуда: Донецк

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

Сообщение futbolim » 2018.08.10, 16:21

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

GHopper
Сообщения: 75
Зарегистрирован: 2017.06.05, 10:53

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

Сообщение GHopper » 2018.08.10, 16:31

Дело в том, что это не всегда удобно.

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

Аватара пользователя
futbolim
Сообщения: 1951
Зарегистрирован: 2012.07.08, 19:28
Откуда: Донецк

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

Сообщение futbolim » 2018.08.10, 16:49

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

andku83
Сообщения: 680
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

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

Сообщение andku83 » 2018.08.10, 18:37

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

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

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

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

GHopper
Сообщения: 75
Зарегистрирован: 2017.06.05, 10:53

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

Сообщение GHopper » 2018.08.10, 21:54

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;
    }
Вот и я так-же делаю сейчас. Но я думал есть более элегантное решение...

Ответить