How can I encrypt all ids in url in Laravel 5.2 - php

I need to do all url ids encrypted like :
user/edit/1
items/edit/35
posts/details/52
to
user/edit/sdfjk54dfds
items/edit/sdfjk54dfds
posts/details/sdfjk5s4dfds
there is lots of areas like blade files and in controllers that id used url('items/edit/2') and also in controller some function are passed by objects like public function itemedit(Items $items).
I tried $encrypt_val = Crypt::encrypt($value) and $decrypt_val = Crypt::decrypt($encrypt_val ); but I need to do it everywhere.
There is any short way or Middleware function to do it ?

Use Laravel Hashids
You can encode id like below
$encoded_id = Hashids::encode($id);
Your URL will be like below
<url>/users/edit/sdfjk54dfds
Hash ID installation guide
https://github.com/vinkla/laravel-hashids

You can use Uuid instead of using integer id. For this please follow the instruction:
Just create a trait:
trait Uuids
{
/**
* Boot function from laravel.
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->{$model->getKeyName()} = Uuid::generate()->string;
});
}
}
and in your model use above trait:
use SomeNamespcaeOfTrait;
class User extends Eloquent
{
use Uuids;
/**
* #var bool
*/
public $incrementing = false;
}
and in your migration use uuid instead of integer.

There's a package called Laravel HashSlug that acts as desired. Similarly to the one in sumit's answer, it's built on Hashids, but design specially to work with urls.
Using the above package all you need to do is add a trait and typehint in controller:
class Post extends Model {
use HasHashSlug;
}
// routes/web.php
Route::resource('/posts', 'PostController');
// app/Http/Controllers/PostController.php
public function show(Post $post){
return view('post.show', compact('post'));
}

Related

How to get results with where condition in Filament Admin Resource

I am using Laravel Filament and made a Resource for User model which works fine.
I have a is_admin field in users table which return 0 and 1. I need users with is_admin = 0 but for now , i am getting all of them.
Can i add a where condition in filament to get only required fields.
The proper way to add additional where conditions with the built-in eloquent query are as follows:
public static function getEloquentQuery(): Builder
{
return static::getModel()::query()->where('is_admin', 1);
}
A bit late for the answer, bit here's an in depth guide.
There are two ways to go about it
#1 Pre-filtering query inside the resource
Inside your resource, override the following method:
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->where('is_admin', 0);
}
#2 Global Scope
Filament uses the eloquent interface, so applying a global scope will do the job aswell.
First, create a global scope class inside App\Models\Scopes\ (not a required path, only a suggestion):
<?php
namespace App\Models\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class AncientScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('is_admin', 0);
}
}
Then, modify your user model to apply the scope:
<?php
namespace App\Models;
use App\Models\Scopes\AncientScope;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::addGlobalScope(new AncientScope);
}
}
you can put ->where('role', '0') after return nameModal::query() at getTablequery(). \
like this
return nameModal::query()->where('role', '0');
Yes you can. You can extend getEloquentQuery() function at related resource class.Since you are talking about User model you can add above function as in the below code example to UserResource.php.
public static function getEleouentQuery () {
return User::where('is_admin',0);
}
Check this for more

How to pass parameter to a laravel elequent model's event observer

I have a model in laravel and I want to do something after the first time which an object of my model is created. the simplest way is to add a static boot method inside my model's class like the code below:
class modelName extends Model
{
public static function boot()
{
parent::boot();
self::created(function ($model) {
//the model created for the first time and saved
//do something
//code here
});
}
}
so far so good! the problem is: the ONLY parameter that created method accepts is the model object itself(according to the documentation) :
Each of these methods receives the model as their only argument.
https://laravel.com/docs/5.5/eloquent#events
I need more arguments to work with after model creation. how can I do that?
Or is there any other way to do something while it's guaranteed that the model has been created?
laravel version is 5.5.
You're close. What I would probably do would be to dispatch an event right after you actually create the model in your controller. Something like this.
class WhateverController
{
public function create()
{
$model = Whatever::create($request->all());
$anotherModel = Another::findOrFail($request->another_id);
if (!$model) {
// The model was not created.
return response()->json(null, 500);
}
event(new WhateverEvent($model, $anotherModel));
}
}
I solved the issue using static property in eloquent model class:
class modelName extends Model
{
public static $extraArguments;
public function __construct(array $attributes = [],$data = [])
{
parent::__construct($attributes);
self::$extraArguments = $data ;
public static function boot()
{
parent::boot();
self::created(function ($model) {
//the model created for the first time and saved
//do something
//code here
self::$extraArguments; // is available in here
});
}
}
It works! but I don't know if it may cause any other misbehavior in the application.
Using laravel events is also a better and cleaner way to do that in SOME cases.but the problem with event solution is you can't know if the model has been created for sure and it's time to call the event or it's still in creating status ( and not created status).

How can I use the show method of my resource controller on a soft deleted model?

So I have a resource controller called ProjectController and I added soft delete and use it as an archive.
Route::get('project/archive', 'ProjectController#trash')->name('project.archive');
Route::resource('project', 'ProjectController');
In this archive, I have a list of the projects.
public function trash()
{
$projects = Project::onlyTrashed()->get();
return view('projects.archive', compact('projects'));
}
Now I want to use the show method to view these projects.
In my \App\Providers\RouteServiceProvider I added:
Route::bind('project', function ($value) {
return \App\Project::withTrashed()->find($value);
});
But this way, I am able to edit the project.
I tried to bind project/show, project/{project}/show, but that does not work.
How can I use the show method of my resource controller on a trashed project?
My complete ProjectController looks like:
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ProjectRequest;
use App\Project;
class ProjectController extends Controller
{
public function index()
{
$projects = Project::all();
return view('project.index', compact('projects'));
}
public function create()
{
return view('project.create');
}
public function store(ProjectRequest $request)
{
Project::create($request->all());
return redirect()->route('project.index');
}
public function show(Project $project)
{
return view('project.show', compact('project'));
}
public function edit(Project $project)
{
return view('project.edit', compact('project'));
}
public function update(ProjectRequest $request, Project $project)
{
$project->update($request->all());
return redirect()->route('project.index');
}
public function destroy(Project $project)
{
$project->delete();
return redirect()->route('project.archive');
}
public function trash()
{
$projects = Project::onlyTrashed()->get();
return view('project.archive', compact('projects'));
}
}
By adding a check in the \App\Providers\RouteServiceProvider.
Route::bind('project', function ($value) {
if (Route::currentRouteName() === 'project.show') {
return \App\Project::withTrashed()->find($value);
}
return \App\Project::find($value);
});
Hopefully this will help others.
I may be completely misunderstood the problem, but as far as I understood:
You can exclude some functions of a controller, such as;
Route::resource('photos', 'PhotoController')->only([
'index', 'show'
]);
Route::resource('photos', 'PhotoController')->except([
'create', 'store', 'update', 'destroy'
]);
More detailed information on https://laravel.com/docs/5.7/controllers#restful-partial-resource-routes
Additionally, if you want to implement a resource controller that uses only trashed projects -rather than a regular laravel model- as a resource you have to generate a new controller via something like
php artisan make:controller -r ProjectArchiveController
and customize the functions of it accordingly. For more options on make:controller command, you can use;
php artisan help make:controller
Hope this all helps.
New addition:
Route::get('project/{id}', 'ProjectController#trash')->name('project.archive');
Route::resource('project', 'ProjectController');
and declaration of the function trash,
public function trash(int $id)
You can add a withTrashed() method to the routes file. From the laravel docs https://laravel.com/docs/8.x/routing#implicit-soft-deleted-models
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return $user->email;
})->withTrashed();
I also posted on laracasts.com, where I partly borrowed from OP's answer.
I use this not for an archive of soft-deleted models, but for a restore route. But the problem is the same: route model binding only works for non-trashed models. I wanted a solution that:
works on all models which use the SoftDeletes trait;
only works on routes which are specifically meant for restoring soft-deleted models;
only works on models which are actually soft-deleted;
Therefore, I utilized the resolveRouteBinding() method (originally in \Illuminate\Database\Eloquent\Model), creating a more generic solution:
\App\Models\Traits\SoftDeletes:
<?php
namespace App\Models\Traits;
use Illuminate\Database\Eloquent\SoftDeletes as EloquentSoftDeletes;
use Illuminate\Support\Facades\Route;
trait SoftDeletes {
use EloquentSoftDeletes;
/**
* Retrieve the model for a bound value.
*
* Modified from \Illuminate\Database\Eloquent\Model::resolveRouteBinding()
*
* #param mixed $value
* #param string|null $field
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value, $field = null) {
$route_name_parts = explode(".", Route::currentRouteName());
if (end($route_name_parts) === 'restore') {
return $this->onlyTrashed()->where($field ?? $this->getRouteKeyName(), $value)->first();
}
return $this->where($field ?? $this->getRouteKeyName(), $value)->first();
}
}
For OP's archive, just add another check on the route name in that if-statement.
On the model, I swap the Eloquent version of SoftDeletes for this one. Now I can just define a route as:
Route::patch(
'/projects/{project}/restore',
[ProjectController::class, 'restore']
)->name('projects.restore');
Thus only routes with a name ending in 'restore' will work on a trashed model, all other routes only work on non-trashed models.
Note
With this, the restore routes exclusively work with trashed models. If you want them to work with non-trashed models as well (but why?), just replace the onlyTrashed() method with the withTrashed() method.

Passing data for all views in Laravel [duplicate]

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);
}}

How to pass data to all views in Laravel 5?

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);
}}

Categories