J'ai rédigé un article de blog plus complet et actualisé sur ce sujet : http://elnur.pro/symfony-without-bundles/
Non, tout ne doit pas être dans un paquet. 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 mettez dans le AppBundle
seulement les choses qui sont vraiment spécifiques à Symfony2. Si vous décidez de passer à un autre framework plus tard, vous vous débarrasserez de la section Bundle
et le remplacer par le contenu du framework choisi.
_Veuillez noter que ce que je suggère ici est pour application code spécifique. Pour les paquets réutilisables, je suggère toujours l'utilisation de les meilleures pratiques ._
Garder les entités hors des liasses
Pour garder les entités dans src/Vendor/Model
en dehors de tout regroupement, j'ai modifié le fichier doctrine
section dans config.yml
de
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 d'entités - à accéder à partir des référentiels Doctrine - commencent avec Model
dans ce cas, par exemple, Model:User
.
Vous pouvez utiliser des sous-espaces de nommage pour regrouper des entités apparentées, 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 paquets
D'abord, vous devez dire JMSDiExtraBundle pour scanner le src
pour les services en ajoutant ceci à config.yml
:
jms_di_extra:
locations:
directories: %kernel.root_dir%/../src
Alors vous définir les contrôleurs comme des services et les mettre sous le 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 à faire est d'indiquer à Symfony de rechercher les modèles sans bundle. Je fais cela en surchargeant le service template guesser, mais puisque l'approche est différente entre Symfony 2.0 et 2.1, je fournis des versions pour les deux.
Remplacer le devineur de modèle de Symfony 2.1+.
J'ai créé un paquet qui fait ça pour vous.
Remplacement de l'écouteur de modèle de Symfony 2.0
Tout d'abord, définissez 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 ajoutant ceci à 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 à partir de liasses. Gardez-les sous le app/Resources/views
dossier. Par exemple, les modèles pour ces deux actions de l'exemple de contrôleur ci-dessus sont situés 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 "bundle" :
{% include ':Controller:view.html.twig' %}
1 votes
C'est juste un commentaire, pas une réponse. Je pense personnellement que nous devrions choisir le framework avec soin avant de commencer le projet. Chaque framework a sa propre façon de faire les choses, il fournira donc des outils pour soutenir cette façon le mieux. Si nous aimons cette façon de faire, nous la suivons. Il y a d'autres choix possibles. Nous ne voulons pas utiliser un couteau pour couper le bois au lieu d'une scie. Mais c'est une question très intéressante que vous avez posée :)