J'ai écrit un article de blog plus approfondi et mis à jour sur ce sujet: http://elnur.pro/symfony-without-bundles/
Non, tout ne doit pas nécessairement être regroupé. Vous pourriez avoir une structure comme celle-ci:
src/Vendor/Model
- pour les modèles,
src/Vendor/Controller
- pour les contrôleurs,
src/Vendor/Service
- pour les services,
src/Vendor/Bundle
- pour les paquets, comme src/Vendor/Bundle/AppBundle
,
- etc.
De cette façon, vous AppBundle
mettriez le seul truc qui est vraiment spécifique à Symfony2. Si vous décidez de passer à un autre framework plus tard, vous vous débarrasserez de l' Bundle
espace de noms et le remplacerez par le framework choisi.
Veuillez noter que ce que je suggère ici concerne le code spécifique à l' application . Pour les bundles réutilisables, je suggère toujours d'utiliser les meilleures pratiques .
Garder les entités hors des bundles
Pour conserver les entités en src/Vendor/Model
dehors de tout ensemble, j'ai changé la doctrine
section config.yml
depuis
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
Les noms des entités - pour accéder à partir des référentiels Doctrine - commencent Model
dans ce cas, par exemple,Model:User
,.
Vous pouvez utiliser subnamespaces à des entités liées au groupe ainsi que , par exemple, src/Vendor/User/Group.php
. Dans ce cas, le nom de l'entité est Model:User\Group
.
Garder les contrôleurs hors des bundles
Tout d'abord, vous devez dire à JMSDiExtraBundle d'analyser le src
dossier pour les services en l'ajoutant à config.yml
:
jms_di_extra:
locations:
directories: %kernel.root_dir%/../src
Ensuite, vous définissez les contrôleurs comme des services et les placez sous l' Controller
espace de noms:
<?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
];
}
}
Notez que j'utilise mon ElnurAbstractControllerBundle pour simplifier la définition des contrôleurs en tant que services.
La dernière chose qui reste est de dire à Symfony de rechercher des modèles sans bundles. Je le fais en remplaçant le service de devinette de modèle, mais comme l'approche est différente entre Symfony 2.0 et 2.1, je fournis des versions pour les deux.
Remplacer le devineur de modèles Symfony 2.1+
J'ai créé un bundle qui fait ça pour vous.
Substitution de l'écouteur de modèles Symfony 2.0
Définissez d'abord la classe:
<?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;
}
}
}
Et puis dites à Symfony de l'utiliser en l'ajoutant à config.yml
:
parameters:
jms_di_extra.template_listener.class: Vendor\Listener\TemplateListener
Utilisation de modèles sans bundles
Maintenant, vous pouvez utiliser des modèles hors des bundles. Gardez-les sous le app/Resources/views
dossier. Par exemple, les modèles de ces deux actions de l'exemple de contrôleur ci-dessus se trouvent dans:
app/Resources/views/User/add.html.twig
app/Resources/views/User/profile.html.twig
Lorsque vous faites référence à un modèle, omettez simplement la partie de l'ensemble:
{% include ':Controller:view.html.twig' %}