contributte/event-dispatcher v komponentě

lookass
Člen | 54
+
0
-

Ahoj, chtěl bych poradit, co dělám špatně, popř. jak zprovoznit contributte/event-dispatcher v komponentě.
V presenteru mi všechno funguje jak má, ale v komponentě nikoliv.

Mám komponentu:

class UserDetail extends \Nette\Application\UI\Control implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
{
	public static function getSubscribedEvents(): array
    {
        return [
            testEvent::class => 'test'
        ];
    }

	public function test(): void
    {
        $this->redrawControl('test');
    }
}

Nějaký model:

class Model
{
	public function __construct(private \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $eventDispatcher)
	{
	}

	public function someMethod()
	{
		$this->eventDispatcher->dispatch(new testEvent(new stdClass()));
	}
}

V momentě, kdy z jiné komponenty zavolám metodu someMethod() z třídy Model, nedojde k předání toho eventu do UserDetail.
Nechápu, proč mi to v presenteru funguje a v kopmonentě nikoliv. Něco zapomínám registrovat do configu?

config:

extensions:
	events: Contributte\EventDispatcher\DI\EventDispatcherExtension

Děkuji předem za případnou pomoc!

Editoval lookass (2. 3. 2021 14:34)

David Matějka
Moderator | 6445
+
+1
-

Ahoj, komponenty maji dva problémy, proč to nefunguje:

  • nejsou v DI containeru jako services
  • jsou lazy

Pokud si ale vytvoříš na komponentu factory, tak by mělo jít nastavit setup, který ji přidá jako subscriber. V DI extension zhruba takto:

		$builder->addFactoryDefinition($this->prefix('userDetail'))
			->setImplement(App\UserDetailFactory::class)
			->getResultDefinition()
			->addSetup('$this->getService(?)->?(?)', ['events.dispatcher', 'addSubscriber', '@self']);

A za druhé musíš tu komponentu v presenteru inicializovat brzo (rozuměj před tím, než se vyvolá event), takže třeba v startup/action

$this['userDetail']
lookass
Člen | 54
+
0
-

Ok, děkuji za rychlou odpověď.

lookass
Člen | 54
+
0
-

@DavidMatějka Asi teda bude lepší komponentu jako EventSubscriber nepoužívat, ale vytvořit další třídu např. UserDetailEventsSubscrieber, tu dát jako servisu do DI, a potom jí pouze předat parametrem instanci té komponenty.

Subscrieber by tedy mohl vypadat takto:

class TestEventSubscriber implements EventSubscriberInterface
{

    public static function getSubscribedEvents()
    {
        return [
            TestEvent::class => 'test'
        ];
    }

    public function test(TestEvent $event)
    {
        $event->call();
    }
}

Event:

class TestEvent
{
    public function __construct(private object $object)
    {
    }

    public function call()
    {
        $class = $this->object;
        $class->someMethod();
    }
}

A potom můžu v komponentě v handleru zavolat metodu z modelu:

public function handleTest(): void
{
	$model->doSomething($this);
}

A modelu předat instanci komponenty do Eventu

public function doSomething($control)
{
	//do something ...
	//create event
	$this->eventDispatcher->dispatch(new TestEvent($control);
}

Tohle funguje, ale nevím, zda to je správné takhle používat.