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
Related
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.
I have a blade file in Laravel, called products.blade.php. Inside of that file, I'm including a sub-view, which displays data from the database. The sub-view is fetching the data using a View Composer (to avoid writing the same code everywhere I need to display that data).
Is it possible to pass the name of the "main" view to that View Composer?
In my AppServiceProvider I have this code:
view()->composer('*', function ($view) {
view()->share('view_name', $view->getName());
});
So the sub-view knows the name of the parent view. I've tried:
#include('sub-view.name', ['parent' => $view_name])
and tried to access that parent variable in the View Composer but I get: Undefined variable: parent.
I've also tried $view->getName() in the compose method of the View Composer, however it gives me the name of the sub-view and I need the parent.
Any help would be appreciated.
Thanks in advance
All the view data is accessible by using $view->getData() method.
So in the view composer you can do
class MyCustomComposer
{
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$currentView = $view->getData()['view_name'];
// Do something
}
}
I have setup my navigation menu from a ViewComposer (see laravel view composers: https://laravel.com/docs/5.6/views#view-composers) like this
View::composer('partials.nav', function ($view) {
$view->with('menu', Nav::all());
});
What I need is that from some controllers to setup which navigation item is active, ie "current section".
Question:
How do I send from some controllers a variable to "partials.nav" like currentNavItem?
Do I send it with the rest of the variables for returned view?
like
return view('page.blade.php",$viewVariables + $optionalVariablesForPartialsViews);
It looks spammy
Side notes:
I use laravel 5.6
Later edit
It looks Laravel 5.1 : Passing Data to View Composer might be an options. I will try and get back .
Because the $variable you want to send differs in different controller's actions yes you need to specify the $variable
return view('page.blade.php",$viewVariables,$variablesForPartialsViews);
of course you might need to set a default value for the $variable in order to avoid undefined variable error
You should handle the parameters.
for exemple:
public function compose(View $view)
{
$view->with('page', $this->getPage());
}
public function getPage()
{
$viewVariables = 2;
$optionalVariablesForPartialsViews = 1;
return $viewVariables + $optionalVariablesForPartialsViews;
}
Under your app folder make a class named yourClassNameFacade. Your class would look like this.
class yourClassNameFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'keyNameYouDecide';
}
}
Then go to the file app/Providers/AppServiceProvider.php and add to the register function
public function register()
{
$this->app->bind('keyNameYouDecide', function (){
//below your logic, in my case a call to the eloquent database model to retrieve all items.
//but you can return whatever you want and its available in your whole application.
return \App\MyEloquentClassName::all();
});
}
Then in your view or any other place you want it in your application you do this to reference it.
view is the following code:
{{ resolve('keyNameYouDecide') }}
if you want to check what is in it do this:
{{ ddd(resolve('keyNameYouDecide')) }}
anywhere else in your code you can just do:
resolve('keyNameYouDecide'))
I wanted to create a custom basepath helper to replace the original zf2 basepath view helper.
So if i call $this->basepath, it will use my custom basepath instead of the original one. I am not sure if this is can be done. I want my custom basepath extends the original basepath class too.
I have found some answers on how to create custom helpers and how to register them in module.php or module.config.php
But i can't find any similar questions on how to override the original helpers!
Factory definition of the basepath view helper is declared as a hardcoded invokable in HelperPluginManager (on line 45) however this definition also overridden in ViewHelperManagerFactory (line 80 to 93) because BasePath view helper requires the Request instance from ServiceLocator:
$plugins->setFactory('basepath', function () use ($serviceLocator) {
// ...
})
I strongly recommend extending the built-in basepath helper with a different name (MyBasePath for example) instead of trying to override the existing one. Overriding that native helper may produce some unexpected headaches later (think about 3rd party modules which uses that helper to work).
For your question; yes, it is possible.
Create the Application\View\Helper\BasePath.php helper class like below:
namespace Application\View\Helper;
use Zend\View\Helper\BasePath as BaseBasePath; // This is not a typo
/**
* Custom basepath helper
*/
class BasePath extends BaseBasePath
{
/**
* Returns site's base path, or file with base path prepended.
*/
public function __invoke($file = null)
{
var_dump('This is custom helper');
}
}
And override the factory in the onBootstrap() method of the Module.php file like below:
namespace Application;
use Zend\Mvc\MvcEvent;
use Application\View\Helper\BasePath; // Your basepath helper.
use Zend\View\HelperPluginManager;
class Module
{
/**
* On bootstrap for application module.
*
* #param MvcEvent $event
* #return void
*/
public function onBootstrap(MvcEvent $event)
{
$services = $event->getApplication()->getServiceManager();
// The magic happens here
$services->get('ViewHelperManager')->setFactory('basepath', function (HelperPluginManager $manager) {
$helper = new BasePath();
// Here you can do whatever you want with the instance before returning
return $helper;
});
}
}
Now you can try in any view like this:
echo $this->basePath('Bar');
This is not a perfect solution but it should work.
I'm returning data from Controller like this:
/**
* Password request sent
*
* #return array
*/
public function passwordRequestSentAction ()
{
return array(
'foo' => $this->bar,
);
}
But $this->foo is null within layout.phtml even though its correct within controller/passwordRequestSent.phtml
I had to create postDispatch method in my abstract controller and link to it in attachDefaultListeners() and do this in postDispatch:
$e->getViewModel()->setVariables($e->getResult()->getVariables());
Is that really the way to go? I simply want to share all my variables across, no matter if its layout or page template.
You can access the layout-template by calling $this->layout():
class MyController extends AbstractActionController
{
public function myAction()
{
$layout = $this->layout();
// Returns the ViewModel of the Layout
}
}
For more information & samples check the manual's examples.
However in most cases I'd suggest writing a viewhelper for these tasks - especially for navigation/... This encapsulates the controller's logic from viewing tasks like I want the navigation displayed here or Show me the user's login box. Same goes for almost every type of status messages.