diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 6932c929a11718933320eba5bfad10f17d005dae..b2d93a2b6fd1b05eb2f0df83c356769017a99c4e 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -5,6 +5,7 @@ twig: languages: '@App\Manager\LanguagesManager' label_manager: '@App\Manager\LabelManager' lexicon_manager: '@App\Manager\LexiconManager' + entry_manager: '@App\Manager\EntryManager' when@test: twig: diff --git a/public/assets/css/app.css b/public/assets/css/app.css index 7a13821c8e60bc048ec2a764135f9980a7d19eb6..15950b070fd1acc92876e098374a2cb4702a254a 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -1,7 +1,3 @@ -.bg-dark-gray { - background-color: darkgrey; -} - /* AJAX LOADING */ #overlay { position: fixed; @@ -149,6 +145,19 @@ table.label-table > tbody > tr > td { background-color: #b5e0b5; } +.text-grey { + color:lightgrey; +} +p:hover .fa.text-grey { + color: dimgrey; +} +.text-light-green { + color:lightgreen; +} +p:hover .fa.text-light-green { + color: limegreen; +} + .bg-label-personal { background-color: #d9f2ff; } @@ -173,6 +182,13 @@ table.label-table > tbody > tr > td { .bg-dark-pink { background-color: #FFE4E4; } +.bg-light-grey { + background-color: #f3f3f3; +} +.bg-dark-gray { + background-color: darkgrey; +} + .badge.badge-milestone { line-height: 1.3; padding-top: 0; @@ -238,4 +254,20 @@ table.label-table > tbody > tr > td { #tabContent #tableLabels { background-color: white; +} + +#entryAttributes p { + margin-bottom: 0.5rem; +} + +#entryAttributes h4 { + color: #0a53be; +} +.left-border-blue { + border-left: 4px solid #0a53be; + +} + +#entryAttributes { + font-size: .8rem; } \ No newline at end of file diff --git a/src/Controller/EntryController.php b/src/Controller/EntryController.php index 90d0e04a561a3584230ece2a91915000e713074c..6d28953d6b0e0fb788f67d89c5be10dad057da95 100644 --- a/src/Controller/EntryController.php +++ b/src/Controller/EntryController.php @@ -6,6 +6,7 @@ use App\Entity\Entry; use App\Entity\Label; use App\Entity\Lexicon; use App\Entity\Log; +use App\Form\BlockType; use App\Form\SearchStringType; use App\Manager\LabelManager; use App\Repository\EntryRepository; @@ -14,6 +15,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Routing\Annotation\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; @@ -27,7 +29,6 @@ class EntryController extends AppBaseController */ public function show(LabelManager $labelManager, Request $request, Entry $entry) { - return $this->render('entry/show.html.twig', array( 'entry' => $entry, )); @@ -159,4 +160,55 @@ class EntryController extends AppBaseController // return $this->redirectToRoute('app_lexicon_show', ['id' => $entry->getLexicon()->getId()]); } + + /** + * @Route("/{id}/edit-block/{blockId}", name="app_entry_edit_block", methods={"GET", "POST"}) + */ + public function editBlock(Request $request, Entry $entry, $blockId): Response + { + $attributes = $entry->getAttributes(); + $propertyAccessor = PropertyAccess::createPropertyAccessor(); + $block = $propertyAccessor->getValue($attributes, $blockId); + + $form = $this->createForm(BlockType::class, ['block' => $block], [ + 'action' => $this->generateUrl('app_entry_edit_block', [ + 'id' => $entry->getId(), + 'blockId' => $blockId + ]) + ]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $propertyAccessor->setValue($attributes, $blockId, $form->get('block')->getData()); + $entry->setAttributes($attributes); + $this->em->flush(); + + return $this->render('closeModalAndReload.html.twig'); + } + + return $this->render('genericModalForm.html.twig', [ + 'title' => "Modifier le bloc", + 'form' => $form->createView(), + ]); + } + /** + * @Route("/{id}/delete-block/{blockId}", name="app_entry_delete_block", methods={"GET", "POST"}) + */ + public function deleteBlock(Request $request, Entry $entry, $blockId): Response + { + $attributes = $entry->getAttributes(); + $propertyAccessor = PropertyAccess::createPropertyAccessor(); + $block = $propertyAccessor->getValue($attributes, $blockId); + preg_match("/(.*)\[([^]]+)\]$/", $blockId, $matches); + $parentId = $matches[1]; + $childId = $matches[2]; + $parentBlock = $propertyAccessor->getValue($attributes, $parentId); + + unset($parentBlock[$childId]); + $propertyAccessor->setValue($attributes, $parentId, $parentBlock); + $entry->setAttributes($attributes); + $this->em->flush(); + + return $this->redirectToRoute('app_entry_show', ['id' => $entry->getId()]); + } } diff --git a/src/Controller/WiktionnaryController.php b/src/Controller/WiktionnaryController.php index c04f9c5e423e91dd49ac407940d009941e370e58..f12c091102e874cb4b738f28439a0283e1ff45b3 100644 --- a/src/Controller/WiktionnaryController.php +++ b/src/Controller/WiktionnaryController.php @@ -7,10 +7,12 @@ use App\Entity\Label; use App\Entity\Log; use App\Form\SearchStringType; use App\Manager\LabelManager; +use App\Manager\WiktionaryManager; use App\Repository\EntryRepository; use Doctrine\Persistence\ManagerRegistry; use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -21,6 +23,25 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; */ class WiktionnaryController extends AppBaseController { + /** + * @Route("/search", name="app_wiktionnary_search", requirements={"id" = "\d+"}) + */ + public function searchWiktionary(Request $request, WiktionaryManager $wiktionaryManager) + { + $form = $this->createForm(SearchStringType::class,null, array('method' => 'GET')); + $form->handleRequest($request); + if ($search = $form->get('searchString')->getData()) { + $wikData = $wiktionaryManager->search($search, $this->getLanguage()); + $entryAttributes = $wiktionaryManager->extractWiktionaryData($wikData, $extractedMorphologicallabels); + } + + return $this->render('entry/showWiktionnaryData.html.twig', array( + 'result' => $wikData ?? null, + 'entryAttributes' => $entryAttributes ?? null, + 'form' => $form->createView(), + )); + } + /** * PAS UTILISÉ * diff --git a/src/Form/BlockType.php b/src/Form/BlockType.php new file mode 100644 index 0000000000000000000000000000000000000000..9353f080f02169a07b15059d2ed8b5aac6d43edf --- /dev/null +++ b/src/Form/BlockType.php @@ -0,0 +1,47 @@ +<?php + +namespace App\Form; + +use App\Entity\Label; +use App\Entity\User; +use App\Languages\LanguagesIso; +use App\Repository\GroupRepository; +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\DateTimeType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class BlockType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('block', TextType::class, [ + 'label' => false, + ]) + ; + + $builder + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'user' => null, + 'attr' => [ + 'data-ajax-form' => '', + 'data-ajax-form-target' => '#bootstrap-modal .modal-content', + 'novalidate' => 'novalidate', + ], + ]); + } +} diff --git a/src/Manager/EntryManager.php b/src/Manager/EntryManager.php new file mode 100644 index 0000000000000000000000000000000000000000..324537178cfd4c5ff735e879bd91e757cb2e16b4 --- /dev/null +++ b/src/Manager/EntryManager.php @@ -0,0 +1,65 @@ +<?php + +namespace App\Manager; + +use App\Entity\Entry; +use App\Entity\Group; +use App\Entity\Headword; +use App\Entity\Label; +use App\Entity\LabelVisibility; +use App\Entity\Lexicon; +use App\Entity\User; +use App\Languages\LanguagesIso; +use Doctrine\Persistence\ManagerRegistry; +use JsonSchema\Validator; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Serializer\SerializerAwareInterface; +use Symfony\Component\Serializer\SerializerInterface; + +class EntryManager +{ + /** + * @var ManagerRegistry + */ + protected $doctrine; + + protected $searchString; + + public function __construct(ManagerRegistry $doctrine) + { + $this->doctrine = $doctrine; + } + + public function getPronunciations(Entry $entry) + { + return $this->getPronunciationsFromSense($this->getSenseFromItem($this->getItems($entry)[0])); + } + + public function getItems(Entry $entry) + { + return $entry->getAttributes()['Items']; + } + + public function getSenseFromItem($item) + { + return $item["Sense"]; + } + + public function getPartOfSpeechFromItem($item) + { + return $item["PartOfSpeech"]; + } + + public function getDefinitionsFromItem($item) + { + return $item["Sense"]["Definitions"]; + } + + public function getPronunciationsFromSense($sense) + { + return $sense["Pronunciations"]; + } + +} diff --git a/src/Manager/WiktionaryManager.php b/src/Manager/WiktionaryManager.php index d6b20996506771fb093403248096b32eb57ec73e..77c7e63352a66f506fe0606c0b0108effe27ee33 100644 --- a/src/Manager/WiktionaryManager.php +++ b/src/Manager/WiktionaryManager.php @@ -83,8 +83,7 @@ class WiktionaryManager throw new \Exception($message); } - // On ajoute automatiquement les labels extrait du wiktionnaire sur le mot-vedette - $headword = $entry->getHeadword(); + // On ajoute automatiquement les labels extraits du wiktionnaire sur le mot-vedette foreach ($morphologicalLabels as $morphologicalLabel) { $label = $this->getOrCreateMorphologicalLabel($morphologicalLabel); $entry->getHeadword()->addLabel($label); @@ -170,6 +169,9 @@ class WiktionaryManager $definition['Examples'] = $examples; } + // TODO Extraction des trads : mais c'est tjs vide dans le wiko, on ne connait pas la structure + + $result[] = $definition; } diff --git a/templates/entry/_entryAttributes.html.twig b/templates/entry/_entryAttributes.html.twig index 28f6ae85fdd242d6856a41b6f94560d960b3a924..47c88796244358bde067aea977cba8a11d130aaf 100644 --- a/templates/entry/_entryAttributes.html.twig +++ b/templates/entry/_entryAttributes.html.twig @@ -1 +1,60 @@ -{{ dump(entry.attributes) }} \ No newline at end of file +<div id="entryAttributes" class="ps-5"> + {{ dump(entry.attributes) }} + + <h4>{{ "Pronunciations"|trans }}</h4> + <div class="ms-1 ps-4"> + {% for pronunciation in entry_manager.pronunciations(entry) %} + {{ pronunciation.accent }} : {{ pronunciation.api }}<br> + {% endfor %} + </div> + + {% set attr = entry.attributes %} + + {% for key, item in attr.Items %} + {######### SET KEY ##########} + {% set itemKey = '[Items]['~key~']' %} + + <h4>{{ entry_manager.partOfSpeechFromItem(item)|trans }}</h4> + + <div class="ms-1 ps-4 left-border-blue bg-light-grey"> + + {% for key, definition in item.Sense.Definitions %} + {######### SET KEY ##########} + {% set definitionKey = itemKey~'[Sense][Definitions]['~key~']' %} + + <div class="mb-3"> + + <p class="fw-bold">{{ loop.index }}. {{ definition.Def }}</p> + + {% for key, example in definition.Examples|default([]) %} + {######### SET KEY ##########} + {% set exampleKey = definitionKey~'[Examples]['~key~']' %} + + <p class="fst-italic"> + {{ example }} + {{ _self.actions(entry, exampleKey, ['edit', 'delete']) }} + </p> + {% endfor %} + + </div> + {% endfor %} + </div> + + {% endfor %} + +</div> + +{% macro actions(entry, key, operations) %} + {% if 'create' in operations %} + <a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: key}) }}" class="modal-form"><i class="fa fa-plus-circle fa-lg text-light-green" title="{{ key }}"></i></a> + {% endif %} + {% if 'edit' in operations %} + <a href="#" data-url="{{ path('app_entry_edit_block', {id: entry.id, blockId: key}) }}" class="modal-form"><i class="fa fa-pencil-square fa-lg text-grey" title="{{ key }}"></i></a> + {% endif %} + {% if 'delete' in operations %} + <a href="#" data-href="{{ path('app_entry_delete_block', {id: entry.id, blockId: key}) }}" + data-confirm="{{ "Confirmer la suppression ?"|trans }}" data-bs-toggle="modal" data-bs-target="#confirm-dialog"><i class="fa fa-trash fa-lg text-grey" title="{{ key }}"></i></a> + {% endif %} + +{% endmacro %} + diff --git a/templates/entry/show.html.twig b/templates/entry/show.html.twig index 71ffa1fb14cd118a9a1863fc42642885c2570dcf..c9b922b0fc4388aef0bc6440e5bff1e6d2a143f3 100644 --- a/templates/entry/show.html.twig +++ b/templates/entry/show.html.twig @@ -38,9 +38,13 @@ <div id="tabContent" class="{{ entry.lexicon.zero ? 'tab-wiktionnary' }}"> <div class="row"> - <div class="col-sm-6"> + <div class="col-sm-6 col-lg-4"> {% include "entry/_entryLabels.html.twig" %} + </div> + </div> + <div class="row"> + <div class="col-sm-9"> {% include "entry/_entryAttributes.html.twig" %} </div> </div> diff --git a/templates/entry/showWiktionnaryData.html.twig b/templates/entry/showWiktionnaryData.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..ff529c041cd724d52ce63222152b1fd200d107b2 --- /dev/null +++ b/templates/entry/showWiktionnaryData.html.twig @@ -0,0 +1,41 @@ +{% extends 'base.html.twig' %} +{% import 'macros.html.twig' as macros %} +{% block container %}container-fluid{% endblock %} + +{% block title %}{{ "Wiktionnaire"|trans }}{% endblock %} + +{% block body %} + + <div class="row justify-content-center m-lg-5 m-sm-3"> + <div class="col-md-12"> + + <div class="row mt-4"> + <div class="col-sm-3"> + {{ form_start(form) }} + <div class="d-flex justify-content-between"> + {{ form_widget(form.searchString) }} + <button type="submit" title="{{ "Filtrer"|trans }}" class="btn btn-block btn-dark" style="margin-left: 10px"> + <i class="fa fa-search"></i> + </button> + <a href="{{ path('app_label_index') }}" title="{{ "Réinitialiser"|trans }}" class="btn btn-block btn-light" style="margin-left: 10px"> + <i class="fa fa-times"></i> + </a> + </div> + {{ form_end(form) }} + </div> + </div> + + <p> + Wiktionnary + {{ dump(result) }} + </p> + + <p> + Attributes + {{ dump(entryAttributes) }} + </p> + + </div> + </div> + +{% endblock %} diff --git a/templates/nav.html.twig b/templates/nav.html.twig index 8af2724e577323028383a5cee052563b67540683..b8cefd8f3b3b9c648cbe88c3f90123e58f41ffac 100644 --- a/templates/nav.html.twig +++ b/templates/nav.html.twig @@ -55,6 +55,9 @@ <li class="nav-item"> <a class="nav-link" href="{{ path('app.swagger_ui') }}"><i class="bi bi-terminal"></i> Swagger</a> </li> + <li class="nav-item"> + <a class="nav-link" href="{{ path('app_wiktionnary_search') }}"><i class="bi bi-book"></i> {{ "Wiktionnaire"|trans }}</a> + </li> {% endif %} diff --git a/translations/messages.fr.yaml b/translations/messages.fr.yaml index a1364079e688b628e3973392ea1443073d6cd8d4..8dfd9d9af08467a40c8b8239ccf6b88586c824da 100644 --- a/translations/messages.fr.yaml +++ b/translations/messages.fr.yaml @@ -2,3 +2,12 @@ "personal" : "Personnel" "group" : "Groupe" "public" : "Public" +"N": "Nom" +"V": "Verbe" +"Interj": "Interjection" +"Adj": "Adjectif" +"Adv": "Adverbe" +"Det": "Déterminant" +"Pro": "Pronom" +"Conj": "Conjonction" +"Prep": "Préposition" \ No newline at end of file