I am reading through the Laravel documentation to try and achieve a deeper understanding of the framework but I am having a bit of trouble with facades. I think I understand what they are, they are mostly used for convenience when accessing Laravels core.
My confusion is with this topic:
How does a facade work? (Specifically related to the getFacadeAccessor() method. Is this magic?)
Facades is another way to use classes without manually creating an object. They are just a shortcut to classes registered by Laravel container.
For example, this:
DB::
Makes absolutely the same as if you'd use the container:
app('db')->
So, DB:: facade is just a shortcut for app('db')->.
And yes, facades use the magic method __callStatic() which resolves an instance of a class and executes given method:
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
Related
I know DI, Solid Principles, factory patterns, adapter pattern and many more maybe. Now let's say I am creating a laravel application and it's gonna be huge. Let's say I have a postscontroller which is resource and has CRUD methods. Now Let's say in that controller's functions, I have a post Model and use it to retrieve data from database. I have a store function where I am creating new Post() and then put it into database.
1) Is it a good practice to have Post model directly in PostController's function and use new Post() also? What is bad in it? I know that this way I am not using dependency injection and patterns, but still why is it bad? As you know , I can still mock the object without dependency injection since laravel has so many amazing testing features. Then why is it that bad to write new keyword in controller's functions and also use Post model directly?
To give you one answer to your question. There is this "Slim controllers, fat models" concept. I used to defer the object creation to the object itself by Named Constructers.
class UserController
{
public function create(UserCreateRequest $request)
{
$user = User::createFromRequest($request);
// do anything else
}
}
class User
{
public static function createFromRequest(UserCreateRequest $request)
{
$user = new User;
$user->first_name = $request->first_name;
// ...
$user->save();
return $user;
}
}
With this you can have more different constructors like User::createAdmin and its testable. You just need to mock the Request.
I usually use parameters like this:
public function test($parameter)
{
echo 'Parameter value: ' . $parameter;
}
While looking at laravel service container I see this code.
public function __construct(UserRepository $users)
{
$this->users = $users;
}
According to the documentation it uses reflection.But i dont understand.
I dont know how the parameter UserRepository $users works. Is that an alias or something?
This is called type-hinting and is used to inject dependencies in a constructor or to validate the right type of argument is passed to a function. The injection simply means that if the class is called with the make method, Laravel will automatically provide an instance of the class required by your constructor.
For example if you have a function public function something(string $something) it would throw an error if any other type than a String is passed to this function, making sure the right data is used.
From the laravel documentation:
Alternatively, and importantly, you may "type-hint" the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, queue jobs, middleware, and more. In practice, this is how most of your objects should be resolved by the container.
For example, you may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class:
Laravel has a great service container and it makes all dependency injections, so you don't need to pass a class a parameter, laravel do it for you.
without container you have to pass this parameter
class A {
public $foo;
public function __construct (Foo $foo){
$this->foo
}
$classA = new A((new Foo))
When laravel encounter with these classes, it resolves them.
Also you can define manually these classes using singleton() or bind() methods
$this->app->singleton('FooBar', function($app)
{
return new FooBar($app['SomethingElse']);
});
Or you may use interfaces. You can bind implemented class for to the interface and laravel when encounter with that interfance, it will resolve as you wish
$this->app->bind('App\ICacheManager', 'App\RedisManager');
public $redis;
public function __contruct(ICacheManager $redis){
$this->redis = $redis;
}
for more further check out laravel service container
I am confused as to how to use the cache in Laravel. I can either use the Cache facade and do something like …
use Cache;
public function someMethod()
{
Cache::remember('users', 60 , function() {
return DB::table('users')->get();
});
}
Or I could use something like this …
use Illuminate\Contracts\Cache\Repository;
protected $cache;
public function __construct(Repository $repository)
{
$this->cache = $repository;
}
public function someMethod()
{
$this->cache->remember('users', 60 , function() {
return DB::table('users')->get();
});
}
Both will implement the same method remember from vendor/laravel/framework/src/Illuminate/Cache/Repository.php
Repository class which implements vendor/laravel/framework/src/Illuminate/Contracts/Cache/Repository.php which I have included in the second method.
As per Laravel docs:
The Illuminate\Contracts\Cache\Factory and Illuminate\Contracts\Cache\Repository contracts provide access to Laravel's cache services. The Factory contract provides access to all cache drivers defined for your application. The Repository contract is typically an implementation of the default cache driver for your application as specified by your cache configuration file.
However, you may also use the Cache facade, which is what we will use throughout this documentation. The Cache facade provides convenient, terse access to the underlying implementations of the Laravel cache contracts.
So can I conclude that both the approach are same. The Cache Facade provides me a cleaner implementation, that's it.
You would get the same result in your application. It's the same but not the same.
In your second approach you are using dependency injection. Which makes it easier to write tests for your class. This way you get a better maintainable application.
Have a deeper look at dependency injection. Here is a nice article: Dependency Injection with Laravel’s IoC.
I'm kind of confused of how to use contracts. I think that's because I haven't used unit-testing so that it's not obvious for me how contracts work.
Let's have look at this code:
use Illuminate\Contracts\Auth\Guard;
...
public function __construct(Guard $auth)
{
$this->auth = $auth;
$this->middleware('guest', ['except' => 'getLogout']);
}
public function postRegister(RegisterRequest $request)
{
// Registration form is valid, create user...
$this->auth->login($user);
return redirect('/');
}
So how do I know which class implements login method of contract in this line: $this->auth->login($user) ? And how can I change the class if I want to use my own?
In laravel 4 I wrote Auth::user() as an example and I used it everywhere in any controller and it worked. Now I should inject a contract inside a controller method and use it like $auth->user?
Also, If I get it right, contracts are used for making an abstraction. Okay, so, if I want to build a new interface for my own class and then have multiple classes that implement my interface, where should I write the code? I can't think of an example but lets imagine I need to implement an interface for enabling/disabling a lamp, and I have two methods like on() and off() and I have multiple ways to do that. Do I need to create new contract for that?
I hope I can make this a bit clearer for you...
Ad.1. You can check default binding at /vendor/laravel/framework/src/Illuminate/Foundation/Application.php (method registerCoreContainerAliases around line 792). If you want to create your own class or extend existing I recommend looking at How to extend Laravel's Auth Guard class? or http://laravel.com/docs/master/extending (this one is more about Laravel 4.x but might give you an idea).
Ad.2. Actually you can still use Auth::user() but I inject a contract in constructor or a method and call it like $this->auth->user or $auth->user.
Ad.3. I have a /app/Repositories folder where I put my interfaces and implementations, so to follow your example I would create subfolder Lamp and I would create LampInterface with on() and off() methods, then I would create something like Lamp.php that implements LampInterface. Next I would create a service provider in /app/Providers, like LampServiceProvider.php with binding:
namespace Apps\Providers;
use Illuminate\Support\ServiceProvider;
class LampServiceProvider extends ServiceProvider {
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(
'App\Repositories\Lamp\LampInterface',
'App\Repositories\Lamp\Lamp'
);
}
}
After that I would register new service provider in /app/config/app.php and finally I can inject my interface like:
public function switchLampOn(App\Repository\Lamp\LampInterface $lamp)
{
$lamp->on();
}
Take a look to that code
<?php
namespace Sestante\SestanteBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sestante\SestanteBundle\Model\StrutturaManager;
class MainController extends Controller
{
public function indexAction(Request $request)
{
return $this->render('SestanteSestanteBundle:Main:index.html.twig');
}
public function showLodgingsAction(Request $request)
{
$repo = $this->getDoctrine()->getRepository('SestanteSestanteBundle:Struttura');
$usr = $this->get('security.context')->getToken()->getUser();
$usrId = $usr->getId();
$sm = new StrutturaManager($repo);
$lodgingList = $sm->retrieveLodgingsFromUser($usrId);
return $this->render('SestanteSestanteBundle:Main:showLodgings.html.twig',array('lodgingList' => $lodgingList));
}
}
This is a controller for an application that I've been writing.
Take a look to showLodgingsAction. I've tryied to place all business logic into a model (StrutturaManager) that with a repository (that I've passed directly from controller because, as far I know, they're available only here or via D.I.) query my db, do some elaboration and return a list that I'll render onto a template.
First question: Is this "code separation" good, or exists a better way for do what I'm trying to do?
Second question: suppose that, now, I want to use an object of StrutturaManager type into indexAction. Remember that mine object want a repository. So, have I to declare again, and again, and again, all my object for every controller's action where I want to use them? I suppose that must exist a smarter method but, at the moment, I don't understand which.
Define StrutturaManager as a service and inject the EntityManager into it. This way the manager will have access to repositories you need and controllers won't know about Doctrine nor repositories — which is a good practice.