根据Symfony的方式,最佳做法是什么?
选项1:
class MyController extends Controller
{
public function myAction(...)
{
// ..
$example = $this->getDoctrine()->getRepository('AppBundle:Contract')->getContracts(array(
'company_id' => $company->getId(),
'contract_month_date_start' => date('Y-m-d', strtotime('first day of this month', $contractDate->getTimestamp())),
'contract_month_date_end' => date('Y-m-d', strtotime('last day of this month', $contractDate->getTimestamp())),
));
// ..
}
}
class ExampleRepository extends EntityRepository
{
public function getContracts($options)
{
//..
$qb->select('contract')
->from('AppBundle:Contract', 'contract')
->where('contract.companyId = :company_id')
->andWhere('contract.startDate < :contract_month_date_end')
->andWhere('contract.endDate < :contract_month_date_end')
->setParameter('company_id', $options['company_id'])
->setParameter('contract_month_date_start', $options['contract_month_date_start'])
->setParameter('contract_month_date_end', $options['contract_month_date_end']);
//..
}
}
选项2:
class MyController extends Controller
{
public function myAction(...)
{
// ..
$example = $this->getDoctrine()->getRepository('AppBundle:Contract')->getContracts(array(
'company' => $company,
'contractDate' => $contractDate
));
// ..
}
}
class ExampleRepository extends EntityRepository
{
public function getContracts($options)
{
//..
$company_id = $options['company']->getId();
$contract_month_date_start = date('Y-m-d', strtotime('first day of this month', $options['contractDate']));
$contract_month_date_end = date('Y-m-d', strtotime('last day of this month', $options['contractDate']));
$qb->select('contract')
->from('AppBundle:Contract', 'contract')
->where('contract.companyId = :company_id')
->andWhere('contract.startDate < :contract_month_date_end')
->andWhere('contract.endDate < :contract_month_date_end')
->setParameter('company_id', $company_id)
->setParameter('contract_month_date_start', $contract_month_date_start)
->setParameter('contract_month_date_end', $contract_month_date_end);
//..
}
}
我觉得第二个更好(使用存储库的不同控制器之间的重复代码更少)。但我也觉得它对存储库负有太多责任。
答案 0 :(得分:1)
Symfony best practices对您的任务不清楚,但恕我直言以下声明可以映射到您的第二个选项
总的来说,这意味着您应该积极地将业务逻辑与框架分离,同时积极地将控制器和路由耦合到框架,以便充分利用它。
正如您已经说过的那样,第二个选项使控制器保持更薄并将逻辑移动到存储库级别,这是 Symfony方式一种完全有效的方法。
添加了一些额外支持在Symfony应用程序中,业务逻辑是您为应用程序编写的所有自定义代码,并非特定于框架(例如路由和控制器)。用作服务的域类,Doctrine实体和常规PHP类是业务逻辑的良好示例。
如果您需要在应用程序周围的不同位置使用此格式,则另一种方法可能是创建一个服务类,您可以将其注入到您需要的存储库中。
答案 1 :(得分:1)
TL; DR:在您的示例中,理想情况下您的格式化逻辑应该是 在中间层处理。
以下是一些改进:
首先,不要从控制器获取存储库。相反,将其声明为服务(例如,在app/config/services.yml
中)。
此外,您可以使用新图层抽象访问您的数据(=您的存储库)。沟通将这样完成:
Controller
&lt; =&gt; Business layer
&lt; =&gt; Data access
。
使用这样的体系结构将帮助您拥有更具可扩展性的应用程序,而无需花费太长时间来实现它。
在您的代码中,它看起来如下所示:
您的控制器,负责&#34;路由&#34;用户对正确服务的请求
class MyController extends Controller
{
public function myAction()
{
// Accessing the contract manager, previously declared as a service in services.yml
$contractManager = $this->get('manager.contract');
$contracts = $contractManager->getMonthlyContracts($company);
}
}
您的业务层,负责执行逻辑:
// This class must be declared as a service in services.yml
class ContractManager {
private $contractRepository;
public function __construct(ContractRepository $contractRepository)
{
$this->contractRepository = $contractRepository;
}
public function getMonthlyContracts(Company $company)
{
// The business layer is responsible for the logic of fetching the data. Therefore, its methods are business-related (here "find the monthly contracts for company X", which is very specific).
// It is its role to set the start and end dates, not the controller's
$contracts = $this->contractRepository->findByCompany(
$company,
new \DateTime('first day of this month'),
new \DateTime('last day of this month')
);
// Do some logic with the contracts if required...
return $contracts;
}
}
您的存储库,负责访问数据:
class ContractRepository extends EntityRepository
{
// The repository handles basic access to data without any logic, hence the generic "findByCompany" method name
public function findByCompany(Company $company, \DateTime $from, \DateTime $to)
{
$qb->select('contract')
->from('AppBundle:Contract', 'contract')
->where('contract.company = :company')
->andWhere('contract.startDate > :from')
->andWhere('contract.endDate < :to')
->setParameter('company', $company)
->setParameter('from', $from)
->setParameter('to', $to);
//...
}
}
请查看Symfony doc,了解如何在services.yml
中将存储库声明为服务。
答案 2 :(得分:0)
我更喜欢在表示层中执行此类工作,如果您使用的是TWIG,则应该查看date格式过滤器,或者如果它是api,您可以使用{来工作到表示层{3}}例如。
通过这种方式,业务逻辑不会改变,也不会影响表示逻辑的更改
我的两分钱。