Nette + Doctrine2 + Gedmo

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

Zkoušel někdo z vás už připojit Gedmo extension k Doctrine2? Potřebuju nějak vyřešit načtení kategorií do stromu a co se mě podařilo vygooglit tak pomocí gedmo by to mělo jít.

Doctrine normálně inituju pomocí neonu takto:

services:
    doctrineConfig:
        class: Doctrine\ORM\Configuration
        setup:
            - setProxyDir(%doctrine.proxyDir%)
            - setProxyNamespace(%doctrine.proxyNamespace%)
            - setAutoGenerateProxyClasses(%doctrine.autoGenerateProxyClasses%)
            - setMetadataCacheImpl
            - setQueryCacheImpl
            - setMetadataDriverImpl

    _doctrineDummyConfig:
        class: Doctrine\ORM\Configuration
        autowired: no

    doctrineChainDriver:
        class: Doctrine\ORM\Mapping\Driver\DriverChain
        setup:
            - addDriver(@_doctrineDummyConfig::newDefaultAnnotationDriver(%doctrine.entityDir%), 'Entities')

    doctrineEventManager:
        class: Doctrine\Common\EventManager
        setup:
            - addEventSubscriber(Doctrine\DBAL\Event\Listeners\MysqlSessionInit('utf8', 'utf8_czech_ci'))

    doctrineCache:
        class: Doctrine\Common\Cache\ArrayCache

    entityManager:
        class: Doctrine\ORM\EntityManager
        create: Doctrine\ORM\EntityManager::create(%doctrine.connection%)

Vše funguje, ale když přidám rozšíření o Gedmo tak je konec. Do doctrineEventManager přidám

- addEventSubscriber(\Gedmo\Timestampable\TimestampableListener())

a laděnka začne řvát že mám špatně anotace. Takže v entitě kde to řve upravím anotace z @id na @ORM\id, @column na @ORM\Column atd. Ale pak mi začne řvát že ta entita není validní classa. Je potřeba ještě někde něco jiného nastavit?

Doctrine2 mám v2.3.2 a Gedmo čerstvě z gitu v2.3.5

akadlec
Člen | 1326
+
0
-

Ještě teda doplním tu hlášku na které končím

Class System is not a valid entity or mapped super class

System je první entita se kterou se pracuje při zpracovávání, je extendována globální entitou která má definované společné vlastnosti. Pokud tuto extenzi odstraním tak stále stejný problém :(

Michal Vyšinský
Člen | 608
+
0
-

Myslím, že je chyba jen v entitě, nechceš ji ukázat? A hodila by se i ona globální entita.

EDIT: První věc co mě napadla: Změnil jsi i anotaci @Entity na @ORM\Entity?

Editoval CherryBoss (15. 3. 2013 10:07)

akadlec
Člen | 1326
+
0
-

jj anotace jsem změni, pokud je necham bez ORM\ tak to řve že je chyba v anotaci, pokud tam všude nahážu to ORM\ tak to právě skončí na té hlášce nevalidní entity.

No entita ma cca takovýto tvar (momentálně nemám kod u sebe)

/**
* @Entity(repositoryClass="SystemRepository")
*/
class System
{
	/**
	 * @GeneratedValue
	 */
	protected $id;

	/**
	 * @Column(type="string", length=100, unique=true)
	 */
	protected $name;

	/**
	 * @Column(type="string", length=250)
	 */
	protected $description;

	....
}

ono pokud to do toho setupu nepřidám tak to jede bez problému, jakmile tam to GEDMO přidám začne to blbnout :(

Editoval akadlec (15. 3. 2013 10:13)

David Matějka
Moderator | 6445
+
0
-

mas definovanej use?
use Doctrine\ORM\Mapping as ORM

akadlec
Člen | 1326
+
0
-

Ano, to co sem tu postnul výše je ukázka ještě před změnou na GEDMO

David Matějka
Moderator | 6445
+
0
-

takhle nějak používám gedmo:

<?php
namespace Foo\Bar;

use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;

/**
 * @Gedmo\Tree(type="nested")
 * @ORM\Table(name="directory_entry")
 * @ORM\Entity(repositoryClass="EntryRepository")
 */
class EntryEntity
{

	/**
	 * @ORM\Id
	 * @ORM\GeneratedValue
	 * @ORM\Column(type="integer")
	 * @var int
	 */
	private $id;

	/**
	 * @ORM\Column(name="name", type="string", length=64)
	 */
	private $name;

	/**
	 * @Gedmo\TreeLeft
	 * @ORM\Column(name="lft", type="integer")
	 */
	private $lft;

	/**
	 * @Gedmo\TreeLevel
	 * @ORM\Column(name="lvl", type="integer")
	 */
	private $lvl;

	/**
	 * @Gedmo\TreeRight
	 * @ORM\Column(name="rgt", type="integer")
	 */
	private $rgt;


	/**
	 * @Gedmo\TreeParent
	 * @ORM\ManyToOne(targetEntity="EntryEntity", inversedBy="children")
	 * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
	 */
	private $parent;

	/**
	 * @ORM\OneToMany(targetEntity="EntryEntity", mappedBy="parent")
	 * @ORM\OrderBy({"lft" = "ASC"})
	 */
	private $children;


	/**
	 * @Gedmo\TreeRoot
	 * @ORM\Column(name="root_id")

	 */
	private $root;
....
}
akadlec
Člen | 1326
+
0
-

Tak tuto entitu jsem si našel v docu u GEDMO, to je ok, ja bych spíš řek že problém bude v tom initu. Doctrine startuju jen pomocí toho neonu, tak nevím jestli mě tam ještě neco nechybi.

David Matějka
Moderator | 6445
+
0
-

koukni na https://github.com/…xtension.php a koukni jestli ti tam neco nechybi, pripadne si rovnou nainstaluj z https://github.com/nella doctrine a gedmo extensions a mas po problemech :)
(pokud jedes na dev verzi nette, tak mrkni na moje https://github.com/…/nette-gedmo a https://github.com/…tte-doctrine jsou to jen forky s kompatibilitou na dev verzi

akadlec
Člen | 1326
+
0
-

Takže beru zpět, neshazuje to gedmo ale orm mapping

Vyhozená exception:

Doctrine\ORM\Mapping\MappingException

Class "IPub\CMS\Models\System\Systems\System" sub class of "IPub\Doctrine\Entity" is not a valid entity or mapped super class.

Entita:

namespace IPub\CMS\Models\System\Systems;

use \Doctrine\ORM\Mapping as ORM,
    \Doctrine\Common\Collections\ArrayCollection;

/**
 * @ORM\Entity(repositoryClass="SystemRepository")
 * @ORM\Table(name="system_systems")
 */
class System extends \IPub\Doctrine\Entity
{
	/**
	 * @ORM\Id
	 * @ORM\Column(type="integer", name="system_id")
	 * @ORM\GeneratedValue
	 */
	protected $id;

	/**
	 * @OneToMany(targetEntity="\IPub\CMS\Models\System\Systems\System", mappedBy="parent")
	 **/
	private $children;

	/**
	 * @ManyToOne(targetEntity="\IPub\CMS\Models\System\Systems\System", inversedBy="children")
	 * @JoinColumn(name="parent_id", referencedColumnName="system_id")
	 **/
	private $parent;

	/**
	 * @ManyToOne(targetEntity="\IPub\CMS\Models\Users\Users\User")
	 * @JoinColumn(name="user_id", referencedColumnName="user_id")
	 */
	protected $owner;

	/**
	 * @OneToOne(targetEntity="\IPub\CMS\Models\System\Resellers\Reseller", inversedBy="system")
	 * @JoinColumn(name="reseller_id", referencedColumnName="reseller_id")
	 **/
	protected $reseller;

	/** @ORM\Column(type="integer", name="package_id", nullable=false) */
	protected $package;

	/** @ORM\Column(type="string", name="system_name", nullable=false) */
	protected $name;

	....
}

Abstraktní entita:

namespace IPub\Doctrine;

use \Doctrine\ORM\Mapping as ORM;

/**
 * Basic entity with ID
 *
 * @ORM\MappedSuperclass
 *
 * @property-read int $id
 */
abstract class Entity extends \Nette\Object
{
	public function setId($id)
	{
		$this->id = $id;

		return $this;
	}

	/**
	 * @return int
	 */
	public function getId()
	{
		return $this->id;
	}

	/**
	 * @return array
	 */
	public function toArray()
	{
		return get_object_vars($this);
	}

	/**
	 * @return string
	 */
	public function __toString()
	{
		if ( isset($this->name) && $this->name !== null )
			return $this->name;
		else
			return (string) $this->id;
	}

	public function __construct()
	{

	}
}

Nastavení a init doctrine2 v neonu:

common:
	parameters:
		doctrine:
			prefix:		 smart_
			entityDir:      %appDir%/models
			proxyDir:       %tempDir%/temp/proxies
			proxyNamespace: Entities\Proxies
			autoGenerateProxyClasses: true
			connection:
				driver:   pdo_mysql
				user:     root
				password: root
				dbname:   nette_smartstart
				host:     localhost
	services:
		# DATABASE SERVICES
		sqlLogger: IPub\Doctrine\Diagnostics\ConnectionPanel::register
		mappingStrategy: \Doctrine\ORM\Mapping\UnderscoreNamingStrategy

		tablePrefix:
			class: IPub\Doctrine\TablePrefix
			arguments: [%doctrine.prefix%]

		doctrineConfig:
			class: Doctrine\ORM\Configuration
			create: Doctrine\ORM\Tools\Setup::createAnnotationMetadataConfiguration(%entityDirs%, true)
			setup:
				- setNamingStrategy(@mappingStrategy)
				- setSQLLogger(@sqlLogger)
				- setProxyDir(%doctrine.proxyDir%)

		doctrineDummyConfig:
			class: Doctrine\ORM\Configuration
			autowired: no

		doctrineChainDriver:
			class: Doctrine\ORM\Mapping\Driver\DriverChain
			setup:
				- addDriver(@doctrineDummyConfig::newDefaultAnnotationDriver(%doctrine.entityDir%), 'Entities')

		doctrineEventManager:
			class: Doctrine\Common\EventManager
			setup:
				- addEventListener('loadClassMetadata', @tablePrefix)
				- addEventSubscriber(Doctrine\DBAL\Event\Listeners\MysqlSessionInit('utf8', 'utf8_general_ci'))

		doctrineCache:
			class: Doctrine\Common\Cache\ArrayCache

		entityManager:
			class: Doctrine\ORM\EntityManager
			create: Doctrine\ORM\EntityManager::create(%doctrine.connection%)
akadlec
Člen | 1326
+
0
-

Takže problém se mě podařilo na 99% odhalit, jen zatím nevím jak jej vyřešit. Problém je v tom že se používá simpleAnotationReader, když jej natvrdo vypnu tak to projde dále. Ten simple anotationreader pak špatně skládá názvy tříd.

jak tedy aktivovat tu extension co je v nellaframeworku?

class Extension extends \Nette\Config\CompilerExtension {}

a následně gedmo

class GedmoExtension extends \Nette\Config\CompilerExtension {}

edit:
předpokládám tedy nějak takto v bootstrapu:

$configurator->onCompile[] = function ($configurator, $compiler) {
    $compiler->addExtension('doctrine', new Nella\Doctrine\Config\Extension);
};

Editoval akadlec (15. 3. 2013 21:59)

akadlec
Člen | 1326
+
0
-

Tak zase update ;)
Tu extension jsem vyhodil protože se mi ji nepodařilo spojit s configem, a padala na tom že chybí driver a vrátil jsem se k definici přes neon a tam stačilo upravit jeden řádek služby:

doctrineChainDriver:
	class: Doctrine\ORM\Mapping\Driver\DriverChain
	setup:
		- addDriver(@doctrineDummyConfig::newDefaultAnnotationDriver(%doctrine.entityDir%, false), 'IPub\CMS\Models')

do metody newDefaultAnnotationDriver jsem přidal za entity dirs false čímže se deaktivuje simpleAnotationDriver.

Doufám že toto vyřešení problému je korektní.

Editoval akadlec (16. 3. 2013 15:10)

akadlec
Člen | 1326
+
0
-

Super, zatím mi tedy vše funguje jen jsem narazil na další problém ;) Snažím se použít extension Blameable. V anotaci je vše ok, při krokování jsem zjistil že tenhle listener funguje ok, ale problém je ten že v tom listeneru není přiřazen user který by se uložil do DB.

Potřeboval bych nějak zavolat něco takového:

$listener->setUserValue($user);

otaázkou tedy je jak se dostat k tomu konkrétnímu listeneru? Je definovaný v service doctrineEventManager pomocí addEventSubscriber

		doctrineEventManager:
			class: Doctrine\Common\EventManager
			setup:
				- addEventListener('loadClassMetadata', @tablePrefix)
				- addEventSubscriber(Doctrine\DBAL\Event\Listeners\MysqlSessionInit('utf8', 'utf8_general_ci'))
				- addEventSubscriber(Gedmo\Timestampable\TimestampableListener())
				- addEventSubscriber(Gedmo\Blameable\BlameableListener())
				- addEventSubscriber(Gedmo\Loggable\LoggableListener())
				- addEventSubscriber(Gedmo\Sluggable\SluggableListener())
				- addEventSubscriber(Gedmo\Tree\TreeListener())
stefi023
Člen | 71
+
0
-

Necetl jsem cely thread, doctrine2 + gedmo vesele pouzivam (ala Nella), ale tvuj problem bych asi resil vyclenenim listeneru jako sluzby:

blameableListener:
	class: Gedmo\Blameable\BlameableListener
	setup:
		- setUser(@user) //nebo kde mas toho uzivatele
doctrineEventManager:
	class: Doctrine\Common\EventManager
	setup:
		- addEventListener('loadClassMetadata', @tablePrefix)
		- addEventSubscriber(Doctrine\DBAL\Event\Listeners\MysqlSessionInit('utf8', 'utf8_general_ci'))
		- addEventSubscriber(Gedmo\Timestampable\TimestampableListener())
		- addEventSubscriber(Gedmo\Loggable\LoggableListener())
		- addEventSubscriber(Gedmo\Sluggable\SluggableListener())
		- addEventSubscriber(Gedmo\Tree\TreeListener())
		- addEventSubscriber(@blameableListener)

ale doporucuji jeste jednou zvazit tu extension z Nella FW, je to tam hezky vyresene a napr Event listenery se pridavaji jen otagovanim sluzby, etc…

akadlec
Člen | 1326
+
0
-

No tu bych i rád použil bohužel se mi jí nedaří zprovoznit :( a sandbox nebo nějaké příklady jsem nenašel :(

No chvíli zkoušení a laborování a podařilo se mi nella extenze rozjet. Hodím to sem kdyby náhodou někdo stejně tápal jako já.

Extensions sem zaregistroval v bootstrapu

$configurator->onCompile[] = function ($configurator, $compiler) {
    $compiler->addExtension('doctrine', new Nella\Doctrine\Config\Extension);
    $compiler->addExtension('gedmo', new Nella\Doctrine\Config\GedmoExtension);
};
$container = $configurator->createContainer();

A v neonu jsem upravil konfigurace. Původně byly v sekci parameters, nyní je to pro každou extension zválšť

common:
	doctrine:
		entityDirs:	['%libsDir%/IPub/CMS/Models']
		proxy:
			dir			: %tempDir%/proxies
			namespace		: 'App\Model\Proxies'
			autogenerate	: true
		connection:
			prefix:		smart_
			driver:		pdo_mysql
			user:		root
			password:		root
			dbname:		nette_smartstart
			host:		localhost
			charset:		utf8
			collation:	utf8_general_ci

	gedmo:
		orm:
			em			: @doctrine.entityManager
			loggable		: true
			sluggable		: true
			softDeleteable	: true
			sortable		: true
			timestampable	: true
			translatable	: true
			tree			: true
			uploadable	: true

Snad jsem to realizoval správně. Gedmo extenze již funguji tak jak mají, ještě tedy musím dodělat tu Blameable která v nella není.

Editoval akadlec (16. 3. 2013 18:01)

akadlec
Člen | 1326
+
0
-

Takže znova jsem se pokusil o dokončení implementace Blameable od gedma za pomocí nella extension z gitu: https://github.com/…xtension.php s tím že jsem tam dodělal to blameable. Listener je regnuty bez problému. Jediné na co jsem narazil je to jak předat tomu listeneru Entitu přihlášeného uživatele.

Do té extension sem mimo jiné přidal tento registrator:

	public static function registerBlameable(ObjectManager $om, EventSubscriber $listener)
	{
		$listener->setUserValue(\Nette\Environment::getUser()->getId());

		if ($om instanceof \Doctrine\ORM\EntityManager || $om instanceof \Doctrine\ODM\MongoDB\DocumentManager) {
			$om->getEventManager()->addEventSubscriber($listener);
		}
	}

a právě ta metoda $listener->setUserValue() provede uložení uživatele do listeneru který se pak použije při update v databázi. Když tam před environment předám ID tak je to málo, protože když se to ukládá tak je pořeba vazba na entitu uživatele. Když si tam předám službu fasády na uživatele tak to neprojde jelikož ta zas má vazbu na doctrine takže na tomhle to umře. Nenapadá někoho jak tam tu entitu uživatele dostat?

stefi023
Člen | 71
+
0
-

Tenhle zacarovany kruh jsem take resil (psal jsem si sve vlastni Blameable rozsireni) ale potreboval jsem to vyresit asap takze nakonec jsem to udelal tak, ze jsem mel vlastni tridu User (uz jsem ji stejne mel z jinych duvodu), ktera mela metodu getUserEntity(EntityManager $em), takze v tom listeneru jsem ji toho entity managera predal (ten je v tech EventArgs $args)… rozhodne na to nejsem pysny, ale fungovalo to… to ale asi neni tvuj pripad, pac bys ten BlameableListener musel trochu prepsat…

Ale napada me, k cemu je vlastne CompilerExtension::afterCompile(Nette\Utils\PhpGenerator\ClassType $class), nedala by se zneuzit k donastaveni sluzby po jejich vytvoreni? fakt netusim…

akadlec
Člen | 1326
+
0
-

No ja už přemýšlel nad tím že bych udělal vlastní \Security\User co by podědil \Nette\Security\User ale měl by k dispozici navíc fasádu pro usera, takže bych si do toho listeneru mohl předat toho usera jak mám teď tj. $listener->setUserValue(\Nette\Environment::getUser()); a pak upravit samotný listener kde se zpracovává user a udělat tam vytažení entity. Bylo by to sice takové přiohnutí a hrabání do samotného Gedmo rozšíření ale zatím mě jiná cesta nenapadla.

Nad tou metodou afterCompile jsem taky přemýšlel ale nedopátral jsem se zatím nikde jak to tam rozumně vyřešit.

stefi023
Člen | 71
+
0
-

Problem je v tom ze to „circular reference detected“ bys tam mel porad:

LISTENER needs USER needs FACADE needs ENTITY_MANAGER needs LISTENER :)

jestli jsem ti teda porozumel… presne tak jsem to chtel take udelat, ale pak mi nezbylo nic jineho, nez tomu USEROVI rict o ENTITY_MANAGER az kdyz se jsem se ho na tu entitu ptal

akadlec
Člen | 1326
+
0
-

No ten error circular reference detected jsem tam měl teď když jsem se pokusil předat přímo fasádu usera protože se udělal ten kruh že. Právě to co jsem popsal výše by fungovalo tak že by se předal jen ten user co by měl v sobě injectovanou fasádu a ta by se použila až při volání dané operace. Zatím jsem to nezkusil takže nevím zda se mi tam taky udělá ten kruh.

stefi023
Člen | 71
+
0
-

Ale ten user by tu fasadu mel injektovanou uz v dobe vytvoreni (standardni cestou), takze si stejne myslim ze by se to zakruhovalo… leda ze bys ji tam nejak nainjektoval az pozdeji

Kazdopadne az to vyresis tak se rad necham inspirovat :)

akadlec
Člen | 1326
+
0
-

Jejda, nevím nevím zda to sám vyřeším ;) ale pokud jo tak to tady postnu

Filip Procházka
Moderator | 4668
+
0
-

Kdybys použil kdyby/events tak se ti container zkompiluje tak, že ti tuhle circural reference přeruší (platí pouze na listenery) ;)

Jenom jsem nezkoušel, jestli je kdyby/events kompatibilní s Nellou (myslím že není) :)

akadlec
Člen | 1326
+
0
-

pls můžeš se rozespat trošku více?

Filip Procházka
Moderator | 4668
+
0
-

Předpokládám, že článek si četl, takže rozvedu pouze to s tím fixováním circural reference.

Protože listenery mívají různé závislosti a né vždy se pustí všechny, tak je kdyby/events optimalizují takovým způsobem, že všechny je zanalyzuje, vytvoří mapu ve které je popsané jaký listener pouslouchá jakou událost a pak zruší jejich přímé provázání s EventManagerem (zahodí všechny metody setup které přidávají listenery). Tahle mapa společně s DI Containerem se předá do EventManageru a on si pak vytahuje listenery podle jména služby až když jsou volány.

Příklad jak to vypadá fyzicky, když se to zkompiluje, můžeš vidět v testech.

akadlec
Člen | 1326
+
0
-

No čet, ale jako newbie v nette se poměrně solidně ztrácím :(

akadlec
Člen | 1326
+
0
-

@Filip Procházka
Tak sem si na to zkusil sednout a pochopit. A pokud jsem pochopil správně tak:

1. V bootsrapu si zaregistruji EventsExtension

$configurator->onCompile[] = function ($configurator, $compiler) {
    $compiler->addExtension('events', new Kdyby\Events\DI\EventsExtension);
    .....
};

2. Vytvořím si svůj listener kde zadefinuji jednolivé eventy onNěco
3. Tento listener zaregistruji v configu, např. ten tvuj newRelic:

services:
	# LISTENERS
	newRelicListener:
		class: Addons\Events\Listeners\NewRelic\NewRelicProfilingListener
		tags: [kdyby.subscriber]

a mám z půle vyhráno? Abych to pak mohl aplikovat na to GEDMO tak musím vzít ty listenery gedma a upravit je aby je volala ta tva extension?

Editoval akadlec (11. 4. 2013 20:15)

Filip Procházka
Moderator | 4668
+
0
-

Listenery gedma zaregistruješ do DIC s libovolným jménem a nastavíš jim tags: [kdyby.subscriber]

akadlec
Člen | 1326
+
0
-

Sry za možná hloupý dotaz, ale jenom takto?

services:
    # LISTENERS
    gedmoBlameableListener:
        class: Gedmo\Blameable\BlameableListener
        tags: [kdyby.subscriber]
Filip Procházka
Moderator | 4668
+
0
-

Mělo by to stačit. Zkoušel jsi to? :) Já Gedmo nepoužívám, ale fungovat by to mělo.

akadlec
Člen | 1326
+
0
-

Takže zkusil jsem to a nefachči :(

services:
    # LISTENERS
    timestampableListener:
	class: Gedmo\Timestampable\TimestampableListener
	tags: [kdyby.subscriber]

upravil sem i ten listener:

class TimestampableListener extends MappedEventSubscriber implements Kdyby\Events\Subscriber
{
	....
}

Je to tento listener: https://github.com/…Listener.php

Doplnění:
když to Gedmo rozšíření Timestampable vyhodím z inicializace dle Nella a udělám to pomocí Kdyby tak to přestane zavěšovat ty události, v tom listeneru je událost onFlush která se nespustí a když se dívam do zaregistrovaných listenerů tak tam není. Zkoušel jsem i upravit listener takto:

namespace Gedmo\Timestampable;

use Kdyby;

use Doctrine\Common\EventArgs,
    Gedmo\Mapping\MappedEventSubscriber,
    Doctrine\Common\NotifyPropertyChanged,
    Gedmo\Exception\UnexpectedValueException;

class TimestampableListener extends MappedEventSubscriber implements Kdyby\Events\Subscriber
{
    /**
     * Specifies the list of events to listen
     *
     * @return array
     */
    public function getSubscribedEvents()
    {
        return array(
            '\\Doctrine\\ORM\\Events::prePersist',
            '\\Doctrine\\ORM\\Events::onFlush',
            '\\Doctrine\\ORM\\Events::loadClassMetadata'
        );
    }

Editoval akadlec (12. 4. 2013 21:35)

akadlec
Člen | 1326
+
0
-

Filip Procházka
nemáš tedy nějaký tip co dělám špatně?

Filip Procházka
Moderator | 4668
+
0
-

@solution to upravoval, aby mu to jelo s Kdyby/Doctrine, koukni: https://gist.github.com/…tion/5389050

Solution
Člen | 50
+
0
-

Já jsem upravoval pouze NS, jelikož ten, co používalo gedmo v hintu u metody pro registraci extensiony, tak byla deprecated: https://github.com/…verChain.php#L27
Ale jinak jsem v podstatě nic z funkčního kódu upravovat nemusel :-).

akadlec
Člen | 1326
+
0
-

Takže pokud se dívám mělo by stači vyřešit to registrování listenerů co použil @Solution v classe GedmoExtension

@Solution
takže se ti povedlo rozchodit to blameable? Aby to přidávalo samo usera co upravuje/pracuje s entitou?

akadlec
Člen | 1326
+
0
-

@Filip Procházka Tak jsem se opět dostal k tomu rozchodit GEDMO podle výše uvedených postupů, měl jsem za to že se mě to podařilo již vyřešit, ale jak se zdá tak ne. Eventy se zaregistrují, projdou i optimalizaci listenerů ale při ukládaní entity se prostě metody onFlush či prePersist apod které mají listenery GEDMa nespustí. Nemohl bys pls nakopnout správným směrem?

stefi023
Člen | 71
+
0
-

Tak vcera jsem zrovna integroval blameable via Nella\Doctrine a Kdyby\Events a zjistil jsem par postrehu, ktere by ti mohly pomoci. Do Nella\Doctrine muzes predat tvuj EventManager (https://github.com/…xtension.php#L46). Ten logicky musi byt pro celou aplikaci (nebo alepson souvisejici cast) pouze jeden, v pripade Kdyby\Events je to
@events.manager:

doctrine:
	eventManager: @events.manager

pak se ti zacnou ty eventy spoustet spravne…

Nicmene ale i po teto integraci jsem stale zasekly na Circular reference detected... Tentokrat ale tak, ze blameableListener je zavisly sam na sobe (?!). Po hlubsim zkoumani fce DI\Container::getService($name) jsem zjistil, ze je to asi tim, ze v pripade blameable se ten blameableListener vola dvakrat (createdBy a updatedBy) a snazi se nejak nakonfigurovat… pri odstraneni jedne z techto akci to jiz funguje…

Debugovanim jsem dosel k tomu, ze pri inicializaci listeneru v LazyEventManageru (https://github.com/…tManager.php#L94) se zavola v urcite zavislosti DI\Container::getService($name) vicekrat (v pripade blameable 2×), a pokazde se snazi inicializovat, na podruhe asi uz v zavislosti na tom prvnim… Uplne presne nevim, co se tam deje, uz byla pozdni nocni hodina, ja chtel jit spat a tak jsem provedl pouze to, ze jsem si v tom EventManageru udelal registr nainicializovanych sluzeb a spoustel to jen pro ty nove:

	/** @var array already inicialized listeners */
	private $inicialized = array();

	/**
	 * @param string $eventName
	 */
	private function initializeListener($eventName)
	{
		foreach ($this->listenerIds[$eventName] as $serviceName) {
			if(!array_key_exists($serviceName,$this->initialized))	{
				$this->initialized[$serviceName] = true;
				$subscriber = $this->container->getService($serviceName);
				/** @var Doctrine\Common\EventSubscriber $subscriber */

				$this->addEventSubscriber($subscriber);
			}

		}

		unset($this->listenerIds[$eventName]);
	}

Ted nedokazu rict, zda jsem delal nekde neco spatne pri definici/registraci listeneru, ale zdalo se mi to vse OK… tak nevim :( Nenapada vas nekoho neco?

Diky

akadlec
Člen | 1326
+
0
-

@stefi023: Takže jestli sem tě dobře pochopil tak doctrině předat ten vlastní event manager což se snažím používat ten layz od Filipa Procházky

$configurator->onCompile[] = function ($configurator, $compiler) {
	$compiler->addExtension('events', new Kdyby\Events\DI\EventsExtension);
};

a pak v neonu:

doctrine:
    eventManager: @events.manager

je tak?

stefi023
Člen | 71
+
0
-

@akadlec: presne tak… to by melo stacit a ty doctrine eventy se razem zacnou spoustet… ovsem jak rikam u me stale v pripade blameable vladla cirkularkova reference :)

akadlec
Člen | 1326
+
0
-

super tak už mi to opět funguje. Tys to blameable ještě nějak upravoval? resp jak mu předáváš referenci na usera?

stefi023
Člen | 71
+
0
-

jen jsem to tak zkousel, tzn nejdriv jsem zkousel vytvorit service: userEntity, ktera dostane Nette\Security\User a UserRepository a ma fci getEntity a vysledek teto fce jsem predal do blameableListeneru.

Z patra (nemam to ted u sebe, jde o princip)

services:
	userRepository: @doctrine::getRepository('User')
	userEntity:
		class: UserEntity
		setup:
			- setUser(@user)
			- setUserRepository(@userRepository)
	blameableListener:
		class: Gedmo\BlameableListener
		setup:
			- setUserValue(@userEntity::getEntity())
		tags: ['kdyby.subscriber']

pak jsem zkousel to predavat i ruzne jinak, ale porad jsem tam mel circular… Ovsem z ladenky bylo videt, ze se vytvareni teto sluzby inicializuje opravdu az on-demand (tzn vsechny zavislosti uz mely existovat)

akadlec
Člen | 1326
+
0
-

Hmmm zkusím si s tím ještě pohrát.

Jinak já dneska opět zapínal TREE a narazil jsem na problém v initu repository pro TREE.

    public function __construct(EntityManager $em, ClassMetadata $class)
    {
        parent::__construct($em, $class);
        $treeListener = null;
        foreach ($em->getEventManager()->getListeners() as $listeners) {
            foreach ($listeners as $listener) {
                if ($listener instanceof \Gedmo\Tree\TreeListener) {
                    $treeListener = $listener;
                    break;
                }
            }
            if ($treeListener) {
                break;
            }
        }
}

V tomto konstruktoru to počítá s tím že tam je pole listenerů, jenže kdyby když se použije kdyby events tak je to mix objektů a polí, takže jsem ten kontruktor upravil:

    public function __construct(EntityManager $em, ClassMetadata $class)
    {
        parent::__construct($em, $class);
        $treeListener = null;
        foreach ($em->getEventManager()->getListeners() as $listeners) {
	        if ( is_array($listeners) ) {
	            foreach ($listeners as $listener) {
	                if ($listener instanceof \Gedmo\Tree\TreeListener) {
	                    $treeListener = $listener;
	                    break;
	                }
	            }

	        } else if ($listeners instanceof \Gedmo\Tree\TreeListener) {
		        $treeListener = $listeners;
		        break;
	        }

            if ($treeListener) {
                break;
            }
        }
}

a vypadá že to šlape.

mishak
Člen | 94
+
0
-

Kompatibilita s Kdyby/Events bude opravena viz. report. Příště to rovnou nahlaš :)

Na integraci Kdyby/Doctrine a Gedmo budu průběžně pracovat tento měsíc, zatím mám chuť to přepsat nebo rovnou vzdát s Kdyby návrhem se to trochu bije (Tree) :).

Balík je Rixxi/Gedmo kód tradičně na github, kdyby někdo chtěl pomoci budu rád!

akadlec
Člen | 1326
+
0
-

mishak: jak seš na tom? Já teď přehodil projekt na Kdyby Doctrine a zkouším to tvoje řešení Gedma.

mishak
Člen | 94
+
0
-

V Kdyby/Events je stále ten bug AFAIK takže je třeba pro tree úprava listeneru jinak to funguje ± samozřejmě stromy mají vlastní repozitáře nekompatibilní s Kdyby\Doctrine\EntityDao tak se na to musí dávat bacha aby je člověk netahal přímo přes Dao (háže vyjímku). Soft-deleteable se musí registrovat ručně a to je nejspíš všechno :)

akadlec
Člen | 1326
+
0
-

Jo tree listener sem si upravil jak jsem psal výše. Přemýšlím že ty repozitáře co má gedmo přepíšu aby to bylo Kdyby\Doctrine\EntityDao. Nahodou blameable si neřešil? Já to zkusil pomocí Kdyby eventů ale stejnak mám ten circual error.

akadlec
Člen | 1326
+
0
-

Stále přemýšlím nad tím jak dořešit GEDMO rozšíření a napadlo mě, je nějak možné se dostat k těm zaregistrovaným listenerům? Třeba ve startup metodě? Aby se pak nad tím listnerem dala zavolat jeho metoda na přiřazení uživatele nebo definice locale?

mishak
Člen | 94
+
0
-

Kolik máš času? Hosiplan chtěl napsat closure tree, by možná bylo lepší napsat vlastní stromy, zbytek jsou celkem jednoduche chování/vlastnosti, které by šli přepsat aby se zachovala kompatibilita s Kdyby\Doctrine. (vykašlat se úplně na Gedmo)

Editoval mishak (3. 10. 2013 17:56)

akadlec
Člen | 1326
+
0
-

mishak: no na tomhle projektu dělám po večerech a o chvílích volna. Jinak ale s mými znalostni nemám šanci to rozšíření napsat tak aby jej posvětil hosiplan :-)

Dočasně sem si to tedy vyřešil v startupu v base presenteru:

$this->context->getService('gedmo.gedmo.blameable')->setUserValue($this->userEntity);
$this->context->getService('gedmo.gedmo.translatable')->setTranslatableLocale($this->languageEntity->locale);

Editoval akadlec (3. 10. 2013 20:02)

mishak
Člen | 94
+
0
-

Se zkušenostmi si starost nedělej cokoli je lepší než nic. Když se navrhne základ ostatní můžou doladit a přispět.

I kdyby šlo ze začátku jen o hacky jak gedmo rozjet s doctrine stalo by to za to.

O dočasném fixu pro gedmo tree listener víš? viz. https://github.com/…ts/issues/22 je to poslední master + můj fix.

Editoval mishak (4. 10. 2013 2:12)