1

在我的应用程序中,用户可以注册 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。但是,这感觉不是很理想。有没有更好的方法来做到这一点?

我想我可以创建成功和请求的响应(无论是重定向还是渲染)并将它们传递给服务方法。但这感觉就像我违反了单一责任原则。

4

1 回答 1

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 控制器可以向用户显示发生了什么,并在必要时采取进一步的行动。

于 2013-08-27T14:33:31.080 回答