I am currently testing phalcon php for a project, and I am looking for a way to automatically inject certain classes automatically based on an implemented interface.
The Dependency Injection reference has an example where if a class implements Phalcon\DI\InjectionAwareInterface, it will automatically inject the DI into that class.
What I want to do is similar. If a class has for instance Aranea\Db\DbAdapterAware, it should automatically inject the DbAdapter in that class. I am looking for something similar to what Zend Framework 2 does (https://juriansluiman.nl/article/121/interface-injection-with-initializers-in-zend-servicemanager), where during DI config you can specify initializers like this:
'initializers' => array(
'logger' => function($service, $sm) {
if ($service instanceof LoggerAwareInterface) {
$logger = $sm->get('logger');
$service->setLogger($logger);
}
}
),
If this is not automatically possible in PhalconPHP, I was thinking of overriding the FactoryDefault class and implement it myself. What would be the right place to inject this logic? In the get* methods, or rather in the set* methods? I assume that a method is not initialized during DI initializing but on first call, so get* would sounds more appropriate?
Thanks for your advice,
Jeroen
The Dependency Injection reference has an example where if a class implements Phalcon\DI\InjectionAwareInterface, it will automatically inject the DI into that class.
That is not entirely true, what it means is that the DI gets (automatically) injected when the service is resolved given it implements this interface, the DI doesn't magically appears there just because the class implements some interface.
If a class has for instance Aranea\Db\DbAdapterAware, it should automatically inject the DbAdapter in that class.
That is sort of how it works (not technically) if your class extends the Phalcon\DI\Injectable (or implements the InjectionAwareInterface in the same way as Phalcon\DI\Injectable). Inside Injectable there is a __get magic, which returns the service from the DI if the service exists. In other words stuff get injected only in the DI, and other classes lookup for services in there.
To inject your own services you can either pass them in your configuration to the DI or extend the DI or FactoryDefault. The difference between the two is that FactoryDefault already comes preconfigured with the useful services, which you might not need though.
I assume that a method is not initialized during DI initializing but on first call, so get* would sounds more appropriate?
Yes, there is a Phalcon\DI\Service object that represents the service and resolved when called for the first time (if it's a shared service) or resolved every time (if it's not). You normally would want all your services to be shared, otherwise this often becomes a bottleneck, e.g., when resolving a non-shared database adapter, which establishes the connection every time you call it…
PS: Note, for it to work as you want it with the DbAdapter you can do a few things:
Add the adapter getter and return DI::getDefault()->getShared('db');
Extend the Phalcon\DI\Injectable and set the DI when the class is created, so it can lookup for services.
Every time you need the adapter simply get it from the DI like shown in the first option.
Related
I have various Loggers defined in my module_config. Each controller or service that needs a specific logger needs to get the logger via its factory injected.
Ideally I don't want to worry about this injection and can make the loggers gloablly accessable (without having the service locator in my service/controller). They should be lazy loaded/instanciated, only when I need them.
Is there a way to do so? I was thinking of initializers, treats or using the event manager.
I know, It sounds like having the service locator back.
Any ideas?
I guess the cleanest way is to use a controller plugin to call upon your loggers from a controller.
Implementation is pretty simple:
Create a new PHP class and have it extend Zend\Mvc\Controller\Plugin\AbstractPlugin.
It's constructor should accept the logger(s) as a dependency, and it's __invoke method can be used to "magically" retrieve a logger.
Next, create a factory for it, implementing Zend\ServiceManager\FactoryInterface and use it to inject the dependencies (i.e., the loggers)
Register the factory in your servicemanager configuration:
'controller_plugins' => array(
'factories' => array(
'Logger' => 'MyApp\Controller\Plugin\Logger',
)
),
You are then able to call it in a controller like so:
$this->logger();
(See http://lab.empirio.no/custom-controller-plugin-in-zf2.html) for more information on creating custom controller plugins.
Lazy-loading loggers can be handled by registering them as lazy services under the lazy_services key in your service_manager configuration.
As for your services, you can implement your own version of a ServiceLocator (also known as a plugin manager).
It would work a lot like the ViewHelperManager, ControllerPluginManager, ValidatorPluginManager, etc.
I won't explain how to do that as it's a lot of code and many how-to's exist on the web on how to create one.
EDIT:
As #tasmaniski noted below you could use injection based on marker interfaces using initializers (ZF2 uses this internally through the 'Aware' interfaces).
Do note that initializers are relatively slow especially when used incorrectly, i.e. as a closure in your Module.php or module.config.php file.
Also, initializers get called upon for each service fetched by the ServiceManager's get() mtehod and can thus add significant overhead.
It is however a much easier and faster solution than writing your own implementation of a plugin manager.
I have exactly the same question in my application/architecture.
So the solution was:
In the scope of Controllers, as #FuST said you have to create controller plugin. Than the logger will be available across all controllers.
In the scope of services, I you can do a "Interface Injection".
So in your Service you have to add 3 thing:
// #1 Create interface with setLogger($logger); method
class YourService implement LoggerInterface {
private $logger; // #2 Define private $logger;
// #3 Add method that you will use to inject the $logger later
public function setLogger($logger){
$this->logger = $logger;
}
}
Than create initializer and inject $logger in every class that implement the LoggerInterface.
Phalcon is a decoupled PHP framework that allows services to be injected via the DI container. They have several default services, but also allow you to define your own services as follows:
$this->di->set('my_service',function(){
return new myService();
});
You can then call the service in the application in a couple of different ways:
$my_service = $this->di->get('my_service');
Or
$my_service = $this->di['my_service'];
My application utilizes the dependency injector along with another feature of the Phalcon framework, a data cache, and these features don't play well together.
As soon as you call a service via the DI in a class, the DI parameter of that class is established. If I try to cache that object, I get an error Serialization of 'Phalcon\DI\FactoryDefault' is not allowed. I've done some searching, and can't seem to find a solution that will allow me to utilize dependency injection and caching on the same object.
The whole code ends up looking something like this:
//In bootstrap file
$this->di->set('my_service',function(){
return new myService();
});
//In another class
class myclass extends Phalcon\Mvc\User\Component
{
$cache;
public function construct(){
$cache = new Phalcon\Cache\Frontend\Data(array('lifetime'=>24*3600*5));
$this->cache = new Phalcon\Cache\Backend\File($cache, array('cacheDir' => '../app/cache/'));
$this->di->get('my_service')->someAction();
$this->cache->save('myKey',$this);
}
}
Is there a way to get around this issue?
I believe the problem is caused by the use of anonymous functions to register services. This is because the application doesn't know what's inside the function until it's actually run, so the factory default DI can't be serialized.
One option would be not to extend the Phalcon Component class, and instead inject the required dependencies as constructor parameters. This way when you serialize your object you're not also serializing the DI (which currently is being inherited through the Componant class).
You can have Phalcon automatically inject the required dependencies by setting it up as part of its service registration in the bootstrap file.
Another option I can think of would be to use a different Frontend cache adapter that doesn't serialize the data:
http://docs.phalconphp.com/en/latest/api/Phalcon_Cache_Frontend_None.html
I'm making my own primitive MVC framework with PHP, and I'm wondering where I should load/instantiate corresponding controller dependencies?
In the constructor of each controller (tightly coupled) or inject them (loosely coupled)?
The only part of the latter that I'm not too sure of is for the dependencies to be instantiated on bootstrap level, outside of the MVC paradigm, before being injected. Not every controller uses the exact same dependencies besides the default parent ones. I would have to instantiate them all, which would also create a lot of overhead.
I've seen some existing frameworks do it like $this->load->model('model'); // CodeIgniter in the constructor, but I have no clue on why they're doing it like that.
I would suggest you inject the dependencies, so your controllers are less coupled to your framework. This will make a switch to another framework easier.
About instantiating dependencies: I suggest you use (or implement) a dependency injection container. This container should contain factories that can instantiate services.
In an ideal situation your controllers are services too (meaning they too have factories in the dependency injection container).
This way only the controller you need for a particular request will be instantiated, and therefor only its dependencies are instantiated.
When building you own framework, this means that after the routing phase (when the correct controller is known), the framework should grab that controller from the container. The container itself will make sure all dependencies that are needed will be provided.
Have a look at Pimple for an example of a simple dependency injection container.
PS: That line from CodeIgniter looks a lot like the service locator pattern. This pattern is similar to dependency injection, but does not provide full inversion of control.
Q: Where should i load/instantiate corresponding controller dependencies?
There are multiple ways.
The load and instantiation concepts are basically "before/outside" and "after/inside".
Before and outside means, that you load the file containing a class (which you want to instantiate and pass to the controller), before you load the controller.
But how do you know, what the controller needs, before loading the controller? Uh..
Dependency Description Files
A description file comes into play, describing the wiring between your controller and it's dependencies. In other words, you can see the dependencies of your controller by looking at it's dependency description file. This concept is often used by Dependency Injection tools, which analyze the object and pull the dependencies names out automatically. It's also possible to maintain such a wiring configuration file manually. But it's tedious.
Service Locator
A Service Locator is a instantiation helper for dependencies.
Basically, it contains the same information like a dependency description file, but this time in form of a registry. The link between parts of your application becomes this registry.
Both strategies introduce overhead. It's a trade-off. When you change the perspective and look at things from an application with maybe 500+ classes, then you realize that a dependency injection tool is sometimes worth it.
Manual Injection
via Constructor Injection.
After and inside means, that you load the file containing your controller and then start to care about the dependencies.
At this point the class is not instantiated, yet, but the autoloader might do it's dirty deeds behind the scene. He evaluates the use statements at the top of your controller file. The use statements declare namespaced classes, which the autoloader resolves to actuall files and loads them. You might then start to use these classes as dependencies in your controller. This is probably the easiest way to solve your problem and i strongly suggest looking into the topics autoloading with namespaces and use-statements.
When the class is instantiated, you have the following possiblities:
use might use Setter Injection or Reference Injection to set the dependencies to the object. This requires that your Constructor Dependencies are already solved or your constructor is empty.
It's possible to combine these strategies.
Q: What does this do $this->load->model('model'); // CodeIgniter?
CodeIgniter is a legacy application framework. It was created in times, when namespaced autoloading wasn't available. $this->load is a basic class loading helper. This is the opposite of an "auto"loader, (which surprise, surprise) loads things automatically.
CodeIgniters loader class is used to load various other classes, like libraries or files from the view, helpers, models or user defined stuff. This is again the concept of a registry. Here the registry just knowns where things are in your application layout and resolves them. So $this->load->model('model'); means that the modelfunction must have some piecies of information, about the position of model files in your application.
You provide a model name and the path for the file is constructed by model.
And this is exaclty what it does (except a bit of overhead): https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Loader.php#L223.
Since I'm a Symfony developer, I can only give you a reference to Symfony.
I think you should do like they are doing in Symfony by thinking about what you need in each
Controller object.
At least, you need :
a Request object
and a Model loader object that gives you every Model you need.
Create a BaseController that implements these few functions and then extend it with custom Controllers.
You can also take a look on Silex : http://silex.sensiolabs.org/ a Micro Framework
Hope it helps.
When do you say "In the constructor" you mean to pass in the conatiner and pull the dependencies from them (in the constructor)?
<?php
class SomeController
{
public function __construct($container)
{
$this->service1 = $contanier->get('service1);
}
//...
}
I advice against that, though simpler and easier you will be coupling your controllers to the container thus using a ServiceLocator instead of truly inversion of control.
If you want your controllers to be easy unit-testable you should use inversion of control:
class SomeController
{
public function __construct($service1)
{
$this->service1 = $service1;
}
//...
}
And you can even create your controller as a service inside the container:
// this uses Pimple notation, I hope you get the point
$container['controller'] = function($c) {
return SomeController($c['service1']);
}
Use proxy services to lazy load them
Also if your controllers needs more than some services and you won't be using all of them you can:
1) Use proxy services in order to lazy load the service only when they are really needed
<?php
class ProxyService
{
/**
* #var Service1Type
*/
private $actualService;
public function __construct()
{
$this->actualService = null;
}
private function initialize()
{
$this->actualService = new Service1(); // This operation may take some time thus we deferred as long as possible
}
private function isInitialized()
{
return $this->actualService === null;
}
public function someActionOnThisService()
{
if (!$this->isInitalized()) {
$this->initalize();
}
$this->actualService->someActionOnThisService();
}
There you have a simple proxy object with lazy loading. You may want to check the fantastic Proxy Manager Library if you want to go that route
2) Split your controller
If your contoller has too many dependencies, you may want to split it.
In fact you may want to read the proposal by Paul M. Jones (lead developer of Aura Framework) about MVC-Refinement, IMHO is a good read even though you may not fully agree with it.
Even if you split your controller in order to reduce the dependencies, lazy loading your dependencies is a good idea (obviously you'll have to check weather if its doable in your context: more work in order to gain more speed).
Maybe you need to define __autoload() function before you try to load the Classes which is not loaded yet. Like:
function __autoload($className) {
require "/path/to/the/class/file/$className.php";
}
My example is very very simple to auto require the file which the class definition is in.
You can also use if-else statement or switch statement in that function to fit your own situations smartly.
The __autoload() function is called when PHP doesn't find the class definition, works for new, class_exists(), call_user_method(), etc, and absolutely for your dependences/parents classes. If there is still no class definition after __autoload() is called, PHP will generate an error.
Or you can use spl_autoload_register() function instead of __autoload() more gracefully.
For more information, you might want to see:
http://php.net/manual/en/function.autoload.php
http://php.net/manual/en/function.spl-autoload-register.php
First of all, sorry for my bad English, I hope you understand what I'm saying.
Here is my problem:
Lets assume i have an MVC application including standard router, controller, model(service) layer and some kind of db connector.
Model layer depends on a db connector, controllers depends on models/services and the top-level "application" class depends on routers and controllers.
My object hierarchy looks like this:
App -> ControllerFactory -> ServiceFactory -> DAO -> DbConnection
Perhaps, written above doesn't look like best application architecture ever, but i want to focus on the other thing:
When i'm trying to instantiate an App class i should pass all dependencies to the class instantiated; class dependencies, in turn, has their own dependencies and so on.
As a result I get all hierarchy stack instantiated at once. But what if i dont need to access the database in some cases; what if some controllers are used for rendering static templates without model interaction?
I mean, what if there are some special cases when class does not require its own dependencies(and in some cases it does)? Should i inject dependencies conditionaly or something?
I'm really stuck at this point and i don't know what to do.
Update: after re-reading carefully your question, here is another advice: yes, every class has different dependencies.
Don't inject every object into every other object. For example, some services might need DAOs, so inject them. But if a service doesn't need a DAO, don't inject any DAO.
The rest of my answer is valid if you have (for example) a service that needs a DAO (and thus a DB connection) not for every method.
What you may be looking for is lazy injection.
It is the act of injecting a dependency not loaded, so that the object is loaded only if/when used.
In conrete terms, that means injecting a proxy object, that would look like and behave exactly like the original object (for example, the db connection).
Several DI container (frameworks) support this so you don't have to create proxies yourself. I'll take as an example PHP-DI (I work on that project FYI).
Here is an example using annotations:
use DI\Annotation\Inject;
class Example {
/**
* #Inject(lazy=true)
* #var My\Class
*/
protected $property;
/**
* #Inject({ "param1" = {"lazy"=true} })
*/
public function method(My\Class $param1) {
}
}
Of course if you don't want to use annotations you can use any other configuration you want (PHP, YAML, …). Here is the same example by configuring the container in pure PHP:
$container->set('Example')
->withProperty('property', 'My\Class', true)
->withMethod('method', array('param1' => array(
'name' => 'My\Class',
'lazy' => true,
)));
See more in the documentation about Lazy Injection.
Note: you may not be using a Container for now (and that's not a problem), but for tackling lazy injection this is a fair amount of work and you might need to start considering using one.
If your dependency construction is complex, simply add a new factory class that should contain all the logic to create a correct object for you.
class AppFactory(){
__construct(all params){
}
build(useDB=true){
// logic to build
if(useDB){
App = new App(new ControllerFactory(new ServiceFactory(new DAO(new DbConnection(params)))))
} else {
App = new App(new ControllerFactory(new ServiceFactory(null))))
}
return App;
}
}
I am currently building an MVC application in PHP (not using any frameworks). I am using yadif (https://github.com/beberlei/yadif) for dependency injection.
I would like to build a login module. It should be able to use adapters, for example one might be able to set that logins are authenticated using the MySql database or some LDAP directory. This setting would be done in the admin area and is stored in a database.
I imagine that I would have an abstract adapter:
<?php
abstract AbstractLoginAdapter{
abstract function login($username, $pass){}
}
I would then just implement adapters like so:
<?php
MySQLLoginAdapter extends AbstractLoginAdapter{
public function login($username, $pass){
//do stuff
}
}
That's all nice and well, but how do I create an instance of the adapter? Usually, dependencies would be injected using yadif via the constructor:
<?php
class loginController{
private $_adapter;
public function __construct(AbstractLoginAdapter $adapter){
$this->_adapter = $adapter;
}
}
However, since I don't know which concrete adapter will be injected, I can't set that in a configuration before hand. Yadif allows me to create a configuration which I then need to pass to the container:
$builder = new Yadif_Builder();
$builder->bind("loginController")
->to("loginController")
->args($SelectedLoginAdapter);
Since the application uses a front controller, a DI container is created there. It then creates a routing object etc.
In light of this, should I pass a reference of that container down to the loginController object, and then use that container to instantiate my adapter?
Or should I instantiate a new container within my loginController object and then just load in an instance of the adapter?
I would do the first: pass a reference down to your controller. You'll want to use a single Dependency Injector Container (DIC) in your application. You don't want to create a new DIC whenever you need access to it. That would lead to duplication of objects stored in the DIC.
I know this is how Symfony 2 does it. All controllers (and many other classes) implement the ContainerAware interface. That interface has a single method setContainer() that is used to pass down a reference to the DIC.
I don't know about your specific DI tool but from a DI point of view you would be specifying which type to use. The container itself is responsible for instantiating a new instance (and possibly of all the dependencies of that type as well) of the configured type.
The benefit of DI in your example would be that you could deploy exactly the same code with a different configuration with 1 installation using LDAP and the other using MySQL authentication.
Refactor type hinting ("AbstractLoginAdapter") to ("MySQLLoginAdapter").
If you call abstract class method in the new __CLASS__ // Fatal Error.