Skip to content

Commit

Permalink
Merge d8eb0a5 into a298c76
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed Oct 10, 2021
2 parents a298c76 + d8eb0a5 commit caebe0c
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 29 deletions.
23 changes: 10 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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,
])
// ...
;
Expand All @@ -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.
Expand Down
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
30 changes: 30 additions & 0 deletions src/DependencyInjection/CollectionJsExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Tienvx\UX\CollectionJs\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

class CollectionJsExtension extends Extension implements PrependExtensionInterface
{
public function prepend(ContainerBuilder $container)
{
// Register the Collection Js form theme if TwigBundle is available
$bundles = $container->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');
}
}
9 changes: 0 additions & 9 deletions src/Form/CollectionJsType.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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;
Expand Down
3 changes: 3 additions & 0 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -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')
;
};
6 changes: 1 addition & 5 deletions src/Resources/views/bootstrap_5_layout.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@
<h2 class="accordion-header">
<button class="accordion-button {{ form.vars.valid ? 'collapsed' }}" type="button" data-bs-toggle="collapse" data-bs-target="#{{ id }}-contents">
<i class="fas fw fa-chevron-right form-collection-item-collapse-marker"></i>
{% if ea is defined %}
{{ value|ea_as_string }}
{% else %}
{{ value }}
{% endif %}
{{ value|collection_js_as_string }}
</button>
<div class="btn-group collection-js-actions" role="group" aria-label="Actions">
{% apply spaceless %}
Expand Down
34 changes: 34 additions & 0 deletions src/Twig/CollectionJsTwigExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Tienvx\UX\CollectionJs\Twig;

use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class CollectionJsTwigExtension extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('collection_js_as_string', [$this, 'representAsString'], ['needs_environment' => 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 '';
}
}
13 changes: 13 additions & 0 deletions tests/CollectionJsBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
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
{
public function provideKernels()
{
yield 'empty' => [new EmptyAppKernel('test', true)];
yield 'framework' => [new FrameworkAppKernel('test', true)];
yield 'twig' => [new TwigAppKernel('test', true)];
}

/**
Expand All @@ -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'));
}
}
39 changes: 39 additions & 0 deletions tests/Kernel/TwigAppKernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Tienvx\UX\CollectionJs\Tests\Kernel;

use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Tienvx\UX\CollectionJs\CollectionJsBundle;
use Tienvx\UX\CollectionJs\Twig\CollectionJsTwigExtension;

class TwigAppKernel extends Kernel
{
use AppKernelTrait;

public function registerBundles()
{
return [new FrameworkBundle(), new TwigBundle(), new CollectionJsBundle()];
}

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->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);
});
}
}
1 change: 1 addition & 0 deletions tests/Kernel/templates/form_theme.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{# dummy file #}
55 changes: 55 additions & 0 deletions tests/Twig/CollectionJsTwigExtensionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Tienvx\UX\CollectionJs\Tests\Twig;

use PHPUnit\Framework\TestCase;
use Tienvx\UX\CollectionJs\Tests\Kernel\TwigAppKernel;
use Twig\Environment;

class CollectionJsTwigExtensionTest extends TestCase
{
/**
* @dataProvider valueDataProvider
*/
public function testRepresentAsString($value, string $expected)
{
$kernel = new TwigAppKernel('test', true);
$kernel->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(), ''],
];
}
}

0 comments on commit caebe0c

Please sign in to comment.