Tôi đã viết một bài đăng blog kỹ lưỡng và cập nhật hơn về chủ đề này: http://elnur.pro/symfony-without-bundles/
Không, không phải tất cả mọi thứ phải ở trong một bó. Bạn có thể có một cấu trúc như thế này:
src/Vendor/Model
- cho các mô hình,
src/Vendor/Controller
- cho bộ điều khiển,
src/Vendor/Service
- Cho dịch vụ,
src/Vendor/Bundle
- cho các gói, như src/Vendor/Bundle/AppBundle
,
- Vân vân.
Bằng cách này, bạn sẽ đưa vào thứ AppBundle
duy nhất thực sự là Symfony2 cụ thể. Nếu bạn quyết định chuyển sang một khung công tác khác sau đó, bạn sẽ thoát khỏi Bundle
không gian tên và thay thế nó bằng các công cụ khung đã chọn.
Xin lưu ý rằng những gì tôi đề xuất ở đây là dành cho mã cụ thể của ứng dụng . Đối với các gói có thể tái sử dụng, tôi vẫn đề nghị sử dụng các thực tiễn tốt nhất .
Giữ các thực thể ra khỏi gói
Để giữ các thực thể src/Vendor/Model
bên ngoài bất kỳ gói nào, tôi đã thay đổi doctrine
phần trong config.yml
từ
doctrine:
# ...
orm:
# ...
auto_mapping: true
đến
doctrine:
# ...
orm:
# ...
mappings:
model:
type: annotation
dir: %kernel.root_dir%/../src/Vendor/Model
prefix: Vendor\Model
alias: Model
is_bundle: false
Tên của các thực thể - để truy cập từ kho lưu trữ của Học thuyết - bắt đầu bằng Model
trong trường hợp này, ví dụ , Model:User
.
Ví dụ, bạn có thể sử dụng tên miền con để nhóm các thực thể liên quan với nhau src/Vendor/User/Group.php
. Trong trường hợp này, tên của thực thể là Model:User\Group
.
Giữ bộ điều khiển ra khỏi gói
Trước tiên, bạn cần nói với JMSDiExtraBundle để quét src
thư mục cho các dịch vụ bằng cách thêm phần này vào config.yml
:
jms_di_extra:
locations:
directories: %kernel.root_dir%/../src
Sau đó, bạn xác định bộ điều khiển là dịch vụ và đặt chúng dưới Controller
không gian tên:
<?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
];
}
}
Lưu ý rằng tôi đang sử dụng Elnur AbTHERControllBundle của mình để đơn giản hóa việc xác định bộ điều khiển là dịch vụ.
Điều cuối cùng còn lại là bảo Symfony tìm kiếm các mẫu không có gói. Tôi làm điều này bằng cách ghi đè dịch vụ đoán mẫu, nhưng vì cách tiếp cận khác nhau giữa Symfony 2.0 và 2.1, tôi đang cung cấp các phiên bản cho cả hai.
Ghi đè trình đoán mẫu Symfony 2.1+
Tôi đã tạo ra một gói làm điều đó cho bạn.
Ghi đè trình nghe mẫu Symfony 2.0
Đầu tiên, xác định lớp:
<?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;
}
}
}
Và sau đó nói với Symfony sử dụng nó bằng cách thêm nó vào config.yml
:
parameters:
jms_di_extra.template_listener.class: Vendor\Listener\TemplateListener
Sử dụng các mẫu không có gói
Bây giờ, bạn có thể sử dụng các mẫu trong số các gói. Giữ chúng trong app/Resources/views
thư mục. Ví dụ: các mẫu cho hai hành động đó từ trình điều khiển mẫu ở trên được đặt trong:
app/Resources/views/User/add.html.twig
app/Resources/views/User/profile.html.twig
Khi đề cập đến một mẫu, chỉ cần bỏ qua phần gói:
{% include ':Controller:view.html.twig' %}