让我们说我的应用有多个页面,如
对于所有这些,我需要一些通用代码。示例:从登录用户获取电子邮件地址,以便在每个页面的右上角显示它,在注销按钮旁边。
所以在每个控制器(HomeController,SettingsController,BlogController)上我都要注册一个twig变量:
例如:AppBundle / Controller / HomeController.php
public function indexAction()
{
$user_email = Something::getUserEmail();
...
return $this->render('home/index.html.twig', array('user_email' => $user_email));
}
所以getUserEmail()
(可能还有很多业务逻辑)在我的应用程序的所有前端控制器方法上都是一样的。将代码复制到呈现页面的每个控制器方法中将是非常多余的。我可以注册一个服务,但我也必须在每个控制器上调用它。我也可以写一个BaseController - 让我们说BaseController->init()
- 但是,我必须一遍又一遍地在每个控制器方法上调用这个方法。
那么为多个/所有控制器放置通用业务逻辑的最佳做法是什么?
奖金:我可以预先注册"像smarty中的twig变量或我是否必须通过render
提交它们?将$ user_email注册一次而不是每个控制器方法都会很好,因为这会再次导致大量重复的代码。
要求Symfony 3 +,4。
答案 0 :(得分:2)
TL; DR:不要让你的控制器'胖'而是使用依赖注入。
我使用Symfony多年了,我有很长一段时间都有同样的问题。 This article值得一读。通过使用许多第三方库和包,我看到了放置业务逻辑的常用方法。
以下是我的一个软件包的目录结构示例:
Appbundle\
Command
Controller
DataFixtures
Datatables
Entity
EventListener
Exception
Extension
Form
Menu
Resources\
views
Security\
Authorization\
Voter
Template
Util
Validator
(并非所有目录都提到)
业务逻辑的一个重要部分是Entity
,而安全规则(主要是SecurityVoters)位于Security\Authorization\Voter
。
对于未与Symfony Components或Doctrine(如Forms,SecurityVoters和我的实体模型)紧密耦合的业务逻辑,我为特定目标创建类(记住单一责任原则)并使用Services / Dependency Injection在我的控制器中使用业务逻辑:
use AppBundle\Mailer\Something;
// ...
public function indexAction()
{
$mailer = $this->get(Something::class);
$user_email = $mailer->getUserEmail();
...
return $this->render('home/index.html.twig', array('user_email' => $user_email));
}
一条重要规则:keep your controller slim。它只有一个目的:获取请求并发回响应。保持控制器尽可能的纤薄有很多优点:
关于Twig变量的问题,请检查How to Inject Variables into all Templates (i.e. global Variables)。
答案 1 :(得分:1)
您是否尝试过Traits?根据文件
Trait旨在减少单一继承的一些限制 通过使开发人员能够在几个方面自由地重用方法集 独立班级
特质与类相似,但仅用于分组 功能细化和一致的方式
如果您不想要注射或服务,这将是一个好主意。 Symfony正在使用这种方法。
abstract class Controller implements ContainerAwareInterface
{
use ContainerAwareTrait;
use ControllerTrait;
....
}
你可以检查两个特征并尝试一下。
希望有所帮助
答案 2 :(得分:0)
如果我理解正确,您可以使用标准控制器和树枝来实现这一目标。您可以为常见操作创建一个控制器,例如呈现登录用户的电子邮件,然后 - 在“base.html.twig”中 - 呈现操作的结果。
// CommonController.php
/**
* @Route("/common/get-email", name="get_email")
*/
public function getEmail()
{
// ... fetch email in some way ...
return $this->render('home/index.html.twig', array('user_email' => $user_email));
}
{{ render(url('get_email')) }}
请考虑 Embedding Controllers 部分。