I've created provider class and put it into app/models/Providers directory:
<?php
//app/models/Providers/NiceUrlServiceProvider.php
namespace Providers;
use Illuminate\Support\ServiceProvider;
class NiceUrlServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('niceurl', function()
{
return new \Utils\NiceUrl();
});
}
}
and facade class in app/models/Facades directory:
<?php
// app/models/Facades/NiceUrl.php
namespace Facades;
use Illuminate\Support\Facades\Facade;
class NiceUrl extends Facade {
protected static function getFacadeAccessor() { return 'niceurl'; }
}
I have also edited app/config/app.php and added this as provider:
'providers' => array(
// default ones
'Providers\NiceUrlServiceProvider',
),
and added alias to Facade:
'aliases' => array(
// default ones
'NiceUrl' => 'Facades\NiceUrl',
),
When I try to run my app I get:
Class 'Providers\NiceUrlServiceProvider' not found
*
* #param \Illuminate\Foundation\Application $app
* #param string $provider
* #return \Illuminate\Support\ServiceProvider
*/
public function createProvider(Application $app, $provider)
{
return new $provider($app); // this line marked as causing problem
}
However if I comment the line where I add my provider and in public/index.php put this code at the end of file:
$x = new \Providers\NiceUrlServiceProvider($app);
$x->register();
echo NiceUrl::create('some thing');
it works without a problem, so it does not seem to be a problem with autoloading.
Also if I register provider manually using:
$app->register('Providers\NiceUrlServiceProvider');
echo NiceUrl::create('some thing');
at the end of public/index.php it is working without a problem.
Questions:
How to make it work?
Where should I hold providers/facades files? Here I put them into model directory into separate folders.
The solution was quite simple but it was not obvious at all. After adding your provider you need to run:
composer dump-autoload
in your main project directory. It will generate new autoload_classmap.php file that will include your service provider. composer-update in this case also will work but it's not neccessary and it will take much more time. It's quite strange that it's necessary when you put provider into app/config/app.php and it's not necessary when you manually register provider but this is how it works.
The solution was quite simple but it was not obvious at all. After adding your provider you need to run:
composer dump-autoload
when you add some folder or other classes which is not in your composer.json autoload you would add it then run the above command.
Related
I just created a simple Laravel CLI package in Laravel 8. My custom command doesn't appear in php artisan list and the provider needs to register manually into config/app.php to make it work. As far as I know, we don't need to register the provider manually in Laravel 5.5+.
Here is my provider source code:
<?php
namespace Robyfirnandoyusuf\BadOmen;
use Illuminate\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
use Robyfirnandoyusuf\BadOmen\Commands\Migrate;
class BadOmenServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->commands([
Migrate::class
]);
}
}
public function register()
{
}
}
and this is the structure of the directories:
Anyone have solution for this problem?
Solved, by adding providers property in the package's composer.json file, with a value of [Robyfirnandoyusuf\BadOmen\BadOmenServiceProvider::class]
. I want to implement this package in my laravel. Package link is below:-
https://github.com/joshdick/miniProxy/blob/master/miniProxy.php
Its working fine when i run using php file. But i don't knw how to implement this package file in laravel. This package contains only one file. Can anyone guide me or help me how to do this package functioning in laravel.
You can simply include this file in your class. Put it somewhere meaningful, like /vendor or /lib and include it in the class where you want to use it.
Some information on including external PHP files: https://laraveldaily.com/how-to-use-external-classes-and-php-files-in-laravel-controller/
simply add it in your composer.json
You can create a ServiceProvider like this in app/Providers :
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
foreach (glob(app_path().'/Helpers/*.php') as $filename) {
require_once($filename);
}
}
}
In you config/app file, add this new serviceProvier
App\Providers\HelperServiceProvider::class,
Then create a folder /Helpers in /app folder (./app/Helpers) and put your file in this folder.
Now you can access all this folder functions from everywhere.
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
I'm asking/answering because I have had so much trouble getting this working and I'd like to show a step-by-step implementation.
References:
https://laravel.com/docs/5.0/facades#creating-facades
http://www.n0impossible.com/article/how-to-create-facade-on-laravel-51
This may not be the only way to implement facades in Laravel 5, but here is how I did it.
We're going to create a custom Foo facade available in the Foobar namespace.
1. Create a custom class
First, for this example, I will be creating a new folder in my project. It will get its own namespace that will make it easier to find.
In my case the directory is called Foobar:
In here, we'll create a new PHP file with our class definition. In my case, I called it Foo.php.
<?php
// %LARAVEL_ROOT%/Foobar/Foo.php
namespace Foobar;
class Foo
{
public function Bar()
{
return 'got it!';
}
}
2. Create a facade class
In our fancy new folder, we can add a new PHP file for our facade. I'm going to call it FooFacade.php, and I'm putting it in a different namespace called Foobar\Facades. Keep in mind that the namespace in this case does not reflect the folder structure!
<?php
// %LARAVEL_ROO%/Foobar/FooFacade.php
namespace Foobar\Facades;
use Illuminate\Support\Facades\Facade;
class Foo extends Facade
{
protected static function getFacadeAccessor()
{
return 'foo'; // Keep this in mind
}
}
Bear in mind what you return in getFacadeAccessor as you will need that in a moment.
Also note that you are extending the existing Facade class here.
3. Create a new provider using php artisan
So now we need ourselves a fancy new provider. Thankfully we have the awesome artisan tool. In my case, I'm gonna call it FooProvider.
php artisan make:provider FooProvider
Bam! We've got a provider. Read more about service providers here. For now just know that it has two functions (boot and register) and we will add some code to register. We're going to bind our new provider our app:
$this->app->bind('foo', function () {
return new Foo; //Add the proper namespace at the top
});
So this bind('foo' portion is actually going to match up with what you put in your FooFacade.php code. Where I said return 'foo'; before, I want this bind to match that. (If I'd have said return 'wtv'; I'd say bind('wtv', here.)
Furthermore, we need to tell Laravel where to find Foo!
So at the top we add the namespace
use \Foobar\Foo;
Check out the whole file now:
<?php
// %LARAVEL_ROOT%/app/Providers/FooProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Foobar\Foo;
class FooProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('foo', function () {
return new Foo;
});
}
}
Make sure you use Foobar\Foo and not Foobar\Facades\Foo - your IDE might suggest the wrong completion.
4. Add our references to config/app.php
Now we have to tell Laravel we're interested in using these random files we just created, and we can do that in our config/app.php file.
Add your provider class reference to 'providers': App\Providers\FooProvider::class
Add your facade class reference to 'aliases': 'Foo' => Foobar\Facades\Foo::class
Remember, in aliases, where I wrote 'Foo', you will want to put the name you want to reference your facade with there. So if you want to use MyBigOlFacade::helloWorld() around your app, you'd start that line with 'MyBigOlFacade' => MyApp\WhereEverMyFacadesAre\MyBigOlFacade::class
5. Update your composer.json
The last code change you should need is to update your composer.json's psr-4 spaces. You will have to add this:
"psr-4": {
"Foobar\\" : "Foobar/",
// Whatever you had already can stay
}
Final move
Okay so now that you have all that changed, the last thing you need is to refresh the caches in both composer and artisan. Try this:
composer dumpautoload
php artisan cache:clear
Usage & A Quick Test:
Create a route in app/routes.php:
Route::get('/foobar', 'FooBarController#testFoo');
Then run
php artisan make:controller FooBarController
And add some code so it now looks like this:
<?php
namespace App\Http\Controllers;
use Foobar\Facades\Foo;
use App\Http\Requests;
class FooBarController extends Controller
{
public function testFoo()
{
dd(Foo::Bar());
}
}
You should end up with the following string:
Troubleshooting
If you end up with and error saying it cannot find the class Foobar\Facades\Foo, try running php artisan optimize
I want a new config file in my Laravel 5 app to store all my constants in. After looking around the net I found the recommended solution seems to be to create a new config file that returns an array of key value pairs and then use that. So I created the following file:
<?php
// config/constants.php
return [
'SITE_NAME' => 'Site Name',
'SITE_EMAIL' => 'email#site.com',
'ADMIN_EMAIL' => 'admin#site.com'
];
Then in one of my controllers I try to access one of these values like so:
echo Config::get('constants.ADMIN_EMAIL');
I just get the following error:
FatalErrorException in WelcomeController.php line 46:
Class 'App\Http\Controllers\Config' not found
Do I have to do something else to get it to work?
In Laravel 5, to avoid this kind of headache, you can use the config helper function to get a config item, like this :
config('constants.ADMIN_EMAIL')
Nice and easy ;)
The Config class is an alias in the global namespace. To reference it from inside the controller (which is in the App\Http\Controllers namespace) you have to prepend it with a backslash:
echo \Config::get('constants.ADMIN_EMAIL');
Or add a use statement above the controller class:
use Config;
class MyController extends Controller {
As an alternative you might also want to use dependency injection to access the config. That would look somewhat like this:
class MyController extends Controller {
public function __construct(Illuminate\Config\Repository $config){
$this->config = $config;
}
public function index(){
echo $this->config->get('constants.ADMIN_EMAIL');
}
}
As #Bernig suggests you can also simply use the new config() helper function:
echo config('constants.ADMIN_EMAIL');
I met the same issue today, and I find an elegant solution:
add the config/your_new_config.php to ConfigServiceProvider, like this:
/**
* Overwrite any vendor / package configuration.
*
* This service provider is intended to provide a convenient location for you
* to overwrite any "vendor" or package configuration that you may want to
* modify before the application handles the incoming request / command.
*
* #return void
*/
public function register()
{
config([
'config/your_new_config.php', // add your new config file here!
]);
}
The reason is well explained in the function's comments