im looking to pass an already instatiated object to my service constructer, rather than creating a new one, to create a new one i do this:
services:
ExampleService:
class: Ex\ModelBundle\lib\Ex\ExSave
LoginService:
class: Snap\ModelBundle\Service\Login
arguments: ["#doctrine.orm.entity_manager", "#ExampleService"]
How would i pass an already instatiated ExampleService to LoginService
By default all services have container scope which according to docs mean:
The same instance is used each time you request it from this container.
So, you create your ExampleService, but any other, subsequent, request for that service is going to return its previously created instance.
It all boils down to point that multiple services can (and will) use shared instance of your ExampleService.
Alternately, you could use Setter Injection.
Basically, you don't pass #ExampleService to __construct but rather to separate setter which will set the property value (within the service). Then you use your service as usual.
Related
I have a config file with such array:
'ppr' => [
'validate' => TestRequest::class
];
Now, I want to retrive this class in other part of the system and use it to validate form (outside of the controller).
While using config('main.ppr.validate') all I receive is namespaced name of the class instead of the class object.
As I already accepted that it won't be that easy to just use reuqests as in controllers, I still do wonder how to pass a class by config.
While passing eloquent models it works like a charm (or i.e. config arrays with middlewares etc.), so I suppose there is some magic binding to the IoC to achive that, is it true?
My question is, how to use class passed as in example above without initializing it like:
$obj = new $className;
Laravel (and many other applications) use Dependency Injection to achieve this magic -- your words, not mine! :D
It seems that the Service Container is what handles this in Laravel and should be of help to you.
Directly from the Laravel docs (linked above):
Within a service provider, you always have access to the container via the $this->app property. We can register a binding using the bind method, passing the class or interface name that we wish to register along with a Closure that returns an instance of the class:
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
Also:
You may use the make method to resolve a class instance out of the container. The make method accepts the name of the class or interface you wish to resolve:
$api = $this->app->make('HelpSpot\API');
And:
If some of your class' dependencies are not resolvable via the container, you may inject them by passing them as an associative array into the makeWith method:
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
IMHO, I would look up where/how this is implemented in the native Laravel code (usually the Illuminate vendor) and see how it is used / meant to be implemented.
Furthermore, ClassName::class will return the namespace + class of that class. This is why you only see the class name and are not actually receiving an object/instance of that class.
I'm not sure what/where/why/how you're implementing your class and why you need this functionality somewhere that it doesn't already exist. Laravel is pretty good about already having things set up where you need them, so think twice before breaking out of the box and make sure there isn't a default solution for your situation!
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.
I need to make a DI container which will automatically inject the needed dependencies.
I only have one idea to do this,
Lets say i have initialized a controller using the container, the container will get the namespace of that object and then it will detect what dependencies it requests. The container should get the namespaces of the dependencies that needs to be injected, and then it will create them, then create a new object witg these depndencies and return it.
But the question is, how can you check what dependencies the constructor requests in php?
ReflectionFunction::getParameters() or ReflectionMethod::getParameters() return an array of ReflectionParameter instances.
Now on the ReflectionParameter instances you can use ReflectionParameter::getClass() to get the classes you need.
To get the class' name, you need to access the name property of that ReflectionClass which was returned by ReflectionParameter::getClass().
I'm currently using an entity with a specific ID in a service. To make this work using dependency injection, I am injecting the entity repository and a specific ID. For example:
public function __construct($myRepo, $myId) {
$this->myEntity = $myRepo->find($myId);
}
Is there a way to directly inject this specific entity without passing in the repository? For example, the ideal method would be:
public function __construct($myEntity) {
$this->myEntity = $myEntity;
}
I can't figure out how to define the services that are needed to do this.
Services should be stateless. Saving a user with a specific id in a service makes them statefull.
Instead of passing the entity in the constructor and saving it in a property, the entity should be passed to the method that is called. E.g. instead of a mailer with the to address passed into the constructor, it should be passed to the mailer#mail() method.
#Wouter makes a good point about services being stateless. However, you can use the DI factory capability to accomplish your goal:
specific_entity:
class: SomeEntity # Not used but you still need something here
factory_service: specific_entity_repository
factory_method: find
arguments:
- 42
This will call the find method on your repository with an argument of 42. The returned entity will then be injected. I'm assuming you already know how to setup a repository as a service.
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.