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:
composer.json: Assign namespace App to the src folder.services.yaml: Assign namespace App to the src folder.MyController class in src folder, under the namespace App\Controller.bootstrap.php: Create a ContainerBuilder instance ($container).bootstrap.php: Create a YamlFileLoader object and load the config file services.yaml into it.bootstrap.php: Get an instance of MyController from the $container and 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:
bootstrap.php
composer.json
config/
services.yaml
src/
Controller/
MyController
vendor/
symfony/
config/
dependency-injection/
filesystem/
polyfill-mbstring/
yaml/
"require": {
"php": ">=5.5.0",
"symfony/dependency-injection": "^4.0",
"symfony/config": "^4.0",
"symfony/yaml": "^4.0",
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
<?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);
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}'
<?php
namespace App\Controller;
class MyController {
public function myAction() {
echo 'Hello from MyController.';
}
}
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."
I went ahead and setup a fresh project.
There are two issues with your setup.
First you do need to compile the container before using it:
// bootstrap.php
$loader->load('services.yaml');
$container->compile();
$myController = $container->get(MyController::class);
And then you need to make your controller service public before pulling it from the container:
// services.yaml
App\:
resource: 'src/*'
exclude: 'src/{Entity,Migrations,Tests}'
App\Controller\:
resource: 'src/Controller/*'
public: true
This is basically what the framework does.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With