Skip to content

Commit

Permalink
Init Twig Extra component
Browse files Browse the repository at this point in the history
  • Loading branch information
loic425 committed Jun 20, 2024
1 parent 9240ed3 commit 040790d
Show file tree
Hide file tree
Showing 18 changed files with 708 additions and 2 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
},
"autoload": {
"psr-4": {
"Sylius\\TwigExtra\\": "src/TwigExtra/src/",
"Sylius\\TwigHooks\\": "src/TwigHooks/src/"
}
},
Expand Down
1 change: 1 addition & 0 deletions config/bundles.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
Sylius\TwigHooks\TwigHooksBundle::class => ['all' => true],
Sylius\TwigExtra\Symfony\TwigExtraBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\UX\LiveComponent\LiveComponentBundle::class => ['all' => true],
Expand Down
92 changes: 92 additions & 0 deletions docs/twig-extra/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
description: >-
Twig Extra is a set of Twig extensions to bring more Twig helpers.
---

# Getting started

## Installation

Install the package using Composer and Symfony Flex:

```bash
composer require sylius/twig-extra
```

## Features

### Sort by

This sort by extension allows to sort an array of objects by a specific property.

```php
class Book {
public function __construct() {
public string $name,
}
}

$books = [new Book('Shinning'), new Book('A Lord Of The Rings')];
```

```twig
<ul>
{% for book in books|sort_by('name') %}
<li>{{ book.name }}</li>
{% endif %}
</ul>
```

```text
. A Lord Of The Rings
. Shinning
```

You can also sort array of arrays.

```php

$books = [['name' => 'Shinning'], ['name' => 'A Lord Of The Rings']];
```

You just need to encapsulate the key with `[]`.

```twig
<ul>
{% for book in books|sort_by('[name]') %}
<li>{{ book.name }}</li>
{% endif %}
</ul>
```

### Test HTML attribute

This Twig extension allows you to add some data attributes in test environment
This allows to identify your data easily in E2E tests without being too much dependant of your HTML changes.

```twig
<h1 {{ sylius_test_html_attribute('title')>Shinning</h1>
```

```html
<h1 data-test-title>Shinning</h1>
```

### Test Form HTML attribute

This is slightly the same behaviour as `sylius_test_html_attribute` Twig function.

```twig
{{ form_row(form.title, sylius_test_form_attribute('title')) }}
```

```html
<!-- The real results depend on your form theme. -->
<label for="book_title">Title</label>
<input
type="text"
id="book_title"
name="title"
data-test-title <!-- This is the added data attribute -->
/>
```
5 changes: 4 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
</php>

<testsuites>
<testsuite name="TwigExtra Test Suite">
<directory>src/TwigExtra/tests</directory>
</testsuite>

<testsuite name="TwigHooks Test Suite">
<directory>src/TwigHooks/tests</directory>

</testsuite>
</testsuites>

Expand Down
33 changes: 33 additions & 0 deletions src/TwigExtra/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "sylius/twig-extra",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Sylius project",
"homepage": "https://sylius.com"
},
{
"name": "Community contributions",
"homepage": "https://github.com/Sylius/Stack/contributors"
}
],
"require": {
"php": "^8.1",
"symfony/http-kernel": "^5.4 || ^6.0",
"symfony/twig-bundle": "^5.4 || ^6.0"
},
"conflict": {
"sylius/ui-bundle": "<2.0"
},
"autoload": {
"psr-4": {
"Sylius\\TwigExtra\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\Sylius\\TwigExtra\\": "tests/"
}
}
}
33 changes: 33 additions & 0 deletions src/TwigExtra/config/services.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Sylius\TwigExtra\Twig\SortByExtension;
use Sylius\TwigExtra\Twig\TestFormAttributeExtension;
use Sylius\TwigExtra\Twig\TestHtmlAttributeExtension;

return function (ContainerConfigurator $configurator): void {
$services = $configurator->services();

$services->set('twig_extra.twig.extension.test_form_attribute', TestFormAttributeExtension::class)
->args([
param('kernel.environment'),
param('kernel.debug'),
])
->tag(name: 'twig.extension')
;

$services->set('twig_extra.twig.extension.test_html_attribute', TestHtmlAttributeExtension::class)
->args([
param('kernel.environment'),
param('kernel.debug'),
])
->tag(name: 'twig.extension')
;

$services->set('twig_extra.twig.extension.sort_by', SortByExtension::class)
->tag(name: 'twig.extension')
;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Sylius\TwigExtra\Symfony\DependencyInjection;

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

final class TwigExtraExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new PhpFileLoader(
$container,
new FileLocator(dirname(__DIR__, 3) . '/config'),
);

$loader->load('services.php');
}
}
11 changes: 11 additions & 0 deletions src/TwigExtra/src/Symfony/TwigExtraBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Sylius\TwigExtra\Symfony;

use Symfony\Component\HttpKernel\Bundle\Bundle;

final class TwigExtraBundle extends Bundle
{
}
56 changes: 56 additions & 0 deletions src/TwigExtra/src/Twig/SortByExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace Sylius\TwigExtra\Twig;

use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class SortByExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('sort_by', [$this, 'sortBy']),
];
}

/**
* @throws NoSuchPropertyException
*/
public function sortBy(iterable $iterable, string $field, string $order = 'ASC'): array
{
$array = $this->transformIterableToArray($iterable);

usort(
$array,
function (array|object $firstElement, array|object $secondElement) use ($field, $order) {
$accessor = PropertyAccess::createPropertyAccessor();

$firstProperty = (string) $accessor->getValue($firstElement, $field);
$secondProperty = (string) $accessor->getValue($secondElement, $field);

$result = strnatcasecmp($firstProperty, $secondProperty);
if ('DESC' === $order) {
$result *= -1;
}

return $result;
},
);

return $array;
}

private function transformIterableToArray(iterable $iterable): array
{
if (is_array($iterable)) {
return $iterable;
}

return iterator_to_array($iterable);
}
}
35 changes: 35 additions & 0 deletions src/TwigExtra/src/Twig/TestFormAttributeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Sylius\TwigExtra\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class TestFormAttributeExtension extends AbstractExtension
{
public function __construct(private string $environment)
{
}

/**
* @return TwigFunction[]
*/
public function getFunctions(): array
{
return [
new TwigFunction(
'sylius_test_form_attribute',
function (string $name, ?string $value = null): array {
if (str_starts_with($this->environment, 'test')) {
return ['attr' => ['data-test-' . $name => (string) $value]];
}

return [];
},
['is_safe' => ['html']],
),
];
}
}
35 changes: 35 additions & 0 deletions src/TwigExtra/src/Twig/TestHtmlAttributeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Sylius\TwigExtra\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class TestHtmlAttributeExtension extends AbstractExtension
{
public function __construct(private readonly string $environment, private readonly bool $isDebugEnabled)
{
}

/**
* @return TwigFunction[]
*/
public function getFunctions(): array
{
return [
new TwigFunction(
'sylius_test_html_attribute',
function (string $name, ?string $value = null): string {
if (str_starts_with($this->environment, 'test') || $this->isDebugEnabled) {
return sprintf('data-test-%s="%s"', $name, (string) $value);
}

return '';
},
['is_safe' => ['html']],
),
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Tests\Sylius\TwigExtra\Functional\Twig\Extension;

use Sylius\TwigExtra\Twig\SortByExtension;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

final class SortByExtensionTest extends KernelTestCase
{
public function testTheContainerContainsTheService(): void
{
$this->bootKernel();

$container = $this->getContainer();

$this->assertTrue($container->has('twig_extra.twig.extension.sort_by'));
$this->assertInstanceOf(SortByExtension::class, $container->get('twig_extra.twig.extension.sort_by'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Tests\Sylius\TwigExtra\Functional\Twig\Extension;

use Sylius\TwigExtra\Twig\TestFormAttributeExtension;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

final class TestFormAttributeExtensionTest extends KernelTestCase
{
public function testTheContainerContainsTheService(): void
{
$this->bootKernel();

$container = $this->getContainer();

$this->assertTrue($container->has('twig_extra.twig.extension.test_form_attribute'));
$this->assertInstanceOf(TestFormAttributeExtension::class, $container->get('twig_extra.twig.extension.test_form_attribute'));
}
}
Loading

0 comments on commit 040790d

Please sign in to comment.