I want to create aliases in laravel like Auth so that i can use it in view just like
Auth::user().
For example, i want to return data from my setting table and want to use it like
Setting::method()->value. in view and use Setting in controllers.
What should i create for this Facades Or Service Providers? Provide me some procedures.
I tried using Service Providers but i am confused how to call database there.
This will be a long answer, using Laravel 5.4.
You need a service class (in this case, it's a concrete class behind the facade). I made it inside app/Services folder:
namespace App\Services;
use Illuminate\Database\DatabaseManager;
class Setting
{
protected $db;
public function __construct(DatabaseManager $db)
{
$this->db = $db;
}
public function method()
{
return;
}
}
As you see, I inject the database inside that concrete class. This is the magic of Laravel IoC. It will automatically resolve any dependency into your concrete class.
Next, create a facade. I made it inside app/Facades folder:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Setting extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'setting';
}
}
Notice the setting string returned from getFacadeAccessor. You need to register this service name later to the Container (IoC). The magic behind this facade is, it's automatically call (proxy) any static method to the instance method of concrete class, in this case you can call:
Service::method()
Register the service to the container. Inside your AppServiceProvider
namespace App\Providers;
use App\Services\Setting;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// ...
/**
* Register any application services.
*
* #return void
*/
public function register()
{
// ...
$this->app->singleton(Setting::class);
$this->app->alias(Setting::class, 'setting');
}
}
In this Service Provider, I declare that Setting service is a singleton service. Which means, you can use Setting service in another place without re-initialize class, in another words you are using the same instance across file. Last, I tell the container that Setting service has another alias, name setting, so Container can figure out which Concrete Class behind App/Facade/Setting.
For aliasing, as mentioned by apokryfos. Register your facade alias inside config/app.php, find the section aliases and add this line:
'aliases' => [
// ...
'Setting' => App\Facades\Setting::class,
],
After this you can call your facade like this:
use Setting;
Setting::method();
Hope this helps.
Related
I am trying to make my own custom Facade and register is with a custom service container and finally creating a custom alias for this facade.
I am not sure what part is not working, maybe there is a problem with the service container registering or maybe with the alias?
Let's start with my facade:
/**
*
* #see \App\Library\Facades\ViewWrapper\CustomView
*/
class CustomViewFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'customview';
}
}
My CustomView class with the logic and the show function
namespace App\Library\Facades\ViewWrapper;
...
class CustomView
{
public function show(...) { ... }
...
}
My CustomViewServiceProvider
namespace App\Providers;
...
class CustomViewServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(CustomViewFacade::class);
$this->app->alias(CustomViewFacade::class, 'customview');
}
}
How I register the provider in the config\app.php
App\Providers\CustomViewServiceProvider::class,
How I create the alias in the config\app.php
'CustomView' => App\Library\Facades\ViewWrapper\CustomViewFacade::class
In my controller I use the facade like this:
use CustomView;
...
public function show(ImageRequest $imagerequest)
{
return CustomView::show(...);
}
I get the following error in the controller:
Class 'CustomView' not found
What am I doing wrong here?
EDIT
After clearing config and composer autoload dump I get the following error:
Call to undefined method App\Library\Facades\ViewWrapper\CustomViewFacade::show()
I think you haven't quite clearly understood how Facades work. They are just an easy way to access your services without having to deal with dependency injection. I'm not a fan of this methodology, but here's how you do it properly.
You need to bind your actual service to the container, not the facade. The facade is almost just a symbolic link to your service within the container.
You need to import the actual service, not the facade. Laravel will automatically bind your dependency in the type-hinted variable, thanks to its behind the scenes magic.
Use:
use App\Library\Facades\ViewWrapper\CustomView;
(small note: your namespace here should be your service's namespace, be aware to not mix up the semantic between facade and service. The service contains the logic, the facade is just an accessor to a service that is already injected. This is important!!)
Instead of:
use CustomView;
It should solve the issue.
Also, I'd suggest you do define how the class should be constructed and injected in the Service Container by using a Closure in the bootstrap function.
class CustomViewServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(CustomView::class, function () {
return new CustomView(...);
);
}
}
Also, the alias function is not necessary in your case. It'd simply allow you to access the service by using the customview key in the Service Container.
Just define the Facade in your config/app.php file.
Another small suggestion: use PHP 7 class selectors instead of strings in your facade accessor definition. For example: CustomView::class intead of customview. It makes your code neater and easier to read.
Please run below command and check:
php artisan config:cache
php artisan cache:clear
Service containers / providers are probably much simpler concepts than I imagine, but after several hours of reading I still don't get it, entirely.
I have created a simple DateFormat class within app/Library. After creating an alias for it inside \config\app.php I can use it right away in any controllers or blade templates.
<?php namespace App\Library;
class DateFormat {
public static function getDate($timestamp){
// processing the timestamp
}
}
Did I just create a Service Container? If yes, do I need to create a Service Provider as well? Where come bindings into the picture?
I would really appreciate some light on the subject.
Thanks
No. What you created is simply an alias to your class. Services Providers are a way of binding a specific class, and often are used in conjuction with a Facade.
An alias is simply a convenient way to use a class without having to import the entire namespaced class every time.
For example, if you have a class \My\Very\Long\Class\Adapter, you could alias this in config/app.php:
// config/app.php
<?php
'aliases' => [
// a bunch of aliases
'MyAdapter' => My\Very\Long\Class\Adapter::class,
]
And now you can just do:
<?php
new MyAdapter();
...
instead of:
<?php
use My\Very\Long\Class\Adapter;
...
new Adapter();
...
A Service Provider is often used when you want to resolve a dependency, most commonly through injection. This can be helpful when the class you want to resolve requires parameters to passed into the constructor or has a common setup every time. You can perform all that setup in the Provider.
Here's a scenario:
You have an API that you want to interact with. We'll call it SuperApi. The docs for SuperAPI say that to create an instance of the SuperApi class, you have to do something like:
<?php
// Some method (a controller or something)
public function index()
{
$superApi = new \SuperApi\Connector($key, $secret);
return $superApi->getCustomers();
}
Now, every time you want to create an instance of this, you'll have to do the same setup (or abstract it to some class, but the fact remains that you need to pass a $key and $secret to the constructor).
If you were to create an alias for this Connector class, maybe it would be:
// config/app.php
<?php
'aliases' => [
// a bunch of aliases
'SuperApi' => SuperApi\Connector::class,
]
So with that alias, you can now do this:
<?php
// Some method (a controller or something)
public function index()
{
$superApi = new SuperApi($key, $secret);
return $superApi->getCustomers();
}
But you see, that even with the alias, you still need to pass the $key and $secret.
This is where a Service Provider can help.
// app/Providers/SuperApiProvider.php
<?php
namespace App\Providers;
use SuperApi\Connector;
use Illuminate\Support\ServiceProvider;
class SuperApiProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function register()
{
$this->app->bind('superApiConnector', function ($app) {
return new ApiConnector($app['config']->get('super-api.key'), $app['config']->get('super-api.secret'));
});
}
}
// app/Providers/SuperApi.php (the Facade)
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Facade;
class SuperApi extends Facade
{
protected static function getFacadeAccessor()
{
return 'superApiConnector';
}
}
// config/super-api.config
<?php
return [
'key' => env('SUPER_API_KEY'),
'secret' => env('SUPER_API_SECRET'),
];
// config/app.php
<?php
'providers' => [
// a bunch of providers
App\Providers\SuperApiProvider::class,
]
See that the string you bind to in the provider ('superApiConnector') is the same as what you return from the facade and the class name of the facade is how you'll actually call the binded class, in this case SuperApi.
Now, when you want to user the SuperApi\Connector class, you can do this:
<?php
// Some method (a controller or something)
public function index()
{
return SuperApi::getCustomers();
}
And as I said above, where a provider really comes in handy is when you want to inject it and have Laravel's IoC Container automatically resolve the injected class:
<?php
// Some method (a controller or something)
public function index(SuperApi $api)
{
return $api->getCustomers();
}
To be clear, you do NOT need a Service Provider to take advantage of dependency injection. As long as the class can be resolved by the application it can be injected. That means whatever arguments the constructor of the class you're injecting takes need to also be auto-resolvable.
I am trying to inject a Manager class into toe Service Container of Lumen. My goal is to have a single instance of LogManager which is available in the whole application via app(LogManager::class).
Everytime i try to access this shortcut i get the following exeption:
[2017-03-23 16:42:51] lumen.ERROR: ReflectionException: Class LogManager does not
exist in /vendor/illuminate/container/Container.php:681
LogManager.php (i placed that class in the same location where my models are (app/LogManager.php))
<?php
namespace App;
use App\LogEntry;
class LogManager
{
...
}
AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\LogManager;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(LogManager::class, function ($app) {
return new LogManager();
});
}
}
I uncommented the line $app->register(App\Providers\AppServiceProvider::class); in bootstrap/app.php
I think that i missed something with the correct namespacing or placement of the classes espaccially LogManager. Maybe some one is willing to give me a hint?
If you need some more informations just give me a hint!
Your class and your service provider look fine. However, wherever you're calling app(LogManager::class) also needs to know the fully qualified name of the class.
Either make sure you have use App\LogManager at the top of the file, or change your call to app(\App\LogManager::class).
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 have a class called Messaging and I created a facade to using it like
Messaging::getConversationMessages($conv_id, $user_id);
I have followed all the instructions in this link below
How do I create a facade class with Laravel?
This is my MessagingServiceProvider calss below which does the binding
<?php
use Illuminate\Support\ServiceProvider;
class MessagingServiceProvider extends ServiceProvider {
/**
* Register the service provider.
*
* #return void
*/
public function register() {
App::bind('messaging', function()
{
return new \Messaging\Messaging;
}
);
}
}
Below is my facade class that I created for me to use it in the way I wanted to
<?php
use Illuminate\Support\Facades\Facade;
class Messaging extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'messaging'; }
}
I have placed my MessagingServiceProvider.php inside a folder called serviceproviders inside app folder, and placed the messaging.php(the file containing the facade class) inside a folder called facade in the app folder and added them to auto load.
Below is the model class for the facade
<?php
namespace Messaging;
use Eloquent; // if you're extending Eloquent
class Messaging extends Eloquent {
...
}
After doing all this still I am getting an error "Non-static method Messaging\Messaging::getConversationMessages() should not be called statically, assuming $this from incompatible context"
You are not using your Facade. Try to namespace it and use a different name:
<?php namespace Messaging;
use Illuminate\Support\Facades\Facade;
class MessagingFacade extends Facade
{
...
}
Then you
composer dumpautoload
And try to use it this way:
Messaging\MessagingFacade::getConversationMessages()
If it works for you, you create an alias for it in app/config/app.php.
'Messaging' => 'Messaging\MessagingFacade',
And you should be able to use it as:
Messaging::getConversationMessages()
About namespaced classes, every time you need to a class from another namespace, you need to go root:
\DB::whatever();