Skip to content

Commit

Permalink
feature #1074 [LiveComponent] Add priority to PreDehydrate & PostHydr…
Browse files Browse the repository at this point in the history
…ate hooks (sneakyvv)

This PR was merged into the 2.x branch.

Discussion
----------

[LiveComponent] Add priority to PreDehydrate & PostHydrate hooks

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| Tickets       |
| License       | MIT

As a follow-up of #1068, I have also added the option to prioritize PreDehydrate & PostHydrate hooks.

Commits
-------

82a9e17 [LiveComponent] Add priority to PreDehydrate & PostHydrate hooks
  • Loading branch information
weaverryan committed Aug 29, 2023
2 parents 35e84e3 + 82a9e17 commit 14115f1
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 33 deletions.
16 changes: 5 additions & 11 deletions src/LiveComponent/src/Attribute/AsLiveComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,33 +67,27 @@ public static function isActionAllowed(object $component, string $action): bool
*/
public static function preReRenderMethods(object $component): iterable
{
$methods = iterator_to_array(self::attributeMethodsFor(PreReRender::class, $component));

usort($methods, static function (\ReflectionMethod $a, \ReflectionMethod $b) {
return $a->getAttributes(PreReRender::class)[0]->newInstance()->priority <=> $b->getAttributes(PreReRender::class)[0]->newInstance()->priority;
});

return array_reverse($methods);
return self::attributeMethodsByPriorityFor($component, PreReRender::class);
}

/**
* @internal
*
* @return \ReflectionMethod[]
*/
public static function postHydrateMethods(object $component): \Traversable
public static function postHydrateMethods(object $component): iterable
{
yield from self::attributeMethodsFor(PostHydrate::class, $component);
return self::attributeMethodsByPriorityFor($component, PostHydrate::class);
}

/**
* @internal
*
* @return \ReflectionMethod[]
*/
public static function preDehydrateMethods(object $component): \Traversable
public static function preDehydrateMethods(object $component): iterable
{
yield from self::attributeMethodsFor(PreDehydrate::class, $component);
return self::attributeMethodsByPriorityFor($component, PreDehydrate::class);
}

public static function liveListeners(object $component): array
Expand Down
7 changes: 7 additions & 0 deletions src/LiveComponent/src/Attribute/PostHydrate.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,11 @@
#[\Attribute(\Attribute::TARGET_METHOD)]
final class PostHydrate
{
/**
* @param int $priority If multiple hooks are registered in a component, use to configure
* the order in which they are called (higher called earlier)
*/
public function __construct(public int $priority = 0)
{
}
}
7 changes: 7 additions & 0 deletions src/LiveComponent/src/Attribute/PreDehydrate.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,11 @@
#[\Attribute(\Attribute::TARGET_METHOD)]
final class PreDehydrate
{
/**
* @param int $priority If multiple hooks are registered in a component, use to configure
* the order in which they are called (higher called earlier)
*/
public function __construct(public int $priority = 0)
{
}
}
56 changes: 48 additions & 8 deletions src/LiveComponent/tests/Unit/Attribute/AsLiveComponentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use PHPUnit\Framework\TestCase;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\PostHydrate;
use Symfony\UX\LiveComponent\Attribute\PreDehydrate;
use Symfony\UX\LiveComponent\Attribute\PreReRender;
use Symfony\UX\LiveComponent\Tests\Fixtures\Component\Component5;

Expand All @@ -21,20 +23,58 @@
*/
final class AsLiveComponentTest extends TestCase
{
public function testCanGetPreDehydrateMethods(): void
public function testPreDehydrateMethodsAreOrderedByPriority(): void
{
$methods = iterator_to_array(AsLiveComponent::preDehydrateMethods(new Component5()));
$hooks = AsLiveComponent::preDehydrateMethods(
new class() {
#[PreDehydrate(priority: -10)]
public function hook1()
{
}

#[PreDehydrate(priority: 10)]
public function hook2()
{
}

#[PreDehydrate]
public function hook3()
{
}
}
);

$this->assertCount(1, $methods);
$this->assertSame('method4', $methods[0]->getName());
$this->assertCount(3, $hooks);
$this->assertSame('hook2', $hooks[0]->name);
$this->assertSame('hook3', $hooks[1]->name);
$this->assertSame('hook1', $hooks[2]->name);
}

public function testCanGetPostHydrateMethods(): void
public function testPostHydrateMethodsAreOrderedByPriority(): void
{
$methods = iterator_to_array(AsLiveComponent::postHydrateMethods(new Component5()));
$hooks = AsLiveComponent::postHydrateMethods(
new class() {
#[PostHydrate(priority: -10)]
public function hook1()
{
}

#[PostHydrate(priority: 10)]
public function hook2()
{
}

#[PostHydrate]
public function hook3()
{
}
}
);

$this->assertCount(1, $methods);
$this->assertSame('method5', $methods[0]->getName());
$this->assertCount(3, $hooks);
$this->assertSame('hook2', $hooks[0]->name);
$this->assertSame('hook3', $hooks[1]->name);
$this->assertSame('hook1', $hooks[2]->name);
}

public function testPreMountHooksAreOrderedByPriority(): void
Expand Down
34 changes: 20 additions & 14 deletions src/TwigComponent/src/Attribute/AsTwigComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,7 @@ public function serviceConfig(): array
*/
public static function preMountMethods(object $component): iterable
{
$methods = iterator_to_array(self::attributeMethodsFor(PreMount::class, $component));

usort($methods, static function (\ReflectionMethod $a, \ReflectionMethod $b) {
return $a->getAttributes(PreMount::class)[0]->newInstance()->priority <=> $b->getAttributes(PreMount::class)[0]->newInstance()->priority;
});

return array_reverse($methods);
return self::attributeMethodsByPriorityFor($component, PreMount::class);
}

/**
Expand All @@ -61,13 +55,7 @@ public static function preMountMethods(object $component): iterable
*/
public static function postMountMethods(object $component): iterable
{
$methods = iterator_to_array(self::attributeMethodsFor(PostMount::class, $component));

usort($methods, static function (\ReflectionMethod $a, \ReflectionMethod $b) {
return $a->getAttributes(PostMount::class)[0]->newInstance()->priority <=> $b->getAttributes(PostMount::class)[0]->newInstance()->priority;
});

return array_reverse($methods);
return self::attributeMethodsByPriorityFor($component, PostMount::class);
}

/**
Expand All @@ -83,4 +71,22 @@ protected static function attributeMethodsFor(string $attribute, object $compone
}
}
}

/**
* @param class-string $attributeClass
*
* @return \ReflectionMethod[]
*
* @internal
*/
protected static function attributeMethodsByPriorityFor(object $component, string $attributeClass): array
{
$methods = iterator_to_array(self::attributeMethodsFor($attributeClass, $component));

usort($methods, static function (\ReflectionMethod $a, \ReflectionMethod $b) use ($attributeClass) {
return $a->getAttributes($attributeClass)[0]->newInstance()->priority <=> $b->getAttributes($attributeClass)[0]->newInstance()->priority;
});

return array_reverse($methods);
}
}

0 comments on commit 14115f1

Please sign in to comment.