Kdyby\Doctrine – vlastní typ sloupce a předání parametru/závislosti

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Gappa
Nette Blogger | 208
+
0
-

Ahoj,

mám vytvořený vlastní typ sloupce (custom mapping), který je zaregistrovaný takto:

doctrine:
	types:
		- NejakyNamespace\FileType

V tom FileType je toto (mimo jiné, dědí od klasického StringType):

	public function convertToPHPValue($value, AbstractPlatform $platform)
	{
		return new File($value);
	}

Jde o to, že bych v entitě chtěl mít pro sloupce, kde bude soubor (typicky nějaká příloha, obrázek) rovnou instanci té třídy File, která by měla metody pro snazší práci – např. by šlo vrátit cestu na serveru, URL na webu atp.

Jenže aby to fungovalo, tak potřebuji nějak předat cestu, kde jsou ony soubory uložené – buď jako cestu, nebo nějakou instanci třídy, ze které to půjde získat:

	public function convertToPHPValue($value, AbstractPlatform $platform)
	{
		return new File($value, $storage);
	}

Ve $value je reálný obsah z DB, tedy název souboru.

Jde to nějak řešit? Nebo na to jdu úplně špatně? :)

Editoval Gappa (21. 4. 2017 14:48)

Svaťa Šimara
Člen | 98
+
0
-

Ahoj,

super problém. Původně jsem chtěl odpovědět: Použij konstruktor pro FileType a je to.

Bohužel instanci vlastního typu vytváří Doctrine sama, a konstruktor volá vždy prázdný, takže problém. Do Doctrine lze registrovat pouze název typu, nikoliv instanci samotnou :-/

Řešení naštěstí je – použít statiku, např. singleton…

public function convertToPHPValue($value, AbstractPlatform $platform)
{
    return new File($value, Storage::getInstance());
}

Anebo krkolomější bez statiky, zato se setter injection…

class FileType {

	/**
	 * @var Storage
	 */
	private $storage;

	public function setStorage(Storage $storage) {
		$this->storage = $storage;
	}

	public function convertToPHPValue($value, AbstractPlatform $platform)
	{
	    return new File($value, $this->storage);
	}

}

Registraci do doctrine budeš mít pořád stejnou, a teď ta finta. Po inicializaci DI kontejneru je potřeba vykonat následující kód. Nejrychlej to můžeš vyzkoušet v bootstrap.php

$container = ...

$fileType = \Doctrine\DBAL\Types\Type::getType(FileType::class);
$storage = $container->getByType(Storage::class);
$fileType->setStorage($storage);

Jak se na to dívám, tak i druhá možnost je se statikou, ale toto je vlastnost Doctrine.

Pokud bude kód z bootstrapu, bude velice vhodné pro něj vytvořit extension.

F.Vesely
Člen | 369
+
0
-

Ja bych to resil jinak, naopak. Mel bych Storage, ktera by na zaklade File vratila cestu na serveru, atd. Takhle by sis zachvili mohl rict, ze chces mit v databazi ulozenou url ve tvaru Presenter:action a chtel bys vracet jiz hotovou url, tak tam soupnes Presenter. Osobne si myslim, ze by Service mela pracovat s Entity, Type, atd. a ne naopak.

@SvaťaŠimara V tvem prvnim pripade s Storage::getInstance(), jak by vypadala implementace, kdybych mel v konstruktoru zavislosti na jine sluzby nebo parametry z kofigurace?

Svaťa Šimara
Člen | 98
+
0
-

@F.Vesely Implementace by vypadala hodně blbě. Spousta problémů k řešení právě díky chybějícímu konstruktoru :-) Ne, že by řešit nešly, ale proč se trápit :-D

Gappa
Nette Blogger | 208
+
0
-

@SvaťaŠimara Díky, zatím jsem to udělal „na test“ přes bootstrap řešení, pak uvidím o dál – tam je akorát chybička v getType – nedává se tam ::class, ale jen název typu, tedy file (v mém případě), jinak funkční :)

@F.Vesely Chápu – uvidím, jestli v praxi tohle řešení bude spíše přínosem, nebo budoucím problémem :)