How to use lazy services with dependency injection in typo3? - symfony

Can I use lazy services in typo3 (version 11)?
I have installed the package symfony/proxy-manager-bridge with composer require symfony/proxy-manager-bridge. The documentation says that is enough.
When I debug the problem I find out that ContainerBuilder::proxyInstantiator is null and ContainerBuilder::setProxyInstantiator() is never called. I think it is the same problem as here.
Is there a way to call ContainerBuilder::setProxyInstantiator() in typo3?
UPDATE
I was able to call ContainerBuilder::setProxyInstantiator() in the typo3 context with a Service.php file. But it did not help with the lazy services.
// myext/Configuration/Services.php
// ...
return static function (ContainerConfigurator $container, ContainerBuilder $containerBuilder) {
$containerBuilder->setProxyInstantiator(new MyRuntimeInstantiator());
};

TYPO3 does not support this integration for lazy services out of the box like Symfony does. Especially you cannot use Symfony bundles since these are integrations specifically meant for Symfony apps similar to extensions in TYPO3.
Within Symfony the Kernel::getContainerBuilder() method is responsible for injecting the proxy instantiator. Here you can see how the Symfony-specific bundle is integrated in case it exists / is installed.
So you may need to try if you can achieve something similar with a Configuration/Services.php which receives the ContainerBuilder instance as argument. See the Services.php of EXT:core for an example.
If it works well, you can even consider publishing this as TYPO3 extension package so that others can get this up and running with a simple package installation just like in Symfony.

Related

How can the "you cannot use the "renderView" method if the Twig bundle is not available" error in symfony 6 be debugged?

I just recently upgraded my project from symfony 4 to 6, without much problems. The current online version is using symfony6 without problem.
I am now trying to clean the code, removing some useless parts and other little modifications, and I just met a strange problem. All my pages are now giving me the error:
You cannot use the "renderView" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".
Problem is: the package is present, so the recommended command does nothing.
I tried to check the code triggering the exception:
protected function renderView(string $view, array $parameters = []): string
{
if (!$this->container->has('twig')) {
throw new \LogicException('You cannot use the "renderView" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
}
...
}
So I checked the twig service with bin/console debug:container twig, which gives me the same output as with the current working version.
There is a note:
"! [NOTE] The "twig" service or alias has been removed or inlined when the container was compiled."
But this note is also present in my production code without problem.
I brought no real modification to the controller files between the two versions, the main difference being files moved and namespaces adapted to this change.
I don't have any ideas other than doing all these changes all over again, but I fear I'll fall on the same result.
Edit:
The problem look larger that I thought, as I get the same problem with the security bundle.
I tried to inject \Twig\Environment in the controller method, and it autowired with no problems.
I tried to update all the recipes with composer recipes, with no interesting result.
I tried to compare it to a newly created Symfony6 controller with twig, but found no significant differences, except the use of php attributes, which I tried to use in my project, with no result either.
Result of bin/console debug:container HomeController:
Option Value
----------------- -------------------------------
Service ID App\Controller\HomeController
Class App\Controller\HomeController
Tags controller.service_arguments
container.service_subscriber
Calls setContainer
Public yes
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
Usages none
Edit:
To be honest, if twig is now a private service, not accessible through the container, why is the AbstractController still using this line:
if (!$this->container->has('twig')) {
throw new \LogicException('You cannot use the "renderView" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
}
Wouldn't that just cause an error for everyone ? Then why not, and only now for me while it doesn't for my current version (my production is operational with the same Symfony 6 packages)
Edit:
By playing in the vendors, I managed to find that in my original code, the ServiceLocator is used in the AbstractController, but in my bugged one, it seems to be a cached Container class that is used (as $this->container).
So the has() method called in not the same...

Attempted to call method "share" on class "Silex\Application" in Silex 2

I am developing a project with silex-skeleton in its most recent version. When trying to use the share method shows me the following error:
Code:
$app['login'] = $app->share(function() use($app) {
return new Model\UserModel($app);
});
Error:
Attempted to call method "share" on class "Silex\Application"
Any suggestions or possible cause of this failure
Silex 2.0 is using Pimple 3.0 which has removed the shared method, now all services are shared by default, if you want a new instance you must call the factory method as stated in the changelog for version 2.0.
So if you want a login service you should create it like this:
<?php
$app['login'] = function($app) {
return new Model\UserModel($app);
};
You can take a look at the docs for the 3.0 Pimple version directly on it's GitHub repository
PS: Keep in mind that, at the time of this writing, Silex 2.0 is in development, so be prepared to adapt your code until it gets a 2.0 stable version. 2.0 has reached prod status as of 2016-05-18

What is __meteor_bootstrap__?

I am just starting with Meteor and working on an existing project. I am running into an issue with one of the packages(observatory-apollo) that's has the following line:
__meteor_bootstrap__.app.use Observatory.logger #TLog.useragent
It is complaining that __meteor_bootstrap__.app is undefined.
What is __meteor_boostrap__ exactly? I can't seem to find a description of what it is but from threads, people seem to know how to use it. I can only see it defined in boot.js, but it doesn't really tell me much...
Meteor uses connect npm module under the hood for various reasons, to serve static files, for example. __meteor_bootstrap__.app was the reference to connect app instance.
Before it was __meteor_bootstrap__.app but it changed couple of releases ago and became WebApp.connectHandlers object and is part of WebApp package.
WebApp is a standard package of Meteor, core package for building webapps. You don't usually need to add explicitly as it is a dependency of standard-app-packages.
Example of usage the connectHandlers is to inject connect middlewares in the same way as you would use any connect middleware (or some express middlewares, express is built on top of connect):
WebApp.connectHandlers
.use(connect.query())
.use(this._config.requestParser(bodyParser))
You can look at meteor-router Atmosphere package and take it as an example: https://github.com/tmeasday/meteor-router/blob/master/lib/router_server.js
More about connect: https://npmjs.org/package/connect

Lazy loading dependencies with symfony DI

Currently I've got a Symfony2 DI container instance ready with a service and all it's dependencies. Lets say for example I have a Car class and it has Engine and Lights as dependencies.
In my current setup both these dependencies are automatically created through setter injection when the Car object is created, but it might very well be that my Car object won't need it's lights this time around thus it doesn't explicitly need to create an instance of this dependency.
Is there a way to achieve this in Symfony DI? Thus only creating an instance of the Lights object when needed? My guess is it'll be some sort of Proxy implementation like Doctrine has but as far as i've seen it doesn't exist in Symfony DI.
Inject the dedendencies that are mandatory through the Constructor via your services.yml, automatically.
If you have optional dependencies inject them through a setter in your Controller when you need them.
$this->container->get('cars')->setLights(new \Namespace\Lights());
Of course your Cars class must be designed like so and you have to direct the injections yourself in your controller, or whereever needed, code.
Question is already answered, but for who needs this functionality, lazy services are implemented in Symfony 2.3.
You need to install the ProxyManager bridge.
You can find official documentation here.
A very interesting question, but I don't think it's possible within Symfony2's Dependency Injection Container. The container is only aware of what you tell it - in this case, you have a dependency that's conditional on a specific use-case. Plus, the registration of services happens early on in the app's life, so I don't see how you could get this to work.
Maybe you should use the Factory pattern. Register a CarFactory as a service, and then when fetching a Car instance, you can specify that it should include a Light dependency.
Can I ask why you want to achieve this? There may be a simpler solution.
It's not a pretty workaround, but you can try injecting the whole DIC, then getting the Light and Engine services when neccessary.
I was thinking about something like this method in the Car class:
protected function getLightService()
{
if (!$this->light) { //so we reuse the first instance
$this->light = $this->dic->get("car.light");
}
return $this->light;
}

MVC2 with Ninject.Web.Mvc 2.2 and Ninject 2.2 runtime version 4.0 always asks for parameterless constructor for controllers

I have a previous project running Ninject 2.0 runtime version 2.0 and now I am using Ninject in a new project and using the new Ninject, ninject web.mvc version 2.2 for runtime version 4.0.
Every single time I get the error no parameterless constructor
Invalid Operation exception
An error occurred when trying to create a controller of type HomeController'. Make sure that the controller has a parameterless public constructor.
What am I missing. All the bindings are registered.
Do I need to now define interfaces for Controllers as well such as HomeController as IHomeController as I have seen in some examples, Or do I get back to using the older version
There is one version that does not show activation exceptions properly but show this exception instead. Most likely the problem is a duplicated binding.
In addition to what Remo Gloor said, you might want to check that MVC is set up to use Ninject correctly. I was doing some things manually on an older version of the MVC plugin and ended up needing to just bite the bullet and make Global extend the NinjectHttpApplication class, which I had previously been avoiding.
The error you're getting is the error you would get if MVC tries using its built-in controller factory to produce controllers. So you may want to create a custom method binding on your controller class and put a breakpoint inside to make sure it's even being invoked.
You may also want to switch to version 2.3. You can pick up the latest builds of Ninject and all its extensions here.
I have seen this issue mentioned couple of times on forums where there is no direct answer, here is the solution to the above problem, i.e., working with latest ninject
Download the latest Ninject from github.
The ninject I got for MVC2 is named as Ninject.Web.Mvc2-2.2.0.0-release-net-4.0 (runtime version 4)
Now during adding reference add Ninject.Web.Mvc.dll(check the version is same as above by right click properties in VS)
Now Add Ninject.dll from the lib folder in same parent folder (check the version as above)
Now Add CommonServiceLocator.NinjectAdapter.dll from the extensions folder in lib parent folder (check the version as above.)
The missing link in all these have been the commonserviceLocator.dll and the correct version should match. This should be tried if you are sure your bindings are correct as mine were and check to see if your project work with older version.
Thanks to everyone, and good luck :)

Resources