Чи все дійсно повинно бути пакетом у Symfony 2.x?


205

Я в курсі питань , як це , де люди , як правило , щоб обговорити загальну концепцію Symfony 2 з пучка.

Річ у тому, що у певній програмі, як, наприклад, у твіттерній програмі, чи все дійсно повинно знаходитись у загальному пакеті, як кажуть офіційні документи ?

Причина, про яку я прошу це, полягає в тому, що, коли ми розробляємо додатки, ми взагалі не хочемо сильно поєднувати наш код з якоюсь повною стеклянною рамкою клею.

Якщо я розробляю додаток на базі Symfony 2, і в якийсь момент я вирішу, що Symfony 2 не є найкращим вибором для продовження розвитку , чи це буде для мене проблемою?

Отже, загальне питання: чому все, що є в'язком, є хорошою справою?

ЗРІД №1

Майже рік тому, як я задав це питання, я написав статтю, щоб поділитися своїми знаннями з цієї теми.


1
Це лише коментар, а не відповідь. Я особисто думаю, що ми повинні ретельно вибирати рамки перед початком проекту. Кожен фреймворк має свій власний спосіб робити речі, тому він надасть інструменти, які найкраще підтримують цей спосіб. Якщо нам це подобається, ми слідуємо. Є й інші варіанти. Ми не хочемо використовувати ніж для різання деревини замість пилки. Але це дуже цікаве питання, яке ви поставили :)
Anh Nguyen

Відповіді:


219

Я написав більш ретельне та оновлене повідомлення в блозі на цю тему: 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

Імена Entities s - для доступу з Доктрини сховищ - Почнемо з того, 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
        ];
    }
}

Зауважте, що я використовую свій ElnurAb абстрактControllerBundle для спрощення визначення контролерів як служб.

Останнє, що залишилося - сказати 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' %}

2
Це насправді цікавий підхід. З цим я можу також розробити реальні пакети, що містять певний набір функцій, якими може користуватися спільнота, не зв'язавши навряд чи мій додаток із самим фреймворком.
Даніель Рібейро

57
Щоб код, яким ви ділитесь із спільнотою, не поєднувався також із Symfony2, ви можете помістити загальні речі в бібліотеку, а потім створити пакет, який інтегрує цю бібліотеку з Symfony2.
Ельнур Абдурахімов

9
Це цікава ідея, доки ви не покладаєтесь на жодну з команд генерації коду. generate:doctrine:crudнаприклад, очікує, що сутність (= модель у випадку elnur) буде всередині пакета для того, щоб працювати.
geca

2
При такому підході чи є можливість відновити функціональність інтерфейсу програми / консолі CLI? Мені подобається ідея зберігати мої моделі на місці поза будь-яким пакетом, але я хотів би зберегти доступ до функцій CLI.
Енді Бейрд

3
Це слід скласти в пакет :)
d0001

20

Звичайно, ви можете скасувати заявку. Просто розробіть його як бібліотеку та інтегруйте її у папку vendor/symfony (або використовуючи depsабо composer.json, залежно від того, як ви використовуєте Symfony2.0 або Symfony2.1). Однак вам потрібен принаймні один пакет, який виконує функцію "фронтенду" вашої бібліотеки, де Symfony2 знаходить контролер (і подібний).


2
Через тег symfony-2.0я вважаю, що ви використовуєте поточну версію 2.0. У цьому випадку створіть сховище git, де вам подобається, і вкладіть у нього все, що ви хочете розвинути незалежно від symfony. У вашому Symfony-проекті оновіть свій файл, depsяк згадується тут symfony.com/doc/current/cookbook/workflow/… Потім просто створіть один (або більше) пакетів (-ів) додатків ( php app/console generate:bundle) для специфічних для сімфонії матеріалів.
KingCrunch

11

Звичайний симфонічний розподіл може працювати без додаткового пакету (додатків), залежно від того, скільки функцій ви хочете використовувати від повної рамки стека.

Наприклад, ваші контролери можуть мати будь-який дзвінок, який можна розмістити в будь-якому місці вашої структури проекту, як тільки вони завантажуються автоматично.

У файлі визначення маршруту ви можете використовувати:

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

Це може бути будь-який звичайний старий php-об'єкт, прив’язаний до рамки лише тим фактом, що він повинен повернути Symfony\Component\HttpFoundation\Responseоб'єкт.

Ваші шаблони гілочок (або інші) можуть бути розміщені як app/Resources/views/template.html.twigі можуть бути відображені за допомогою ::template.html.twigлогічного імені.

Усі послуги DI можуть бути визначені в app / config / config.yml (або імпортовані з, app/config/services.ymlнаприклад, і всі класи сервісів можуть бути і будь-якими простими старими PHP-об'єктами. Не пов'язані з рамкою взагалі.

Все це за замовчуванням надається повною рамкою стека symfony.

Де у вас виникнуть проблеми, коли ви захочете використовувати файли перекладу (наприклад, xliff), оскільки вони виявляються лише через пакети .

Розподіл симфоні-світла має на меті вирішити подібні проблеми, виявивши все, що зазвичай було б відкрито лише через пучки.


5

Ви можете використовувати KnpRadBundle , який намагається спростити структуру проекту.

Інший підхід полягає у використанні, src/Company/Bundle/FrontendBundleнаприклад, для пакетів та src/Company/Stuff/Class.phpкласів, які є симфонічно незалежними та які можуть бути повторно використані поза рамками


Але тоді я б з'єднав додаток до KnpRadBundle ... Чи не існує простішого підходу до цього питання?
Даніель Рібейро

1
Частини, які залежать від symfony (Контролери, Моделі, шаблони тощо), завжди будуть поєднані з symfony, оскільки ви користуєтесь ним (розширення класів, використання помічників тощо). Класи, які працюють окремо, будуть знаходитись у просторі імен компанії, і ви можете завантажити їх за допомогою контейнера залежності. Ці заняття можуть бути рамковими незалежними.
miguel_ibero

1
Вся справа в тому, що концепція Bundleіде безпосередньо на публічний обмін. Коли я пишу якусь заявку, я не хочу ділитися своїм кодом, за винятком тих частин, які я навмисно побудував як модулі, керовані громадою. Я помиляюся?
Даніель Рібейро

Вам не доведеться ділитися пакетами. Подумайте про групу як про групу класів з деякою конфігурацією. У кожному проекті ви можете мати різні пакети.
miguel_ibero

Вам слід прочитати книгу
сімфоні

5

Оскільки минуло вже 5 років, ось ще кілька статей про пакети Symfony.

  1. Що таке пачки в Symfony? Ільтар ван дер Берг.

TLDR:

Вам потрібно кілька пакетів у вашій програмі безпосередньо? Швидше за все, ні. Вам краще писати AppBundle, щоб запобігти спагетті залежностей. Ви можете просто дотримуватися кращих практик, і це буде добре.

  1. Симфонія: Як зв’язати Тоні Убернікеля.

TLDR:

Створіть лише один пакет під назвою AppBundle для логіки вашої програми. Один AppBundle - але, будь ласка, не вкладайте туди свою логіку програми!


-2

Symfony Framework дуже хороший для швидкого запуску доказів концепції, і весь код може входити в додаток до пакету за замовчуванням у src /

У цьому пакеті ви можете структурувати свій код за своїм бажанням.

Якщо ви хочете використовувати іншу технологію для розробки свого POC, ви можете легко перекласти це, оскільки ви не структуруєте весь свій код у концепції розробки.

Для всієї концепції ви цього не екстремізували. Пачка - це добре, але зв'язуйте все, і кожен день - це не добре.

Можливо, ви можете використовувати Silex (мікро-рамку Symfony), щоб розробити Proof of Concept для зменшення впливу сторонніх постачальників.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.