Exceptions как и с чем

WMix

герр M:)ller
Партнер клуба
это же тоже получается middleware, или? смотри, у нас валидацией занимается клиент, те краствых сообщений при обработке выдавать не надо, но это не решает основную задачу валидации, middleware грубо говоря наполовину модель. те обработка почты будет похожа на это
PHP:
class UserService{
  function do(User $user){
    // ...
  }
  function createUser($name, $balba):User{
    // тут валидация и выкидываем исключение
    return new User($name, $balba);
  }
}

// middleware
function beforeMyAction(Request $r):User{
  // в этом месте вероятно придется исключение врапить
  // и чет мне совсем не нравится трайкэтчить
  try{
    return $service->createUser($r->name, $r->blabla);
  }
  catch(\Exception $e){
    throw BadRequestHttpException(...);
  }
}

// controller
function myAction(User $user){
   // тут всегда готовые обьекты
  return $service->do($user)
}
че думаешь?


https://silex.symfony.com/doc/2.0/usage.html#route-variable-converters
 

fixxxer

К.О.
Партнер клуба
Я не понимаю, зачем это. Это аутентификация или что?

(Вот этот подход с анемичными моделями и классами типа FooService это, конечно, жесть еще похуже Active Record.)
 

WMix

герр M:)ller
Партнер клуба
в данном случае это любое действие, пользователь и остальное это просто примеры. те еслиб была аутентификация то и метод назывался бы authenticate те. "do" в примере - "что нибудь".
основная идея в том что в "действие" заходят только готовые обьекты (ну или данные) те такоe тоже допустимо
PHP:
function authenticateAction($nick, $pass){
  return $service->authenticate($nick, $pass);
}
function renameAction(User $user, $new_name){
  // только эта часть в сервисе уже
  $user->rename($new_name);
}
(прелюдия getById итд. всегда в middleware)
дальше только действия и визуализация результата. не понимаю почему "анемичный"?.
 

Вурдалак

Продвинутый новичок
@WMix, для переименования нужны $userId и $newName. Что ты там в своем «middleware» собрался валидировать?
 

WMix

герр M:)ller
Партнер клуба
@fixxxer, для того чтобы с этим работать, чтоб действия были короткими, чтоб сосредоточится на самом действии а не подготовке и проверке
@Вурдалак, $userId это клевая штука и в руте (POST /user/{userId}/rename) она вероятно так и называлась
в middleware мы из {userId} создали обьект User, мы проверили что он существует и разрешон (в моей группе где я админ к примеру)
 

Вурдалак

Продвинутый новичок
@fixxxer, для того чтобы с этим работать, чтоб действия были короткими, чтоб сосредоточится на самом действии а не подготовке и проверке
Для этого есть command handler'ы. Только по прежнему нужно передавать userId.
 

WMix

герр M:)ller
Партнер клуба
"command handler" это по сути тотже "action handler". в данном случае в action handler прописано что перед началом action запусти converter и создай из scalar-value object
 

Вурдалак

Продвинутый новичок
"command handler" это по сути тотже "action handler". в данном случае в action handler прописано что перед началом action запусти converter и создай из scalar-value object
Нетранзакционно и привязано к HTTP (по сути action'ы-то — это часть HTTP-контроллеров).
 

WMix

герр M:)ller
Партнер клуба
Нетранзакционно
это нет, возможно несколько ограничено но,
вызов post это команда (изменение состояния), всегда 1 транзакция, всегда синхронно (session read/write).
вызов get это query, без транзакций, асинхронно (session read / write_close)
(по крайней мере это цель, есть исключения)

привязано к HTTP (по сути action'ы-то — это часть HTTP-контроллеров).
а как иначе?
 

fixxxer

К.О.
Партнер клуба
Не забывайте чейнить эксепшены…
В данном конкретном случае, когда exception гарантированно будет обработан кодом вида return $response->status($e->getCode()), не вижу в этом смысла. Хотя сам обычно чейню тупо на автомате. Но на code review бы придираться не стал.
 

Вурдалак

Продвинутый новичок
это нет, возможно несколько ограничено но,
вызов post это команда (изменение состояния), всегда 1 транзакция, всегда синхронно (session read/write).
вызов get это query, без транзакций, асинхронно (session read / write_close)
(по крайней мере это цель, есть исключения)
Я не понял к чему этот набор утверждений. Где у тебя транзакция-то? Где ты пишешь SELECT ... FOR UPDATE?

Эээ, command handler? Application, не привязанный ни к одному из внешних форматов.
 

WMix

герр M:)ller
Партнер клуба
Где ты пишешь SELECT ... FOR UPDATE?
PHP:
class UserService{
    public function getUserById($id, $for_update=false){
        return $this->mapper->getById($id, $for_update);
    }
}
function before(Request $request){
  return $this->service->getUserById($request->attributes->get('id'), $request->isMethod(Request::METHOD_POST));
}
Эээ, command handler? Application, не привязанный ни к одному из внешних форматов.
я не очень понял, я подумаю
 

Вурдалак

Продвинутый новичок
PHP:
class UserService{
    public function getUserById($id, $for_update=false){
        return $this->mapper->getById($id, $for_update);
    }
}
function before(Request $request){
  return $this->service->getUserById($request->attributes->get('id'), $request->isMethod(Request::METHOD_POST));
}
Что ты будешь делать, если в другом middleware есть какой-нибудь логгер, пишущий в базу, используя тот же connection? Что ты будешь делать, если у тебя есть событие, по которому синхронно выполняется другой обработчик, который тоже попадёт под действие транзакции (письмо отправится, а потом выяснится, что транзакцию нужно откатывать)? Что ты будешь делать, если соответствие «метод HTTP-API <-> бизнес-действие» перестанет быть взаимно однозначным (один вызов API -> несколько команд)?

Зачем вообще так завязываться на HTTP-контекст? Как ты собираешься переиспользовать то же бизнес-действие в CLI, в сценариях автотестов, в другом API (иметь одновременно несколько API разных форматов и версий в долгосрочных проектах — не редкость, ибо BC), в админке (админка может иметь свой API на другом хосте)? Я просто вызову $this->bus->handle(new RenameUser(42, 'Alice')), зная, что либо действие выполнится транзакционно, либо упадёт с ошибкой. А как вызывать твой «экшн», размазанный по куче классов? Делать sub/slave HTTP-request из CLI?
 

WMix

герр M:)ller
Партнер клуба
такие вопросы странные, как будто простую идею не понял, наоборот модель свободная, это http на моделе завязан. переиспользовать, вообще никаких проблем, мыло я отправлю через bus. те оно отправится если транзакция была завершена и демон не упал.
А как вызывать твой «экшн», размазанный по куче классов?
как угодно, так нравится?
PHP:
$router['RenameUser']->handle(['id'=>42, 'name' => 'Alice']);
вобще не понимаю твою проблему

если ты о командах, то там ничего другого кроме вышеописаного.
 
Сверху