FindOrFail
FindOrFail
Давно интересует вопрос: как справляться без findOrFail? Я имею ввиду то что разработчики Yii упорно отказываются добавлять в ORM методы которые кидают исключение при не найденной модели (якобы это нарушает какие-то паттерны, хотя AR сама по себе является антипаттерном). Писать повсюду сотни проверок на null и вручную кидать 404 - нереально (будет просто охренительное захламление кода, превращая его в нечитабельное гавно). Так что у меня например это вообще игнорируется и падает с NullReferenceException в местах использования модели. Знаю что это ненормально, но не знаю как быть по другому...
Re: FindOrFail
сделайте свой промежуточный SuperActiveRecord и в нем добавьте этот метод, и все все свои классы наследуйте от вашего нового.
Re: FindOrFail
1) Создаёте класс ActiveQueryExtended, отнаследованный от ActiveQuery;
2) переопределяете в нём все поисковые методы (->one(), ->all() и т.п., чтобы результат выполнения проверялся и кидалось исключение);
3) создаёте класс ActiveRecordExtended отнаследованный от ActiveRecord;
4) добавляете в нём метод findOrException() (можно конечно и родной find() переопределить, но чревато, ибо не во всех 100% случаев нужны исключения). В этом методе создаёте и возвращаете экземпляр ActiveQueryExtended на основе класса модели;
5) наследуете свои модели от ActiveRecordExtended.
Re: FindOrFail
Черт. Вот почему я должен делать столько лишних действий если в других фреймворках это есть из коробки? Кстати может есть уже какие-нибудь готовые врапперы над Yii такого типа? Чтоб композером подцепить и все.Alexum писал(а): ↑2018.05.31, 15:291) Создаёте класс ActiveQueryExtended, отнаследованный от ActiveQuery;
2) переопределяете в нём все поисковые методы (->one(), ->all() и т.п., чтобы результат выполнения проверялся и кидалось исключение);
3) создаёте класс ActiveRecordExtended отнаследованный от ActiveRecord;
4) добавляете в нём метод findOrException() (можно конечно и родной find() переопределить, но чревато, ибо не во всех 100% случаев нужны исключения). В этом методе создаёте и возвращаете экземпляр ActiveQueryExtended на основе класса модели;
5) наследуете свои модели от ActiveRecordExtended.
Re: FindOrFail
Другие фреймворки - это Laravel, по-видимому.
Re: FindOrFail
Если только findOrFail необходим, то можно даже трейтом обойтись
И примешивайте к своим моделям.
Код: Выделить всё
trait ExceptionOnFindFail {
public static function findOrFail($param) {
if (($res = static::findOne($param)) === null) {
throw new NotFoundHttpException();
}
return $res;
}
}
Re: FindOrFail
Не только. ActiveQuery->oneOrFail тоже бы не помешал. По сути только эти два и нужны - т.к. для массивов и так нормально когда пустой массив возвращается. Т.е. итерация по нему не вызовет ошибки, а просто ничего не произойдет.mkramer писал(а): ↑2018.05.31, 16:20 Если только findOrFail необходим, то можно даже трейтом обойтисьИ примешивайте к своим моделям.Код: Выделить всё
trait ExceptionOnFindFail { public static function findOrFail($param) { if (($res = static::findOne($param)) === null) { throw new NotFoundHttpException(); } return $res; } }
Re: FindOrFail
Ну сделайте ещё свой ActiveQuery или примесь/поведение для него. Всё равно ActiveQuery почти всегда переопределяется даже в простых проектах
Re: FindOrFail
Как показывали выше - это довольно не простое занятие переопределять ActiveQuery, т.к. тогда придется все методы AR переопределять чтобы они мою реализацию использовали. И я ни разу не видел чтобы кто-то его переопределял. С чего вы такое взяли я без понятия.
Re: FindOrFail
Хорошо бы чтобы тут отписался кто-нибудь из разработчиков Yii. Так сказать хочется посмотреть в глаза человеку заставляющему так страдать своих пользователей.
Re: FindOrFail
Мне так и не ответили по сути: как вы справляетесь без такого метода? Если не говорить о переопределении всего этого барахла (т.к. я слабо верю что кто-то реально этим занимается). Ставите овер 100500 проверок и вручную кидаете исключения? Игнорите это как я? Или как-то еще?
Re: FindOrFail
Ну я руками или как gii генерит отдельный метод. Мне три лишние строчки не трудно написать.
Переопределить ActiveQuery, чтоб добавить туда oneOrFail() - очень просто. И я его всегда переопределяю, поскольку scopes вынесены в Yii туда, и я предпочитаю писать Model::find()->newest(10)->all() вместо Model::find()->orderBy(["dt" => SORT_DESC])->limit(10)->all()
https://www.yiiframework.com/doc/guide/ ... ry-classes
Переопределить ActiveQuery, чтоб добавить туда oneOrFail() - очень просто. И я его всегда переопределяю, поскольку scopes вынесены в Yii туда, и я предпочитаю писать Model::find()->newest(10)->all() вместо Model::find()->orderBy(["dt" => SORT_DESC])->limit(10)->all()
Вот ничего подобного. Вcё работает через ActiveRecord::find(), поэтому переопределить достаточно его, и об этом написано в документации, которую я прочёл первым делом, когда перешёл на Yii2 с Kohana.т.к. тогда придется все методы AR переопределять чтобы они мою реализацию использовали
https://www.yiiframework.com/doc/guide/ ... ry-classes
Re: FindOrFail
зачем Alexum посоветовал кидать исключение из all() - не знаю, честно говоря
Re: FindOrFail
Нет высокой активности в сторону этой фичи: https://github.com/yiisoft/yii2/issues/15937
Пообсуждали и забили.
Пообсуждали и забили.
Re: FindOrFail
mkramer оказался прав - переопределить не так уж сложно:
Ладно сойдет. Придется правда это таскать за собой в другие проекты...
Код: Выделить всё
class ActiveQuery extends \yii\db\ActiveQuery {
public function oneOrFail(string $message = null, ?Connection $db = null) {
$value = $this->one($db);
if (is_null($value))
throw new NotFoundHttpException($message);
return $value;
}
}
class ActiveRecord extends \yii\db\ActiveRecord {
public static function find(): ActiveQuery {
return \Yii::createObject(ActiveQuery::class, [get_called_class()]);
}
public static function findOneOrFail($condition, string $message = null) {
$value = static::findOne($condition);
if (is_null($value))
throw new NotFoundHttpException($message);
return $value;
}
}
Re: FindOrFail
Таскать лучше трейтами. Вдруг не от ActiveRecord надо будет унаследоваться