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)