From eb334fec94a92a05930c4b0541af845ee597171c Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Thu, 13 Nov 2025 10:47:05 +0100 Subject: [PATCH] init --- .gitignore | 10 ++ README.md | 82 +++++++++++++ composer-require-checker.json | 20 +++ composer-unused.php | 9 ++ composer.json | 102 ++++++++++++++++ docker-compose.yml | 9 ++ phpcs.xml | 34 ++++++ phpstan-baseline.neon | 6 + phpstan.neon | 16 +++ phpunit.xml | 14 +++ .../SasedevHiddenEntityTypeExtension.php | 22 ++++ .../DataTransformer/ObjectToIdTransformer.php | 66 ++++++++++ .../ObjectsToIdTransformer.php | 64 ++++++++++ .../Form/DataTransformer/Transformer.php | 63 ++++++++++ .../Form/Type/HiddenDocumentType.php | 22 ++++ .../Form/Type/HiddenEntityType.php | 22 ++++ .../Form/Type/HiddenObjectType.php | 60 +++++++++ .../Resources/config/form.yaml | 7 ++ .../SasedevHiddenEntityTypeBundle.php | 9 ++ .../ObjectToIdTransformerTest.php | 114 ++++++++++++++++++ .../ObjectsToIdTransformerTest.php | 98 +++++++++++++++ .../Form/Type/HiddenObjectTypeFailedTest.php | 59 +++++++++ .../Tests/Form/Type/HiddenObjectTypeTest.php | 71 +++++++++++ .../Tests/Form/Type/TestFormType.php | 26 ++++ .../Tests/Model/TestFormModel.php | 17 +++ .../Tests/Model/TestObject.php | 17 +++ 26 files changed, 1039 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 composer-require-checker.json create mode 100644 composer-unused.php create mode 100644 composer.json create mode 100644 docker-compose.yml create mode 100644 phpcs.xml create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.neon create mode 100644 phpunit.xml create mode 100644 src/Sasedev/HiddenEntityTypeBundle/DependencyInjection/SasedevHiddenEntityTypeExtension.php create mode 100644 src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectToIdTransformer.php create mode 100644 src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectsToIdTransformer.php create mode 100644 src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/Transformer.php create mode 100644 src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenDocumentType.php create mode 100644 src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenEntityType.php create mode 100644 src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenObjectType.php create mode 100644 src/Sasedev/HiddenEntityTypeBundle/Resources/config/form.yaml create mode 100644 src/Sasedev/HiddenEntityTypeBundle/SasedevHiddenEntityTypeBundle.php create mode 100644 tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/DataTransformer/ObjectToIdTransformerTest.php create mode 100644 tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/DataTransformer/ObjectsToIdTransformerTest.php create mode 100644 tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeFailedTest.php create mode 100644 tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeTest.php create mode 100644 tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/TestFormType.php create mode 100644 tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestFormModel.php create mode 100644 tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestObject.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c01d334 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/bin/ +/vendor/ +/composer.phar +/composer.lock +/.phpunit.cache/ +phpcs.cache +# eclipse +/.project +/.settings +/.buildpath \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..26a50b9 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# Sasedev - Hidden Entity Type Bundle + +Hidden entity type for Symfony forms. + +[![paypal](https://img.shields.io/badge/Donate-Paypal-blue.svg)](http://paypal.me/Sasedev) + +## What is it? + +This is a Symfony form type that allows you to add an entity in your form that would be displayed as a hidden input. + +## Installation + +### Step 1: Download HiddenEntityTypeBundle using composer +```bash +$ composer require sasedev/hidden-entity-type-bundle +``` +Composer will install the bundle to your project's vendor directory. + +### Step 2: Enable the bundle +Enable the bundle in the config if flex it did´nt do it for you: +```php + ['all' => true], + // ... +]; +``` + +## Usage + +### Simple usage: +You can use the type in your forms just like this: +```php +add('entity', HiddenEntityType::class, array( + 'class' => YourBundleEntity::class +)); +``` +You can also use the `HiddenDocumentType::class` type: +```php +add('document', HiddenDocumentType::class, array( + 'class' => YourBundleDocument::class +)); +``` +There is only one required option "class". You must specify entity class in Symfony format that you want to be used in your form. + +### Advanced usage: +You can use the `HiddenEntityType` or `HiddenDocumentType` type in your forms this way: +```php +add('entity', HiddenEntityType::class, array( + 'class' => YourBundleEntity::class, // required + 'property' => 'entity_id', // Mapped property name (default is 'id'), not required + 'multiple' => false, // support for an array of entities, not required + 'data' => $entity, // Field value by default, not required + 'invalid_message' => 'The entity does not exist.', // Message that would be shown if no entity found, not required +)); +``` + +## Reporting an issue or a feature request +Feel free to report any issues. If you have an idea to make it better go ahead and modify and submit pull requests. + +### Copy + +This is a modified copy of source from Shapecode (https://github.com/shapecode/hidden-entity-type-bundle) that support sf>=7.3. + +### Original + +The orginal source is from Glifery (https://github.com/Glifery/EntityHiddenTypeBundle) but seems not to be supported anymore. \ No newline at end of file diff --git a/composer-require-checker.json b/composer-require-checker.json new file mode 100644 index 0000000..f8332b1 --- /dev/null +++ b/composer-require-checker.json @@ -0,0 +1,20 @@ +{ + "symbol-whitelist": [ + "null", + "true", + "false", + "static", + "self", + "parent", + "array", + "string", + "int", + "float", + "bool", + "iterable", + "callable", + "mixed", + "void", + "object" + ] +} \ No newline at end of file diff --git a/composer-unused.php b/composer-unused.php new file mode 100644 index 0000000..536e40d --- /dev/null +++ b/composer-unused.php @@ -0,0 +1,9 @@ +addNamedFilter(NamedFilter::fromString('symfony/framework-bundle'))->addNamedFilter(NamedFilter::fromString('symfony/yaml')); +}; \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6ecbaa1 --- /dev/null +++ b/composer.json @@ -0,0 +1,102 @@ +{ + "name": "sasedev/hidden-entity-type-bundle", + "type": "symfony-bundle", + "description": "Hidden field for Symfony entities", + "keywords": [ + "entity", + "hidden", + "form", + "type", + "shapecode", + "sasedev", + "symfony" + ], + "homepage": "https://git.sasedev.com/Sasedev/hidden-entity-type-bundle", + "license": "MIT", + "authors": [ + { + "name": "Salah Abdelkadeur Seifeddine", + "homepage": "https://sasedev.com", + "email": "sinus@sasedev.net" + }, + { + "name": "Nikita Loges", + "homepage": "https://loges.one", + "email": "dev@loges.one" + }, + { + "name": "Glifery", + "email": "glifery@gmail.com" + } + ], + "autoload": { + "psr-4": { + "": "src" + } + }, + "autoload-dev": { + "psr-4": { + "": "tests" + } + }, + "require": { + "php": ">=8.2", + "symfony/framework-bundle": "^7.3.6", + "symfony/config": "^7.3.6", + "symfony/http-kernel": "^7.3.7", + "symfony/dependency-injection": "^7.3.6", + "symfony/form": "^7.3.6", + "symfony/yaml": "^7.3.5", + "symfony/options-resolver": "^7.3.3", + "symfony/property-access": "^7.3.3", + "symfony/property-info": "^7.3.5", + "doctrine/persistence": "^4.1.1", + "webmozart/assert": "^1.12.1" + }, + "require-dev": { + "icanhazstring/composer-unused": "^0.9.5", + "doctrine/coding-standard": "^14.0", + "squizlabs/php_codesniffer": "^4.0.1", + "phpstan/phpstan": "^2.1.32", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.8", + "phpstan/phpstan-strict-rules": "^2.0.7", + "phpstan/phpstan-webmozart-assert": "^2.0", + "maglnet/composer-require-checker": "^4.18", + "phpstan/phpstan-symfony": "^2.0.8", + "phpunit/phpunit": "^12.4.3", + "symfony/var-dumper": "^7.3.5" + }, + "scripts": { + "check": [ + "@crc", + "@unused", + "@cs-check", + "@phpstan", + "@phpunit" + ], + "phpstan": "phpstan analyse --ansi", + "phpstan-update-baseline": "phpstan analyse --ansi --generate-baseline phpstan-baseline.neon", + "crc": "vendor/bin/composer-require-checker --config-file=./composer-require-checker.json --ansi", + "phpunit": "phpunit --colors=always", + "cs-check": "phpcs -s", + "cs-fix": "phpcbf", + "unused": "vendor/bin/composer-unused" + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "bin-dir": "bin", + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "icanhazstring/composer-unused": true + }, + "bump-after-update": true, + "sort-packages": true + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f414deb --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: '3.6' +services: + app: + image: webdevops/php:8.3 + volumes: + - ./:/app/ + environment: + PHP_MEMORY_LIMIT: 4G + PHP_DATE_TIMEZONE: Europe/Zurich \ No newline at end of file diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..994331d --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + src/ + tests/ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..d65608b --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,6 @@ +parameters: + ignoreErrors: + - + message: "#^Method Sasedev\\\\HiddenEntityTypeBundle\\\\Form\\\\DataTransformer\\\\Transformer\\:\\:getRepository\\(\\) return type with generic interface Doctrine\\\\Persistence\\\\ObjectRepository does not specify its types\\: T$#" + count: 1 + path: src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/Transformer.php \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..e439d0d --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,16 @@ +includes: + - vendor/phpstan/phpstan/conf/bleedingEdge.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon + - vendor/phpstan/phpstan-webmozart-assert/extension.neon + - vendor/phpstan/phpstan-symfony/extension.neon + - vendor/phpstan/phpstan-symfony/rules.neon + - phpstan-baseline.neon + +parameters: + level: max + paths: + - src + - tests \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..35efe4d --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,14 @@ + + + + + + tests + + + + + src + + + \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/DependencyInjection/SasedevHiddenEntityTypeExtension.php b/src/Sasedev/HiddenEntityTypeBundle/DependencyInjection/SasedevHiddenEntityTypeExtension.php new file mode 100644 index 0000000..522d616 --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/DependencyInjection/SasedevHiddenEntityTypeExtension.php @@ -0,0 +1,22 @@ +load('form.yaml'); + } +} \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectToIdTransformer.php b/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectToIdTransformer.php new file mode 100644 index 0000000..9407613 --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectToIdTransformer.php @@ -0,0 +1,66 @@ + + */ +class ObjectToIdTransformer extends Transformer { + + public function transform(mixed $value): mixed { + if ($value === null) { + return null; + } + + Assert::isInstanceOf($value, $this->class); + + $accessor = PropertyAccess::createPropertyAccessor(); + $property = $this->getProperty(); + + if (! $accessor->isReadable($value, $property)) { + return null; + } + + $valueObject = $accessor->getValue($value, $property); + + if ($valueObject === null) { + return null; + } + + if (! is_string($valueObject) && ! is_numeric($valueObject)) { + throw new LogicException('id hast to be string or integer', 1653564596059); + } + + return (string) $valueObject; + } + + public function reverseTransform(mixed $value): mixed { + if ($value === null) { + return null; + } + + $repo = $this->getRepository(); + $property = $this->getProperty(); + $class = $this->getClass(); + + $result = $repo->findOneBy([$property => $value]); + + if ($result === null) { + throw new TransformationFailedException(sprintf('Can\'t find entity of class "%s" with property "%s" = "%s".', $class, $property, $value), 1701526691297); + } + + Assert::isInstanceOf($result, $this->class); + + return $result; + } +} \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectsToIdTransformer.php b/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectsToIdTransformer.php new file mode 100644 index 0000000..bc139a4 --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/ObjectsToIdTransformer.php @@ -0,0 +1,64 @@ + + */ +class ObjectsToIdTransformer extends Transformer { + + public function transform(mixed $value): mixed { + if ($value === null) { + return null; + } + + Assert::allIsInstanceOf($value, $this->class); + + $accessor = PropertyAccess::createPropertyAccessor(); + $property = $this->getProperty(); + + $valueIds = []; + + foreach ($value as $e) { + if (! $accessor->isReadable($e, $property)) { + continue; + } + + $valueIds[] = $accessor->getValue($e, $property); + } + + return implode(',', $valueIds); + } + + public function reverseTransform(mixed $value): mixed { + if ($value === null) { + return []; + } + + $repo = $this->getRepository(); + $property = $this->getProperty(); + $class = $this->getClass(); + + $ids = explode(',', $value); + + $results = $repo->findBy([$property => $ids]); + + if (count($results) === 0) { + throw new TransformationFailedException(sprintf('Can\'t find entity of class "%s" with property "%s" = "%s".', $class, $property, $value), 1701526676576); + } + + Assert::allIsInstanceOf($results, $this->class); + + return $results; + } +} \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/Transformer.php b/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/Transformer.php new file mode 100644 index 0000000..f7c8ef4 --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/Form/DataTransformer/Transformer.php @@ -0,0 +1,63 @@ + + */ +abstract class Transformer implements DataTransformerInterface { + + /** + * + * @param class-string $class + */ + public function __construct(protected readonly ManagerRegistry $registry, protected readonly string $class, protected readonly string $property = 'id') { + if (! class_exists($class)) { + throw new InvalidArgumentException(sprintf('Expected an existing class name. Got: "%s"', $class), 1701527124965); + } + + $this->validate(); + } + + protected function getRepository(): ObjectRepository { + return $this->registry->getRepository($this->getClass()); + } + + /** + * + * @return class-string + */ + protected function getClass(): string { + return $this->class; + } + + protected function getProperty(): string { + return $this->property; + } + + protected function validate(): void { + $reflectionExtractor = new ReflectionExtractor(); + $propertyInfo = new PropertyInfoExtractor([$reflectionExtractor]); + + $properties = $propertyInfo->getProperties($this->class) ?? []; + + if (! in_array($this->property, $properties, true)) { + throw new NoSuchPropertyException(sprintf('property %s is missing in class %s', $this->property, $this->class), 1701527107565); + } + } +} \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenDocumentType.php b/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenDocumentType.php new file mode 100644 index 0000000..866a7a3 --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenDocumentType.php @@ -0,0 +1,22 @@ +setDefaults(['invalid_message' => 'The document does not exist.']); + } + + public function getParent(): string { + return HiddenObjectType::class; + } + + public function getBlockPrefix(): string { + return 'sasedev_hidden_document'; + } +} \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenEntityType.php b/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenEntityType.php new file mode 100644 index 0000000..4276736 --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenEntityType.php @@ -0,0 +1,22 @@ +setDefaults(['invalid_message' => 'The entity does not exist.']); + } + + public function getParent(): string { + return HiddenObjectType::class; + } + + public function getBlockPrefix(): string { + return 'sasedev_hidden_entity'; + } +} \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenObjectType.php b/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenObjectType.php new file mode 100644 index 0000000..512856f --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/Form/Type/HiddenObjectType.php @@ -0,0 +1,60 @@ + $options + */ + public function buildForm(FormBuilderInterface $builder, array $options): void { + $transformerClassName = $options['multiple'] === true ? ObjectsToIdTransformer::class : ObjectToIdTransformer::class; + + /** + * + * @phpstan-var class-string $class + */ + $class = $options['class']; + + $property = $options['property']; + assert(is_string($property)); + + $transformer = new $transformerClassName($this->registry, $class, $property); + + $builder->addModelTransformer($transformer); + } + + public function configureOptions(OptionsResolver $resolver): void { + $resolver->setRequired(['class']); + + $resolver->setDefaults(['multiple' => false,'data_class' => null,'invalid_message' => 'The object does not exist.','property' => 'id']); + + $resolver->setAllowedTypes('invalid_message', ['null','string']); + $resolver->setAllowedTypes('property', ['string']); + $resolver->setAllowedTypes('multiple', ['boolean']); + } + + public function getParent(): string { + return HiddenType::class; + } + + public function getBlockPrefix(): string { + return 'sasedev_hidden_object'; + } +} \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/Resources/config/form.yaml b/src/Sasedev/HiddenEntityTypeBundle/Resources/config/form.yaml new file mode 100644 index 0000000..7c439e6 --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/Resources/config/form.yaml @@ -0,0 +1,7 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + Sasedev\HiddenEntityTypeBundle\Form\Type\HiddenObjectType: ~ \ No newline at end of file diff --git a/src/Sasedev/HiddenEntityTypeBundle/SasedevHiddenEntityTypeBundle.php b/src/Sasedev/HiddenEntityTypeBundle/SasedevHiddenEntityTypeBundle.php new file mode 100644 index 0000000..356f86d --- /dev/null +++ b/src/Sasedev/HiddenEntityTypeBundle/SasedevHiddenEntityTypeBundle.php @@ -0,0 +1,9 @@ +setName('test'); + + // mock any dependencies + $objectRepository = $this->createConfiguredMock(ObjectRepository::class, ['findOneBy' => $object,'findBy' => [$object]]); + + $registry = $this->createConfiguredMock(ManagerRegistry::class, ['getRepository' => $objectRepository]); + + $transformer = new ObjectToIdTransformer($registry, TestObject::class, 'name'); + + $transformed = $transformer->transform($object); + $reversed = $transformer->reverseTransform('test'); + + self::assertEquals('test', $transformed); + self::assertEquals($object, $reversed); + } + + public function testInvalidValidTransformation(): void { + $object = new TestObject(); + $object->setName('test'); + + // mock any dependencies + $objectRepository = $this->createConfiguredMock(ObjectRepository::class, ['findOneBy' => null,'findBy' => [null]]); + + $registry = $this->createConfiguredMock(ManagerRegistry::class, ['getRepository' => $objectRepository]); + + $transformer = new ObjectToIdTransformer($registry, TestObject::class, 'name'); + + $this->expectException(TransformationFailedException::class); + // phpcs:disable Generic.Files.LineLength.TooLong + $this->expectExceptionMessage('Can\'t find entity of class "Sasedev\HiddenEntityTypeBundle\Tests\Model\TestObject" with property "name" = "test".'); + // phpcs:enable Generic.Files.LineLength.TooLong + + $transformed = $transformer->transform($object); + $reversed = $transformer->reverseTransform('test'); + + self::assertEquals('test', $transformed); + self::assertEquals(null, $reversed); + } + + public function testInvalidProperty(): void { + $object = new TestObject(); + $object->setName('test'); + + // mock any dependencies + $objectRepository = $this->createConfiguredMock(ObjectRepository::class, ['findOneBy' => null,'findBy' => [null]]); + + $registry = $this->createConfiguredMock(ManagerRegistry::class, ['getRepository' => $objectRepository]); + + $this->expectException(NoSuchPropertyException::class); + $this->expectExceptionMessage('property id is missing in class Sasedev\HiddenEntityTypeBundle\Tests\Model\TestObject'); + + new ObjectToIdTransformer($registry, TestObject::class, 'id'); + } + + public function testInvalidObject(): void { + $object = new TestFormModel(); + + $registry = $this->createMock(ManagerRegistry::class); + + $transformer = new ObjectToIdTransformer($registry, TestObject::class, 'name'); + + $this->expectException(InvalidArgumentException::class); + // phpcs:disable Generic.Files.LineLength.TooLong + $this->expectExceptionMessage('Expected an instance of Sasedev\HiddenEntityTypeBundle\Tests\Model\TestObject. Got: Sasedev\HiddenEntityTypeBundle\Tests\Model\TestFormModel'); + // phpcs:enable Generic.Files.LineLength.TooLong + + $transformer->transform($object); + } + + public function testInvalidArray(): void { + $object = new TestFormModel(); + + $registry = $this->createMock(ManagerRegistry::class); + + $transformer = new ObjectToIdTransformer($registry, TestObject::class, 'name'); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Expected an instance of Sasedev\HiddenEntityTypeBundle\Tests\Model\TestObject. Got: array'); + + // @phpstan-ignore-next-line + $transformer->transform([$object]); + } + + public function testInvalidClass(): void { + $registry = $this->createMock(ManagerRegistry::class); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Expected an existing class name. Got: "FakeClass"'); + + // @phpstan-ignore-next-line + new ObjectToIdTransformer($registry, 'FakeClass', 'name'); + } +} \ No newline at end of file diff --git a/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/DataTransformer/ObjectsToIdTransformerTest.php b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/DataTransformer/ObjectsToIdTransformerTest.php new file mode 100644 index 0000000..01042d8 --- /dev/null +++ b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/DataTransformer/ObjectsToIdTransformerTest.php @@ -0,0 +1,98 @@ +setName('test'); + + // mock any dependencies + $objectRepository = $this->createConfiguredMock(ObjectRepository::class, ['findBy' => [$object]]); + + $registry = $this->createConfiguredMock(ManagerRegistry::class, ['getRepository' => $objectRepository]); + + $transformer = new ObjectsToIdTransformer($registry, TestObject::class, 'name'); + + $transformed = $transformer->transform([$object]); + $reversed = $transformer->reverseTransform('test'); + + self::assertEquals('test', $transformed); + self::assertEquals([$object], $reversed); + } + + public function testInvalidValidTransformation(): void { + $object = new TestObject(); + $object->setName('test'); + + // mock any dependencies + $objectRepository = $this->createConfiguredMock(ObjectRepository::class, ['findBy' => []]); + + $registry = $this->createConfiguredMock(ManagerRegistry::class, ['getRepository' => $objectRepository]); + + $transformer = new ObjectsToIdTransformer($registry, TestObject::class, 'name'); + + $this->expectException(TransformationFailedException::class); + // phpcs:disable Generic.Files.LineLength.TooLong + $this->expectExceptionMessage('Can\'t find entity of class "Sasedev\HiddenEntityTypeBundle\Tests\Model\TestObject" with property "name" = "test".'); + // phpcs:enable Generic.Files.LineLength.TooLong + + $transformed = $transformer->transform([$object]); + $reversed = $transformer->reverseTransform('test'); + + self::assertEquals('test', $transformed); + self::assertEquals(null, $reversed); + } + + public function testInvalidProperty(): void { + $registry = $this->createMock(ManagerRegistry::class); + + $this->expectException(NoSuchPropertyException::class); + $this->expectExceptionMessage('property id is missing in class Sasedev\HiddenEntityTypeBundle\Tests\Model\TestObject'); + + new ObjectsToIdTransformer($registry, TestObject::class, 'id'); + } + + public function testInvalidObject(): void { + $object = new TestFormModel(); + + $registry = $this->createMock(ManagerRegistry::class); + + $transformer = new ObjectsToIdTransformer($registry, TestObject::class, 'name'); + + $this->expectException(InvalidArgumentException::class); + // phpcs:disable Generic.Files.LineLength.TooLong + $this->expectExceptionMessage('Expected an instance of Sasedev\HiddenEntityTypeBundle\Tests\Model\TestObject. Got: Sasedev\HiddenEntityTypeBundle\Tests\Model\TestFormModel'); + // phpcs:enable Generic.Files.LineLength.TooLong + + $transformer->transform([$object]); + } + + public function testInvalidArray(): void { + $object = new TestFormModel(); + + $registry = $this->createMock(ManagerRegistry::class); + + $transformer = new ObjectsToIdTransformer($registry, TestObject::class, 'name'); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Expected an iterable. Got: Sasedev\HiddenEntityTypeBundle\Tests\Model\TestFormModel'); + + // @phpstan-ignore-next-line + $transformer->transform($object); + } +} \ No newline at end of file diff --git a/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeFailedTest.php b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeFailedTest.php new file mode 100644 index 0000000..3851601 --- /dev/null +++ b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeFailedTest.php @@ -0,0 +1,59 @@ +createConfiguredMock(ObjectRepository::class, ['findOneBy' => null,'findBy' => []]); + + $this->registry = $this->createConfiguredMock(ManagerRegistry::class, ['getRepository' => $objectRepository]); + + parent::setUp(); + } + + /** + * + * @return list + */ + protected function getExtensions(): array { + // create a type instance with the mocked dependencies + $type = new HiddenObjectType($this->registry); + + return [ // register the type instances with the PreloadedExtension + new PreloadedExtension([$type], [])]; + } + + public function testSubmitValidData(): void { + $formData = ['object' => 'test']; + + $data = new TestFormModel(); + + $form = $this->factory->create(TestFormType::class, $data); + $form->submit($formData); + + self::assertTrue($form->isSynchronized()); + self::assertEquals(null, $data->getObject()); + + $view = $form->createView(); + $children = $view->children; + + foreach (array_keys($formData) as $key) { + self::assertArrayHasKey($key, $children); + } + } +} \ No newline at end of file diff --git a/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeTest.php b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeTest.php new file mode 100644 index 0000000..8a5bd60 --- /dev/null +++ b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/HiddenObjectTypeTest.php @@ -0,0 +1,71 @@ +setName('test'); + + // mock any dependencies + $objectRepository = $this->createConfiguredMock(ObjectRepository::class, ['findOneBy' => $object,'findBy' => [$object]]); + + $this->registry = $this->createConfiguredMock(ManagerRegistry::class, ['getRepository' => $objectRepository]); + + $this->testObject = $object; + + parent::setUp(); + } + + /** + * + * @return list + */ + protected function getExtensions(): array { + // create a type instance with the mocked dependencies + $type = new HiddenObjectType($this->registry); + + return [ // register the type instances with the PreloadedExtension + new PreloadedExtension([$type], [])]; + } + + public function testSubmitValidData(): void { + $formData = ['object' => 'test']; + + $data = new TestFormModel(); + + $form = $this->factory->create(TestFormType::class, $data); + $form->submit($formData); + + $testObject = $data->getObject(); + assert($testObject instanceof TestObject); + + self::assertTrue($form->isSynchronized()); + self::assertEquals($this->testObject->getName(), $testObject->getName()); + + $view = $form->createView(); + $children = $view->children; + + foreach (array_keys($formData) as $key) { + self::assertArrayHasKey($key, $children); + } + } +} \ No newline at end of file diff --git a/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/TestFormType.php b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/TestFormType.php new file mode 100644 index 0000000..4747076 --- /dev/null +++ b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Form/Type/TestFormType.php @@ -0,0 +1,26 @@ +add('object', HiddenObjectType::class, ['class' => TestObject::class,'property' => 'name']); + } + + public function configureOptions(OptionsResolver $resolver): void { + $resolver->setDefaults(['data_class' => TestFormModel::class]); + } +} \ No newline at end of file diff --git a/tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestFormModel.php b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestFormModel.php new file mode 100644 index 0000000..d16326b --- /dev/null +++ b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestFormModel.php @@ -0,0 +1,17 @@ +object; + } + + public function setObject(TestObject|null $object): void { + $this->object = $object; + } +} \ No newline at end of file diff --git a/tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestObject.php b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestObject.php new file mode 100644 index 0000000..7d5794d --- /dev/null +++ b/tests/Sasedev/HiddenEntityTypeBundle/Tests/Model/TestObject.php @@ -0,0 +1,17 @@ +name; + } + + public function setName(string|null $name): void { + $this->name = $name; + } +} \ No newline at end of file