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ứ AppBundleduy 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 Bundlekhô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/Modelbên ngoài bất kỳ gói nào, tôi đã thay đổi doctrinephần trong config.ymltừ
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 Modeltrong 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 srcthư 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 Controllerkhô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/viewsthư 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' %}