Оценка кода

grigori

( ͡° ͜ʖ ͡°)
Команда форума
@hell0w0rd, взгляд неплохо бы аргументировать, а то у нас все эксперты в политике, футболе и медицине, кроме, соответственно, политиков, футболистов и врачей
 

hell0w0rd

Продвинутый новичок
Гм. Ошибка улетает куда-то и кто-то ее обрабатыает, это работает не явно.
Код:
try {
  ...
} catch (e) {
  return new ErrorResponse(e);
}
вот так лучше. Понятно где и что происходит.
 

Вурдалак

Продвинутый новичок
> разнести этот mapping по конфигам, аннотациям.
а симфони умеет по аннотациям передать exception в соответствующий обработчик?
Я не думаю, что такое есть из коробки, но вроде это несложно делается. Нужно повесить на событие GetResponseForExceptionEvent штуку, которая по типу исключения достанет метаинформацию из конфига об HTTP-статусе, возможном обработчике и т.д.
 

Вурдалак

Продвинутый новичок
Гм. Ошибка улетает куда-то и кто-то ее обрабатыает, это работает не явно.
Код:
try {
  ...
} catch (e) {
  return new ErrorResponse(e);
}
вот так лучше. Понятно где и что происходит.
Чем же это лучше? У тебя в каждом action'е будет такой код. А если ты попытаешься указывать конкретный тип исключения, то ты столкнешься с проблемами, которые я описал выше.
 

Adelf

Administrator
Команда форума
Мне сам подход не нравится, когда ошибки улетают куда-то за пределы контроллера.
Есть такой принцип. Single Responsibility называется. Controller just controls the request processing flow. Обработка ошибок не его забота. Это забота, как ни странно, товарища по имени Error Handler. Не люблю все эти слова mvc hmvc... юзайте SRP и будет легко и приятно, имхо. И Laravel я люблю именно за то, что он легок для следования SRP.

@Adelf, а если типов entity много? Т.е. не только Client как в примере, и для всех надо выдавать осмысленное сообщение об ошибке, например, надо вывести не "Запись не найдена", а "Пользователь не найден", "Товар не найден" и т.д.? В таких случаях все перехватывать в одном месте для всех типов?
Помоему, ты процедурно мыслишь немного. В самом простейшем случае у Exception есть message. В случаях посложнее можно ClientNotFoundException, etc. насоздавать. и там по соглашениям, ключи для локализированного вывода ошибок. Или если уж совсем не вмешивать в модель такую инфу, да - делай маппинг вроде - ClientNotFoundException -> client_not_found -> локализация сообщения и вывод. Это лишь только вариант. Возможностей много.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Гм. Ошибка улетает куда-то и кто-то ее обрабатыает, это работает не явно.
try catch лучше. Понятно где и что происходит.
"Явное лучше, чем неявное." Уже было. Однако, развитие программирования всегда идет по пути роста уровней абстракции.
Вопрос не в том, лучше ли абстрагироваться или писать процедурно, а в том, как именно лучше абстрагироваться от throw new MyExceptionClass, если есть множество одинаковых случаев.
Подходов всегда два: соглашения (laravel, yii, reactjs, etc) и конфиги (symfony).
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Есть такой принцип. Single Responsibility называется. Controller just controls the request processing flow. Обработка ошибок не его забота. Это забота, как ни странно, товарища по имени Error Handler. Не люблю все эти слова mvc hmvc... юзайте SRP и будет легко и приятно, имхо. И Laravel я люблю именно за то, что он легок для следования SRP.
Принцип SRP является частным случаем Бритвы Оккама, и рассматривать его надо в контексте, не противоречащем основному правилу.
Надо делать так просто, как это возможно, но не проще. В твоем случае выводы не совсем корректны.
SRP не связан с hmvc, а твои выводы приведут лишь к монолитности и хрупкости. Когда будут нужны изменения в логике обработчика для частных случаев придется писать простыню if-else или уходить в стратегию.

Пример моей реальной задачи, которую я решал осенью. В проекте приняли новый стандарт, по которому часть url на сайте должны стать с / в конце, а часть - без. Соответственно, весь трафик по проиндексированным вразнобой url надо было редиректить к стандартным. Единый exception здесь был бы как корове седло.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Пример моей реальной задачи, которую я решал осенью. В проекте приняли новый стандарт, по которому часть url на сайте должны стать с / в конце, а часть - без. Соответственно, весь трафик по проиндексированным вразнобой url надо было редиректить к стандартным. Единый exception здесь был бы как корове седло.
А ты это решал как-то на уровне контроллеров? Проще, например, добавить флаг к параметрам нужных route'ов: если есть флаг и без «/» на конце, то редирект.
 

Adelf

Administrator
Команда форума
"Хотя на самом деле решения равноправны и сравниваться должны практикой." :)
Ну давай сравним. Не на практике, конечно, а на глаз.Перепишу свой метод так, как описывается в мануалах по ларавель.
PHP:
    public function postUpdate(\Request $request, $id)
    {
        $client = Client::find($id);
     
        if(!$client) {
            abort(404, 'Client not found');
        }

        $this->authorize('manage', $client);
        // И то я не сомневаюсь, что наверняка
        // прям тут стали бы проверять права вручную,
        // без помощи ларавелевского authorize, где
        // правила авторизации описаны отдельно в своем провайдере или Policies
     
        $validator = \Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
            // много много строк...
            // и конечно среди них будут правила валидации типа not_exists и unique
            // которые сами залезут в базу и посмотрят все что надо
        ]);

        if ($validator->fails()) {
            return redirect()//->action or route...
                ->withErrors($validator)
                ->withInput();
        }

        $client->fill($request->all());

        return redirect()->...;
    }
И так КАЖДЫЙ action. Это еще самый простой вариант. Я насмотрелся уже этих ТТУК. Аллергия у меня на них. Контроллер, который знает как валидировать, как обрабатывать ошибки, да и бизнес-логика... чо уж там, раз уж все в контроллеры тащить, то и ее можно.

P.S. Да, я знаю что я тот еще догматик. Разносить по классам как в моем примере довольно дорого по времени. Но, мне кажется, даст большой выигрыш в дальнейшей поддержке.
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Пример моей реальной задачи, которую я решал осенью. В проекте приняли новый стандарт, по которому часть url на сайте должны стать с / в конце, а часть - без. Соответственно, весь трафик по проиндексированным вразнобой url надо было редиректить к стандартным. Единый exception здесь был бы как корове седло.
Вот это вообще контроллеров не касается :) Как Вурдалак уже заметил это проблема роутинга.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Я это решал на разных уровнях, где можно было - в nginx, а часть в логике приложения.

Например, были url вида zzz.domain.tld/title/, и оказалось, что при смене title внезапно теряется трафик на проиндексированные url.
Нужно все перевести на domain.tld/zzz/title.123.html, где 123 - id сущности.
Чтобы получить 123 надо сходить в базу, это уже логика приложения.
Так вот перед тем как выкинуть 404 контроллер должен определить что это старый формат, проверить zzz и по title узнать 123. Причем, для некорректного zzz надо выдавать одну ошибку, для несуществующего title - другую. Делать 2 редиректа сначала для zzz, потом для 123 нельзя - гугл против.
И тут со стройной логикой получается хрень.

у меня была куча ситуаций, когда legacy-код написан с уверенностью, что юзеры ходят стройными рядами и читают мысли дизайнера, а они оказались толпой идиотов, и внезапно надо переделать обработку неожиданной херни в половине из десятков частных случаев
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Перепишу свой метод так, как описывается в мануалах по ларавель.
Разносить по классам как в моем примере довольно дорого по времени. Но, мне кажется, даст большой выигрыш в дальнейшей поддержке.
То, что я не согласен с твоим решением, не значит, что я предпочитаю try-catch как у @hell0w0rd. :)
Ты не на ту тему споришь со мной. Я о другом.
Твой подход красивый на бумаге, да забыли про овраги - когда придется менять поведение для части случаев, проброс исключений из модели напрямую в error handler не позволит обработать контекст, который находится в ведении контроллера.
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Получается, error handler - это 2й уровень контроллера.
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
error handler бывает разный. Разумеется, обычно есть глобальный, выполянемый в catch вызова controller->action(). Так во всех фреймворках вменяемых.

Ты предлагаешь бороться с лагами репликации на уровне контроллера? :)
 

Вурдалак

Продвинутый новичок
Например, были url вида zzz.domain.tld/title/, и оказалось, что при смене title внезапно теряется трафик на проиндексированные url.
Нужно все перевести на domain.tld/zzz/title.123.html, где 123 - id сущности.
Чтобы получить 123 надо сходить в базу, это уже логика приложения.
Так вот перед тем как выкинуть 404 контроллер должен определить что это старый формат, проверить zzz и по title узнать 123. Причем, для некорректного zzz надо выдавать одну ошибку, для несуществующего title - другую. Делать 2 редиректа сначала для zzz, потом для 123 нельзя - гугл против.
И тут со стройной логикой получается хрень.
Твой подход красивый на бумаге, да забыли про овраги - когда придется менять поведение для части случаев, проброс исключений из модели напрямую в error handler не позволит обработать контекст, который находится в ведении контроллера.
Твой кейс не противоречит его подходу, просто нужно было бы написать
PHP:
public function actionGetArticle($id, $title) {
    $articleDto = $this->articleQueryService->get($id);

    if ($articleDto->getTitle() !== $title) {
        return redirect()->route('_article', ['id' => $id, 'title' => $articleDto->getTitle()]);
    }

    // ...
}
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
@Вурдалак =)))
Мои контроллеры устроены иначе. В них заложен только один сценарий - когда все хорошо. Если что-то плохо - где-то кидается исключение и система знает что ответить юзеру. Код в разы более чистый
...
Controller just controls the request processing flow. Обработка ошибок не его забота. Это забота, как ни странно, товарища по имени Error Handler.
if ($articleDto->getTitle() !== $title) - и я об этом же
 
Последнее редактирование:

Redjik

Джедай-мастер
@Adelf, чувак, я хочу с тобой работать на одном проекте =)
задолбался с теми, кто пишет на Ларке по мануалам =(
 

hell0w0rd

Продвинутый новичок
@Redjik, так объединяйтесь, создайте свой мануал. Вон как react в js сообществе появился, огромное кол-во людей заинтересовалось функциональщиной.
 
Сверху