Well I'm a big fan of constructor based DI, so effectively the Portlet constructor parameters lists its dependancies. So with Reflection can inspect the constructor arguments and create/get instances to satisfy its dependancies.
function __construct(LotusNotusConnector $lotusNotus) { ... } }
$portlet = $container->create('CalendarPortlet');
Which would cause a call to $container->create('LotusNotusConnector')
Wether create() actually creates a new instance of a class, or returns an existing (shared) instance is part of the container configuration.
Phemto is good place to learn from http://phemto.sourceforge.net/quick-start.php
Right, but this only works if I have access to $container. If call my command from the front controller and inside my command I call the various portlets, then I have a problem. It would be nonsensical to put a dependency on the lotus notes class for the command, since this is totally optional. So like I said, I would either need: 1) a static method to access the global service container 2) have a different service container that I instantiate inside the command that manages the portlets
In this case I am leaning towards 2), since its very unlikely that other parts of the application need access to the lotus notes class. There might be other commands that need access to this dependency configuration (like the admin command), but that command might as well use the same service container.
I'd probably pass the container into the controllers & commands.
Possibly create a new scope of the container maybe
$local = new Container($container);
So Portlets can still share object instances like a database connection, but add to or override if needed.
If a command needs to create various portlets then it needs a portlet factory. This factory is a dependency of your command and should be injected via the constructor
public function __construct(PortletFactory $pf,//other dependencies...
Since you're injecting the PortletFactory from your controller, the command doesn't need to know any of the dependencies of the various portlets. The factory can be an interface because the command doesn't care how it's making portlets, it just wants them.
interface PortletFactory { /** * @return Portlet */ public function create($portletName, $user); }
When you instantiate a command in your front controller (or maybe in the container itself) you can pull an implementation of PortletFactory from the container to pass to the command constructor.
Your container might give you an implementation that is just a thin wrapper around the container itself, or an implementation that provides mock portlets when you're in testing mode. The idea is the command is not dependent on the container, only on what it actually needs: something that can create portlets.
Yeah well. The command managing the portlets might or might not have to instantiate one or even many portlets. This is all dynamic based on user input and the users data. As such I cannot reasonably inject these dependencies without putting a lot of overhead on each request. I could try and break up the command to ensure that all requests where I know I will not need a portlet will be handled by another command. But I am still stuck with the situation that some requests might need some or even all portlets, while others will only need a single one. The dependencies of each portlet are obviously radically different, one needing a DB connection, the other needing a connection to Lotus Notes, the other one needing a different DB connection, the next one reading an RSS feed or whatever.
So like I was saying, imho the best approach remains making a new service container inside the command. If there is overlap in dependencies from the general framework and the portlets, I can look into making these dependencies of the framework and then manually setting the instance in the command service container.
What I am still unsure about is if I want a fallback to be able to call the "global" service container statically if all else fails.