I'm trying to do a view::share('current_user', Auth::User()); but in laravel 5 i can't find where to do this, in L4 you could do this in the baseController, but that one doesn't exists anymore.
grt Glenn
I am using Laravel 5.0.28, view::share('current_user', Auth::User()) doesn't work anymore because this issue https://github.com/laravel/framework/issues/6130
What I do instead is, first create a new service provider using artisan.
php artisan make:provider ComposerServiceProvider
Then add ComposerServiceProvider to config/app.php providers array
//...
'providers' => [
//...
'App\Providers\ComposerServiceProvider',
]
//...
Then open app/Providers/ComposerServiceProvider.php that just created, inside boot method add the following
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
View::composer('*', function($view)
{
$view->with('current_user', Auth::user());
});
}
Finally, import View and Auth facade
use Auth, View;
For more information, see http://laravel.com/docs/5.0/views#view-composers
First, you can probably create your own BaseController and extend it in other controllers.
Second thing is, that you may use Auth:user() directly in View, you don't need to assign anything in the view.
For other usages you can go to app/Providers/App/ServiceProvider.php and in boot method you can View::share('current_user', Auth::User()); but of course you need to add importing namespaces first:
use View;
use Auth;
because this file is in App\Providers namespace
In Laravel 5 uses the same method as in laravel 4:
View::share('current_user', Auth::User());
or using the view helper:
view()->share('current_user', Auth::User());
See in http://laravel.com/docs/5.0/views
This will may help:
App::booted(function()
{
View::share('current_user', Auth::user());
});
I'v tried it, put it in app/Providers simply not working. The alternative way is to create a Global middleware and put View::share('currentUser', Auth::user()); there.
Related
I am trying to deep dive laravel concept. In the very first step i got stuck. Loading different classes and use them.
In the laravel routing (where you can register web routes for your application), there is no any use keyword used for using class and initiate Route class in web.php
Route::get('/home', 'HomeController#index')->name('home');
how Route::get run without using any class?
And when we go more deep using model class
namespace hosam\Http\Controllers\Auth;
use hosam\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Auth;
use Illuminate\Support\Facades\DB;
and we use Auth in aur code like this.
Auth::login($user);
from using use keyword does php load auth class in our code where we are using Use Auth?
All the route files under routes folder are loaded automatically by laravel. routes/web.php and laravel/api.php are assigned to middleware web and api respectively.
All the classes and namespaces in laravel are loaded from the composer autoloader.
These files are mapped in the RouteServiceProvider class under Provider folder. So that class use Route facade. As the web.php and api.php is not called directly so there is no need to initiate the class in the particiular file
//RouteServiceProvider.php
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
Routing
You can also make your Helper folder with HelperClass and run can be run from any where
make folder in app > Helpers folder.
make helper class Helpers.php
where you can write all your function like
function write_yourfunction(){
// your code
// return something
}
to load every where you can use service provider. Edit app > Providers > AppServiceProvider.php
public function register()
{
foreach (glob(app_path() . '/Helpers/*.php') as $filename) {
require_once($filename);
}
}
Now you can call write_yourfunction() 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'm currently developing a package in/for Laravel 5.
My package contains a custom middleware and I would like to add it to the $routeMiddlewarearray of the Kernel class from in my package Service Provider.
But I can't seem to find a way to do this.
I tried to make a custom class that extends the Kernel class and then I can merge the array with my array.
But once out of the constructor it's not possible.
In L4 you had App::middleware, but that function is no longer available in L5.
Can anyone who has solved this problem help me solving this?
Please, tell me if my question is not clear enough, so that I can clarerify it a bit.
Since Laravel 5.4 (tested up to 5.8) you would call the following line from a service provider.
$this->app['router']->aliasMiddleware('my-package-middleware', \My\Package\Middleware::class);
Or you can use the app() helper as below.
app('router')->aliasMiddleware('my-package-middleware', \My\Package\Middleware::class);
It's about Laravel 5.6
/*In your package service provider*/
public function boot()
{
/** #var Router $router */
$router = $this->app['router'];
$router->pushMiddlewareToGroup('web', MyPackage\Middleware\WebOne::class);
}
In your package service provider you can access the router instance like this:
$this->app['router']
Next you can register middleware like this:
$this->app['router']->middleware('middlewareName', 'your\namespace\MiddlewareClass');
you place this code in the register method of your service provider.
You can do this with these two ways:
Register your middle-ware inside your general middle-ware provider
Register the middle-ware inside your package Service Provider
lets try first one by create your TestMiddleware.php file in your src package folder and place it in somewhere, in my case i placed it inside Middle-ware folder and then add it to your composer.json auto-loader like this:
"autoload": {
"psr-4": {
"Vendor\\Package\\Middleware": "packages/Vendor/Package/src/Middleware"
}
}
And write your general middle-ware:
namespace Vendor\Package\Middleware;
class TestMiddleware {
public function handle( $request, Closure $next ) {
echo 'hello, world!';
}
}
And then then add the Middle-ware to your main project middle-ware, in Lumen you should add it like this:
$app->middleware([
Vendor\Package\Middleware\TestMiddleware::class
]);
Add middle-ware to package service provider
And the second way, create middle-ware and load it in autoloader like last example and then create a service provider and register your middle-ware inside boot method:
public function boot()
{
$this->app->middleware([
\Vendor\Package\Middleware\TestMiddleware::class
]);
}
And finally you should register your service provider inside your main project (Lumen example)
$app->register(Vendor\Package\TestServiceProvider::class);
in laravel 9 in package service provider and in register function will use
app('router')->aliasMiddleware method for ex:
app('router')->aliasMiddleware('yourmiddleware',yourclass::class)
Solution for Lumen:
$this->app->middleware($middleware);
There are two ways to register your package middlewares.
The first way would be pushing middleware into existing middleware group with the following method:
$this->middlewareGroup($group_name, $middleware_list)
And the other way would be registering a custom middleware and assigning your middlewares to that group.
$this->pushMiddlewareToGroup($group_name, $middleware_list)
You can learn more in the links below
middlewareGroup:
https://laravel.com/api/5.5/Illuminate/Routing/Router.html#method_middlewareGroup
pushMiddlewareToGroup: https://laravel.com/api/5.5/Illuminate/Routing/Router.html#method_pushMiddlewareToGroup
I am working on designing a specific web framework that allows our team to add new components as plugins, then allowing customers to add these plugins or modules using a control panel.
With CodeIgniter things were easy , just copy the controller into the controllers folder and the client-side module will find its way via the URL app/index.php/module/function
But Laravel doesn't allow such dynamic routing.
Is there anyway to extend the route configuration without editing the routes.php by hand ?
You can simply add any routes you want in your service provider's 'boot' method:
public function boot()
{
$this->app['router']->get('my-route', 'MyVendor\Mypackage\MyController#action');
}
If you want to have a kind of automatic prefix, that doesn't happen automatically, but it's not too hard to create one:
public function boot()
{
$this->app['router']->group(['prefix' => 'my-module'], function ($router) {
$router->get('my-route', 'MyVendor\MyPackage\MyController#action');
$router->get('my-second-route', 'MyVendor\MyPackage\MyController#otherAction');
});
}
A lot of people will have this prefix as a config variable so that developers can choose the prefix they want (if you do this remember to name your routes so you can refer to them easily):
public function boot()
{
$this->app['router']->group(['prefix' => \Config::get('my-package::prefix')], function ($router) {
$router->get('my-route', 'MyVendor\MyPackage\MyController#action');
$router->get('my-second-route', 'MyVendor\MyPackage\MyController#otherAction');
});
}
I know I'm bit late but in Laravel 5.4 we can achieve something like this:
Step 1 Create your package and create service provider in it.
Step 2 Register your package service provider in laravel config app.
Step 3 Now create a sperate routes service provider which will contain following
namespace MyPackage\Providers;
use App\Providers\RouteServiceProvider;
use Illuminate\Support\Facades\Route;
class MyPackageRouteServiceProvider extends RouteServiceProvider
{
protected $namespace='MyPackage\Controllers';
public function boot()
{
parent::boot();
}
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
protected function mapApiRoutes()
{
Route::prefix('Mypackage\api')
->middleware('api')
->namespace($this->namespace)
->group(__DIR__ . '\..\Routes\api.php');
}
protected function mapWebRoutes()
{
Route::prefix('Mypackage')
->middleware('web')
->namespace($this->namespace)
->group(__DIR__ . '\..\Routes\web.php');
}
}
Note: I'm considering there is Routes Folder and contain web.php and api.php file. According to your question you want to load it dynamically you can have a constructor function and pass the package name, prefix and namespace as per your ease.
Step 4 Now the final step is registering the service provider you can call something like this in your package service provider:
public function boot()
{
$this->app->register('Mypackage\Providers\MyPackageRouteServiceProvider');
}
Hope this helps. Cheers
Just some theory
That's in fact pretty easy! When you think about it, Laravels routing layer is also just a component that is bound to Laravels container.
That allows us to grab it from there wherever we're accessing the container. Since you're trying to modify routes in a package, a great place to do it would be in your packages Service Provider.
Also, when doing that in a Service Provider you'll automatically have access to the app property (Your service provider is a child class of Laravels ServiceProvider class) and you can grab the router pretty easy!
Hands on code
<?php namespace My\Packages\Namespace;
use Illuminate\Support\ServiceProvider;
class MyPackageProvider extends ServiceProvider {
public function boot()
{
$this->app['router']->get('package-route', function(){
return "I just dynamically registered a route out of my package";
});
}
}
That's the Service Provider of your package. The only thing the user will have to do is to add the Service Provider to his providers array in the config/app.php.
Be careful!
When a user has defined a route that is identically named as your dynamically added route, your route will be overwritten. Make sure that you're using some kind of route prefixes if you are dynamically adding routes.
Further Reading
Laravel Docs - IoC Container