### Install moneyphp/money Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/MoneyField.html Command to install the Money PHP library, required for the useMoneyObject option. ```bash $ composer require moneyphp/money ``` -------------------------------- ### Install Flysystem bundle and adapter Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html Install the Flysystem bundle and the adapter for your storage service (e.g., Amazon S3). ```bash $ composer require league/flysystem-bundle ``` ```bash $ composer require league/flysystem-aws-s3-v3 ``` -------------------------------- ### Install assets with assets:install --symlink Source: https://symfony.com/bundles/EasyAdminBundle/current/design.html Run this command to manually install the bundle's assets into the public/bundles/ directory when automatic copying or symlinking fails. The --symlink option can be removed if the system does not support symbolic links. ```bash # remove the --symlink option if your system doesn't support symbolic links $ php bin/console assets:install --symlink ``` -------------------------------- ### Install symfony/expression-language Source: https://symfony.com/bundles/EasyAdminBundle/current/security.html Install the Symfony ExpressionLanguage component with Composer before using Expression objects in EasyAdmin permissions. ```bash $ composer require symfony/expression-language ``` -------------------------------- ### Run easyadmin:ai:install command Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Run this command in your Symfony application to install the EasyAdmin AI coding agents skill. It asks which agents to install for and whether to add an EasyAdmin section to your AI instructions files. ```bash $ php bin/console easyadmin:ai:install ``` -------------------------------- ### Install EasyAdmin with Composer Source: https://symfony.com/bundles/EasyAdminBundle/current/index.html Install EasyAdmin in your application. Requires PHP 8.2 or higher, Symfony 6.4 or higher, and Doctrine ORM entities. If Symfony Flex is used, you are ready to create your first Dashboard after running this command. ```bash $ composer require easycorp/easyadmin-bundle ``` -------------------------------- ### Install EasyAdmin AI skill with --skip-guidelines Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Adds --skip-guidelines to leave CLAUDE.md and AGENTS.md untouched. Use with --all and --no-interaction to skip all questions. ```bash $ php bin/console easyadmin:ai:install --all --skip-guidelines ``` -------------------------------- ### setUploadedFileNamePattern with placeholders Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/ImageField.html Renames uploaded images using a pattern with placeholders. The example combines date, slug, content hash, and extension placeholders. ```php yield ImageField::new('...') ->setUploadedFileNamePattern('[YYYY]/[MM]/[DD]/[slug]-[contenthash].[extension]'); ``` -------------------------------- ### useMoneyObject example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/MoneyField.html Enables handling of Money\Money objects on new pages where the value is null. On edit and detail pages it is detected automatically. ```php yield MoneyField::new('price')->useMoneyObject(); ``` -------------------------------- ### setFileConstraints option example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html Defines validation constraints for the uploaded file. By default no constraints are applied. This example uses the File constraint with filenameCharset 'ASCII'. ```text 1 2 3 ``` ```php use Symfony\Component\Validator\Constraints\File; yield FileField::new('...')->setFileConstraints(new File(filenameCharset: 'ASCII')); ``` -------------------------------- ### setUploadDir option example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html Sets the upload directory for storing uploaded files. Relative paths are resolved from the project root; absolute paths are used as-is. The property stores only the file path relative to this directory. This option is required; omitting it throws an exception. ```text 1 2 3 4 5 6 ``` ```php // relative to your project root directory yield FileField::new('...')->setUploadDir('public/uploads/files/'); // absolute filesystem paths are also supported yield FileField::new('...')->setUploadDir('/mnt/data/uploads/'); // the property will only store the file path relative to this dir // (e.g. 'catalog.pdf', 'venue/contract.docx') ``` -------------------------------- ### setBasePath example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/ImageField.html Configures the base path for images served in read-only pages. Use when images are stored under a subdirectory like 'uploads/images/'. ```php yield ImageField::new('...')->setBasePath('uploads/images/'); ``` -------------------------------- ### setStoredAsCents example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/MoneyField.html Disables the default assumption that money amounts are stored as cents. Use this option when amounts are not stored in cents. ```php yield MoneyField::new('...')->setStoredAsCents(false); ``` -------------------------------- ### setFileConstraints example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/ImageField.html Defines custom constraints for the uploaded file. By default, an empty Image constraint is used, which only validates that the file is an image. ```php yield ImageField::new('...')->setFileConstraints(new Image(filenameCharset: 'ASCII')); ``` -------------------------------- ### Install EasyAdmin AI skill for specific agents Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Use --agent multiple times to select agents (claude, agents, junie, windsurf). Any other value fails and lists valid values. --agent and --all only skip the first question; add --no-interaction to skip the second. ```bash # install the skill for one or more agents $ php bin/console easyadmin:ai:install --agent=claude --agent=agents # install the skill for all the supported agents $ php bin/console easyadmin:ai:install --all # install the skill for the detected agents without asking anything $ php bin/console easyadmin:ai:install --no-interaction ``` -------------------------------- ### Custom EasyAdmin conventions section Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Add your own project conventions in a section titled `## EasyAdmin conventions` outside the markers. The install and update commands never change this section. ```markdown ... ## EasyAdmin conventions - All CRUD controllers live in `src/Controller/Admin/` and their tests in `tests/Admin/Controller/`. - Prices are stored in cents and displayed with `MoneyField`. - Never display the `password` property of the `User` entity. ``` -------------------------------- ### ActionMenu with Button, Overlay, and ActionList Source: https://symfony.com/bundles/EasyAdminBundle/current/components.html Builds a dropdown menu with a toggle button, an overlay, and an action list. Items render as GET links by default; add the `renderAsForm` prop to submit the item URL with a POST request instead, as shown for the Delete item. ```twig ``` -------------------------------- ### setNumDecimals example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/MoneyField.html Sets the number of decimals used to format money amounts. By default, 2 decimals are used. ```php yield MoneyField::new('...')->setNumDecimals(0); ``` -------------------------------- ### Update EasyAdmin AI skill copies Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Refreshes installed skill copies and instruction blocks after EasyAdmin updates. Never asks anything and never creates new files. Silent and returns success when skill isn't installed. ```bash $ php bin/console easyadmin:ai:update ``` -------------------------------- ### EasyAdmin guidelines block in CLAUDE.md/AGENTS.md Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html This block is added by the EasyAdmin install command and is delimited by markers. The commands replace the contents of this block on every run, so do not edit the text inside the markers. ```markdown This project uses EasyAdmin 5.5.2. Before creating or modifying admin dashboards, CRUD controllers, fields, actions, filters or their tests, read and follow the `easyadmin` skill at `.claude/skills/easyadmin/SKILL.md`. ... ``` -------------------------------- ### Translation file with custom generator keys Source: https://symfony.com/bundles/EasyAdminBundle/current/dashboards.html Example translation file structure when using the custom generator. Keys follow the pattern 'admin.entities..singular', 'plural', and 'fields.'. ```yaml # translations/messages.en.yaml admin: entities: blogpost: singular: 'Blog Post' plural: 'Blog Posts' fields: title: 'Post Title' ``` -------------------------------- ### Restrict admin routes with allowedDashboards and deniedDashboards Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Shows how to restrict admin routes to specific dashboards using the 'allowedDashboards' and 'deniedDashboards' options of the #[AdminRoute] attribute. The first example allows only the listed dashboards, while the second denies the listed ones. These options can be applied at class or action level, with action-level values overriding class-level ones. ```php use App\Controller\Admin\DashboardController; use App\Controller\Admin\GuestDashboardController; use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminRoute; // Use the 'allowedDashboards' option to NOT generate a route for ANY dashboards // except those listed explicitly: #[AdminRoute('...', name: '...', allowedDashboards: [DashboardController::class, '...'])] class BusinessStatsController extends AbstractController { /* ... */ } // Use the 'deniedDashboards' option to generate a route for ALL dashboards // except those listed explicitly: #[AdminRoute('...', name: '...', deniedDashboards: [GuestDashboardController::class, '...'])] class BusinessStatsController extends AbstractController { /* ... */ } ``` -------------------------------- ### setNumberFormat option examples Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/IntegerField.html Uses the setNumberFormat option to format the integer value with a sprintf-compatible format string. The first example displays integers in scientific notation, the second adds left/right padding (e.g., 123 becomes '+00123'). ```php // this would display integers in scientific notation (e.g. 1234567890 = '1.234568e+9') yield IntegerField::new('...')->setNumberFormat('%e'); // formatting also helps you to add left/right padding to numbers // the following example would format 123 as '+00123' yield IntegerField::new('...')->setNumberFormat('%+06d'); ``` -------------------------------- ### Configure custom actions with linkToCrudAction, linkToRoute, and linkToUrl in EasyAdmin Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Shows how to define custom actions in an EasyAdmin CRUD controller using Action::new() with linkToCrudAction(), linkToRoute(), and linkToUrl(). The example includes route parameters as an array or a callable, and adds actions to the detail page. Note that using setCssClass() or addCssClass() removes default CSS classes, and the style/render methods accept an optional boolean for conditional application. ```php namespace App\Controller\Admin; use App\Entity\Order; use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminRoute; use EasyCorp\Bundle\EasyAdminBundle\Config\Action; use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; use Symfony\Component\HttpFoundation\Response; class OrderCrudController extends AbstractCrudController { // ... public function configureActions(Actions $actions): Actions { // this action executes the 'renderInvoice()' method of the current CRUD controller $viewInvoice = Action::new('viewInvoice', 'Invoice', 'fa fa-file-invoice') ->linkToCrudAction('renderInvoice'); // if the method is not defined in a CRUD controller, link to its route $sendInvoice = Action::new('sendInvoice', 'Send invoice', 'fa fa-envelope') // if the route needs parameters, you can define them: // 1) using an array ->linkToRoute('invoice_send', [ 'send_at' => (new \DateTime('+ 10 minutes'))->format('YmdHis'), ]) // 2) using a callable (useful if parameters depend on the entity instance) // (the type-hint of the function argument is optional but useful) ->linkToRoute('invoice_send', function (Order $order): array { return [ 'uuid' => $order->getId(), 'method' => $order->getUser()->getPreferredSendingMethod(), ]; }); // this action points to the invoice in the Stripe application $viewStripeInvoice = Action::new('viewStripeInvoice', 'Stripe Invoice', 'fab fa-stripe') ->linkToUrl(function (Order $entity) { return 'https://www.stripe.com/invoice/'.$entity->getStripeReference(); }); return $actions // ... ->add(Crud::PAGE_DETAIL, $viewInvoice) ->add(Crud::PAGE_DETAIL, $sendInvoice) ->add(Crud::PAGE_DETAIL, $viewStripeInvoice) ; } #[AdminRoute('/{id}/invoice')] public function renderInvoice(Order $order): Response { // add your custom order logic here... } } ``` -------------------------------- ### setCurrencyPropertyPath examples Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/MoneyField.html Sets the property path that stores the currency code. Accepts any valid Symfony PropertyAccess expression. ```php yield MoneyField::new('...')->setCurrencyPropertyPath('currency'); yield MoneyField::new('...')->setCurrencyPropertyPath('currencyCode'); yield MoneyField::new('...')->setCurrencyPropertyPath('currency.code'); ``` -------------------------------- ### MaskedEmailConfigurator example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields.html Masks the local part of every EmailField value on the index page, rendering jane.doe@example.com as j***@example.com. The full address remains visible on detail and edit pages. In supports(), you can also match a property name or a custom option. ```php namespace App\Admin\Configurator; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext; use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldConfiguratorInterface; use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto; use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField; final class MaskedEmailConfigurator implements FieldConfiguratorInterface { public function supports(FieldDto $field, EntityDto $entityDto): bool { return EmailField::class === $field->getFieldFqcn(); } public function configure(FieldDto $field, EntityDto $entityDto, AdminContext $context): void { if (Crud::PAGE_INDEX !== $context->getCrud()->getCurrentPage()) { return; } $email = (string) $field->getValue(); if (!str_contains($email, '@')) { return; } [$local, $domain] = explode('@', $email, 2); $field->setFormattedValue(substr($local, 0, 1).'***@'.$domain); } } ``` -------------------------------- ### setCurrency example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/MoneyField.html Sets the currency for the field using an ISO 4217 code. The currency is required for read-only pages. The code must be known to ICU, otherwise an \InvalidArgumentException is thrown. ```php // e.g. 'INR' = 'Indian Rupee' yield MoneyField::new('...')->setCurrency('INR'); ``` -------------------------------- ### Configure CRUD globally in DashboardController with configureCrud() Source: https://symfony.com/bundles/EasyAdminBundle/current/crud.html Add the configureCrud() method to your dashboard to apply the same configuration to all CRUD controllers. The example sets the pagination page size to 30 for every controller, which each controller can override if needed. ```php use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; #[AdminDashboard(routePath: '/admin', routeName: 'admin')] class DashboardController extends AbstractDashboardController { // ... public function configureCrud(): Crud { return Crud::new() // this defines the pagination size for all CRUD controllers // (each CRUD controller can override this value if needed) ->setPaginatorPageSize(30) ; } } ``` -------------------------------- ### setBasePath option example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html Sets the base path for linking files in read-only pages. The first block is a placeholder line number; the second is the actual PHP code. Use this option when files are served under a subpath like 'uploads/files/'. ```text 1 ``` ```php yield FileField::new('...')->setBasePath('uploads/files/'); ``` -------------------------------- ### Show entity actions inline with showEntityActionsInlined() Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Use the showEntityActionsInlined() design option in the configureCrud() method to display all entity actions inline on the index page instead of in a dropdown. This applies to the ProductCrudController example. ```php namespace App\Controller\Admin; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; class ProductCrudController extends AbstractCrudController { // ... public function configureCrud(Crud $crud): Crud { return $crud // ... ->showEntityActionsInlined() ; } } ``` -------------------------------- ### HTML rendering and security with renderAsHtml Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/AssociationField.html Shows the difference between escaped output (default, safe) and HTML output with renderAsHtml: true. The first example uses a template without renderAsHtml, so HTML is escaped. The second uses renderAsHtml with a template, and the third uses a callback that generates HTML with htmlspecialchars for escaping. When renderAsHtml is true, you must handle escaping yourself to prevent XSS. ```php // escaped output (default, safe) yield AssociationField::new('category')->autocomplete( template: 'admin/autocomplete/category.html.twig' ); // HTML output (use only with trusted content) yield AssociationField::new('product')->autocomplete( template: 'admin/autocomplete/product.html.twig', renderAsHtml: true ); // callbacks can also generate HTML when combined with renderAsHtml yield AssociationField::new('category')->autocomplete( callback: static fn ($e): string => '' . htmlspecialchars($e->getTitle()) . '', renderAsHtml: true ); ``` -------------------------------- ### Add EasyAdmin type declarations to tsconfig.json Source: https://symfony.com/bundles/EasyAdminBundle/current/events.html Adds the EasyAdmin type declarations file to the 'include' option of tsconfig.json for TypeScript support. Requires the 'tom-select' package to be installed, otherwise TypeScript compilation fails. ```json { "include": [ "src/**/*", "vendor/easycorp/easyadmin-bundle/assets/types.d.ts" ] } ``` -------------------------------- ### setEntryToStringMethod() option Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/CollectionField.html Defines how to get the string representation of each collection entry. Can be a method name or a callable that receives the entity and translator service. The first block is a placeholder line number; the second is the actual PHP code. ```text 1 2 3 4 5 6 7 8 9 ``` ```php // this calls the 'getFullName()' method in the entity yield CollectionField::new('...')->setEntryToStringMethod('getFullName'); // you can also pass a callable to generate the string yield CollectionField::new('...')->setEntryToStringMethod(fn (): string => '...'); // your callable receives the entity and the translator service as arguments yield CollectionField::new('...')->setEntryToStringMethod( fn (Category $value, TranslatorInterface $translator): string => $translator->trans($value->getDescription()) ); ``` -------------------------------- ### Generate EasyAdmin CRUD URLs in Twig templates using ea_url() Source: https://symfony.com/bundles/EasyAdminBundle/current/crud.html Shows how to use the ea_url() Twig function to generate EasyAdmin URLs, mirroring the controller examples. Set the controller, and the dashboard if multiple dashboards exist. Additional parameters like product.id are used for edit action. ```twig {# if your application defines only one Dashboard #} {% set url = ea_url() .setController('App\\Controller\\Admin\\ProductCrudController') .setAction('index') %} {# if you prefer PHP constants, use this: .setAction(constant('EasyCorp\\Bundle\\EasyAdminBundle\\Config\\Action::INDEX')) #} {# if your application defines multiple Dashboards #} {% set url = ea_url() .setDashboard('App\\Controller\\Admin\\DashboardController') .setController('App\\Controller\\Admin\\ProductCrudController') .setAction('index') %} {# some actions require additional parameters #} {% set url = ea_url() .setController('App\\Controller\\Admin\\ProductCrudController') .setAction('edit') .setEntityId(product.id) %} ``` -------------------------------- ### Use ea().templatePath() to include templates by name in Twig Source: https://symfony.com/bundles/EasyAdminBundle/current/crud.html Use ea().templatePath() in Twig to get the actual path for a template name, so custom templates are used automatically. This example includes the flash_messages template and conditionally includes the label/null template when a variable is null. ```twig
{{ include(ea().templatePath('flash_messages')) }}
{% if some_value is null %} {{ include(ea().templatePath('label/null')) }} {% endif %} ``` -------------------------------- ### Enable allowRiskyInlineRender on FileField Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html The first block is a placeholder value ("1") shown in the source before the actual code example. The second block shows how to enable the allowRiskyInlineRender option on a FileField, which disables the forced download protection for risky file types. Only enable this when uploads are restricted to trusted users, sanitized, or served from a separate domain. ```text 1 ``` ```php yield FileField::new('...')->allowRiskyInlineRender(); ``` -------------------------------- ### Different fields per page using $pageName Source: https://symfony.com/bundles/EasyAdminBundle/current/fields.html Use the $pageName argument to return different fields for each page. The example checks for Crud::PAGE_INDEX and Crud::PAGE_DETAIL, returning different field sets; the '...' placeholders are not actual code. ```php use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; public function configureFields(string $pageName): iterable { $id = IdField::new('id'); $firstName = TextField::new('firstName'); $lastName = TextField::new('lastName'); $phone = TextField::new('phone'); $email = EmailField::new('email'); $createdAt = DateTimeField::new('createdAt'); if (Crud::PAGE_INDEX === $pageName) { return [$id, $firstName, $lastName, $phone]; } elseif (Crud::PAGE_DETAIL === $pageName) { return ['...']; } else { return ['...']; } } ``` -------------------------------- ### setThousandsSeparator option example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/IntegerField.html Uses the setThousandsSeparator option to set the character used to separate thousands groups. The example displays '12345' as '12 345'. ```php // this would display '12345' as '12 345' yield IntegerField::new('...')->setThousandsSeparator(' '); ``` -------------------------------- ### SKILL.md front matter with metadata Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Shows the front matter of the SKILL.md file with the metadata section including author, easyadmin-version, and installed-by lines. The installed-by line indicates EasyAdmin maintains this copy; deleting it makes the file yours. ```markdown # .claude/skills/easyadmin/SKILL.md --- name: easyadmin # ... metadata: author: EasyCorp easyadmin-version: '5.5.2' installed-by: 'easyadmin:ai:install' --- ``` -------------------------------- ### setDecimalSeparator option example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/NumberField.html Sets a custom decimal separator for the field, overriding the locale default. For example, with ',' the value 12345.67 is displayed as '12345,67'. This option overrides the setDecimalSeparator() CRUD option for this field only. ```php // this would display '12345.67' as '12345,67' yield NumberField::new('...')->setDecimalSeparator(','); ``` -------------------------------- ### Check EasyAdmin AI skill updates with --check Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Writes nothing. Returns 0 when all copies and instruction blocks match the project's EasyAdmin version, 1 when any is outdated. Compares file contents, not version numbers. ```bash $ php bin/console easyadmin:ai:update --check ``` -------------------------------- ### setUploadedFileNamePattern with closure Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html Uses a closure to generate the uploaded file name. The closure receives the UploadedFile instance as its first argument and the current entity instance as the second argument (not shown here). The returned string still undergoes placeholder substitution, so you can combine both mechanisms. ```php yield FileField::new('...')->setUploadedFileNamePattern( fn (UploadedFile $file): string => sprintf('upload_%d_%s.%s', random_int(1, 999), $file->getFilename(), $file->guessExtension()) ); ``` -------------------------------- ### setNumberFormat option example Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/NumberField.html Formats the number using a sprintf() format string. For example, '%e' displays numbers in scientific notation. This option overrides the setNumberFormat() CRUD option for this field only. Using this option makes EasyAdmin ignore the setNumDecimals() and setRoundingMode() options. ```php // this would display numbers in scientific notation (e.g. 123456.7890 = '1.234568e+5') yield NumberField::new('...')->setNumberFormat('%e'); ``` -------------------------------- ### Configure fields by returning property name strings Source: https://symfony.com/bundles/EasyAdminBundle/current/fields.html Option 1: Return an array of property names as strings. EasyAdmin automatically creates the appropriate field objects and applies default configuration for each property. ```php public function configureFields(string $pageName): iterable { return [ 'title', 'description', 'price', 'stock', 'publishedAt', ]; } ``` -------------------------------- ### showFlag option Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/CountryField.html Use showFlag(false) to hide the flag. The second example shows how to hide it only in form pages. ```php yield CountryField::new('...')->showFlag(false); // hide it in form pages only yield CountryField::new('...')->showFlag(Crud::PAGE_NEW !== $pageName && Crud::PAGE_EDIT !== $pageName); ``` -------------------------------- ### Configure Actions in ProductCrudController Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Shows the basic structure of a CRUD controller with the configureActions() method where actions are configured. The method receives an Actions object and returns it after configuration. ```php namespace App\Controller\Admin; use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; class ProductCrudController extends AbstractCrudController { // ... public function configureActions(Actions $actions): Actions { // ... } } ``` -------------------------------- ### showName option Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/CountryField.html Use showName(false) to hide the country name. The second example shows how to show it only in form pages. ```php yield CountryField::new('...')->showName(false); // show it only in form pages yield CountryField::new('...')->showName(Crud::PAGE_NEW === $pageName || Crud::PAGE_EDIT === $pageName); ``` -------------------------------- ### setUploadedFileNamePattern with placeholder pattern Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html Sets a file name pattern for uploaded files. The pattern supports placeholders like [YYYY], [MM], [DD], [slug], [contenthash], and [extension]. The old [day], [month], and [year] placeholders are deprecated and will be removed in EasyAdmin 6.0. ```php yield FileField::new('...') ->setUploadedFileNamePattern('[YYYY]/[MM]/[DD]/[slug]-[contenthash].[extension]'); ``` -------------------------------- ### Using enum with setChoices Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/ChoiceField.html Shows how to use a backed enum with setChoices(), either with all cases or a subset. ```php // you can set the options as all the possible cases of the Enum explicitly yield ChoiceField::new('status')->setChoices(BlogPostStatus::cases()); // you can select only some of the possible enum values: yield ChoiceField::new('status')->setChoices([BlogPostStatus::Draft, BlogPostStatus::Published]); ``` -------------------------------- ### setUploadedFileNamePattern with closure Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/ImageField.html Accepts a closure that receives Symfony's UploadedFile instance to generate a custom file name. The returned string still undergoes placeholder substitution. ```php yield ImageField::new('...')->setUploadedFileNamePattern( fn (UploadedFile $file): string => sprintf('upload_%d_%s.%s', random_int(1, 999), $file->getFilename(), $file->guessExtension()) ); ``` -------------------------------- ### Configure Gemini CLI to read AGENTS.md Source: https://symfony.com/bundles/EasyAdminBundle/current/ai-coding-agents.html Add this to your project's `.gemini/settings.json` so Gemini CLI reads `AGENTS.md` in addition to its default `GEMINI.md`. Without this, Gemini CLI ignores the instructions block added to `AGENTS.md`. ```json { "context": { "fileName": ["AGENTS.md", "GEMINI.md"] } } ``` -------------------------------- ### Doctrine entity with enum property Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/ChoiceField.html Doctrine entity with a property using an enum type. EasyAdmin automatically gets all possible enum values for such properties. ```php #[Entity] class BlogPost { // ... #[Column(type: 'string', enumType: BlogPostStatus::class)] public $status; } ``` -------------------------------- ### Enable action confirmation with askConfirmation() Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Enable a confirmation modal for an action by calling askConfirmation() with no arguments. The modal shows a generic message before the action executes. This is useful for destructive or important actions. ```php use EasyCorp\Bundle\EasyAdminBundle\Config\Action; use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; public function configureActions(Actions $actions): Actions { $archiveAction = Action::new('archive', 'Archive') ->linkToCrudAction('archive') ->askConfirmation(); return $actions ->add(Crud::PAGE_INDEX, $archiveAction); } ``` -------------------------------- ### setTargetFieldName with multiple fields Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/SlugField.html Pass an array of field names to concatenate their slugs in the given order. The example shows 'year', 'type', and 'title' producing '2023-news-lorem-ipsum'. ```php // the slugs are concatenated in the same order (e.g. '2023-news-lorem-ipsum') yield SlugField::new('...')->setTargetFieldName(['year', 'type', 'title']); ``` -------------------------------- ### Generate Dashboard Controller Command Source: https://symfony.com/bundles/EasyAdminBundle/current/dashboards.html Use this command to quickly generate a dashboard controller in EasyAdmin. After running it, visiting the /admin URL shows the default Welcome Page. ```shell $ php bin/console make:admin:dashboard ``` -------------------------------- ### Entity with array country codes Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/CountryField.html Example entity that converts between a string property and an array of country codes, using '|' as a delimiter. This is useful when allowMultipleChoices is enabled. ```php class MyEntity { // ... public function getCountry(): ?array { return '' === $this->country ? null : explode('|', $this->country); } public function setCountry(?array $countryCodes): self { $this->country = null === $countryCodes ? '' : implode('|', $countryCodes); return $this; } } ``` -------------------------------- ### Get AdminContext via AdminContextProvider in a service Source: https://symfony.com/bundles/EasyAdminBundle/current/dashboards.html Inject the AdminContextProvider service into a service to obtain the AdminContext object. The getContext() method returns the context for the current request. ```php use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider; final class SomeService { public function __construct( private AdminContextProvider $adminContextProvider, ) { } public function someMethod() { $context = $this->adminContextProvider->getContext(); } // ... } ``` -------------------------------- ### stripTags option usage Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/TextField.html Strips HTML tags from contents before displaying, using PHP's strip_tags() function. For example, foo becomes foo. ```php // if original contents are foo, it only displays foo yield TextField::new('...')->stripTags(); ``` -------------------------------- ### Restrict field visibility with setPermission() Source: https://symfony.com/bundles/EasyAdminBundle/current/security.html Use setPermission() on a field to hide it from users who lack the given role. In this example, the 'sales' field requires ROLE_ADMIN and 'commission' requires ROLE_FINANCE. ```php public function configureFields(string $pageName): iterable { return [ IdField::new('id'), TextField::new('price'), IntegerField::new('stock'), // users must have this permission/role to see this field IntegerField::new('sales')->setPermission('ROLE_ADMIN'), NumberField::new('commission')->setPermission('ROLE_FINANCE'), // ... ]; } ``` -------------------------------- ### Create global action with Action::new and linkToUrl Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Creates a custom global action that links to an external URL and adds it to the index page. Use this when you need a global action above the listed entries on the index page. ```php $goToStripe = Action::new('goToStripe') ->linkToUrl('https://www.stripe.com/') ->createAsGlobalAction() ; $actions->add(Crud::PAGE_INDEX, $goToStripe); ``` -------------------------------- ### Configure Flysystem storage in config/packages/flysystem.yaml Source: https://symfony.com/bundles/EasyAdminBundle/current/fields/FileField.html Configure the Flysystem storage service in your application. The key 'default.storage' is used later in setFlysystemStorage(). ```yaml # config/packages/flysystem.yaml flysystem: storages: default.storage: aws: client: 'Aws\S3\S3Client' bucket: 'my-bucket' ``` -------------------------------- ### Replace or add action with set() in configureActions Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Use the set() method to add an action or replace an existing one with the same name. This avoids the exception thrown by add() when the action already exists. ```php public function configureActions(Actions $actions): Actions { return $actions // ... // this replaces the built-in 'detail' action if it's already added ->set(Crud::PAGE_INDEX, $myCustomDetailAction) ; } ``` -------------------------------- ### Define fields with PHP generators Source: https://symfony.com/bundles/EasyAdminBundle/current/fields.html Use PHP generators to define fields with greater control. The example yields fields conditionally based on an expression, and the '... some expression ...' is a placeholder for your own condition. ```php public function configureFields(string $pageName): iterable { yield IdField::new('id')->hideOnForm(); if ('... some expression ...') { yield TextField::new('firstName'); yield TextField::new('lastName'); } yield TextField::new('phone'); yield EmailField::new('email')->hideOnIndex(); yield DateTimeField::new('createdAt')->onlyOnDetail(); } ``` -------------------------------- ### Define custom action basics with Action::new() Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Create a custom action with Action::new(), specifying the internal name, optional label, and optional icon. The label can be null to autogenerate from the name, or false to hide it (then an icon is required). ```php // the only mandatory argument is the internal name of the action (which is // used to add the action to some pages, to reorder the action position, etc.) $viewInvoice = Action::new('viewInvoice'); // the second optional argument is the label visible to end users $viewInvoice = Action::new('viewInvoice', 'Invoice'); // not defining the label explicitly or setting it to NULL means // that the label is autogenerated from the name (e.g. 'viewInvoice' -> 'View Invoice') $viewInvoice = Action::new('viewInvoice', null); // set the label to FALSE to not display any label for this action (but make sure // to display an icon for the action; otherwise users can't see or click on the action) $viewInvoice = Action::new('viewInvoice', false); // the third optional argument is the icon name $viewInvoice = Action::new('viewInvoice', 'Invoice', 'fa fa-file-invoice'); ``` -------------------------------- ### Configure custom action rendering and styling Source: https://symfony.com/bundles/EasyAdminBundle/current/actions.html Configure the rendering and styling of a custom action: render as link, button, or form; set HTML attributes; apply built-in styling methods (asDefaultAction, asPrimaryAction, etc.); set or add CSS classes; set translation parameters; or use a custom Twig template. ```php $viewInvoice = Action::new('viewInvoice', 'Invoice', 'fa fa-file-invoice') // actions created with Action::new() are rendered as `` elements that // trigger GET requests; use this method to restore that rendering when // some other method changed it ->renderAsLink() // this method renders the action as a `