gpt4 book ai didi

symfony - Symfony 2.x 中的所有内容真的都应该是 bundle 吗?

转载 作者:行者123 更新时间:2023-12-02 00:11:30 26 4
gpt4 key购买 nike

我知道类似 this 的问题,人们倾向于讨论 bundle 的一般 Symfony 2 概念。

问题是,在特定的应用程序中,例如类似 twitter 的应用程序,是否所有内容都应该真正位于通用包内,例如 official docs说?

我问这个问题的原因是,当我们开发应用程序时,通常我们不希望将代码与某些全栈粘合框架高度耦合。

如果我开发一个基于 Symfony 2 的应用程序,并且在某些时候,我认为 Symfony 2 并不是保持开发继续的最佳选择,这对我来说会是一个问题吗?

所以普遍的问题是:为什么所有东西都 bundle 是一件好事?

编辑#1

自从我问这个问题以来已经快一年了,我写了一篇article分享我关于这个主题的知识。

最佳答案

我已经就此主题撰写了一篇更全面且更新的博客文章:http://elnur.pro/symfony-without-bundles/

<小时/>

不,并非所有内容都必须 bundle 在一起。你可以有这样的结构:

  • src/Vendor/Model — 对于模型,
  • src/Vendor/Controller — 对于 Controller ,
  • src/Vendor/Service — 对于服务,
  • src/Vendor/Bundle — 用于 bundle ,例如 src/Vendor/Bundle/AppBundle
  • 等等

这样,您就可以仅将 Symfony2 特定的内容放入 AppBundle 中。如果您决定稍后切换到另一个框架,您将摆脱 Bundle 命名空间并将其替换为所选的框架内容。

请注意,我在这里建议的是针对应用特定代码。对于可重复使用的 bundle ,我仍然建议使用 the best practices .

将实体排除在 bundle 之外

为了将 src/Vendor/Model 中的实体保留在任何 bundle 之外,我已将 config.yml 中的 doctrine 部分从

doctrine:
# ...
orm:
# ...
auto_mapping: true

doctrine:
# ...
orm:
# ...
mappings:
model:
type: annotation
dir: %kernel.root_dir%/../src/Vendor/Model
prefix: Vendor\Model
alias: Model
is_bundle: false

实体的名称 - 从 Doctrine 存储库访问 - 在本例中以 Model 开头,例如 Model:User

您可以使用子命名空间将相关实体分组在一起,例如src/Vendor/User/Group.php。在本例中,实体的名称为 Model:User\Group

将 Controller 排除在 bundle 之外

首先,你需要告诉JMSDiExtraBundle通过将其添加到 config.yml 来扫描 src 文件夹中的服务:

jms_di_extra:
locations:
directories: %kernel.root_dir%/../src

那么你define controllers as services并将它们放在 Controller 命名空间下:

<?php
namespace Vendor\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use JMS\DiExtraBundle\Annotation\Service;
use JMS\DiExtraBundle\Annotation\InjectParams;
use JMS\SecurityExtraBundle\Annotation\Secure;
use Elnur\AbstractControllerBundle\AbstractController;
use Vendor\Service\UserService;
use Vendor\Model\User;

/**
* @Service("user_controller", parent="elnur.controller.abstract")
* @Route(service="user_controller")
*/
class UserController extends AbstractController
{
/**
* @var UserService
*/
private $userService;

/**
* @InjectParams
*
* @param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}

/**
* @Route("/user/add", name="user.add")
* @Template
* @Secure("ROLE_ADMIN")
*
* @param Request $request
* @return array
*/
public function addAction(Request $request)
{
$user = new User;
$form = $this->formFactory->create('user', $user);

if ($request->getMethod() == 'POST') {
$form->bind($request);

if ($form->isValid()) {
$this->userService->save($user);
$request->getSession()->getFlashBag()->add('success', 'user.add.success');

return new RedirectResponse($this->router->generate('user.list'));
}
}

return ['form' => $form->createView()];
}

/**
* @Route("/user/profile", name="user.profile")
* @Template
* @Secure("ROLE_USER")
*
* @param Request $request
* @return array
*/
public function profileAction(Request $request)
{
$user = $this->getCurrentUser();
$form = $this->formFactory->create('user_profile', $user);

if ($request->getMethod() == 'POST') {
$form->bind($request);

if ($form->isValid()) {
$this->userService->save($user);
$request->getSession()->getFlashBag()->add('success', 'user.profile.edit.success');

return new RedirectResponse($this->router->generate('user.view', [
'username' => $user->getUsername()
]));
}
}

return [
'form' => $form->createView(),
'user' => $user
];
}
}

请注意,我正在使用我的 ElnurAbstractControllerBundle简化将 Controller 定义为服务。

剩下的最后一件事是告诉 Symfony 寻找没有 bundle 的模板。我通过覆盖模板猜测器服务来做到这一点,但由于 Symfony 2.0 和 2.1 之间的方法不同,我为它们提供了版本。

覆盖 Symfony 2.1+ 模板猜测器

我创建了一个 bundle这会为你做到这一点。

重写 Symfony 2.0 模板监听器

首先,定义类:

<?php
namespace Vendor\Listener;

use InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener as FrameworkExtraTemplateListener;
use JMS\DiExtraBundle\Annotation\Service;

class TemplateListener extends FrameworkExtraTemplateListener
{
/**
* @param array $controller
* @param Request $request
* @param string $engine
* @throws InvalidArgumentException
* @return TemplateReference
*/
public function guessTemplateName($controller, Request $request, $engine = 'twig')
{
if (!preg_match('/Controller\\\(.+)Controller$/', get_class($controller[0]), $matchController)) {
throw new InvalidArgumentException(sprintf('The "%s" class does not look like a controller class (it must be in a "Controller" sub-namespace and the class name must end with "Controller")', get_class($controller[0])));

}

if (!preg_match('/^(.+)Action$/', $controller[1], $matchAction)) {
throw new InvalidArgumentException(sprintf('The "%s" method does not look like an action method (it does not end with Action)', $controller[1]));
}

$bundle = $this->getBundleForClass(get_class($controller[0]));

return new TemplateReference(
$bundle ? $bundle->getName() : null,
$matchController[1],
$matchAction[1],
$request->getRequestFormat(),
$engine
);
}

/**
* @param string $class
* @return Bundle
*/
protected function getBundleForClass($class)
{
try {
return parent::getBundleForClass($class);
} catch (InvalidArgumentException $e) {
return null;
}
}
}

然后通过将其添加到 config.yml 来告诉 Symfony 使用它:

parameters:
jms_di_extra.template_listener.class: Vendor\Listener\TemplateListener

使用不带 bundle 的模板

现在,您可以使用 bundle 中的模板。将它们保存在 app/Resources/views 文件夹下。例如,上面示例 Controller 中这两个操作的模板位于:

  • app/Resources/views/User/add.html.twig
  • app/Resources/views/User/profile.html.twig

引用模板时,只需省略 bundle 部分即可:

{% include ':Controller:view.html.twig' %}

关于symfony - Symfony 2.x 中的所有内容真的都应该是 bundle 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9999433/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com