Pass variables to multiple view in laravel - laravel

I want to pass a variable to multiple view bu when i use share method in View. Its says the share method isn't find on View.
How you say i use it and i try the composer either but no matter how i try it can't work could you give me simple example of this action
My controller categorycontroller.php
public function site(){
$data = array();
$data['subcategories'] = SubCategory::all();
$data['categories'] = Category::all();
return view('template.sitemap',compact("data"));
}
My route web.php
Route::get('/404.html', function () {
return view('template/404');
})->name('404.html');
Route::get('404.html','CategoryController#site')->name('404');
Route::get('/sitemap.html', function () {
return view('template/sitemap');
})->name('sitemap.html');
Route::get('sitemap.html','CategoryController#site')->name('sitemap');
what do you suggest?

You can make a variable accessible in multiple views using one of these methods for example:
AppServiceProvider ( reference: https://laravel.com/docs/5.6/providers ) with ViewComposer ( reference: https://laravel.com/docs/master/views#view-composers )
You'll need to add to your ServiceProvider boot() method something similar to this:
public function boot()
{
View::share('variable_name', 'some_value_here');
}
Or inside a controller:
public function __construct() {
$something = 'just a test';
View::share('something', $something);
}

Related

How to pass data to all views in Laravel 5.6?

I have two controllers. StudentController and TeacherController. I have a variable $chat which I want to pass in all the views of StudentController and TeacherController. The $chat will contain different data for both these controllers.
I searched and found ways, but I am getting empty data. I am doing it like this.
<?php
namespace App\Http\Controllers;
use View;
class StudentController extends Controller {
public function __construct()
{
$this->middleware('auth')->except(['home']);
$this->middleware('access')->except(['home']);
$chats = studentChat();
View::share('chats', $chats);
}
So, here I am printing and it is returning an empty array, but when I use the same in a function the array contains data. What is wrong here? Can anyone please help?
What I tried:
public function boot()
{
View::composer('*', function ($view) {
$chats = Cache::remember('chats', 60, function () {
if(Auth::user()->user_type() == config('constant.student'))
{
return studentChat();
}
else
{
return teacherChat();
}
});
$view->with('chats', $chats);
});
}
If you use View::share your share data to ALL your view, if you need to add data to few different views you may do this:
Create blade file(chat.blade.php for your case), and put your variables:
<? $chats = studentChat(); ?>
Include this file to the begining of your views where your need this 'global' varables:
//begin of your blade file
#include('chat')
//some code
{{ $chat->channel }}
Sharing Data With All Views
Occasionally, you may need to share a piece of data with all views that are rendered by your application. You may do so using the view facade's share method. Typically, you should place calls to share 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:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$chats = studentChat();
View::share('chats', $chats);
}
public function register()
{
//
}
}
So, what I did was in the AppServiceProvider class, in the boot function I added this.
View::composer('*', function ($view) {
if(!\Auth::check())
{
return;
}
$userType = \Auth::user()->user_type ;
if($userType == config('constant.student'))
{
$chats = studentChat();
}
else if($userType == config('constant.teacher'))
{
$chats = teacherChat();
}
$view->with('chats', $chats);
});
You can pass data to the view Like.
return View::make('demo')->with('posts', $posts);
For more details visit article : Introduction to Routing in Laravel
write your query in boot method in appServiceProvider like,
View::composer('*', function ($view) {
$share_query = Cache::remember('share_query', 60,function () {
return App\User::all();
});
$view->with('share_query', $share_query);
});
Your final solution is ok, but not the cleanest possible.
Here is what i would do.
Define a class with a single function that contains your logic and return $chats, that way you will encapsulate your logic properly and keep your service provider boot method clean.
Then you have 2 options:
Inject your class in the boot() method of the service provider you use, then call its function and uses View::share. Should looks like :
public function boot(ChatResolver $chatResolver)
{
$chats = $chatResolver->getChats();
View::share(compact('chats));
}
If you only use $chats variable in a signe view or partial (like a part of layout), you can also inject the class you defined directly in the view.
Here is a link to Laravel doc regarding that.
In some cases it might be the easiest solution.

Prevent using same query twice, once in each view composer

I have two View composers in my AppServiceProvider class, below:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
View::composer('left', function ($view)
{
if (Auth::check())
{
$user = Auth::user();
// Gets a list of the people the user is following
$usersFollowing = Following::where('user_id', $user->id)
->get();
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
View::composer('right', function ($view)
{
if (Auth::check())
{
$user = Auth::user();
// Gets a list of the people the user is following
$usersFollowing = Following::where('user_id', $user->id)
->get();
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
}
}
As you can see, both composers request the same query data ($usersFollowing). Both of these layouts (left.blade.php and right.blade.php) are called on all of my pages (by including them in the base layout).
The problem with this is that the page is requesting $usersFollowing twice on a single page load. It's calling the query once for left.blade.php and once for right.blade.php.
I'm also calling Auth::user() twice, once in each composer.
How can I prevent these queries from being called twice for the same request, and only call it once?
I think it is simple to move your queries to top of your method and use them inside both View composers. This way your query would only run once.
Here is my proposed way of doing this;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$user = Auth::user();
// Gets a list of the people the user is following
$usersFollowing = Following::where('user_id', $user->id)
->get();
// You can use `use` keyword to access external variables inside callback function.
//Both of these variables will be accessible inside callback
View::composer('left', function ($view) use ($usersFollowing,$user)
{
if (Auth::check())
{
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
View::composer('right', function ($view) use ($usersFollowing,$user)
{
if (Auth::check())
{
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
}
}
I hope this can be helpful and you can generalize this method to any other situations where you need this kind of functionality.

Passing a variable to a master template in laravel

In laravel i have defined a route like this
Route::get('/', array(){
'as' => 'index',
'uses' => 'HomeController#index'
});
The function index() in the HomeController contains
public function index(){
$index = new ExampleModel;
$data = $index->getExampleList();
return View::make('public.index');
}
Now the problem is i have a master layout called happypath inside layouts folder in my views which yields this public.index content and i need to pass this $data to layouts.happypath. How do i do this ?
You can use a view composer for example:
namespace App\Providers;
use App\ExampleModel;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
protected $exampleModel;
public function __construct(ExampleModel $exampleModel)
{
$this->exampleModel = $exampleModel;
}
public function boot()
{
view()->composer('layouts.happypath', function ($view) {
$view->with('publicIndex', $this->exampleModel->getExampleList());
});
}
public function register()
{
//
}
}
So, every time you use/render the layouts.happypath the $publicIndex variable will be attached within the layout. Also you need to add the ComposerServiceProvider class in your config/app.php file in the providers array. You may access/reference the data using $publicIndex variable in your layout. There are other ways like global shared $information using view()->share(...) method to share a peace of data all over the views but this may help you.
I could not figure out the ComposerServiceProvider View::composer thing. So i basically solved it like this in Laravel 4.2. Added this code to the BaseController.php
protected $menuList;
public function __construct() {
$response = API::pool([
['GET', API::url('level')],
]);
$index = new Index();
$index->setCourseList($response[0]->json()['Category']);
$result = $index->getCourseList();
View::share('result', $result); //This line shares the $result globally across all the views in laravel 4.2
}
This can be done with a Service Provider. You can either use an existing one or create a new one.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\ExampleModel;
class ViewServiceProvider extends ServiceProvider
{
public function boot()
{
$index = new ExampleModel;
$data = $index->getExampleList();
view()->share('public.index', $data);
}
public function register()
{
}
}
Source: EasyLaravel.com

Passing the same data over different views in Laravel

I have for example this code in my HomeController:
public function index() {
$comments = Comment::get_recent();
$top = User::get_top_uploaders()->get();
$top_something = User::get_top_something_uploaders()->get();
$data = Post::orderBy('created_at', 'DESC')->paginate(6);
return View::make('index') ->with('data', $data)
->with('comments', $comments)
->with('top', $top)
->with('top_something', $top_something);
}
It works great, but I need to make another couple of view with the same data not only for index but also for other pages like comments(), post()...
How to make this in HomeController that I don't need to make it copy and paste those variables in every controller?
Pass your data using share method:
// for single controller:
class SomeController extends BaseController {
public function __construct()
{
$data = Post::orderBy('created_at', 'DESC')->paginate(6);
View::share('data', $data);
}
}
For all controllers you can put this code in BaseController's constructor
If the data is displayed using the same HTML each time you could put that piece of HTML into a partial and then use a View Composer.
Create a view and call it whatever you want and put in your HTML for the data.
In templates that need that partial include it #include('your.partial')
In either app/routes.php or even better app/composers.php (don't forget to autoload it)
View::Composer('your.partial', function($view)
{
$data = Post::orderBy('created_at', 'DESC')->paginate(6);
$view->with('data', $data);
});
Now whenever that partial is included in one of your templates it will have access to your data

Laravel 4: Reference controller object inside filter

I have a controller in Laravel 4, with a custom variable declared within it.
class SampleController extends BaseController{
public $customVariable;
}
Two questions: Is there any way I can call within a route filter:
The controller object where the filter is running at.
The custom variable from that specific controller ($customVariable).
Thanks in advance!
as per this post:
http://forums.laravel.io/viewtopic.php?pid=47380#p47380
You can only pass parameters to filters as strings.
//routes.php
Route::get('/', ['before' => 'auth.level:1', function()
{
return View::make('hello');
}]);
and
//filters.php
Route::filter('auth.level', function($level)
{
//$level is 1
});
In controllers, it would look more like this
public function __construct(){
$this->filter('before', 'someFilter:param1,param2');
}
EDIT:
Should this not suffice to your needs, you can allways define the filter inside the controller's constructor. If you need access to the current controller ($this) and it's custom fields and you have many different classes you want to have that in, you can put the filter in BaseController's constructor and extend it in all classes you need.
class SomeFancyController extends BaseController {
protected $customVariable
/**
* Instantiate a new SomeFancyController instance.
*/
public function __construct()
{
$ctrl = $this;
$this->beforeFilter(function() use ($ctrl)
{
//
// do something with $ctrl
// do something with $ctrl->customVariable;
});
}
}
EDIT 2 :
As per your new question I realised the above example had a small error - as I forgot the closure has local scope. So it's correct now I guess.
If you declare it as static in your controller, you can call it statically from outside the controller
Controller:
class SampleController extends BaseController
{
public static $customVariable = 'test';
}
Outside your controller
echo SampleController::$customVariable
use:
public function __construct()
{
$this->beforeFilter('auth', ['controller' => $this]);
}

Resources