ฉันเขียนบทความในบล็อกนี้อย่างละเอียดมากขึ้นและอัปเดตในหัวข้อนี้: http://elnur.pro/symfony-without-bundles/
ไม่ไม่ใช่ทุกอย่างจะต้องอยู่ในกลุ่ม คุณสามารถมีโครงสร้างแบบนี้:
src/Vendor/Model
- สำหรับรุ่น
src/Vendor/Controller
- สำหรับตัวควบคุม
src/Vendor/Service
- สำหรับบริการ
src/Vendor/Bundle
- สำหรับการรวมกลุ่มเช่นsrc/Vendor/Bundle/AppBundle
,
- เป็นต้น
ด้วยวิธีนี้คุณจะใส่AppBundle
เฉพาะสิ่งที่เฉพาะ Symfony2 เท่านั้น หากคุณตัดสินใจที่จะเปลี่ยนเป็นเฟรมเวิร์กอื่นในภายหลังคุณจะต้องลบBundle
เนมสเปซและแทนที่ด้วยเฟรมเวิร์กที่เลือก
โปรดทราบว่าสิ่งที่ฉันแนะนำที่นี่สำหรับรหัสเฉพาะแอพ สำหรับการรวมกลุ่มนำมาใช้ใหม่ก็ยังแนะนำให้ใช้ปฏิบัติที่ดีที่สุด
การป้องกันเอนทิตีออกจากบันเดิล
เพื่อให้หน่วยงานในsrc/Vendor/Model
ด้านนอกของมัดใด ๆ ผมเคยเปลี่ยนdoctrine
ในส่วนconfig.yml
จาก
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
ในกรณีนี้ยกตัวอย่างเช่น
คุณสามารถใช้ subnamespaces src/Vendor/User/Group.php
ไปยังกลุ่มหน่วยงานที่เกี่ยวข้องร่วมกันยกตัวอย่างเช่น Model:User\Group
ในกรณีนี้ชื่อของกิจการคือ
ไม่ให้ตัวควบคุมออกจากชุดข้อมูล
ก่อนอื่นคุณต้องแจ้งให้JMSDiExtraBundleสแกนsrc
โฟลเดอร์เพื่อรับบริการต่างๆโดยเพิ่มไปที่config.yml
:
jms_di_extra:
locations:
directories: %kernel.root_dir%/../src
จากนั้นคุณกำหนดคอนโทรลเลอร์เป็นบริการและวางไว้ใต้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ของฉันเพื่อลดความซับซ้อนของการกำหนดตัวควบคุมเป็นบริการ
สิ่งสุดท้ายที่เหลือคือการบอกให้ Symfony ค้นหาเทมเพลตที่ไม่มีบันเดิล ฉันทำสิ่งนี้โดยการเอาชนะบริการเดาแม่แบบ แต่เนื่องจากวิธีการนี้แตกต่างกันระหว่าง Symfony 2.0 และ 2.1 ฉันจึงให้บริการทั้งสองรุ่น
การเอาชนะตัวเดาเทมเพลต Symfony 2.1+
ฉันได้สร้างกลุ่มที่ทำเพื่อคุณ
การเอาชนะฟังแม่แบบ 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;
}
}
}
จากนั้นบอก Symfony ให้ใช้งานโดยเพิ่มสิ่งนี้ลงในconfig.yml
:
parameters:
jms_di_extra.template_listener.class: Vendor\Listener\TemplateListener
ใช้เทมเพลตที่ไม่มีบันเดิล
ตอนนี้คุณสามารถใช้เทมเพลตจากบันเดิล เก็บไว้ในapp/Resources/views
โฟลเดอร์ ตัวอย่างเช่นเทมเพลตสำหรับการกระทำสองอย่างจากตัวควบคุมตัวอย่างด้านบนอยู่ใน:
app/Resources/views/User/add.html.twig
app/Resources/views/User/profile.html.twig
เมื่ออ้างถึงเทมเพลตเพียงแค่ละเว้นส่วนบันเดิล:
{% include ':Controller:view.html.twig' %}