I'm starting a large codeigniter project and would like to try to create some reusable 'mini' views for snippets of content like loops of data which may be displayed on different pages/controllers.
Is it better to call the views from within the main controller's view? If so, how? Or should I call the 'mini view' from the controller and thus pass the view's code to the main view?
Views within other views are called Nested views.
There are two ways of including nested views in CodeIgniter:
1. Load a nested view inside the controller
Load the view in advance and pass to the other view. First put this in the controller:
<?php
// the "TRUE" argument tells it to return the content, rather than display it immediately
$data['menu'] = $this->load->view('menu', NULL, TRUE);
$this->load->view ('home', $data);
?>
Then put <?=$menu?> in your view at the point you want the menu to appear.
2. Load a view "from within" a view
First put this in the controller:
<?php
$this->load->view('home');
?>
Then put this in the /application/views/home.php view:
<?php $this->view('menu'); ?>
<p>Other home content...</p>
About best method, I prefer the 1st method over 2nd one, because by using 1st method I don't have to mix up code, it is not like include php. Although indirectly both are same, the 1st method is clearer & cleaner than 2nd one!
Honestly I prefer to do this by having template views then loading that with the necessary data from the controller, it means a lot less repeated code and follows the DRY concept better than loading views from views. Especially for things like headers, footers and menus.
So my template view would look something like this:
template.php
$this->load->view('header',$title);
$this->load->view('sidebar',$sidebar_content);
$this->load->view('main_content',$main_content);
$this->load->view('footer');
Then in my controller I pass the data required to the template like this:
$data['title'] = 'Home Page';
$data['sidebar_content']='pages/standard_sidebar';
$data['main_content'] ='pages/my_home_page';
$this->load->view('template',$data);
There are a number of benefits to doing it this way. First is I can have multiple templates, for example I have, in my case, two main ones, one for full page views without a sidebar and one for pages with a sidebar, I also call an if statement to decide which header to include, the regular one or the one with the admin menu in it.
Yes I could include the header, sidebar and footer in every main view page, but that ends up in a ton of duplicate code. And what happens if for example I want all my pages to have something new, some other small snippet? Using templates I add the snippet to the appropriate template and it's done. Going the other route I find every page and add the snippet view there, it's the equivalent to having CSS in the page in my opinion, wasteful and not ultimately maintainable.
METHOD 1
I use this method into my view to insert the include view where I want
$this->load->view('include/include_view');
METHOD 2
or in the controller you can load more than a view like this:
$this->load->view('header_view');
$this->load->view('list_view');
$this->load->view('footer_view');
No one method is better than the other, it depends if you have to pass some data (in this case use method2) or if you want to include a view in a specific part of your main view (in this case is better to use method1)
METHOD 3
Passing data to your include view by your main view
into your controller:
$data['title'] = "Title";
$this->load->view('main_view',$data);
in your view
$data2['title'] = $title;
$this->load->view('include/include_view',$data2);
If you want to pass entire data to your include view you can do in this way:
in your controller:
$data['nestedView']['title'] = 'title';
in your view
$this->load->view('includes/included_view', $nestedView);
This a simple way of including views within views.there is no need to load views in advance.just pass view path to other view.
In your controller use this:
$data['middle'] = 'includeFolder/include_template_view'; //the view you want to include
$this->load->view('main_template_view',$data); //load your main view
and in main_template_view you can include other views :
$this->load->view($middle);
In my opinion for solve in more efficient way this problem I have done so:
You create a new helper (in application/helpers) with name (es. common_helpers.php, the underscore is important). In this file, you put all the functions for example build pieces of html in common.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
function getHead(){
require_once(APPPATH."views/common/head.php");
}
function getScripts(){
require_once(APPPATH."views/common/scripts.php");
}
function getFooter(){
require_once(APPPATH."views/common/footer.php");
}
In your controller you call only one view in respect of MVC and call the functions from your custom helper.
class Hello extends CI_Controller {
public function index(){
$this->load->helper('common');
$this->load->view('index');
}
}
In the controller
controller
<?php
public function view($page = NULL)
{
if ( ! file_exists(APPPATH.'views/pages/'.$page.'.php'))
{
$data['title'] = ucfirst($page); // Capitalize the first letter
// Whoops, we don't have a page for that
show_404();
}
$data= array('');
$data['title'] = ucfirst($page); // Capitalize the first letter
$data['page_layout']='pages/'.$page;
$this->load->view('page_layout', $data);
}
?>
In the Views folder create a page called page_layout.php
page_layout.php
//This is where you set the layout to call any view through a variable called $page_layout declared in the controller//
<?php
$this->load->view('header');
$this->view($page_layout);
$this->load->view('footer');
?>
Related
I am doing a small project using Yii2.
Suppose I have same layout (header, footer) in a view (eg site) except a login.php in this view. I want a different or no header / footer in this file. What can I do the remove the header / footer only from this view file.
All I could get to change layout in different views. Is it possible to change layout in a single file of a view?
Inside the relative action:
public function actionYourAction($id)
{
$this->layout = 'yourNewLayout';
return $this->render('yourView', [
'model' =>$model,
]);
}
I am a little late to the party, but you CAN change your layout from within your view. You do not have to declare it in your controller. I personally think it is better to do it in the view, because you can easily see later what is going on. If your making HTML edits, you would go into the view file, and easily be able to see which layout it is using. Putting this in the Controller, you (or someone later on) might miss the layout change nested into your controller's action.
Since $this refers to your view in Yii2 and not your controller as it did in Yii1, the old $this->layout doesn't work anymore from within your view.
Now, in Yii2, you refer to the controller from your view using $this->context.
$this->context->layout = 'your-layout';
In my project I wanted 2 layouts: one for site and one for the webapp. As the main.php file is the default layout, I've created a site.php layout and in the beginning of the siteController, just after the class declaration, I've put
public $layout = 'site';
The result is that only the siteController rendered views are using the site.php layout. It worked for me.
I'm also a litte late to the party, but struggled with this stuff today...
To me, to create a separate layout just because I want to skip the footer or header seems like much code for little win. If I can stick to the main layout, I can just get at the controller and the action
currently loaded, and have it omitted this way (write this in main.php):
$contr = Yii::$app->controller->id;
$action = Yii::$app->controller->action->id;
$skipFooter = $contr == 'site' && $action == 'login'; //...or enter here what U want
... and then later:
<?php if (!$skipFooter): ?> //Never at login...
<footer class="footer">
<div class="container">
<p class="pull-left">© YourSite.com <?= date('Y') ?></p>
<p class="pull-right"><?= Yii::powered() ?></p>
</div>
</footer>
<?php endif; ?>
As an admin I can create pages (don't think I have to paste my adminpagescontroller here, because you understand the logic). What I'm getting stuck on, is selecting, but especially using the layout that will be used for the page.
i.e. I have three layouts:
page with left sidebar
page with right sidebar
page with full-width (no sidebars)
And i.e. I want to create a salespage or so, which uses the layouts "page with full-width". How can I call this in my view?
Now all my views begin with #extends('layouts.path.file') <--- I need that to be filled in by the database, if you know what I mean.
One way of doing it is to use a view composer to define the current layout to be used. View composers set variables that can be used by all your views ('*') or just some ('users.profile', 'admin.profile'), so this is an example of using a user specific layout:
View::composer('*', function($view)
{
$view->with('userLayout', Auth::check() ? Auth::user()->layout : 'main');
});
And in your view you just have to:
#extends('layouts.'.$userLayout);
If you just need to select a page on your controller, you can pass a layout to it:
return View::make('myview')->with('layout', 'front.main');
And use it in your view:
#extends('layouts.'.$layout);
And if you have it on a table, you can just pass it on:
$layout = Pages::first()->layout;
return View::make('myview')->with('layout', $layout);
Or do the same in your composer
View::composer('*', function($view)
{
$layout = Pages::first()->layout;
$view->with('layout', $layout);
});
A lot of people like to set the layout in controller too, so you could in your controller do:
public function showProfile()
{
$this->layout = Pages::first()->layout;
$this->layout->content = View::make('user.profile');
}
And your views doesn't have to #extend a layout anymore, because you are already telling them which layout to use.
i am using laravel's blade template and i have a master template for all my pages. In the master template i have a top bar and a sidebar. I want to load something in the sidebar. But i don't know how do it in a simpler way. Now i am calling that method (which i want in to display in my sidebar) in every controller i have like this:
View::make()->with('data_to_load_in_sidebar',$data_to_load_in_sidebar)
How can i load this only once, not every time i generate a view?
This is what view composers are for, any view that is loaded will automatically have it's composer run alongside providing the view with any extra data it may require.
View::composer(array('partials.sidebar'), function($view)
{
$news = News::all();
$view->with('news', $news);
});
I typically put this in my routes.php file in both L3 and L4.
In the view views\partials\sidebar.blade.php you now always have access to the variable $news that will contain all models from the News collection.
I would share top bar & sidebar data in constructor (prefferably in some BaseController's contructor, that other controllers extends).
public function __construct()
{
// if needed, call parent's contructor method as well
parent::__construct()
$data_to_load_in_sidebar = loadDataForSidebar();
View::share('data_to_load_in_sidebar',$data_to_load_in_sidebar)
}
I'm starting a large codeigniter project and would like to try to create some reusable 'mini' views for snippets of content like loops of data which may be displayed on different pages/controllers.
Is it better to call the views from within the main controller's view? If so, how? Or should I call the 'mini view' from the controller and thus pass the view's code to the main view?
Views within other views are called Nested views.
There are two ways of including nested views in CodeIgniter:
1. Load a nested view inside the controller
Load the view in advance and pass to the other view. First put this in the controller:
<?php
// the "TRUE" argument tells it to return the content, rather than display it immediately
$data['menu'] = $this->load->view('menu', NULL, TRUE);
$this->load->view ('home', $data);
?>
Then put <?=$menu?> in your view at the point you want the menu to appear.
2. Load a view "from within" a view
First put this in the controller:
<?php
$this->load->view('home');
?>
Then put this in the /application/views/home.php view:
<?php $this->view('menu'); ?>
<p>Other home content...</p>
About best method, I prefer the 1st method over 2nd one, because by using 1st method I don't have to mix up code, it is not like include php. Although indirectly both are same, the 1st method is clearer & cleaner than 2nd one!
Honestly I prefer to do this by having template views then loading that with the necessary data from the controller, it means a lot less repeated code and follows the DRY concept better than loading views from views. Especially for things like headers, footers and menus.
So my template view would look something like this:
template.php
$this->load->view('header',$title);
$this->load->view('sidebar',$sidebar_content);
$this->load->view('main_content',$main_content);
$this->load->view('footer');
Then in my controller I pass the data required to the template like this:
$data['title'] = 'Home Page';
$data['sidebar_content']='pages/standard_sidebar';
$data['main_content'] ='pages/my_home_page';
$this->load->view('template',$data);
There are a number of benefits to doing it this way. First is I can have multiple templates, for example I have, in my case, two main ones, one for full page views without a sidebar and one for pages with a sidebar, I also call an if statement to decide which header to include, the regular one or the one with the admin menu in it.
Yes I could include the header, sidebar and footer in every main view page, but that ends up in a ton of duplicate code. And what happens if for example I want all my pages to have something new, some other small snippet? Using templates I add the snippet to the appropriate template and it's done. Going the other route I find every page and add the snippet view there, it's the equivalent to having CSS in the page in my opinion, wasteful and not ultimately maintainable.
METHOD 1
I use this method into my view to insert the include view where I want
$this->load->view('include/include_view');
METHOD 2
or in the controller you can load more than a view like this:
$this->load->view('header_view');
$this->load->view('list_view');
$this->load->view('footer_view');
No one method is better than the other, it depends if you have to pass some data (in this case use method2) or if you want to include a view in a specific part of your main view (in this case is better to use method1)
METHOD 3
Passing data to your include view by your main view
into your controller:
$data['title'] = "Title";
$this->load->view('main_view',$data);
in your view
$data2['title'] = $title;
$this->load->view('include/include_view',$data2);
If you want to pass entire data to your include view you can do in this way:
in your controller:
$data['nestedView']['title'] = 'title';
in your view
$this->load->view('includes/included_view', $nestedView);
This a simple way of including views within views.there is no need to load views in advance.just pass view path to other view.
In your controller use this:
$data['middle'] = 'includeFolder/include_template_view'; //the view you want to include
$this->load->view('main_template_view',$data); //load your main view
and in main_template_view you can include other views :
$this->load->view($middle);
In my opinion for solve in more efficient way this problem I have done so:
You create a new helper (in application/helpers) with name (es. common_helpers.php, the underscore is important). In this file, you put all the functions for example build pieces of html in common.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
function getHead(){
require_once(APPPATH."views/common/head.php");
}
function getScripts(){
require_once(APPPATH."views/common/scripts.php");
}
function getFooter(){
require_once(APPPATH."views/common/footer.php");
}
In your controller you call only one view in respect of MVC and call the functions from your custom helper.
class Hello extends CI_Controller {
public function index(){
$this->load->helper('common');
$this->load->view('index');
}
}
In the controller
controller
<?php
public function view($page = NULL)
{
if ( ! file_exists(APPPATH.'views/pages/'.$page.'.php'))
{
$data['title'] = ucfirst($page); // Capitalize the first letter
// Whoops, we don't have a page for that
show_404();
}
$data= array('');
$data['title'] = ucfirst($page); // Capitalize the first letter
$data['page_layout']='pages/'.$page;
$this->load->view('page_layout', $data);
}
?>
In the Views folder create a page called page_layout.php
page_layout.php
//This is where you set the layout to call any view through a variable called $page_layout declared in the controller//
<?php
$this->load->view('header');
$this->view($page_layout);
$this->load->view('footer');
?>
I have a site that has a lot of pages that lye at the root (ex. /contact, /about, /home, /faq, /privacy, /tos, etc.). My question is should these all be separate controllers or one controller with many methods (ex. contact, about, index within a main.php controller )?
UPDATE:
I just realized that methods that are within the default controller don't show in the url without the default controller (ie. main/contact wont automatically route to /contact if main is the default controller ). So you would need to go into routes and override each page.
If all of these are just pages, I would recommend putting them into a single controller. I usually end up putting static pages like this into a 'pages' controller and putting in routes for each static page to bypass the '/pages' in my URLs.
If they are share the same functionality, so they should be in the same controller.
for example, if all of them are using the same model to take content from, so, one controller can easily handle it.
Why in one controller? because you always want to reuse your code.
class someController{
function cotact(){
print $this->getContentFromModel(1);
}
function about(){
print $this->getContentFromModel(2);
}
function home(){
print $this->getContentFromModel(3);
}
private function getContentFromModel($id){
return $this->someContentModel->getContentById($id);
}
}
(instead of print, you should use load a view)
See in my example how all of the function are using the same getContentFromModel function to share the same functionality.
but this is one case only, there could be ther cases that my example can be bad for...
in application/config/routes.php
$route['contact'] = "mainController/contact";
$route['about'] = "mainController/about";
$route['home'] = "mainController/home";
$route['faq'] = "mainController/faq";
$route['privacy'] = "mainController/privacy";
and you should add all of these methods within the mainController.php
You can also save the content of the pages in your database, and them query it. For instance, you can send the url as the keyword to identify the page content
$route['contact'] = "mainController/getContent/contact";
$route['about'] = "mainController/getContent/about";
$route['home'] = "mainController/getContent/home";
$route['faq'] = "mainController/getContent/faq";
$route['privacy'] = "mainController/getContent/privacy";
in this case you only have to create one method named "getContent" in the controller "mainController" and this method will look something like this:
class mainController extends CI_Controller
{
public function getContent($param)
{
$query = $this->db->get_where('mytable', array('pageName' => $param));
// then get the result and print it in a view
}
}
Hope this works for you
The page names you listed should probably be different methods inside your main controller. When you have other functionality that is related to another specific entity, like user, you can create another controller for the user entity and have different methods to display the user, update the user, register the user. But its all really a tool for you to organize your application in a way that makes sense for your domain and your domain model.
I've written a blog post about organizing CodeIgniter controller methods that might be helpful to you. Check it out here: http://caseyflynn.com/2011/10/26/codeigniter-php-framework-how-to-organize-controllers-to-achieve-dry-principles/