kikwik / easyadmin-utils-bundle
Utility for easycorp/easyadmin-bundle v5.x: Dynamic Paginator Page Size, Dynamic index fields, Relative time, Sticky header, Sticky footer
Package info
github.com/kikwik/easyadmin-utils-bundle
Type:symfony-bundle
pkg:composer/kikwik/easyadmin-utils-bundle
Requires
- easycorp/easyadmin-bundle: ^5.0
- symfony/framework-bundle: ^6.4|^7.0|^8.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Utility for easycorp/easyadmin-bundle v5.x: Dynamic Paginator Page Size, Dynamic index fields, Relative time, Sticky header, Sticky footer
Features
- Dynamic Paginator Page Size: Paginator page size can be choosen by the user per controller
- Dynamic index fields: Field shown on index page can be choosen by the user per controller
- Relative time: Add a tooltip with distance of time in words
- Sticky header: Table head can be stiky on top in the index pages
- Sticky footer: Footer with pagination can be sticky on bottom in the index pages
Installation
Make sure Composer is installed globally, as explained in the installation chapter of the Composer documentation.
Open a command console, enter your project directory and execute:
$ composer require kikwik/easyadmin-utils-bundle
Usage
Dynamic Paginator Page Size and Dynamic index fields
- Extends your EasyAdmin crud controller from
AbstractConfigurableCrudController - call parent methods in
configureCrud, andconfigureActions. - DO NOT define
configureFieldsmethod, instead define aconfigureAvailableFieldswith the same signature - in case you need some services inside the controller remember to call the parent constructor with the
CrudConfigurationparameter
an example for src/Controller/Admin/UserCrudController.php:
namespace App\Controller\Admin; use App\Entity\User; use Doctrine\ORM\EntityManagerInterface; use EasyCorp\Bundle\EasyAdminBundle\Config\Action; use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField; use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField; use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField; use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField; use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; use Kikwik\EasyAdminUtilsBundle\Controller\AbstractConfigurableCrudController; use Kikwik\EasyAdminUtilsBundle\Service\CrudConfiguration; use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class UserCrudController extends AbstractConfigurableCrudController { public function __construct( CrudConfiguration $crudConfiguration, private UserPasswordHasherInterface $userPasswordHasher, private UrlGeneratorInterface $urlGenerator, ) { parent::__construct($crudConfiguration); // call the parent constructor } public static function getEntityFqcn(): string { return User::class; } public function configureCrud(Crud $crud): Crud { return parent::configureCrud($crud) // this will eventually set the $crud->setPaginatorPageSize() // set here your crud configuration ->setEntityLabelInPlural('Utenti') ->setEntityLabelInSingular( fn (?User $user, ?string $pageName) => $user ? sprintf('Utente %s', $user) : 'Utente' ) ; } public function configureActions(Actions $actions): Actions { $impersonateAction = Action::new('impersonate', 'Imporsona', 'fa fa-user-secret') ->linkToUrl(function (?User $user) { return $this->urlGenerator->generate('app_home', ['_switch_user' => $user?->getUserIdentifier()]); }) ; return parent::configureActions($actions) // this will add the "Configure" global action // add here your custom actions ->add(Crud::PAGE_INDEX, $impersonateAction) ->add(Crud::PAGE_DETAIL, $impersonateAction) ->setPermission('impersonate','ROLE_ALLOWED_TO_SWITCH') ; } public function configureAvailableFields(string $pageName): iterable { $roleHierarchy = $this->getParameter('security.role_hierarchy.roles'); $rolesChoices = []; foreach($roleHierarchy as $role => $children) { $label = str_replace('ROLE_', '', $role); $value = $role; $rolesChoices[$label] = $value; } return [ FormField::addColumn('col-xl-4'), FormField::addFieldset('Credenziali'), TextField::new('email'), TextField::new('plainPassword', 'Nuova Password') ->onlyOnForms() ->setFormType(RepeatedType::class) ->setFormTypeOptions([ 'type' => PasswordType::class, 'required' => false, 'first_options' => ['label' => 'Nuova Password'], 'second_options' => ['label' => 'Conferma Password'], 'invalid_message' => 'Le password non coincidono.', ]), ChoiceField::new('roles', 'Permessi') ->setPermission('ROLE_SUPER_ADMIN') ->setChoices($rolesChoices) ->allowMultipleChoices() ->renderExpanded() ->formatValue(function($value) { $badges = ''; if(is_array($value)) { foreach($value as $role) { switch($role) { case 'ROLE_SUPER_ADMIN': case 'ROLE_DEVELOPER': $badgeClass = 'badge-danger'; break; default: $badgeClass = 'badge-secondary'; break; } $label = str_replace('ROLE_', '', $role); $badges .= sprintf('<span class="badge %s">%s</span>', $badgeClass, $label); } } return $badges; }), BooleanField::new('isEnabled'), FormField::addFieldset('Accessi')->hideOnForm(), IntegerField::new('loginCount')->hideOnForm(), DateTimeField::new('lastLoginAt')->hideOnForm(), TextField::new('lastLoginFromIp')->hideOnForm()->hideOnIndex(), DateTimeField::new('previousLoginAt')->hideOnForm(), TextField::new('previousFromIp')->hideOnForm()->hideOnIndex(), FormField::addColumn('col-xl-4'), FormField::addFieldset('Password')->hideOnForm(), DateTimeField::new('changePasswordRequestedAt')->hideOnForm()->hideOnIndex(), DateTimeField::new('passwordChangedAt')->hideOnForm()->hideOnIndex(), TextField::new('passwordChangedFromIp')->hideOnForm()->hideOnIndex(), FormField::addColumn('col-xl-4'), FormField::addFieldset('Creazione')->hideOnForm(), DateTimeField::new('createdAt')->hideOnForm()->hideOnIndex(), TextField::new('createdBy')->hideOnForm()->hideOnIndex(), TextField::new('createdFromIp')->hideOnForm()->hideOnIndex(), FormField::addFieldset('Modifica')->hideOnForm(), DateTimeField::new('updatedAt')->hideOnForm()->hideOnIndex(), TextField::new('updatedBy')->hideOnForm()->hideOnIndex(), TextField::new('updatedFromIp')->hideOnForm()->hideOnIndex(), ]; } public function persistEntity(EntityManagerInterface $entityManager, object $entityInstance): void { $this->updatePassword($entityInstance); parent::persistEntity($entityManager, $entityInstance); } public function updateEntity(EntityManagerInterface $entityManager, object $entityInstance): void { $this->updatePassword($entityInstance); parent::updateEntity($entityManager, $entityInstance); } private function updatePassword($entityInstance) { if ($entityInstance instanceof User && $entityInstance->getPlainPassword()) { $hashedPassword = $this->userPasswordHasher->hashPassword($entityInstance, $entityInstance->getPlainPassword()); $entityInstance->setPassword($hashedPassword); } } }
Relative time, Sticky header and Sticky footer
In you dashboard controller add these assets:
namespace App\Controller\Admin; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; class DashboardController extends AbstractDashboardController { public function configureAssets(): Assets { return Assets::new() ->addJsFile('bundles/kikwikeasyadminutils/js/relative-time.js') ->addCssFile('bundles/kikwikeasyadminutils/css/index-sticky-header.css') ->addCssFile('bundles/kikwikeasyadminutils/css/index-sticky-footer.css') ; } }