I'm trying to implement the DependencyInjection Component from Symfony (version 4.0.0) into my project. For this I followed the following simple steps, in order to understand the autowiring process:
- In
composer.json: Assign namespaceAppto thesrcfolder. - In
services.yaml: Assign namespaceAppto thesrcfolder. - Define
MyControllerclass insrcfolder, under the namespaceApp\Controller. - In
bootstrap.php: Create aContainerBuilderinstance ($container). - In
bootstrap.php: Create aYamlFileLoaderobject and load the config fileservices.yamlinto it. - In
bootstrap.php: Get an instance ofMyControllerfrom the$containerand display it on screen.
But I keep receiving the following error:
( ! ) Fatal error: Uncaught ReflectionException: Class does not exist in <path-to-my-project-root>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 1051
( ! ) ReflectionException: Class does not exist in <path-to-my-project-root>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 1051
Call Stack
# Time Memory Function Location
1 0.0160 354632 {main}( ) .../index.php:0
2 0.0166 357928 require_once( '<path-to-my-project-root>/bootstrap.php' ) .../index.php:7
3 0.0872 1752040 Symfony\Component\DependencyInjection\ContainerBuilder->get( ) .../bootstrap.php:16
4 0.0872 1752040 Symfony\Component\DependencyInjection\ContainerBuilder->doGet( ) .../ContainerBuilder.php:522
5 0.0872 1752816 Symfony\Component\DependencyInjection\ContainerBuilder->createService( ) .../ContainerBuilder.php:555
6 0.0873 1752928 __construct ( ) .../ContainerBuilder.php:1051
The error occurs at this line (1051) in ContainerBulder::createService method, because $definition->getClass() returns NULL:
private function createService(Definition $definition, array &$inlineServices, $id = null, $tryProxy = true) {
// Line 1051:
$r = new \ReflectionClass($class = $parameterBag->resolveValue($definition->getClass()));
//..
}
In the chapter Automatic Service Loading in services.yaml, as I understood it, by using only those settings without any other settings in services.yaml, the DI container will know how to create an instance of MyController. Maybe I'm wrong?...
Could you please take a second to help me? Thank you very much.
My project consists of the following structure and files:
Project structure
bootstrap.php
composer.json
config/
services.yaml
src/
Controller/
MyController
vendor/
symfony/
config/
dependency-injection/
filesystem/
polyfill-mbstring/
yaml/
composer.json
"require": {
"php": ">=5.5.0",
"symfony/dependency-injection": "^4.0",
"symfony/config": "^4.0",
"symfony/yaml": "^4.0",
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
bootstrap.php
<?php
use App\Controller\MyController;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
require '../vendor/autoload.php';
$container = new ContainerBuilder();
$fileLocator = new FileLocator(__DIR__ . '/config');
$loader = new YamlFileLoader($container, $fileLocator);
$loader->load('services.yaml');
$myController = $container->get(MyController::class);
var_dump($myController);
config/services.yaml
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
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests}'
src/Controller/MyController
<?php
namespace App\Controller;
class MyController {
public function myAction() {
echo 'Hello from MyController.';
}
}
Update 1:
After container compilation with compile()
$loader->load('services.yaml');
$container->compile();
I received the following error:
( ! ) Fatal error: Uncaught Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "App\Controller\MyController". in <my-project-path>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 950
( ! ) Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "App\Controller\MyController". in <my-project-path>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 950
Call Stack
# Time Memory Function Location
1 0.1512 357648 {main}( ) .../index.php:0
2 0.1675 361056 require_once( '<my-project-path>/bootstrap.php' ) .../index.php:7
3 3.5621 2582624 Symfony\Component\DependencyInjection\ContainerBuilder->get( ???, ??? ) .../bootstrap.php:18
4 3.5621 2582624 Symfony\Component\DependencyInjection\ContainerBuilder->doGet( ???, ???, ??? ) .../ContainerBuilder.php:522
I checked the $container->definitions array following the compile() call. I realised that all services (including App\Controller\MyController) saved in definitions list prior to compile() where removed from the array by the compilation process.
More of it: In $compiler->passConfig->log I found these entries (after compilation step):
[0] string "Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\Container\ContainerInterface"; reason: private alias."
[1] string "Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\DependencyInjection\ContainerInterface"; reason: private alias."
[2] string "Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "App\Service\MyService" to "App\Controller\MyController"."
[3] string "Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "App\Controller\MyController"; reason: unused."
[4] string "Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "App\Service\MyService"; reason: unused."
$definition->getClass()returnsNULL. For me that seems odd, because I would have expected a class name, or instance, or similar ofMyController. My composer and autoload are working ok. I can't find the missing piece, if any. Or maybe there's a bug...YamlFileLoader::loadis called, then theBadMethodCallException('Adding definition to a compiled container is not allowed')is thrown inContainerBuilder::setDefinition. In general, it seems that aclassproperty must be defined in the yaml file. Otherwise theReflectionException(on line 1051) is thrown over and over again. I also looked into the Changelog. Not even that simple code example is running. I had to defineclass: ...too.