I have a registered service where I inject the content of a json as argument (see followed configuration, App\Service\Authenticator service)
parameters:
env(LDAP_CONFIG_FILE): '../auth.json'
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
App\Service\Authenticator:
arguments:
$config: '%env(json:file:resolve:LDAP_CONFIG_FILE)%'
$environment: '%env(APP_ENV)%'
When I try to inject this service in a controller, this works fine as expected. But when I inject the service into a command I get this error :
> php bin/console app:execute
[WARNING] Some commands could not be registered:
In EnvVarProcessor.php line 136:
File "../auth.json" not found (resolved from "resolve:LDAP_CONFIG_FILE").
Command "app:execute" is not defined.
And if I replace env(LDAP_CONFIG_FILE) by auth.json it work in a command but not in a controller anymore.
How can I configure to make it work in both commands and controllers ?
Edit: I found a temporary fix with the default processor but I really want a clean solution.
Related
I start new project and install fresh copy of Symfony 5 (microservice skeleton), and add first controller HealthCheckController to the default folder src/Controller, at this moment all is fine, I can get access to it from browser.
In next step I change a project name in composer.json and all related namespaces in code to
"autoload": {
"psr-4": {
"Project\\SubProject\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Project\\SubProject\\Tests\\": "tests/"
}
},
and in service.yaml
Project\SubProject\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
- '../src/Tests/'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
Project\SubProject\Controller: # assuming you have namespace like that
resource: '../src/Controller/'
tags: [ 'controller.service_arguments' ]
everything still works.
Next step is to change directory structure, add layers and modules. So I move Kernel.php to the Common/Infrastructure/Symfony/ (ofcourse I change path to config files in the kernel) and controller to folder Common/Interfaces/Controller and change configs in the service.yaml
Project\SubProject\:
resource: '../src/'
exclude:
- '../src/Common/Infrastructure/Symfony/DependencyInjection/'
- '../src/Common/Infrastructure/Symfony/Kernel.php'
- '../src/Module1/Infrastructure/Entity/'
- '../src/Module2/Infrastructure/Entity/'
- '../src/Module3/Infrastructure/Entity/'
- '../src/Module1/Test/'
- '../src/Module2/Test/'
- '../src/Module3/Test/'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
Project\SubProject\Common\Interfaces\Controller\: # assuming you have namespace like that
resource: '../src/Common/Interfaces/Controller/'
tags: [ 'controller.service_arguments' ]
and in routes/annotation/yaml
controllers:
resource: ../../src/Common/Interfaces/Controller
type: annotation
kernel:
resource: ../../src/Common/Infrastructure/Symfony/Kernel.php
type: annotation
and now I'm getting error Project\SubProject\Common\Interfaces\Controller\HealthCheckController" has no container set, did you forget to define it as a service subscriber?
What I'm doing wrong, I forgot to change something???
I know you can tell me you need to add container to controller like this
Project\SubProject\Common\Interfaces\Controller\HealthCheckController:
calls:
- method: setContainer
arguments: ['#service_container']
but it's stupid to configure each controller manually when autowire feature turned on, and when it worked with a default directory structure.
Also I clear cache by CLI command and manually deleting folder.
It was somewhat difficult to follow exactly what your configuration files ended as. I don't have a specific answer for you but I was a bit intrigued at the notion of moving Kernel.php. You did not mention moving the config directory so I chose to leave it where it was and:
namespace Project\SubProject\Common\Infrastructure\Symfony;
class Kernel extends BaseKernel
{
protected function configureContainer(ContainerConfigurator $container): void
{
$base = $this->getProjectDir();
$container->import($base . '/config/{packages}/*.yaml');
$container->import($base . '/config/{packages}/'.$this->environment.'/*.yaml');
$container->import($base . '/config/services.yaml');
$container->import($base . '/config/{services}_'.$this->environment.'.yaml');
}
# same for configureRoutes
# project/config/services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
Project\SubProject\:
resource: '../src/'
exclude:
- '../src/Common/Infrastructure/Symfony/Kernel.php'
Project\SubProject\Common\Interfaces\Controller\:
resource: '../src/Common/Interfaces/Controller/'
tags: ['controller.service_arguments']
# project/config/routes/annotations.yaml
controllers:
resource: ../../src/Common/Interfaces/Controller/
type: annotation
Tweaked index.php and console to use the new Kernel path and it all worked as expected.
I should point out that as long as you are extending from AbstractController then you don't actually need the Controller section in services.yaml at all. It's quite puzzling why you seem to be getting a controller service but setContainer is not being called.
bin/console debug:container HealthCheckController
Class Project\SubProject\Common\Interfaces\Controller\HealthCheckController
Tags controller.service_arguments
container.service_subscriber
Calls setContainer
The Calls setContainer is obviously the important line.
I'm guessing you do have a typo somewhere and I suspect you did not actually start your namespace with Project\SubProject. But again it does work as expected.
Just for my own reference I checked in my test project.
In Symfony 4, I would like to combine different configuration files for services. In the following scenario, my attempt is to import services from php configuration named services.php and then perform the other services configurations in the yaml file that imports the others services..
services.yaml
imports:
- { resource: services.php }
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'
services.php
<?php
use Symfony\Component\DependencyInjection\Definition;
$definition = new Definition();
$definition
->setAutowired(true)
->setAutoconfigured(true)
->setPublic(false)
;
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Migrations,Tests}');
$container->getDefinition(\App\SomeClass::class)
->setArgument('$param', 'someValue');
Class file
class SomeClass
{
public function __construct(string $param)
{
...
}
I get the following error:
Cannot autowire service
"App\SomeClass": argument "$param"
of method "__construct()" is type-hinted "string", you should
configure its value explicitly.
Also, I'm wondering if I have to necessary to overwrite the initial _defaults definition (or others already done in by the files that imports) from the yaml or I can inherit. Not sure how these files are all merged.
The problem is that you registering the classes in src/* twice, once in your services.php and once in your services.yaml.
So in the first run with services.php you correctly define the class and the required argument, then, in the second run with services.yaml the definition is being overwritten and it loses the argument again.
The minimal solution would be to exclude the SomeClass.php in the services.yaml so it won't be registered a second time:
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php,SomeClass.php}' # <- here I added SomeClass.php
It would be better though to create a separate namespace and exclude the directory in the YAML and only register this directory in the PHP-config.
When I enable the 'dev' mode in my Symfony 4 app (that is already online in a shared hosting service) it shows this message:
(1/1) ParameterNotFoundException
You have requested a non-existent parameter "locale".
in ParameterBag.php (line 100)
at ParameterBag->get('locale')
in EnvPlaceholderParameterBag.php (line 57)
at EnvPlaceholderParameterBag->get('locale')
in ParameterBag.php (line 216)
at ParameterBag->resolveString('%locale%', array('locale' => true))
in ParameterBag.php (line 187)
...
and does not allow to debug the app. My config/services.yml code is as default:
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: 'en'
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.
public: false # Allows optimizing the container by removing unused Services; this also means
# fetching Services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
...
Please, someone can help me to fix this error.
Had the same problem during the fresh symfony 4.3 + sonata admin bundle installation.
As a solution I added locale parameter:
// /config/services.yaml
parameters:
locale: 'en'
While I am not a Symphony expert the documentation appears to allow anything in the parameters section, but it does mention also defining the values in the .env.dist file as well for them to be used here.
http://symfony.com/doc/current/best_practices/configuration.html#canonical-parameters
When upgrading from symfony 4.2 to symfony 4.4 I also got this error when composer commands.
This parameter seems so be used in config/packages/translation.yml.
Updating the symfony/translation recipe which no longer refers to %locale% but hardcode 'en' solves the problem for me.
Simply run composer recipes:install symfony/translation --force -v
I'm trying to add an old Bundle that I have built on Symfony 3.* to Symfony 4 but I get this error:
The autoloader expected class
"App\SBC\TiersBundle\Controller\ChantierController" to be defined in
file
"/Applications/MAMP/htdocs/Projects/HelloSymfony4/vendor/composer/../../src/SBC/TiersBundle/Controller/ChantierController.php".
The file was found but the class was not in it, the class name or
namespace probably has a typo in
/Applications/MAMP/htdocs/Projects/HelloSymfony4/config/services.yaml
(which is loaded in resource
"/Applications/MAMP/htdocs/Projects/HelloSymfony4/config/services.yaml").
It seems like the framework did not recognise the namespace of the bundle so I did these steps:
In config/bundle.php I added the third line:
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
\SBC\TiersBundle\TiersBundle::class => ['all' => true], // this one
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
];
And in composer.json I added the first line in autoload section:
"autoload": {
"psr-4": {
"SBC\\": "src/SBC/",
"App\\": "src/"
}
},
Because the namespace of my Bundle starts with SBC\, and I have launched composer dump-autoload in the console.
<?php
namespace SBC\TiersBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class TiersBundle extends Bundle
{
}
ChantierController.php:
namespace SBC\TiersBundle\Controller;
use SBC\TiersBundle\Entity\Chantier;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class ChantierController extends Controller
{
...
}
And this is my Bundle under /src:
Unfortunately still facing the same error, how can I fix it and thanks in advance.
UPDATE: config/services.yaml:
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
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.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
SBC\:
resource: '../src/SBC/*'
exclude: '../src/SBC/TiersBundle/{Entity,Migrations,Tests}'
SBC\TiersBundle\Controller\:
resource: '../src/SBC/TiersBundle/Controller'
tags: ['controller.service_arguments']
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
The problem is most likely caused by Symfony configuration and conflict in namespaces. First you need to adjust your config/services.yaml:
SBC\:
resource: '../src/SBC/*'
exclude: '../src/SBC/TiersBundle/{Entity,Migrations,Tests,Kernel.php}'
SBC\TiersBundle\Controller\:
resource: '../src/SBC/TiersBundle/Controller'
tags: ['controller.service_arguments']
App\:
resource: '../src/*'
exclude: '../src/{SBC,Entity,Migrations,Tests,Kernel.php}'
This way you'll define defaults for your namespace and prevent the default namespace App to include your directory when generating autoload classes. Note that if you are using annotation routes, you also need to adjust config/routes/annotations.yaml:
sbc_controllers:
resource: ../../src/SBC/TiersBundle/Controller/
type: annotation
so the routes are generated correctly. After performing these steps run composer dump-autoload again and clear Symfony's cache.
This might be helpful in the future if you run into another problems: https://github.com/symfony/symfony/blob/master/UPGRADE-4.0.md
I want to use a controller as a service in symfony2. I defined the service in the test\testBundle\Resources\services.yml file:
parameters:
# user.example.class: test\testBundle\Example
services:
test.controller:
class: test\testBundle\Controller\TestController
and call the service in my controller:
$this->get('test.controller');
but symfony throws the following exception:
You have requested a non-existent service "test.controller".
You may have forgotten to import the services.yml file from a config file that's already being read, typically app/config/config.yml:
imports:
- { resource: '#MyBundle/Resources/config.yml' }
It is a convention to put config files in the Resources/config directory inside your bundle, cf. Importing Configuration with imports in the Symfony2 docs:
imports:
- { resource: '#MyBundle/Resources/config/config.yml' }