Ako predávať adresáre projektu registrovaným službám

před 3 lety od Rick Strafy  

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

  1. Já to řeším konstantou v konfigu, viz

    constants:
    	WWW_DIR: %wwwDir%
    	APP_DIR: %appDir%
    	VENDOR_DIR: %vendorDir%
    	TEMP_DIR: %tempDir%
    
    	STORNO_DIR: "%wwwDir%/upload/storno/"
    	WWW_STORNO_DIR: "/upload/storno/"
    
    před 3 lety · replied [2] David Grudl
  2. #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.

    před 3 lety
  3. Ř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.

    před 3 lety · replied [4] Spectator
  4. 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áš?

    před 3 lety

Chcete-li odeslat komentář, přihlaste se