Parcourir la source

AdminLte intégration action sort

tags/0.1
Fab il y a 3 ans
Parent
révision
bd321231f9
13 fichiers modifiés avec 390 ajouts et 17 suppressions
  1. +127
    -2
      Controller/Admin/AbstractCrudController.php
  2. +1
    -0
      Controller/Admin/DashboardController.php
  3. +1
    -1
      Field/FileManagerField.php
  4. +1
    -2
      Field/GalleryManagerField.php
  5. +1
    -1
      Field/ImageManagerField.php
  6. +2
    -9
      Form/Type/Crud/CrudFormType.php
  7. +1
    -1
      Form/Type/Crud/FileManagerType.php
  8. +25
    -0
      Form/Type/Crud/PositionType.php
  9. +4
    -0
      Resources/assets/app/adminlte/sort/app.sort.js
  10. +39
    -0
      Resources/assets/app/adminlte/sort/sort.js
  11. +45
    -0
      Resources/assets/app/adminlte/sort/sort.scss
  12. +1
    -1
      Resources/config/services.yml
  13. +142
    -0
      Resources/views/adminlte/crud/sort.html.twig

+ 127
- 2
Controller/Admin/AbstractCrudController.php Voir le fichier

@@ -2,22 +2,39 @@

namespace Lc\SovBundle\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityUpdatedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\PaginatorFactory;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
use Lc\SovBundle\Doctrine\Extension\SeoInterface;
use Lc\SovBundle\Doctrine\Extension\SortableInterface;
use Lc\SovBundle\Doctrine\Extension\TranslatableInterface;
use Lc\SovBundle\Field\CollectionField;
use Lc\SovBundle\Field\GalleryManagerField;
use Lc\SovBundle\Form\Type\Crud\PositionType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
@@ -50,7 +67,6 @@ abstract class AbstractCrudController extends EaAbstractCrudController
}
);
}

/* Boutons des actions dans les listes */
$actionsArray[Crud::PAGE_INDEX] = [
Action::NEW => [
@@ -107,6 +123,14 @@ abstract class AbstractCrudController extends EaAbstractCrudController
$actions->add(Crud::PAGE_EDIT, Action::DELETE);
$actions->add(Crud::PAGE_NEW, Action::INDEX);

if (in_array(SortableInterface::class, class_implements($this->getEntityFqcn()))) {
$sortAction = Action::new('sort', 'Ordonner', 'fa fa-sort')
->linkToCrudAction('sort')
->setCssClass('btn btn-info')
->createAsGlobalAction();

$actions->add(Crud::PAGE_INDEX, $sortAction);
}
$actions->reorder(Crud::PAGE_EDIT, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_CONTINUE]);
$actions->reorder(Crud::PAGE_NEW, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_ADD_ANOTHER]);

@@ -182,6 +206,105 @@ abstract class AbstractCrudController extends EaAbstractCrudController
return $responseParameters;
}


public function sort(AdminContext $context)
{
$event = new BeforeCrudActionEvent($context);
$this->get('event_dispatcher')->dispatch($event);
if ($event->isPropagationStopped()) {
return $event->getResponse();
}

if (!$this->isGranted(Permission::EA_EXECUTE_ACTION) || !in_array(
SortableInterface::class,
class_implements($this->getEntityFqcn())
)) {
throw new ForbiddenActionException($context);
}

$fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
$filters = $this->get(FilterFactory::class)->create(
$context->getCrud()->getFiltersConfig(),
$fields,
$context->getEntity()
);
$queryBuilder = $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters);
$paginator = $this->get(PaginatorFactory::class)->create($queryBuilder);

$entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults());
$this->get(EntityFactory::class)->processFieldsForAll($entities, $fields);

$sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults()))
->add(
'entities',
CollectionType::class,
array(
'required' => true,
'allow_add' => true,
'entry_type' => PositionType::class,
)
)
->getForm();

$entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn());
$repository = $entityManager->getRepository($this->getEntityFqcn());

$sortableForm->handleRequest($context->getRequest());

if ($sortableForm->isSubmitted() && $sortableForm->isValid()) {
// $entityInstance = $event->getEntityInstance();

foreach ($sortableForm->get('entities')->getData() as $elm) {
$entityInstance = $repository->find($elm['id']);
$entityDto = $context->getEntity()->newWithInstance($entityInstance);

if (!$entityDto->isAccessible()) {
throw new InsufficientEntityPermissionException($context);
}

$event = new BeforeEntityDeletedEvent($entityInstance);
$this->get('event_dispatcher')->dispatch($event);
$entityInstance = $event->getEntityInstance();

$entityInstance->setPosition($elm['position']);
$this->updateEntity($entityManager, $entityInstance);

$this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance));
}

$url = $this->get(AdminUrlGenerator::class)
->setAction(Action::INDEX)
->generateUrl();
$this->addFlash('success', 'Position modifié', array(), 'mweb');

return $this->redirect($url);
}

$responseParameters = $this->configureResponseParameters(
KeyValueStore::new(
[
'pageName' => Crud::PAGE_INDEX,
'templatePath' => '@LcSov/adminlte/crud/sort.html.twig',
'entities' => $entities,
'paginator' => $paginator,
'global_actions' => array(),
'batch_actions' => array(),
'filters' => $filters,
'sortable_form' => $sortableForm,
]
)
);
$responseParameters->set('fields', $this->configureFields('index'));
$event = new AfterCrudActionEvent($context, $responseParameters);
$this->get('event_dispatcher')->dispatch($event);
if ($event->isPropagationStopped()) {
return $event->getResponse();
}

return $responseParameters;
}


public function configureFields(string $pageName): iterable
{
if (in_array(SeoInterface::class, class_implements($this->getEntityFqcn()))) {
@@ -194,7 +317,9 @@ abstract class AbstractCrudController extends EaAbstractCrudController
'Affiché dans les résultats de recherche Google'
)->hideOnIndex(),
CollectionField::new('oldUrls')
->setFormTypeOption('entry_type', TextType::class)->setLabel('Anciennes urls du document')->hideOnIndex()
->setFormTypeOption('entry_type', TextType::class)->setLabel(
'Anciennes urls du document'
)->hideOnIndex(),
];
}


+ 1
- 0
Controller/Admin/DashboardController.php Voir le fichier

@@ -40,6 +40,7 @@ class DashboardController extends AbstractDashboardController
$assets->addWebpackEncoreEntry('adminlte-common');
$assets->addWebpackEncoreEntry('adminlte-index');
$assets->addWebpackEncoreEntry('adminlte-form');
$assets->addWebpackEncoreEntry('adminlte-sort');

return $assets;
}

+ 1
- 1
Field/FileManagerField.php Voir le fichier

@@ -4,7 +4,7 @@ namespace Lc\SovBundle\Field;

use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Lc\SovBundle\Form\Type\FileManagerType;
use Lc\SovBundle\Form\Type\Crud\FileManagerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

/**

+ 1
- 2
Field/GalleryManagerField.php Voir le fichier

@@ -4,8 +4,7 @@ namespace Lc\SovBundle\Field;

use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Lc\SovBundle\Form\Type\FileManagerType;
use Lc\SovBundle\Form\Type\GalleryManagerType;
use Lc\SovBundle\Form\Type\Crud\FileManagerType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;



+ 1
- 1
Field/ImageManagerField.php Voir le fichier

@@ -4,7 +4,7 @@ namespace Lc\SovBundle\Field;

use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Lc\SovBundle\Form\Type\FileManagerType;
use Lc\SovBundle\Form\Type\Crud\FileManagerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

/**

Form/Type/CrudFormType.php → Form/Type/Crud/CrudFormType.php Voir le fichier

@@ -1,21 +1,14 @@
<?php

namespace Lc\SovBundle\Form\Type;
namespace Lc\SovBundle\Form\Type\Crud;


use ArrayObject;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Dto\AssetsDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use EasyCorp\Bundle\EasyAdminBundle\Form\EventListener\EasyAdminTabSubscriber;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\EaFormPanelType;
use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**

Form/Type/FileManagerType.php → Form/Type/Crud/FileManagerType.php Voir le fichier

@@ -1,6 +1,6 @@
<?php

namespace Lc\SovBundle\Form\Type;
namespace Lc\SovBundle\Form\Type\Crud;

use Lc\SovBundle\DataTransformer\FileManagerTypeToDataTransformer;
use Lc\SovBundle\Entity\File\File;

+ 25
- 0
Form/Type/Crud/PositionType.php Voir le fichier

@@ -0,0 +1,25 @@
<?php

namespace Lc\SovBundle\Form\Type\Crud;


use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;

class PositionType extends AbstractType
{

/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('id', HiddenType::class);
$builder->add('position', HiddenType::class);
}

}

+ 4
- 0
Resources/assets/app/adminlte/sort/app.sort.js Voir le fichier

@@ -0,0 +1,4 @@

import 'jquery-ui'
import './sort.js'
import './sort.scss'

+ 39
- 0
Resources/assets/app/adminlte/sort/sort.js Voir le fichier

@@ -0,0 +1,39 @@
jQuery(document).ready(function () {
initSovSortableList();
});

function initSovSortableList() {

if ($('.sov-sortable').length > 0) {
$('.sov-sortable tbody').sortable({
placeholder: "ui-state-highlight"
});

$('.sov-sortable tbody').on("sortupdate", function (event, ui) {

prototype = $('#form_entities').data('prototype');

$('.sov-sortable tr.sov-draggable').each(function (index, li) {

// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);

// Replace '__name__' in the prototype's HTML to
$(li).find('div:last-child').remove();

$(li).append(newForm);
$(li).find('#form_entities_' + index + '_id').val($(li).data('id'));
if ($('.sov-sortable').data('parent-position') !== '') {
//Ajout d'un 0 initial pour les nuémros <10
indexAsString = index.toString().padStart(2, '0');
val = $('.sov-sortable').data('parent-position') + '.' + indexAsString
} else {
val = index;
}
$(li).find('#form_entities_' + index + '_position').val(val);
});

});
}
}


+ 45
- 0
Resources/assets/app/adminlte/sort/sort.scss Voir le fichier

@@ -0,0 +1,45 @@

.form-sent {
.form-control:invalid {
border-color: #dc3545;
padding-right: 2.25rem;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");
background-repeat: no-repeat;
background-position: center right calc(.375em + .1875rem);
background-size: calc(.75em + .375rem) calc(.75em + .375rem);
}

select.form-control:invalid + .select2 .select2-selection {
border-color: #dc3545;
}

select.form-control:invalid + .select2 .select2-selection b {
border-color: #dc3545 transparent transparent transparent;
}

.form-check-label input:invalid ~ .checkmark {
border-color: #dc3545;
}
}

.nav-item .nav-link {
position: relative;

.invalid-form {
display: none;
position: absolute;
top: -7px;
right: -6px;
color: #dc3545;
background: #fff;
border-radius: 10px;
font-size: 1.2rem;
}
}

.nav-item.has-invalid .nav-link .invalid-form {
display: inline-block;
z-index: 2;
}



+ 1
- 1
Resources/config/services.yml Voir le fichier

@@ -16,7 +16,7 @@ services:
resource: '../../Controller/'
tags: [ 'controller.service_arguments' ]

Lc\SovBundle\Form\Type\CrudFormType:
Lc\SovBundle\Form\Type\Crud\CrudFormType:
decorates: EasyCorp\Bundle\EasyAdminBundle\Form\Type\CrudFormType
arguments: ['@form.type_guesser.doctrine', '@.inner']


+ 142
- 0
Resources/views/adminlte/crud/sort.html.twig Voir le fichier

@@ -0,0 +1,142 @@
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #}
{# @var entities \EasyCorp\Bundle\EasyAdminBundle\Collection\EntityDtoCollection #}
{# @var paginator \EasyCorp\Bundle\EasyAdminBundle\Orm\EntityPaginator #}
{% extends ea.templatePath('layout') %}
{% trans_default_domain ea.i18n.translationDomain %}

{% block body_id entities|length > 0 ? 'ea-index-' ~ entities|first.name : '' %}
{% block body_class 'index' ~ (entities|length > 0 ? ' index-' ~ entities|first.name : '') %}

{% block content_title %}
Tri position
{# {%- apply spaceless -%}
{% set default_title = ea.crud.defaultPageTitle('index')|trans(ea.i18n.translationParameters, 'EasyAdminBundle') %}
{{ ea.crud.customPageTitle is null ? default_title|raw : ea.crud.customPageTitle('index')|trans(ea.i18n.translationParameters)|raw }}
{%- endapply -%} #}
{% endblock %}

{% set has_batch_actions = batch_actions|length > 0 %}
{% block page_actions %}
{# {% block global_actions %}
<div class="global-actions">
{% for action in global_actions %}
{{ include(action.templatePath, { action: action }, with_context = false) }}
{% endfor %}
</div>
{% endblock global_actions %}
{% block batch_actions %}
{% if has_batch_actions %}
<div class="batch-actions" style="display: none">
{% for action in batch_actions %}
{{ include(action.templatePath, { action: action }, with_context = false) }}
{% endfor %}
</div>
{% endif %}
{% endblock %} #}
{% endblock page_actions %}

{% block main %}
{# sort can be multiple; let's consider the sorting field the first one #}
{% set sort_field_name = app.request.get('sort')|keys|first %}
{% set sort_order = app.request.get('sort')|first %}
{% set some_results_are_hidden = false %}
{% set has_footer = entities|length != 0 %}
{% set has_search = ea.crud.isSearchEnabled %}
{% set has_filters = filters|length > 0 %}
{% set has_datagrid_tools = has_search or has_filters %}

{{ form_start(sortable_form) }}

{% embed '@LcSov/adminlte/embed/card.html.twig' %}
{% block css %}card-table card-outline card-primary{% endblock %}
{% block header %}
<span data-toggle="tooltip" class="badge badge-light" data-original-title="Total" title="Total">
{{ paginator.numResults }} résultats
</span>
{% endblock %}
{% block body %}

<div class="table-responsive">
<table class="table table-bordered table-hover table-striped sov-sortable"
data-parent-position="{{ entity is defined and entity is not null ? entity.position : '' }}">
<thead>
{% block table_head %}
<tr>
<th></th>
{% for field in fields ?? [] %}
{% set field = field.getAsDto() %}
{% set is_sorting_field = ea.search.isSortingField(field.property) %}
<th class="{{ is_sorting_field ? 'sorted' }} {{ field.isVirtual ? 'field-virtual' }} {% if field.textAlign %}text-{{ field.textAlign }}{% endif %}"
dir="{{ ea.i18n.textDirection }}">
<span>{{ field.label|raw }}</span>
</th>
{% endfor %}

</tr>
{% endblock table_head %}
</thead>

<tbody>
{% block table_body %}
{% for entity in entities %}
{% if not entity.isAccessible %}
{% set some_results_are_hidden = true %}
{% else %}

<tr class="sov-draggable" data-id="{{ entity.primaryKeyValueAsString }}">
<td>
<i class="fa fa-fw fa-sort"></i>
</td>
{% for field in entity.fields %}
<td class="{{ field.property == sort_field_name ? 'sorted' }} text-{{ field.textAlign }} {{ field.cssClass }}"
dir="{{ ea.i18n.textDirection }}">
{{ include(field.templatePath, { field: field, entity: entity }, with_context = false) }}
</td>
{% endfor %}
</tr>
{% endif %}
{% else %}
<tr>
<td class="no-results" colspan="100">
{{ 'datagrid.no_results'|trans(ea.i18n.translationParameters, 'EasyAdminBundle') }}
</td>
</tr>
{% endfor %}

{% if some_results_are_hidden %}
<tr class="datagrid-row-empty">
<td class="text-center" colspan="{{ entities|first.fields|length + 1 }}">
<span class="datagrid-row-empty-message"><i
class="fa fa-lock mr-1"></i> {{ 'datagrid.hidden_results'|trans({}, 'EasyAdminBundle') }}</span>
</td>
</tr>
{% endif %}
{% endblock table_body %}
</tbody>
</table>
<div style="display: none;">
{{ form_row(sortable_form.entities) }}

{{ form_rest(sortable_form) }}
</div>

</div>
{% endblock %}
{% endembed %}

{% embed '@LcSov/adminlte/embed/card.html.twig' %}
{% block footer %}
<div class="form-actions">
<div class="button-action">
{# <a class=" {{ _action.css_class|default('') }}" href="{{ path('easyadmin', _request_parameters|merge({ action: _action.name })) }}" target="{{ _action.target }}">
{{ _action.label is defined and not _action.label is empty ? _action.label|trans(_trans_parameters) }}
</a> #}
<button type="submit" class="btn btn-primary float-right"> Sauvegarder</button>
</div>
</div>
{% endblock %}
{% endembed %}
{{ form_end(sortable_form) }}

{% endblock main %}


Chargement…
Annuler
Enregistrer