Symfony 4: Statically get container in helper class - symfony

I'm working on an active record-like system for symfony and I encountered a problem.
I have a helper class in symfony that is not a service, nor do I want it to become one. This class has a static property named container and a static method to set it. Now the question is, when do I call this static method to set the container?
I've tried the bundle extension, compiler pass, all to no success. (Mostly because they have to be services and when I make it a service and extend it later, it skips the compiler pass.)
Let me know if anyone requires any further information and thanks in advance!

If you want to inject the container into the helper, i.e. call Helper::set($ontainer) you have to do it when the compiled container is available. Both Extension and Compiler Pass modify the container before compilation and therefore are probably not the right place, unless you want to inject the helper as a service into the container and reference the container, much like the following approach outlines.
You could call the Setter-method in your Kernel, where the container is created, or inside a Controller, which is loaded when the container is built and - when you extend the Controller-base class, has access to the container. I don't think that's a good idea though because you can never be certain when/if the method was called and what container is in there. Also, when using the new AbstractController base class you don't have access to the full container, only a service locator for the specific services needed by the controller.
When configuring it as a service inside your services.yaml you can use calls or setter injection to inject the container service by referencing #container. I also wouldn't recommend this, but I consider it the lesser of the two evils, considering what you are asking.

Related

Difficulty copying/extending singleton manager class

I want to extend or copy the PopUpManager class to add the ability to keep track of the number of windows.
I just want to add a simple windowCount++ when a window is added and windoCount-- when it's removed.
the problem is PopUpManager is a Singleton class... I wasn't able to make it work properly by extending it. And now I have tried to copy the code from the PopUpManager.as file and just add my variable to the end of its functions. It doesn't seem to be working though since it says my properties are undefined even though they are declared above the constructor.
I am thinking I would have to make a copy of the PopUpManagerImpl.as since that's wehre it seems much of the business resides (PopUpManagerImpl extends EventDispatcher implements IPopUpManager) would that allow me to have access to the variable? and should I ignore the manager and just put it in the implementation class?
here is a link about Using the Flex Singleton register, which helped me out when finding myself in the same situation.
I hope you can inspire from that too.
You likely didn't declare yours properties as static. The PopUpManager uses all static methods - this is why working with it you use syntax like:
PopUpManager.createPopUp(...
instead of
var popUpManager:PopUpManager = new PopUpManager();
popUpManager.createPopUp(...
This means that any variables declared in the PopUpManager need to also be static so as to be accessible at the class level.
public static var windowCount:int

Unity: registering a decorator in a child container

I have the following scenario:
In the base container, I am registering a type.
container.RegisterType<IFoo,Foo>();
In a child container I would like to register a Decorator which wraps whatever the base container uses. So if I have this class:
public class FooDecorator: IFoo
{
public FooDecorator(IFoo foo) {}
}
I want to register:
childContainer.RegisterType<IFoo,FooDecorator>();
It would seem reasonable to me that when the child container resolves IFoo in the FooDecorator constructor, it will try to resolve the parent container's IFoo. But it doesn't. It tries to resolves FooDecorator again, and therefore again and again until a StackOverflow exception is raised.
I know this can be solved by specifying an InjectionConstructor in the child container registration, like this:
childContainer.RegisterType<IFoo,FooDecorator>(
new InjectionConstructor(new ResolvedParameter<Foo>()));
But this seems fragile. If someone wants to change the actual instance of IFoo in the base container from Foo to something else, he would have to also modify all the child containers as well.
So am I missing something? Is there a better solution to the problem?
You can use named mapping:
parentContainer.RegisterType<IFoo, Foo>("decorated");
childContainer.RegisterType<IFoo, FooDecorator>(
new InjectionConstructor(new ResolvedParameter<IFoo>("decorated")));
This way the registration of the decorator depends on the named mapping "decorated" of the interface IFoo.
onof's answer requires fiddling with constructor parameters, that may change during development. My answer elsewhere addresses this but has different drawbacks in exchange.
With my technique the registration would look as follows:
unityContainer.RegisterType<IService, LoggedService<ProfiledService<Service>>>();

call flex initComplete at a specific time

Below is the overriden on complete function for a preloader in Flex.
private function initComplete(e:Event):void
{
//dispatchEvent(new Event(Event.COMPLETE));
cp.status.text="Configuring... Please Wait";
}
What I want to do is when the app has finsihed loading I want to change the preloaders text to "configuring".
Then I want to go and do a bunch of setup stuff in my code.
Once I've done all the setup I wanted how can I get the Preloader to dispatch its Event.complete from else where in my code?
I tried Application.application.preloader but it comes up null.
So I guess my question really is how to access a preloader from anywhere in my application.
Would a better approach be to have all setup classes as members of my preloader class?
One thing that might help is a Model-View-Controller pattern. Are you using a framework for your application like Mate, Swiz, or Cairngorm?
If you were using Mate, for example, you could do something like this:
Create an AppStateManager class with a property (e.g. applicationState)
Create an EventMap with an EventHandler for the FlexEvent.INITIALIZE event. In this handler, set the AppStateManager.applicationState to something like "CONFIGURING"
Your EventMap has an injector that injects the applicationState property into a view. The injector listens for changes to this property and updates the view. In this case it might just be injected into your main view.
In the main view, you have a public bindable property also called applicationState that gets injected by Mate.
In the setter for this property, you can have an if/then or a switch that does different tasks depending on the state. For example, if applicationState == "COMPLETE", then this.preloader.dispatchEvent(Event.COMPLETE) or something like that.
The details are pseudo-sketched out but the idea is to use Flex's bindings to notify view components when changes have been made, and to have shared objects that maintain state. Not sure if that's what you're looking for...
The component LifeCycle does specific stuff in a specific order, and the near final element is to make the component visible.
It sounds to me like you want to defer this setting of visible to true to do other stuff. But, I imaging if you were making use of the component LifeCycle this would be a non-issue.
What sort of app init stuff do you need to do?

How to hack private static field in Flex?

Is there a way to change private static field of an alien class?
For example:
package mx.managers {
public class TooltipManager ... {
private static var _impl:IToolTipManager2; // <- assign my own value here
...
}
}
In Java it is possible to do it using Reflection API. What about Flex?
No, that is not possible.
If you are looking into changing the implementation of the TooltipManager, have a look at the Singleton class in the Flex SDK. You'll need to create a custom implementation and register it via the Singleton class before the application initializes. The best is to override the application preloader and do the registration there.
Well, if you feel like you can handle the extra responsibility, you can monkey patch the class by copying the source into your own source tree with the same package and apply the necessary modifications. That way the flex compiler will use your implementation rather than the SDK implementation.
This technique is sometimes used as a last resort to fix issues which cannot be fixed otherwise. Drawbacks include issues such as forwards compatibility and unintended side effects in the same or other classes dependant on the class your editing.

Autofac in web applications, where should I store the container for easy access?

I'm still pretty new to using Autofac and one thing I miss in the documentation and examples is how to make it easy to get to the configured container from different places in a web application.
I know I can use the Autofac controller factory to automatically resolve constructor injected dependencies for controllers, but how about the other stuff you might need to resolve that is not injected yet.
Is there an obvious pattern I am not aware of for this?
Thank you!
The Autofac "way" is to have an IContext constructor parameter. Autofac will inject an object that can be used to resolve types.
The context is usually the container behind the scenes, IContainer implements the IContext interface, though IContext is limited to only doing resolves.
I know that the container should not be "overused", but I have, as the OP, classes that requires resolving types that is not known ahead of time (and thus cannot be used as constructor params). I find it useful in these cases, to think of the container as yet another service that can be used to resolve other services, and inject that like any other service.
If you feel that using IContext binds you to Autofac and you need to abstract that with your own interface this is just a matter of registering an IContext wrapper class with your container.
Update: in Autofac 2, the IContext is called IComponentContext.
First of all try not to overuse the IoC container. Its great for "wiring up" controllers, views and services but objects that need to be created during runtime should be created by factory objects and not by the container. Otherwise you get Container.Resolve calls all through your code, tying it to your container. These extra dependencies defeat the purpose of using IoC. In most cases I can get by only resolving one or two dependencies at the top level of my application. The IoC container will then recursively resolve most dependencies.
When I need the container elsewhere in my program here's a trick I often use.
public class Container : IContainer
{
readonly IWindsorContainer container;
public Container()
{
// Initialize container
container = new WindsorContainer(new XmlInterpreter(new FileResource("castle.xml")));
// Register yourself
container.Kernel.AddComponentInstance<IContainer>(this);
}
public T Resolve<T>()
{
return container.Resolve<T>();
}
}
I wrap the container in a Container class like this. It adds itself to the wrapped container in the constructor. Now classes that need the container can have an IContainer injected. (the example is for Castle Windsor but it can probably be adapted for AutoFac)
Having IOC container globally available is not a best practice. Even passing container is not encouraged.
If dependency injection can not be used (you need to create\request objects after component has been created) then you can:
Use hand-coded factories (factory is injected to the component and component uses factory to create other objects)
Use Autofac delegate factories or new auto-generated factories in Autofac 2.
Peter Lillevold's response above is correct - you can access the container from any component by taking a dependency on the IContext interface.
If you really do need the actual container reference, see Autofac.Integration.Web.IContainerProviderAccessor.
The usual way of doing this is to store the container in a static variable in your Global app class.

Resources