Rozšíření ContainerBuilder

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Trunda
Člen | 26
+
0
-

Zdravím,

z jistého důvodu jsem si chtěl rozšířit ContainerBuilder, ale zjistil jsem nepříjemnou věc. Vzhledem k tomu, že Nette\Config\Compiler má vlastnost container privátní, není možné vlastní implementaci ContainerBuilderu do Compileru injectnout.

Uniká mi něco? Proč je container private?

Filip Procházka
Moderator | 4668
+
0
-

Proč bys něco takového dělal? Určitě najdeme lepší řešení, než hackovat „jádro“ Nette.

Trunda
Člen | 26
+
0
-

V pozadí této změny je lenost a pohodlnost ;). Pokusím se to popsat:

Přepsal jsem si své nadstavby, resp. jejich zavedení do DI, jako CompilerExtensions, a mým cílem bylo aby mi IDE napovídalo i pro NestedAccesor. Jediná možnost jak to udělat je upravit generování SystemContaineru tak aby „vyrobil“ více tříd resp. třídu pro každý současný NestedAccesor a přidal k ní dokumentaci jejich properties. Pak by IDE napovídalo například u Doctrine 2 a NestedSet i tuto konstrukci:

// Presneter
$this->context->doctrine->nestedSet->getManager('Entita');
// nebo i
$this->context->doctrine->entityManager;

Původně jsem to chtěl udělat také jako extension v metodě afterCompile, ale to vzhledem k tomu, že generováná třída (istance třídy Nette\Utils\PhpGenerator\ClassType) není předávána referencí nelze.

Vím že IDE mi bude napovídat pro tuto konstrukci:

// Presneter
$this->context->doctrine_nestedSet->getManager('Entita');
// nebo i
$this->context->doctrine_entityManager;

ale já to podtržítko prostě nemůžu vystát :)

Doufám, že je to pochopitelné.

Editoval Trunda (18. 1. 2012 15:14)

Filip Procházka
Moderator | 4668
+
0
-

V první řadě bych si rejpl. Třídy se vždy předávají „referencí“. Když někam předáváš objekt, tak je to pořád ten stejný objekt, po cestě přes argumenty metody se ti sám neklonuje ;)

Co se týče toho napovídání, určitě by bylo lepší udělat podporu přímo do Nette. Já bych to také ocenil ;) Pokud víš jak, úplně nejlepší by bylo, kdyby jsi to implementoval a poslal pull request na githubu.

Trunda
Člen | 26
+
0
-

ad rejpnutí: jasně, asi jsem měl napsat že tu referenci „ukazatel do paměti“ nemohu změnit, mohu změnit objekt na kterž ukazuje, myslím že si rozumíme.

myslím že vím, ok pokusím se o to.

Trunda
Člen | 26
+
0
-

HosipLan napsal(a):

Pokud víš jak, úplně nejlepší by bylo, kdyby jsi to implementoval a poslal pull request na githubu.

Tak jsem to sepsal viz https://github.com/…ea7878553342

Je to ozkoušené a funguje to dobře.

pokud mám například rozšíření:

class ConfigExtension extends Nette\Config\CompilerExtension
{
    public function loadConfiguration()
    {
        $container = $this->getContainerBuilder();
        $container->addDefinition($this->prefix('bar'))
                ->setClass('Foo\Bar')
                ->setFactory(__CLASS__ . '::createBar');
    }

    /**
     * @return Foo\Bar
     */
    public static function createBar()
    {
        return new Foo\Bar;
    }

}

Vytvoří to container:

/**
 * @property Nette\Application\Application $application
 * @property Nette\Caching\Storages\FileJournal $cacheJournal
 * @property Nette\Caching\Storages\FileStorage $cacheStorage
 * @property Symfony\Component\Console\Application $console
 * @property NestedAccessor_constants $constants
 * @property Nette\DI\Container $container
 * @property NestedAccessor_foo $foo
 * @property Nette\Http\Context $httpContext
 * @property Nette\Http\Request $httpRequest
 * @property Nette\Http\Response $httpResponse
 * @property Nette\Mail\SendmailMailer $mailer
 * @property NestedAccessor_nette $nette
 * @property NestedAccessor_php $php
 * @property Nette\Application\PresenterFactory $presenterFactory
 * @property Nette\Application\Routers\RouteList $router
 * @property Nette\Http\Session $session
 * @property Nette\Caching\Storages\PhpFileStorage $templateCacheStorage
 * @property Nette\Security\User $user
 * @property Nette\Http\UserStorage $userStorage
 */
class SystemContainer extends Nette\DI\Container
{
	/**
	 * @return NestedAccessor_php
	 */
	protected function createServiceFoo()
	{
		$service = new NestedAccessor_foo($this, 'foo');
		return $service;
	}

	// ....
}

// ....

/**
 * @property Foo\Bar $bar
 */
class NestedAccessor_foo extends Nette\DI\NestedAccessor
{
}

Takže IDE napovídá jak má :).

David Grudl
Nette Core | 8228
+
0
-

Jde to i jednodušeji

Filip Procházka
Moderator | 4668
+
0
-

Díky Davide, moc jsem si oddychl ;)

Trunda
Člen | 26
+
0
-

Díky, mohu se zeptat proč se na řádku 133 nekontroluje přítomnost definice? Pokud mám rozšíření, které obsahuje definici jen jedné služby, nemohu pro něj použít přímo jméno rozšíření a zanáším si tak „jmenný prostor“ pouze s jednou službou.

Ukázka:

class ConfigExtension extends Nette\Config\CompilerExtension
{
    public function loadConfiguration()
    {
        $container = $this->getContainerBuilder();
        $container->addDefinition($this->name)
                ->setClass('Foo\Bar')
                ->setFactory(__CLASS__ . '::createBar');
    }

    /**
     * @return Foo\Bar
     */
    public static function createBar()
    {
        return new Foo\Bar;
    }

}
Filip Procházka
Moderator | 4668
+
0
-

To je ale tvoje mínus, že. Pokud máš jen jednu službu, dej ji do configu ;)

Trunda
Člen | 26
+
0
-

Není to konkrétně můj problém, psal jsem to jako otázku. Jestli to má hlubší význam. Ale díky.

David Grudl
Nette Core | 8228
+
0
-

Mám takovou představu, že každá služba by existovala ve vlastním „namespace“, který představuje název rozšíření. Z důvodů historickým jsou služby Nette bez prefixu, ale nové služby už taky prefixuju.