I'm using Zend Framework 1 and Pimple dependency injector. After watching some Google Guice presentations on YouTube, I'm not sure if I'm really using DI and not a simple factory. The way I'm making use of my Pimple injector is by asking it to give me an instance of some object based on a string key registered and associated with the object:
class SomeService extends AbstactService {
/** #var Pimple $injector Inherited from base class */
protected $injector;
public function save(array $data) {
$model = $this->injector["some-model"];
if (empty($data["id"])) {
$model->insert($data);
} else {
$model->update($data);
}
}
}
The member variable $injector is created and configured at bootstrap, and sent to my AbstractService class, so all concrete services inherit it.
So by the way that $injector is used here, even though it uses Pimple (a DI container), is this implementing DI pattern or something else (factory or maybe service locator) ?
Update
Some further info: I'm using Zend Framework (MVC) building a nutrition/exercise website.
I think what is confusing me is how to create some object inside a method, where that object is only needed for that method, and the method takes some run-time arguments. For example, the SomeService class gets instantiated by the container in my controller. Then I call SomeService::save() passing in $data. Where and how would $model be created? Suppose $model is only used in that particular method, so that it wouldn't make sense to make it a class member, how could that be injected by the container?
Related
I have made a repository pattern app, having a repo and interface:
class UserRepository extends EloquentRepository implements UserRepositoryInterface
{
public function __construct()
{
$this->model = new User();
}
...
}
The repository and interfaces as well as extended class and its interface is registered in service provider and is called on app boot.
The questions I have are:
Is there a need to watch out for the order of registering? For example, should EloquentRepository class be loaded before the
repo, or does Laravel handle that on its own?
In case I inject UserRepositoryInterface in a controller, is the constructor method called automatically even though I didn't really new-up a class?
How long does the DI injection "live"? If I inject it in a page controller which calls some other controller and needs the same dependency, does the constructor call twice then, and operate separately in each controller?
Is there a difference if I call it like App::make() instead of DI?
Is there a need to watch out for the order of registering? For example, should EloquentRepository class be loaded before the repo, or does Laravel handle that on its own?
I don't quite understand where you would load EloquentRepository as (from the code posted) it seems you're only extending it. Which shouldn't be a problem.
In case I inject UserRepositoryInterface in a controller, is the constructor method called automatically even though I didn't really new-up a class?
Yes. Most of Laravel's main classes (controllers included) are loaded with DI in mind and the dependencies will be resolved automatically.
That being said, since you are injecting an interface and an interface by default cannot be initialized as a class, since it has no implementation - you need to bind an implementation to the interface first in order to use it.
How long does the DI injection "live"? If I inject it in a page controller which calls some other controller and needs the same dependency, does the constructor call twice then, and operate separately in each controller?
My understanding is that a new instance of the class will be created when the next controller is initialized. Unless you bind a class as a singleton.
Is there a difference if I call it like App::make() instead of DI?
App::make(some::class) will automatically resolve the dependencies of class some.
For example:
namespace App;
use App\Dependancy;
class Test
{
protected $d;
public function __construct(Dependancy $d)
{
$this->d = $d;
}
}
If you call this in the controller: $a = new \App\Test() you will get an error that \App\Test constructor expects class Dependency as first parameter.
But if you initialize it like this: $a = \App::make(\App\Test::class) the Dependency will be automatically resolved.
try to make the repositories abstract in the controllers and inject these through constructor.
like this here:
public function __construct(EloquentRepository $repository)
{
$this->repository = $repository;
}
And in the AppServiceProvider you can inject repositories you will need.
public function boot()
{
// provides any Repository in SomeController
$this->app->when(SomeController::class)
->needs(EloquentRepository::class)
->give(function (Application $app) {
return $app->make(SomeRepositoryInterface::class)
});
}
I'm currently working on my first PHP/Laravel 4 project, I'm developing on it a storage class to add Eloquent support to a 3rd party library.
My EloquentStorage class extends the AbstractStorage class from the library, and I make usage of most of AbstractStorage methods. Now that I want to add Eloquent support to my new EloquentStorage class, I faced the fact that PHP does not support multiple inheritance.
Is there a proper way to define an Eloquent model without extending it as:
class MyClass extends Eloquent {}
And, if not, how to deal with such situation when I need to extend 3rd party class and also extend Eloquent? Maybe using Laravel's IoC?
I think your model should extend from Eloquent, and instead be accessed through a repository. Your repository can have a $storage property, and would be responsible for calling the appropriate methods on your AbstractStorage implementation. Below is more pseudo- than actual code, but illustrates where you can plug in your implementation for an update operation.
class MyClass extends Eloquent
{
/* Normal Eloquent model implementation */
}
class MyRepository
{
protected $storage;
protected $myClass;
public function __construct(MyClass $myClass, AbstractStorage $storage)
{
$this->myClass = $myClass;
$this->storage = $storage;
}
public function update($id, $data)
{
// This is just an example operation, basically here's your chance to call
// the 3rd-party implementation. Here is pre-eloquent update, but can be
// after
$this->storage->update($id, $data);
// Use the empty Eloquent class property instance to obtain an instance of
// the requested model
$instance = $this->myClass->find($id);
// set instance properties
$instance->save();
// Example post-eloquent update
$this->storage->update($id, $data);
}
}
class MyStorage extends AbstractStorage { /* Your Storage Implementation */ }
$repo = new MyRepository(new MyClass, new MyStorage);
// Update item id 42's foo property
$repo->update(42, [ 'foo' => 'bar' ]);
A benefit to this approach is that the construction of the repository itself can be offloaded to the IoC through a Service Provider, and be injected inside of a controller / form validator etc, which means the execution will become automatic and hide the underlying complexity of the 3rd party library from the rest of the system (the repository helps keep your 3rd party abstraction from leaking).
Another benefit is that you don't need any special code in your eloquent models having anything to do with your completely unrelated 3rd party code. All of the logic is encapsulated in a single spot, and can even be shared amongst multiple models. Want to change 3rd party providers? Write a new implementation of AbstractStorage, update the service provider and you're done.
One other benefit is improved testability. Instead of statically utilizing an eloquent model directly (a la $user = User::find($id)) you would be manipulating your repository object instead ($user = $this->repo->find($id)). Since your repository can be trivially mocked and itself be tested (without also testing Eloquent or hitting the database), you can write integration tests on all of your controller routes and know the moment that changes to your codebase break your business rules.
for someone it might seem stupid, anyway I am new to the Symfony world and reading the documentation I came up with a doubt:
How does Symfony inject the DI Container instance inside of each Controller class which extends Controller in such a way that you can easily access a service from the container using the get($id) method??? Like here:
use Acme\HelloBundle\Newsletter\NewsletterManager;
// ...
public function sendNewsletterAction()
{
$mailer = $this->get('my_mailer');
$newsletter = new NewsletterManager($mailer);
// ...
}
I saw the source of the Controller class from GitHub, the Controller class in Symfony extends the abstract class ContainerAware which implements the ContainerAwareInterface interface, which has a method setContainer(ContainerInterface $container = null);
I can assume that the Controller itself attempts to set a reference to the Container instance calling setContainer inherited from the ContainerAware abstract class, but I am not sure whether I am right or not, but since I know that in Symfony2 every service (object with particular functionality) is under the supervision of the DI Container, who is responsible to inject the container to the Controller setContainer() setter? The Container itself? But how?
Thanks for the attention!
With controllers, Symfony2 uses the ControllerResolver class to determine if the Controller is an implementation of ContainerAwareInterface, and will inject the container that way. See this file (lines highlighted):
https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php#L79-L82
As for other services, you will have to manually inject the container into them via service definitions.
I have problem or misunderstanding of zf2's serviceLocator. Which is the right way to get a library/class with serviceLocator, which need configuration in the __construct method.
For example:
class PhpVersion extends AbstractTest implements TestInterface
{
public function __construct($expectedVersion, $operator = '>=')
{
}
}
The problem is that, the ServiceLocator's get method requires only one variable - Libraries name, without any place for configuration or dependency
P.S. My solution is with making a factory, but I think there should be a smarter way.
you can create your own service locator by extending the zends service locator class and customizing the get method to accepts arguments and pass them on to the constructor of that object.
So this is probably a rather simple question but I can't seems to find a very direct answer. I supposed to could keep reading the source until i figure it out but I was hoping to get a bit of understand of the process of doing so.
I understand IoC and Dependency injection, I am certainly not very experienced in either but I have a good understand of what they are trying to accomplish. So how does this Laravel instantiate to static instances? I know it uses PHP reflections but I'm still lost on the part of going from non-static to static methods. Also I know Laravel is not the only framework to implement such a design but its my preferred and most understood framework.
When you call a static method on a facade it is being handled by the magic __callStatic method on the Facade class. This method gets the underlying class that serves the facade and proxies the static call to it.
Let's look at an example facade:
<?php
class MyFacade extends Facade {
public function getFacadeAccessor() { return "MyFacade"; }
}
With this example when we make a call to the class in a static manner such as: MyFacade::doSomething() no static method exists on the class. The underlying Facade base class however contains a __callStatic method that will be called.
Facade Class Source Code
public static function __callStatic($method, $args)
{
$instance = static::resolveFacadeInstance(static::getFacadeAccessor());
switch (count($args))
{
case 0:
return $instance->$method();
// Snipped for brevity...
This method then looks up the underlying class to service the facade. If the getFacadeAccessor method on the facade returns a string then a matching entry in the application's IOC container is used (i.e. $app['MyFacade']). If we returned an object from the getFacadeAccessor method it would be used instead (i.e. public function getFacadeAccessor(){ return new MyClass(); }
Turns out that Laravel instantiate the classes under the hood! In this site, the guy makes you understanding a little more of the Laravel's core by using it to create a new facade. In the way, he explains how tit works!
It quite simple, actualy:
1 - You create a classe which extends from Laravel's Facade class with a single call like:
<?php namespace Name\Space;
use Illuminate\Support\Facades\Facade;
class MyClass extends Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'myclass'; }
}
... that's make Laravel look for $app['myclass']. So, the ServiceProvider will bind the myclass to MyClass (according to Laravel's conventions).
2 - For that, of course, you'll have to create a Service Provider.
The Service Provider will be responsible for returning the namespace, in this case Name\Space, for the class(es) that you may want to 'turn into facades'.
3 - You'll have to register your Service Provider in the providers array in the app/config/app.php.
Now, if you look with more attention, you'll realise that what Laravel does is just import a namespace and understanding it as it was a class, as well. Under the hood, it will call a instance, but for user (programmer) it will looks like a static call.
I hope I had been clear about it! Look the link I gave to you up there and HAVE FUN! :D