Pass variable in every view file - laravel - laravel

I want to send some variable in every views which contains data from database. I have written the following code in base controller because it is extended by all of the controller:
public function __construct()
{
$opening_hours = OpeningHours::first();
$social_media = SocialMedia::first();
$website = Website::first();
view()->share('opening_hours', $opening_hours)
->share('social_media', $social_media)
->share('website', $website);
}
Also I have also called parent::__construct(); in all of my controllers. But, I am still getting undefined variable $opening_hours in view file when I try to debug it. How can I send website data (website logo, contact, email) that has to be included in every views file?

Laravel provides us some features like this. You can try View Composers. These are very useful if we want some data on every screen. But we want to place this on separate place instead of writing code in every controller.
https://laravel.com/docs/master/views#view-composers
That will help us.

You can try this way
Create a one middleware and add this code into middleware and use middle where you want this data and data will be available on that view.
$opening_hours = OpeningHours::first();
$social_media = SocialMedia::first();
$website = Website::first();
view()->share('opening_hours', $opening_hours)
->share('social_media', $social_media)
->share('website', $website);

You are a file called AppServiceProvider.php inside of app/Providers folder, In there you can do the following:
<?php
namespace App\Providers;
use View;
use App\OpeningHours;
use App\SocialMedia;
use App\Website;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
public function boot()
{
$contact_details = [
'opening_hours' => OpeningHours::first(),
'social_media' = SocialMedia::first(),
'website' => Website::first(),
];
View::share('contact_details', $contact_details);
}
}
Updated and added a guess to the namespace of the models being used.

Related

Laravel installation in sub-folder and horizon not working

I have installed the Laravel in sub-folder and is trying to install the horizon. After routing to "test.com/sub-folder/horizon", all the design in broken and also the internal links are pointing to main domain instead of main-domain-without-subfolder.
After the search, it seems to be the known issue which is already reported in github issue
Has there is any work around to make horizon work when Laravel is installed in sub-folder?
I have a solution that only involves PHP.
The issue, as pointed out by #Isaiahiroko, is the basePath defined for Horizon's interface. That code is in Laravel\Horizon\Http\Controllers\HomeController::index(). The idea is this: we are going to pass to Laravel's service container our own implementation of that controller that will override the basePath definition passed to Horizon's interface.
Create a new controller with code like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Laravel\Horizon\Horizon;
use Laravel\Horizon\Http\Controllers\HomeController;
class HorizonHomeController extends HomeController
{
/**
* Overrides default horizon route to support subdirectory hosting.
*/
public function index ()
{
// We use a plain request to check for the base url.
$request = request();
// Set up our base path.
$base_path = Str::substr($request->getBasePath(), 1);
if (!empty($base_path)) {
$base_path .= '/';
}
// Patch default horizon variables with our own base path.
$variables = Horizon::scriptVariables();
$variables['path'] = $base_path . config('horizon.path');
// Render horizon's home view.
return view('horizon::layout', [
'assetsAreCurrent' => Horizon::assetsAreCurrent(),
'horizonScriptVariables' => $variables,
'cssFile' => Horizon::$useDarkTheme ? 'app-dark.css' : 'app.css',
'isDownForMaintenance' => App::isDownForMaintenance(),
]);
}
}
What's left is telling Laravel's service container that when Horizon's HomeController is requested, it should provide our HorizonHomeController class. In your AppServiceProvider, at the end of the register() method, set this up:
// [...]
class AppServiceProvider extends ServiceProvider
{
// [...]
/**
* Register any application services.
*
* #return void
* #throws InvalidConfiguration
*/
public function register()
{
// [...]
// Horizon's subdirectory hack
$this->app->bind(
Laravel\Horizon\Http\Controllers\HomeController::class,
App\Http\Controllers\HorizonHomeController::class
);
}
// [...]
}
After that, you should be able to browse to http(s)://<your-host>/<your-sub-dir>/horizon normally.
Considerations:
To me this feels cleaner that patching a compiled js, which also has the downside that needs to be re-applied every time Horizon is updated (this can be mitigated with a post-update script in composer, tho). Also, for additional points, this solution is only overriding the method that renders the view, but not the route, which means all of Horizon's authentication mechanisms (middlewares and gates) are working exactly as described in the documentation.
If you desperately need to do this, here is a hack:
In public\vendor\horizon\app.js, search for window.Horizon.basePath
replace window.Horizon.basePath="/"+window.Horizon.path; with window.Horizon.basePath="/[you sub-directoy]/"+window.Horizon.path;
It should work...until you run update one day and it mysteriously stop working.

Undefined variable error while extending the layouts

I have created a layout named front where the menu & footer are defined! The front layout contains the menu items from menu controller.
Here's my menu controller -
$menu = Menu::all();
/* some other long code */
Now i'm trying to extend the layouts using #extends('front') on posts page.
It returns the following error:
"Undefined variable: menus" in View: C:\xxxxx\layouts\front.blade.php.
I know it can be fixed by using $menu = Menu::all(); in the posts controller also.
Since the application is huge & i can't keep pasting the menu controller code in every view that is extended.
How do i make the menu controller code global, so that whenever i extend the front layouts, it doesn't give me Undefined variable error ?
You can use view composers to make a variable available to multiple views
In your app/Providers/AppServiceProvider.php boot function
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->composer(['first.view', 'second.view', 'another.view'], function ($view) {
return $view->with('menus', App\Menu::all());
});
}
And to make the variable available everywhere, use the * wildcard instead
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->composer('*', function ($view) {
return $view->with('menus', App\Menu::all());
});
}
Watch the #Watercayman's comment under your question..
But I think the thing that you want is below:
You need to show your variable in the blade where you didn't sent from controller.
In this kind of situations you can use "share" functionality from "Illuminate\Support\Facades\View".
You can just share your variable from main Controller's constructor (this can be as "App\Http\Controllers\Controller", or other as well if it takes care for all pages which uses $menu), like this:
use Illuminate\Support\Facades\View;
public function __construct()
{
// here you can write some global things for all controllers which extending from this
$menu = Menu::all();
View::share('menu', $menu);
}
If this variable is only needed by a layout, you can use a view composer for the layout to pass the variable you need.
// a service provider # boot
View::composer('layouts.front', function ($view) {
$menus = Menu::all();
...
$view->with('menus', $menus);
});
Laravel 6.0 Docs - Views - View Composers

Laravel - Share data with all views when the data is available

I'm writing a web app using Laravel 5.6. I need a list of all the connections the current session user have, in all the views.
I tried something like this
View::share('connections', Connection::getList(Auth::id()))
I put this code inside the boot function of AppServiceProvider. But the problem arises when the user isn't already logged in, because at that time Auth::id() is set to null.
The connection list is not generated when the user logs in. This throws the following error:
connections variable is not defined.
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 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

How to use global variables in Laravel

Is it possible to share and change some variable between multiple views? For example, I want to have a variable $user that will be shared between all views. When a user logs the variable is set up, when the user logs out, the variable is unset. I was unable to achieve requested using
the following combination:
in AppServiceProvider:
view()->share('var', 1);
in the controller:
$var = view()->shared('var');.
$var ++;
view()->share('var', var);
return view(''', 'var'=>$var)
Every time when the page is reloaded $var is always the same (2).
I want to have a variable $user that will be shared between all views
You should use auth()->user() to get authenticated user instance in any view.
But if you don't want to use it for some reason, you could share the variable between multiple views with a view composer.
share() method will be useful only if you want to share a variable with all views. To make it work, put view()->share('key', 'value') to the boot() method of a service provider.
Also, the code in your controller looks like you want to share data not between views, but between requests. Use session for that.
To save the data:
session(['key' => 'value']);
To get the data in another request:
session('key');
It would be better to add another service provider. Take a look at my provider:
<?php
namespace App\Providers;
use Request;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider
{
public function boot()
{
$this->globalThings();
//call another globals' function here
}
public function register()
{
//
}
/**
* Get the golbals
*/
private function globalThings()
{
view()->composer(array('*.*'),function($view){
//get the data however you want it!
$view->with('global', Model::where('field','value')->get());
});
}
And don't forget to add the service provider to list of provider is config/app.php
App\Providers\ViewComposerServiceProvider::class,

Pass data to all views AND use them in routes

I've followed this documentation to pass data to all of my views:
https://laravel.com/docs/5.2/views#sharing-data-with-all-views
However, it doesn't let me access the variables in my routes file.
How can I pass a variable to all of my views AND be able to use it in my routes file across all of my routes?
You need to think about your process. The purpose of passing a certain piece of data to all views is because that value is relevant to the view, not the route or controller action. For example, page titles or showing the user the current date at the bottom of the page.
To do what you want, take a look at the API documentation for Illuminate\View\View and you will see functions offsetGet and offsetSet.
Here's an example:
app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
view()->share('title', 'Qevo');
}
public function register()
{
//
}
}
resources/views/example.blade.php
<h1>{{ $title }}</h1>
app/Http/routes.php
Route::get('/test', function () {
// view has to be created for shared data to be set
$v = view('example');
// get the value of the shared data
$page_title = $v->offsetGet('title');
// set a new value
$v->offsetSet('title', $page_title . ' helps');
return $v;
});
I think you should use Session (or caching the data)
I think using sessions is the best way here
lets suppose you want to add somedata to the Current user session
Session::put('key', 'value');
now you can access this in your View like this
Session::get('key');
and inside your controller/routes file
$value = Session::get('key');
This way the data is available inside controller , routes file and views

Resources