Haruskah semuanya benar-benar bundel di Symfony 2.x?

205

Saya menyadari pertanyaan seperti ini , di mana orang cenderung membahas konsep bundel Symfony 2 umum.

Masalahnya adalah, dalam aplikasi tertentu, seperti, misalnya, aplikasi seperti twitter, haruskah semuanya benar-benar ada di dalam bundel generik, seperti yang dikatakan dokumen resmi ?

Alasan saya menanyakan hal ini adalah karena ketika kita mengembangkan aplikasi, secara umum, kita tidak ingin memasangkan kode kita ke beberapa kerangka kerja stack penuh.

Jika saya mengembangkan aplikasi berbasis Symfony 2 dan, pada titik tertentu, saya memutuskan Symfony 2 bukan pilihan terbaik untuk menjaga pengembangan berjalan , apakah itu akan menjadi masalah bagi saya?

Jadi pertanyaan umumnya adalah: mengapa semuanya menjadi bundel adalah hal yang baik?

EDIT # 1

Hampir setahun sekarang sejak saya mengajukan pertanyaan ini, saya menulis artikel untuk membagikan pengetahuan saya tentang topik ini.

Daniel Ribeiro
sumber
1
Ini hanya komentar, bukan jawaban. Saya pribadi berpikir, kita harus memilih kerangka kerja dengan hati-hati sebelum memulai proyek. Setiap kerangka kerja memiliki cara sendiri untuk melakukan hal-hal, sehingga akan menyediakan alat untuk mendukung cara yang terbaik. Jika kita suka seperti itu, kita ikuti. Ada pilihan lain di luar sana. Kami tidak ingin menggunakan pisau untuk memotong kayu, bukan gergaji. Tapi itu pertanyaan yang sangat menarik yang Anda ajukan :)
Anh Nguyen

Jawaban:

219

Saya telah menulis posting blog yang lebih menyeluruh dan diperbarui tentang topik ini: http://elnur.pro/symfony-without-bundles/


Tidak, tidak semuanya harus dalam satu bundel. Anda dapat memiliki struktur seperti ini:

  • src/Vendor/Model - untuk model,
  • src/Vendor/Controller - untuk pengontrol,
  • src/Vendor/Service - untuk layanan,
  • src/Vendor/Bundle- untuk bundel, seperti src/Vendor/Bundle/AppBundle,
  • dll.

Dengan cara ini, Anda hanya akan memasukkan AppBundlehal-hal yang benar-benar spesifik untuk Symfony2. Jika Anda memutuskan untuk beralih ke kerangka kerja lain nanti, Anda akan menyingkirkan Bundlenamespace dan menggantinya dengan hal-hal kerangka kerja yang dipilih.

Harap perhatikan bahwa yang saya sarankan di sini adalah untuk kode khusus aplikasi . Untuk bundel yang dapat digunakan kembali, saya masih menyarankan menggunakan praktik terbaik .

Menjaga entitas dari bundel

Untuk menjaga entitas di src/Vendor/Modelluar bundel apa pun, saya telah mengubah doctrinebagian config.ymldari

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

untuk

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

Nama-nama entitas - untuk diakses dari repositori Doktrin - mulai dengan Modeldalam kasus ini, misalnya Model:User,.

Anda dapat menggunakan subnamespaces untuk mengelompokkan entitas terkait bersama, misalnya src/Vendor/User/Group.php,. Dalam hal ini, nama entitas adalah Model:User\Group.

Menghindari pengontrol dari bundel

Pertama, Anda perlu memberi tahu JMSDiExtraBundle untuk memindai srcfolder untuk layanan dengan menambahkan ini ke config.yml:

jms_di_extra:
    locations:
        directories: %kernel.root_dir%/../src

Kemudian Anda mendefinisikan pengontrol sebagai layanan dan menempatkannya di bawah Controllernamespace:

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

Perhatikan bahwa saya menggunakan ElnurAbstractControllerBundle saya untuk menyederhanakan mendefinisikan pengontrol sebagai layanan.

Hal terakhir yang tersisa adalah memberi tahu Symfony untuk mencari templat tanpa bundel. Saya melakukan ini dengan mengesampingkan layanan penebak template, tetapi karena pendekatannya berbeda antara Symfony 2.0 dan 2.1, saya menyediakan versi untuk keduanya.

Mengganti penebak templat Symfony 2.1+

Saya telah membuat bundel yang melakukan itu untuk Anda.

Mengganti pendengar template Symfony 2.0

Pertama, tentukan kelasnya:

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

Dan kemudian beri tahu Symfony untuk menggunakannya dengan menambahkan ini ke config.yml:

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

Menggunakan templat tanpa bundel

Sekarang, Anda dapat menggunakan templat dari bundel. Simpan di bawah app/Resources/viewsfolder. Misalnya, templat untuk dua tindakan dari contoh controller di atas berada di:

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

Saat merujuk ke templat, cukup abaikan bagian bundel:

{% include ':Controller:view.html.twig' %}
Elnur Abdurrakhimov
sumber
2
Itu sebenarnya pendekatan yang sangat menarik. Dengan itu, saya juga dapat mengembangkan bundel nyata yang berisi serangkaian fitur spesifik yang dapat digunakan komunitas, tanpa menyatukan aplikasi saya ke framework itu sendiri.
Daniel Ribeiro
57
Untuk membuat kode yang Anda bagikan dengan komunitas yang tidak digabungkan dengan Symfony2 juga, Anda bisa meletakkan hal-hal umum ke perpustakaan dan kemudian membuat bundel yang mengintegrasikan perpustakaan itu dengan Symfony2.
Elnur Abdurrakhimov
9
Ini adalah ide yang menarik asalkan Anda tidak bergantung pada perintah pembuatan kode. generate:doctrine:crudmisalnya mengharapkan entitas (= model dalam kasus elnur) berada di dalam sebuah bundel agar dapat bekerja.
geca
2
Dengan pendekatan ini, adakah cara untuk mendapatkan kembali fungsionalitas antarmuka aplikasi / konsol CLI? Saya suka gagasan menjaga model saya di tempat di luar bundel apa pun, tetapi saya ingin mempertahankan akses ke fungsionalitas CLI.
Andy Baird
3
Ini harus dimasukkan ke dalam bundel :)
d0001
20

Tentu saja Anda dapat memisahkan aplikasi Anda. Hanya mengembangkannya sebagai perpustakaan dan mengintegrasikannya ke vendor/folder symfony (baik dengan menggunakan depsatau composer.json, tergantung apakah Anda menggunakan Symfony2.0 atau Symfony2.1). Namun, Anda memerlukan setidaknya satu bundel, yang bertindak sebagai "frontend" dari perpustakaan Anda, tempat Symfony2 menemukan controller (dan semacamnya).

KingCrunch
sumber
2
Karena tag, symfony-2.0saya anggap Anda menggunakan versi 2.0 saat ini. Dalam hal ini buat repositori git di mana pun Anda suka dan masukkan semuanya ke dalamnya, apa yang ingin Anda kembangkan independen dari symfony. Dalam proyek-symfony Anda, perbarui deps-file Anda seperti yang disebutkan di sini symfony.com/doc/current/cookbook/workflow/... Kemudian buat satu (atau lebih) bundel aplikasi () ( php app/console generate:bundle) untuk barang-barang khusus symfony.
KingCrunch
11

Distribusi symfony biasa dapat bekerja tanpa bundel (aplikasi) tambahan, tergantung pada seberapa banyak fungsionalitas yang ingin Anda gunakan dari kerangka stack penuh.

Misalnya, pengontrol Anda bisa berupa panggilan apa pun yang dapat diletakkan di mana saja dalam struktur proyek Anda, segera setelah mereka dimuat secara otomatis.

Dalam file definisi perutean, Anda dapat menggunakan:

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

Itu bisa berupa objek php lama biasa, hanya terikat pada kerangka oleh fakta bahwa ia harus mengembalikan Symfony\Component\HttpFoundation\Responseobjek.

Templat ranting Anda (atau yang lain) dapat diletakkan seperti app/Resources/views/template.html.twigdan dapat dirender menggunakan ::template.html.twignama logis.

Semua layanan DI dapat didefinisikan di app / config / config.yml (atau diimpor dari app/config/services.ymlmisalnya, dan semua kelas layanan dapat berupa objek php lama yang biasa juga. Tidak terikat dengan kerangka kerja sama sekali.

Semua ini disediakan secara default oleh framework full stack symfony.

Di mana Anda akan memiliki masalah adalah ketika Anda ingin menggunakan file terjemahan (seperti xliff), karena mereka ditemukan hanya melalui bundel .

The symfony cahaya tujuan distribusi untuk memecahkan masalah semacam ini dengan menemukan segala sesuatu yang akan biasanya ditemukan hanya melalui bundel.

Florian Klein
sumber
5

Anda bisa menggunakan KnpRadBundle , yang mencoba menyederhanakan struktur proyek.

Pendekatan lain adalah menggunakan src/Company/Bundle/FrontendBundlemisalnya untuk bundel dan src/Company/Stuff/Class.phpuntuk kelas-kelas yang symfony independen dan yang dapat digunakan kembali di luar kerangka kerja

miguel_ibero
sumber
Tapi kemudian saya akan menggabungkan aplikasi ke KnpRadBundle ... Apakah tidak ada pendekatan yang lebih mudah dalam hal ini?
Daniel Ribeiro
1
Bagian-bagian yang bergantung pada symfony (Pengontrol, Model, templat, dll ...) akan selalu digabungkan ke symfony, karena Anda menggunakannya (memperluas kelas, menggunakan bantuan, dll ...). Kelas-kelas yang bekerja sendiri akan berada di namespace Perusahaan, dan Anda bisa memuatnya menggunakan wadah dependensi. Kelas-kelas ini dapat menjadi kerangka kerja independen.
miguel_ibero
1
Masalahnya, konsep Bundlelangsung berbagi secara publik. Ketika saya menulis beberapa aplikasi, saya tidak ingin membagikan kode saya, kecuali untuk bagian-bagian yang saya sengaja buat sebagai modul berbasis komunitas. Apakah aku salah?
Daniel Ribeiro
Anda tidak harus membagikan bundel. Pikirkan bundel sebagai sekelompok kelas dengan beberapa konfigurasi. Di setiap proyek Anda dapat memiliki bundel yang berbeda.
miguel_ibero
Anda harus membaca buku symfony
miguel_ibero
5

Karena sudah 5 tahun berlalu, berikut adalah beberapa artikel tentang Bundel Symfony.

  1. Apa itu Bundel dalam Symfony? oleh Iltar van der Berg.

TLDR:

Apakah Anda memerlukan banyak bundel dalam aplikasi Anda secara langsung? Kemungkinan besar tidak. Anda lebih baik menulis AppBundle untuk mencegah spageti dependensi. Anda cukup mengikuti praktik terbaik dan itu akan berfungsi dengan baik.

  1. Symfony: Cara Membundel oleh Toni Uebernickel.

TLDR:

Buat hanya satu bundel yang disebut AppBundle untuk logika aplikasi Anda. One AppBundle - tapi tolong jangan menaruh logika aplikasi Anda di sana!

Reshat Belyalov
sumber
-2

Kerangka kerja Symfony sangat baik untuk meluncurkan bukti konsep dengan cepat dan semua kode dapat dimasukkan dalam aplikasi bundel default di src /

Dalam bundel ini, Anda dapat menyusun kode sesuai keinginan.

Setelah jika Anda ingin menggunakan teknologi lain untuk mengembangkan POC Anda, Anda dapat dengan mudah menerjemahkannya karena Anda tidak menyusun semua kode Anda dalam konsep paket.

Untuk semua konsep Anda tidak melakukan ekstremisme ini. Bundel itu bagus tapi bundel segalanya dan setiap hari tidak bagus.

Mungkin Anda dapat menggunakan Silex (kerangka mikro Symfony) untuk mengembangkan Bukti Konsep Anda untuk mengurangi dampak bundel pihak ketiga.

wanita gelap
sumber