Sangfroid 1 месяц назад
Родитель
Сommit
9e8cb060d2

+ 12 - 0
assets/styles/badges.css

@@ -10,6 +10,18 @@
   margin-right: 5px;
 }
 
+.tag {
+  display: inline-block;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  border-radius: 7px;
+  text-transform: uppercase;
+  color: #fff;
+  margin-right: 3px;
+  background-color: #17a2b8;
+}
+
 /* Badge pour l'état "Publié" */
 .badge-published {
   background-color: #28a745; /* Vert */

+ 7 - 0
src/Entity/Article.php

@@ -155,4 +155,11 @@ class Article
 
         return $this;
     }
+
+    public function clearTags(): static
+    {
+        $this->tags = new ArrayCollection();
+
+        return $this;
+    }
 }

+ 6 - 1
src/Entity/Tag.php

@@ -6,7 +6,7 @@ use App\Repository\TagRepository;
 use Doctrine\ORM\Mapping as ORM;
 
 #[ORM\Entity(repositoryClass: TagRepository::class)]
-class Tag
+class Tag implements \Stringable
 {
     #[ORM\Id]
     #[ORM\GeneratedValue]
@@ -16,6 +16,11 @@ class Tag
     #[ORM\Column(length: 50)]
     private ?string $name = null;
 
+    public function __toString(): string
+    {
+        return $this->getName();
+    }
+
     public function getId(): ?int
     {
         return $this->id;

+ 56 - 1
src/Form/ArticleType.php

@@ -3,19 +3,29 @@
 namespace App\Form;
 
 use App\Entity\Article;
+use App\Entity\Tag;
 use App\Entity\User;
+use App\Repository\TagRepository;
 use App\Service\BaseUrl;
+use Doctrine\ORM\EntityManagerInterface;
 use Symfony\Bridge\Doctrine\Form\Type\EntityType;
 use Symfony\Component\Form\AbstractType;
 use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
 use Symfony\Component\Form\Extension\Core\Type\TextareaType;
 use Symfony\Component\Form\Extension\Core\Type\TextType;
 use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\Form\FormEvent;
+use Symfony\Component\Form\FormEvents;
 use Symfony\Component\OptionsResolver\OptionsResolver;
 
 class ArticleType extends AbstractType
 {
-    public function __construct(protected BaseUrl $baseUrl)
+    public function __construct(
+        protected readonly BaseUrl $baseUrl,
+        protected readonly EntityManagerInterface $em,
+        protected readonly TagRepository $tagRepository
+    
+    )
     {
         
     }
@@ -35,6 +45,13 @@ class ArticleType extends AbstractType
                     'data-url' => $this->baseUrl->getBasePath()
                 ],
             ])
+            ->add('tags', TextType::class, [
+                'mapped' => false,
+                'required' => false,
+                'attr'  => [
+                    'placeholder' => 'Entrez des tag séparés par des virgules'
+                ]
+            ])
             ->add('content', TextareaType::class, [
                 'required'  => false,
                 'attr'  =>  [
@@ -56,6 +73,44 @@ class ArticleType extends AbstractType
                 'choice_value'  => null
             ])
         ;
+
+        // Listener pour pré-remplir le champ texte lors de l'édition
+        $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event): void {
+            /** @var Article $article */
+            $article = $event->getData();
+            $form = $event->getForm();
+            if ($article && $article->getTags()) {
+                $tags = $article->getTags()->map(fn($tag) => $tag->getName())->toArray();
+                if ($form->has('tags')) {
+                    $form->get('tags')->setData(implode(', ', $tags));
+                }
+            }
+        });
+
+        // Écouteur d'événement pour permettre la création de nouveaux tags
+        $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event): void {
+            $article = $event->getData();
+            $form = $event->getForm();
+
+            $article->clearTags();
+
+            $tagsInput = $form->get('tags')->getData();
+            if ($tagsInput) {
+                $tags = array_map('trim', explode(',', $tagsInput));
+                
+                foreach ($tags as $tagName) {
+                    $tag = $this->tagRepository->findOneBy(['name' => $tagName]);
+                    
+                    if (!$tag) {
+                        $tag = new Tag();
+                        $tag->setName($tagName);
+                        $this->em->persist($tag);
+                    }
+
+                    $article->addTag($tag);
+                }
+            }
+        });
     }
 
     public function configureOptions(OptionsResolver $resolver): void

+ 1 - 1
templates/article/_form.html.twig

@@ -17,7 +17,7 @@
             <div class="div-bouton-slug"><button type="button" class="bouton-slug" data-slugger-target="bouton" data-action="click->slugger#open">Générer un slug</butt></div>
             {{ form_help(form.slug) }}
         </div>
-        
+        {{ form_row(form.tags ) }}
         {{ form_row(form.content) }}
         {{ form_row(form.publicationDate) }}
         {{ form_row(form.author) }}

+ 9 - 0
templates/article/show.html.twig

@@ -19,6 +19,15 @@
                 <th>Permalien</th>
                 <td>{{ url('app_view', {slug: article.slug}) }}</td>
             </tr>
+            <tr>
+                <th>Tags</th>
+                <td>
+                    {% for tag in article.tags %}
+                        <span class="tag">{{ tag }}</span>
+                        {% if not loop.last %} {% endif %}
+                    {% endfor %}
+                </td>
+            </tr>
             <tr>
                 <th>Date de publication</th>
                 <td>{{ article.publicationDate ? article.publicationDate|date('Y-m-d H:i:s') : '' }}</td>

+ 6 - 0
templates/index/index.html.twig

@@ -11,6 +11,12 @@
                 <header class="titre-article">
                     <h1><a href="{{ path('app_view', {'slug': article.slug}) }}">{{ article.title}}</a></h1>
                     <p class="article-by">{{ article.publicationDate | format_date('long') }} - {{ article.author }}</p>
+                    <p class="article-by">
+                        {% for tag in article.tags %}
+                            <span class="tag">{{ tag }}</span>
+                            {% if not loop.last %} {% endif %}
+                        {% endfor %}
+                    </p>
                 </header>
                 <section class="contenu">
                     {{ article.content | markdown }}

+ 6 - 0
templates/view/index.html.twig

@@ -16,6 +16,12 @@
         <header class="titre-article">
             <h1>{{ article.title}}</h1>
             <p class="article-by">{{ article.publicationDate | format_date('long')}} - {{ article.author }}</p>
+            <p class="article-by">
+                {% for tag in article.tags %}
+                    <span class="tag">{{ tag }}</span>
+                    {% if not loop.last %} {% endif %}
+                {% endfor %}
+            </p>
         </header>
         <section class="contenu">
             {{ article.content | markdown }}