In my Symfony 6.4 project, I'm trying to declare an abstract service in services.yaml by doing the following :
imports:
- { resource: services/ }
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
services:
_defaults:
autowire: true
autoconfigure: true
# parent form
App\Admin\Form\HostingFormAbstract:
arguments:
$authorizationChecker: '@security.authorization_checker'
$tokenStorage: '@security.token_storage'
$phpHandlers: '%php_handlers%'
$nodeJsHandlers: '%nodeJs_handlers%'
abstract: true
# children forms
App\Admin\Form\HostingFormCreate:
parent: App\Admin\Form\HostingFormAbstract
class: App\Admin\Form\HostingFormCreate
calls:
- [setGroupManager, ['@App\Services\Managers\GroupManager']]
tags: [form.type]
App\Admin\Form\HostingFormUpdate:
parent: App\Admin\Form\HostingFormAbstract
class: App\Admin\Form\HostingFormUpdate
calls:
- [setHostnameManager, ['@App\Services\Managers\HostnameManager']]
tags: [form.type]
...
The HostingFormAbstract class is extending AbstractType from symfony/form package :
namespace App\Admin\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
abstract class HostingFormAbstract extends AbstractType
{
private TokenStorageInterface $tokenStorage;
private AuthorizationCheckerInterface $authorizationChecker;
private array $phpHandlers;
private array $nodeJsHandlers;
public function __construct(TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorizationChecker, array $phpHandlers, array $nodeJsHandlers)
{
$this->tokenStorage = $tokenStorage;
$this->authorizationChecker = $authorizationChecker;
$this->phpHandlers = $phpHandlers;
$this->nodeJsHandlers = $nodeJsHandlers;
}
...
And with that, I get the following error while going on my symfony app :
The service "App\Admin\Form\HostingFormAbstract" tagged "form.type" must not be abstract.
For more context, I'm rewriting a Symfony 3.4 app into a new Symfony 6.4 app.
It was working fine on 3.4, but now it seems that in services.yaml, you can't declare an abstract service/class extending the AbstractType class.
I tried to add a custom tag in the yaml for this service, but it didn't change anything.
I didn't find any workaround on Symfony documentation, and it seems odd to me that you can't do that. Maybe I missed something.
If anyone as an idea on how to do this...
Thanks !
Edit, working solution :
It seems that there is something wrong with my multiple .yaml files registering the services.
Here is what I had to do in order to have my service registered :
autoconfigure: false
to my App\Admin\Form\HostingFormAbstract serviceimports:
- { resource: services/ }
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
...
App\Admin\Form\HostingFormAbstract:
class: App\Admin\Form\HostingFormAbstract
autoconfigure: false
arguments:
$authorizationChecker: '@security.authorization_checker'
$tokenStorage: '@security.token_storage'
$phpHandlers: '%php_handlers%'
$nodeJsHandlers: '%nodeJs_handlers%'
abstract: true
App\Admin\Form\HostingFormCreate:
parent: App\Admin\Form\HostingFormAbstract
class: App\Admin\Form\HostingFormCreate
calls:
- [ setGroupManager, [ '@App\Services\Managers\GroupManager' ] ]
tags: [ form.type ]
App\Admin\Form\HostingFormUpdate:
parent: App\Admin\Form\HostingFormAbstract
class: App\Admin\Form\HostingFormUpdate
calls:
- [ setHostnameManager, [ '@App\Services\Managers\HostnameManager' ] ]
tags: [ form.type ]
It's the default behavior of autoconfigure
option, setting the form.type
tag to all FormTypeInterface
classes under the service scope.
However, you can exclude any service from been auto-tagged by setting autoconfigure: false
like this:
App\Admin\Form\HostingFormAbstract:
autoconfigure: false
// ...
and then the error should disappear.