2

I have a Legacy App and I'm using Symfony with it. Everything works fine so far.

Now I want to use Autowiring for my Legacy-Controllers.

  • they're loaded using composers classmap functionality
  • are in the Root-Namespace (e.g. \Controller_Page)
  • class names are different from filenames

Yeah. I know it's shitty. But it's legacy and I don't want to touch every single Controller at the moment (bigger problems in that app).

I'd like to use Dependency-Injection and Autowiring to reduce the (terrible) mess.

Here are some approaches I already tried:

services:
 _defaults:
        autowire: true
        autoconfigure: true
    "\\":
        resource: '../legacy/Controller'
        tags: ['controller.service_arguments']

Namespace is not a valid PSR-4 prefix

services:
 _defaults:
        autowire: true
        autoconfigure: true
    "":
        resource: '../legacy/Controller'
        tags: ['controller.service_arguments']

Namespace prefix must end with a "\"

// in Kernel::configureContainer()
$container->registerForAutoconfiguration(\BaseController::class);

(my \BaseController has only Symfony\Component\HttpFoundation\RequestStack as __construct-argument)

Controller "BaseController" has required constructor arguments and does not exist in the container. Did you forget to define such a service?

// in Kernel::configureContainer()
$container->registerForAutoconfiguration(\Controller_Legacy::class);

Cannot load resource "4208ad7faaf7d383f981bd32e92c4f2f".

I have no clue how to accomplish that. Thanks for your help.

Edit 1

Got one step further. I accomplished autoconfiguration for one of that legacy controllers like that:

// Kernel.php
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
{
    $container->addDefinitions([
        \Controller_Legacy::class => (new Definition(\Controller_Legacy::class))
            ->setAutowired(true)
            ->setAutoconfigured(true)
            ->addTag('controller.service_arguments'),
    ]);


    // ...
}

So it seems that my previous problems where caused by the yaml configuration or smth and not by the container itself.

Now I have to find a way to register all of my Legacy-Controllers. Will play around a bit and update if I find a good solution. (Good solutions more than welcome)

Edit2

Okay, it was not the YAML-Configuration. If I use PHP-Configuration I get the same problem.

/** @var $this \Symfony\Component\DependencyInjection\Loader\PhpFileLoader */

$definition = new Definition();

$definition
    ->setAutowired(true)
    ->setAutoconfigured(true)
    ->setPublic(false)
;

$this->registerClasses($definition, '\\', '../legacy/*');

Namespace is not a valid PSR-4 prefix.

I'll try to register the classes manually now.

Patrick
  • 1,562
  • 1
  • 16
  • 33
  • Autowire has some pretty strict requirements as far as naming conventions, class names and namespaces. Have you tried manually configuring just one controller? – Cerad Jun 13 '19 at 11:52
  • Yes, manually configuring the Controllers works. I'd just love to have Autowiring (and even more important Autoconfiguration) in place. Is there a way to work around those "strict requirements"? – Patrick Jun 13 '19 at 15:28
  • Not as far as I know. The autowire code is the very definition of magic. It works great but I doubt if anyone besides the author really understands it. – Cerad Jun 13 '19 at 19:42
  • Seems to be a limitation in the configuration only :-) I'm one step further, but still not there. I edited the original question. – Patrick Jun 13 '19 at 21:01

1 Answers1

0

Okay, I added the step that lead to this result in the original question. For me this solution works. It's maybe not the best one, but does the trick. (Open for better suggestions though).

In Kernel.php I abused the composer-Autoloader to fetch the classes I need and registered them as Services. Since unused Services will get removed I have no problems :-)

protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
{
    /** @var ClassLoader $classLoader */
    $classLoader = require $this->getProjectDir().'/vendor/autoload.php';

    foreach (array_keys($classLoader->getClassMap()) as $class) {
        $definition = (new Definition($class))
            ->setAutowired(true)
            ->setAutoconfigured(true)
            ->setPublic(false);

        $container->setDefinition($class, $definition);
    }

    // Since my ClassMap contains not only controllers, I add the 'controller.service_arguments'-Tag
    // after the loop.
    $container
        ->registerForAutoconfiguration(\BaseController::class)
        ->addTag('controller.service_arguments');

    // ...
}
Patrick
  • 1,562
  • 1
  • 16
  • 33