Skip to content

Commit

Permalink
Move to newer service configuration for 5.4+ services
Browse files Browse the repository at this point in the history
  • Loading branch information
pkly committed Apr 19, 2024
1 parent c8b1b8c commit ff0c3d2
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 51 deletions.
28 changes: 26 additions & 2 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Doctrine\ORM\Events;
use DualMedia\DoctrineEventConverterBundle\EventSubscriber\DispatchingSubscriber;
use DualMedia\DoctrineEventConverterBundle\Proxy\Generator;
use DualMedia\DoctrineEventConverterBundle\Service\DelayableEventDispatcher;
Expand All @@ -27,12 +28,35 @@

$services->set(VerifierService::class);

$services->set(DispatchingSubscriber::class)
$def = $services->set(DispatchingSubscriber::class)
->arg('$eventService', new Reference(EventService::class))
->arg('$subEventService', new Reference(SubEventService::class))
->arg('$verifierService', new Reference(VerifierService::class))
->arg('$dispatcher', new Reference(DelayableEventDispatcher::class))
->tag('doctrine.event_subscriber');
->tag('doctrine.event_listener', [
'event' => Events::prePersist,
])
->tag('doctrine.event_listener', [
'event' => Events::postPersist,
])
->tag('doctrine.event_listener', [
'event' => Events::preUpdate,
])
->tag('doctrine.event_listener', [
'event' => Events::postUpdate,
])
->tag('doctrine.event_listener', [
'event' => Events::preRemove,
])
->tag('doctrine.event_listener', [
'event' => Events::postRemove,
])
->tag('doctrine.event_listener', [
'event' => Events::preFlush,
])
->tag('doctrine.event_listener', [
'event' => Events::postFlush,
]);

$services->set(Generator::class)
->arg(0, '%kernel.cache_dir%/dm-smd-event-distributor-bundle')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,10 @@ public function process(
$output = [];
krsort($subEventConstruct, SORT_NUMERIC); // sort by priorities (200 -> 0 -> -200)

foreach ($subEventConstruct as $data) {
$output[] = $data;
foreach ($subEventConstruct as $prioritySortedList) {
foreach ($prioritySortedList as $data) {
$output[] = $data;
}
}

$subEventService->setArgument('$entries', $output);
Expand Down
21 changes: 2 additions & 19 deletions src/EventSubscriber/DispatchingSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace DualMedia\DoctrineEventConverterBundle\EventSubscriber;

use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\Event\PostPersistEventArgs;
Expand All @@ -22,7 +21,7 @@
use DualMedia\DoctrineEventConverterBundle\Service\SubEventService;
use DualMedia\DoctrineEventConverterBundle\Service\VerifierService;

class DispatchingSubscriber implements EventSubscriber
class DispatchingSubscriber
{
private bool $preFlush = false;

Expand All @@ -48,25 +47,9 @@ public function __construct(
) {
}

public function getSubscribedEvents(): array
{
return [
Events::prePersist,
Events::postPersist,
Events::preUpdate,
Events::postUpdate,
Events::preRemove,
Events::postRemove,
Events::preFlush,
Events::postFlush,
];
}

public function prePersist(
PrePersistEventArgs $args
): void {
echo 'DISPATCHED!!!!!!!!!!!';

if ($args->getObject() instanceof EntityInterface) {
$this->process(Events::prePersist, $args->getObject());
}
Expand Down Expand Up @@ -196,7 +179,7 @@ private function subEvents(
$subEvent->setEntity($entity)
->setChanges(array_intersect_key(
$event->getChanges(),
$model->fieldList
$model->fields
)) // save only fields that the event requested, ignore rest
->setEventType($event->getEventType());

Expand Down
4 changes: 2 additions & 2 deletions src/Model/SubEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ class SubEvent
{
/**
* @param bool $allMode If all the fields must be meeting the requirements of the event
* @param array<string, null|array{0?: mixed, 1?: mixed}> $fieldList The fields that must be changed, null means that any change is required, 0 and 1 indexes match before/after
* @param array<string, null|array{0?: mixed, 1?: mixed}> $fields The fields that must be changed, null means that any change is required, 0 and 1 indexes match before/after
* @param array<string, mixed> $requirements Required field states for this event to fire
* @param list<string> $types Event types in which this event may be triggered
*/
public function __construct(
public readonly bool $allMode,
public readonly array $fieldList,
public readonly array $fields,
public readonly array $requirements,
public readonly array $types,
public readonly bool $afterFlush,
Expand Down
2 changes: 1 addition & 1 deletion src/Service/SubEventService.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function __construct(
[$eventClass, $entities, $allMode, $fieldList, $requirements, $types, $afterFlush] = $entry;

foreach ($entities as $entity) {
if (!array_key_exists($entity, $this->events[$entity])) {
if (!array_key_exists($entity, $this->events)) {
$this->events[$entity] = [];
}

Expand Down
50 changes: 30 additions & 20 deletions src/Service/VerifierService.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function __construct(
}

/**
* @param array<string, array<int, mixed>> $changes
* @param array<string, array{0: mixed, 1: mixed}> $changes
*/
public function validate(
array $changes,
Expand Down Expand Up @@ -49,48 +49,58 @@ public function validateRequirements(
}

/**
* @param array<string, array<int, mixed>> $changes
* @param array<string, array{0: mixed, 1: mixed}> $changes
*/
public function validateFields(
array $changes,
SubEvent $model,
string $type
): bool {
if (!in_array($type, [Events::postUpdate, Events::preUpdate], true)) {
return false;
return true;
}

if ($model->allMode && count(array_diff_key($model->fieldList, $changes))) { // Event contains keys that haven't changed
if ($model->allMode && count(array_diff_key($model->fields, $changes))) { // Event contains keys that haven't changed
return false;
} elseif (!$model->allMode && !count(array_intersect_key($changes, $model->fieldList))) { // Event doesn't contain any of the required keys
} elseif (!$model->allMode && !count(array_intersect_key($changes, $model->fields))) { // Event doesn't contain any of the required keys
return false;
}

$validFields = [];

foreach ($changes as $field => $fields) {
if (!array_key_exists($field, $model->fieldList)) {
continue;
} elseif (null === ($modelWantedState = $model->fieldList[$field])) {
// if you set null instead of setting null for key 0 you're dumb and #wontfix
$validFields[$field] = true;
if (!array_key_exists($field, $model->fields)) {
continue;
}

$count = count($modelWantedState);

if (1 === $count) {
$existingCounter = array_key_exists(0, $modelWantedState) ? 0 : 1;
$validFields[$field] = $this->equals($fields[$existingCounter], $modelWantedState[$existingCounter]); // @phpstan-ignore-line
} elseif (2 === $count) {
/** @var array{0: mixed, 1: mixed} $modelWantedState */
$validFields[$field] = $this->equals($fields[0], $modelWantedState[0]) && $this->equals($fields[1], $modelWantedState[1]);
}
$validFields[$field] = null === ($modelWantedState = $model->fields[$field])
|| $this->validateField($fields, $modelWantedState);
}

$reduced = array_reduce($validFields, fn ($carry, $data) => $carry + ((int)$data));

return !$model->allMode ? $reduced > 0 : $reduced === count($model->fieldList);
return !$model->allMode ? $reduced > 0 : $reduced === count($model->fields);
}

/**
* @param array{0: mixed, 1: mixed} $changes
* @param array{0?: mixed, 1?: mixed} $wantedState
*/
public function validateField(
array $changes,
array $wantedState
): bool {
$count = count($wantedState);

if (1 === $count) {
$existingCounter = array_key_exists(0, $wantedState) ? 0 : 1;
return $this->equals($changes[$existingCounter], $wantedState[$existingCounter]); // @phpstan-ignore-line
} elseif (2 === $count) {
/** @var array{0: mixed, 1: mixed} $wantedState */
return $this->equals($changes[0], $wantedState[0]) && $this->equals($changes[1], $wantedState[1]);
}

return false;
}

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/Fixtures/Enum/BackedIntEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace DualMedia\DoctrineEventConverterBundle\Tests\Fixtures\Enum;

enum BackedIntEnum: int
{
case Is5 = 5;
}
6 changes: 3 additions & 3 deletions tests/Model/ChangeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
namespace DualMedia\DoctrineEventConverterBundle\Tests\Model;

use DualMedia\DoctrineEventConverterBundle\Model\Change;
use DualMedia\DoctrineEventConverterBundle\Tests\KernelTestCase;
use PHPUnit\Framework\TestCase;

class ChangeTest extends KernelTestCase
class ChangeTest extends TestCase
{
public function test()
public function test(): void
{
$change = new Change('status', 1, 2);

Expand Down
33 changes: 31 additions & 2 deletions tests/Service/EventServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

namespace DualMedia\DoctrineEventConverterBundle\Tests\Service;

use Doctrine\ORM\Events;
use DualMedia\DoctrineEventConverterBundle\Service\EventService;
use DualMedia\DoctrineEventConverterBundle\Tests\Fixtures\Entity\ComplexEntity;
use DualMedia\DoctrineEventConverterBundle\Tests\Fixtures\Entity\Item;
use DualMedia\DoctrineEventConverterBundle\Tests\Fixtures\Event\ComplexEntityEvent;
use PHPUnit\Framework\TestCase;
use Pkly\ServiceMockHelperTrait;

Expand All @@ -15,12 +19,37 @@ class EventServiceTest extends TestCase
protected function setUp(): void
{
$this->service = $this->createRealMockedServiceInstance(EventService::class, [
'entries' => [],
'entries' => [
[
ComplexEntityEvent::class,
[ComplexEntity::class],
Events::prePersist,
true,
],
],
]);
}

public function test(): void
{
$this->assertTrue(true);
$this->assertNotEmpty(
$events = $this->service->get(Events::prePersist, ComplexEntity::class),
'There should be exactly 1 event for specified inputs'
);
$this->assertCount(1, $events, 'There should be exactly 1 event for specified inputs');

$this->assertEquals(
ComplexEntityEvent::class,
$events[0]->eventClass
);
$this->assertTrue($events[0]->afterFlush);
}

public function testNotFound(): void
{
$this->assertEmpty(
$this->service->get(Events::postRemove, Item::class),
'No events should be returned from service'
);
}
}
81 changes: 81 additions & 0 deletions tests/Service/SubEventServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace DualMedia\DoctrineEventConverterBundle\Tests\Service;

use Doctrine\ORM\Events;
use DualMedia\DoctrineEventConverterBundle\Service\SubEventService;
use DualMedia\DoctrineEventConverterBundle\Tests\Fixtures\Entity\ComplexEntity;
use DualMedia\DoctrineEventConverterBundle\Tests\Fixtures\Entity\Item;
use DualMedia\DoctrineEventConverterBundle\Tests\Fixtures\Event\ComplexEntityEvent;
use PHPUnit\Framework\TestCase;
use Pkly\ServiceMockHelperTrait;

class SubEventServiceTest extends TestCase
{
use ServiceMockHelperTrait;

private SubEventService $service;

protected function setUp(): void
{
$this->service = $this->createRealMockedServiceInstance(SubEventService::class, [
'entries' => [
[
ComplexEntityEvent::class,
[ComplexEntity::class],
false,
[
'stuff' => null,
],
[
'requirement' => 42,
],
[
Events::prePersist,
],
true,
],
],
]);
}

public function test(): void
{
$this->assertNotEmpty(
$events = $this->service->get(ComplexEntity::class),
'There should be exactly 1 event for specified inputs'
);
$this->assertCount(1, $events, 'There should be exactly 1 event for specified inputs');

$this->assertArrayHasKey(
ComplexEntityEvent::class,
$events
);
$this->assertCount(1, $events[ComplexEntityEvent::class]);
$event = $events[ComplexEntityEvent::class][0];

$this->assertFalse(
$event->allMode
);
$this->assertEquals([
'stuff' => null,
], $event->fields);
$this->assertEquals([
'requirement' => 42,
], $event->requirements);
$this->assertEquals([
Events::prePersist,
], $event->types);
$this->assertTrue(
$event->afterFlush
);
}

public function testEmpty(): void
{
$this->assertEmpty(
$this->service->get(Item::class),
'There should be sub events for specified entity'
);
}
}
Loading

0 comments on commit ff0c3d2

Please sign in to comment.