What is the best practice for displaying multiple views in Codeigniter? - model-view-controller

I'm trying to determine the best practice for calling multiple views from the same method in a controller.
Is it preferable in the controller to make one view call, then have that view call all the views it needs, or call all the views you need in sequence in the controller?
Example:
function index(){
//set all data variables
//then send them to the view
$this->load->view($index_view, $data);
}
or
function index(){
//set variables
//then call each view
$this->load->view($header_view, $header_data);
$this->load->view($body_view, $body_data);
$this->load->view($footer_view, $footer_data);
The Codeigniter guide shows both ways, but does not seem to advise to the best practice...is there one?

I didn't like the way of including the header/footer within the view, and I didn't like loading the footer and header each time in every single Controller function.
To fix this, I extended the Controller class with my own view display function.
<?php
// in application/libraries/MY_Controller.php
class MY_Controller extends Controller {
function _displayPage($page, $data = array()) {
$this->view->load('header', $data);
$this->view->load($page, $data);
$this->view->load('footer', $data);
}
}
?>
// in application/controllers/home.php
<?php
class Home extends MY_Controller {
function index() {
$this->_displayPage('home/index', array('title' => 'Home'));
}
}
?>
Not sure if this is CodeIgniter "best practice" but it makes sense to me.

I don't think there is a definitive answer for that. Choose one and stick with it, it's important to be consistent.
Anyway, I'd prefer the second one.

I would say that the controller should only display one view. Then it's up to the view if it wants to show a header, footer, sidebar or whatever. The controller shouldn't have to care, its job is to get data from a model and hand it to a view. Not decide if the view should have a header and a footer.

Agree with Christian Davén: its view / display logic not data or business / logic. essentially its the same as using php includes for snippets like navigation, footer etc. you're just embedding markup.

This is expected behavior. Once variables are set they become available within the controller class and its view files. Sending an array in $this->load->view() is the same as sending an array directly to $this->load->vars() before calling the view file. This simplifies things for most people using multiple views in a controller. If you are using multiple view files in a single controller and want them to each have their own set of variables exclusively, you’ll need to manually clear out the $this->load->_ci_cached_vars array between view calls.
A code comment in the Loader class describes another situation showing why this is the desired default behavior:
You can either set variables using the dedicated $this->load_vars()
function or via the second parameter of this function. We'll merge
the two types and cache them so that views that are embedded within
other views can have access to these variables.

Related

Laravel include view

I want to include a view like so: #include(user.myview), but within this view I need UserController logic. So I thought about calling a route: #include( route('user.route') ) which calls a Controllerfunction and returns the view but that isn't working. Any Ideas how to deal with this problem?
You need to create view composer and use it to get the data.
View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location.
Simply add a link in you view and include it in your desired location.
Link will have a route.
On clicking the link, controller method can be called. e.g. show_link.blade.php
In your show_link.blade.php view:
<a href= {{route('route-name')}} > Click here</a>.
This route will call a method via .
Route::get('/call/method', 'controller#your_method_name')->name('route-name');
In controller, method your_method_name that will look like this:
public function your_method_name()
{
return "show what you want to";
}

How to make a laravel 5 view composer

I'm still learning Laravel and I'm working on a small project to help me understand better. In the project, I am in need of a global array, so that I may display it or its attributes on every view rendered. sort of on a notification bar, so that each page the user visits, he/she can see the number of notifications (which have been fetched in the background and are stored in the array).
I have done some research, and realized that I have to fetch and compile the array in a view composer I think. But everywhere I go, I cant seem to understand how to make a view composer.
I need to fetch the relevant rows from the database table, and make the resulting array available to each view rendered (I'm thinking attaching it somehow to my layouts/default.blade.php file.). Please help, any and all advice is greatly appreciated:)
You can now inject services on your view
More info here: https://laracasts.com/series/whats-new-in-laravel-5-1/episodes/2
You have to use Sub-Views of laravel blade. I guess your functionality is like a sidebar or like a top bar which will be rendered at every page.
//Your Controller pass data
class YOUR_CONTROLLER extends Controller {
public function index()
{
$data = YOUR_DATA;
return view('YOUR_VIEW_FILE', get_defined_vars());
}
}
//In Your View File
#extends('LAYOUTS_FILE')
#section('YOUR_SECTION')
#include('YOUR_SUB_VIEW_FOR_NOTIFICATION')//You need not pass any data passed all data will be available to this sub view.
#endsection
In your sub view
//Do what ever you want looping logic rendering HTML etc.
//In your layout file just yield or render the section that's it
#yield('YOUR_SECTION')
More explanation can be found Including Sub-Views

Custom MVC Framework: How do I propogate data to a view?

I am creating a custom MVC framework.
I verrrrry loosely modeled it after the codeIgniter framework, but it's ground-up custom for the most part.
I'm at the point where I have URL's routing to the appropriate controller actions, but I'm stuck at the point where I generate a view that can utilize data generated by the controller.
I have views defined (static HTML with inline php ready to populate dynamic data), and I have the destructor of my base controller require()'ing the view in order to populate the browser with the view... here's the code:
public function __destruct()
{
if ($this->bSuppressView === false)
{
require(APP_PATH.'views/layout/header.php');
require(APP_PATH.'views/'.$this->sController.'/view.'.$this->sController.'.'.$this->sAction.'.php');
require(APP_PATH.'views/layout/footer.php');
}
}
Basically, when the controller is done executing, the teardown process of the base controller will then include the global header view, the controller's action's view, and then the global footer view, which should populate the webpage with everything for the URL that was requested...
HOWEVER, I cannot access any globally defined variables from the embedded php in the view code. In my bootstrap class, I define a bunch of local variables such as my config variable, etc., but the view seems to consider those variables undefined. Additionally, i'm unsure how to allow the view to access data that the controller may have generated. Where do I "stick" it to make it available to the view?
Let me know if this isn't clear, and i'll update.
Thanks!
UPDATE: I've discovered that while doing it this way, the "environment" of the views is within the controller object, which, as far as I can tell is a great thing! I don't have to propogate anything anywhere but in the controller, and I can use "$this->" in the views to get access to anything public or private from within the controller class!!!
That leaves the question: is this "normally" how it's done in MVC? What's the BEST way to propogate a view? I think this will suit my purposes, and I will post back if I discover a limitation to just treating the embedded view php as "within the scope of the calling controller"...
The way this is generally done, is that the view is actually an object. You pass that object you're variables, and that view object takes the template you gave it, includes it so that it's in the current scope, and grab the output into a variable using output buffering.
To give you a basic idea:
// controller object
$this->set('key','val');
$this->render('mytemplate');
// controller base class
$view = new View;
$view->setData($this->getData());
// view class
class View {
....
function render() {
ob_start();
include $this->resolveTemplate();
$out = ob_get_contents();
ob_end_clean();
return $out;
}

What are Partial Views?

I've been using Codeigniter in order to get accustomed to the Model-View-Controller architecture, and to try and speed up the process of making and implementing sites.
I keep seeing references to "Partial Views" but can't find a definition for the term.
Can anyone tell me what a partial view is, and where it is used?
A partial view is just a sub-view that you can include in a parent view. Let's take a look at a common example:
// Controller:
$data['myvar'] = array('element1', 'element2', 'element3');
$this->load->view('myview', $data);
// Myview:
<ul>
foreach ($myvar as $var) {
$this->load->view('partialview', array('var', $var));
}
</ul>
// Partialview:
<li><?= $var ?></li>
This is useful to repeat content according to a list.
Note that nothing differs between a view and a partialview, it's just the way you include it that defines the term.
The best way to describe a "partial view" is to think of it as a template, it displays a chunk of html with Model data passed to it.
Good examples of where to use one would be where you plan on displaying the same html over and over, like a menu or a page header or even better yet use them to display content requested using ajax.
Basically you call an action on the controller that returns the partial view from lets say jQuery and then put the returned markup into a select or div tag. Here is an example of doing that from my blog easy ajax with aspnet mvc and jquery, yes I know it asp.net mvc not php and codeigniter, but the principal is the same.

codeigniter - loading a library from a view?

I have some data that I have to display as a table.
I think I should pass the data from the controller as $data['events'] = array(.....
and then load the view to display them.
<?php
$this->load->library('table');
echo $this->table->generate($events);
?>
this doesn't work though - it gives a Fatal error: Call to a member function generate() on a non-object
If I paste the same code in the controller, obviously using ->generate($data['events'] the table gets displayed correctly.
Should I get that views can't load libraries, or I am doing something wrong?
Or maybe should I capture the output of the library in the controller and send that to the view?
If you need to call a library (and its functions) within a view, you can do this:
$CI =& get_instance();
$CI->load->library('library_name');
$CI->library_name->yourFunction();
You should run below code in the controller:
<?php
$this->load->library('table');
echo $this->table->generate($events);
?>
and store the data in variable and then send to the view.
To answer what you are doing wrong, you should know that the CodeIgniter class isn't declared in the view, and that this is the case for a reason - to abstract your PHP code from your HTML. Views should contain minimal PHP code (basic loops, conditions).
With this in mind, you should include your library as normal in the controller as follows;
controller
$this->load->library('table');
$data['events_table'] = $this->table->generate($events);
$this->load->view(....);
In the view, you simple echo the data. Although CodeIgniter allows short-hand tags, you should use standard PHP tags to keep to a convention that will work anywhere you keep your code.
view
<?php echo $events_table; ?>
You can auto-load the library in config/autoload.php
$autoload['libraries'] = array('database','session','table');
Then you can simply call the functions in your view .
echo $this->table->generate($events);
This was useful for me when i was creating a dynamic menu header . i auto-loaded the library which has the function for dynamic menu creation and then i simply called that function from the view , by the way it is bad practice .
That is one wrong approach to MVC. You don't need to load the library in the view, because all views are loaded from one CONTROLLER, so every external Helper or Library should be loaded from the controller and the used or send to the views
Regards,
Pedro
Note the shoulds: CodeIgniter is flexible in that it lets you do things the wrong way. It just makes it a little more difficult. You can do almost everything in the view, even when you shouldn't; but loading helpers, models, and views has to be done in the controller.
In controller or model use
$this->load->library('mylib');
$mylib=$this->mylib;
$data['mylib']=$mylib;
$this->load->view('myview',$data,false);
and than in view you can use library directly:
$mylib->myfunction();
It's not MVC like solution but works if you need.
Simply load library on controller, then use it view.
Controller:
$this->load->library('table');
$data = array(
array(1,2,3,4,5),
array(1,2,3,4,5),
array(1,2,3,4,5),
);
$this->load->view('the_view', compact('data'));
View:
echo $this->table->generate($data);

Resources