From 199930d23a4ec4ae909c56f84c0fb9c1289763da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 11 Dec 2019 16:08:16 +0100 Subject: [PATCH] [wip] add actions to crud --- CHANGELOG.md | 1 + CRUD/Controller/CRUDController.php | 79 ++++++++++++------- CRUD/Resolver/Resolver.php | 53 ++++++++++++- CRUD/Templating/TwigCRUDResolver.php | 14 ++++ DependencyInjection/Configuration.php | 4 + Resources/config/services/crud.yml | 1 + .../public/sass/custom/_record_actions.scss | 1 + .../public/sass/custom/modules/_buttons.scss | 15 +++- .../public/sass/custom/modules/copy-solid.svg | 4 + Resources/translations/messages.fr.yml | 21 ++++- Resources/views/CRUD/_edit_content.html.twig | 28 ++++++- Resources/views/CRUD/_edit_title.html.twig | 2 +- Resources/views/CRUD/_new_content.html.twig | 22 +++++- Resources/views/CRUD/_view_content.html.twig | 46 +++++++++++ Resources/views/CRUD/_view_title.html.twig | 1 + Resources/views/CRUD/view.html.twig | 10 +++ 16 files changed, 265 insertions(+), 37 deletions(-) create mode 100644 Resources/public/sass/custom/modules/copy-solid.svg create mode 100644 Resources/views/CRUD/_view_content.html.twig create mode 100644 Resources/views/CRUD/_view_title.html.twig create mode 100644 Resources/views/CRUD/view.html.twig diff --git a/CHANGELOG.md b/CHANGELOG.md index 355a69d02..da3b1c469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,3 +96,4 @@ Version 1.5.14 Branch CRUD-Init ================ +- create an api for rendering entities diff --git a/CRUD/Controller/CRUDController.php b/CRUD/Controller/CRUDController.php index 85bf34493..70f6e9a75 100644 --- a/CRUD/Controller/CRUDController.php +++ b/CRUD/Controller/CRUDController.php @@ -31,6 +31,7 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Chill\MainBundle\CRUD\Resolver\Resolver; /** * @@ -161,7 +162,8 @@ class CRUDController extends AbstractController } $defaultTemplateParameters = [ - 'entity' => $entity + 'entity' => $entity, + 'crud_name' => $this->getCrudName() ]; return $this->render( @@ -193,17 +195,15 @@ class CRUDController extends AbstractController $em->flush(); $this->onPostFlush($action, $entity, $form, $request); - $this->addFlash('succes', $this->generateFormSuccessMessage($action, $entity)); + $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); - $result = $this->onBeforeRedirect($action, $entity, $form, $request); + $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); if ($result instanceof Response) { return $result; } - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index', [ - 'id' => $entity->getId() - ]); + return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index'); } elseif ($form->isSubmitted()) { $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); @@ -223,7 +223,11 @@ class CRUDController extends AbstractController protected function formCreateAction($action, Request $request, $formClass = null): Response { - $entity = $this->createEntity($action, $request); + if ($request->query->has('duplicate')) { + $entity = $this->duplicateEntity($action, $request); + } else { + $entity = $this->createEntity($action, $request); + } $this->checkACL($action, $entity); @@ -243,9 +247,9 @@ class CRUDController extends AbstractController $em->flush(); $this->onPostFlush($action, $entity, $form, $request); $this->getPaginatorFactory(); - $this->addFlash('succes', $this->generateFormSuccessMessage($action, $entity)); + $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); - $result = $this->onBeforeRedirect($action, $entity, $form, $request); + $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); if ($result instanceof Response) { return $result; @@ -280,9 +284,17 @@ class CRUDController extends AbstractController return $this->getDoctrine() ->getRepository($this->getEntityClass()) ->find($id); - + } + + protected function duplicateEntity(string $action, Request $request) + { + $id = $request->query->get('duplicate_id', 0); + $originalEntity = $this->getEntity($action, $id, $request); + $this->getDoctrine()->getManager() + ->detach($originalEntity); + return $originalEntity; } protected function getEntityClass(): string @@ -311,14 +323,7 @@ class CRUDController extends AbstractController protected function buildDefaultRole($action) { - if (empty($this->crudConfig['base_role'])) { - throw new \LogicException(sprintf("the base role is not defined. You must define " - . "on or override %s or %s methods", __METHOD__, "getRoleFor")); - } - - return \strtoupper( - $this->crudConfig['base_role']. - '_'. + return $this->getCrudResolver()->buildDefaultRole($this->getCrudName(), $action); } @@ -334,21 +339,19 @@ class CRUDController extends AbstractController $form = $this->createForm($formClass, $entity, $formOptions); - $this->addDefaultButtons($action, $form); + $this->customizeForm($action, $form); return $form; } - protected function addDefaultButtons($action, FormInterface $form) + protected function customizeForm($action, FormInterface $form) { - $form->add('submit', SubmitType::class, [ - 'label' => $this->generateLabelForButton($action, 'submit', $form) - ]); + } protected function generateLabelForButton($action, $formName, $form) { - return $action; + return sprintf("crud.%s.button_action_form", $action); } protected function generateFormErrorMessage($action, FormInterface $form): string @@ -362,13 +365,13 @@ class CRUDController extends AbstractController { switch ($action) { case 'edit': - $msg = "The data have been successfully updated"; + $msg = "crud.edit.success"; break; case 'new': - $msg = "The date have been successfully created"; + $msg = "crud.new.success"; break; default: - $msg = "Your request has been successfully executed"; + $msg = "crud.default.success"; } return $this->getTranslator()->trans($msg); @@ -403,6 +406,8 @@ class CRUDController extends AbstractController return '@ChillMain/CRUD/edit.html.twig'; case 'index': return '@ChillMain/CRUD/index.html.twig'; + case 'view': + return '@ChillMain/CRUD/view.html.twig'; default: throw new \LogicException("the view for action $action is not " . "defined. You should override ".__METHOD__." to add this " @@ -445,8 +450,20 @@ class CRUDController extends AbstractController { } - protected function onBeforeRedirect(string $action, $entity, FormInterface $form, Request $request) + protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request) { + $next = $request->request->get("submit", "save-and-close"); + + switch ($next) { + case "save-and-close": + return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index'); + case "save-and-new": + return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_new'); + default: + return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', [ + 'id' => $entity->getId() + ]); + } } protected function getActionConfig(string $action) @@ -481,6 +498,11 @@ class CRUDController extends AbstractController return $this->get(EventDispatcherInterface::class); } + protected function getCrudResolver(): Resolver + { + return $this->get(Resolver::class); + } + public static function getSubscribedServices() { return \array_merge( @@ -490,6 +512,7 @@ class CRUDController extends AbstractController 'translator' => TranslatorInterface::class, AuthorizationHelper::class => AuthorizationHelper::class, EventDispatcherInterface::class => EventDispatcherInterface::class, + Resolver::class => Resolver::class, ] ); } diff --git a/CRUD/Resolver/Resolver.php b/CRUD/Resolver/Resolver.php index 0eac94d01..2475efd42 100644 --- a/CRUD/Resolver/Resolver.php +++ b/CRUD/Resolver/Resolver.php @@ -41,10 +41,35 @@ class Resolver */ protected $propertyAccess; - function __construct(EntityManagerInterface $em) + /** + * + * @var array + */ + protected $crudConfig; + + /** + * @deprecated + */ + const ROLE_VIEW = 'role.view'; + + /** + * @deprecated + */ + const ROLE_EDIT = 'role.edit'; + + /** + * The key to get the role necessary for the action + */ + const ROLE = 'role'; + + function __construct(EntityManagerInterface $em, array $crudConfig) { $this->em = $em; + foreach($crudConfig as $conf) { + $this->crudConfig[$conf['name']] = $conf; + } + $this->buildPropertyAccess(); } @@ -69,13 +94,37 @@ class Resolver return $this->propertyAccess->getValue($entity, $path); } + public function getConfigValue($key, $crudName, $action = null) + { + $config = $this->crudConfig[$crudName]; + + switch ($key) { + case self::ROLE: + dump($config); + return $config['actions'][$action]['role'] ?? $this->buildDefaultRole($crudName, $action); + } + } + + public function buildDefaultRole($crudName, $action) + { + if (empty($this->crudConfig[$crudName]['base_role'])) { + throw new \LogicException(sprintf("the base role is not defined. You must define " + . "on or override %s or %s methods", __METHOD__, "getRoleFor")); + } + + return \strtoupper( + $this->crudConfig[$crudName]['base_role']. + '_'. + $action); + } + public function getTwigTemplate($entity, $path): string { list($focusEntity, $subPath) = $this->getFocusedEntity($entity, $path); $classMetadata = $this->em->getClassMetadata(\get_class($focusEntity)); $type = $classMetadata->getTypeOfField($subPath); - dump($type); + switch ($type) { default: diff --git a/CRUD/Templating/TwigCRUDResolver.php b/CRUD/Templating/TwigCRUDResolver.php index ca398814c..9c83df864 100644 --- a/CRUD/Templating/TwigCRUDResolver.php +++ b/CRUD/Templating/TwigCRUDResolver.php @@ -22,6 +22,7 @@ namespace Chill\MainBundle\CRUD\Templating; use Chill\MainBundle\CRUD\Resolver\Resolver; use Twig\TwigFilter; +use Twig\TwigFunction; use Twig\Extension\AbstractExtension; use Twig\Environment; @@ -50,6 +51,14 @@ class TwigCRUDResolver extends AbstractExtension ]; } + public function getFunctions() + { + return [ + new TwigFunction('chill_crud_config', [$this, 'getConfig'], + ['is_safe' => 'html']) + ]; + } + public function display(Environment $env, $entity, $path): string { $data = $this->resolver->getData($entity, $path); @@ -57,5 +66,10 @@ class TwigCRUDResolver extends AbstractExtension return $env->render($template, ['data' => $data, 'entity' => $entity, ]); } + + public function getConfig($configKey, $crudName, $action = null) + { + return $this->resolver->getConfigValue($configKey, $crudName, $action); + } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index bb15f3b42..f718ecdd9 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -154,6 +154,10 @@ class Configuration implements ConfigurationInterface ->defaultNull() ->info('the role that will be required for this action. Override option `base_role`') ->end() + ->scalarNode('template') + ->defaultNull() + ->info('the template to render the view') + ->end() ->end() ->end() ->end() diff --git a/Resources/config/services/crud.yml b/Resources/config/services/crud.yml index ab686d34e..478122b73 100644 --- a/Resources/config/services/crud.yml +++ b/Resources/config/services/crud.yml @@ -7,6 +7,7 @@ services: Chill\MainBundle\CRUD\Resolver\Resolver: arguments: $em: '@Doctrine\ORM\EntityManagerInterface' + $crudConfig: '%chill_main_crud_route_loader_config%' Chill\MainBundle\CRUD\Templating\TwigCRUDResolver: arguments: diff --git a/Resources/public/sass/custom/_record_actions.scss b/Resources/public/sass/custom/_record_actions.scss index 3cd9fc9a5..64ee66077 100644 --- a/Resources/public/sass/custom/_record_actions.scss +++ b/Resources/public/sass/custom/_record_actions.scss @@ -10,6 +10,7 @@ ul.record_actions, ul.record_actions_column { display: flex; justify-content: flex-end; padding: 0.5em 0; + flex-wrap: wrap-reverse; li { display: inline-block; diff --git a/Resources/public/sass/custom/modules/_buttons.scss b/Resources/public/sass/custom/modules/_buttons.scss index b465742f7..e070dcd57 100644 --- a/Resources/public/sass/custom/modules/_buttons.scss +++ b/Resources/public/sass/custom/modules/_buttons.scss @@ -1,7 +1,7 @@ .sc-button { margin-bottom: 0.5rem; - &.bt-submit, &.bt-save, &.bt-create, &.bt-new { + &.bt-submit, &.bt-save, &.bt-create, &.bt-new, &.bt-duplicate { @include button($green, $white); } @@ -19,6 +19,7 @@ &:not(.change-icon) { + // icons using font-awesome "old way" &.bt-create::before, &.bt-save::before, &.bt-new::before, @@ -31,6 +32,14 @@ font: normal normal normal 14px/1 FontAwesome; margin-right: 0.5em; } + + // icons using font-awesome "new svg way" + &.bt-duplicate::before { + display: inline-block; + width: 1em; + margin-right: 0.5em; + vertical-align: middle; + } &.bt-save::before { // add a floppy @@ -60,6 +69,10 @@ &.bt-show::before, &.bt-view::before { content: ""; } + + &.bt-duplicate::before { + content: url("./copy-solid.svg"); + } } > i.fa { diff --git a/Resources/public/sass/custom/modules/copy-solid.svg b/Resources/public/sass/custom/modules/copy-solid.svg new file mode 100644 index 000000000..6acdf87cd --- /dev/null +++ b/Resources/public/sass/custom/modules/copy-solid.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index b8990fca0..93c2c303d 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -229,4 +229,23 @@ Log in with your new password: Connectez-vous avec votre nouveau mot de passe # impersonate Exit impersonation: Retour Administrateur Impersonate: Mode fantôme -Impersonate mode: Mode fantôme \ No newline at end of file +Impersonate mode: Mode fantôme + +crud: + new: + button_action_form: Créer + link_edit: Modifier + save_and_close: Créer & fermer + save_and_show: Créer & voir + save_and_new: Créer & nouveau + success: Les données ont été créées + edit: + button_action_form: Enregistrer + back_to_view: Voir + save_and_close: Modifier & fermer + save_and_show: Modifier & voir + success: Les données ont été modifiées + default: + success: Les données ont été enregistrées + view: + link_duplicate: Dupliquer \ No newline at end of file diff --git a/Resources/views/CRUD/_edit_content.html.twig b/Resources/views/CRUD/_edit_content.html.twig index 9dcb7820a..0ede64748 100644 --- a/Resources/views/CRUD/_edit_content.html.twig +++ b/Resources/views/CRUD/_edit_content.html.twig @@ -1,13 +1,13 @@
{% block crud_content_header %} -

{{ 'crud.title.edit_of_%crud_name%'|trans({'%crud_name%' : crud_name }) }}

+

{{ ('crud.'~crud_name~'.title_edit')|trans }}

{% endblock crud_content_header %} {% block crud_content_form %} {{ form_start(form) }} {% block crud_content_form_rows %} - {% for f in form if f.vars.name != 'submit' %} + {% for f in form %} {{ form_row(f) }} {% endfor %} {% endblock crud_content_form_rows %} @@ -20,8 +20,30 @@ {{ 'Cancel'|trans }} + {% endblock %} + {% block content_form_actions_view %} + {% if is_granted(chill_crud_config('role', crud_name, 'view'), entity) %} +
  • + + {{ 'crud.edit.back_to_view'|trans }} + +
  • + {% endif %} {% endblock %} -
  • {{ form_widget(form.submit, { 'attr': { 'class': 'sc-button bt-edit'} } ) }}
  • + {% block content_form_actions_save_and_close %} +
  • + +
  • + {% endblock %} + {% block content_form_actions_save_and_show %} +
  • + +
  • + {% endblock %} {% endblock %} diff --git a/Resources/views/CRUD/_edit_title.html.twig b/Resources/views/CRUD/_edit_title.html.twig index c98b7f2cd..7561ceda4 100644 --- a/Resources/views/CRUD/_edit_title.html.twig +++ b/Resources/views/CRUD/_edit_title.html.twig @@ -1 +1 @@ -{{ 'crud.title.edit_of_%crud_name%'|trans({'%crud_name%' : crud_name }) }} +{{ ('crud.'~crud_name~'.title_edit')|trans }} diff --git a/Resources/views/CRUD/_new_content.html.twig b/Resources/views/CRUD/_new_content.html.twig index c01969e24..3da85d3ad 100644 --- a/Resources/views/CRUD/_new_content.html.twig +++ b/Resources/views/CRUD/_new_content.html.twig @@ -21,7 +21,27 @@ {% endblock %} -
  • {{ form_widget(form.submit, { 'attr': { 'class': 'sc-button bt-new'} } ) }}
  • + {% block content_form_actions_save_and_close %} +
  • + +
  • + {% endblock %} + {% block content_form_actions_save_and_show %} +
  • + +
  • + {% endblock %} + {% block content_form_actions_save_and_new %} +
  • + +
  • + {% endblock %} {% endblock %} diff --git a/Resources/views/CRUD/_view_content.html.twig b/Resources/views/CRUD/_view_content.html.twig new file mode 100644 index 000000000..39cf85359 --- /dev/null +++ b/Resources/views/CRUD/_view_content.html.twig @@ -0,0 +1,46 @@ +
    + {% block crud_content_header %} +

    {{ 'crud.%crud_name%.title_view'|trans({'%crud_name%' : crud_name }) }}

    + {% endblock crud_content_header %} + + {% block crud_content_view %} + + {% block crud_content_view_details %} +
    +
    id
    +
    {{ entity.id|default("No id") }}
    +
    + {% endblock crud_content_view_details %} + + {% block crud_content_view_actions %} +
      + {% block content_view_actions_back %} +
    • + + {{ 'Cancel'|trans }} + +
    • + {% endblock %} + {% block content_view_actions_duplicate_link %} + {% if is_granted(chill_crud_config('role', crud_name, 'new'), entity) %} +
    • + + {{ 'crud.view.link_duplicate'|trans }} + +
    • + {% endif %} + {% endblock content_view_actions_duplicate_link %} + {% block content_view_actions_edit_link %} + {% if is_granted(chill_crud_config('role', crud_name, 'view'), entity) %} +
    • + + {{ 'crud.new.link_edit'|trans }} + +
    • + {% endif %} + {% endblock content_view_actions_edit_link %} +
    + {% endblock crud_content_view_actions %} + + {% endblock crud_content_view %} +
    diff --git a/Resources/views/CRUD/_view_title.html.twig b/Resources/views/CRUD/_view_title.html.twig new file mode 100644 index 000000000..3473dd298 --- /dev/null +++ b/Resources/views/CRUD/_view_title.html.twig @@ -0,0 +1 @@ +{{ 'crud.%crud_name%.title_view'|trans({'%crud_name%' : crud_name }) }} \ No newline at end of file diff --git a/Resources/views/CRUD/view.html.twig b/Resources/views/CRUD/view.html.twig new file mode 100644 index 000000000..f32234a33 --- /dev/null +++ b/Resources/views/CRUD/view.html.twig @@ -0,0 +1,10 @@ +{% extends '@ChillMain/layout.html.twig' %} + +{% block title %} +{% include('@ChillMain/CRUD/_view_title.html.twig') %} +{% endblock %} + +{% block content %} +{% embed '@ChillMain/CRUD/_view_content.html.twig' %} +{% endembed %} +{% endblock %}