Kdyby\Doctrine jak nastavit prefix tabulek v db

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

Ahoj, používám Kdyby\Doctrine a dostal jsem se do situace, kdy potřebuji všem tabulkám v db nastavit prefix a nevím, jak na to.
Podle manuálu jsem si vytvořil třídu:

namespace App\Subscriber;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Kdyby\Events\Subscriber;
use Nette\SmartObject;

class TablePrefixSubscriber implements Subscriber
{
	use SmartObject;
	protected $prefix = '';


	/**
	 * Constructor
	 *
	 * @param string $prefix
	 */
	public function __construct($prefix)
	{
		$this->prefix = (string) $prefix;
	}


	/**
	 * @return array
	 */
	public function getSubscribedEvents()
	{
		return array('loadClassMetadata');
	}


	/**
	 * @param LoadClassMetadataEventArgs $args
	 *
	 * @return void
	 */
	public function loadClassMetadata(LoadClassMetadataEventArgs $args)
	{
		$classMetadata = $args->getClassMetadata();

		// Only add the prefixes to our own entities.
		if (FALSE !== strpos($classMetadata->namespace, 'Some\Namespace\Part'))
		{
			// Do not re-apply the prefix when the table is already prefixed
			if (false === strpos($classMetadata->getTableName(), $this->prefix))
			{
				$tableName = $this->prefix . $classMetadata->getTableName();
				$classMetadata->setPrimaryTable(['name' => $tableName]);
			}

			foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping)
			{
				if ($mapping['type'] == ClassMetadataInfo::MANY_TO_MANY && $mapping['isOwningSide'] == true)
				{
					$mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name'];

					// Do not re-apply the prefix when the association is already prefixed
					if (false !== strpos($mappedTableName, $this->prefix))
					{
						continue;
					}

					$classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName;
				}
			}
		}
	}
}

v config.neon jsem si třídu zaregistroval:

events:
    subscribers:
        - App\Subscriber\TablePrefixSubscriber('prefix_')

Ale docttrine s tím prefixem nepracuje. Přiznám, že s těma eventama z Kdyby moc neumím. Ví někdo, co dělám špatně? Beru i nějaký jiný návrh řešení toho problému s prefixem.

mkoubik
Člen | 728
+
0
-

Smazal jsi cache?

lvq
Člen | 47
+
0
-

Ano, cache (temp/cache) jsem smazal a zkusil jsem to teď pro jistotu ještě jednou a nic se nezměnilo…

CZechBoY
Člen | 3608
+
0
-

Myslim, že ještě je potřeba přidat na tu službu tag. Většina lidí to dělá takhle:

decorator:
	Doctrine\Common\EventSubcriber: # zahrnuje i  Kdyby\Events\Subscriber
		tags: [kdyby.subscriber]
lvq
Člen | 47
+
0
-

Tak to taky nepomáhá. Zkoušel jsem všelijaké kombinace, co jsem našel tady na fóru.
(Našel jsem taky, že by se eventy měly prý snad volat jen na registrovaných službách, ale nevím, co by to znamenalo v tomto případě…)

looky
Člen | 99
+
0
-

Zkus se subscribovat na Doctrine\\ORM\\Event::loadClassMetadata.

(případně je na to konstanta loadClassMetadata v třídě Kdyby\Doctrine\Events)

Editoval looky (3. 10. 2016 11:41)

lvq
Člen | 47
+
0
-

@looky: Zdá se, že to nemá žádný vliv…

looky
Člen | 99
+
0
-

@lvq Cache jsi předpokládám smazal. Spustí se vůbec ta listener metoda?

Editoval looky (3. 10. 2016 13:00)

Jiří Nápravník
Člen | 710
+
0
-

Já používám tohle a funguje bez problémů

services:
	-
		class: JiriNapravnik\Doctrine\EventSubscriber\TablePrefixSubscriber(%database.tablePrefix%)
		tags: [kdyby.subscriber]
lvq
Člen | 47
+
0
-

Vypadá to, že je to na dobré cestě. Objevil jsem vaše odpovědi až teď a musím pryč od PC. Večer nebo během zítřka dám vědět, jak to vypadá…

lvq
Člen | 47
+
0
-

Tak už to jede :-)
Ta metoda loadClassMetadata se právě nespouštěla, teď se spouští. Pořádně si to nedovedu vysvětlit (cache jsem mazal poctivě si myslím). Pak jsem v ní řádek

if (FALSE !== strpos($classMetadata->namespace, 'Some\Namespace\Part'))

přespal za svůj namespace a už se to chytá.
V neonu funguje toto:

events:
	subscribers:
		- App\Subscriber\TablePrefixSubscriber()

i toto:

	-
		class: App\Subscriber\TablePrefixSubscriber()
		tags: [kdyby.subscriber]

Díky všem přispívajícím.

looky
Člen | 99
+
0
-

Ještě dodám, že ten foreach bys neměl mít uvnitř toho ifu, který kontroluje jestli jde o tvůj namespace. Protože pak se prefixnou všechny ManyToMany relace z tvých entit na cizí a zároveň se neprefixnou relace z cizích entit na tvoje. Ten foreach by měl být mimo, a uvnitř něj bys měl znovu kontrolovat $mapping['targetEntity'].

Zároveň myslím, že kontrola, jestli už ta tabulka není prefixlá je zbytečná, protože tahle celá mašinérie se volá pouze jednou pro každou entitu.

EDIT: ukázka mojí implementace

Editoval looky (4. 10. 2016 15:10)