### Install Frontend Dependencies Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Installs frontend dependencies using NPM. Use 'npm clean-install' for a fresh installation or 'npm install' to upgrade packages. ```bash npm clean-install ``` ```bash npm install ``` -------------------------------- ### Full CarAdmin Example with Custom Action Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_custom_action.md A complete example of an admin class (`CarAdmin`) demonstrating the integration of a custom 'clone' action, including route definition and list field configuration. ```php // src/Admin/CarAdmin.php namespace App\Admin; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Route\RouteCollection; final class CarAdmin extends AbstractAdmin { protected function configureRoutes(RouteCollectionInterface $collection): void { $collection ->add('clone', $this->getRouterIdParameter().'/clone'); } protected function configureListFields(ListMapper $list): void { $list ->addIdentifier('name') ->add('engine') ->add('rescueEngine') ->add('createdAt') ->add(ListMapper::NAME_ACTIONS, null, [ 'actions' => [ 'show' => [], 'edit' => [], 'delete' => [], 'clone' => [ 'template' => '@App/CRUD/list__action_clone.html.twig', ] ] ]); } } ``` -------------------------------- ### Install Symfony Maker Bundle Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/console.md Installs the Symfony Maker Bundle, which is required for the `make:sonata:admin` command. Install this in development environments. ```bash composer require symfony/maker-bundle --dev ``` -------------------------------- ### Install yokai/sonata-workflow Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_workflow_integration.md Use Composer to download the necessary library for integrating Symfony Workflow with Sonata. ```bash composer require yokai/sonata-workflow ``` -------------------------------- ### Install Python Dependencies for Documentation Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Installs the necessary Python packages, including Sphinx, for rendering documentation. Ensure your Python environment is set up and pip is available. ```bash pip install --requirement docs/requirements.txt --user ``` -------------------------------- ### Initialize ACL Tables Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/security.md Run this console command to initialize the necessary database tables for ACL functionality. This is a one-time setup step. ```bash bin/console init:acl ``` -------------------------------- ### PHP Docblock and Type Hinting Example Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Example demonstrating preferred usage of phpdoc annotations, including @phpstan- annotations for static analysis and type hinting. Multiline signatures are allowed for lines exceeding 120 characters. ```php /** * @param Bar|Baz $foo * @param class-string $class * @param int $limit a crucial, fascinating comment * * @return object * * @phpstan-template T of object * @phpstan-param class-string $class * @phpstan-return T */ protected function bar($foo, string $class, int $limit): object { // ... } ``` -------------------------------- ### Install SonataAdminBundle with Composer Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/getting_started/installation.md Use Composer to add the SonataAdminBundle to your project dependencies. This command should be run in your project's root directory. ```bash composer require sonata-project/admin-bundle ``` -------------------------------- ### Build and View Documentation Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Builds the project documentation locally using Sphinx and opens it in your default browser. This command assumes Python dependencies are installed and the PATH environment variable is correctly configured. ```bash $YOUR_FAVORITE_BROWSER docs/_build/html/index.html ``` -------------------------------- ### Example: Boolean Filter with Default Values Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/action_list.md This example demonstrates setting default filter values for an 'enabled' field using `EqualType` and `BooleanType` constants. Ensure the correct integer values are used for the filter. ```php use Sonata\Form\Type\EqualType; use Sonata\Form\Type\BooleanType; final class UserAdmin extends Sonata\UserBundle\Admin\Model\UserAdmin { protected function configureDefaultFilterValues(array &$filterValues): void { $filterValues['enabled'] = [ 'type' => EqualType::TYPE_IS_EQUAL, // => 1 'value' => BooleanType::TYPE_YES // => 1 ]; } } ``` -------------------------------- ### Setup ACL Definitions Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/console.md Updates ACL definitions for all available Admin classes. Run this command after creating new Admin classes to ensure ACLs are up-to-date. ```bash bin/console sonata:admin:setup-acl ``` -------------------------------- ### Clear Cache and Install Assets Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/getting_started/installation.md After installation and configuration, clear the application cache and install necessary assets using Symfony's console commands. This ensures all changes are applied correctly. ```bash bin/console cache:clear ``` ```bash bin/console assets:install ``` -------------------------------- ### Example Entity Class Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_data_mapper.md Defines an entity with a constructor and an update method, avoiding individual setters for fields. ```php namespace App\Entity; final class Example { private string $name; private string $description; public function __construct(string $name, string $description) { $this->name = $name; $this->description = $description; } public function update(string $description) { $this->description = $description } // rest of the code goes here } ``` -------------------------------- ### Commit Message with Description Example Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Illustrates a commit message with a clear subject and a detailed description explaining the 'why' behind the changes and referencing related issues. ```text call foo::bar() instead of bar::baz() This fixes a bug that arises when doing this or that, because baz() needs a flux capacitor object that might not be defined. Fixes #42 ``` -------------------------------- ### Custom RouteBuilder Implementation Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/advanced_configuration.md Implement the RouteBuilderInterface to create a custom route builder. This example shows how to extend the default PathInfoBuilder and add/remove routes. ```php namespace App\Route; use Sonata\AdminBundle\Builder\RouteBuilderInterface; use Sonata\AdminBundle\Admin\AdminInterface; use Sonata\AdminBundle\Route\PathInfoBuilder; use Sonata\AdminBundle\Route\RouteCollectionInterface; final class EntityRouterBuilder implements RouteBuilderInterface { private PathInfoBuilder $pathInfoBuilder; public function __construct(PathInfoBuilder $pathInfoBuilder) { $this->pathInfoBuilder = $pathInfoBuilder; } public function build(AdminInterface $admin, RouteCollectionInterface $collection) { $this->pathInfoBuilder->build($admin, $collection); $collection->add('yourSubAction'); // The create button will disappear, delete functionality will be disabled as well // No more changes needed! $collection->remove('create'); $collection->remove('delete'); } } ``` -------------------------------- ### Configure Show View with Groups and Tabs Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/getting_started/the_show_view.md Organize fields in the show view using tabs and groups, similar to the FormMapper. This example demonstrates creating a 'Post' tab with 'Content' and 'Meta data' groups, and a 'Publish Options' tab. ```php protected function configureShowFields(ShowMapper $show): void { $show ->tab('Post') ->with('Content', ['class' => 'col-md-9']) // ... ->end() ->with('Meta data', ['class' => 'col-md-3']) // ... ->end() ->end() ->tab('Publish Options') // ... ->end() ; } ``` -------------------------------- ### Add Custom Action to Dashboard (Template) Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_custom_action.md Configure dashboard actions by overwriting `getDashboardActions` and specifying a template for the action. This example adds an 'import' action to the dashboard. ```php protected function configureDashboardActions(array $actions): array { $actions['import'] = ['template' => 'import_dashboard_button.html.twig']; return $actions; } ``` -------------------------------- ### Bad Commit Message Subject Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Avoid vague subjects. This example is too generic and doesn't convey the specific action taken. ```text Update README.md ``` -------------------------------- ### UserAdmin preUpdate Hook Example Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/saving_hooks.md Implement the preUpdate hook in a UserAdmin class to handle user password and canonical field updates before the object is persisted. ```php namespace Sonata\UserBundle\Admin\Entity; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Form\Type\ModelType; use Sonata\UserBundle\Form\Type\SecurityRolesType; use Sonata\UserBundle\Model\UserManagerInterface; final class UserAdmin extends AbstractAdmin { private UserManagerInterface $userManager; public function __construct(UserManagerInterface $userManager) { $this->userManager = $userManager; } protected function configureFormFields(FormMapper $form): void { $form ->with('General') ->add('username') ->add('email') ->add('plainPassword', 'text') ->end() ->with('Groups') ->add('groups', ModelType::class, ['required' => false]) ->end() ->with('Management') ->add('roles', SecurityRolesType::class, ['multiple' => true]) ->add('locked', null, ['required' => false]) ->add('expired', null, ['required' => false]) ->add('enabled', null, ['required' => false]) ->add('credentialsExpired', null, ['required' => false]) ->end() ; } public function preUpdate(object $user): void { $this->userManager->updateCanonicalFields($user); $this->userManager->updatePassword($user); } } ``` -------------------------------- ### Dashboard Block Layout Example Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/dashboard.md Illustrates the positioning of dashboard blocks, showing supported zones like 'top', 'left', 'center', 'right', and 'bottom'. The 'top' and 'bottom' positions can also accept a 'class' option for width control. ```yaml sonata_admin: dashboard: blocks: # display dashboard block in the top zone with a col-md-6 css class - position: top class: col-md-6 type: sonata.admin.block.admin_list ``` -------------------------------- ### Configure Label Strategy in Services XML Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/translation.md Set the label translator strategy for an admin service in the services.xml configuration file. This example uses the 'sonata.admin.label.strategy.native' strategy. ```xml ``` -------------------------------- ### Registering Custom Routes in configureRoutes Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_decouple_crud_controller.md Define custom routes within the configureRoutes method of your admin class. This example shows how to add both a controller action and an invokable controller. ```php use App\Controller\CarAdminSoldAction; use Sonata\AdminBundle\Route\RouteCollectionInterface; protected function configureRoutes(RouteCollectionInterface $collection) { $collection ->add('clone', $this->getRouterIdParameter().'/clone', [ '_controller' => 'App\Controller\CarAdminController::clone', ]) // Using invokable controller: ->add('sold', $this->getRouterIdParameter().'/sold', [ '_controller' => CarAdminSoldAction::class, ]); } ``` -------------------------------- ### Import and Use jQuery UI Plugins Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_jquery_ui.md Import the necessary jQuery UI widget and the specific plugin you want to use. After importing, you can initialize the plugin on selected elements. This example shows how to use the draggable and sortable plugins. ```javascript import $ from 'jquery'; import 'jquery-ui/ui/widget'; import 'jquery-ui/ui/widgets/draggable'; $('.foo').draggable(); // The new UI plugin can be used. $('.bar').sortable(); // The already loaded by sonata plugin can be used too. ``` -------------------------------- ### Define Custom Batch Action in Admin Class Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/batch_actions.md Override `configureBatchActions` to define new batch actions. This example adds a 'merge' action, conditional on edit and delete route/access permissions. ```php protected function configureBatchActions(array $actions): array { if ( $this->hasRoute('edit') && $this->hasAccess('edit') && $this->hasRoute('delete') && $this->hasAccess('delete') ) { $actions['merge'] = [ 'ask_confirmation' => true, 'controller' => 'app.controller.merge::batchMergeAction', // Or 'App/Controller/MergeController::batchMergeAction' base on how you declare your controller service. ]; } return $actions; } ``` -------------------------------- ### Implement Batch Action Controller Logic Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/batch_actions.md Implement the core logic for a batch action in a Symfony controller. This example handles merging selected items, including checking permissions, finding a target, processing selected models, and providing flash messages. ```php // src/Controller/MergeController.php namespace App\Controller; use Sonata\AdminBundle\Admin\AdminInterface; use Sonata\AdminBundle\Datagrid\ProxyQueryInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; class MergeController extends AbstractController { public function batchMergeAction(ProxyQueryInterface $query, AdminInterface $admin): RedirectResponse { $admin->checkAccess('edit'); $admin->checkAccess('delete'); $modelManager = $admin->getModelManager(); $target = $modelManager->find($admin->getClass(), $request->get('targetId')); if ($target === null) { $this->addFlash('sonata_flash_info', 'flash_batch_merge_no_target'); return new RedirectResponse( $admin->generateUrl('list', [ 'filter' => $admin->getFilterParameters() ]) ); } $selectedModels = $query->execute(); // do the merge work here try { foreach ($selectedModels as $selectedModel) { $modelManager->delete($selectedModel); } $this->addFlash('sonata_flash_success', 'flash_batch_merge_success'); } catch (\Exception $e) { $this->addFlash('sonata_flash_error', 'flash_batch_merge_error'); } finally { return new RedirectResponse( $admin->generateUrl('list', [ 'filter' => $admin->getFilterParameters() ]) ); } } // ... } ``` -------------------------------- ### Child Admin Route Name Example Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/routing.md Demonstrates how a child Admin class's route name is prefixed by its parent's route name. The parent defines 'sonata_post', and the child 'comment', resulting in 'sonata_post_comment_list'. ```php // The parent admin class final class PostAdmin extends AbstractAdmin { protected function generateBaseRouteName(bool $isChildAdmin = false): string { return 'sonata_post'; } } ``` ```php // The child admin class final class CommentAdmin extends AbstractAdmin { protected function generateBaseRouteName(bool $isChildAdmin = false): string { return 'comment'; } // will result in routes named : // sonata_post_comment_list // sonata_post_comment_create // etc.. // ... } ``` -------------------------------- ### Child Admin Route Pattern Example Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/routing.md Illustrates how a child Admin class's route pattern is prefixed by its parent's. The parent uses 'post', the child 'comment', leading to URLs like '/admin/post/{postId}/comment/{commentId}/edit'. ```php // The parent admin class final class PostAdmin extends AbstractAdmin { protected function generateBaseRoutePattern(bool $isChildAdmin = false): string { return 'post'; } // ... } ``` ```php // The child admin class final class CommentAdmin extends AbstractAdmin { protected function generateBaseRoutePattern(bool $isChildAdmin = false): string { return 'comment'; } // ... } ``` -------------------------------- ### Define SonataAdminBundle Routes Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/getting_started/installation.md Configure routing in `config/routes/sonata_admin.yaml` to make the SonataAdminBundle's pages accessible via the `/admin` prefix. This setup uses a specific resource type for Sonata Admin routes. ```yaml # config/routes/sonata_admin.yaml admin_area: resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml' prefix: /admin _sonata_admin: resource: . type: sonata_admin prefix: /admin ``` -------------------------------- ### Add Custom Clone Route Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_custom_action.md Define a custom route for a 'clone' action within the `configureRoutes` method of your admin class. This example shows how to create a route that includes the entity's ID. ```php use Sonata\AdminBundle\Route\RouteCollectionInterface; protected function configureRoutes(RouteCollectionInterface $collection): void { $collection ->add('clone', $this->getRouterIdParameter().'/clone'); } ``` -------------------------------- ### ModelAutocompleteType with Custom Callback Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/form_types.md This example shows how to use a custom callback function to modify the query used for retrieving autocomplete items. It demonstrates how to access the Datagrid and Request objects to add custom filtering conditions. ```php $form ->add('category', ModelAutocompleteType::class, [ 'property' => 'title', 'callback' => static function (AdminInterface $admin, string $property, $value): void { $datagrid = $admin->getDatagrid(); $query = $datagrid->getQuery(); $query ->andWhere($query->getRootAlias() . '.foo=:barValue') ->setParameter('barValue', $admin->getRequest()->get('bar')) ; $datagrid->setValue($property, null, $value); }, ]) ; ``` -------------------------------- ### Setup CRUD ACL Rules for Admin Classes Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/security.md Install or update the CRUD ACL rules for your Admin classes. This command assigns default roles and permissions for viewing, editing, creating, and operating on admin resources. ```bash bin/console sonata:admin:setup-acl Starting ACL AdminBundle configuration > install ACL for sonata.media.admin.media - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_GUEST, permissions: ["VIEW","LIST"] - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_STAFF, permissions: ["EDIT","LIST","CREATE"] - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_EDITOR, permissions: ["OPERATOR","EXPORT"] - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_ADMIN, permissions: ["MASTER"] ... skipped ... ``` -------------------------------- ### ExampleAdmin Configuration Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_data_mapper.md Configures the SonataAdmin class to utilize the custom ExampleDataMapper for form field handling. ```php namespace App\Admin; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Form\FormMapper; use App\Form\DataMapper\ExampleDataMapper; final class ExampleAdmin extends AbstractAdmin { protected function configureFormFields(FormMapper $form): void { $form ->add('name', null) ->add('description', null) ; $builder = $form->getFormBuilder(); $builder->setDataMapper(new ExampleDataMapper()); } // ... } ``` -------------------------------- ### Create Super Admin User Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/security.md Use this command to create a new user with super-admin privileges. You will be prompted to enter username, email, and password. ```bash bin/console sonata:user:create --super-admin Please choose a username:root Please choose an email:root@domain.com Please choose a password:root Created user root ``` -------------------------------- ### Get Breadcrumbs for Admin Action Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/breadcrumbs.md Use the `sonata.admin.breadcrumbs_builder` service to retrieve breadcrumb data for a specific admin and action. ```php $this->get('sonata.admin.breadcrumbs_builder')->getBreadcrumbs($admin, $action); ``` -------------------------------- ### Configure ModelAutocompleteType in SonataAdminBundle Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/form_types.md Example of configuring the ModelAutocompleteType in an AbstractAdmin class to set the property for searching and specify a custom template. ```php // src/Admin/ArticleAdmin.php use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Form\Type\ModelAutocompleteType; final class ArticleAdmin extends AbstractAdmin { protected function configureFormFields(FormMapper $form): void { $form ->add('category', ModelAutocompleteType::class, [ 'property' => 'title', 'template' => '@App/Form/Type/sonata_type_model_autocomplete.html.twig', ]) ; } } ``` -------------------------------- ### Explain Admin Service Details Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/console.md Prints detailed information about a specific admin service. Requires the admin service ID as an argument. ```bash bin/console sonata:admin:explain sonata.news.admin.post ``` -------------------------------- ### Pluralized Translation Message Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/dashboard.md Example of a pluralized translation message for the 'app.page.stats' in an XLIFF file. This is used for dynamic display of counts. ```xml app.page.stats {0} results|{1} result|]1,Inf] results ``` -------------------------------- ### Use Menu Provider for Dynamic Menus Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_knp_menu.md Configure a menu group to be populated by a KnpMenu provider. This allows for complex, business-logic-driven menus. ```yaml # config/packages/sonata_admin.yaml sonata_admin: dashboard: groups: my_group: provider: 'MyBundle:MyMenuProvider:getMyMenu' icon: 'fas fa-edit' # html is also supported ``` -------------------------------- ### List Available Admin Services Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/console.md Prints all available admin service IDs registered in the `sonata.admin.pool`. Use this to verify admin configurations. ```bash bin/console sonata:admin:list ``` -------------------------------- ### Add ModelAutocompleteType Field with Custom Attributes Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/form_types.md Example of adding a ModelAutocompleteType field to a form, including custom HTML attributes for client-side integration. ```php $form ->add('category', ModelAutocompleteType::class, [ 'property' => 'title', 'attr' => [ 'data-my-custom-variable' => 'my-custom-value', ], ]) ; ``` -------------------------------- ### Configure Sonata Admin for BlogPost with Workflow Extension Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_workflow_integration.md Register the BlogPost admin service and the WorkflowExtension in Sonata's configuration. Specify the workflow transitions and their corresponding icons. ```yaml services: app.admin.blog_post: class: App\Admin\BlogPostAdmin tags: - { name: sonata.admin, model_class: App\Entity\BlogPost, controller: Yokai\SonataWorkflow\Controller\WorkflowController, manager_type: orm } app.admin.extension.workflow.blog_post: class: Yokai\SonataWorkflow\Admin\Extension\WorkflowExtension arguments: - '@workflow.registry' - transitions_icons: start_review: fas fa-question interrupt_review: fas fa-edit restart_review: fas fa-question publish: fas fa-check ``` -------------------------------- ### ModelAutocompleteType with Custom ToString Callback Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/form_types.md This example shows how to customize the string representation of an entity displayed in the autocomplete suggestions by providing a 'to_string_callback' function. ```php $form ->add('category', ModelAutocompleteType::class, [ 'property' => 'title', 'to_string_callback' => function($entity, $property) { return $entity->getTitle(); }, ]) ; ``` -------------------------------- ### Complete ClientAdmin Configuration Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_sortable_listing.md Combine the SortableAdminTrait with the ListMapper configuration in your Admin class to fully enable sortable behavior. ```php // src/Admin/ClientAdmin.php namespace App\Admin; use Runroom\SortableBehaviorBundle\Admin\SortableAdminTrait; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Datagrid\ListMapper; final class ClientAdmin extends AbstractAdmin { use SortableAdminTrait; protected function configureListFields(ListMapper $list): void { $list ->addIdentifier('name') ->add('enabled') ->add(ListMapper::NAME_ACTIONS, ListMapper::TYPE_ACTIONS, [ 'actions' => [ 'move' => [ 'template' => '@RunroomSortableBehavior/sort.html.twig' ], ], ]) ; } } ``` -------------------------------- ### Compile Frontend Assets for Production Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Compiles and optimizes frontend assets for production using Webpack Encore. This command also runs lint checks. ```bash npx encore production ``` -------------------------------- ### Override Base Route Pattern Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/routing.md Override `generateBaseRoutePattern` to set a custom URL pattern for your Admin class. This example sets the base URL to '/admin/foo'. ```php final class FooAdmin extends AbstractAdmin { protected function generateBaseRoutePattern(bool $isChildAdmin = false): string { return 'foo'; } } ``` -------------------------------- ### Configuring List Field with Data Transformer Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/action_list.md Example of configuring a Sonata Admin list field to use a custom Data Transformer for a 'choice' type. ```php // ... protected function configureListFields(ListMapper $list): void { $list ->add('moderation_status', 'choice', [ 'editable' => true, 'choices' => ModerationStatus::choices(), 'data_transformer' => new ModerationStatusDataTransformer(), ]) ; } ``` -------------------------------- ### Create Custom Controller for Menu Entry Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_knp_menu.md Define a controller with routes that can be linked in the admin menu. Ensure routes are properly defined with names. ```php use Symfony\Component\HttpFoundation\Response; final class BlogController { /** * @Route("/blog", name="blog_home") */ public function blogAction(): Response { // ... } /** * @Route("/blog/article/{articleId}", name="blog_article") */ public function ArticleAction(string $articleId): Response { // ... } } ``` -------------------------------- ### ExampleDataMapper Implementation Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_data_mapper.md Implements DataMapperInterface to map data between forms and entities that lack setters. Handles both new entity creation and updates. ```php namespace App\Form\DataMapper; use Symfony\Component\Form\DataMapperInterface; use App\Entity\Example; final class ExampleDataMapper implements DataMapperInterface { /** * @param Example $data * @param FormInterface[]|\Traversable $forms */ public function mapDataToForms($data, $forms) { if (null !== $data) { $forms = iterator_to_array($forms); $forms['name']->setData($data->getName()); $forms['description']->setData($data->getDescription()); } } /** * @param FormInterface[]|\Traversable $forms * @param Example $data */ public function mapFormsToData($forms, &$data) { $forms = iterator_to_array($forms); if (null === $data->getId()) { $name = $forms['name']->getData(); $description = $forms['description']->getData(); // New entity is created $data = new Example( $name, $description ); } else { $data->update( $forms['description']->getData() ); } } } ``` -------------------------------- ### Good Commit Message with Description Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md An example of a well-structured commit message, including a descriptive subject and a detailed explanation in the body, referencing multiple issues. ```text Change web UI background color to pink This is a consensus made on #4242 in addition to #1337. We agreed that blank color is boring and so deja vu. Pink is the new way to do. ``` -------------------------------- ### Add Image Preview in Basic SonataAdmin Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_image_previews.md Use 'help' and 'help_html' options in `configureFormFields` to display an image preview. This method works for single-layer Admins. Ensure the `Image::getWebPath()` helper method is available. ```php final class ImageAdmin extends AbstractAdmin { protected function configureFormFields(FormMapper $form): void { // get the current Image instance $image = $this->getSubject(); // use $fileFormOptions so we can add other options to the field $fileFormOptions = ['required' => false]; if ($image && ($webPath = $image->getWebPath())) { // get the request so the full path to the image can be set $request = $this->getRequest(); $fullPath = $request->getBasePath().'/'.$webPath; // add a 'help' option containing the preview's img tag $fileFormOptions['help'] = ''; $fileFormOptions['help_html'] = true; } $form ->add('file', 'file', $fileFormOptions) ; } } ``` -------------------------------- ### Configure Role Hierarchy in security.yaml Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/security.md Define role hierarchies for SonataAdminBundle permissions in your security.yaml file. This example shows how to group roles for readers, editors, and administrators. ```yaml # config/packages/security.yaml security: # ... role_hierarchy: # for convenience, I decided to gather Sonata roles here ROLE_SONATA_FOO_READER: - ROLE_SONATA_ADMIN_DEMO_FOO_LIST - ROLE_SONATA_ADMIN_DEMO_FOO_VIEW ROLE_SONATA_FOO_EDITOR: - ROLE_SONATA_ADMIN_DEMO_FOO_CREATE - ROLE_SONATA_ADMIN_DEMO_FOO_EDIT ROLE_SONATA_FOO_ADMIN: - ROLE_SONATA_ADMIN_DEMO_FOO_DELETE - ROLE_SONATA_ADMIN_DEMO_FOO_EXPORT # those are the roles I will use (less verbose) ROLE_STAFF: [ROLE_USER, ROLE_SONATA_FOO_READER] ROLE_ADMIN: [ROLE_STAFF, ROLE_SONATA_FOO_EDITOR, ROLE_SONATA_FOO_ADMIN] ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] # you could alternatively use for an admin who has all rights ROLE_ALL_ADMIN: [ROLE_STAFF, ROLE_SONATA_FOO_ALL] # set access_strategy to unanimous, else you may have unexpected behaviors access_decision_manager: strategy: unanimous ``` -------------------------------- ### Configure Global Preview Template Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/preview_mode.md Globally set the preview template for all admin entities via the `sonata_admin.templates.preview` configuration key. ```yaml sonata_admin: templates: preview: '@App/CRUD/preview.html.twig' ``` -------------------------------- ### Run Frontend Lint Checks Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Executes ESLint for JavaScript and Stylelint for SCSS to check code quality against defined standards. ```bash npx eslint assets/js ``` ```bash npx stylelint assets/scss ``` -------------------------------- ### Customize Field Route in List View Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/action_list.md Customize the route for a specific field in the List view, for example, to link to the 'edit' action instead of the default 'show'. ```php namespace App\Admin; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Show\ShowMapper; final class MediaAdmin extends AbstractAdmin { protected function configureListFields(ListMapper $list): void { $list ->addIdentifier('field', null, [ 'route' => [ 'name' => 'edit' ] ]); } } ``` -------------------------------- ### Define Show Action Fields with Field Types Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/action_show.md Configure the fields to be displayed in the show action. Supports default text display and specific types like BOOLEAN for custom rendering. ```php protected function configureShowFields(ShowMapper $show): void { // here we set the fields of the ShowMapper variable, // $show (but this can be called anything) $show // The default option is to display the value // as text (for boolean this will be 1 or 0) ->add('name') ->add('phone') ->add('email') // The boolean option is actually very cool // true shows a check mark and the 'yes' label // false shows a check mark and the 'no' label ->add('dateCafe', FieldDescriptionInterface::TYPE_BOOLEAN) ->add('datePub', FieldDescriptionInterface::TYPE_BOOLEAN) ->add('dateClub', FieldDescriptionInterface::TYPE_BOOLEAN) ; } ``` -------------------------------- ### Enable Bootlint in SonataAdminBundle Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_bootlint.md Add this configuration to enable Bootlint integration in your SonataAdminBundle application. Open your browser debugger to view Bootlint warnings in the console. ```yaml sonata_admin: options: use_bootlint: true # enable Bootlint ``` -------------------------------- ### Add Basic Filter/Search Option Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/getting_started/the_list_view.md Configure datagrid filters to allow searching and ordering of items in the list view. This example adds a filter for the 'title' field. ```php namespace App\Admin; use Sonata\AdminBundle\Datagrid\DatagridMapper; final class BlogPostAdmin extends AbstractAdmin { protected function configureDatagridFilters(DatagridMapper $datagrid): void { $datagrid->add('title'); } } ``` -------------------------------- ### Dynamically Add Admin Extension in PHP Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/extensions.md Demonstrates how to programmatically add an extension to an admin class within its `configure` method. This is useful for conditional extension application based on runtime logic. ```php use App\AdminExtension\PublishStatusAdminExtension; use Sonata\AdminBundle\Admin\AbstractAdmin; final class PublishStatusAdmin extends AbstractAdmin { protected function configure(): void { // ... if ($someCondition) { $this->addExtension(new PublishStatusAdminExtension()); } } } ``` -------------------------------- ### Configure Role-Based Security Handler Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/security.md Set the security handler to use role-based permissions. This is suitable for simpler permission management without complex ACL setups. ```yaml sonata_admin: security: handler: sonata.admin.security.handler.role role_admin: ROLE_ADMIN role_super_admin: ROLE_SUPER_ADMIN ``` -------------------------------- ### ICU Message Format Translation Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/dashboard.md Example of using ICU Message Format for pluralized translations, compatible with symfony/translation version 4.2 and above. This provides more advanced pluralization rules. ```xml app.page.stats {count, plural, =0 {results} one {result} other {results}} ``` -------------------------------- ### Create Doctrine Schema Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/getting_started/creating_an_admin.md Command to create the database schema based on the defined Doctrine entities. ```bash bin/console doctrine:schema:create ``` -------------------------------- ### Style Form Groups with Custom Classes Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/getting_started/the_form_view.md Apply custom CSS classes to form groups to control their layout and appearance. This example assigns column classes for a two-column layout. ```php protected function configureFormFields(FormMapper $form): void { $form ->with('Content', ['class' => 'col-md-9']) // ... ->end() ->with('Meta data', ['class' => 'col-md-3']) // ... ->end() ; } ``` -------------------------------- ### Simulate Multi-Field Sorting with Default Orders Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/action_list.md Add default sorting orders for 'author' and 'createdAt' fields in ascending order within the `configureQuery` method to simulate multi-field sorting. ```php protected function configureQuery(ProxyQueryInterface $query): ProxyQueryInterface { $rootAlias = current($query->getRootAliases()); $query->addOrderBy($rootAlias.'.author', 'ASC'); $query->addOrderBy($rootAlias.'.createdAt', 'ASC'); return $query; } ``` -------------------------------- ### Register Custom Action Route without Entity Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_custom_action.md How to register a route for a custom action that is not directly tied to an entity, using the `configureRoutes` method. This example registers an 'import' action. ```php use Sonata\AdminBundle\Route\RouteCollectionInterface; protected function configureRoutes(RouteCollectionInterface $collection): void { $collection->add('import'); } ``` -------------------------------- ### Fix Coding Style with PHP CS Fixer Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Use PHP Coding Standard Fixer to automatically format your code according to project standards before committing. Ensure you have installed it first. ```bash php-cs-fixer fix --verbose ``` -------------------------------- ### Customize ACL Editor Role List in PHP Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/security.md Override the `getAclRoles()` method in a controller to customize the list of roles available in the ACL editor. This example demonstrates how to display only specific roles. ```php protected function getAclRoles(): \Traversable { // Display only ROLE_BAPTISTE and ROLE_HELENE $roles = [ 'ROLE_BAPTISTE', 'ROLE_HELENE' ]; return new \ArrayIterator($roles); } ``` -------------------------------- ### Implement Custom Security Handler Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/advanced_configuration.md Create a custom `SecurityHandlerInterface` to fully control access management logic. Implement `isGranted`, `getBaseRole`, and other methods as needed. ```php // src/Security/Handler/CustomSecurityHandler.php use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface; final class CustomSecurityHandler implements SecurityHandlerInterface { public function isGranted(AdminInterface $admin, $attributes, ?object $object = null): bool { return $this->customAccessLogic(); } public function getBaseRole(AdminInterface $admin): string { return ''; } public function buildSecurityInformation(AdminInterface $admin): array { return []; } public function createObjectSecurity(AdminInterface $admin, object $object): void { } public function deleteObjectSecurity(AdminInterface $admin, object $object): void { } } ``` -------------------------------- ### Customize ACL Editor User List in PHP Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/security.md Override the `getAclUsers()` method in a controller to customize the list of users displayed in the ACL editor. This example shows how to display only specific users. ```php protected function getAclUsers(): \Traversable { $userManager = $container->get('sonata.user.manager.user'); // Display only kevin and anne $users[] = $userManager->findUserByUsername('kevin'); $users[] = $userManager->findUserByUsername('anne'); return new \ArrayIterator($users); } ``` -------------------------------- ### Format Frontend Code with Prettier Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/CONTRIBUTING.md Applies code formatting rules to all files in the 'assets' directory using Prettier. This ensures consistent code style across the project. ```bash npx prettier --write assets ``` -------------------------------- ### Reorder Form Fields in SonataAdminBundle Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/extensions.md Use the `reorder` method on the `FormMapper` to specify the order of fields within a group. This example shows reordering 'url' and 'position' fields in the 'main' group. ```php public function configureFormFields(FormMapper $form): void { $form ->with('main') ->reorder([ 'url', 'position' ]) ->add('position') ->end() ; } ``` -------------------------------- ### Configure ImageAdmin for File Uploads Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/cookbook/recipe_file_uploads.md Add a FileType field to your Admin class and implement prePersist and preUpdate methods to manage file uploads. This ensures Doctrine lifecycle events are triggered for file persistence. ```php use Symfony\Component\Form\Extension\Core\Type\FileType; final class ImageAdmin extends AbstractAdmin { protected function configureFormFields(FormMapper $form): void { $form ->add('file', FileType::class, [ 'required' => false ]) ; } public function prePersist(object $image): void { $this->manageFileUpload($image); } public function preUpdate(object $image): void { $this->manageFileUpload($image); } private function manageFileUpload(object $image): void { if ($image->getFile()) { $image->refreshUpdated(); } } // ... } ``` -------------------------------- ### Configure Date and Time Display in Lists Source: https://github.com/sonata-project/sonataadminbundle/blob/4.x/docs/reference/field_types.md Use this to store dates in UTC but display them in the user's timezone. Specify the desired date format and timezone. ```php protected function configureListFields(ListMapper $list): void { $list // store date in UTC but display is in the user timezone ->add('date', null, [ 'format' => 'Y-m-d H:i', 'timezone' => 'America/New_York', ]) ; } ```