How can I set a "default" view and/or controller so it will be always called no matter the route?
I have tried with:
(routes.php)
Route::get('/*', function(){
return View::make('master');
});
and:
Route::get('*', function(){
return View::make('master');
});
But gives me NotFoundHttpException;
Related question: Is there a better way to do this than setting it in the routes.php?
Thanks!
Laravel have something called Controller Layouts, then in your controller you can create a variable named $layout and set it to a master or default view:
class Controller extends BaseController
{
protected $layout = 'layout.master';
public function getIndex() {
$data[];
$this->layout->content = View::make('myview', $data);
}
Now in the layout.master view you can access the $content variable.
Related
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);
}
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.
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
I wanted to ask how can I define a multiple layouts for the same controller in Laravel.
The scenario here is like the following:
I have a controller Home and i have two actions in this controller one called steps and the other called login.
I want the both of them load different layout.
The way that I used to make this is as follow:
protected $layout = "layouts.page";
public function index()
{
// Get to the page of the website making steps
$this->layout->content = View::make('steps');
}
Can I define multiple layouts? Maybe passing an array as follow:
protected $layout = array('first' => "layouts.page", 'second' => 'layouts.second');
Best solution is to create a method to generate your view, nesting your multiples layouts :
return View::make('layouts.master', array())
->nest('section_one', YOUR_SECOND_MASTER, array())
->nest...
and stop setting protected $layout with a layout.
I achieve in this way
$this->layout = View::make('layout.master');
$this->layout->content = View::make('step.demo')
Use View Composers or look at the section passing sub-views to views under http://laravel.com/docs/responses#views.
You can also specify multiple sections for the layout that is defined at http://laravel.com/docs/templates#blade-templating
EDIT:
If you want to define a master layout for different views from the same controller, then define the layout on the View it self. Take a look at the section Using A Blade Layout
The #extends is used to define the layout on the view itself.
Hope this helps for what you are looking for.
If you look at the BaseController, which your controller likely extends, you'll see the layout variable is ultimately used simply as th e result of any old View.
In other words, your $layout variable is just a View. You can create any $layout variable in your controller:
<?php
class MyController extends BaseController {
protected $layout;
protected $layout_alt;
// Here we're over-riding setupLayout() from
// the BaseController
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
if ( ! is_null($this->layout_alt))
{
$this->layout_alt = View::make($this->layout_alt);
}
}
}
Then in your view, you can return:
$this->layout_alt->content = View::make('steps');
Of course, the possibilities are endless as Abishek R Srikaanth pointed out. You can do fancy things with Blade as well :D
The way i do this is quite similar to #fideloper's answer.
protected $layout;
private $_layout = null;
public function __construct()
{
}
private function _setupLayout()
{
if ( ! is_null($this->_layout))
{
$this->layout = View::make($this->_layout);
}
}
public function home() {
$this->_layout = 'layouts.1col_public';
$this->_setUpLayout();
$this->layout->content = View::make('static/home');
}
public function about() {
$this->_layout = 'layouts.2col_public';
$this->_setUpLayout();
$this->layout->active_menu = 'about';
$this->layout->content = View::make('static/default');
}
This isn't common practise, and I haven't tested it yet, but it's worth a try.
In your controller's method:
$this->layout = View::make('layouts.master1");
I am trying to extend the CI_Controller class to load my global page header file so I don't have to load it at the beginning of every single controller method. It doesn't seem to be working. I know the Controller extension itself works... if I remove the call of the model method from the constructor and load it from my controller method, the rest of the controller extension works fine. But when I load the model method from within the constructor of the controller extension, I get a blank page(I haven't generated the main content yet).
Any ideas?
application/core/MY_Controller.php
<?php
class MY_Controller extends CI_Controller {
var $user = array();
function __construct(){
parent::__construct();
$this->load->model('member');
if($this->session->userdata('member_id')){
$this->member->get_info($this->session->userdata('member_id'));
$this->user = $this->member->info;
$this->member->update_activity($this->session->userdata('member_id'));
} else {
$this->load->helper('cookie');
if(get_cookie('Teacher Tools Member Cookie')){
$this->member->auto_login(get_cookie('Teacher Tools Member Cookie'));
} else {
$this->user = $this->member->default_info();
}
}
$this->load->model('template');
$this->template->overall_header();
}
}
application/models/template.php
<?php
class Template extends MY_Model {
function __construct(){
parent::__construct();
}
function overall_header($title = 'Home'){
$data = array(
'BASE_URL' => base_url(),
'MAIN_NAVIGATION' => $this->main_navigation(),
'TOOLBAR' => $this->toolbar()
);
return $this->parser->parse('overall_header.tpl', $data);
}
MY_Model is an extension of the CI_Model class to load member information into $this->user.
I think response generation is done in Controller's method and all HTML pieces that you might have gets glued there. So if you are calling /controller/method_a then method_a will be responsible for returning response whereas in constructor you cannot set response.
I agree with you on setting important data in Constructor once so that you don't have to do this again and again in each method. I think you should assign output to some Controller level variable and then use that variable in your Controller's method.
I' am sure you got my point.
For this reason there is a config/autoload.php:
$autoload['model'] = array('YourModel');