Skip to content

Commit 95cc2f5

Browse files
committed
feature #725 [LiveComponent] Fix calculateFingerprint with big objects (LunkLoafGrumble)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- [LiveComponent] Fix calculateFingerprint with big objects | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | Tickets | N/A | License | MIT This pull request will fix an issue for large objects (for example entities with a large relations) with in the FingerprintCalculator While working with liveComponents I noticed my project getting slower and slower. After some digging I found out that in the calculateFingerprint function the data is serialized. When an entity with relations passes by it will serialize the entity and its child objects. This takes a considerable amount of time and is not needed. Commits ------- b55f97e [LiveComponent] Fix calculateFingerprint with big objects
2 parents 77fd0b6 + b55f97e commit 95cc2f5

File tree

3 files changed

+71
-4
lines changed

3 files changed

+71
-4
lines changed

src/LiveComponent/src/DependencyInjection/LiveComponentExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ function (ChildDefinition $definition, AsLiveComponent $attribute) {
174174

175175
$container->register('ux.live_component.deterministic_id_calculator', DeterministicTwigIdCalculator::class);
176176
$container->register('ux.live_component.fingerprint_calculator', FingerprintCalculator::class)
177-
->setArguments(['%kernel.secret%']);
177+
->setArguments([new Reference('serializer'), '%kernel.secret%']);
178178

179179
$container->setAlias(ComponentValidatorInterface::class, ComponentValidator::class);
180180

src/LiveComponent/src/Util/FingerprintCalculator.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
/*
46
* This file is part of the Symfony package.
57
*
@@ -11,6 +13,9 @@
1113

1214
namespace Symfony\UX\LiveComponent\Util;
1315

16+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
17+
use Symfony\UX\LiveComponent\LiveComponentHydrator;
18+
1419
/**
1520
* @author Ryan Weaver <[email protected]>
1621
*
@@ -20,12 +25,16 @@
2025
*/
2126
class FingerprintCalculator
2227
{
23-
public function __construct(private string $secret)
24-
{
28+
public function __construct(
29+
private NormalizerInterface $objectNormalizer,
30+
private string $secret,
31+
) {
2532
}
2633

2734
public function calculateFingerprint(array $data): string
2835
{
29-
return base64_encode(hash_hmac('sha256', serialize($data), $this->secret, true));
36+
$normalizedData = $this->objectNormalizer->normalize($data, context: [LiveComponentHydrator::LIVE_CONTEXT => true]);
37+
38+
return base64_encode(hash_hmac('sha256', serialize($normalizedData), $this->secret, true));
3039
}
3140
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\LiveComponent\Tests\Integration\Util;
13+
14+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
15+
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\Entity1;
16+
use Zenstruck\Foundry\Test\Factories;
17+
use Zenstruck\Foundry\Test\ResetDatabase;
18+
19+
use function Zenstruck\Foundry\create;
20+
21+
final class FingerprintCalculatorTest extends KernelTestCase
22+
{
23+
use Factories;
24+
use ResetDatabase;
25+
26+
public function testFingerprintEqual()
27+
{
28+
$fingerprintCalculator = self::getContainer()->get('ux.live_component.fingerprint_calculator');
29+
30+
$entityOne = create(Entity1::class)->object();
31+
32+
$entityTwo = clone $entityOne;
33+
34+
self::assertNotSame(
35+
spl_object_id($entityOne),
36+
spl_object_id($entityTwo)
37+
);
38+
39+
self::assertSame(
40+
$fingerprintCalculator->calculateFingerprint([$entityOne]),
41+
$fingerprintCalculator->calculateFingerprint([$entityTwo])
42+
);
43+
}
44+
45+
public function testFingerprintNotEqual()
46+
{
47+
$fingerprintCalculator = self::getContainer()->get('ux.live_component.fingerprint_calculator');
48+
49+
$entityOne = create(Entity1::class)->object();
50+
51+
$entityTwo = create(Entity1::class)->object();
52+
53+
self::assertNotSame(
54+
$fingerprintCalculator->calculateFingerprint([$entityOne]),
55+
$fingerprintCalculator->calculateFingerprint([$entityTwo])
56+
);
57+
}
58+
}

0 commit comments

Comments
 (0)