I'm working with Laravel 5.8 and it's an Online Store project written by other programmers.
Basically I have faced something weird that never seen before.
Let's say we have this at a Controller method:
$payment = CourseRegistrationFacade::insertCourseRegisterInformation($courseId,$date,$memberId,$userId);
And then we goto the CourseRegistrationFacade and it goes like this:
class CourseRegistrationFacade extends BaseFacade
{
}
So the whole class is empty but it extends another Facade which is BaseFacade and it goes like this:
class BaseFacade extends Facade
{
protected static function getFacadeAccessor()
{
return static::class;
}
protected static function shouldProxyTo($class)
{
app()->bind(self::getFacadeAccessor(), $class)
}
}
And that's it !
I don't really know where the heal is insertCourseRegisterInformation !!
So if you know how this Facade works, please let me know...
Here is the full code of BaseFacade.php:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class BaseFacade extends Facade
{
protected static function getFacadeAccessor()
{
return static::class;
}
public static function shouldProxyTo($class)
{
app()->bind(self::getFacadeAccessor(), $class);
}
}
Search in the code for:
CourseRegistrationFacade::shouldProxyTo(
Most likely in the service provider that line is somewhere registering that facade to some concrete implementation of a class. Then check the contents of the class (the argument passed to shouldProxyTo).
Inside that class there should be a method called insertCourseRegisterInformation.
The way facades work is they resolve the class out of the container and then call the method you call statically.
So for example, let's say you have a UserService.php with a method register() and that class is mapped to a UserServiceFacade.php. When you do UserServiceFacade::register(), __callStatic will get the facade accessor (actual class) from the container, then call the register() method of that class.
You can understand better by inspecting __callStatic inside Facade.php.
Essentially UserServiceFacade::register() is the same as doing:
$userService = app()->make(UserService::class);
$userService->register()
By using the facade you can hide the concrete implementation and could possibly switch it to something else in the future by just changing it in a single place.
I think there must be a Provider exists for that Facade which is initializing its associated class and insertCourseRegisterInformation method definition must be declared in it. Please find that provider and then you'll find its associated class from that Provider code. I think you can find all registered providers from config/app.php
These reference articles might help you.
Reference 1:
https://grafxflow.co.uk/blog/mvc/adding-global-custom-class-facades-laravel-5
Reference 2: http://www.expertphp.in/article/how-to-create-custom-facade-in-laravel-52
Related
So I have the following class that's a facade:
namespace App\Helpers;
use App\Http\Requests\HomepageRequest;
class Params {
public function __construct(HomepageRequest $request) {
}
Then I have the ParamsServiceProvider class which instantiates the facade class on script startup:
public function register()
{
//
App::bind('params', function() {
return new Params();
});
}
edit: here is the actual facade for the Params class
use Illuminate\Support\Facades\Facade;
class Params extends Facade {
protected static function getFacadeAccessor() {
return 'params';
}
}
This all works fine, the class is instantiated properly, however, it doesn't seem to inject the request object in the constructor like it would in a controller class. Is there a way to inject the request into a facade class like you would in a controller? With the current code, I get the following error:
Too few arguments to function App\Helpers\Params::__construct(), 0
passed in /var/www/v4api/html/app/Providers/ParamsServiceProvider.php
on line 21 and exactly 1 expected
I want to avoid having to manually pass the request input into the class and just have it automatically be injected in the constructor. Any help that you guys can give would be appreciated!
Looks like this worked out:
In the ParamsServiceProvider, instead of using App::bind to instantiate the Params class, do this instead:
public function register()
{
App::alias(Params::class, 'params');
}
then the request object will be injected properly into the facade.
The class you've posted isn't actually a Facade - it's just a regular class.
Because you've type-hinted it's dependencies you don't need to tell Laravel how to create an instance of it - it can work it out all by itself.
You can either inject that class into a controller method (where Laravel will new it up for you), or you can call app(App\Helpers\Params::class) and it will return a new instance of the class for you.
Read more on creating facade classes if you want to create an actual facade. Alternatively you can create a realtime facade - where you instead reference Facades\App\Helpers\Params::foo() and Laravel will let you use the method as if you had an instance of that class.
You have a number options here - point the facade straight to the underlying class and let Laravel work out how to build it, explicitly bind it to the container, or use a realtime facade. Let's go through each.
class Params extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Helpers\Params::class;
}
}
This option points the facade straight to the class you intend it to be a facade for and Laravel will work out the rest.
Alternatively, you can keep it as params and instead fix the binding in the container.
The first example use's Laravel's container to make an instance of the class and return it. Laravel can automatically reflect the class and inject it's dependencies.
App::bind('params', function ($app) {
return $app->make(Params::class);
});
The second example explicitly builds the instance the way you desire, which is just additional code for you to maintain.
App::bind('params', function() {
return new Params(new HomepageRequest);
});
The final option - as mentioned in the earlier answer - is to use a realtime facade and skip the manual binding entirely. You can learn more about realtime facades in the docs.
This is a follow-up to my previous question about resolving the diamond issue in php.
As I state in that question, I resolve my problem by using traits and passing the instance of the class to the method of the trait. Such as:
trait SecurityTrait
{
public function beforeExecuteRouteTrait($controller, Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
return $this->beforeExecuteRouteTrait($this, $dispatcher);
}
}
However, I am still uncomfortable with this as I don't think this is how traits are really supposed to be used. In my reading I haven't found any way in which to access class members in traits (make $this inside a trait refer to the class using it). Is this possible? Or is there another way to implement a similar behaviour?
After reading some of the answers...
Previously I thought I had received errors when using $this->... inside the trait and this led me to believe the trait could not access anything to do with the underlying class. After reading the answers I tried altering my code to use $this->... inside a trait again and it works - which means a typo several weeks ago has given me far too much headache...
The example given previously now looks like this
trait SecurityTrait
{
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
}
Much cleaner and more easily understandable but provides the same functionality.
If you use a trait inside a class then that trait has full access to all class's members and vice versa - you can call private trait methods from the class itself.
Think of traits as code that literally gets copy/pasted into the class body.
For example:
trait Helper
{
public function getName()
{
return $this->name;
}
private function getClassName()
{
return get_class($this);
}
}
class Example
{
use Helper;
private $name = 'example';
public function callPrivateMethod()
{
// call a private method on a trait
return $this->getClassName();
}
}
$e = new Example();
print $e->getName(); // results in "example"
print $e->callPrivateMethod(); // results in "Example"
In my view referencing classes in traits is not the best way to use them but there's nothing stopping anyone from doing it.
No, that's exactly what Traits are for. Your class already extends a class so you can't inherit the methods and variables of any other classes.
Think of a Trait like copy/paste for code execution. When a class includes a Trait, it's just as if you had written all that code into the class itself.
I have the following problem in my laravel 5 project. I have a service provider for form macros named MacroServiceProvider.php. Some macros should receive data from the database, I'm currently using the model and getting the results with eloquent but I want to use repositories instead, so I created my repository but I can't inject this directly to my service provider.
I want something like this:
...
public function register(MyRepoInterface $repo)
{
$registers = $repo->findAll();
Form::macro...
}
...
How can I do this?
Thanks.
I don't think you can do what are you asking, and I think you are misunderstanding the way providers work and what they are intended for.
In providers, you usually say what are the bindings among interfaces and implementations, so that when you do dependency injection in your application code, it works. I'm pretty sure they are not intended for doing real stuff.
For what you say about your code, I imagine something like this:
a repository interface (MyRepoInterface) with a real implementation using Eloquent (say EloquentMyRepo)
a facade, say Macro, so that you can do Macro::myMacro1(), Macro::myMacro2(), etc.
the methods myMacro1(), myMacro2(), etc, use the repository to get some data from the db and then call some methods from the Form facade
If I'm right, then I suggest something like this.
Repository
Define the interface in the file MyRepoInterface.php with
interface MyRepoInterface
{
public function findAll();
// ... your other repo methods
}
and an implementation EloquentMyRepo.php with
class EloquentMyRepo implements MyRepoInterface
{
public function findAll()
{
// ... do what you need
}
}
Facade
Define a facade file MacroFacade.php with this
use Illuminate\Support\Facades\Facade;
class MacroFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'macro';
}
}
Service class
Define your macro service class in a file MacroService.php, where you can use dependency injection and access your repository. In this class you define your myMacro1()... methods.
class MacroService
{
protected $myRepo;
public function __construct(MyRepoInterface $myRepo)
{
$this->myRepo = $myRepo;
}
public function myMacro1()
{
// access the repo
$items = $this->myRepo->findAll();
// ... do something with $items and finally return a string
return Form::macro(...);
}
public function myMacro2($arg1, $arg2)
{
// ... use the parameters to do something else
}
}
Bindings
In your Providers/AppServiceProvider.php file, go to the register() method and add
public function register()
{
// ...
$this->app->bind('App\MyRepoInterface', 'App\EloquentMyRepo');
// ...
}
so that when you use MyRepoInterface in dependency injection, Laravel knows it has to use an instance of EloquentMyRepo.
Now, let's create a service provider for your macro service. Create a file Providers/MacroServiceProvider.php and put in it
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class MacroServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('macro', 'App\MacroService');
}
}
Now, when we need the facade that is registered as macro, an instance of MacroService is used.
Configuration
We finally need some changes to the configuration. Open the config/app.php file, add the new provider
...
'providers' => [
...
'App\Providers\AppServiceProvider',
...
'App\Providers\MacroServiceProvider',
],
(note that the MacroServiceProvider is declared after the AppServiceProvider.)
Add the alias for the facade:
'aliases' => [
...
'Macro' => 'App\MacroFacade',
],
Done!
What happens
Let's suppose you call
...
Macro::myMacro1();
...
in your code. How the right method is called?
Macro is an alias handled by the MacroFacade class
The facade is registered in the IoC with the macro name by the getFacadeAccessor() method of MacroFacade
The MacroServiceProvider registered the MacroService class as an implementation for macro
An instance of MacroService must be created, but it has MyRepoInterface as dependency
The AppServiceProvider said Laravel to use EloquentMyRepo when MyRepoInterfice is required
So an instance of EloquentMyRepo is created and it is used to create an instance of MacroService
Macro has been resolved to an instance of MacroService
Laravel calls the myMacro1() method of that instance
I hope this can clarify a bit what happens.
I am attempting to create a facade within laravel 4.1. I have created the facade, service provider and the class, to no avail. I followed numerous "how to's" including the advanced video for custom facades on Laracasts. No matter how many times I try, I end up with the exception of Non-static method Custom\Helpers\Helper::doSomething() should not be called statically
Here is my code...
HelpersServiceProvider.php
<?php namespace Custom\Helpers;
use Illuminate\Support\ServiceProvider;
class HelpersServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('trial','Custom\Helpers\Helper');
}
}
HelpersFacade.php
<?php namespace Custom\Facades;
use Illuminate\Support\Facades\Facade;
class Helper extends Facade {
protected static function getFacadeAccessor()
{
return 'trial';
}
}
Helpers.php
<?php namespace Custom\Helpers;
class Helper {
public function doSomething()
{
return 'Hello';
}
}
I add the service provider to my app.php file and register the facade alias
'Custom\Helpers\HelpersServiceProvider',
'Helper' => 'Custom\Facades\Helper',
Then when I try to access it via a Static call (yes, I know it's not really static) or via the service provider directly I get the exception error.
Scratching my head on this one...
It looks like you have an incorrectly named class (or file):
HelpersFacade.php
class Helper extends Facade {
Additionally, your Helper class is in Helpers.php. Those need to match, also.
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