diff --git a/src/Controller/ApiEntryController.php b/src/Controller/ApiEntryController.php index f3a24cf265be18ae75dcd42f76054253d2d100b2..b6aa70145badc106a6e2b538c0ea1868d10b1681 100644 --- a/src/Controller/ApiEntryController.php +++ b/src/Controller/ApiEntryController.php @@ -156,7 +156,7 @@ class ApiEntryController extends ApiBaseController return $this->createJsonResponse(401, ['error' => sprintf("Les lexiques cibles doivent tous appartenir à la même langue")]); } - $forceCreation = $data['force'] ?? false; + $forceCreation = isset($data['force']) && $data['force'] === true; $headword = $this->getHeadwordForWord($data['graphy'], $language); // On récupère ou on crée le mot-vedette diff --git a/src/Controller/ApiGraphyListController.php b/src/Controller/ApiGraphyListController.php index f6e975b55f3344e5fa49b7419e0355b744f60e79..fc29e5f930788ef4e30a29e6453963f743781769 100644 --- a/src/Controller/ApiGraphyListController.php +++ b/src/Controller/ApiGraphyListController.php @@ -6,6 +6,7 @@ use App\Entity\Entry; use App\Entity\Graphy; use App\Entity\GraphyList; use App\Form\GraphyListType; +use App\Manager\WiktionaryManager; use App\Repository\GraphyListRepository; use Doctrine\Persistence\ManagerRegistry; use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; @@ -106,7 +107,7 @@ class ApiGraphyListController extends ApiBaseController } /** - * Ajout de graphies à la liste PAS DE VALIDATION (on crée la graphie dans Balex sans s'assurer qu'elle existe dans le wiktionnaire) + * Ajout de graphies à la liste. PAS DE VALIDATION si force=true (on crée la graphie dans Balex sans s'assurer qu'elle existe dans le wiktionnaire) * * @Route("/add-graphies/{id}", name="api_graphy_list_add_graphies", methods={"POST"}) * @@ -125,6 +126,7 @@ class ApiGraphyListController extends ApiBaseController * required=true, * @OA\JsonContent( * required={"items"}, + * @OA\Property(property="force", type="bool", example="false", description="force la création de la graphie même si elle n'est pas trouvée dans le wiktionnaire"), * @OA\Property(property="items", type="array", * example={"salut", "les", "amis"}, * @OA\Items( @@ -136,7 +138,7 @@ class ApiGraphyListController extends ApiBaseController * @OA\Tag(name="Lists") * @Security(name="OAuth2") */ - public function addGraphiesToGraphyList(Request $request, GraphyList $graphyList = null): Response + public function addGraphiesToGraphyList(WiktionaryManager $wiktionaryManager, Request $request, GraphyList $graphyList = null): Response { if (!$graphyList) { return $this->createJsonResponse(401, ['error' => sprintf("Pas de liste trouvée pour cette id")]); @@ -148,6 +150,7 @@ class ApiGraphyListController extends ApiBaseController if ($missingFields = $this->getMissingFields($data, ['items'])) { return $this->createJsonResponse(401, ['error' => sprintf("Veuillez fournir une valeur pour: %s", implode(', ', $missingFields))]); } + $forceCreation = isset($data['force']) && $data['force'] === true; // Pour chaque mot suggéré par l'utilisateur, on cherche la graphie ou on la crée si elle n'existe pas // et on la lie à la liste @@ -158,10 +161,14 @@ class ApiGraphyListController extends ApiBaseController 'language' => $language, ]); if (!$graphy) { - $graphy = new Graphy(); - $graphy->setLanguage($language); - $graphy->setValue($item); - $this->doctrine->getManager()->persist($graphy); + if ($forceCreation || $wiktionaryManager->search($item, $language)) { + $graphy = new Graphy(); + $graphy->setLanguage($language); + $graphy->setValue($item); + $this->doctrine->getManager()->persist($graphy); + } else { + return $this->createJsonResponse(401, ['warning' => sprintf("Le mot «%s» n'existe pas dans le wiktionnaire.", $item)]); + } } $graphyList->addGraphy($graphy); diff --git a/src/Controller/LexiconController.php b/src/Controller/LexiconController.php index aa2fda5833ac965a958eb80c0c783351a69b7e98..4e907e8ec0de1d14cafb28bc58e5e408f4a26bf8 100644 --- a/src/Controller/LexiconController.php +++ b/src/Controller/LexiconController.php @@ -18,81 +18,23 @@ use Symfony\Component\Routing\Annotation\Route; class LexiconController extends AbstractController { /** - * @Route("/", name="app_graphy_list_index", methods={"GET"}) + * @Route("/", name="app_lexicon_index", methods={"GET"}) */ public function index(LexiconRepository $lexiconRepository): Response { - return $this->render('graphy_list/index.html.twig', [ - 'lexicons' => $lexiconRepository->findVisible($this->getUser()), + return $this->render('lexicon/index.html.twig', [ + 'lexicons' => $lexiconRepository->findAll(), ]); } /** - * @Route("/ajouter", name="app_graphy_list_new", methods={"GET", "POST"}) - */ - public function new(Request $request, LexiconRepository $lexiconRepository): Response - { - $lexicon = new Lexicon($this->getUser()); - $form = $this->createForm(LexiconType::class, $lexicon); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $lexicon->getLexicon()->setLanguage($form->get('language')->getData()); - $lexiconRepository->add($lexicon, true); - - return $this->redirectToRoute('app_graphy_list_index'); - } - - return $this->render('genericForm.html.twig', [ - 'title' => "Créer un lexicone", - 'form' => $form->createView(), - 'back_url' => $this->generateUrl('app_graphy_list_index'), - ]); - } - - /** - * @Route("/{id}", name="app_graphy_list_show", methods={"GET"}) - * @IsGranted("Lexicon_VIEW", subject="lexicon") + * @Route("/{id}", name="app_lexicon_show", methods={"GET"}) */ public function show(Lexicon $lexicon): Response { - return $this->render('graphy_list/show.html.twig', [ + return $this->render('lexicon/show.html.twig', [ 'lexicon' => $lexicon, ]); } - /** - * @Route("/{id}/modifier", name="app_graphy_list_edit", methods={"GET", "POST"}) - * @IsGranted("Lexicon_EDIT", subject="lexicon") - */ - public function edit(Request $request, Lexicon $lexicon, LexiconRepository $lexiconRepository): Response - { - $form = $this->createForm(LexiconType::class, $lexicon); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $lexiconRepository->add($lexicon, true); - - return $this->redirectToRoute('app_graphy_list_index'); - } - - return $this->render('genericForm.html.twig', [ - 'title' => "Modifier un lexicone", - 'form' => $form->createView(), - 'back_url' => $this->generateUrl('app_graphy_list_show', ['id' => $lexicon->getId()]), - ]); - } - - /** - * @Route("/{id}/supprimer", name="app_graphy_list_delete", methods={"POST"}) - * @IsGranted("Lexicon_DELETE", subject="lexicon") - */ - public function delete(Request $request, Lexicon $lexicon, LexiconRepository $lexiconRepository): Response - { - if ($this->isCsrfTokenValid('delete'.$lexicon->getId(), $request->request->get('_token'))) { - $lexiconRepository->remove($lexicon, true); - } - - return $this->redirectToRoute('app_graphy_list_index'); - } } diff --git a/src/Entity/Entry.php b/src/Entity/Entry.php index 017199be57b31c981cce965657105102156b50a9..33e80d4b47c73d8dddcfd06ea99173d70adc315d 100644 --- a/src/Entity/Entry.php +++ b/src/Entity/Entry.php @@ -83,6 +83,18 @@ class Entry return $this->getHeadword()->getValue(); } + public function getFormattedDefinitions() + { + $result = []; + foreach ($this->getAttributes()['Items'] as $item) { + $definitions = $item['Sense']['Definitions'] ?? []; + foreach ($definitions as $definition) { + $result[] = $item['PartOfSpeech'] . ' : ' . $definition['Def']; + } + } + return array_filter($result); + } + /** * @ORM\PrePersist * @ORM\PreUpdate diff --git a/src/Entity/Headword.php b/src/Entity/Headword.php index b821713e1b9e79b05ade01966b65ddb0b1affdd5..5e47cf15dfc15173c6de237f21616b415170accf 100644 --- a/src/Entity/Headword.php +++ b/src/Entity/Headword.php @@ -73,6 +73,62 @@ class Headword $this->labels = new ArrayCollection(); } + /** + * @return Label[] + */ + public function getMorphologicalLabels() + { + $result = []; + foreach ($this->getLabels() as $label) { + if ($label->isMorphological()) { + $result[] = $label; + } + } + return $result; + } + + /** + * @return Label[] + */ + public function getThematicLabels() + { + $result = []; + foreach ($this->getLabels() as $label) { + if ($label->isThematic()) { + $result[] = $label; + } + } + return $result; + } + + /** + * @return Label[] + */ + public function getListLabels() + { + $result = []; + foreach ($this->getLabels() as $label) { + if ($label->isList()) { + $result[] = $label; + } + } + return $result; + } + + /** + * @return Label[] + */ + public function getMilestoneLabels() + { + $result = []; + foreach ($this->getLabels() as $label) { + if ($label->isMilestone()) { + $result[] = $label; + } + } + return $result; + } + /** * @ORM\PrePersist * @ORM\PreUpdate @@ -196,8 +252,8 @@ class Headword } /** - * @return Collection<int, Label> - */ + * @return Collection|Label[] + */ public function getLabels(): Collection { return $this->labels; diff --git a/templates/base.html.twig b/templates/base.html.twig index 9482fb87c9d788c68374d7a642a01f544516c79d..befd3f5fbb698da7ab79547d5e3d8eef8ac0a496 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -21,7 +21,7 @@ {% include "nav.html.twig" %} {% endblock %} -<div class="container pt-2"> +<div class="{% block container %}container {% endblock %} pt-2"> {% block flash_messages %} <div id="flashes" class="row"> <div class="col-md-12"> diff --git a/templates/lexicon/index.html.twig b/templates/lexicon/index.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..14ec2aee6d53e680fa1152947bb6538173d136d9 --- /dev/null +++ b/templates/lexicon/index.html.twig @@ -0,0 +1,57 @@ +{% extends 'base.html.twig' %} +{% block container %}container-fluid{% endblock %} + +{% block title %}Lexiques{% endblock %} + +{% block body %} + + <div class="row justify-content-center m-5"> + <div class="col-md-12"> + <h3 class="card-title d-flex justify-content-between"> + Lexiques + </h3> + <div class="card mt-3"> + <div class="card-body"> + <table class="table"> + <thead> + <tr> + <th>Id</th> + <th>Langue</th> + <th>Type</th> + <th>Utilisateur</th> + <th>Groupe</th> + <th>Entrées</th> + <th>Listes liées</th> + <th>Date création</th> + <th></th> + </tr> + </thead> + <tbody> + {% for lexicon in lexicons %} + {# @var lexicon \App\Entity\Lexicon #} + <tr> + <td>{{ lexicon.id }}</td> + <td>{{ lexicon.language }}</td> + <td>{{ lexicon.category }}</td> + <td>{{ lexicon.user }}</td> + <td>{{ lexicon.group }}</td> + <td>{{ lexicon.entries|join(', ') }}</td> + <td>{% for graphyList in lexicon.graphyLists %}<span class="badge bg-primary">{{ graphyList }}</span> {% endfor %}</td> + <td>{{ lexicon.createdAt ? lexicon.createdAt|date('Y-m-d H:i:s') : '' }}</td> + <td class="text-end"> + <a href="{{ path('app_lexicon_show', {'id': lexicon.id}) }}" class="btn btn-dark btn-xs">Voir</a> + </td> + </tr> + {% else %} + <tr> + <td colspan="9">Aucun lexique</td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> + </div> + </div> + +{% endblock %} diff --git a/templates/lexicon/show.html.twig b/templates/lexicon/show.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..8df5ddd900cb37d38dd221d6a74fe4dc53742e6b --- /dev/null +++ b/templates/lexicon/show.html.twig @@ -0,0 +1,58 @@ +{% extends 'base.html.twig' %} +{% block container %}container-fluid{% endblock %} + +{% block title %}Lexique {{ lexicon.id }}{% endblock %} + +{% block body %} + + <div class="row justify-content-center m-5"> + <div class="col-md-12"> + + <h1>Lexique {{ lexicon.id }}</h1> + <div class="card mt-4"> + <div class="card-body"> + + <h3 class="card-title d-flex justify-content-between"> + Entrées + </h3> + + <table class="table"> + <thead> + <tr> + <th>Mot-vedette</th> + <th>Morphologie</th> + <th>Thématique</th> + <th>Listes</th> + <th>Objectifs</th> + <th>Définitions</th> + <th>Création</th> + <th>Mise à jour</th> + </tr> + </thead> + <tbody> + {% for entry in lexicon.entries %} + {# @var entry \App\Entity\Entry #} + <tr> + <td>{{ entry }}</td> + <td>{% for label in entry.headword.morphologicalLabels %}<span class="badge bg-primary">{{ label }}</span> {% endfor %}</td> + <td>{% for label in entry.headword.thematicLabels %}<span class="badge bg-secondary">{{ label }}</span> {% endfor %}</td> + <td>{% for label in entry.headword.listLabels %}<span class="badge bg-info">{{ label }}</span> {% endfor %}</td> + <td>{% for label in entry.headword.milestoneLabels %}<span class="badge bg-warning">{{ label }}</span> {% endfor %}</td> + <td> + {% for definition in entry.formattedDefinitions %} + <i class="bi-caret-right-fill"></i> {{ definition }}<br> + {% endfor %} + </td> + <td>{{ entry.createdAt ? entry.createdAt|date('Y-m-d H:i:s') : '' }}</td> + <td>{{ entry.updatedAt ? entry.updatedAt|date('Y-m-d H:i:s') : '' }}</td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> + + </div> + </div> + +{% endblock %} diff --git a/templates/nav.html.twig b/templates/nav.html.twig index 7e19cadbbf2076f18cfd3cd5086d2f2a97bcc716..c01583eeafb58c1ec85ad833031cfbe7af39a95f 100644 --- a/templates/nav.html.twig +++ b/templates/nav.html.twig @@ -20,6 +20,9 @@ <li class="nav-item"> <a class="nav-link {{ 'app_user_index' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_user_index') }}">Utilisateurs</a> </li> + <li class="nav-item"> + <a class="nav-link {{ 'app_lexicon_index' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_lexicon_index') }}">Lexiques</a> + </li> <li class="nav-item"> <a class="nav-link" href="{{ path('app.swagger_ui') }}">Swagger</a> </li>