I have the following table: group_pages in mysql database with page name route name :
id name route
--------------------
0 About about
1 Contact contact
2 Blog blog
what I am trying to do is to create dynamic routes in my : routes.php ?
Where if I go to for example: /about it will go to AboutController.php ( which will be created dynamically) is that possible? is it possible to create a dynamic controller file?
I am trying to create dynamic pages routes that links to a controller
example i want to generate this dynamically in my routes.php
Route::controller('about', 'AboutController');
Route::controller('contact', 'ContactController');
Route::controller('blog', 'BlogController');
This is not the right way to create dynamic pages instead, you should use a database and keep all pages in the database. For example:
// Create pages table for dynamic pages
id | slug | title | page_content
Then create Page Eloquent model:
class Page extends Eloquent {
// ...
}
Then create Controller for CRUD, you may use a resource controller or a normal controller, for example, normally a PageController:
class PageController extends BaseController {
// Add methods to add, edit, delete and show pages
// create method to create new pages
// submit the form to this method
public function create()
{
$inputs = Input::all();
$page = Page::create(array(...));
}
// Show a page by slug
public function show($slug = 'home')
{
$page = page::whereSlug($slug)->first();
return View::make('pages.index')->with('page', $page);
}
}
The views/page/index.blade.php view file:
#extends('layouts.master')
{{-- Add other parts, i.e. menu --}}
#section('content')
{{ $page->page_content }}
#stop
To show pages create a route like this:
// could be page/{slug} or only slug
Route::get('/{slug}', array('as' => 'page.show', 'uses' => 'PageController#show'));
To access a page, you may require url/link like this:
http://example.com/home
http://example.com/about
This is a rough idea, try to implement something like this.
After spending 2 hours, digging through google and Laravel source, I came up with this solution, which I think works the best and looks the cleanest. No need for redirects and multiple inner requests.
You add this route at the very bottom of routes files.
If no other routes are matched, this is executed. In the closure, you decide which controller and action to execute.
The best part is - all route parameters are passed to action, and method injection still works. The ControllerDispatcer line is from Laravel Route(r?) class.
My example would handle 2 cases - first checks if user exists by that name, then checks if an article can be found by the slug.
Laravel 5.2 (5.3 below)
Route::get('{slug}/{slug2?}', function ($slug) {
$class = false;
$action = false;
$user = UserModel::where('slug', $slug)->first();
if ($user) {
$class = UserController::class;
$action = 'userProfile';
}
if (!$class) {
$article= ArticleModel::where('slug', $slug)->first();
if ($article) {
$class = ArticleController::class;
$action = 'index';
}
}
if ($class) {
$route = app(\Illuminate\Routing\Route::class);
$request = app(\Illuminate\Http\Request::class);
$router = app(\Illuminate\Routing\Router::class);
$container = app(\Illuminate\Container\Container::class);
return (new ControllerDispatcher($router, $container))->dispatch($route, $request, $class, $action);
}
// Some fallback to 404
throw new NotFoundHttpException;
});
5.3 has changed how the controller gets dispatched.
Heres my dynamic controller example for 5.3, 5.4
namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use Illuminate\Routing\ControllerDispatcher;
use Illuminate\Routing\Route;
class DynamicRouteController extends Controller
{
/**
* This method handles dynamic routes when route can begin with a category or a user profile name.
* /women/t-shirts vs /user-slug/product/something
*
* #param $slug1
* #param null $slug2
* #return mixed
*/
public function handle($slug1, $slug2 = null)
{
$controller = DefaultController::class;
$action = 'index';
if ($slug1 == 'something') {
$controller = SomeController::class;
$action = 'myAction';
}
$container = app();
$route = $container->make(Route::class);
$controllerInstance = $container->make($controller);
return (new ControllerDispatcher($container))->dispatch($route, $controllerInstance, $action);
}
}
Hope this helps!
try
Route::get('/', ['as' => 'home', 'uses' => 'HomeController#index']);
$pages =
Cache::remember('pages', 5, function() {
return DB::table('pages')
->where('status', 1)
->lists('slug');
});
if(!empty($pages))
{
foreach ($pages as $page)
{
Route::get('/{'.$page.'}', ['as' => $page, 'uses' => 'PagesController#show']);
}
}
There is a component available, which you can use to store routes in a database. As an extra advantage, this component only loads the current active route, so it improves performance, since not all routes are loaded into the memory.
https://github.com/douma/laravel-database-routes
Follow the installation instructions provided in the readme.
Storing routes in the database
The only thing needed here is injecting the RouteManager into for example a cli command. With addRoute can tell the RouteManager to store the route into the database. You can easily change this code and use your own repository of pages or other data to construct the routes.
use Douma\Routes\Contracts\RouteManager;
class RoutesGenerateCommand extends Command
{
protected $signature = 'routes:generate';
private $routeManager;
public function __construct(RouteManager $routeManager)
{
$this->routeManager = $routeManager;
}
public function handle()
{
$this->routeManager->addRoute(
new Route('/my-route', false, 'myroute', MyController::class, 'index')
);
}
}
Run this cli command every 2-5 minutes or after a change in your data to make sure the routes are recent.
Register the RouteMiddleware in App\Http\Kernel.php
\Douma\Routes\Middleware\RouteMiddleware::class
Empty your web.php
If you have defined any Laravel route, make sure to empty this file.
Using routes from the database
You can use the route in blade:
{{ RouteManager::routeByName('myroute')->url() }}
Or you can inject the RouteManager-interface anywhere you like to obtain the route:
use Douma\Routes\Contracts\RouteManager;
class MyClass
{
public function __construct(RouteManager $routeManager)
{
$this->routeManager = $routeManager;
}
public function index()
{
echo $this->routeManager->routeByName('myroute')->url();
}
}
For more information see the readme.
We can make dynamic route by this way
// Instanciate a router class.
$router = app()->make('router');
Get Route value from Database
// For route path this can come from your database.
$paths = ['path_one','path_two','path_three'];
Then iterate the value to make dynamic route
// Then iterate the router "get" method.
foreach($paths as $path){
$router->resource($path, 'YourController');
}
You can use GET|POST|PUT|PATCH|DELETE methods also
// Then iterate the router "get" method.
foreach($paths as $path){
$router->get($path, 'YourController#index')->name('yours.index');
}
You can do something like this. It works perfect for me
use Illuminate\Container\Container;
use Illuminate\Routing\ControllerDispatcher;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Illuminate\Routing\Route as MainRoute;
use Illuminate\Routing\Router;
Route::group([
'prefix' => config('app.payment.route_prefix'),
'namespace' => config('app.payment.route_namespace'),
'middleware' => config('app.payment.route_middleware')
], function (Router $router) {
/**
* Resolve target payment method controller
*
* #param $key Example key [paypal]
* #param $action
* #return mixed
*/
$resolver = function ($key, $action) {
$route = app(MainRoute::class);
$container = app(Container::class);
// Generate App\\Http\Controllers\PaymentMethods\PaypalController
$controller = app(sprintf('%s\\%sController', config('app.payment.route_namespace'), ucfirst($key)));
return (new ControllerDispatcher($container))->dispatch($route, $controller, $action);
};
$router->post('{key}/error', function ($key) use ($resolver) {
return $resolver($key, 'error');
});
$router->post('{key}/success', function ($key) use ($resolver) {
return $resolver($key, 'success');
});
$router->get('{key}', function ($key) use ($resolver) {
return $resolver($key, 'index');
});
});
Related
Let's say I have a controller called TeamsController. Controller has following method, that returns all teams user has access to.
public function findAll(Request $request): JsonResponse
{
//...
}
Then I have bunch of other controllers with the same method. I would like to create a single route, that would work for all controllers, so I would not need to add a line for each controller every time I create a new controller.
I am unable to catch the controller name from URI. This is what I have tried.
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
// This works
//$router->get('teams', 'TeamsController#findAll');
// This just returns TeamsController#findAll string as a response
$router->get('{resource}', function ($resource) {
return ucfirst($resource) . 'Controller#findAll';
});
});
You return a string instead of calling a controller action:
I believe Laravel loads the controllers this way (not tested)
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
$router->get('{resource}', function ($resource) {
$app = app();
$controller = $app->make('\App\Http\Controllers\'. ucfirst($resource) . 'Controller');
return $controller->callAction('findAll', $parameters = array());
});
});
But again, I don't really think it's a good idea.
App::bind('App\Http\Repositories\languageRepository',
function( $app, array $parameters)
{
return new App\Http\Repositories\languageRepository($parameters[0]);
} );
Route::get('/test/{id}', 'testController#getme');
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Repositories\languageRepository;
class test extends Controller
{
//
protected $language;
public function __construct(languageRepository $rep){
$this->language = $rep;
}
public function getme(){
$this->language->getMe();
}
}
When user accesses the route /test/5 for example, it goes to test Controller. what I'd like to do is that it should automatically pass my route parameter to App:bind function and automatically create languageRepository class with the constructor value passed as my route paramter. what happens is the code actually tells me $parameters[0] is undefined offset. why is that? I've tried App::make but then how do I pass the parameter from route to App::make?
You can accomplish this using the container's request instance, for query parameters:
App::bind('App\Http\Repositories\languageRepository',function($app)
{
$request = $app['request'];
$parameters = $request->all();
return new App\Http\Repositories\languageRepository($parameters[0]);
});
You can accomplish this using the container's request instance, for a route parameter:
App::bind('App\Http\Repositories\languageRepository',function($app)
{
$request = $app['request'];
$segment = $request->segment(1);
return new App\Http\Repositories\languageRepository($segment);
});
In my app I've got a group of routes which need some bootstraping before dispatching.
To illustrate the situation:
There is a special routes group with prefix 'app'. All of this routes have also some params:
site.dev/app/index?age=11&else=af3fs4ta21
Without these params user shouldn't be allowed to access route. I've got it done by creating a simple route middleware.
if (!$request->exists('age') || !$request->exists('else')) {
return redirect('/');
}
Next step is to initialize a class which takes route parameters as a construct arguments. Then param "else" is being used as a argument to db calls. I need to access this class in every route from /app route group.
In order to achive that I tried setting up a serviceprovider:
public function register()
{
$this->app->singleton(Dual::class, function ($app) {
return new Dual($this->app->request->all());
});
}
Then I created a special controller extending BaseController and passing Dual class to its constructor.
class DualController extends Controller
{
public function __construct(Request $request, Dual $dual)
{
$this->middleware(\App\Http\Middleware\DualMiddleware::class);
$this->dual = $dual;
}
}
And then every single controller is extending DualController and accessing Dual class by $this->dual->method().
It is working if route params are in their place and there is already a row in a database.
The problem
This middleware is executed AFTER ServiceProvider & DualController are initializing class Dual. So, middleware is not really working. If route params are not present it is going to fail.
Moreover, in case that there is no required row in database for some reason, Dual class will not be initialized (as it depends on calls to db) and whole app will crash saying that I am trying to perform operations on null.
Desired behaviour
First check route for params presence.
Second, check if there is row in db with key from route.
Third - try to initialize Dual class and pass it to all controllers used by route group /app.
If any of the steps fail -> display proper message.
Part of dual class:
class Dual
{
protected $client = null;
public $config = [];
public function __construct($config)
{
$this->config = $config;
$this->bootstrap();
}
public function getEli()
{
$eli = Eli::where(['else' => $this->config['else']])->first();
return $eli;
}
public function instantiateClient()
{
$client = Client::factory(Client::ADAPTER_OAUTH, [
'entrypoint' => $this->getEli()->eli_url,
'client_id' => '111',
'client_secret' => '111',
]);
$client->setAccessToken($this->getEli()->accessToken()->first()->access_token);
return $client;
}
public function getClient()
{
if ($this->client === null)
{
throw new \Exception('Client is NOT instantiated');
}
return $this->client;
}
public function bootstrap()
{
$this->client = $this->instantiateClient();
}
You can do this in middleware:
$isElseExists = Model::where('else', request('else'))->first();
if (request('age') && request('else') && $isElseExists) {
return $next($request);
} else {
return back()->with('error', 'You are not allowed');
}
If everything is fine, controller method will be executed. Then you'll be able to inject Dual class without any additional logic.
If something is wrong, a user will be redirected to previous URI with error message flashed into session.
I want to have some default data accessible in all views in my Laravel 5 application.
I have tried to search for it but only find results for Laravel 4. I have read the documentation 'Sharing Data With All Views' here but I can't understand what to do. Where should the following code be placed?
View::share('data', [1, 2, 3]);
Thanks for your help.
This target can achieve through different method,
1. Using BaseController
The way I like to set things up, I make a BaseController class that extends Laravel’s own Controller, and set up various global things there. All other controllers then extend from BaseController rather than Laravel’s Controller.
class BaseController extends Controller
{
public function __construct()
{
//its just a dummy data object.
$user = User::all();
// Sharing is caring
View::share('user', $user);
}
}
2. Using Filter
If you know for a fact that you want something set up for views on every request throughout the entire application, you can also do it via a filter that runs before the request — this is how I deal with the User object in Laravel.
App::before(function($request)
{
// Set up global user object for views
View::share('user', User::all());
});
OR
You can define your own filter
Route::filter('user-filter', function() {
View::share('user', User::all());
});
and call it through simple filter calling.
Update According to Version 5.*
3. Using Middleware
Using the View::share with middleware
Route::group(['middleware' => 'SomeMiddleware'], function(){
// routes
});
class SomeMiddleware {
public function handle($request)
{
\View::share('user', auth()->user());
}
}
4. Using View Composer
View Composer also help to bind specific data to view in different ways. You can directly bind variable to specific view or to all views. For Example you can create your own directory to store your view composer file according to requirement. and these view composer file through Service provide interact with view.
View composer method can use different way, First example can look alike:
You could create an App\Http\ViewComposers directory.
Service Provider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
public function boot() {
view()->composer("ViewName","App\Http\ViewComposers\TestViewComposer");
}
}
After that, add this provider to config/app.php under "providers" section.
TestViewComposer
namespace App\Http\ViewComposers;
use Illuminate\Contracts\View\View;
class TestViewComposer {
public function compose(View $view) {
$view->with('ViewComposerTestVariable', "Calling with View Composer Provider");
}
}
ViewName.blade.php
Here you are... {{$ViewComposerTestVariable}}
This method could help for only specific View. But if you want trigger ViewComposer to all views, we have to apply this single change to ServiceProvider.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
public function boot() {
view()->composer('*',"App\Http\ViewComposers\TestViewComposer");
}
}
Reference
Laravel Documentation
For Further Clarification Laracast Episode
If still something unclear from my side, let me know.
You can either create your own service provider (ViewServiceProvider name is common) or you can use the existing AppServiceProvider.
In your selected provider, put your code in the boot method.
public function boot() {
view()->share('data', [1, 2, 3]);
}
This will make a $data variable accessible in all your views.
If you rather want to use the facade instead of the helper, change view()-> to View:: but don't forget to have use View; at the top of your file.
I found this to be the easiest one. Create a new provider and user the '*' wildcard to attach it to all views. Works in 5.3 as well :-)
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
* #return void
*/
public function boot()
{
view()->composer('*', function ($view)
{
$user = request()->user();
$view->with('user', $user);
});
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
The best way would be sharing the variable using View::share('var', $value);
Problems with composing using "*":
Consider following approach:
<?php
// from AppServiceProvider::boot()
$viewFactory = $this->app->make(Factory::class);
$viewFacrory->compose('*', GlobalComposer::class);
From an example blade view:
#for($i = 0; $i<1000; $i++)
#include('some_partial_view_to_display_i', ['toDisplay' => $i])
#endfor
What happens?
The GlobalComposer class is instantiated 1000 times using
App::make.
The event composing:some_partial_view_to_display_i is handled
1000 times.
The compose function inside the GlobalComposer class is called 1000 times.
But the partial view some_partial_view_to_display_i has nothing to do with the variables composed by GlobalComposer but heavily increases render time.
Best approach?
Using View::share along a grouped middleware.
Route::group(['middleware' => 'WebMiddleware'], function(){
// Web routes
});
Route::group(['prefix' => 'api'], function (){
});
class WebMiddleware {
public function handle($request)
{
\View::share('user', auth()->user());
}
}
Update
If you are using something that is computed over the middleware pipeline you can simply listen to the proper event or put the view share middleware at the last bottom of the pipeline.
In the documentation:
Typically, you would place calls to the share method within a service
provider's boot method. You are free to add them to the
AppServiceProvider or generate a separate service provider to house
them.
I'm agree with Marwelln, just put it in AppServiceProvider in the boot function:
public function boot() {
View::share('youVarName', [1, 2, 3]);
}
I recommend use an specific name for the variable, to avoid confussions or mistakes with other no 'global' variables.
You have two options:
1. Share via Boot function in App\Providers\AppServiceProvider:
public function boot()
{
view()->share('key', 'value');
}
And access $key variable in any view file.
Note: Remember that you can't access current Session, Auth, Route data here. This option is good only if you want to share static data. Suppose you want to share some data based on the current user , route, or any custom session variable you won't be able to do with this.
2. Use of a helper class:
Create a helper class anywhere in your application and register it in Alias array in app.php file in config folder.
'aliases' => [
...,
'Helper' => App\HelperClass\Helper::class,
],
and create Helper.php in HelperClass folder within App folder:
namespace App\HelperClass;
class Helper
{
public static function Sample()
{
//Your Code Here
}
}
and access it anywhere like Helper::Sample().
You will not be restricted here to use Auth, Route, Session, or any other classes.
The documentation is hear https://laravel.com/docs/5.4/views#view-composers but i will break it down
Look for the directory app\Providers in the root directory of your application and create the file ComposerServiceProvider.php and copy and past the text below into it and save it.
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function boot()
{
// Using class based composers...
View::composer(
'profile', 'App\Http\ViewComposers\ProfileComposer'
);
// Using Closure based composers...
View::composer('dashboard', function ($view) {
//
});
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
From the root of your application open Config/app.php and look for the Providers section in the file and copy and past this 'App\Providers\ComposerServiceProvider', to the array.
By doing this, we have created the Composer Service Provider. When you run your application with the view Profile like so http://yourdomain/something/profile, the service provider ComposerServiceProvider is called and the class App\Http\ViewComposers\ProfileComposer is instantiated calling the method Composer due to the code below inside the boot method or function.
// Using class based composers...
View::composer(
'profile', 'App\Http\ViewComposers\ProfileComposer'
);
If you refresh your application you will get an error because the class App\Http\ViewComposers\ProfileComposer does not exist yet. Now lets create it.
Go to the directory path app/Http
Create the directory called ViewComposers
Create the file ProfileComposer.php.
class ProfileComposer
{
/**
* The user repository implementation.
*
* #var UserRepository
*/
protected $users;
/**
* Create a new profile composer.
*
* #param UserRepository $users
* #return void
*/
public function __construct(UserRepository $users)
{
// Dependencies automatically resolved by service container...
$this->users = $users;
}
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$view->with('count', $this->users->count());
}
}
Now go to your view or in this case Profile.blade.php and add
{{ $count }}
and that will show the count of users on the profile page.
To show the count on all pages change
// Using class based composers...
View::composer(
'profile', 'App\Http\ViewComposers\ProfileComposer'
);
To
// Using class based composers...
View::composer(
'*', 'App\Http\ViewComposers\ProfileComposer'
);
1) In (app\Providers\AppServiceProvider.php)
// in boot function
view()->composer('*', function ($view) {
$data = User::messages();
$view->with('var_messages',$data);
});
2) in Your User Model
public static function messages(){ // this is just example
$my_id = auth()->user()->id;
$data= Message::whereTo($my_id)->whereIs_read('0')->get();
return $data; // return is required
}
3) in Your View
{{ $var_messages }}
I think that the best way is with View Composers. If someone came here and want to find how can do it with View Composers way, read my answer => How to share a variable across all views?
Laravel 5.6 method: https://laravel.com/docs/5.6/views#passing-data-to-views
Example, with sharing a model collection to all views (AppServiceProvider.php):
use Illuminate\Support\Facades\View;
use App\Product;
public function boot()
{
$products = Product::all();
View::share('products', $products);
}
The documentation is here https://laravel.com/docs/5.4/views#view-composers but i will break it down
1.Look for the directory Providers in your root directory and create the for ComposerServiceProvider.php with content
Inside your config folder you can create a php file name it for example "variable.php" with content below:
<?php
return [
'versionNumber' => '122231',
];
Now inside all the views you can use it like
config('variable.versionNumber')
I created ViewServiceProvider for passing data for multiple views, in Laravel 8
Creating app/Provides/ViewServiceProvider.php file.
class ViewServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
//for user views(resources/views/user/*)
View::composer(['user.*'], function ($view) {
$f_user = Auth::user();
$f_platform = 'user';
$view->with(compact( 'f_user', 'f_platform'));
});
// for admin views(resources/views/admin/*)
View::composer('admin.*', function ($view) {
$f_admin = Auth::guard('admin')->user();
$f_platform = 'admin';
$view->with(compact( 'f_admin', 'f_platform'));
});
//for all views(resources/views/*)
View::composer('*', function ($view) {
$f_something = [];
$view->with(compact('f_something'));
});
}
}
Register ViewServiceProvider in config/app.php
'providers' => [
...
App\Providers\ViewServiceProvider::class,
],
Using in blades
{{ $f_user }}
{{ $f_platform }}
{{ $f_something }}
{{ $f_admin }}
{{ $f_platform }}
{{ $f_something }}
for example you can return list of all tables in database to the all views of Controller
like this :
public function __construct()
{
$tables = DB::select('SHOW TABLES'); // returns an array of stdObjects
view()->share('tables', $tables);
}
In Laravel 5 and above versions , you can edit boot function in
AppServiceProvider.php to access variable in all views
public function boot()
{
\View::composer('*', function($view){
$view->with('key', 'value');
});
}
"Key" represents the name of the variable which you want to set, so that you can use it later in any .blade.php file and "value" represents the value represented by the variable... For Example :
//setting user role to be accessed by all blade.php files
public function boot(){
//
View::composer('*', function($view){
view->with('role', Auth::user()->infouser->role);
});
}
If are you using Laravel 8 you can do this like that,
class Controller extends BaseController{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct(){
$categories = Category::where('show_menu', '=', 1)->where('status', '=', 'approved')->get();
view()->share('categories', $categories);
}}
I want to have some default data accessible in all views in my Laravel 5 application.
I have tried to search for it but only find results for Laravel 4. I have read the documentation 'Sharing Data With All Views' here but I can't understand what to do. Where should the following code be placed?
View::share('data', [1, 2, 3]);
Thanks for your help.
This target can achieve through different method,
1. Using BaseController
The way I like to set things up, I make a BaseController class that extends Laravel’s own Controller, and set up various global things there. All other controllers then extend from BaseController rather than Laravel’s Controller.
class BaseController extends Controller
{
public function __construct()
{
//its just a dummy data object.
$user = User::all();
// Sharing is caring
View::share('user', $user);
}
}
2. Using Filter
If you know for a fact that you want something set up for views on every request throughout the entire application, you can also do it via a filter that runs before the request — this is how I deal with the User object in Laravel.
App::before(function($request)
{
// Set up global user object for views
View::share('user', User::all());
});
OR
You can define your own filter
Route::filter('user-filter', function() {
View::share('user', User::all());
});
and call it through simple filter calling.
Update According to Version 5.*
3. Using Middleware
Using the View::share with middleware
Route::group(['middleware' => 'SomeMiddleware'], function(){
// routes
});
class SomeMiddleware {
public function handle($request)
{
\View::share('user', auth()->user());
}
}
4. Using View Composer
View Composer also help to bind specific data to view in different ways. You can directly bind variable to specific view or to all views. For Example you can create your own directory to store your view composer file according to requirement. and these view composer file through Service provide interact with view.
View composer method can use different way, First example can look alike:
You could create an App\Http\ViewComposers directory.
Service Provider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
public function boot() {
view()->composer("ViewName","App\Http\ViewComposers\TestViewComposer");
}
}
After that, add this provider to config/app.php under "providers" section.
TestViewComposer
namespace App\Http\ViewComposers;
use Illuminate\Contracts\View\View;
class TestViewComposer {
public function compose(View $view) {
$view->with('ViewComposerTestVariable', "Calling with View Composer Provider");
}
}
ViewName.blade.php
Here you are... {{$ViewComposerTestVariable}}
This method could help for only specific View. But if you want trigger ViewComposer to all views, we have to apply this single change to ServiceProvider.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
public function boot() {
view()->composer('*',"App\Http\ViewComposers\TestViewComposer");
}
}
Reference
Laravel Documentation
For Further Clarification Laracast Episode
If still something unclear from my side, let me know.
You can either create your own service provider (ViewServiceProvider name is common) or you can use the existing AppServiceProvider.
In your selected provider, put your code in the boot method.
public function boot() {
view()->share('data', [1, 2, 3]);
}
This will make a $data variable accessible in all your views.
If you rather want to use the facade instead of the helper, change view()-> to View:: but don't forget to have use View; at the top of your file.
I found this to be the easiest one. Create a new provider and user the '*' wildcard to attach it to all views. Works in 5.3 as well :-)
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
* #return void
*/
public function boot()
{
view()->composer('*', function ($view)
{
$user = request()->user();
$view->with('user', $user);
});
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
The best way would be sharing the variable using View::share('var', $value);
Problems with composing using "*":
Consider following approach:
<?php
// from AppServiceProvider::boot()
$viewFactory = $this->app->make(Factory::class);
$viewFacrory->compose('*', GlobalComposer::class);
From an example blade view:
#for($i = 0; $i<1000; $i++)
#include('some_partial_view_to_display_i', ['toDisplay' => $i])
#endfor
What happens?
The GlobalComposer class is instantiated 1000 times using
App::make.
The event composing:some_partial_view_to_display_i is handled
1000 times.
The compose function inside the GlobalComposer class is called 1000 times.
But the partial view some_partial_view_to_display_i has nothing to do with the variables composed by GlobalComposer but heavily increases render time.
Best approach?
Using View::share along a grouped middleware.
Route::group(['middleware' => 'WebMiddleware'], function(){
// Web routes
});
Route::group(['prefix' => 'api'], function (){
});
class WebMiddleware {
public function handle($request)
{
\View::share('user', auth()->user());
}
}
Update
If you are using something that is computed over the middleware pipeline you can simply listen to the proper event or put the view share middleware at the last bottom of the pipeline.
In the documentation:
Typically, you would place calls to the share method within a service
provider's boot method. You are free to add them to the
AppServiceProvider or generate a separate service provider to house
them.
I'm agree with Marwelln, just put it in AppServiceProvider in the boot function:
public function boot() {
View::share('youVarName', [1, 2, 3]);
}
I recommend use an specific name for the variable, to avoid confussions or mistakes with other no 'global' variables.
You have two options:
1. Share via Boot function in App\Providers\AppServiceProvider:
public function boot()
{
view()->share('key', 'value');
}
And access $key variable in any view file.
Note: Remember that you can't access current Session, Auth, Route data here. This option is good only if you want to share static data. Suppose you want to share some data based on the current user , route, or any custom session variable you won't be able to do with this.
2. Use of a helper class:
Create a helper class anywhere in your application and register it in Alias array in app.php file in config folder.
'aliases' => [
...,
'Helper' => App\HelperClass\Helper::class,
],
and create Helper.php in HelperClass folder within App folder:
namespace App\HelperClass;
class Helper
{
public static function Sample()
{
//Your Code Here
}
}
and access it anywhere like Helper::Sample().
You will not be restricted here to use Auth, Route, Session, or any other classes.
The documentation is hear https://laravel.com/docs/5.4/views#view-composers but i will break it down
Look for the directory app\Providers in the root directory of your application and create the file ComposerServiceProvider.php and copy and past the text below into it and save it.
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function boot()
{
// Using class based composers...
View::composer(
'profile', 'App\Http\ViewComposers\ProfileComposer'
);
// Using Closure based composers...
View::composer('dashboard', function ($view) {
//
});
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
From the root of your application open Config/app.php and look for the Providers section in the file and copy and past this 'App\Providers\ComposerServiceProvider', to the array.
By doing this, we have created the Composer Service Provider. When you run your application with the view Profile like so http://yourdomain/something/profile, the service provider ComposerServiceProvider is called and the class App\Http\ViewComposers\ProfileComposer is instantiated calling the method Composer due to the code below inside the boot method or function.
// Using class based composers...
View::composer(
'profile', 'App\Http\ViewComposers\ProfileComposer'
);
If you refresh your application you will get an error because the class App\Http\ViewComposers\ProfileComposer does not exist yet. Now lets create it.
Go to the directory path app/Http
Create the directory called ViewComposers
Create the file ProfileComposer.php.
class ProfileComposer
{
/**
* The user repository implementation.
*
* #var UserRepository
*/
protected $users;
/**
* Create a new profile composer.
*
* #param UserRepository $users
* #return void
*/
public function __construct(UserRepository $users)
{
// Dependencies automatically resolved by service container...
$this->users = $users;
}
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$view->with('count', $this->users->count());
}
}
Now go to your view or in this case Profile.blade.php and add
{{ $count }}
and that will show the count of users on the profile page.
To show the count on all pages change
// Using class based composers...
View::composer(
'profile', 'App\Http\ViewComposers\ProfileComposer'
);
To
// Using class based composers...
View::composer(
'*', 'App\Http\ViewComposers\ProfileComposer'
);
1) In (app\Providers\AppServiceProvider.php)
// in boot function
view()->composer('*', function ($view) {
$data = User::messages();
$view->with('var_messages',$data);
});
2) in Your User Model
public static function messages(){ // this is just example
$my_id = auth()->user()->id;
$data= Message::whereTo($my_id)->whereIs_read('0')->get();
return $data; // return is required
}
3) in Your View
{{ $var_messages }}
I think that the best way is with View Composers. If someone came here and want to find how can do it with View Composers way, read my answer => How to share a variable across all views?
Laravel 5.6 method: https://laravel.com/docs/5.6/views#passing-data-to-views
Example, with sharing a model collection to all views (AppServiceProvider.php):
use Illuminate\Support\Facades\View;
use App\Product;
public function boot()
{
$products = Product::all();
View::share('products', $products);
}
The documentation is here https://laravel.com/docs/5.4/views#view-composers but i will break it down
1.Look for the directory Providers in your root directory and create the for ComposerServiceProvider.php with content
Inside your config folder you can create a php file name it for example "variable.php" with content below:
<?php
return [
'versionNumber' => '122231',
];
Now inside all the views you can use it like
config('variable.versionNumber')
I created ViewServiceProvider for passing data for multiple views, in Laravel 8
Creating app/Provides/ViewServiceProvider.php file.
class ViewServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
//for user views(resources/views/user/*)
View::composer(['user.*'], function ($view) {
$f_user = Auth::user();
$f_platform = 'user';
$view->with(compact( 'f_user', 'f_platform'));
});
// for admin views(resources/views/admin/*)
View::composer('admin.*', function ($view) {
$f_admin = Auth::guard('admin')->user();
$f_platform = 'admin';
$view->with(compact( 'f_admin', 'f_platform'));
});
//for all views(resources/views/*)
View::composer('*', function ($view) {
$f_something = [];
$view->with(compact('f_something'));
});
}
}
Register ViewServiceProvider in config/app.php
'providers' => [
...
App\Providers\ViewServiceProvider::class,
],
Using in blades
{{ $f_user }}
{{ $f_platform }}
{{ $f_something }}
{{ $f_admin }}
{{ $f_platform }}
{{ $f_something }}
for example you can return list of all tables in database to the all views of Controller
like this :
public function __construct()
{
$tables = DB::select('SHOW TABLES'); // returns an array of stdObjects
view()->share('tables', $tables);
}
In Laravel 5 and above versions , you can edit boot function in
AppServiceProvider.php to access variable in all views
public function boot()
{
\View::composer('*', function($view){
$view->with('key', 'value');
});
}
"Key" represents the name of the variable which you want to set, so that you can use it later in any .blade.php file and "value" represents the value represented by the variable... For Example :
//setting user role to be accessed by all blade.php files
public function boot(){
//
View::composer('*', function($view){
view->with('role', Auth::user()->infouser->role);
});
}
If are you using Laravel 8 you can do this like that,
class Controller extends BaseController{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct(){
$categories = Category::where('show_menu', '=', 1)->where('status', '=', 'approved')->get();
view()->share('categories', $categories);
}}