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 %}
+
+ {% 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 %}