在我的应用程序中,用户可以注册3种许可证:可供所有人使用的免费许可证,人们必须支付的订阅许可证(通过外部方管理)和许可发票,这需要他们联系我们。
人们可以在注册时或之后通过他们的个人资料选择他们的许可。这是两种不同的控制器,采用不同的方法。
我有一个subscription.manager
服务方法subscribe(User $user, License $license)
,它接收用户和许可证实体,并处理为用户签署正确许可证的所有逻辑。
根据用户选择的许可证,结果可能会有所不同:
最后一个选项是一个简单的RedirectResponse
,但根据他们是注册还是只是更改了现有的许可订阅,我想显示不同的页面。
处理此问题的最佳方法是什么?
目前,我这样做:
$response = $this->get('subscription.manager')->subscribe($user, $license);
switch (true) {
case $response instanceof SuccessResponse:
return $this->redirect('success_url');
break;
case $response instanceof RequestedResponse;
return $this->redirect('requested_url');
break;
case $response instanceof RedirectResponse:
return $response;
break;
default:
throw new \Exception('Response not recognized');
}
SuccessResponse
和RequestedResponse
是我创建的简单类,并且几乎没有信息,它们纯粹表示方法中发生了什么。
这允许我复制粘贴此块并简单地切换成功和请求的URL。但是,这感觉不是很理想。有更好的方法吗?
我想我可以创建成功并请求响应(无论是重定向还是渲染)并将其传递给服务方法。但这感觉就像我违反了单一责任原则。
答案 0 :(得分:1)
我认为您的订阅管理员不应该关注重定向和内容。所以作为我要做的第一步:
$result = $this->get('subscription.manager')->subscribe($user, $license);
switch ($result) {
case 'ProcessedFreeLicense':
return $this->redirect('success_url');
break;
case 'ProcessedInvoicedLicense';
return $this->redirect('requested_url');
break;
case 'ProcessedSubstrictionLicense':
return $response;
break;
default:
throw new \Exception('Response not recognized');
}
这仍然会在控制器中留下一个switch语句和一些重复的代码。您可以将switch语句移动到基本控制器类。
但是,我会考虑调度一个ProcessedLicense事件,然后让一个监听器决定为每种许可证做什么。请看一下FOSUserBundle.RegistrationController的开发版本,以获得一个工作示例,但基本上是:
$result = $this->get('subscription.manager')->subscribe($user, $license);
$event = new ProcessedLicenseEvent($user,$license,$results);
$dispatcher->dispatch(LicenseEvents::PROCESSED_LICENSE, $event);
return $event->getResponse();
所以现在所有与处理许可证后要做的事情相关的逻辑都可以隐藏在一个或多个侦听器中。它可以根据需要进行更改,而不会影响您的控制器。
=============================================== ======================
我想我会为完整性添加第三种方法。这种方法在一些基于C#/ Java的应用程序中很常见。这是一种“一劳永逸”的方法,在这种方法中,命令不会返回值,控制器也不会期望值。
// This is the Command. It does not return a value.
$this->get('subscription.manager')->subscribe($user, $license);
// Always just go here
return $this->redirect('user_license_status_page');
显然,我们简化了命令对象,因为它不再需要返回值。我们摆脱了共享的switch语句。 licence_status控制器可以向用户显示发生的情况,并在必要时采取进一步措施。