diff --git a/.github/workflows/recipe.yaml b/.github/workflows/recipe.yaml
index 4c84937e..a6f10a8f 100644
--- a/.github/workflows/recipe.yaml
+++ b/.github/workflows/recipe.yaml
@@ -18,21 +18,8 @@ jobs:
strategy:
fail-fast: false
matrix:
- php: ['7.4', '8.0', '8.1']
- sylius: ['~1.8.0', '~1.9.0', '~1.10.0', '~1.11.0', '~1.12.0']
- exclude:
- - php: 8.0
- sylius: '~1.8.0'
- - php: 8.0
- sylius: '~1.9.0'
- - php: 8.1
- sylius: '~1.8.0'
- - php: 8.1
- sylius: '~1.9.0'
- - php: 7.4
- sylius: '~1.11.0'
- - php: 7.4
- sylius: '~1.12.0'
+ php: ['8.0', '8.1']
+ sylius: ['~1.10.0', '~1.11.0', '~1.12.0']
steps:
- name: Setup PHP
diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml
index 46e47827..9acdf597 100644
--- a/.github/workflows/security.yaml
+++ b/.github/workflows/security.yaml
@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- php: ['7.4', '8.0', '8.1']
+ php: ['8.0', '8.1']
steps:
- uses: actions/checkout@v3
diff --git a/README.md b/README.md
index 4e10ceda..7abfe74e 100644
--- a/README.md
+++ b/README.md
@@ -217,7 +217,23 @@ You can distinguish the `Row` element and the `Column` element by their dotted b
In this example, we will add a Google Maps element.
-### Define your UiElement
+With the Maker Bundle, you can create a new UiElement very easily:
+
+```bash
+bin/console make:ui-element
+```
+
+Then you will have to answer some questions, or you can add arguments to the command to avoid the questions.
+
+```bash
+bin/console make:ui-element app.google_maps "map pin"
+```
+
+Just add the translations!
+
+### Define your UiElement (for PHP < 8.1)
+
+**Tips:** If you are using PHP 8.1 or newer, you can use the `#[AsUiElement]` attribute to define your UiElement. You can skip this step.
Define your UiElement in your configuration folder, let's say in `config/packages/monsieurbiz_sylius_richeditor_plugin.yaml` as example.
@@ -273,6 +289,48 @@ class GoogleMapsType extends AbstractType
}
```
+For PHP 8.1 and newer, you can use the `#[AsUiElement]` attribute to define your UiElement. For example:
+
+```php
+=1.8 <1.13"
+ "sylius/sylius": ">=1.10 <1.13"
},
"require-dev": {
"behat/behat": "^3.6.1",
@@ -43,7 +43,8 @@
"symfony/dotenv": "^4.4",
"symfony/flex": "^1.7",
"symfony/web-profiler-bundle": "^4.4",
- "phpmd/phpmd": "@stable"
+ "phpmd/phpmd": "@stable",
+ "symfony/maker-bundle": "^1.39"
},
"prefer-stable": true,
"autoload": {
diff --git a/dist/config/packages/monsieurbiz_sylius_rich_editor_plugin_custom.yaml b/dist/config/packages/monsieurbiz_sylius_rich_editor_plugin_custom.yaml
index 3b7f2f4e..0009d7c7 100644
--- a/dist/config/packages/monsieurbiz_sylius_rich_editor_plugin_custom.yaml
+++ b/dist/config/packages/monsieurbiz_sylius_rich_editor_plugin_custom.yaml
@@ -4,17 +4,18 @@ monsieurbiz_sylius_richeditor:
tags: [ html ]
monsieurbiz.youtube:
tags: [ youtube ]
- app.google_maps:
- title: 'app.ui_element.google_maps.title'
- description: 'app.ui_element.google_maps.description'
- icon: map pin
- tags: [ map ]
- classes:
- form: App\Form\Type\UiElement\GoogleMapsType
- ui_element: App\UiElement\GoogleMapsUiElement
- templates:
- admin_render: '/Admin/UiElement/google_maps.html.twig'
- front_render: '/Shop/UiElement/google_maps.html.twig'
+# Example without PHP Attributes or for PHP version < 8.1
+# app.google_maps:
+# title: 'app.ui_element.google_maps.title'
+# description: 'app.ui_element.google_maps.description'
+# icon: map pin
+# tags: [ map ]
+# classes:
+# form: App\Form\Type\UiElement\GoogleMapsType
+# ui_element: App\UiElement\GoogleMapsUiElement
+# templates:
+# admin_render: '/Admin/UiElement/google_maps.html.twig'
+# front_render: '/Shop/UiElement/google_maps.html.twig'
app.noseeme:
title: 'You should not see me'
description: 'The invisible Ui Element'
diff --git a/dist/src/Form/Type/UiElement/GoogleMapsType.php b/dist/src/Form/Type/UiElement/GoogleMapsType.php
index c4f4dacd..09a4553b 100644
--- a/dist/src/Form/Type/UiElement/GoogleMapsType.php
+++ b/dist/src/Form/Type/UiElement/GoogleMapsType.php
@@ -13,11 +13,19 @@
namespace App\Form\Type\UiElement;
+use App\UiElement\GoogleMapsUiElement;
+use MonsieurBiz\SyliusRichEditorPlugin\Attribute\AsUiElement;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;
+#[AsUiElement(
+ code: 'app.google_maps',
+ icon: 'map pin',
+ uiElement: GoogleMapsUiElement::class,
+ tags: ['map'],
+)]
class GoogleMapsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
diff --git a/dist/templates/Admin/UiElement/google_maps.html.twig b/dist/templates/Admin/UiElement/google_maps.html.twig
new file mode 100644
index 00000000..fc27f965
--- /dev/null
+++ b/dist/templates/Admin/UiElement/google_maps.html.twig
@@ -0,0 +1,13 @@
+{#
+UI Element template
+type: google_map
+element fields:
+ link: string
+element methods:
+ getLocale(): string
+#}
+
+
+ {{ ui_element.getLocale() }}
+ {{ element.link|replace({'hl=en': 'hl=' ~ ui_element.getLocale()}) }}
+
diff --git a/dist/templates/Shop/UiElement/google_maps.html.twig b/dist/templates/Shop/UiElement/google_maps.html.twig
new file mode 100644
index 00000000..5b03a243
--- /dev/null
+++ b/dist/templates/Shop/UiElement/google_maps.html.twig
@@ -0,0 +1,12 @@
+{#
+UI Element template
+type: google_map
+element fields:
+ link: string
+element methods:
+ getLocale(): string
+#}
+
+
diff --git a/phpmd.xml b/phpmd.xml
index 0000ac58..d4952b22 100644
--- a/phpmd.xml
+++ b/phpmd.xml
@@ -44,7 +44,7 @@
-
+
diff --git a/phpstan.neon b/phpstan.neon
index 226c59b5..dc6ef67f 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -19,5 +19,8 @@ parameters:
- 'tests/Application/app/**.php'
- 'tests/Application/src/**.php'
+ # Skeleton files
+ - 'src/Resources/skeleton/*.php'
+
ignoreErrors:
- '/Parameter #1 \$configuration of method Symfony\\Component\\DependencyInjection\\Extension\\Extension::processConfiguration\(\) expects Symfony\\Component\\Config\\Definition\\ConfigurationInterface, Symfony\\Component\\Config\\Definition\\ConfigurationInterface\|null given\./'
diff --git a/src/Attribute/AsUiElement.php b/src/Attribute/AsUiElement.php
new file mode 100644
index 00000000..c0439fad
--- /dev/null
+++ b/src/Attribute/AsUiElement.php
@@ -0,0 +1,96 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace MonsieurBiz\SyliusRichEditorPlugin\Attribute;
+
+use Attribute;
+use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElement;
+
+#[Attribute(Attribute::TARGET_CLASS)]
+class AsUiElement
+{
+ /**
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+ * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
+ */
+ public function __construct(
+ public string $code,
+ public string $icon,
+ public ?string $title = null,
+ public ?string $description = null,
+ public string $uiElement = UiElement::class,
+ public ?TemplatesUiElement $templates = null,
+ public string $alias = '',
+ public string $wireframe = '',
+ public bool $enabled = true,
+ public array $tags = [],
+ ) {
+ }
+
+ public function getCode(): string
+ {
+ return $this->code;
+ }
+
+ public function getConfiguration(): array
+ {
+ $configuration = [
+ 'title' => $this->getTitle(),
+ 'description' => $this->getDescription(),
+ 'icon' => $this->icon,
+ 'wireframe' => $this->wireframe,
+ 'enabled' => $this->enabled,
+ 'tags' => $this->tags,
+ 'classes' => [
+ 'ui_element' => $this->uiElement,
+ ],
+ 'templates' => [
+ 'admin_render' => $this->getTemplates()->adminRender,
+ 'front_render' => $this->getTemplates()->frontRender,
+ 'admin_form' => $this->getTemplates()->adminForm,
+ ],
+ 'form_options' => [],
+ ];
+
+ if ($this->alias) {
+ $configuration['alias'] = $this->alias;
+ }
+
+ return $configuration;
+ }
+
+ private function getTitle(): string
+ {
+ return $this->title ?? 'app.ui_element.' . $this->getLastPartOfCode() . '.title';
+ }
+
+ private function getDescription(): string
+ {
+ return $this->description ?? 'app.ui_element.' . $this->getLastPartOfCode() . '.description';
+ }
+
+ private function getTemplates(): TemplatesUiElement
+ {
+ return $this->templates ?? new TemplatesUiElement(
+ adminRender: 'Admin/UiElement/' . $this->getLastPartOfCode() . '.html.twig',
+ frontRender: 'Shop/UiElement/' . $this->getLastPartOfCode() . '.html.twig',
+ );
+ }
+
+ private function getLastPartOfCode(): string
+ {
+ $parts = explode('.', $this->code);
+
+ return end($parts);
+ }
+}
diff --git a/src/Attribute/TemplatesUiElement.php b/src/Attribute/TemplatesUiElement.php
new file mode 100644
index 00000000..dda45ac9
--- /dev/null
+++ b/src/Attribute/TemplatesUiElement.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace MonsieurBiz\SyliusRichEditorPlugin\Attribute;
+
+use Attribute;
+
+#[Attribute(Attribute::TARGET_PROPERTY)]
+final class TemplatesUiElement
+{
+ public function __construct(
+ public string $adminRender,
+ public string $frontRender,
+ public string $adminForm = '@MonsieurBizSyliusRichEditorPlugin/Admin/form.html.twig',
+ ) {
+ }
+}
diff --git a/src/DependencyInjection/UiElementRegistryPass.php b/src/DependencyInjection/UiElementRegistryPass.php
index 3c68a698..86614107 100644
--- a/src/DependencyInjection/UiElementRegistryPass.php
+++ b/src/DependencyInjection/UiElementRegistryPass.php
@@ -13,9 +13,11 @@
namespace MonsieurBiz\SyliusRichEditorPlugin\DependencyInjection;
+use MonsieurBiz\SyliusRichEditorPlugin\Attribute\AsUiElement;
use MonsieurBiz\SyliusRichEditorPlugin\UiElement\Metadata;
use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElement;
use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElementInterface;
+use ReflectionClass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
@@ -38,35 +40,79 @@ public function process(ContainerBuilder $container): void
return;
}
+ $this->processConfiguration($uiElements, $container, $registry, $metadataRegistry);
+ $this->processAttribute($container, $registry, $metadataRegistry);
+ }
+
+ private function processConfiguration(mixed $uiElements, ContainerBuilder $container, Definition $registry, Definition $metadataRegistry): void
+ {
if (!\is_array($uiElements)) {
return;
}
foreach ($uiElements as $code => $configuration) {
- $metadataRegistry->addMethodCall('addFromCodeAndConfiguration', [$code, $configuration]);
- $metadata = Metadata::fromCodeAndConfiguration($code, $configuration);
+ if (!\is_array($configuration)) {
+ continue;
+ }
+ $this->registerUiElement($code, $configuration, $container, $registry, $metadataRegistry);
+ }
+ }
- $id = $metadata->getServiceId('richeditor.ui_element');
+ private function processAttribute(ContainerBuilder $container, Definition $registry, Definition $metadataRegistry): void
+ {
+ foreach ($container->getDefinitions() as $definition) {
+ if ($this->accept($definition) && $reflectionClass = $container->getReflectionClass($definition->getClass(), false)) {
+ $this->processClass($definition, $reflectionClass, $container, $registry, $metadataRegistry);
+ }
+ }
+ }
- $class = $metadata->getClass('ui_element');
- $this->validateUiElementResource($class);
+ /**
+ * @param ReflectionClass