Ako predávať adresáre projektu registrovaným službám
V tomto veľmi krátkom článku si ukážeme 2 jednoduché spôsoby ako predávať cesty k adresárom projektu ostatným službám, je to vcelku jednoduchá vec ktorú väčšina z vás pozná, no opakovanie je matka múdrosti.
Povedzme, že v našej aplikácii máme CronTaskExecutor
na
vykonávanie cronových úloh z databázy cez shell_exec
funkciu,
ktorá potrebuje cestu k našej aplikácii, táto služba požaduje
$logger
službu poskytnutú z DI containera a $appDir
string, ktorý musíme predať z nášho konfiguračného súboru.
class CronTaskExecutor
{
public function __construct(
private Logger $logger,
private string $appDir,
) {}
}
services:
- CronTaskExecutor(appDir: %appDir%)
Dnes už nie je potrebné pridávať služby do neon konfigurácie ručne,
pretože máme built-in
search extension na automatickú registráciu našich tried na základe
prípon, ako sú napríklad Facade, Repository, Factory, Executor, Manager,
Sender, Helper atď. Jediný dôvod prečo sme museli upravovať konfiguračný
súbor bol ten, že sme potrebovali odovzdať konštantu
%appDir%
.
Predstavte si, že máte dosť veľký projekt a často musíte používať
cesty k adresárom ako %tempDir%
%appDir%
alebo
%vendorDir%
a možno aj vlastné cesty k adresárom pre zálohy,
médiá a podobne. Zakaždým keď potrebujete nejakú cestu k adresáru by ste
museli do neon konfigurácie pridávať službu.
Jednoduchým riešením je vytvoriť službu, ktorá bude poskytovať všetky
dôležité adresáre projektu pre ostatné služby, a zaregistrovať ju len
raz. Keď služba bude potrebovať nejakú cestu k adresáru, jednoducho v nej
požiadame našu službu DirectoryProvider
. Tu je ukážka služby
s pridanou $backupDir
:
(PHP 8.1 readonly properties sú použité len preto, aby sme sa v tomto článku vyhli dlhým triedam s private properties a public gettermi)
declare(strict_types=1);
namespace App\Model;
class DirectoryProvider
{
public readonly string $backupDir;
public function __construct(
public readonly string $appDir,
public readonly string $tempDir,
public readonly string $vendorDir,
) {
$this->backupDir = $this->appDir . '/../backups';
}
}
a teraz musíme túto službu zaregistrovať v konfiguračnom súbore:
services:
- App\Model\DirectoryProvider(
appDir: %appDir%,
tempDir: %tempDir%,
vendorDir: %vendorDir%,
)
Takže s touto službou už nebudeme musieť pridávať služby, ktoré
pracujú s adresármi aplikácií do nášho konfiguračného súboru, pretože
teraz môžeme namiesto toho vyžiadať DirectoryProvider
a
použiť $this->directoryProvider->appDir
.
class CronTaskExecutor
{
public function __construct(
private Logger $logger,
private DirectoryProvider $directoryProvider,
) {}
public function execute(CronTask $task): void
{
$appDir = $this->directoryProvider->appDir;
}
}
Gettery vs public readonly
Jediným dôvodom prečo som v príklade použil novú syntax z PHP 8.1
(čoskoro výjde), je len zjednodušenie triedy a ušetrenie miesta v článku,
stále uprednostňujem syntax s gettermi, pretože metóde môžete odovzdať
ďalšie parametre, napríklad getMediaDir(MediaType::Images)
, a
keď sa tak rozhodnete a budete už používať public readonly properties,
prinesie to trochu nekonzistentnosti.
Komentáře
Já to řeším konstantou v konfigu, viz
#1 Michal Kumžák používání konstant je samozřejmě možná cesta, nicméně vytvářejí skryté závislosti a jdou tedy proti smyslu dependency injection. Vhodnější je proto explicitní předání cest, ať už parametrem, nebo jako objekt.
Řeším to obdobně, jen pro každý adresář mám vlastní službu. Konkrétně abstract Directory a potomky TempDir, WwwDir,… Občas má potomek specifické metody. Lépe se mi pak refaktoruje a hledají zavislosti.
To jsem rád, že to mám to stejně 🙂
#3 Milo Tohle zní taky docela zajímavě. Kdy je potřeba TempDir a ještě třeba DataDir, tak předáváš každou zvlášť nebo nad tím máš ještě něco, co zná všechny app Directory a to teprve předáváš?
Chcete-li odeslat komentář, přihlaste se