Symfony 2.x'te her şey gerçekten bir paket olmalı mı?


205

Ben gibi sorular farkındayım bu insanlar demetinin genel Symfony'nin 2 kavramını tartışmak eğilimindedir.

Mesele şu ki, belirli bir uygulamada, örneğin, twitter benzeri bir uygulamada, her şey gerçekten resmi belgelerin dediği gibi genel bir paket içinde olmalı mı?

Bunu sormamın nedeni, uygulamaları geliştirirken, genel olarak kodumuzu tam yığın yapıştırıcı çerçevesiyle birleştirmek istemiyoruz.

Symfony 2 tabanlı bir uygulama geliştirirsem ve bir noktada Symfony 2'nin gelişimi devam ettirmek için gerçekten en iyi seçim olmadığına karar veririm , bu benim için bir sorun olacak mı?

Genel soru şudur: Neden her şey bir demet olmak iyi bir şeydir?

DÜZENLEME 1.

Bu soruyu sorduğumdan neredeyse bir yıl sonra bu konu hakkındaki bilgimi paylaşmak için bir makale yazdım .


1
Bu sadece bir yorum, cevap değil. Şahsen, projeye başlamadan önce çerçeveyi dikkatle seçmeliyiz. Her çerçevenin bir şeyler yapmak için kendi yolu vardır, bu nedenle bu yolu en iyi şekilde destekleyecek araçlar sağlayacaktır. Eğer bu şekilde seversek takip ederiz. Orada başka seçenekler var. Tahtayı kesmek için testere yerine bıçak kullanmak istemiyoruz. Ama çok ilginç bir soru sordun :)
Anh Nguyen

Yanıtlar:


219

Bu konuda daha ayrıntılı ve güncel bir blog yazısı yazdım: http://elnur.pro/symfony-without-bundles/


Hayır, her şeyin bir paket halinde olması gerekmez. Bunun gibi bir yapıya sahip olabilirsiniz:

  • src/Vendor/Model - modeller için,
  • src/Vendor/Controller - kontrolörler için,
  • src/Vendor/Service - hizmetler için,
  • src/Vendor/Bundle- demetler gibi src/Vendor/Bundle/AppBundle,
  • vb.

Bu şekilde, AppBundlegerçekten Symfony2'ye özgü olan şeyleri koyacaksınız . Daha sonra başka bir çerçeveye geçmeye karar verirseniz, Bundlead alanından kurtulur ve seçilen çerçeve öğeleriyle değiştirirsiniz.

Burada önerdiğim şeyin uygulamaya özel kod için olduğunu lütfen unutmayın . Yeniden kullanılabilir paketler için hala en iyi uygulamaları kullanmanızı öneririm .

Varlıkları grupların dışında tutma

Varlıkları tutmak için src/Vendor/Modelherhangi bir paketin dışına, ben değiştim doctrinebölümüne config.ymlgelen

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

için

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

Varlıkların adları - Doktrin depolarından erişmek için - Modelbu durumda, örneğin,Model:User .

İlgili varlıkları birlikte gruplandırmak için alt ad alanlarını kullanabilirsiniz, örneğin src/Vendor/User/Group.php. Bu durumda, işletmenin adı Model:User\Group.

Denetleyicileri paketlerin dışında tutma

İlk olarak, JMSDiExtraBundle'asrc klasörü hizmetler için taramasını şunu eklemeniz gerekir config.yml:

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

Daha sonra denetleyicileri hizmetler olarak tanımlar ve Controllerad alanının altına koyarsınız :

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

ElnurAbstractControllerBundle'ımı denetleyicileri hizmetler olarak tanımlamayı kolaylaştırmak için kullandığımı unutmayın .

Kalan son şey Symfony'a paketsiz şablon aramasını söylemektir. Bunu şablon tahmin hizmetini geçersiz kılarak yapıyorum, ancak Symfony 2.0 ve 2.1 arasındaki yaklaşım farklı olduğundan, her ikisi için de sürümler sağlıyorum.

Symfony 2.1+ şablon tahmincisini geçersiz kılma

Bunu sizin için yapan bir paket hazırladım .

Symfony 2.0 şablon dinleyicisini geçersiz kılma

İlk önce sınıfı tanımlayın:

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

Ve sonra Symfony'a bunu ekleyerek onu kullanmasını söyleyin config.yml:

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

Şablonları demetsiz kullanma

Artık şablonları paketlerin dışında kullanabilirsiniz. Bunları app/Resources/viewsklasörün altında tutun . Örneğin, yukarıdaki örnek denetleyiciden bu iki eylemin şablonları şu konumda bulunur:

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

Bir şablona başvururken, paket parçasını atlamanız yeterlidir:

{% include ':Controller:view.html.twig' %}

2
Bu gerçekten ilginç bir yaklaşım. Bununla birlikte, uygulamanızı çerçevenin kendisine bağlamadan, topluluğun kullanabileceği belirli özellikler içeren gerçek paketler de geliştirebilirim.
Daniel Ribeiro

57
Toplulukla paylaştığınız kodu da Symfony2 ile eşleşmemiş hale getirmek için, genel bilgileri bir kütüphaneye koyabilir ve ardından bu kütüphaneyi Symfony2 ile entegre eden bir paket oluşturabilirsiniz.
Elnur Abdurrakhimov

9
Kod oluşturma komutlarının hiçbirine güvenmediğiniz sürece bu ilginç bir fikirdir. generate:doctrine:crudörneğin, işletmenin (= elnur'un durumunda model) çalışabilmesi için bir paketin içinde olmasını bekler.
geca

2
Bu yaklaşımla CLI uygulama / konsol arayüzünün işlevselliğini yeniden kazanmanın bir yolu var mı? Modellerimi herhangi bir paketin dışında bir yerde tutma fikrini seviyorum, ancak CLI işlevselliğine erişimi korumak istiyorum.
Andy Baird

3
Bu bir pakete
konulmalıdır

20

Tabii ki uygulamanızı deşifre edebilirsiniz. Sadece bir kütüphane olarak geliştirin ve symfony vendor/-folder'a entegre edin ( Symfony2.0 veya Symfony2.1 kullanıp kullanmadığınıza bağlı olarak depsveya kullanarak composer.json). Ancak, Symfony2'nin denetleyiciyi (ve benzeri) bulduğu kütüphanenizin "ön ucu" olarak işlev gören en az bir pakete ihtiyacınız vardır.


2
Etiketi nedeniyle symfony-2.0geçerli 2.0 sürümünü kullandığınızı varsayacağım. Bu durumda, istediğiniz yerde bir git deposu oluşturun ve her şeyi içine koyun, sembolizmden bağımsız olarak geliştirmek istediğiniz şeyi koyun. Senin symfony-proje güncellemede senin depsburada sözü gibi -dosyadan symfony.com/doc/current/cookbook/workflow/... Sonra sadece bir (veya daha fazla) uygulama paketi (ler) (oluşturmak php app/console generate:bundlesymfony özgü şeyler için).
KingCrunch

11

Genel bir symfony dağıtımı, tam yığın çerçevesinden ne kadar işlevsellik kullanmak istediğinize bağlı olarak herhangi bir ek (uygulama) paketi olmadan çalışabilir.

Örneğin, denetleyicileriniz otomatik olarak yüklenir yüklenmez proje yapınızın herhangi bir yerine yerleştirilebilecek herhangi bir çağrılabilir olabilir.

Bir yönlendirme tanımı dosyasında şunları kullanabilirsiniz:

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

Herhangi bir düz eski php nesnesi olabilir, sadece bir Symfony\Component\HttpFoundation\Responsenesneyi döndürmek zorunda kalmasıyla çerçeveye bağlanır .

Dal şablonlarınız (veya diğerleri) mantıklı ad app/Resources/views/template.html.twigkullanılarak oluşturulabilir ve oluşturulabilir ::template.html.twig.

Tüm DI hizmetleri app / config / config.yml içinde tanımlanabilir (veya app/config/services.ymlörneğin içe aktarılabilir) ve tüm hizmet sınıfları da herhangi bir düz eski php nesnesi olabilir.

Tüm bunlar varsayılan olarak symfony tam yığın çerçevesi tarafından sağlanır.

Sorun yaşayacağınız yer, çeviri dosyaları (xliff gibi) kullanmak isteyeceğiniz zamandır, çünkü bunlar yalnızca paketler aracılığıyla keşfedilir .

Symfony ışık dağılımı amaçları genellikle sadece demetleri aracılığıyla keşfedilecek her şeyi keşfederek bu sorunları çözmek için.


5

Proje yapısını basitleştirmeye çalışan KnpRadBundle kullanabilirsiniz .

Başka bir yaklaşım, src/Company/Bundle/FrontendBundleörneğin paketler ve src/Company/Stuff/Class.phpsembolik bağımsız olan ve çerçevenin dışında tekrar kullanılabilen sınıflar için kullanmaktır


Ama sonra uygulamayı KnpRadBundle'a bağlayacağım ... Bu konuda daha kolay bir yaklaşım yok mu?
Daniel Ribeiro

1
Symfony'ye bağlı parçalar (Denetleyiciler, Modeller, şablonlar, vb.) Kullandığınız için her zaman semfoniye bağlanır (sınıfları genişletmek, yardımcıları kullanmak vb.). Tek başına çalışan sınıflar Şirket ad alanında olacaktır ve bunları bağımlılık kapsayıcısını kullanarak yükleyebilirsiniz. Bu sınıflar çerçeveden bağımsız olabilir.
miguel_ibero

1
Mesele şu ki, Bundledoğrudan halka açık paylaşma kavramı . Bir uygulama yazarken, kasıtlı olarak topluluk güdümlü modüller olarak yaptığım parçalar dışında kodumu paylaşmak istemiyorum. Yanlış mıyım?
Daniel Ribeiro

Paketleri paylaşmak zorunda değilsiniz. Bazı yapılandırmaya sahip bir grup sınıf olarak bir paket düşünün. Her projede farklı paketler olabilir.
miguel_ibero


5

Zaten 5 yıl geçtiğinden, Symfony Bundles hakkında birkaç makale daha var.

  1. Symfony'de Paketler Nelerdir? ile Iltar van der Berg.

TLDR:

Doğrudan uygulamanızda birden fazla pakete mi ihtiyacınız var? Büyük olasılıkla değil. Bir bağımlılık spagetti önlemek için bir AppBundle yazmak daha iyidir. Sadece en iyi uygulamaları takip edebilirsiniz ve iyi çalışır.

  1. Symfony: Toni Uebernickel tarafından nasıl paketlenir?

TLDR:

Uygulama mantığınız için yalnızca AppBundle adlı bir paket oluşturun. Bir AppBundle - ama lütfen uygulama mantığınızı oraya koymayın!


-2

Symfony çerçevesi hızlı bir kavram kanıtı başlatmak için çok iyi ve tüm kod src /

Bu pakette kodunuzu istediğiniz gibi yapılandırabilirsiniz.

Daha sonra POC'nizi geliştirmek için başka bir teknoloji kullanmak istiyorsanız, bunu kolayca çevirebilirsiniz çünkü tüm kodunuzu paket tasarımında yapılandırmazsınız.

Tüm konseptler için bunu aşmadınız. Paket iyi ama her şeyi paketleyin ve her gün iyi değil.

Belki de paket üçüncü tarafların etkisini azaltmak için Konsept Kanıtınızı geliştirmek için bir Silex (Symfony mikro çerçevesi) kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.