admin管理员组文章数量:1208155
Because I want my applications to follow some kind of DDD structure, I want my Controller, Entity, Repository, Form etc to sit within a specific directory. For example: src/Appication/Dealer/Controller/DealerController.php
In order to load this controller, i have created a routing service: src/Routing/ApplicationLoader.php. That works fine if i run it in a test script. It gives me a list of the routes that are available within the dealer controller.
But symfony is giving me this:
Service "@App\Routing\ApplicationLoader" not found: the container inside "Symfony\Component\DependencyInjection\Argument\ServiceLocator" is a smaller service locator that only knows about the "kernel" and "security.route_loader.logout" services in @App\Routing\ApplicationLoader (which is being imported from "/var/www/html/config/routes.yaml"). Make sure the "App\Routing\ApplicationLoader" bundle is correctly registered and loaded in the application kernel class. If the bundle is registered, make sure the bundle path "@App\Routing\ApplicationLoader" is not empty.
It's not even hitting the ApplicationLoader.php
(tested by adding an exit e.g.)
How can i get symfony to understand it needs to load my script? ;)
(and i think my routes and services are correct - see below)
To test this, just create a clean symfony installation, create an entity and a crud with the maker, create the directory structure: src/Application/%entityName%/
- Controller/
- Entity/
- Repository/
- Form/
and put the respective files in there. Then modify the services and routes.yaml according to the ones below and put the ApplicationLoader.php in the src/Routing folder.
This is my services.yaml
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: false # Automatically injects dependencies in your services.
autoconfigure: false # 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'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
App\Routing\ApplicationLoader:
public: true
arguments:
$controllerDirectory: '%kernel.project_dir%/src/Application'
tags:
- { name: 'router.loader', priority: 0 }
This is my routes.yaml
# Handles routes for generic controllers in src/Controller/
controllers:
resource:
path: ../src/Controller/
namespace: App\Controller
type: attribute
# Handles custom routes for controllers under src/Application
custom_routes:
resource: '@App\Routing\ApplicationLoader'
type: service
This is my ApplicationLoader.php
:
<?php
namespace App\Routing;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Finder\Finder;
use ReflectionClass;
class ApplicationLoader extends Loader
{
private bool $isLoaded = false;
private string $controllerDirectory;
public function __construct(string $controllerDirectory)
{
$this->controllerDirectory = $controllerDirectory;
}
public function load($resource, ?string $type = null): RouteCollection
{
error_log("Loading resource: $resource with type: $type");
if (true === $this->isLoaded) {
throw new \RuntimeException('Do not add the "application" loader twice');
}
$routes = new RouteCollection();
// Use Symfony Finder to scan the directory for controllers
$finder = new Finder();
$finder->files()->in($this->controllerDirectory)->name('*Controller.php');
// Iterate through controller files and add routes
foreach ($finder as $file) {
$className = $this->getClassNameFromFile($file);
error_log("Processing controller: $className");
$reflectionClass = new ReflectionClass($className);
// Check if the class has route annotations or attributes
if ($reflectionClass->isSubclassOf('Symfony\Bundle\FrameworkBundle\Controller\AbstractController')) {
$this->addRoutesFromAttributes($reflectionClass, $routes);
}
}
return $routes;
}
public function supports($resource, ?string $type = null): bool
{
error_log("Checking support for resource: $resource with type: $type");
return 'service' === $type;
}
private function getClassNameFromFile($file): string
{
// Resolve the absolute path of the controller directory
$controllerDirectoryRealPath = realpath($this->controllerDirectory);
// Resolve the file's real path
$fileRealPath = $file->getRealPath();
// Calculate the relative path by removing the base directory
$relativePath = substr($fileRealPath, strlen($controllerDirectoryRealPath) + 1);
// Normalize directory separators to backslashes for namespaces
$relativePath = str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath);
// Remove the file extension (.php) and prepend the base namespace
return 'App\Application\' . str_replace('.php', '', $relativePath);
}
private function addRoutesFromAttributes(\ReflectionClass $reflectionClass, RouteCollection $routes): void
{
// Check the class-level attributes for the base path (e.g., #[Route('/dealer')])
$classAttributes = $reflectionClass->getAttributes(\Symfony\Component\Routing\Attribute\Route::class);
$classBasePath = '';
foreach ($classAttributes as $classAttribute) {
$classRoute = $classAttribute->newInstance();
$classBasePath = $classRoute->getPath();
}
// Iterate through each method to find route attributes
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
// Ignore inherited methods from AbstractController
// Skip methods from parent classes
if ($method->getDeclaringClass()->getName() !== $reflectionClass->getName()) {
continue;
}
// Get method attributes for routes
$methodAttributes = $method->getAttributes(\Symfony\Component\Routing\Attribute\Route::class);
foreach ($methodAttributes as $methodAttribute) {
$methodRoute = $methodAttribute->newInstance();
// Combine the class-level base path and the method-level path
$fullPath = rtrim($classBasePath, '/') . '/' . ltrim($methodRoute->getPath() ?? '', '/');
// Add the route to the collection
$routes->add(
$methodRoute->getName(),
new Route(
$fullPath,
['_controller' => $reflectionClass->getName() . '::' . $method->getName()],
[], // Default requirements
[], // Default options
'', // Host
[], // Schemes
$methodRoute->getMethods()
)
);
}
}
}
}
this is my test.php
script that lives in /public
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use App\\Routing\ApplicationLoader;
use Symfony\Component\Routing\RouteCollection;
try {
// Define the directory where your Application controllers are located
$controllerDirectory = __DIR__ . '/../src/Application';
// Instantiate your ApplicationLoader with the specified directory
$loader = new ApplicationLoader($controllerDirectory);
// Invoke the loader to load routes
$routes = $loader->load(null, 'service');
// Display loaded routes
echo "Loaded Routes:\n";
foreach ($routes as $name => $route) {
echo " - $name: " . $route->getPath() . "<br/>";
echo " Controller: " . $route->getDefault('_controller') . "<br/>";
echo " Methods: " . implode(', ', $route->getMethods()) . "<br/><br/>";
}
} catch (Throwable $e) {
// Catch and display errors for debugging
echo "Error: " . $e-\>getMessage() . "\<br/\>";
echo $e-\>getTraceAsString() . "\<br/\>";
}
Please help ;)
Because I want my applications to follow some kind of DDD structure, I want my Controller, Entity, Repository, Form etc to sit within a specific directory. For example: src/Appication/Dealer/Controller/DealerController.php
In order to load this controller, i have created a routing service: src/Routing/ApplicationLoader.php. That works fine if i run it in a test script. It gives me a list of the routes that are available within the dealer controller.
But symfony is giving me this:
Service "@App\Routing\ApplicationLoader" not found: the container inside "Symfony\Component\DependencyInjection\Argument\ServiceLocator" is a smaller service locator that only knows about the "kernel" and "security.route_loader.logout" services in @App\Routing\ApplicationLoader (which is being imported from "/var/www/html/config/routes.yaml"). Make sure the "App\Routing\ApplicationLoader" bundle is correctly registered and loaded in the application kernel class. If the bundle is registered, make sure the bundle path "@App\Routing\ApplicationLoader" is not empty.
It's not even hitting the ApplicationLoader.php
(tested by adding an exit e.g.)
How can i get symfony to understand it needs to load my script? ;)
(and i think my routes and services are correct - see below)
To test this, just create a clean symfony installation, create an entity and a crud with the maker, create the directory structure: src/Application/%entityName%/
- Controller/
- Entity/
- Repository/
- Form/
and put the respective files in there. Then modify the services and routes.yaml according to the ones below and put the ApplicationLoader.php in the src/Routing folder.
This is my services.yaml
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: false # Automatically injects dependencies in your services.
autoconfigure: false # 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'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
App\Routing\ApplicationLoader:
public: true
arguments:
$controllerDirectory: '%kernel.project_dir%/src/Application'
tags:
- { name: 'router.loader', priority: 0 }
This is my routes.yaml
# Handles routes for generic controllers in src/Controller/
controllers:
resource:
path: ../src/Controller/
namespace: App\Controller
type: attribute
# Handles custom routes for controllers under src/Application
custom_routes:
resource: '@App\Routing\ApplicationLoader'
type: service
This is my ApplicationLoader.php
:
<?php
namespace App\Routing;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Finder\Finder;
use ReflectionClass;
class ApplicationLoader extends Loader
{
private bool $isLoaded = false;
private string $controllerDirectory;
public function __construct(string $controllerDirectory)
{
$this->controllerDirectory = $controllerDirectory;
}
public function load($resource, ?string $type = null): RouteCollection
{
error_log("Loading resource: $resource with type: $type");
if (true === $this->isLoaded) {
throw new \RuntimeException('Do not add the "application" loader twice');
}
$routes = new RouteCollection();
// Use Symfony Finder to scan the directory for controllers
$finder = new Finder();
$finder->files()->in($this->controllerDirectory)->name('*Controller.php');
// Iterate through controller files and add routes
foreach ($finder as $file) {
$className = $this->getClassNameFromFile($file);
error_log("Processing controller: $className");
$reflectionClass = new ReflectionClass($className);
// Check if the class has route annotations or attributes
if ($reflectionClass->isSubclassOf('Symfony\Bundle\FrameworkBundle\Controller\AbstractController')) {
$this->addRoutesFromAttributes($reflectionClass, $routes);
}
}
return $routes;
}
public function supports($resource, ?string $type = null): bool
{
error_log("Checking support for resource: $resource with type: $type");
return 'service' === $type;
}
private function getClassNameFromFile($file): string
{
// Resolve the absolute path of the controller directory
$controllerDirectoryRealPath = realpath($this->controllerDirectory);
// Resolve the file's real path
$fileRealPath = $file->getRealPath();
// Calculate the relative path by removing the base directory
$relativePath = substr($fileRealPath, strlen($controllerDirectoryRealPath) + 1);
// Normalize directory separators to backslashes for namespaces
$relativePath = str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath);
// Remove the file extension (.php) and prepend the base namespace
return 'App\Application\' . str_replace('.php', '', $relativePath);
}
private function addRoutesFromAttributes(\ReflectionClass $reflectionClass, RouteCollection $routes): void
{
// Check the class-level attributes for the base path (e.g., #[Route('/dealer')])
$classAttributes = $reflectionClass->getAttributes(\Symfony\Component\Routing\Attribute\Route::class);
$classBasePath = '';
foreach ($classAttributes as $classAttribute) {
$classRoute = $classAttribute->newInstance();
$classBasePath = $classRoute->getPath();
}
// Iterate through each method to find route attributes
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
// Ignore inherited methods from AbstractController
// Skip methods from parent classes
if ($method->getDeclaringClass()->getName() !== $reflectionClass->getName()) {
continue;
}
// Get method attributes for routes
$methodAttributes = $method->getAttributes(\Symfony\Component\Routing\Attribute\Route::class);
foreach ($methodAttributes as $methodAttribute) {
$methodRoute = $methodAttribute->newInstance();
// Combine the class-level base path and the method-level path
$fullPath = rtrim($classBasePath, '/') . '/' . ltrim($methodRoute->getPath() ?? '', '/');
// Add the route to the collection
$routes->add(
$methodRoute->getName(),
new Route(
$fullPath,
['_controller' => $reflectionClass->getName() . '::' . $method->getName()],
[], // Default requirements
[], // Default options
'', // Host
[], // Schemes
$methodRoute->getMethods()
)
);
}
}
}
}
this is my test.php
script that lives in /public
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use App\\Routing\ApplicationLoader;
use Symfony\Component\Routing\RouteCollection;
try {
// Define the directory where your Application controllers are located
$controllerDirectory = __DIR__ . '/../src/Application';
// Instantiate your ApplicationLoader with the specified directory
$loader = new ApplicationLoader($controllerDirectory);
// Invoke the loader to load routes
$routes = $loader->load(null, 'service');
// Display loaded routes
echo "Loaded Routes:\n";
foreach ($routes as $name => $route) {
echo " - $name: " . $route->getPath() . "<br/>";
echo " Controller: " . $route->getDefault('_controller') . "<br/>";
echo " Methods: " . implode(', ', $route->getMethods()) . "<br/><br/>";
}
} catch (Throwable $e) {
// Catch and display errors for debugging
echo "Error: " . $e-\>getMessage() . "\<br/\>";
echo $e-\>getTraceAsString() . "\<br/\>";
}
Please help ;)
Share Improve this question edited Jan 20 at 10:04 Stok asked Jan 19 at 1:27 StokStok 511 silver badge4 bronze badges1 Answer
Reset to default 2OK, the answer was actually much simpler and what I wanted could actually be achieved with just changing the routes.yaml
to:
Standard controllers (keep this as it's working):
resource:
path: ../src/Controller/
namespace: App\Controller
type: attribute
All application routes (this will scan all Controller directories under Application application_routes):
resource:
path: ../src/Application/
namespace: App\Application
type: attribute
Leave the services.yaml
as it is originally and change the mapping section in the config/packages/doctrine.yaml
to this:
mappings:
Default:
is_bundle: false
type: attribute
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Default
Controller:
is_bundle: false
type: attribute
dir: '%kernel.project_dir%/src/Controller'
prefix: 'App\Controller'
alias: Controller
Application:
is_bundle: false
type: attribute
dir: '%kernel.project_dir%/src/Application'
prefix: 'App\Application'
alias: Application
This way applications that live in src/Controller
are loaded but also everything inside src/Application/MyApp/Controller
.
本文标签:
版权声明:本文标题:php - Service not found the container inside "ServiceLocator" is a smaller service locator that only knows abo 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738749363a2110302.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论