Some icons have been renamed by Font Awesome, and the correct class is now fas
or fab
instead of
fa
, for example before you would have used fa fa-edit
, and after fas fa-edit
.
Sonata includes the compatibility layer of Font Awesome 5 that ensure the old icons names from version 4 still works. So we encourage to upgrade the names of all your custom icons, but the old code should still work.
If you still need it, please set it up on your own!
Frontend dependencies are handled with NPM. Bower is not used anymore.
A lot of assets that were previously public are handled with NPM and placed in a private node_modules/
directory.
From these dependencies, only the necessary files are exposed publicly through Webpack Encore.
The jQuery UI dependency was fully included before, but now we only include the sortable widget (JavaScript and CSS), the rest of this dependency is not exposed. If you are adding more JavaScript or CSS using another widget of jQuery UI please include it yourself.
Please check the src/Resources/public
and the documentation to see the used CSS, JavaScript, images and fonts.
If you are customising (specially removing standard JavaScript or CSS) assets, this will affect you.
All the deprecated code introduced on 3.x is removed on 4.0.
Please read 3.x upgrade guides for more information.
See also the diff code.
Some classes and methods are now final
and should not be overridden:
Sonata\AdminBundle\Admin\AbstractAdmin::getActionButtons
Sonata\AdminBundle\Admin\AbstractAdmin::getBatchActions
Sonata\AdminBundle\Admin\AbstractAdmin::urlize
Sonata\AdminBundle\Admin\Extension\LockExtension
Sonata\AdminBundle\Admin\FieldDescriptionCollection
Sonata\AdminBundle\Block\AdminListBlockService
Sonata\AdminBundle\Block\AdminSearchBlockService
Sonata\AdminBundle\Block\AdminStatsBlockService
Sonata\AdminBundle\Command\ExplainAdminCommand
Sonata\AdminBundle\Command\GenerateObjectAclCommand
Sonata\AdminBundle\Command\ListAdminCommand
Sonata\AdminBundle\Command\SetupAclCommand
Sonata\AdminBundle\Command\Validators
Sonata\AdminBundle\Datagrid\Datagrid
Sonata\AdminBundle\Datagrid\SimplePager
Sonata\AdminBundle\DependencyInjection\Compiler\AddDependencyCallsCompilerPass
Sonata\AdminBundle\DependencyInjection\Compiler\AddFilterTypeCompilerPass
Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass
Sonata\AdminBundle\DependencyInjection\Compiler\GlobalVariablesCompilerPass
Sonata\AdminBundle\DependencyInjection\Configuration
Sonata\AdminBundle\DependencyInjection\SonataAdminExtension
Sonata\AdminBundle\DependencyInjection\Compiler\ModelManagerCompilerPass
Sonata\AdminBundle\Event\AdminEventExtension
Sonata\AdminBundle\Event\ConfigureEvent
Sonata\AdminBundle\Event\ConfigureMenuEvent
Sonata\AdminBundle\Event\ConfigureQueryEvent
Sonata\AdminBundle\Event\PersistenceEvent
Sonata\AdminBundle\Exception\LockException
Sonata\AdminBundle\Exception\ModelManagerException
Sonata\AdminBundle\Exception\NoValueException
Sonata\AdminBundle\Filter\FilterFactory
Sonata\AdminBundle\Form\ChoiceList\ModelChoiceLoader
Sonata\AdminBundle\Form\DataTransformer\ArrayToModelTransformer
Sonata\AdminBundle\Form\DataTransformer\ModelToIdPropertyTransformer
Sonata\AdminBundle\Form\DataTransformer\ModelToIdTransformer
Sonata\AdminBundle\Form\DataTransformer\ModelsToArrayTransformer
Sonata\AdminBundle\Form\EventListener\MergeCollectionListener
Sonata\AdminBundle\Form\Extension\ChoiceTypeExtension
Sonata\AdminBundle\Form\Extension\Field\Type\FormTypeFieldExtension
Sonata\AdminBundle\Form\Extension\Field\Type\MopaCompatibilityTypeFieldExtension
Sonata\AdminBundle\Form\Type\AclMatrixType
Sonata\AdminBundle\Form\Type\AdminType
Sonata\AdminBundle\Form\Type\ChoiceFieldMaskType
Sonata\AdminBundle\Form\Type\CollectionType
Sonata\AdminBundle\Form\Type\Filter\ChoiceType
Sonata\AdminBundle\Form\Type\Filter\DateRangeType
Sonata\AdminBundle\Form\Type\Filter\DateTimeRangeType
Sonata\AdminBundle\Form\Type\Filter\DateTimeType
Sonata\AdminBundle\Form\Type\Filter\DateType
Sonata\AdminBundle\Form\Type\Filter\DefaultType
Sonata\AdminBundle\Form\Type\Filter\NumberType
Sonata\AdminBundle\Form\Type\ModelAutocompleteType
Sonata\AdminBundle\Form\Type\ModelHiddenType
Sonata\AdminBundle\Form\Type\ModelListType
Sonata\AdminBundle\Form\Type\ModelReferenceType
Sonata\AdminBundle\Form\Type\ModelType
Sonata\AdminBundle\Guesser\TypeGuesserChain
Sonata\AdminBundle\Manipulator\ServicesManipulator
Sonata\AdminBundle\Menu\MenuBuilder
Sonata\AdminBundle\Model\AuditManager
Sonata\AdminBundle\Route\AdminPoolLoader
Sonata\AdminBundle\Route\DefaultRouteGenerator
Sonata\AdminBundle\Route\RouteCollection
Sonata\AdminBundle\Route\RoutesCache
Sonata\AdminBundle\Route\RoutesCacheWarmUp
Sonata\AdminBundle\Security\Acl\AdminPermissionMap
Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder
Sonata\AdminBundle\Security\Handler\AclSecurityHandler
Sonata\AdminBundle\Security\Handler\NoopSecurityHandler
Sonata\AdminBundle\SonataAdminBundle
Sonata\AdminBundle\Translator\BCLabelTranslatorStrategy
Sonata\AdminBundle\Translator\FormLabelTranslatorStrategy
Sonata\AdminBundle\Translator\NativeLabelTranslatorStrategy
Sonata\AdminBundle\Translator\UnderscoreLabelTranslatorStrategy
Sonata\AdminBundle\Twig\Extension\SonataAdminExtension
Sonata\AdminBundle\Twig\GlobalVariables
Sonata\AdminBundle\Util\AdminAclManipulator
Sonata\AdminBundle\Util\FormBuilderIterator
Sonata\AdminBundle\Util\FormViewIterator
Sonata\AdminBundle\Util\AdminAclManipulator
If you have implemented a custom admin, you must adapt the signature of the following new methods to match the one in AdminInterface
again:
hasAccess
configureActionButtons
getExportFields
setTemplates
setTemplate
getTemplates
getClassnameLabel
getPersistentParameter
preValidate
getSubClasses
addSubClass
getDashboardActions
getActionButtons
isCurrentRoute
The following methods changed their visiblity to protected:
configureActionButtons
configure
urlize
The method signature of configureActionButtons
has changed. A new parameter buttonList
was added.
Some of the tasks to update your admin classes can be automated using Rector.
Use the below config in your rector.php
config as a starting point to automate your update.
<?php
declare(strict_types=1);
use PHPStan\Type\ArrayType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\StringType;
use PHPStan\Type\UnionType;
use PHPStan\Type\VoidType;
use Rector\Config\RectorConfig;
use Rector\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector;
use Rector\TypeDeclaration\Rector\ClassMethod\AddParamTypeDeclarationRector;
use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnTypeDeclarationRector;
use Rector\TypeDeclaration\ValueObject\AddParamTypeDeclaration;
use Rector\TypeDeclaration\ValueObject\AddReturnTypeDeclaration;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
return static function (RectorConfig $rectorConfig): void {
// ....
$services = $rectorConfig->services();
$rectorConfig->ruleWithConfiguration(AddReturnTypeDeclarationRector::class, [
new AddReturnTypeDeclaration(AbstractAdmin::class, 'preBatchAction', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configure', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'alterNewInstance', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'alterObject', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'preValidate', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'preUpdate', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'postUpdate', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'prePersist', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'postPersist', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'preRemove', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'postRemove', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureFormFields', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureListFields', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureDatagridFilters', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureShowFields', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureRoutes', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureTabMenu', new VoidType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'generateBaseRoutePattern', new StringType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'generateBaseRouteName', new StringType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'getSubClass', new StringType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'createNewInstance', new ObjectWithoutClassType()),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configurePersistentParameters', new ArrayType(new StringType(), new MixedType())),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureFilterParameters', new ArrayType(new StringType(), new MixedType())),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureActionButtons', new ArrayType(new StringType(), new MixedType())),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureExportFields', new ArrayType(new IntegerType(), new StringType())),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureDashboardActions', new ArrayType(new StringType(), new ArrayType(new StringType(), new MixedType()))),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureBatchActions', new ArrayType(new StringType(), new ArrayType(new StringType(), new MixedType()))),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'getAccessMapping', new ArrayType(new StringType(), new UnionType([new StringType(), new ArrayType(new IntegerType(), new StringType())]))),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'getPermissionsShow', new ArrayType(new IntegerType(), new StringType())),
new AddReturnTypeDeclaration(AbstractAdmin::class, 'configureQuery', new ObjectType(ProxyQueryInterface::class)),
]);
$rectorConfig->ruleWithConfiguration(AddParamTypeDeclarationRector::class, [
new AddParamTypeDeclaration(AbstractAdmin::class, 'alterNewInstance', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'alterObject', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'preValidate', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'preUpdate', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'postUpdate', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'prePersist', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'postPersist', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'preRemove', 0, new ObjectWithoutClassType()),
new AddParamTypeDeclaration(AbstractAdmin::class, 'postRemove', 0, new ObjectWithoutClassType()),
]);
$services->set(AddParamBasedOnParentClassMethodRector::class);
};
If you have implemented a custom admin extension, you must adapt the signature of the following new methods to match the one in AdminExtensionInterface
again:
configureActionButtons
configureBatchActions
getAccessMapping
The third argument of the AdminListBlockService::__construct
method is now mandatory.
The fourth argument of the AdminListBlockService::__construct
method is now mandatory.
The AdminHelper::__construct
method changes its Pool
param to a PropertyAccessorInterface
one.
The buildBreadcrumbs
method may no longer be called from outside the class.
The buildBreadcrumbs
method has been removed from the interface.
The Twig filters that come with the bundle will no longer load a default template when used with a missing template.
The sonata_admin
twig extension is now final. You may no longer extend it.
Method SimplePager::getResults
is always returning an array
LockInterface
extends from ModelManagerInterface
.
RouteCollection
implements RouteCollectionInterface
.
When there is no searchable filters, SearchHandler::search()
returns null
. Previously, it was returning false
.
When the service security.csrf.token_manager
is not available, getCsrfToken()
returns null
. Previously, it was returning false
.
The isXmlHttpRequest()
, redirectTo()
, isPreviewApproved()
, isInPreviewMode()
, isPreviewDeclined()
,
validateCsrfToken()
signatures were changed. They now require to pass the request as first argument.
The CRUDController::getRequest()
method was removed.
The type for argument 4 in apply()
method has been changed from array
to Sonata\AdminBundle\Filter\Model\FilterData
.
Before:
public function apply(ProxyQueryInterface $query, array $filterData): void;
After:
public function apply(ProxyQueryInterface $query, FilterData $filterData): void;
The form label are now correctly using the label translator strategy for field with .
(which won't be replaced by __
). For instance, with the underscore label strategy, the
label foo.barBaz
was previously form.label_foo__bar_baz
and now is form.label_foo_bar_baz
to be consistent with others labels like show.label_foo_bar_baz
.
They don't reset the existing templates anymore.
BaseFieldDescription, FieldDescriptionCollection, FieldDescriptionInterface and FieldDescriptionRegistryInterface
Moved from the Sonata\AdminBundle\Admin
to the Sonata\AdminBundle\FieldDescription
namespace.
Remove AdminInterface $admin
argument from
BuilderInterface::fixFieldDescription()
DatagridBuilderInterface::addFilter()
ListBuilderInterface::buildField()
ListBuilderInterface::addField()
ShowBuilderInterface::addField()
Use $fieldDescription->getAdmin()
to access to the admin value.
ListMapper::NAME_ACTIONS
change to _actions
.
ListMapper::NAME_BATCH
change to _batch
.
ListMapper::NAME_SELECT
change to _select
.
Be aware it implies that the following code
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('_action', null, [
'actions' => [
'show' => [],
'edit' => [],
'delete' => [],
]
]);
}
should be updated to
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('_actions', null, [
'actions' => [
'show' => [],
'edit' => [],
'delete' => [],
]
]);
}
but the best is to use the constant ListMapper::NAME_ACTIONS
.
Instead of relying on the ROLE_MYADMIN_EDIT
role, a new ROLE_MYADMIN_HISTORY
role was introduced to get access to the history actions. If you use the
revisions be sure to add this role to your users.