From c52bbd4e944a78580904cdb22bb924c7d9b450af Mon Sep 17 00:00:00 2001 From: tienvx Date: Sun, 10 Oct 2021 22:10:16 +0700 Subject: [PATCH 1/3] Fix unknown filter --- composer.json | 7 ++- .../CollectionJsExtension.php | 30 ++++++++++ src/Form/CollectionJsType.php | 9 --- src/Resources/config/services.php | 3 + .../views/bootstrap_5_layout.html.twig | 6 +- src/Twig/CollectionJsTwigExtension.php | 34 ++++++++++++ tests/CollectionJsBundleTest.php | 13 +++++ tests/Kernel/TwigAppKernel.php | 39 +++++++++++++ tests/Kernel/templates/form_theme.html.twig | 1 + tests/Twig/CollectionJsTwigExtensionTest.php | 55 +++++++++++++++++++ 10 files changed, 181 insertions(+), 16 deletions(-) create mode 100644 src/DependencyInjection/CollectionJsExtension.php create mode 100644 src/Twig/CollectionJsTwigExtension.php create mode 100644 tests/Kernel/TwigAppKernel.php create mode 100644 tests/Kernel/templates/form_theme.html.twig create mode 100644 tests/Twig/CollectionJsTwigExtensionTest.php diff --git a/composer.json b/composer.json index 88fb11f..a9b3771 100644 --- a/composer.json +++ b/composer.json @@ -30,13 +30,16 @@ }, "require": { "php": "^7.4|^8.0", + "symfony/config": "^4.4|^5.0", "symfony/dependency-injection": "^4.4.17|^5.0", "symfony/form": "^4.4.17|^5.0", - "symfony/http-kernel": "^4.4.17|^5.0" + "symfony/http-kernel": "^4.4.17|^5.0", + "twig/twig": "^2.12|^3.0" }, "require-dev": { "phpunit/phpunit": "^9.5", - "symfony/framework-bundle": "^4.4.17|^5.0" + "symfony/framework-bundle": "^4.4.17|^5.0", + "symfony/twig-bundle": "^4.4.17|^5.0" }, "conflict": { "symfony/flex": "<1.13" diff --git a/src/DependencyInjection/CollectionJsExtension.php b/src/DependencyInjection/CollectionJsExtension.php new file mode 100644 index 0000000..5edab72 --- /dev/null +++ b/src/DependencyInjection/CollectionJsExtension.php @@ -0,0 +1,30 @@ +getParameter('kernel.bundles'); + + if (!isset($bundles['TwigBundle'])) { + return; + } + + $container->prependExtensionConfig('twig', ['form_themes' => ['@CollectionJs/bootstrap_5_layout.html.twig']]); + } + + public function load(array $configs, ContainerBuilder $container) + { + $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('services.php'); + } +} diff --git a/src/Form/CollectionJsType.php b/src/Form/CollectionJsType.php index c3ae97a..558e315 100644 --- a/src/Form/CollectionJsType.php +++ b/src/Form/CollectionJsType.php @@ -1,14 +1,5 @@ - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - namespace Tienvx\UX\CollectionJs\Form; use Symfony\Component\Form\AbstractType; diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php index 9b33324..b64bfc9 100644 --- a/src/Resources/config/services.php +++ b/src/Resources/config/services.php @@ -3,10 +3,13 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Tienvx\UX\CollectionJs\Form\CollectionJsType; +use Tienvx\UX\CollectionJs\Twig\CollectionJsTwigExtension; return static function (ContainerConfigurator $container): void { $container->services() ->set(CollectionJsType::class) ->tag('form.type') + ->set(CollectionJsTwigExtension::class) + ->tag('twig.extension') ; }; diff --git a/src/Resources/views/bootstrap_5_layout.html.twig b/src/Resources/views/bootstrap_5_layout.html.twig index b8fcc24..57d67e8 100644 --- a/src/Resources/views/bootstrap_5_layout.html.twig +++ b/src/Resources/views/bootstrap_5_layout.html.twig @@ -38,11 +38,7 @@

{% apply spaceless %} diff --git a/src/Twig/CollectionJsTwigExtension.php b/src/Twig/CollectionJsTwigExtension.php new file mode 100644 index 0000000..edf1274 --- /dev/null +++ b/src/Twig/CollectionJsTwigExtension.php @@ -0,0 +1,34 @@ + true]), + ]; + } + + public function representAsString(Environment $environment, $value): string + { + if ($filter = $environment->getFilter('ea_as_string')) { + return $filter->getCallable()($value); + } + + if (\is_string($value)) { + return $value; + } + + if (\is_object($value) && method_exists($value, '__toString')) { + return (string) $value; + } + + return ''; + } +} diff --git a/tests/CollectionJsBundleTest.php b/tests/CollectionJsBundleTest.php index a2a1435..91b1fd5 100644 --- a/tests/CollectionJsBundleTest.php +++ b/tests/CollectionJsBundleTest.php @@ -6,6 +6,7 @@ use Symfony\Component\HttpKernel\Kernel; use Tienvx\UX\CollectionJs\Tests\Kernel\EmptyAppKernel; use Tienvx\UX\CollectionJs\Tests\Kernel\FrameworkAppKernel; +use Tienvx\UX\CollectionJs\Tests\Kernel\TwigAppKernel; class CollectionJsBundleTest extends TestCase { @@ -13,6 +14,7 @@ public function provideKernels() { yield 'empty' => [new EmptyAppKernel('test', true)]; yield 'framework' => [new FrameworkAppKernel('test', true)]; + yield 'twig' => [new TwigAppKernel('test', true)]; } /** @@ -23,4 +25,15 @@ public function testBootKernel(Kernel $kernel) $kernel->boot(); $this->assertArrayHasKey('CollectionJsBundle', $kernel->getBundles()); } + + public function testFormThemeMerging() + { + $kernel = new TwigAppKernel('test', true); + $kernel->boot(); + $this->assertEquals([ + 'form_div_layout.html.twig', + '@CollectionJs/bootstrap_5_layout.html.twig', + 'form_theme.html.twig', + ], $kernel->getContainer()->getParameter('twig.form.resources')); + } } diff --git a/tests/Kernel/TwigAppKernel.php b/tests/Kernel/TwigAppKernel.php new file mode 100644 index 0000000..62db606 --- /dev/null +++ b/tests/Kernel/TwigAppKernel.php @@ -0,0 +1,39 @@ +load(function (ContainerBuilder $container) { + $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true]); + $container->loadFromExtension('twig', [ + 'default_path' => __DIR__ . '/templates', + 'strict_variables' => true, + 'form_themes' => [ + 'form_theme.html.twig', + ], + 'exception_controller' => null, + 'debug' => '%kernel.debug%', + ]); + + $container->setAlias('test.collection_js.twig_extension', CollectionJsTwigExtension::class)->setPublic(true); + }); + } +} diff --git a/tests/Kernel/templates/form_theme.html.twig b/tests/Kernel/templates/form_theme.html.twig new file mode 100644 index 0000000..e4ede06 --- /dev/null +++ b/tests/Kernel/templates/form_theme.html.twig @@ -0,0 +1 @@ +{# dummy file #} diff --git a/tests/Twig/CollectionJsTwigExtensionTest.php b/tests/Twig/CollectionJsTwigExtensionTest.php new file mode 100644 index 0000000..208b012 --- /dev/null +++ b/tests/Twig/CollectionJsTwigExtensionTest.php @@ -0,0 +1,55 @@ +boot(); + $container = $kernel->getContainer()->get('test.service_container'); + + $rendered = $container->get('test.collection_js.twig_extension')->representAsString( + $container->get(Environment::class), + $value + ); + + $this->assertSame($expected, $rendered); + } + + public function valueDataProvider(): array + { + $text = 'some text'; + $object = new class($text) { + private string $text; + + public function __construct(string $text) + { + $this->text = $text; + } + + public function __toString(): string + { + return $this->text; + } + }; + + return [ + [$text, $text], + [$object, $text], + [123, ''], + [[$text], ''], + [true, ''], + [false, ''], + [new \stdClass(), ''], + ]; + } +} From d8eb0a5f4a5d0eaf36039567e94b365061459c93 Mon Sep 17 00:00:00 2001 From: tienvx Date: Sun, 10 Oct 2021 22:11:04 +0700 Subject: [PATCH 2/3] Update usage for Symfony in readme --- README.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a0abb01..5f987e2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ UX Collection JS requires PHP 7.4+ and Symfony 4.4+. Install this bundle using Composer and Symfony Flex: ```sh -composer require tienvx/ux-collection-js +composer require tienvx/ux-collection-js:^1.0@alpha # Don't forget to install the JavaScript dependencies as well and compile yarn add --dev '@symfony/stimulus-bridge@^2.0.0' @@ -19,26 +19,27 @@ yarn encore dev ## Usage +### Symfony + Use the new CollectionType class defined by this bundle: ```php // ... use Tienvx\UX\CollectionJs\Form\CollectionJsType; -class TaskType extends AbstractType +class PostType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder // ... - ->add('tags', CollectionJsType::class, [ - 'entry_type' => TextType::class, + ->add('attachments', CollectionJsType::class, [ + 'entry_type' => FileType::class, 'allow_add' => true, - 'allow_remove' => true, + 'allow_delete' => true, 'allow_move_up' => true, 'allow_move_down' => true, 'call_post_add_on_init' => true, - 'prototype' => true, ]) // ... ; @@ -48,13 +49,9 @@ class TaskType extends AbstractType } ``` -Then you need to set the form theme: -```yaml -# config/packages/twig.yaml -twig: - # For bootstrap for example - form_themes: ['@CollectionJs/bootstrap_5_layout.html.twig'] -``` +### Easyadmin + +TBD ## Contributing Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. From 554c8c9f6d61b3487f58e3ad62b3f12bc61bc6f0 Mon Sep 17 00:00:00 2001 From: tienvx Date: Sun, 10 Oct 2021 23:31:54 +0700 Subject: [PATCH 3/3] Test with and without easyadmin filter --- tests/Twig/CollectionJsTwigExtensionTest.php | 30 ++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/tests/Twig/CollectionJsTwigExtensionTest.php b/tests/Twig/CollectionJsTwigExtensionTest.php index 208b012..e01e18e 100644 --- a/tests/Twig/CollectionJsTwigExtensionTest.php +++ b/tests/Twig/CollectionJsTwigExtensionTest.php @@ -5,18 +5,23 @@ use PHPUnit\Framework\TestCase; use Tienvx\UX\CollectionJs\Tests\Kernel\TwigAppKernel; use Twig\Environment; +use Twig\TwigFilter; class CollectionJsTwigExtensionTest extends TestCase { /** * @dataProvider valueDataProvider */ - public function testRepresentAsString($value, string $expected) + public function testRepresentAsString(?TwigFilter $filter, $value, string $expected) { $kernel = new TwigAppKernel('test', true); $kernel->boot(); $container = $kernel->getContainer()->get('test.service_container'); + if ($filter) { + $container->get(Environment::class)->addFilter($filter); + } + $rendered = $container->get('test.collection_js.twig_extension')->representAsString( $container->get(Environment::class), $value @@ -28,6 +33,7 @@ public function testRepresentAsString($value, string $expected) public function valueDataProvider(): array { $text = 'some text'; + $textFromFilter = 'some text from filter'; $object = new class($text) { private string $text; @@ -41,15 +47,23 @@ public function __toString(): string return $this->text; } }; + $filter = new TwigFilter('ea_as_string', fn () => $textFromFilter); return [ - [$text, $text], - [$object, $text], - [123, ''], - [[$text], ''], - [true, ''], - [false, ''], - [new \stdClass(), ''], + [$filter, $text, $textFromFilter], + [$filter, $object, $textFromFilter], + [$filter, 123, $textFromFilter], + [$filter, [$text], $textFromFilter], + [$filter, true, $textFromFilter], + [$filter, false, $textFromFilter], + [$filter, new \stdClass(), $textFromFilter], + [null, $text, $text], + [null, $object, $text], + [null, 123, ''], + [null, [$text], ''], + [null, true, ''], + [null, false, ''], + [null, new \stdClass(), ''], ]; } }