From de305fdb50b83b8168f77a40162e6dd44b38a036 Mon Sep 17 00:00:00 2001 From: Etienne Gutbub Date: Wed, 16 Oct 2024 14:14:45 +0200 Subject: [PATCH 1/5] feat(ArticlesSelections): Add uiElement to display a selected list of articles --- src/Form/Type/ArticleSelectionElementType.php | 73 +++++++++++ src/Form/Type/ArticlesDisplayType.php | 43 +++++++ .../ArticlesSelectionUiElementType.php | 93 ++++++++++++++ .../UiElement/CaseStudiesUiElementType.php | 4 +- src/Resources/translations/messages.en.yaml | 19 ++- src/Resources/translations/messages.fr.yaml | 19 ++- .../UiElement/articles_selection.html.twig | 110 +++++++++++++++++ .../UiElement/articles_selection.html.twig | 113 ++++++++++++++++++ .../Wireframe/articles-selection.svg.twig | 3 + src/UiElement/ArticlesSelectionUiElement.php | 72 +++++++++++ 10 files changed, 545 insertions(+), 4 deletions(-) create mode 100644 src/Form/Type/ArticleSelectionElementType.php create mode 100644 src/Form/Type/ArticlesDisplayType.php create mode 100644 src/Form/Type/UiElement/ArticlesSelectionUiElementType.php create mode 100644 src/Resources/views/Admin/UiElement/articles_selection.html.twig create mode 100644 src/Resources/views/Shop/UiElement/articles_selection.html.twig create mode 100644 src/Resources/views/Wireframe/articles-selection.svg.twig create mode 100644 src/UiElement/ArticlesSelectionUiElement.php diff --git a/src/Form/Type/ArticleSelectionElementType.php b/src/Form/Type/ArticleSelectionElementType.php new file mode 100644 index 0000000..cd3c37a --- /dev/null +++ b/src/Form/Type/ArticleSelectionElementType.php @@ -0,0 +1,73 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace MonsieurBiz\SyliusBlogPlugin\Form\Type; + +use MonsieurBiz\SyliusBlogPlugin\Entity\Article; +use MonsieurBiz\SyliusBlogPlugin\Entity\ArticleInterface; +use MonsieurBiz\SyliusBlogPlugin\Repository\ArticleRepositoryInterface; +use Sylius\Bundle\ResourceBundle\Form\DataTransformer\ResourceToIdentifierTransformer; +use Sylius\Component\Channel\Context\ChannelContextInterface; +use Sylius\Component\Locale\Context\LocaleContextInterface; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\ReversedTransformer; +use Symfony\Component\Validator\Constraints as Assert; + +final class ArticleSelectionElementType extends AbstractType +{ + public function __construct( + private readonly ArticleRepositoryInterface $articleRepository, + private readonly ChannelContextInterface $channelContext, + private readonly LocaleContextInterface $localeContext, + ) { + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $articles = $this->articleRepository->createShopListQueryBuilderByType( + $this->localeContext->getLocaleCode(), + ArticleInterface::BLOG_TYPE, + $this->channelContext->getChannel(), + null + ); + + $articles = $articles->orderBy('translation.title')->getQuery()->getResult(); + + $builder + ->add('article', EntityType::class, [ + 'class' => Article::class, + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.article', + 'choice_label' => fn (Article $article) => $article->getTitle(), + 'choice_value' => fn (?Article $article) => $article?->getId(), + 'required' => true, + 'choices' => $articles, + ]) + ->add('position', IntegerType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.position', + 'required' => true, + 'constraints' => [ + new Assert\NotBlank(), + new Assert\GreaterThan(0), + ], + ]) + ; + + $builder->get('article')->addModelTransformer( + new ReversedTransformer(new ResourceToIdentifierTransformer($this->articleRepository, 'id')), + ); + } +} diff --git a/src/Form/Type/ArticlesDisplayType.php b/src/Form/Type/ArticlesDisplayType.php new file mode 100644 index 0000000..abfd012 --- /dev/null +++ b/src/Form/Type/ArticlesDisplayType.php @@ -0,0 +1,43 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace MonsieurBiz\SyliusBlogPlugin\Form\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; + +final class ArticlesDisplayType extends AbstractType +{ + public const MULTIPLE_WITH_IMAGE = 'multiple_with_image'; + + public const MULTIPLE_WITHOUT_IMAGE = 'multiple_without_image'; + + public const SINGLE = 'single'; + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameters) + */ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('display', ChoiceType::class, [ + 'label' => 'monsieurbiz_blog.articles.display.label', + 'required' => true, + 'choices' => [ + 'monsieurbiz_blog.articles.display.choices.multiple_with_image' => self::MULTIPLE_WITH_IMAGE, + 'monsieurbiz_blog.articles.display.choices.multiple_without_image' => self::MULTIPLE_WITHOUT_IMAGE, + 'monsieurbiz_blog.articles.display.choices.single' => self::SINGLE, + ], + ]) + ; + } +} diff --git a/src/Form/Type/UiElement/ArticlesSelectionUiElementType.php b/src/Form/Type/UiElement/ArticlesSelectionUiElementType.php new file mode 100644 index 0000000..efeb0d9 --- /dev/null +++ b/src/Form/Type/UiElement/ArticlesSelectionUiElementType.php @@ -0,0 +1,93 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace MonsieurBiz\SyliusBlogPlugin\Form\Type\UiElement; + +use MonsieurBiz\SyliusBlogPlugin\Form\Type\ArticlesDisplayType; +use MonsieurBiz\SyliusBlogPlugin\Form\Type\ArticleSelectionElementType; +use MonsieurBiz\SyliusRichEditorPlugin\Attribute\AsUiElement; +use MonsieurBiz\SyliusRichEditorPlugin\Attribute\TemplatesUiElement; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\Validator\Constraints as Assert; + +#[AsUiElement( + code: 'monsieurbiz_blog.articles_selection_ui_element', + icon: 'newspaper', + title: 'monsieurbiz_blog.ui_element.articles_selection_ui_element.title', + description: 'monsieurbiz_blog.ui_element.articles_selection_ui_element.description', + uiElement: 'MonsieurBiz\SyliusBlogPlugin\UiElement\ArticlesSelectionUiElement', + templates: new TemplatesUiElement( + adminRender: '@MonsieurBizSyliusBlogPlugin/Admin/UiElement/articles_selection.html.twig', + frontRender: '@MonsieurBizSyliusBlogPlugin/Shop/UiElement/articles_selection.html.twig', + ), + wireframe: 'articles-selection', + tags: [], +)] +class ArticlesSelectionUiElementType extends AbstractType +{ + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('title', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.title', + 'required' => false, + ]) + ->add('display', ArticlesDisplayType::class, [ + 'label' => false, // already defined in the ArticlesDisplayType + ]) + ->add('articles', CollectionType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.articles', + 'entry_type' => ArticleSelectionElementType::class, + 'prototype_name' => '__article_selection__', + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + 'delete_empty' => true, + 'attr' => [ + 'class' => 'ui segment secondary collection--flex', + ], + 'constraints' => [ + new Assert\Count(['min' => 1]), + ], + ]) + ->add('btnLabel', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.btn_label', + 'required' => false, + ]) + ->add('btnUrl', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.btn_url', + 'required' => false, + ]) + ; + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function finishView(FormView $view, FormInterface $form, array $options): void + { + usort($view['articles']->children, function (FormView $articleA, FormView $articleB) { + return match (true) { + !$articleA->offsetExists('position') => -1, + !$articleB->offsetExists('position') => 1, + default => $articleA['position']->vars['data'] <=> $articleB['position']->vars['data'] + }; + }); + } +} diff --git a/src/Form/Type/UiElement/CaseStudiesUiElementType.php b/src/Form/Type/UiElement/CaseStudiesUiElementType.php index 1d81755..30117eb 100644 --- a/src/Form/Type/UiElement/CaseStudiesUiElementType.php +++ b/src/Form/Type/UiElement/CaseStudiesUiElementType.php @@ -23,15 +23,15 @@ #[AsUiElement( code: 'monsieurbiz_blog.case_studies_ui_element', icon: 'crosshairs', - uiElement: 'MonsieurBiz\SyliusBlogPlugin\UiElement\CaseStudiesUiElement', title: 'monsieurbiz_blog.ui_element.case_studies_ui_element.title', description: 'monsieurbiz_blog.ui_element.case_studies_ui_element.description', + uiElement: 'MonsieurBiz\SyliusBlogPlugin\UiElement\CaseStudiesUiElement', templates: new TemplatesUiElement( adminRender: '@MonsieurBizSyliusBlogPlugin/Admin/UiElement/case_studies.html.twig', frontRender: '@MonsieurBizSyliusBlogPlugin/Shop/UiElement/case_studies.html.twig', ), - tags: [], wireframe: 'case-studies', + tags: [], )] class CaseStudiesUiElementType extends AbstractType { diff --git a/src/Resources/translations/messages.en.yaml b/src/Resources/translations/messages.en.yaml index b3103e1..339771a 100644 --- a/src/Resources/translations/messages.en.yaml +++ b/src/Resources/translations/messages.en.yaml @@ -49,7 +49,7 @@ monsieurbiz_blog: edit_case_study: Edit case study no_results_to_display: No results to display ui_element: - case_studies_ui_element: + case_studies_ui_element: title: Case studies Element description: Display a list of case studies. fields: @@ -57,6 +57,23 @@ monsieurbiz_blog: case_studies: Case studies case_study: Case study position: Position + articles_selection_ui_element: + title: Articles selection Element + description: Display a list of manually selected articles. + fields: + title: Title + articles: Articles + btn_label: Button label + btn_url: Button url + article: Article + position: Position + articles: + display: + label: Display + choices: + multiple_with_image: Multiple with image + multiple_without_image: Multiple without image + single: Single monsieurbiz_menu: provider: diff --git a/src/Resources/translations/messages.fr.yaml b/src/Resources/translations/messages.fr.yaml index d56ef28..6284ac8 100644 --- a/src/Resources/translations/messages.fr.yaml +++ b/src/Resources/translations/messages.fr.yaml @@ -49,7 +49,7 @@ monsieurbiz_blog: edit_case_study: Modifier l'étude de cas no_results_to_display: Aucun résultat à afficher ui_element: - case_studies_ui_element: + case_studies_ui_element: title: Lame Études de cas description: Affiche une liste d'études de cas. fields: @@ -57,6 +57,23 @@ monsieurbiz_blog: case_studies: Études de cas case_study: Étude de cas position: Position + articles_selection_ui_element: + title: Lame Sélection d'articles + description: Affiche une liste d'articles sélectionné manuellement. + fields: + title: Titre + articles: Articles + btn_label: Libellé du bouton + btn_url: URL du bouton + article: Article + position: Position + articles: + display: + label: Affichage + choices: + multiple_with_image: Multiple avec image + multiple_without_image: Multiple sans image + single: Unique monsieurbiz_menu: provider: blog_list: Liste d'articles de blog diff --git a/src/Resources/views/Admin/UiElement/articles_selection.html.twig b/src/Resources/views/Admin/UiElement/articles_selection.html.twig new file mode 100644 index 0000000..3813f55 --- /dev/null +++ b/src/Resources/views/Admin/UiElement/articles_selection.html.twig @@ -0,0 +1,110 @@ +{# +UI Element template +type: articles_selection +element fields : + title + display + articles + btnLabel + btnUrl +element methods: + getArticles +#} + +{% set articles = ui_element.getArticles(element) %} +{% set display = element.display.display %} + +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
+
+
+ +{% if articles|length > 0 %} + {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} +
+ {% for article in articles %} +
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} +
+ {% for article in articles %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} +
+ {% for article in articles %} +
+
+
+
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+
+
+ {% endfor %} +
+ {% endif%} +{% endif %} diff --git a/src/Resources/views/Shop/UiElement/articles_selection.html.twig b/src/Resources/views/Shop/UiElement/articles_selection.html.twig new file mode 100644 index 0000000..6ce0854 --- /dev/null +++ b/src/Resources/views/Shop/UiElement/articles_selection.html.twig @@ -0,0 +1,113 @@ +{# +UI Element template +type: articles_selection +element fields : + title + display + articles + btnLabel + btnUrl +element methods: + getArticles +#} + +{% set articles = ui_element.getArticles(element) %} +{% set display = element.display.display %} + +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
+
+
+ +{% if articles|length > 0 %} + {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} +
+ {% for article in articles %} +
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} +
+ {% for article in articles %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} +
+ +
+
+ {% for article in articles %} +
+
+
+
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+
+
+ {% endfor %} +
+ {% endif%} +{% endif %} diff --git a/src/Resources/views/Wireframe/articles-selection.svg.twig b/src/Resources/views/Wireframe/articles-selection.svg.twig new file mode 100644 index 0000000..3abf037 --- /dev/null +++ b/src/Resources/views/Wireframe/articles-selection.svg.twig @@ -0,0 +1,3 @@ + + + diff --git a/src/UiElement/ArticlesSelectionUiElement.php b/src/UiElement/ArticlesSelectionUiElement.php new file mode 100644 index 0000000..a5988c8 --- /dev/null +++ b/src/UiElement/ArticlesSelectionUiElement.php @@ -0,0 +1,72 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace MonsieurBiz\SyliusBlogPlugin\UiElement; + +use MonsieurBiz\SyliusBlogPlugin\Entity\ArticleInterface; +use MonsieurBiz\SyliusBlogPlugin\Repository\ArticleRepositoryInterface; +use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElementInterface; +use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElementTrait; +use Sylius\Component\Channel\Context\ChannelContextInterface; +use Sylius\Component\Locale\Context\LocaleContextInterface; + +final class ArticlesSelectionUiElement implements UiElementInterface +{ + use UiElementTrait; + + public function __construct( + private readonly ArticleRepositoryInterface $articleRepository, + private readonly LocaleContextInterface $localeContext, + private readonly ChannelContextInterface $channelContext, + ) { + } + + /** + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * + * @return ArticleInterface[] + */ + public function getArticles(array $element): array + { + // A case study in array contains `article` (the ID) and `position` keys + $caseStudiesArray = $element['articles'] ?? []; + + // List the IDs to retrieve from repository + $articleIds = array_map(function ($article) { + return $article['article']; + }, $caseStudiesArray); + + // Prepare sorting + usort($caseStudiesArray, function ($articleA, $articleB) { + return $articleA['position'] <=> $articleB['position']; + }); + + $result = []; + // Retrieve case studies objects + if (\count($caseStudiesArray) > 0 && \count($articleIds) > 0) { + $caseStudies = $this->articleRepository->findEnabledAndPublishedByIds( + $articleIds, + $this->localeContext->getLocaleCode(), + ArticleInterface::BLOG_TYPE, + $this->channelContext->getChannel() + ); + foreach ($caseStudiesArray as $articleArray) { + foreach ($caseStudies as $article) { + if ($article->getId() === $articleArray['article']) { + $result[] = $article; + } + } + } + } + + return $result; + } +} From 67a883e69c95ce8ae9e499e70687f83977e4d326 Mon Sep 17 00:00:00 2001 From: Etienne Gutbub Date: Wed, 16 Oct 2024 16:56:10 +0200 Subject: [PATCH 2/5] feat(ArticlesByTags): Add a new uiElement to display blog articles with tags --- .../UiElement/ArticlesByTagsUiElementType.php | 112 ++++++++++++++++++ src/Repository/ArticleRepository.php | 25 ++++ src/Repository/ArticleRepositoryInterface.php | 5 + src/Resources/translations/messages.en.yaml | 11 ++ src/Resources/translations/messages.fr.yaml | 11 ++ .../UiElement/articles_by_tags.html.twig | 110 +++++++++++++++++ .../UiElement/articles_selection.html.twig | 35 +++--- .../Shop/UiElement/articles_by_tags.html.twig | 110 +++++++++++++++++ .../UiElement/articles_selection.html.twig | 35 +++--- .../views/Wireframe/articles-by-tags.svg.twig | 3 + src/UiElement/ArticlesByTagsUiElement.php | 42 +++++++ 11 files changed, 463 insertions(+), 36 deletions(-) create mode 100644 src/Form/Type/UiElement/ArticlesByTagsUiElementType.php create mode 100644 src/Resources/views/Admin/UiElement/articles_by_tags.html.twig create mode 100644 src/Resources/views/Shop/UiElement/articles_by_tags.html.twig create mode 100644 src/Resources/views/Wireframe/articles-by-tags.svg.twig create mode 100644 src/UiElement/ArticlesByTagsUiElement.php diff --git a/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php b/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php new file mode 100644 index 0000000..aeb42fd --- /dev/null +++ b/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php @@ -0,0 +1,112 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace MonsieurBiz\SyliusBlogPlugin\Form\Type\UiElement; + +use MonsieurBiz\SyliusBlogPlugin\Entity\Tag; +use MonsieurBiz\SyliusBlogPlugin\Form\Type\ArticlesDisplayType; +use MonsieurBiz\SyliusBlogPlugin\Repository\TagRepositoryInterface; +use MonsieurBiz\SyliusRichEditorPlugin\Attribute\AsUiElement; +use MonsieurBiz\SyliusRichEditorPlugin\Attribute\TemplatesUiElement; +use Sylius\Component\Locale\Context\LocaleContextInterface; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Validator\Constraints as Assert; + +#[AsUiElement( + code: 'monsieurbiz_blog.articles_by_tags_ui_element', + icon: 'tags', + title: 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.title', + description: 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.description', + uiElement: 'MonsieurBiz\SyliusBlogPlugin\UiElement\ArticlesByTagsUiElement', + templates: new TemplatesUiElement( + adminRender: '@MonsieurBizSyliusBlogPlugin/Admin/UiElement/articles_by_tags.html.twig', + frontRender: '@MonsieurBizSyliusBlogPlugin/Shop/UiElement/articles_by_tags.html.twig', + ), + wireframe: 'articles-by-tags', + tags: [], +)] +class ArticlesByTagsUiElementType extends AbstractType +{ + public function __construct( + private readonly TagRepositoryInterface $tagRepository, + private readonly LocaleContextInterface $localeContext, + ) { + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $tags = $this->tagRepository->createListQueryBuilder( + $this->localeContext->getLocaleCode(), + ); + + $tags = $tags->orderBy('translation.name')->getQuery()->getResult(); + + $builder + ->add('title', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.title', + 'required' => false, + ]) + ->add('display', ArticlesDisplayType::class, [ + 'label' => false, // already defined in the ArticlesDisplayType + ]) + ->add('tags', EntityType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.tags', + 'required' => false, + 'class' => Tag::class, + 'choice_label' => fn (Tag $tag) => $tag->getName(), + 'choice_value' => fn (?Tag $tag) => $tag?->getId(), + 'choices' => $tags, + 'multiple' => true, + ]) + ->add('limit', IntegerType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.limit', + 'help' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.help.limit', + 'required' => true, + 'constraints' => [ + new Assert\NotBlank(), + new Assert\GreaterThan(0), + ], + ]) + ->add('btnLabel', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.btn_label', + 'required' => false, + ]) + ->add('btnUrl', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.btn_url', + 'required' => false, + ]) + ; + + $builder->get('tags')->addModelTransformer( + new CallbackTransformer( + function ($tagsAsArray) { + return $this->tagRepository->findBy(['id' => $tagsAsArray ?? []]); + }, + function ($tagsAsString) { + $tags = []; + foreach ($tagsAsString as $tag) { + $tags[] = $tag->getId(); + } + + return $tags; + } + ), + ); + } +} diff --git a/src/Repository/ArticleRepository.php b/src/Repository/ArticleRepository.php index 56fc559..23aea3b 100644 --- a/src/Repository/ArticleRepository.php +++ b/src/Repository/ArticleRepository.php @@ -60,6 +60,31 @@ public function findAllEnabledAndPublishedByTag(string $localeCode, string $type ; } + public function findAllEnabledAndPublishedByTags(string $localeCode, string $type, ChannelInterface $channel, array $tags, int $limit): array + { + $queryBuilder = $this->createListQueryBuilderByType($localeCode, $type) + ->andWhere(':channel MEMBER OF ba.channels') + ->andWhere('ba.enabled = true') + ->andWhere('ba.state = :state') + ->setParameter('channel', $channel) + ->setParameter('state', ArticleInterface::STATE_PUBLISHED) + ->setMaxResults($limit) + ->orderBy('ba.publishedAt', 'DESC') + ; + + if (!empty($tags)) { + $queryBuilder + ->andWhere(':tags MEMBER OF ba.tags') + ->setParameter('tags', $tags) + ; + } + + return $queryBuilder + ->getQuery() + ->getResult() + ; + } + public function findOnePublishedBySlug(string $slug, string $localeCode, string $type, ChannelInterface $channel): ?ArticleInterface { return $this->createListQueryBuilderByType($localeCode, $type) diff --git a/src/Repository/ArticleRepositoryInterface.php b/src/Repository/ArticleRepositoryInterface.php index 69919f3..23a4d7e 100644 --- a/src/Repository/ArticleRepositoryInterface.php +++ b/src/Repository/ArticleRepositoryInterface.php @@ -29,6 +29,11 @@ public function createShopListQueryBuilderByType(string $localeCode, string $typ */ public function findAllEnabledAndPublishedByTag(string $localeCode, string $type, ChannelInterface $channel, TagInterface $tag, int $limit): array; + /** + * @return ArticleInterface[] + */ + public function findAllEnabledAndPublishedByTags(string $localeCode, string $type, ChannelInterface $channel, array $tags, int $limit): array; + public function findOnePublishedBySlug(string $slug, string $localeCode, string $type, ChannelInterface $channel): ?ArticleInterface; public function findAllEnabledAndPublishedByAuthor(string $localeCode, string $type, ChannelInterface $channel, AuthorInterface $author, int $limit): array; diff --git a/src/Resources/translations/messages.en.yaml b/src/Resources/translations/messages.en.yaml index 339771a..ff1aebc 100644 --- a/src/Resources/translations/messages.en.yaml +++ b/src/Resources/translations/messages.en.yaml @@ -67,6 +67,17 @@ monsieurbiz_blog: btn_url: Button url article: Article position: Position + articles_by_tags_ui_element: + title: Articles by tags Element + description: Display a list of articles by tags. + fields: + title: Title + tags: Tags + limit: limit + btn_label: Button label + btn_url: Button url + help: + limit: The maximum number of articles to display articles: display: label: Display diff --git a/src/Resources/translations/messages.fr.yaml b/src/Resources/translations/messages.fr.yaml index 6284ac8..81a13e4 100644 --- a/src/Resources/translations/messages.fr.yaml +++ b/src/Resources/translations/messages.fr.yaml @@ -67,6 +67,17 @@ monsieurbiz_blog: btn_url: URL du bouton article: Article position: Position + articles_by_tags_ui_element: + title: Lame Articles par tags + description: Affiche une liste d'articles par tags. + fields: + title: Titre + tags: Tags + limit: Limite + btn_label: Libellé du bouton + btn_url: URL du bouton + help: + limit: Le nombre maximum d'articles à afficher articles: display: label: Affichage diff --git a/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig b/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig new file mode 100644 index 0000000..e634165 --- /dev/null +++ b/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig @@ -0,0 +1,110 @@ +{# +UI Element template +type: articles_selection +element fields : + title + display + tags + limit + btnLabel + btnUrl +element methods: + getArticles +#} + +{% set articles = ui_element.getArticles(element.tags|default([]), element.limit|default(3)) %} +{% set display = element.display.display %} + +{% if articles|length > 0 %} +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
+
+
+ {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} +
+ {% for article in articles %} +
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} +
+ {% for article in articles %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} +
+ {% for article in articles %} +
+
+
+
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+
+
+ {% endfor %} +
+ {% endif%} +{% endif %} diff --git a/src/Resources/views/Admin/UiElement/articles_selection.html.twig b/src/Resources/views/Admin/UiElement/articles_selection.html.twig index 3813f55..4e86956 100644 --- a/src/Resources/views/Admin/UiElement/articles_selection.html.twig +++ b/src/Resources/views/Admin/UiElement/articles_selection.html.twig @@ -14,26 +14,25 @@ element methods: {% set articles = ui_element.getArticles(element) %} {% set display = element.display.display %} -
-
-
- {% if element.title|default('') is not empty %} -
- {{ element.title }} -
- {% endif %} -
-
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} - - {% endif %} +{% if articles|length > 0 %} +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
-
- -{% if articles|length > 0 %} {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %}
{% for article in articles %} diff --git a/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig b/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig new file mode 100644 index 0000000..e634165 --- /dev/null +++ b/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig @@ -0,0 +1,110 @@ +{# +UI Element template +type: articles_selection +element fields : + title + display + tags + limit + btnLabel + btnUrl +element methods: + getArticles +#} + +{% set articles = ui_element.getArticles(element.tags|default([]), element.limit|default(3)) %} +{% set display = element.display.display %} + +{% if articles|length > 0 %} +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
+
+
+ {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} +
+ {% for article in articles %} +
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} +
+ {% for article in articles %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} +
+ {% for article in articles %} +
+
+
+
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+
+
+ {% endfor %} +
+ {% endif%} +{% endif %} diff --git a/src/Resources/views/Shop/UiElement/articles_selection.html.twig b/src/Resources/views/Shop/UiElement/articles_selection.html.twig index 6ce0854..cdc2908 100644 --- a/src/Resources/views/Shop/UiElement/articles_selection.html.twig +++ b/src/Resources/views/Shop/UiElement/articles_selection.html.twig @@ -14,26 +14,25 @@ element methods: {% set articles = ui_element.getArticles(element) %} {% set display = element.display.display %} -
-
-
- {% if element.title|default('') is not empty %} -
- {{ element.title }} -
- {% endif %} -
-
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} - - {% endif %} +{% if articles|length > 0 %} +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
-
- -{% if articles|length > 0 %} {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %}
{% for article in articles %} diff --git a/src/Resources/views/Wireframe/articles-by-tags.svg.twig b/src/Resources/views/Wireframe/articles-by-tags.svg.twig new file mode 100644 index 0000000..3abf037 --- /dev/null +++ b/src/Resources/views/Wireframe/articles-by-tags.svg.twig @@ -0,0 +1,3 @@ + + + diff --git a/src/UiElement/ArticlesByTagsUiElement.php b/src/UiElement/ArticlesByTagsUiElement.php new file mode 100644 index 0000000..a81ba1e --- /dev/null +++ b/src/UiElement/ArticlesByTagsUiElement.php @@ -0,0 +1,42 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace MonsieurBiz\SyliusBlogPlugin\UiElement; + +use MonsieurBiz\SyliusBlogPlugin\Entity\ArticleInterface; +use MonsieurBiz\SyliusBlogPlugin\Repository\ArticleRepositoryInterface; +use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElementInterface; +use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElementTrait; +use Sylius\Component\Channel\Context\ChannelContextInterface; +use Sylius\Component\Locale\Context\LocaleContextInterface; + +final class ArticlesByTagsUiElement implements UiElementInterface +{ + use UiElementTrait; + + public function __construct( + private readonly ArticleRepositoryInterface $articleRepository, + private readonly LocaleContextInterface $localeContext, + private readonly ChannelContextInterface $channelContext, + ) { + } + + public function getArticles(array $tags, int $limit): array + { + return $this->articleRepository->findAllEnabledAndPublishedByTags( + $this->localeContext->getLocaleCode(), + ArticleInterface::BLOG_TYPE, + $this->channelContext->getChannel(), + $tags, + $limit + ); + } +} From d33bcc5acd63f7c4a5828e19ef68cfe92934e99b Mon Sep 17 00:00:00 2001 From: Etienne Gutbub Date: Wed, 16 Oct 2024 17:09:33 +0200 Subject: [PATCH 3/5] refactor(ArticlesSelection): merge templates and include it --- .../UiElement/articles_by_tags.html.twig | 95 +----------------- .../Admin/UiElement/articles_cards.html.twig | 94 ++++++++++++++++++ .../UiElement/articles_selection.html.twig | 95 +----------------- .../Shop/UiElement/articles_by_tags.html.twig | 95 +----------------- .../Shop/UiElement/articles_cards.html.twig | 94 ++++++++++++++++++ .../UiElement/articles_selection.html.twig | 98 +------------------ 6 files changed, 192 insertions(+), 379 deletions(-) create mode 100644 src/Resources/views/Admin/UiElement/articles_cards.html.twig create mode 100644 src/Resources/views/Shop/UiElement/articles_cards.html.twig diff --git a/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig b/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig index e634165..fe6d553 100644 --- a/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig +++ b/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig @@ -13,98 +13,5 @@ element methods: #} {% set articles = ui_element.getArticles(element.tags|default([]), element.limit|default(3)) %} -{% set display = element.display.display %} -{% if articles|length > 0 %} -
-
-
- {% if element.title|default('') is not empty %} -
- {{ element.title }} -
- {% endif %} -
-
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} - - {% endif %} -
-
-
- {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} -
- {% for article in articles %} -
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} -
- {% for article in articles %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} -
- {% for article in articles %} -
-
-
-
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
-
-
- {% endfor %} -
- {% endif%} -{% endif %} +{{ include('@MonsieurBizSyliusBlogPlugin/Admin/UiElement/articles_cards.html.twig') }} diff --git a/src/Resources/views/Admin/UiElement/articles_cards.html.twig b/src/Resources/views/Admin/UiElement/articles_cards.html.twig new file mode 100644 index 0000000..f9a3cb0 --- /dev/null +++ b/src/Resources/views/Admin/UiElement/articles_cards.html.twig @@ -0,0 +1,94 @@ +{% if articles|length > 0 %} + {% set display = element.display.display %} +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
+
+
+ {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} +
+ {% for article in articles %} +
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} +
+ {% for article in articles %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} +
+ {% for article in articles %} +
+
+
+
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+
+
+ {% endfor %} +
+ {% endif%} +{% endif %} diff --git a/src/Resources/views/Admin/UiElement/articles_selection.html.twig b/src/Resources/views/Admin/UiElement/articles_selection.html.twig index 4e86956..92e8b2d 100644 --- a/src/Resources/views/Admin/UiElement/articles_selection.html.twig +++ b/src/Resources/views/Admin/UiElement/articles_selection.html.twig @@ -12,98 +12,5 @@ element methods: #} {% set articles = ui_element.getArticles(element) %} -{% set display = element.display.display %} -{% if articles|length > 0 %} -
-
-
- {% if element.title|default('') is not empty %} -
- {{ element.title }} -
- {% endif %} -
-
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} - - {% endif %} -
-
-
- {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} -
- {% for article in articles %} -
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} -
- {% for article in articles %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} -
- {% for article in articles %} -
-
-
-
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
-
-
- {% endfor %} -
- {% endif%} -{% endif %} +{{ include('@MonsieurBizSyliusBlogPlugin/Admin/UiElement/articles_cards.html.twig') }} diff --git a/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig b/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig index e634165..b869e7b 100644 --- a/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig +++ b/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig @@ -13,98 +13,5 @@ element methods: #} {% set articles = ui_element.getArticles(element.tags|default([]), element.limit|default(3)) %} -{% set display = element.display.display %} -{% if articles|length > 0 %} -
-
-
- {% if element.title|default('') is not empty %} -
- {{ element.title }} -
- {% endif %} -
-
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} - - {% endif %} -
-
-
- {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} -
- {% for article in articles %} -
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} -
- {% for article in articles %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} -
- {% for article in articles %} -
-
-
-
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
-
-
- {% endfor %} -
- {% endif%} -{% endif %} +{{ include('@MonsieurBizSyliusBlogPlugin/Shop/UiElement/articles_cards.html.twig') }} diff --git a/src/Resources/views/Shop/UiElement/articles_cards.html.twig b/src/Resources/views/Shop/UiElement/articles_cards.html.twig new file mode 100644 index 0000000..f9a3cb0 --- /dev/null +++ b/src/Resources/views/Shop/UiElement/articles_cards.html.twig @@ -0,0 +1,94 @@ +{% if articles|length > 0 %} + {% set display = element.display.display %} +
+
+
+ {% if element.title|default('') is not empty %} +
+ {{ element.title }} +
+ {% endif %} +
+
+ {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} + + {{ element.btnLabel }} + + {% endif %} +
+
+
+ {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} +
+ {% for article in articles %} +
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} +
+ {% for article in articles %} +
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+ {% endfor %} +
+ {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} +
+ {% for article in articles %} +
+
+
+
+
+ {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} +
+
+
+ {{ article.title }} + {% if article.description|default('') is not empty %} +
+ {{ article.description }} +
+ {% endif %} + +
+
+
+
+ {% endfor %} +
+ {% endif%} +{% endif %} diff --git a/src/Resources/views/Shop/UiElement/articles_selection.html.twig b/src/Resources/views/Shop/UiElement/articles_selection.html.twig index cdc2908..4bcb63b 100644 --- a/src/Resources/views/Shop/UiElement/articles_selection.html.twig +++ b/src/Resources/views/Shop/UiElement/articles_selection.html.twig @@ -12,101 +12,5 @@ element methods: #} {% set articles = ui_element.getArticles(element) %} -{% set display = element.display.display %} -{% if articles|length > 0 %} -
-
-
- {% if element.title|default('') is not empty %} -
- {{ element.title }} -
- {% endif %} -
-
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} - - {% endif %} -
-
-
- {% if display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITH_IMAGE') %} -
- {% for article in articles %} -
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::MULTIPLE_WITHOUT_IMAGE') %} -
- {% for article in articles %} -
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
- {% endfor %} -
- {% elseif display == constant('MonsieurBiz\\SyliusBlogPlugin\\Form\\Type\\ArticlesDisplayType::SINGLE') %} -
- -
-
- {% for article in articles %} -
-
-
-
-
- {% include '@MonsieurBizSyliusBlogPlugin/Admin/Article/_image.html.twig' with { 'article' : article, isThumbnail: true } %} -
-
-
- {{ article.title }} - {% if article.description|default('') is not empty %} -
- {{ article.description }} -
- {% endif %} - -
-
-
-
- {% endfor %} -
- {% endif%} -{% endif %} +{{ include('@MonsieurBizSyliusBlogPlugin/Shop/UiElement/articles_cards.html.twig') }} From 1e9e3bf5d37207cdd7ff055e4391a53aeba51f95 Mon Sep 17 00:00:00 2001 From: Etienne Gutbub Date: Wed, 23 Oct 2024 16:35:56 +0200 Subject: [PATCH 4/5] refactor(ArticlesSelection): rename buttonLabel and buttonUrl --- .../UiElement/ArticlesByTagsUiElementType.php | 9 +++++---- .../ArticlesSelectionUiElementType.php | 9 +++++---- src/Resources/translations/messages.en.yaml | 10 +++++----- src/Resources/translations/messages.fr.yaml | 8 ++++---- .../Admin/UiElement/articles_by_tags.html.twig | 4 ++-- .../Admin/UiElement/articles_cards.html.twig | 6 +++--- .../UiElement/articles_selection.html.twig | 4 ++-- .../Shop/UiElement/articles_by_tags.html.twig | 4 ++-- .../Shop/UiElement/articles_cards.html.twig | 6 +++--- .../UiElement/articles_selection.html.twig | 4 ++-- src/UiElement/ArticlesSelectionUiElement.php | 18 +++++++++--------- 11 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php b/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php index aeb42fd..c23dea0 100644 --- a/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php +++ b/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php @@ -16,6 +16,7 @@ use MonsieurBiz\SyliusBlogPlugin\Repository\TagRepositoryInterface; use MonsieurBiz\SyliusRichEditorPlugin\Attribute\AsUiElement; use MonsieurBiz\SyliusRichEditorPlugin\Attribute\TemplatesUiElement; +use MonsieurBiz\SyliusRichEditorPlugin\Form\Type\LinkType; use Sylius\Component\Locale\Context\LocaleContextInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; @@ -83,12 +84,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void new Assert\GreaterThan(0), ], ]) - ->add('btnLabel', TextType::class, [ - 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.btn_label', + ->add('buttonLabel', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.button_label', 'required' => false, ]) - ->add('btnUrl', TextType::class, [ - 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.btn_url', + ->add('buttonUrl', LinkType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.button_url', 'required' => false, ]) ; diff --git a/src/Form/Type/UiElement/ArticlesSelectionUiElementType.php b/src/Form/Type/UiElement/ArticlesSelectionUiElementType.php index efeb0d9..904f678 100644 --- a/src/Form/Type/UiElement/ArticlesSelectionUiElementType.php +++ b/src/Form/Type/UiElement/ArticlesSelectionUiElementType.php @@ -15,6 +15,7 @@ use MonsieurBiz\SyliusBlogPlugin\Form\Type\ArticleSelectionElementType; use MonsieurBiz\SyliusRichEditorPlugin\Attribute\AsUiElement; use MonsieurBiz\SyliusRichEditorPlugin\Attribute\TemplatesUiElement; +use MonsieurBiz\SyliusRichEditorPlugin\Form\Type\LinkType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -66,12 +67,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void new Assert\Count(['min' => 1]), ], ]) - ->add('btnLabel', TextType::class, [ - 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.btn_label', + ->add('buttonLabel', TextType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.button_label', 'required' => false, ]) - ->add('btnUrl', TextType::class, [ - 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.btn_url', + ->add('buttonUrl', LinkType::class, [ + 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.button_url', 'required' => false, ]) ; diff --git a/src/Resources/translations/messages.en.yaml b/src/Resources/translations/messages.en.yaml index ff1aebc..2c47ef6 100644 --- a/src/Resources/translations/messages.en.yaml +++ b/src/Resources/translations/messages.en.yaml @@ -63,8 +63,8 @@ monsieurbiz_blog: fields: title: Title articles: Articles - btn_label: Button label - btn_url: Button url + button_label: Button label + button_url: Button url article: Article position: Position articles_by_tags_ui_element: @@ -73,9 +73,9 @@ monsieurbiz_blog: fields: title: Title tags: Tags - limit: limit - btn_label: Button label - btn_url: Button url + limit: Limit + button_label: Button label + button_url: Button url help: limit: The maximum number of articles to display articles: diff --git a/src/Resources/translations/messages.fr.yaml b/src/Resources/translations/messages.fr.yaml index 81a13e4..f9f99df 100644 --- a/src/Resources/translations/messages.fr.yaml +++ b/src/Resources/translations/messages.fr.yaml @@ -63,8 +63,8 @@ monsieurbiz_blog: fields: title: Titre articles: Articles - btn_label: Libellé du bouton - btn_url: URL du bouton + button_label: Libellé du bouton + button_url: URL du bouton article: Article position: Position articles_by_tags_ui_element: @@ -74,8 +74,8 @@ monsieurbiz_blog: title: Titre tags: Tags limit: Limite - btn_label: Libellé du bouton - btn_url: URL du bouton + button_label: Libellé du bouton + button_url: URL du bouton help: limit: Le nombre maximum d'articles à afficher articles: diff --git a/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig b/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig index fe6d553..4400064 100644 --- a/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig +++ b/src/Resources/views/Admin/UiElement/articles_by_tags.html.twig @@ -6,8 +6,8 @@ element fields : display tags limit - btnLabel - btnUrl + buttonLabel + buttonUrl element methods: getArticles #} diff --git a/src/Resources/views/Admin/UiElement/articles_cards.html.twig b/src/Resources/views/Admin/UiElement/articles_cards.html.twig index f9a3cb0..23f6033 100644 --- a/src/Resources/views/Admin/UiElement/articles_cards.html.twig +++ b/src/Resources/views/Admin/UiElement/articles_cards.html.twig @@ -10,9 +10,9 @@ {% endif %}
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} + {% if element.buttonUrl|default('') is not empty and element.buttonLabel|default('') is not empty %} + + {{ element.buttonLabel }} {% endif %}
diff --git a/src/Resources/views/Admin/UiElement/articles_selection.html.twig b/src/Resources/views/Admin/UiElement/articles_selection.html.twig index 92e8b2d..5222cce 100644 --- a/src/Resources/views/Admin/UiElement/articles_selection.html.twig +++ b/src/Resources/views/Admin/UiElement/articles_selection.html.twig @@ -5,8 +5,8 @@ element fields : title display articles - btnLabel - btnUrl + buttonLabel + buttonUrl element methods: getArticles #} diff --git a/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig b/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig index b869e7b..f8dd7a9 100644 --- a/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig +++ b/src/Resources/views/Shop/UiElement/articles_by_tags.html.twig @@ -6,8 +6,8 @@ element fields : display tags limit - btnLabel - btnUrl + buttonLabel + buttonUrl element methods: getArticles #} diff --git a/src/Resources/views/Shop/UiElement/articles_cards.html.twig b/src/Resources/views/Shop/UiElement/articles_cards.html.twig index f9a3cb0..23f6033 100644 --- a/src/Resources/views/Shop/UiElement/articles_cards.html.twig +++ b/src/Resources/views/Shop/UiElement/articles_cards.html.twig @@ -10,9 +10,9 @@ {% endif %}
- {% if element.btnUrl|default('') is not empty and element.btnLabel|default('') is not empty %} - - {{ element.btnLabel }} + {% if element.buttonUrl|default('') is not empty and element.buttonLabel|default('') is not empty %} + + {{ element.buttonLabel }} {% endif %}
diff --git a/src/Resources/views/Shop/UiElement/articles_selection.html.twig b/src/Resources/views/Shop/UiElement/articles_selection.html.twig index 4bcb63b..52e91c2 100644 --- a/src/Resources/views/Shop/UiElement/articles_selection.html.twig +++ b/src/Resources/views/Shop/UiElement/articles_selection.html.twig @@ -5,8 +5,8 @@ element fields : title display articles - btnLabel - btnUrl + buttonLabel + buttonUrl element methods: getArticles #} diff --git a/src/UiElement/ArticlesSelectionUiElement.php b/src/UiElement/ArticlesSelectionUiElement.php index a5988c8..496559d 100644 --- a/src/UiElement/ArticlesSelectionUiElement.php +++ b/src/UiElement/ArticlesSelectionUiElement.php @@ -36,30 +36,30 @@ public function __construct( */ public function getArticles(array $element): array { - // A case study in array contains `article` (the ID) and `position` keys - $caseStudiesArray = $element['articles'] ?? []; + // An article in array contains `article` (the ID) and `position` keys + $articlesArray = $element['articles'] ?? []; // List the IDs to retrieve from repository $articleIds = array_map(function ($article) { return $article['article']; - }, $caseStudiesArray); + }, $articlesArray); // Prepare sorting - usort($caseStudiesArray, function ($articleA, $articleB) { + usort($articlesArray, function ($articleA, $articleB) { return $articleA['position'] <=> $articleB['position']; }); $result = []; - // Retrieve case studies objects - if (\count($caseStudiesArray) > 0 && \count($articleIds) > 0) { - $caseStudies = $this->articleRepository->findEnabledAndPublishedByIds( + // Retrieve articles objects + if (\count($articlesArray) > 0 && \count($articleIds) > 0) { + $articles = $this->articleRepository->findEnabledAndPublishedByIds( $articleIds, $this->localeContext->getLocaleCode(), ArticleInterface::BLOG_TYPE, $this->channelContext->getChannel() ); - foreach ($caseStudiesArray as $articleArray) { - foreach ($caseStudies as $article) { + foreach ($articlesArray as $articleArray) { + foreach ($articles as $article) { if ($article->getId() === $articleArray['article']) { $result[] = $article; } From 3945a3ea56ab1522d0682bb50b6e4aa9e0b21691 Mon Sep 17 00:00:00 2001 From: Etienne Gutbub Date: Wed, 23 Oct 2024 16:56:42 +0200 Subject: [PATCH 5/5] refactor(ArticlesSelection): use query builder when using an EntityType field --- src/Form/Type/ArticleSelectionElementType.php | 18 ++++++++--------- src/Form/Type/CaseStudyElementType.php | 20 +++++++++---------- .../UiElement/ArticlesByTagsUiElementType.php | 12 +++++------ 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/Form/Type/ArticleSelectionElementType.php b/src/Form/Type/ArticleSelectionElementType.php index cd3c37a..b129cc5 100644 --- a/src/Form/Type/ArticleSelectionElementType.php +++ b/src/Form/Type/ArticleSelectionElementType.php @@ -38,15 +38,6 @@ public function __construct( */ public function buildForm(FormBuilderInterface $builder, array $options): void { - $articles = $this->articleRepository->createShopListQueryBuilderByType( - $this->localeContext->getLocaleCode(), - ArticleInterface::BLOG_TYPE, - $this->channelContext->getChannel(), - null - ); - - $articles = $articles->orderBy('translation.title')->getQuery()->getResult(); - $builder ->add('article', EntityType::class, [ 'class' => Article::class, @@ -54,7 +45,14 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'choice_label' => fn (Article $article) => $article->getTitle(), 'choice_value' => fn (?Article $article) => $article?->getId(), 'required' => true, - 'choices' => $articles, + 'query_builder' => function (ArticleRepositoryInterface $articleRepository) { + return $articleRepository->createShopListQueryBuilderByType( + $this->localeContext->getLocaleCode(), + ArticleInterface::BLOG_TYPE, + $this->channelContext->getChannel(), + null + )->orderBy('translation.title'); + }, ]) ->add('position', IntegerType::class, [ 'label' => 'monsieurbiz_blog.ui_element.articles_selection_ui_element.fields.position', diff --git a/src/Form/Type/CaseStudyElementType.php b/src/Form/Type/CaseStudyElementType.php index d884057..2a355ad 100644 --- a/src/Form/Type/CaseStudyElementType.php +++ b/src/Form/Type/CaseStudyElementType.php @@ -38,23 +38,21 @@ public function __construct( */ public function buildForm(FormBuilderInterface $builder, array $options): void { - $caseStudies = $this->articleRepository->createShopListQueryBuilderByType( - $this->localeContext->getLocaleCode(), - ArticleInterface::CASE_STUDY_TYPE, - $this->channelContext->getChannel(), - null - ); - - $caseStudies = $caseStudies->orderBy('translation.title')->getQuery()->getResult(); - $builder ->add('case_study', EntityType::class, [ 'class' => Article::class, 'label' => 'monsieurbiz_blog.ui_element.case_studies_ui_element.fields.case_study', 'choice_label' => fn (Article $caseStudy) => $caseStudy->getTitle(), - 'choice_value' => fn (?Article $caseStudy) => $caseStudy ? $caseStudy->getId() : null, + 'choice_value' => fn (?Article $caseStudy) => $caseStudy?->getId(), 'required' => true, - 'choices' => $caseStudies, + 'query_builder' => function (ArticleRepositoryInterface $articleRepository) { + return $articleRepository->createShopListQueryBuilderByType( + $this->localeContext->getLocaleCode(), + ArticleInterface::CASE_STUDY_TYPE, + $this->channelContext->getChannel(), + null + )->orderBy('translation.title'); + }, ]) ->add('position', IntegerType::class, [ 'label' => 'monsieurbiz_blog.ui_element.case_studies_ui_element.fields.position', diff --git a/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php b/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php index c23dea0..06af902 100644 --- a/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php +++ b/src/Form/Type/UiElement/ArticlesByTagsUiElementType.php @@ -52,12 +52,6 @@ public function __construct( */ public function buildForm(FormBuilderInterface $builder, array $options): void { - $tags = $this->tagRepository->createListQueryBuilder( - $this->localeContext->getLocaleCode(), - ); - - $tags = $tags->orderBy('translation.name')->getQuery()->getResult(); - $builder ->add('title', TextType::class, [ 'label' => 'monsieurbiz_blog.ui_element.articles_by_tags_ui_element.fields.title', @@ -72,7 +66,11 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'class' => Tag::class, 'choice_label' => fn (Tag $tag) => $tag->getName(), 'choice_value' => fn (?Tag $tag) => $tag?->getId(), - 'choices' => $tags, + 'query_builder' => function (TagRepositoryInterface $tagRepository) { + return $tagRepository->createListQueryBuilder( + $this->localeContext->getLocaleCode(), + )->orderBy('translation.name'); + }, 'multiple' => true, ]) ->add('limit', IntegerType::class, [