Jak získat službu ve statické třídě nebo objektu mimo DI

- Vojtěch Dobeš
- Gold Partner | 1316
Správným způsobem je si onu superCool službu předat do
daného kódu jako argument – to je DI. Je jedno, jestli to za tebe udělá
Nette, anebo si ji předáš ručně. To je jediný způsob, jak se vyhnout
Environment, který je postupně opouštěn právě proto, že
obchází transparentní předávání argumentů.
class MyObjectOutsideOfDIContainer
{
public static function methodThatNeedsSuperCoolService($superCoolService)
{
// no need for Environment...
}
}

- mkoubik
- Člen | 728
Já bych si na to asi napsal wrapper třídu, která bude používat DI, zaregistruješ si ji jako službu a ona pak bude ve svých metodách volat tu statickou.
Nevím přesně jak ta třída vypadá a jak ji chceš používat, ale něco takového by nešlo?
class Wrapper
{
private $dependency;
public function __construct(Dependency $dependency)
{
$this->dependency = $dependency;
}
public function coolMethod($param)
{
UglyStaticClass::$dependency = $this->dependency;
return UglyStaticClass::coolMethod($param);
}
}
Editoval mkoubik (20. 6. 2014 11:18)

- akadlec
- Člen | 1326
K těm statickým třídám/voláním, tady to mám v routeru:
$list[] = new NetteRouteMock('[!<locale [a-z]{2,4}>/]mailbox/<mailbox>', array(
'module' => 'Frontend',
'presenter' => 'Default',
'action' => 'default',
'mailbox' => array(
Route::FILTER_OUT => 'IPub\MailboxModule\Router\FoldersRouter::getFolderSlugById',
Route::FILTER_IN => 'IPub\MailboxModule\Router\FoldersRouter::getFolderIdBySlug'
),
'locale' => array(
Route::VALUE => 'en',
'fixity' => Route::CONSTANT,
)
));
a pak samotná classa:
class FoldersRouter
{
/**
* @param string $slug
*
* @return int|bool
*/
public static function getFolderIdBySlug($slug)
{
// Get module facade
$folderFacade = \Nette\Environment::getService('mailboxModule.folderFacade');
// Check if slug is number...
if (is_numeric($slug)) {
if ($folderEntity = $folderFacade->findOneByIdentifier((int) $slug)) {
return $folderEntity;
}
// Check if slug is string...
} else if (is_string($slug)) {
if ($folderEntity = $folderFacade->findOneBySlug((string) $slug)) {
return $folderEntity;
}
}
return NULL;
}
//....
}
další případ je kdy to potřebuju dostat do objektu, ale vytvoření objektu je úplně mimo, ja jen té extension řeknu jakou classu má použít.

- Vojtěch Dobeš
- Gold Partner | 1316
Pokud prostě neexistuje jiná cesta, než tahat si to odněkud globálně,
tak lze buď použít Environment, anebo třeba $GLOBALS.

- Vojtěch Dobeš
- Gold Partner | 1316
V tom příkladu vůbec nechápu, proč by ta filtrovací třída nemohla fungovat jako klasický objekt, který nainstancuješ s tím, co je potřeba.

- Tomáš Votruba
- Moderator | 1114
Tzn. že teď už víš?
Stačí přidat extension mezi služby. Pak už bude fungovat autowiring a
můžes si do něj předávat služby.
Editoval Tomáš Votruba (20. 6. 2014 13:35)

- Vojtěch Dobeš
- Gold Partner | 1316
Začíná to nabírat sureálné obrysy. Z jakého důvodu nemůže být
FoldersRouter normálně autowirovanou službou?

- akadlec
- Člen | 1326
Jak jsem psal leda by tam byl parametr ze kterého by to šlo vytáhnout:
class MailboxModuleExtension extends DI\CompilerExtension implements IRouterProvider
{
public function getRoutesDefinition()
{
// Create module routes group
$list = new NetteRouteListMock('Mailbox');
$list[] = new NetteRouteMock('[!<locale [a-z]{2,4}>/]mailbox/<mailbox>', array(
'module' => 'Frontend',
'presenter' => 'Default',
'action' => 'default',
'mailbox' => array(
Route::FILTER_OUT => 'IPub\MailboxModule\Router\FoldersRouter::getFolderSlugById',
Route::FILTER_IN => 'IPub\MailboxModule\Router\FoldersRouter::getFolderIdBySlug'
),
'locale' => array(
Route::VALUE => 'en',
'fixity' => Route::CONSTANT,
)
));
return array($list);
}
}

- David Matějka
- Moderator | 6445
Tyhle providery se hodeji jen pokud prave to, co to vraceji, nema zavislost na sluzbach. Pokud je to na necem zavisle, je lepsi tu routu registrovat jako sluzbu a otagovat

- Tomáš Votruba
- Moderator | 1114
@akadlec Uvedu příklad:
services:
- MailboxModuleExtension # případně přidat v samotném rozšíření v loadConfiguration()
extensions:
- MailboxModuleExtension

- David Matějka
- Moderator | 6445
Koukal jsem na implementaci flame/modules a mohlo by fungovat:
array (
"mailbox" => array(
Route::FILTER_IN => new PhpLiteral('$this->getService("someService")->doFoo()'),
),
)

- Filip Procházka
- Moderator | 4668
Proč je problém použít normálně objekty v tom routeru?
Route::FILTER_IN => [$object, 'getFolderSlugById'],
nebo
Route::FILTER_IN => function () use (...) { ... },

- David Matějka
- Moderator | 6445
@FilipProcházka ty routy se zpracovavaji pri kompilaci kontejneru a dosadeji se do setupu routeru. Takze se nejdriv museji exportovat, coz se sluzbou neudelas. viz https://github.com/…xtension.php#L238
Editoval matej21 (20. 6. 2014 20:34)

- David Matějka
- Moderator | 6445
Jak jsem psal – router provider je dobry se statickyma routama. Pro komplexnejsi routy bych pouzil otagovane sluzby. Neco jako
$builder->addService('myRouteList')
->setFactory(...)
->addTag(Foo::ROUTE);
v beforeCompile pak vytahnout vsechny sluzby s timhle tagem a doplnit je do routeru

- David Matějka
- Moderator | 6445
Nejjednoduseji zhruba:
$router = $builder->getDefinition('router');
foreach(array_keys($builder->findByTag(...)) as $name) {
$router->addSetup('offsetSet(?, ?)', array(NULL, '@' . $name));
}
nebo prependnout podobne jako ve flame modules https://github.com/…xtension.php#L238

- Tomáš Votruba
- Moderator | 1114
@akadlec Pro použití služeb v routeru při zachování modularity čekni tento PR.
Stačí ti službu s routami otagovat a v ní mít metodu createRouter v duchu routeru v sandboxu:
services:
-
class: App\CoreModule\Routing\RouterFactory
tags: [flame.modules.router]
Editoval Tomáš Votruba (23. 8. 2014 20:21)