Sylius Stack
  • Sylius Stack Documentation
  • Getting started
  • Cookbook
    • How to customize your admin panel
      • Basic operations
      • Customizing your grids
      • Customizing the logo
      • Customizing the menu
      • Configuring the security access
      • Customizing the page titles
    • How to use in a DDD architecture
      • Architecture overview
      • Resource configuration
      • Basic operations
      • Operation using a grid
  • Admin UI
    • Getting started
  • Bootstrap Admin UI
    • Getting started
  • Resource
    • Resource Bundle documentation
      • Installation
      • Create new resource
      • Configure your resource
      • Configure your operations
      • Validation
      • Redirect
      • Resource factories
      • Providers
      • Processors
      • Responders
      • Legacy Resource Documentation
        • Configuration
        • Services
        • Routing
        • Forms
        • Getting a Single Resource
        • Getting a Collection of Resources
        • Creating Resources
        • Updating Resources
        • Deleting Resources
        • Configuring a state machine
        • Configuration Reference
  • Grid
    • Grid Bundle documentation
      • Installation
      • Creating your first grid
      • Configuring Fields
      • Field types
      • Creating a custom Field Type
      • Creating a custom Action
      • Creating a custom Bulk Action
      • Filters
      • Creating a custom Filter
      • Advanced configuration
      • Configuration Reference
  • 🍀Twig Extra
    • Getting started
  • 🌱Twig Hooks
    • Getting started
    • Passing data to your hookables
    • Making your hookables configurable
    • Autoprefixing feature
    • Composable Layouts with a predictable structure
    • Advanced
      • Ergonomic work with hooks
      • Metadata objects
      • Multiple hooks inside a single template
      • Overriding hookables
Powered by GitBook
On this page
  • Fields
  • Adding the speaker avatar using Twig field
  • Filters
  • Adding an autocomplete filter
  1. Cookbook
  2. How to customize your admin panel

Customizing your grids

PreviousBasic operationsNextCustomizing the logo

Last updated 1 month ago

Based on the grid generated by default, our goal here is to obtain a nicely customized grid with autocomplete filters and more!

Let's imagine we have the following grid.

src/Grid/TalkGrid.php
<?php

namespace App\Grid;

use App\Entity\Talk;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\ShowAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\BulkActionGroup;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\ItemActionGroup;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\MainActionGroup;
use Sylius\Bundle\GridBundle\Builder\Field\DateTimeField;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Bundle\GridBundle\Grid\AbstractGrid;
use Sylius\Bundle\GridBundle\Grid\ResourceAwareGridInterface;

final class TalkGrid extends AbstractGrid implements ResourceAwareGridInterface
{
    public function __construct()
    {
        // TODO inject services if required
    }

    public static function getName(): string
    {
        return 'app_talk';
    }

    public function buildGrid(GridBuilderInterface $gridBuilder): void
    {
        $gridBuilder
            // see https://github.com/Sylius/SyliusGridBundle/blob/master/docs/field_types.md
            ->addField(
                StringField::create('title')
                    ->setLabel('Title')
                    ->setSortable(true)
            )
            ->addField(
                StringField::create('description')
                    ->setLabel('Description')
                    ->setSortable(true)
            )
            ->addField(
                DateTimeField::create('startsAt')
                    ->setLabel('StartsAt')
            )
            ->addField(
                DateTimeField::create('endsAt')
                    ->setLabel('EndsAt')
            )
            ->addField(
                StringField::create('track')
                    ->setLabel('Track')
                    ->setPath('track.value')
                    ->setSortable(true)
            )
            ->addActionGroup(
                MainActionGroup::create(
                    CreateAction::create(),
                )
            )
            ->addActionGroup(
                ItemActionGroup::create(
                    // ShowAction::create(),
                    UpdateAction::create(),
                    DeleteAction::create()
                )
            )
            ->addActionGroup(
                BulkActionGroup::create(
                    DeleteAction::create()
                )
            )
        ;
    }

    public function getResourceClass(): string
    {
        return Talk::class;
    }
}

Fields

Let's clean up our grid and remove unnecessary fields.

src/Grid/TalkGrid.php
<?php

namespace App\Grid;

use App\Entity\Talk;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\ShowAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\BulkActionGroup;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\ItemActionGroup;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\MainActionGroup;
use Sylius\Bundle\GridBundle\Builder\Field\DateTimeField;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Bundle\GridBundle\Grid\AbstractGrid;
use Sylius\Bundle\GridBundle\Grid\ResourceAwareGridInterface;

final class TalkGrid extends AbstractGrid implements ResourceAwareGridInterface
{
    public static function getName(): string
    {
        return 'app_talk';
    }

    public function buildGrid(GridBuilderInterface $gridBuilder): void
    {
        $gridBuilder
            ->addField(
                StringField::create('title')
                    ->setLabel('Title')
                    ->setSortable(true)
            )
            ->addField(
                DateTimeField::create('startsAt')
                    ->setLabel('StartsAt')
            )
            ->addActionGroup(
                MainActionGroup::create(
                    CreateAction::create(),
                )
            )
            ->addActionGroup(
                ItemActionGroup::create(
                    // ShowAction::create(),
                    UpdateAction::create(),
                    DeleteAction::create()
                )
            )
            ->addActionGroup(
                BulkActionGroup::create(
                    DeleteAction::create()
                )
            )
        ;
    }

    public function getResourceClass(): string
    {
        return Talk::class;
    }
}

We have removed the "description", "endsAt" and "track" grid fields.

Adding the speaker avatar using Twig field

Now, let's add the speaker avatar into our talk grid.

<?php

namespace App\Grid;

use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Bundle\GridBundle\Grid\AbstractGrid;
use Sylius\Bundle\GridBundle\Grid\ResourceAwareGridInterface;
// ...

final class TalkGrid extends AbstractGrid implements ResourceAwareGridInterface
{
    // ...

    public function buildGrid(GridBuilderInterface $gridBuilder): void
    {
        $gridBuilder
            ->addField(
                TwigField::create('avatar', 'talk/grid/field/speaker_avatar.html.twig')
                    ->setPath('.')
                    ->setLabel('app.ui.avatar'),
            )
            // ...
        ;
    }

    // ...
}

templates/talk/grid/speaker_avatar.html.twig

{{ avatar.default(avatar_path, 'img-thumbnail') }}

Filters

Adding an autocomplete filter

We'd like to filter our talks by a specific speaker.

src/Form/SpeakerAutocompleteType.php
declare(strict_types=1);

namespace App\Form;

use App\Entity\Speaker;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\UX\Autocomplete\Form\AsEntityAutocompleteField;
use Symfony\UX\Autocomplete\Form\BaseEntityAutocompleteType;

#[AsEntityAutocompleteField(
    alias: 'app_admin_speaker',
    route: 'ux_entity_autocomplete_admin',
)]
final class SpeakerAutocompleteType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'class' => Speaker::class,
            'choice_label' => 'fullName',
        ]);
    }

    public function getParent(): string
    {
        return BaseEntityAutocompleteType::class;
    }
}

Now we need to create our custom Grid filter.

src/Grid/Filter/SpeakerFilter.php
<?php

declare(strict_types=1);

namespace App\Grid\Filter;

use App\Form\SpeakerAutocompleteType;
use Sylius\Component\Grid\Data\DataSourceInterface;
use Sylius\Component\Grid\Filter\EntityFilter;
use Sylius\Component\Grid\Filtering\ConfigurableFilterInterface;

final class SpeakerFilter implements ConfigurableFilterInterface
{
    public function __construct(
        private readonly EntityFilter $entityFilter,
    ) {
    }

    public function apply(DataSourceInterface $dataSource, string $name, mixed $data, array $options): void
    {
        // We simply reuse the logic of the built-in EntityFilter provided by the Sylius Grid package.
        $this->entityFilter->apply($dataSource, $name, $data, $options);
    }

    public static function getFormType(): string
    {
        return SpeakerAutocompleteType::class;
    }

    public static function getType(): string
    {
        return self::class;
    }
}

Then, we add our SpeakerFilter to our grid.

src/Grid/TalkGrid.php
<?php

declare(strict_types=1);

namespace App\Grid;

use App\Grid\Filter\SpeakerFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Bundle\GridBundle\Grid\AbstractGrid;
use Sylius\Bundle\GridBundle\Grid\ResourceAwareGridInterface;
// ...

final class TalkGrid extends AbstractGrid implements ResourceAwareGridInterface
{
    // ...

    public function buildGrid(GridBuilderInterface $gridBuilder): void
    {
        $gridBuilder
            ->addFilter(
                Filter::create(name: 'speaker', type: SpeakerFilter::class)
                    ->setLabel('app.ui.speaker')
                    ->setOptions(['fields' => ['speaker.id']]), // TODO, we need to check if this is necessary
            )
            // ...
        ;
    }

    // ...
}

So, let's start by creating a FormType following the

Symfony UX Autocomplete Documentation
Overview of an admin dashboard
Overview of an admin dashboard
Overview of an admin dashboard
Overview of an admin dashboard
Overview of an admin dashboard
Overview of an admin dashboard