JSifalda's blog

The simple way




Nette moduly (a vlastní instalátor) #3

Po tom co Filip Procházka nastínil svůj koncept řešení problému modulů dostali věci kolem modulů rychlý spád.

I já jsem si vzal z Filipova konceptu inspiraci a vytvořil jsem Nette rozšíření Flame/Modules, které implementuje právě zmíněný koncept + několik dalších fičurek.

Repositář Flame/Modules je vlastně jednoduché (s takřka žádnými nároky na výkon) Nette rozšíření s vlastním extensions instalátorem.

Motivace

Celé je to postavené na tom, že chceme mít co nejsnadnější distribuci Nette modulů a to jen tak, že zaregistrujeme v composer.json balíček modulu a Composer se o vše ostatní postará sám. A tak to skutečně funguje!

Minimální konfigurace

Flame/Modules lze použít samostatně - nezávisle na Flame/Framework. Ale Flame fw tomu přidá trochu syntax cukříku:

bootstrap.php

$configurator = new \Flame\Configurator;
$configurator->createModulesInstaller()
    ->addConfig(__DIR__ . '/config/extensions.php')
    ->register();
return $configurator;

TIP: Configurační soubor může být ve formátu NEON

Jediné, co je tedy potřeba v bootstrapu udělat je to, že vytvoříte Modules installer, přidáme configurační soubor, kde je seznam extensions, které chcete zaregistrovat.

TIP: Pokud chcete zaregistrovat pouze jedno rozšíření a nestarat se tak o celý configurační soubor, můžete použít metodu registerExtension($extension)

Konfigurace zapsaná v syntaxi php může vypadat takto:

extensions.php

return array(
    'modules' => array(
        'REST' => 'Flame\Rest\DI\RestExtension',
        'doctrine' => 'Flame\Doctrine\DI\OrmExtension',
        'events' => 'Kdyby\Events\DI\EventsExtension',
        'Enlan\CategoryModule\DI\CategoryExtension',
        'Enlan\UserModule\DI\UserExtension',
        'Flame\CMS\AngularModule\DI\AngularExtension'
    )
);

Pokud používáte balíček, který je kompatibilní s Flame/Modules, Composer se vám bude starat o konfiguraci extensions sám - bude přidávat/odebírat jednotlivé rozšíření do konfiguračního souboru vzhledem k tomu, co se nachází v composer.json.

Proč nepoužít standarní "ExtensionsExtension"?

Pokud by se vám zdálo, že použítí Modules instalatéru je zbytečné a že by se tedy stačilo spolehnout pouze na dostupný ExtensionsExtension, tak vás musím přesvědčit o opaku.

Takto zaregistrované rozříšení není plnohodnotným rozšířením, protože se nezpracová současně s dalšími rozšířeními zaregistrovanými z bootstrapu, ale až později. A to s sebou nese spoustu omezení, jako např. nemožnost použít IEntityProvider z mého oblíbeného balíčku Kdyby/Doctrine. Takto zpětně zaregistrované rozšíření není dostupné při konfiguraci OrmExtension.

Providers

A teď jednotlivě k dostupným rozhraním, které může implementovat vaše rozšíření.

IConfigProvider

Asi nejkurióznější rozhraní, které můžete použít, pokud jste líní a nechcete se pouštět do konfigurace pomocí php. Metoda getConfigFiles() vrací pole neon configuračních souborů.

V praxi se však nedoporučuje používat.

ILatteMacrosProvider

Rozhraní, které můžete použít, pokud chcete do šablon zaregistrovat vlastní makra. Metoda getLatteMacros() vrací pole s makro sety.

Ukázka:

/**
 * Get array of latte macros classes
 *
 * @return array
 */
public function getLatteMacros()
{
    return array(
        'Flame\CMS\AngularModule\Templating\AngularMacros'
    );
}

IPresenterMappingProvider

Implementujte pokud potřebujete specifikvoat namespace mapping pro daný modul. Ukázka:

/**
 * Returns array of ClassNameMask => PresenterNameMask
 *
 * @see https://github.com/nette/nette/blob/master/Nette/Application/PresenterFactory.php#L138
 * @return array
 */
public function getPresenterMapping()
{
    return array(
        'Angular' => 'Flame\CMS\AngularModule\*Module\Presenters\*Presenter'
    );
}}

IRouterProvider

Asi jedno z nejužitečnějších rozhraní. Implementujte ho pokud má mít vaše rozšíření vlastní routy.

Ukázka:

/**
 * Returns array of ServiceDefinition,
 * that will be appended to setup of router service
 *
 * @example
 * return array(
 *      array('Nette\Application\Routers\Route' => array('/', array(
 *          'presenter' => 'Homepage',
 *          'action' => 'default'
 *      )))
 * );
 */
function getRoutesDefinition()
{
    return array(
        array('Nette\Application\Routers\Route' => array('/', array(
            'module' => 'Enlan',
            'presenter' => 'Homepage',
            'action' => 'default'
        ))),
        array('AdamStipak\RestRoute' => array('Api:V1', 'json', true))
    );
}

Rád bych, aby metoda getRoutesDefinition() vracela pole již nakonfigurovaných rout, aby nebylo třeba této složité konfigurace přes další array. Nette cache něco takového zatím ale nepodporuje.

V plánu je doimplementovat zmíněné ITracyPanelsProvider, ITracyBarPanelsProvider nebo např. ILatteHelpersProvider.

Vytvoření vlastního modulu

Každý Nette Modul musí mít vlastní rozšíření.

Doporučuji podědit NamedExtension pro snadnější práci a lepší kompatibilitu (není však podmínkou).

TIP: Pokud chcete mít na starost samostatnou registraci extension můžete implementovat rozhraní IDomainExtension a metodu register(Configurator $configurator)

Pokud chceme, aby se registraci rozšíření postaral sám Composer, musíme v composer.json definovat sekci extra:

{
     "extra": {
        "module": {
          "class": "Flame\\CMS\\AngularModule\\DI\\AngularExtension",
          "name": "Angular"
        }
      }
}

"name" není nutné specifikovat.

To hlavní je, že nesmíme zapomenout pozměnit "type" daného balíčku ze standartního "library" na "nette-module"

"type": "nette-module",

Kompletní ukázka souboru composer.json

A to je vše!

O všechno ostatní se už postará vlastní composer instalátor.

Pokud chcete i vy vyzkoušet Flame/Modules tak přidejte do svého composer.json:

{
    "require": {
        "flame/framework": "dev-master",
        "flame/modules": "dev-master",
        "flame/module-installer": "@dev"
    }
}

Pokud se chcete podívat na jednoduchou implentaci Flame/Modules v praxi tak doporučuji Flame\CMS\ErrorModule nebo Flame\CMS\AngularModule. Případně složitější ukázky na Bitbucketu

~~Flame/Modules jsou kompatibilní jen s @dev verzí Nette~~

Flame/Modules jsou nyní plně kompatibilní i s @stable verzí Nette


Za zmínku taktéž stojí pokus o implementaci Modular od @mishak87

Co si o tom myslíte vy? Budete používat Flame/Modules? :-)

13.08.2013 at 14:18:06