Czy wszystko naprawdę powinno być pakietem w Symfony 2?x?

Znam takie pytania jakto , gdzie ludzie mają tendencję do omawiania ogólnej koncepcji Symfony 2 pakietu.

Rzecz w tym, że w konkretnej aplikacji, jak na przykład aplikacja podobna do Twittera, czy wszystko naprawdę powinno znajdować się w ogólnym pakiecie, jak mówią official docs?

Powodem, dla którego o to pytam, jest to, że kiedy tworzymy aplikacje, ogólnie rzecz biorąc, nie chcemy bardzo łączyć naszego kodu z jakimś klejem z pełnym stosem ramy.

Jeśli rozwinę aplikację opartą na Symfony 2 i w pewnym momencie uznam, że Symfony 2 nie jest najlepszym wyborem, aby kontynuować rozwój , czy będzie to dla mnie problemem?

Więc ogólne Pytanie brzmi: dlaczego wszystko jest wiązką dobrą rzeczą?

Edytuj#1

Prawie rok temu, odkąd zadałem to pytanie, napisałem Artykuł, aby podzielić się swoją wiedzą na ten temat.

Author: Daniel Ribeiro, 2012-04-03

6 answers

Napisałem dokładniejszy i zaktualizowany wpis na blogu na ten temat: http://elnur.pro/symfony-without-bundles/


Nie, nie wszystko musi być w pakiecie. Możesz mieć taką strukturę:
  • src/Vendor/Model - dla modeli,
  • src/Vendor/Controller - dla kontrolerów,
  • src/Vendor/Service - dla usług,
  • src/Vendor/Bundle - dla wiązek, np. src/Vendor/Bundle/AppBundle,
  • itd.

W ten sposób, można umieścić AppBundle tylko to, co jest naprawdę Symfony2 specific. Jeśli później zdecydujesz się przełączyć na inny framework, pozbędziesz się przestrzeni nazw Bundle i zastąpisz ją wybranymi frameworkami.

proszę zauważyć, że to, co sugeruję tutaj jest dla app specyficzny kod. W przypadku pakietów wielokrotnego użytku nadal sugeruję stosowanie najlepszych praktyk .

Trzymanie Bytów z wiązek

Aby zachować encje w src/Vendor/Model poza dowolnym pakietem, zmieniłem doctrine sekcję w config.yml od

doctrine:
    # ...
    orm:
        # ...
        auto_mapping: true

Do

doctrine:
    # ...
    orm:
        # ...
        mappings:
            model:
                type: annotation
                dir: %kernel.root_dir%/../src/Vendor/Model
                prefix: Vendor\Model
                alias: Model
                is_bundle: false

Nazwy encji - aby uzyskać dostęp z repozytoriów doktryn-zaczynają się od Model w tym przypadku, na przykład, Model:User.

Możesz używać przestrzeni podrzędnych do grupowania powiązanych jednostek, na przykład src/Vendor/User/Group.php. W tym przypadku nazwa podmiotu to Model:User\Group.

Trzymanie kontrolerów z dala od wiązek

Po pierwsze, musisz powiedzieć JMSDiExtraBundle Aby zeskanować src folder dla usług, dodając to do config.yml:
jms_di_extra:
    locations:
        directories: %kernel.root_dir%/../src

Wtedy ty zdefiniuj Kontrolery jako usługi i umieść je w przestrzeni nazw 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
        ];
    }
}

Zauważ, że używam mojego ElnurAbstractControllerBundle Aby uprościć definiowanie kontrolerów jako usług.

Ostatnia rzecz, jaką pozostało, to polecenie Symfony, aby szukał szablonów bez pakietów. Robię to, nadpisując usługę zgadywania szablonów, ale ponieważ podejście jest inne między Symfony 2.0 i 2.1, dostarczam wersje dla obu z nich.

Nadpisanie Symfony 2.1 + template guesser

Stworzyłem pakiet który robi to za Ciebie.

Nadpisywanie szablonu Symfony 2.0 listener

Najpierw zdefiniuj klasę:

<?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;
        }
    }
}

A następnie powiedz Symfony, aby go użył, dodając to do config.yml:

parameters:
    jms_di_extra.template_listener.class: Vendor\Listener\TemplateListener

Używanie szablonów bez pakietów

Teraz możesz używać szablonów z pakietów. Trzymaj je w folderze app/Resources/views. Na przykład szablony dla tych dwóch akcji z przykładowego kontrolera powyżej znajdują się in:

  • app/Resources/views/User/add.html.twig
  • app/Resources/views/User/profile.html.twig

Odwołując się do szablonu, po prostu pomiń część pakietu:

{% include ':Controller:view.html.twig' %}
 221
Author: Elnur Abdurrakhimov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Oczywiście możesz oddzielić swoją aplikację. Po prostu rozwiń go jako bibliotekę i Zintegruj z folderem symfony vendor/ - (używając deps lub composer.json, w zależności od tego, czy używasz Symfony2. 0 lub Symfony2.1). Potrzebujesz jednak co najmniej jednego pakietu, który działa jako "frontend" Twojej biblioteki, gdzie Symfony2 znajduje kontroler (i takie).

 21
Author: KingCrunch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-03 18:48:59

Zwykła Dystrybucja symfony może działać bez dodatkowego pakietu (aplikacji), w zależności od tego, ile funkcji chcesz użyć z frameworka pełnego stosu.

Na przykład, Twoje kontrolery mogą być dowolnymi wywołaniami, które można umieścić w dowolnym miejscu struktury projektu, gdy tylko zostaną automatycznie załadowane.

W pliku definicji trasowania można użyć:

test:
    pattern:   /test
    defaults:  { _controller: Controller\Test::test }

Może to być dowolny zwykły stary obiekt php, tylko związany z frameworkiem przez fakt, że musi zwrócić Symfony\Component\HttpFoundation\Response obiekt.

Twoje szablony gałązek (lub inne) mogą być umieszczone jak app/Resources/views/template.html.twig i mogą być renderowane za pomocą nazwy logicznej ::template.html.twig.

Wszystkie usługi DI mogą być zdefiniowane w app/config / config.yml (lub zaimportowany z app/config/services.yml na przykład, a wszystkie klasy usług mogą być dowolnymi zwykłymi obiektami php. w ogóle nie związane z ramami.

To wszystko jest domyślnie dostarczane przez framework pełnego stosu symfony.

Gdzie będziesz miał problemy, to kiedy będziesz chciał użyć plików tłumaczeniowych (takich jak xliff), ponieważ są one odkrywane przez pakiety tylko .

Dystrybucja symfony-light mA na celu rozwiązanie tego typu problemów poprzez odkrywanie wszystkiego, co zwykle zostanie odkryte tylko za pomocą wiązek.

 11
Author: Florian Klein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-15 15:11:41

Ponieważ minęło już 5 lat, oto kilka artykułów o pakietach Symfony.

  1. Czym są pakiety w Symfony?Autor: Iltar van der Berg.

TLDR:

Czy potrzebujesz wielu pakietów bezpośrednio w aplikacji? Najprawdopodobniej nie. Lepiej napisać AppBundle, żeby zapobiec spaghetti z zależności. Możesz po prostu przestrzegać najlepszych praktyk i będzie działa dobrze.

  1. Symfony: jak Bundle By Toni Uebernickel.

TLDR:

Utwórz tylko jeden pakiet o nazwie AppBundle dla logiki aplikacji. Jeden AppBundle - ale proszę nie umieszczać logiki aplikacji tam!

 5
Author: Reshat Belyalov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-14 10:01:26

Możesz użyć KnpRadBundle , który stara się uprościć strukturę projektu.

Innym podejściem jest użycie src/Company/Bundle/FrontendBundle Na przykład dla pakietów i src/Company/Stuff/Class.php dla klas, które są niezależne od symfony i które mogą być ponownie użyte poza frameworkiem

 4
Author: miguel_ibero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-03 19:10:17

Symfony framework jest bardzo dobry do szybkiego uruchomienia proof of concept I cały kod można wprowadzić w domyślnej aplikacji pakietu w src /

W tym pakiecie możesz układać swój kod tak, jak chcesz.

Po, jeśli chcesz użyć innej technologii do opracowania POC, możesz łatwo to przetłumaczyć, ponieważ nie uporządkujesz całego kodu w koncepcji pakietu.

Dla wszystkich pojęć nie musisz tego robić. Pakiet jest dobry, ale pakiet wszystko i codziennie nie jest dobrze.

Być może możesz użyć Silex (Symfony micro framework) do opracowania swojego Proof of Concept w celu zmniejszenia wpływu pakietu stron trzecich.

 -2
Author: darkomen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-27 14:03:38