Význam a použití DI extension

jstas
Člen | 4
+
0
-

Zdravím!

Jako nezkušený programátor nedokážu rozpoznat, zda nepokládám stupidní dotaz, nicméně i přes veškerou svou snahu jsem nedokázal přijít na to, jakým způsobem fungují extensions v konfiguračním souboru config.neon. Možná mám problém se samotným pochopením významu extensions.

V rámci své aplikace, na které se s Nette seznamuji, jsem se rozhodl, že bych do konfiguračního souboru uložil jména některých tabulek z databáze (na tom v podstatě nesejde, mohlo to být cokoliv jiného). Cílem bylo v tomto souboru definovat (v podstatě) konstanty, které by se daly používat napříč projektem a v případě změny názvu tabulky se kód upravoval pouze na jednom místě. Rozšířil jsem tedy soubor config.neon o následující kód.

extensions:
	tables: App\Config\Extensions\TablesExtension

tables:
	# Config
	table_users: users_cs
	table_articles: articles_cs

Kód extension pak vypadá následovně.

<?php

namespace App\Config\Extensions;

use Nette\DI\CompilerExtension;

class TablesExtension extends CompilerExtension {
	public $config;

	public function loadConfiguration() {
		$this->config = $this->getConfig();
	}
}

Z vysvětlení a příkladů (v dokumentaci) mi není jasné, jak potom k datům z extension (očekávané v $config) přistoupím. Pokusím-li se TablesExtension dostat do nějaké třídy v aplikaci pomocí konstruktoru jako DI službu, nastane Nette\DI\ServiceCreationException, tedy toto.

Service 'settingsManager' (type of App\Managers\Settings\SettingsManager): Service of type App\Config\Extensions\TablesExtension needed by $tables in App\Managers\BaseManager::__construct() not found. Did you register it in configuration file?

Pokud TablesExtension přidám v config.neon i mezi services, předaná instance v BaseManager data (názvy tabulek) neobsahuje. To považuji už jen za výstřel do tmy. Skutečně netuším, jak správně tedy extensions kdekoliv v aplikaci využít. Předpokládal jsem, že blok kódu (níže), který je do metody loadConfiguration() přidáván v dokumentaci (na níž vede odkaz výše), nebudu potřebovat, neboť žádné prefixy nevyužívám a žádné další služby uvnitř této nevyužívám.

$builder = $this->getContainerBuilder();
$builder->addDefinition($this->prefix('articles'))
	->setFactory(App\Model\HomepageArticles::class, ['@connection'])
	->addSetup('setLogger', ['@logger']);

Nenašel by se zde prosím někdo, kdo by mi pomohl do problému trochu více zabřednout? Zajímá mě, jestli na problém pohlížím zcela špatně, nebo jen někde dělám nějakou hloupou chybu.

Mnohokrát Vám předem děkuji.

S pozdravem Honza

Šaman
Člen | 2667
+
+3
-

Na tohle DI extension vůbec nepotřebuješ. Jestli chceš jen načítat parametry z configu, tak si vytvoř nějakou třídu, třeba TableConfig, která v konstruktoru přijme pole parametrů, ideálně si je dokáže zvalidovat a potom je pomocí nějakých getterů dává.

V configu si v sekci parameters vytvoříš pole tables a pak toto pole předáš té třídě. Voila, máš třídu, která dostala z configu názvy tabulek a tu si injectuješ kam potřebuješ.

parameters:
	tables:
		table_users: users_cs
		table_articles: articles_cs

services:
	- App\…\TableConfig(%tables%)
class TableConfig
{

	/** @var array */
	protected $tables;


	/**
	 * @param array
	 */
	public function __construct(array $tables)
	{
		$this->tables= $tables;
	}


	/**
	 * @param string
	 * @return string
	 */
	public function getTable($name)
	{
		return $this->tables[$name];
	}

}

P.S. Je to nástřel bez namespaces, bez validace, případné traity SmartObject a bez PHP7 typů. Je to upravená funkčni ukázka z jednoho staršího projektu.

P.P.S. Jinak extension jsem nikdy nepotřeboval sám psát a mám dojem, že je to vyšší dívčí – když potřebuješ s třidama v DI kontejneru nějak dál manipulovat. Třeba DibiExtension umožňovala zápis databáze do vlastní sekce dibi, automaticky vytvořila třídy Dibi a konfiguraci jim předala a ještě to celé zaregistrovala do Tracy panelu, takže se tam ukazovaly dotazy do db. Tedy dělala nějakou magii na pozadí. Bez použití extension se musely údaje o připojení k DB zapsat do sekce parameters, pak v services zaregistrovat správné třídy a parametry jim předat a TracyPanel se dal zaregistrovat taky ručně.

Takže pokud chceš transparentní zápis a týká se to jen tvé aplikace, použij nějaký způsob jako jsem ukázal. Extension je opravdu rozšíření DI kontejneru ve smyslu přidat mu nějakou novou funkci, nebo syntax. Ty myslím potřebuješ obyčejnou práci s parametry, na což je ten DI kontejner a zápis v configu dělaný.

Editoval Šaman (14. 3. 2020 2:15)

jstas
Člen | 4
+
0
-

Zdravím!

Děkuji mnohokrát za vysvětlení. Přesně jsem potřeboval, aby mi někdo řekl, že se neorientuji správně, a navíc mě nasměroval tam, kam jsem se původně chtěl dostat.

Přiložený kód přesně a jednoduše řeší můj problém.

Díky z Váš čas!

S pozdravem Honza