For the most part I get the idea behind a facade and how the details of instantiating the object are hidden behind the static calls.
So if we take a look at this straight forward example here: Example
We see some code like this for the facade, which at this point just sets up some sort of Alias. At this point it seems the facade still knows nothing about the Superuser class.
class SuperuserFacade extends Facade
{
protected static function getFacadeAccessor() {
return 'MyAlias';
}
}
The logic is glued by the service provider here it seems:
class SuperuserServiceProvider extends ServiceProvider
{
public function register() {
App::bind('MyAlias', function(){
return new Superuser;
});
}
}
But it just binds the class the facade alias MyAlias. Why bother with that facade class and two separate files, can't we just do all this logic right in the service provider? Or alternatively in the facade provider having it just return the Superuser class?
It seems like we have the facade not really doing anything and then another file telling that facade what to do. Why have these concerns been separated?
The facade class is a simple proxy -- it directs any calls to the facade class to the root class, which is retrieved from the IoC container via the facade accessor (in this case, MyAlias).
I call Superuser::whoami()
The Superuser facade goes "okay, I need to find the class that I'm a proxy for."
The facade calls getFacadeAccessor() to determine what IoC binding to retrieve and subsequently call.
The facade requests the MyAlias key from the IoC container. The container then returns an existing class if it has been built already, or it runs its bound closure which generates a new Superuser instance.
Now that the facade knows what class it's passing calls to, it forwards the whoami() method call to the newly-returned Superuser instance, which then returns whatever it is designed to.
The service provider's register() method simply registers a binding to the IoC container, to be retrieved later by whatever needs it. That's it. MyAlias is a simple string key used to look up that binding.
The facade allows you to use an IoC-bound class as if it were a static class.
I recommend reading other articles about the concept, because the article you linked is both inaccurate and not very informational about why things work. Here is a better article by Chris Fidao.
Related
When implementing a service, base on Laravel's documentation, a service should be registered on the service provider so it could be injected into a class via dependency injection. But I do notice that even though I do not create a service provider as such, I could still inject that class.
If so, what's the use of the service provider class if I could just directly inject it?
Here's some sample:
use App\Http\Service\MailerService;
class MailerServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(MailerService::class, function($app) {
return new MailerService();
});
}
}
class MailerService
{
public function send()
{
// do something here
}
}
class MailerController
{
public function sendEmail(MailerService $mailerService)
{
$mailerService->send();
}
}
Good question!
Laravel's Container has the ability to "auto-resolve" dependencies. If you ask the Container to create an instance of a class and there is no specific binding definition for the class, the Container will attempt to find the class, use PHP's Reflection functionality to check its dependencies, and recursively build the dependency tree until it's finished or runs into a problem.
The use-cases and benefits of using a Service Provider even with this capability:
You want to bind an Interface to the container, and have it resolved to a concrete class. Interfaces can't be instantiated directly, so you have to tell the container what concrete class to use.
Your binding has a non-class dependency, such as a string config value. These can't be auto-resolved.
Auto-wiring is slow. It has to use Reflection for every class that doesn't have a service provider binding.
You want to include some sort of logic in the resolution process.
Might be a couple other use cases or benefits I'm forgetting, but those should be a good start!
As for the title I've googled about two hours searching for a efficient answer and read repeatedly the official documentation, but without any step further, considering I'm relatively new to the framework. The doubt arise while searching for a correct way to share some code between controllers and i stumbled in service providers, so:
I've created say a MyCustomServiceProvider;
I've added it to the providers and aliases arrays within the app.php file;
finally I've created a custom helpers class and registered it like:
class MyCustomServiceProvider extends ServiceProvider
{
public function boot()
{
//
}
public function register()
{
$this->app->bind('App\Helpers\Commander', function(){
return new Commander();
});
}
}
So far, however, if I use that custom class within a controller I necessarily need to add the path to it through the use statement:
use App\Helpers\Commander;
otherwise I get a nice class not found exception and obviously my controller does not his job.
I suspect there's something which escapes to me on service providers! :-)
So far, however, if I use that custom class within a controller I
necessarily need to add the path to it through the use statement:
`use App\Helpers\Commander;`
otherwise I get a nice class not found
exception and obviously my controller does not his job.
Yes, that's how it works. If you don't want to use the full name, you can use a Facade instead.
Create the Facade class like this:
class Commander extends Facade
{
protected static function getFacadeAccessor() { return 'commander'; }
}
register the service:
$this->app->singleton('commander', function ($app) {
return new Commander();
});
add the alias to your config/app.php:
'aliases' => [
//...
'Commander' => Path\To\Facades\Commander::class,
//...
],
and use it like a Facade:
\Commander::doStuff();
On why your code still works, even when you remove the bind:
When you type-hint a parameter to a function, and Laravel does not know about the type you want (through binding), Laravel will do its best to create that class for you, if it is possible. So even though you didn't bind the class, Laravel will happily create a instance of that class for you. Where you actually need the binding is when you use interfaces. Usually, you'd not type-hint specific classes but a interface. But Laravel can not create a instance of an interface and pass it to you, so Laravel needs to know how it can construct a class which implements the interface you need. In this case, you'd bind the class (or the closure which creates the class) to the interface.
I'm just starting with laravel and want to understand this...
Lets say we have a class in our application:
namespace App\Tests;
class MyTest{
public function sayHello($name){
echo "Hello, $name!";
}
public static function anotherTest(){
echo "another test...";
}
}
What is the advantage of creating a facade and a service provider over just using it as
use App\Tests\MyTest;
//... controller declarations here ....
public function someaction(){
$mt = new MyTest();
$mt->sayHello('John');
//or
MyTest::anotherTest();
}
//... etc...
A Facade in Laravel is only a convenient way to get an object from the Service Container and call a method on it.
So calling a Facade like this :
//access session using a Facade
$value = Session::get('key');
Is like doing:
//access session directly from the Service Container
$value = $app->make('session')->get('key');
As the Facade resolves the session key out of the Service Container and call the method get on it
Once understood what a Facade does, you should understand what is the Service container and what are the benefits of using it
The Service Container in Laravel cloud be a Dependency Injection Container and a Registry for the application
The advantages of using a Service Container over creating manually your objects are stated in one of my previous answers and in the doc page, but briefly:
Capacity to manage class dependencies on object instantation
Binding of interfaces to concrete classes, so that when a interface is requested in your program, a concrete class is instantiated automatically by the service container. Changing the concrete class on the binding, will change the concrete objects instantiated through all your app
Possibility to create single intances and get them back later (Singleton)
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
So in trying to implement IoC, DI, etc. in Laravel 4, I've hit a wall. Either I'm misunderstanding something or doing something horribly wrong, not sure which...
So I have a class Person ("business class", not a model or library):
namespace Entities;
use Interfaces\Person as PersonInterface;
class Person implements PersonInterface {...}
a factory which has:
use Interfaces\Person;
...
App::singleton('user', function($app) {
...
$user_object = new Person();
...
});
and in the aliases array:
'Interfaces\Person' => 'Entities\Person'
Problem is that doesn't work because the Person class can't implement its interface because the interface is bound back to the Person class:
Entities\Person cannot implement Entities\Person - it is not an interface
I seem to be caught in a catch 22 of using IoC and interfaces in the application preventing the classes from actually instantiating.
Don't know if it's relevant, but putting
App::bind('Interfaces\Person','Entities\Person');
in the routes.php files doesn't seem to do anything (but putting it in the aliases array does). Surely I'm doing something wrong here. Any ideas?
Maybe I can help. To bind an interface to the IoC, you want to have an interface and an implementation of the interface. It looks like you have that step correct. You also want to create a service provider. More info on that here: http://laravel.com/docs/ioc#service-providers
Remove any bindings you have from the routes.php file. The service provider is what binds the route, and config/app.php registers it in the IoC as described more fully below.
Your service provider might look something like this:
File Name: ServiceProviders/PersonServiceProvider.php
<?php namespace ServiceProviders;
use Illuminate\Support\ServiceProvider;
use Entities\Person;
class PersonServiceProvider extends ServiceProvider {
/**
* Register the binding.
*
* #return void
*/
public function register()
{
$this->app->bind('Interfaces\Person', function()
{
return new Person();
});
}
}
Once the service provider is created, register it in the config/app.php file as follows:
'ServiceProviders\PersonServiceProvider',
Don't use the aliases. This is used for registering the aliases of facades, which is not what you're attempting to do here if I understand your question correctly.
Lastly, to follow the generally accepted Laravel naming conventions, I'd suggest naming the interface file "PersonInterface.php" and its interface "interface PersonInterface." Similarly, the implementation file might be called "EloquentPerson.php" and the "class EloquentPerson extends PersonInterface". This assumes you're using Eloquent. It's similar to what you have, but I think the class and interface names could make it more readable with those small tweaks.