-
Notifications
You must be signed in to change notification settings - Fork 155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ResourceToIdentifierCacheableTransformer form data transformer #771
base: 1.9
Are you sure you want to change the base?
Changes from all commits
bdafb7d
05f4d6f
363700b
0e5a9bd
9efbb6b
b04a64a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,86 @@ | ||||||||||||
<?php | ||||||||||||
|
||||||||||||
/* | ||||||||||||
* This file is part of the Sylius package. | ||||||||||||
* | ||||||||||||
* (c) Paweł Jędrzejewski | ||||||||||||
* | ||||||||||||
* For the full copyright and license information, please view the LICENSE | ||||||||||||
* file that was distributed with this source code. | ||||||||||||
*/ | ||||||||||||
|
||||||||||||
declare(strict_types=1); | ||||||||||||
|
||||||||||||
namespace Sylius\Bundle\ResourceBundle\Form\DataTransformer; | ||||||||||||
|
||||||||||||
use Sylius\Component\Resource\Model\ResourceInterface; | ||||||||||||
use Sylius\Component\Resource\Repository\RepositoryInterface; | ||||||||||||
use Symfony\Component\Form\DataTransformerInterface; | ||||||||||||
use Symfony\Component\Form\Exception\TransformationFailedException; | ||||||||||||
use Symfony\Component\PropertyAccess\PropertyAccess; | ||||||||||||
use Webmozart\Assert\Assert; | ||||||||||||
|
||||||||||||
final class ResourceToIdentifierCacheableTransformer implements DataTransformerInterface | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Though that's just a matter of taste There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggested name is in line with the rest of the sylius, I vote for it as well |
||||||||||||
{ | ||||||||||||
private RepositoryInterface $repository; | ||||||||||||
|
||||||||||||
private string $identifier; | ||||||||||||
|
||||||||||||
/** @var array<ResourceInterface> */ | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Think it should work |
||||||||||||
private static array $cache; | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Pretty sure making it static could potentially leak objects between different instances. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible or needed to make use of psr CacheInterface/symfony cache for this? |
||||||||||||
|
||||||||||||
public function __construct(RepositoryInterface $repository, ?string $identifier = null) | ||||||||||||
{ | ||||||||||||
$this->repository = $repository; | ||||||||||||
$this->identifier = $identifier ?? 'id'; | ||||||||||||
} | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* @psalm-suppress MissingParamType | ||||||||||||
* | ||||||||||||
* @param mixed $value | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
*/ | ||||||||||||
public function transform($value) | ||||||||||||
{ | ||||||||||||
if (null === $value) { | ||||||||||||
return null; | ||||||||||||
} | ||||||||||||
|
||||||||||||
/** @psalm-suppress ArgumentTypeCoercion */ | ||||||||||||
Assert::isInstanceOf($value, $this->repository->getClassName()); | ||||||||||||
|
||||||||||||
return PropertyAccess::createPropertyAccessor()->getValue($value, $this->identifier); | ||||||||||||
} | ||||||||||||
|
||||||||||||
/** @param mixed $value */ | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
public function reverseTransform($value): ?ResourceInterface | ||||||||||||
{ | ||||||||||||
if (null === $value) { | ||||||||||||
return null; | ||||||||||||
} | ||||||||||||
|
||||||||||||
if (isset(self::$cache[$value])) { | ||||||||||||
return self::$cache[$value]; | ||||||||||||
} | ||||||||||||
|
||||||||||||
/** @var ResourceInterface|null $resource */ | ||||||||||||
$resource = $this->repository->findOneBy([$this->identifier => $value]); | ||||||||||||
if (null === $resource) { | ||||||||||||
throw new TransformationFailedException(sprintf( | ||||||||||||
'Object "%s" with identifier "%s"="%s" does not exist.', | ||||||||||||
$this->repository->getClassName(), | ||||||||||||
$this->identifier, | ||||||||||||
$value, | ||||||||||||
)); | ||||||||||||
} | ||||||||||||
|
||||||||||||
self::$cache[$value] = $resource; | ||||||||||||
|
||||||||||||
return $resource; | ||||||||||||
} | ||||||||||||
|
||||||||||||
public function clear(): void | ||||||||||||
{ | ||||||||||||
self::$cache = []; | ||||||||||||
} | ||||||||||||
Comment on lines
+81
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Sylius package. | ||
* | ||
* (c) Paweł Jędrzejewski | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace spec\Sylius\Bundle\ResourceBundle\Form\DataTransformer; | ||
|
||
use PhpSpec\ObjectBehavior; | ||
use Prophecy\Argument; | ||
use Sylius\Component\Resource\Model\ResourceInterface; | ||
use Sylius\Component\Resource\Repository\RepositoryInterface; | ||
use Symfony\Component\Form\Exception\TransformationFailedException; | ||
|
||
final class ResourceToIdentifierCacheableTransformerSpec extends ObjectBehavior | ||
{ | ||
function let(RepositoryInterface $repository): void | ||
{ | ||
$this->beConstructedWith($repository, 'id'); | ||
} | ||
|
||
function it_does_not_reverses_null_value(RepositoryInterface $repository): void | ||
{ | ||
$repository->findOneBy(Argument::any())->shouldNotBeCalled(); | ||
|
||
$this->reverseTransform(null)->shouldReturn(null); | ||
} | ||
|
||
function it_throws_an_exception_on_non_existing_resource(RepositoryInterface $repository): void | ||
{ | ||
$repository->getClassName()->willReturn(ResourceInterface::class); | ||
$repository->findOneBy(['id' => 6])->willReturn(null); | ||
|
||
$this->shouldThrow(TransformationFailedException::class)->during('reverseTransform', [6]); | ||
} | ||
|
||
function it_reverse_transform_identifier_to_resource(RepositoryInterface $repository, ResourceInterface $resource): void | ||
{ | ||
$repository->findOneBy(['id' => 5])->willReturn($resource); | ||
|
||
$this->reverseTransform(5)->shouldReturn($resource); | ||
} | ||
|
||
function it_reverse_transforms_identifier_to_resource_using_cache( | ||
RepositoryInterface $repository, | ||
ResourceInterface $resource, | ||
): void { | ||
$this->clear(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creating a method just for the specs to work is a bad idea. Even more so since it's not in any interface. Normally for something like this, you could use Remove the |
||
|
||
$repository->findOneBy(['id' => 5]) | ||
->willReturn($resource) | ||
->shouldBeCalledOnce() | ||
; | ||
|
||
$this->reverseTransform(5)->shouldReturn($resource); | ||
$this->reverseTransform(5)->shouldReturn($resource); | ||
} | ||
|
||
function it_transforms_null_value_to_empty_string(RepositoryInterface $repository): void | ||
{ | ||
$repository->getClassName()->willReturn(ResourceInterface::class); | ||
|
||
$this->transform(null)->shouldReturn(null); | ||
} | ||
|
||
function it_transforms_resource_in_identifier(RepositoryInterface $repository, ResourceInterface $resource): void | ||
{ | ||
$repository->getClassName()->willReturn(ResourceInterface::class); | ||
|
||
$resource->getId()->willReturn(6); | ||
|
||
$this->transform($resource)->shouldReturn(6); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it should be placed into src/Component/src/Symfony/Form/DataTransformer directory.