I really don't enjoy writing in every controller:
$this->load->view('templates/header');
$this->load->view('body');
$this->load->view('templates/footer');
Is it possible to do, that header and footer would be included automatically and if we need to change it, we could also do that? How do you deal with that? Or it's not a problem in your opinion? Thanks.
Here's what I do:
<?php
/**
* /application/core/MY_Loader.php
*
*/
class MY_Loader extends CI_Loader {
public function template($template_name, $vars = array(), $return = FALSE)
{
$content = $this->view('templates/header', $vars, $return);
$content .= $this->view($template_name, $vars, $return);
$content .= $this->view('templates/footer', $vars, $return);
if ($return)
{
return $content;
}
}
}
For CI 3.x:
class MY_Loader extends CI_Loader {
public function template($template_name, $vars = array(), $return = FALSE)
{
if($return):
$content = $this->view('templates/header', $vars, $return);
$content .= $this->view($template_name, $vars, $return);
$content .= $this->view('templates/footer', $vars, $return);
return $content;
else:
$this->view('templates/header', $vars);
$this->view($template_name, $vars);
$this->view('templates/footer', $vars);
endif;
}
}
Then, in your controller, this is all you have to do:
<?php
$this->load->template('body');
Yes.
Create a file called template.php in your views folder.
The contents of template.php:
$this->load->view('templates/header');
$this->load->view($v);
$this->load->view('templates/footer');
Then from your controller you can do something like:
$d['v'] = 'body';
$this->load->view('template', $d);
This is actually a very simplistic version of how I personally load all of my views. If you take this idea to the extreme, you can make some interesting modular layouts:
Consider if you create a view called init.php that contains the single line:
$this->load->view('html');
Now create the view html.php with contents:
<!DOCTYPE html>
<html lang="en">
<? $this->load->view('head'); ?>
<? $this->load->view('body'); ?>
</html>
Now create a view head.php with contents:
<head>
<title><?= $title;?></title>
<base href="<?= site_url();?>">
<link rel="shortcut icon" href='favicon.ico'>
<script type='text/javascript'>//Put global scripts here...</script>
<!-- ETC ETC... DO A BUNCH OF OTHER <HEAD> STUFF... -->
</head>
And a body.php view with contents:
<body>
<div id="mainWrap">
<? $this->load->view('header'); ?>
<? //FINALLY LOAD THE VIEW!!! ?>
<? $this->load->view($v); ?>
<? $this->load->view('footer'); ?>
</div>
</body>
And create header.php and footer.php views as appropriate.
Now when you call the init from the controller all the heavy lifting is done and your views will be wrapped inside <html> and <body> tags, your headers and footers will be loaded in.
$d['v'] = 'fooview'
$this->load->view('init', $d);
Try following
Folder structure
-application
--controller
---dashboards.php
--views
---layouts
----application.php
---dashboards
----index.php
Controller
class Dashboards extends CI_Controller
{
public function __construct()
{
parent::__construct();
$data = array();
$data['js'] = 'dashboards.js'
$data['css'] = 'dashbaord.css'
}
public function index()
{
$data = array();
$data['yield'] = 'dashboards/index';
$this->load->view('layouts/application', $data);
}
}
View
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Some Title</title>
<link rel="stylesheet" href="<?php echo base_url(); ?>assets/css/app.css" />
<link rel="stylesheet" href="<?php echo base_url(); ?>assets/css/<?php echo $css; ?>" />
</head>
<body>
<header></header>
<section id="container" role="main">
<?php $this->load->view($yield); ?>
</section>
<footer></footer>
<script src="<php echo base_url(); ?>assets/js/app.js"></script>
<script src="<php echo base_url(); ?>assets/js/<?php echo $js; ?>"></script>
</body>
</html>
When you need to load different js, css or whatever in the header or footer use the __construct function to $this->load->vars
Kind of a rails like approach here
Or more complex, but makes life easy is to use more constants in boot.
So subclasses can be defined freely, and a single method to show view.
Also selected constants can be passed to javascript in the header.
<?php
/*
* extends codeigniter main controller
*/
class CH_Controller extends CI_Controller {
protected $viewdata;
public function __construct() {
parent::__construct();
//hard code / override and transfer only required constants (for security) server constants
//such as domain name to client - this is for code porting and no passwords or database details
//should be used - ajax is for this
$this->viewdata = array(
"constants_js" => array(
"TOP_DOMAIN"=>TOP_DOMAIN,
"C_UROOT" => C_UROOT,
"UROOT" => UROOT,
"DOMAIN"=> DOMAIN
)
);
}
public function show($viewloc) {
$this->load->view('templates/header', $this->viewdata);
$this->load->view($viewloc, $this->viewdata);
$this->load->view('templates/footer', $this->viewdata);
}
//loads custom class objects if not already loaded
public function loadplugin($newclass) {
if (!class_exists("PL_" . $newclass)) {
require(CI_PLUGIN . "PL_" . $newclass . ".php");
}
}
then simply:
$this->show("<path>/views/viewname/whatever_V.php");
will load header, view and footer.
I tried almost all the answers proposed on this page and many other stuff. The best option I finally keeped on all my websites is the following architecture:
A single view
I display only one view in the browser. Here is my main view (/views/page.php):
<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<?= $header ?? '' ?>
</head>
<body>
<div style="width:1200px">
<?= $content ?? '' ?>
</div>
</body>
</html>
Controllers deal with multiple views
Of course, I had several views but they are concatenated to build the $header and the $content variables. Here is my controller:
$data['header'] = $this->load->view('templates/google-analytics', '', TRUE)
.$this->load->view('templates/javascript', '', TRUE)
.$this->load->view('templates/css', '', TRUE);
$data['content'] = $this->load->view('templates/navbar', '', TRUE)
.$this->load->view('templates/alert', $myData, TRUE)
.$this->load->view('home/index', $myData, TRUE)
.$this->load->view('home/footer', '', TRUE)
.$this->load->view('templates/modal-login', '', TRUE);
$this->load->view('templates/page', $data);
Look how beautiful and clear is the source code.
You no longer have HTML markup opened in one view and closed in another.
Each view is now dedicated to one and only one stuff.
Look how views are concatenated: method chaining pattern, or should we say: concatanated chaining pattern!
You can add optional parts (for example a third $javascript variable at the end of the body)
I frequently extend CI_Controller to overload $this->load->view with extra parameters dedicated to my application to keep my controllers clean.
If you are always loading the same views on several pages (this is finally the answer to the question), two options depending on your needs:
load views in views
extend CI_Controller or CI_Loader
I'm so proud of this architecture...
A simple rewrite of #Landons MY_Loader, to include multiple files for the body, e.i. page unique sidebars...
<?php
class MY_Loader extends CI_Loader {
public function template($template_name, $vars = array(), $return = FALSE)
{
$content = $this->view('frontend/templates/header', $vars, $return);
if(is_array($template_name)) { //return all values in contents
foreach($template_name as $file_to_load) {
$content .= $this->view('frontend/'.$file_to_load, $vars, $return);
}
}
else {
$content .= $this->view('frontend/'.$template_name, $vars, $return);
}
$content .= $this->view('frontend/templates/footer', $vars, $return);
if ($return)
{
return $content;
}
}
}
This works both ways...
Including one file to template:
$data['moo'] = 'my data'];
$this->load->template('home', $data);
Include multiple files to template:
$data['catalog'] = 'catalog load 1';
$data['sidebar'] = 'sidebar load 2';
$load = array('catalog/catalog', 'catalog/sidebar');
$this->load->template($load, $data);
CodeIgniter-Assets is easy to configure repository to have custom header and footer with CodeIgniter I hope this will solve your problem.
Redefine the CI_Loader::view function by adding a file named as 'MY_Loader.php' in your application/core folder and adding the following content
/**
* /application/core/MY_Loader.php
*/
class MY_Loader extends CI_Loader
{
public function view($view, $vars = array(), $return = FALSE, $include_template=TRUE)
{
$header='';
$footer='';
if($include_template)
{
$header=parent::view('templates/header',$vars,$return);
}
$content=parent::view($view, $vars,$return);
if($include_template)
{
$footer=parent::view('templates/footer',$vars,$return);
}
if($return)
return "$header$content$footer";
return $this;
}
}
You can use your config.php file, and also use the power of helpers in CodeIgniter.
$config['header_css'] = array('style.css','prettyPhoto.css','nivo-slider.css');
$config['header_js'] = array('core.js','core.js',
'jquery-1.4.1.min.js',
'jquery-slidedeck.pack.lite.js',
'jquery-prettyPhoto.js',
'jquery.nivo.slider.js');
Source: https://jamshidhashimi.com/dynamically-add-javascript-and-css-files-in-codeigniter-header-page/
Here is how I handle mine. I create a file called template.php in my views folder. This file contains all of my my main site layout. Then from this template file I call my additional views. Here is an example:
<!doctype html>
<html lang="en">
<head>
<meta charset=utf-8">
<title><?php echo $title; ?></title>
<link href="<?php echo base_url() ;?>assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="<?php echo base_url() ;?>assets/css/main.css" rel="stylesheet" type="text/css" />
<noscript>
Javascript is not enabled! Please turn on Javascript to use this site.
</noscript>
<script type="text/javascript">
//<![CDATA[
base_url = '<?php echo base_url();?>';
//]]>
</script>
</head>
<body>
<div id="wrapper">
<div id="container">
<div id="top">
<?php $this->load->view('top');?>
</div>
<div id="main">
<?php $this->load->view($main);?>
</div>
<div id="footer">
<?php $this->load->view('bottom');?>
</div>
</div><!-- end container -->
</div><!-- end wrapper -->
<script type="text/javascript" src="<?php echo base_url();?>assets/js/jquery-1.8.2.min.js" ></script>
<script type="text/javascript" src="<?php echo base_url();?>assets/js/bootstrap.min.js"></script>
</body>
</html>
From my controller, I will pass the name of the view to $data['main']. So I will do something like this then:
class Main extends CI_Controller {
public function index()
{
$data['main'] = 'main_view';
$data['title'] = 'Site Title';
$this->load->vars($data);
$this->load->view('template', $data);
}
}
I had this problem where I want a controller to end with a message such as 'Thanks for that form' and generic 'not found etc'.
I do this under views->message->message_v.php
<?php
$title = "Message";
$this->load->view('templates/message_header', array("title" => $title));
?>
<h1>Message</h1>
<?php echo $msg_text; ?>
<h2>Thanks</h2>
<?php $this->load->view('templates/message_footer'); ?>
which allows me to change message rendering site wide in that single file for any thing that calls
$this->load->view("message/message_v", $data);
This question has been answered properly, but I would like to add my approach, it's not that different than what the others have mentioned.
I use different layouts pages to call different headers/footers, some call this layout, some call it template etc.
Edit core/Loader.php and add your own function to load your layout, I called the function e.g.layout.
Create your own template page and make it call header/footer for you, I called it default.php and put in a new directory e.g. view/layout/default.php
Call your own view page from your controller as you would normally. But instead of calling $this-load->view use $this->load->layout, layout function will call the default.php and default.php will call your header and footer.
1)
In core/Loader.php under view() function I duplicated it and added mine
public function layout($view, $vars = array(), $return = FALSE)
{
$vars["display_page"] = $view;//will be called from the layout page
$layout = isset($vars["layout"]) ? $vars["layout"] : "default";
return $this->_ci_load(array('_ci_view' => "layouts/$layout", '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return));
}
2) Create layout folder and put default.php in it in view/layout/default.php
$this->load->view('parts/header');//or wherever your header is
$this->load->view($display_page);
$this->load->view('parts/footer');or wherever your footer is
3) From your controller, call your layout
$this->load->layout('projects');// will use 'view/layout/default.php' layout which in return will call header and footer as well.
To use another layout, include the new layout name in your $data array
$data["layout"] = "full_width";
$this->load->layout('projects', $data);// will use full_width.php layout
and of course you must have your new layout in the layout directory as in:
view/layout/full_width.php
Using This Helper For Dynamic Template Loading
// get Template
function get_template($template_name, $vars = array(), $return = FALSE) {
$CI = & get_instance();
$content = "";
$last = $CI - > uri - > total_segments();
if ($CI - > uri - > segment($last) != 'tab') {
$content = $CI - > load - > view('Header', $vars, $return);
$content. = $CI - > load - > view('Sidebar', $vars, $return);
}
$content. = $CI - > load - > view($template_name, $vars, $return);
if ($CI - > uri - > segment($last) != 'tab') {
$content. = $CI - > load - > view('Footer', $vars, $return);
}
if ($return) {
return $content;
}
}
i had reached for this and i hope to help all create my_controller in application/core
then put this code in it with change as your file's name
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
// this is page helper to load pages daunamically
class MY_Controller extends CI_Controller {
function loadPage($user,$data,$page='home'){
switch($user){
case 'user':
$this->load->view('Temp/head',$data);
$this->load->view('Temp/us_sidebar',$data);
$this->load->view('Users/'.$page,$data);
$this->load->view('Temp/footer',$data);
break;
case 'admin':
$this->load->view('Temp/head',$data);
$this->load->view('Temp/ad_sidebar',$data);
$this->load->view('Admin/'.$page,$data);
$this->load->view('Temp/footer',$data);
break;
case 'visitor';
$this->load->view('Temp/head',$data);
$this->load->view($page);
$this->load->view('Temp/footer',$data);
break;
default:
echo 'wrong argument';
die();
}//end switch
}//end function loadPage
}
in your controller
use this
class yourControllerName extends MY_Controller
note : about name of controller prefix you have to be sure about your prefix on config.php file
i hope that give help to any one
Does anyone know how to upload images using PHP and calling the UploadHandler.php?
I'm not sure what information needs to be passed and in what format.
Here's what I have so far:
$prop="test";
session_id($prop);
#session_start();
$url = 'http://christinewilson.ca/wp-content/uploads/2013/02/port_rhdefence.png';
$file_name[] = file_get_contents($url);
error_reporting(E_ALL | E_STRICT);
require('UploadHandler.php');
$upload_handler = new UploadHandler(array(
'user_dirs' => true
));
The response is contained within the UploadHandler class object and can be retrieved like shown below.
$upload_handler = new UploadHandler();
$response = $upload_handler->response;
$files = $response['files'];
$file_count = count($files);
for ($c = 0; $c < $file_count; $c++) {
if (isset($files[$c]->error))
continue;
$type = $files[$c]->type;
$name = $files[$c]->name;
$url = $files[$c]->url;
}
I could not find a way to get the file name via php so I had to do it myself.
First you need to add a public variable under UploadHandler.php
class UploadHandler
{
public $file_name;
protected $options;
and then add that to the function that creates the name
protected function get_file_name($name,
$type = null, $index = null, $content_range = null) {
$this->file_name = $this->get_unique_filename(
$this->trim_file_name($name, $type, $index, $content_range),
$type,
$index,
$content_range
);
return $this->file_name;
}
then under index.php you could do something like this
$upload_handler = new UploadHandler();
echo "\r\n [" . $upload_handler->fileName . "]\r\n";
I hope this help you or save someone some time :)
you can use the basic plugin:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
</head>
<body>
<input id="fileupload" type="file" name="files[]" data-url="server/php/" multiple>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="js/vendor/jquery.ui.widget.js"></script>
<script src="js/jquery.iframe-transport.js"></script>
<script src="js/jquery.fileupload.js"></script>
<script>
$(function () {
$('#fileupload').fileupload({
dataType: 'json',
done: function (e, data) {
$.each(data.result.files, function (index, file) {
$('<p/>').text(file.name).appendTo(document.body);
});
}
});
});
</script>
</body>
I ran into the same problem, where in the PHP I wanted to write all the URLS that UploadHandler.php had created to a mySQL database. If you look through the code, you'll see that
public function post($print_response = true)
actually returns the data structure from generate_response (which is a array with all the processed image metadata like image size, sanitized url, etc), but the call to $this->post() never does anything which it. So I add a variable
protected $upload_content = [];
to the class definition and changed the logic in function
protected function initialize()
to
case 'POST':
$this->upload_content = $this->post(false);
break;
to update this variable after the images have been processed (you would need to do something similar with the GET case if you are using that). Then, I add a public function to the class to get this variable
public function get_upload_content() {
return $this->upload_content;
}
and now the UploadHandler class can be called like this
$upload_handler = new UploadHandler();
$images = $upload_handler->get_upload_content();
// Call a function that writes the urls in $images array to a database
Hope this helps!
First of all you should create protected variable:
protected $options;
protected $uploaded_files = [];
then you should assign to this variable the response value in post() method:
$this->uploaded_files = $response;
return $this->generate_response($response, $print_response);
then you should create public method which would return that response:
public function get_uploaded_files() {
return $this->uploaded_files;
}
and finally you should initiate the class and call the method:
$uploadPicture = new UploadHandler();
$images = $uploadPicture->get_uploaded_files();
Hope this Helps !
I'm in the process of working on my first code igniter project. I have some javascript that I need to write to initiate an instance of something on document ready. It's a one off, will never be called again. I need to include it in the head, but there may be a case where I need to do this at the end of the body. So, for example, lets say I have this:
<script>
alert('this is a one off alert');
</script>
What is the best practice in doing this stuff? Is it acceptable practice to put this in the controller? Does it need a model writing for it? Or do I need to create individual views for each script to be in MVC?
Thanks.
JS is part of HTML so it should not be in controller or in model, so it should be in view, as you are using framework then you should keep it in a separate file, you can have separate file for each method in your controller or one single JS file each controller.
also you can make a base_controller in your core folder and extend all your controller with it, there you can set all the default JS and CSS. so if you call an index method for a controller it will load with default JS and CSS and if need to add any new just pass it from the controller as John B said
You can have this function in your helper file
/**
* getting js files from public folder
* #param array $js
* #return string
*/
function js_tag($js) {
$out = "";
if (!empty($js)) {
$js = array_reverse($js);
foreach ($js as $j) {
if (strstr($j, "http:") == "" && strstr($j, "https:") == "") {
if ($j == 'tinymac') {
$out.='<script type="text/javascript" src="' . base_url() . 'jscripts/tiny_mce/tiny_mce.js"></script>' . "\n";
} else {
$out.='<script type="text/javascript" src="' . base_url() . 'public/js/' . $j . '"></script>' . "\n";
}
} else {
$out.='<script type="text/javascript" src="' . $j . '"></script>' . "\n";
}
}
}
$out .= '<script type="text/javascript"> var baseurl = "' . base_url() . '"</script>' . "\n";
return $out;
}
/**
* getting css files from public folder
* #author Amir M
* #param array $css
* #return string
*/
function css_tag($css) {
$out = "";
if (!empty($css)) {
$css = array_reverse($css);
foreach ($css as $c) {
if (strstr($c, "http:") == "" && strstr($c, "https:") == "") {
$out.= link_tag(base_url() . "public/css/" . $c) . "\n";
} else {
$out.= link_tag($c) . "\n";
}
}
}
return $out;
}
and you can call it from controller
public function index(){
$data['js'] = js_tag('one.js', 'two.js' , 'jquery.js');
$data['css'] = css_tag('one.css', 'two.css' , 'jquery-ui.css');
$thuis->load->view('index' , $data);
}
Note: the above method will reverse the array so the last value in the array will come first on the page so keep the jQuery last in the array
in the header which is common on all website
<?php echo $js.$css?>
generally the practice I use is this:
All view files load a common header. And the view files are loaded at the end of the controller.
You can either hardcode or pass the links for scripts you want to initiate from the controller. Hardcoding the script tags is self explanatory. If you want to do it a bit more dynamically, you could set up an array of script sources and just loop through them in the header.
so in the controller
$data['scripts'] = array();
$data['scripts'][] = 'http://yoursourcehere';
or if self hosting:
$data['scripts'][] = site_url('assets/js/yourscript.js');
then the view
if(isset($scripts))
{
foreach($scripts as $script)
{
echo '<script type="text/javascript" src="'.$script.'"></script>';
}
}
so basically you can just put all your custom script in a separate file an load it this way. Its practical because it can load all your scripts at once in a common way.
Following this tutorial http://johnsquibb.com/tutorials/mvc-framework-in-1-hour-part-one Im trying to write my first MVC Blog.
I understood how it works, router.php Calls the suitable page controller. This controller calls the model, Then calls the View page with the returned value.
My question is, What if I want to add to the same news.php page a header\footer. Normally I would write "include("header.php"). But now when using MVC, how could I implement that?
These are my files:
router.php:
<?php
/**
* This controller routes all incoming requests to the appropriate controller
*/
//Automatically includes files containing classes that are called
//fetch the passed request
$pageURL = $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
$path_parts = pathinfo($pageURL);
$page_name = $path_parts['filename'];
$parsed = explode('?' , $page_name);
//the page is the first element
$page = array_shift($parsed);
// If there is any variables, GET them.
if(!empty($parsed))
{
$parsed = explode('&' , $parsed[0]);
$getVars = array();
foreach ($parsed as $argument)
{
//explode GET vars along '=' symbol to separate variable, values
list($variable , $value) = explode('=' , $argument);
$getVars[$variable] = urldecode($value);
}
}
//compute the path to the suitable file
$target ='controllers/' . $page . '_controller.php';
//get target controller
if (file_exists($target))
{
include_once($target);
//modify page to fit naming convention
$class = ucfirst($page) . '_Controller';
//instantiate the appropriate class
if (class_exists($class))
{
$controller = new $class;
}
else
{
//did we name our class correctly?
die('class does not exist!');
}
}
else
{
//can't find the file in 'controllers'!
die('page does not exist!');
}
//once we have the controller instantiated, execute the default function
//pass any GET varaibles to the main method
$controller->main($getVars);
// AutoLoad
function __autoload($className)
{
// Parse out filename where class should be located
// This supports names like 'Example_Model' as well as 'Example_Two_Model'
list($suffix, $filename) = preg_split('/_/', strrev($className), 2);
$filename = strrev($filename);
$suffix = strrev($suffix);
//select the folder where class should be located based on suffix
switch (strtolower($suffix))
{
case 'model':
$folder = '/models/';
$filename = ($className);
break;
case 'library':
$folder = '/libraries/';
break;
case 'driver':
$folder = '/libraries/drivers/';
break;
}
//compose file name
$file = SERVER_ROOT . $folder . strtolower($filename) . '.php';
//fetch file
if (file_exists($file))
{
//get file
include_once($file);
}
else
{
//file does not exist!
die("File '$filename' containing class '$className' not found in
'$folder'.");
}
}
?>
post_controller.php
<?php
/**
* This file handles the retrieval and serving of posts posts
*/
class Posts_Controller
{
/**
* This template variable will hold the 'view' portion of our MVC for this
* controller
*/
public $template = 'posts';
/**
* This is the default function that will be called by router.php
*
* #param array $getVars the GET variables posted to index.php
*/
public function main(array $getVars)
{
//$b_controller =new Bottom_Bar_Controller;
//$b_controller->main($getVars);
$postsModel = new Posts_Model;
//get an post
$post = $postsModel->get_post($getVars['id']);
//create a new view and pass it our template
$header = new View_Model('header_template');
$bottom_bar = new View_Model('bottom_bar');
$view = new View_Model($this->template);
//assign post data to view
$view->assign('header', $header->render(FALSE));
$view->assign('bottom', $bottom_bar->render(FALSE));
$view->assign('title' , $post['title']);
$view->assign('content' , $post['content']);
$view->assign('date' , $post['date']);
$view->assign('by' , $post['added_by']);
$view->render();
}
}
posts_model.php
<?php
/**
* The Posts Model does the back-end heavy lifting for the Posts Controller
*/
class Posts_Model
{
/**
* Holds instance of database connection
*/
private $db;
public function __construct()
{
$this->db = new MysqlImproved_Driver;
}
/**
* Fetches article based on supplied name
*
* #param string $author
*
* #return array $article
*/
public function get_post($id)
{
//connect to database
$this->db->connect();
//sanitize data
$author = $this->db->escape($id);
//prepare query
$this->db->prepare
(
"
SELECT * FROM `posts`
WHERE
`id` = '$id'
LIMIT 1
;
"
);
//execute query
$this->db->query();
$article = $this->db->fetch('array');
return $article;
}
}
?>
view_model.php
<?php
/**
* Handles the view functionality of our MVC framework
*/
class View_Model
{
/**
* Holds variables assigned to template
*/
private $data = array();
/**
* Holds render status of view.
*/
private $render = FALSE;
/**
* Accept a template to load
*/
public function __construct($template)
{
//compose file name
$file = SERVER_ROOT . '/views/' . strtolower($template) . '.php';
if (file_exists($file))
{
/**
* trigger render to include file when this model is destroyed
* if we render it now, we wouldn't be able to assign variables
* to the view!
*/
$this->render = $file;
}
}
/**
* Receives assignments from controller and stores in local data array
*
* #param $variable
* #param $value
*/
public function assign($variable , $value)
{
$this->data[$variable] = $value;
}
/**
* Render the output directly to the page, or optionally, return the
* generated output to caller.
*
* #param $direct_output Set to any non-TRUE value to have the
* output returned rather than displayed directly.
*/
public function render($direct_output = TRUE)
{
// Turn output buffering on, capturing all output
if ($direct_output !== TRUE)
{
ob_start();
}
// Parse data variables into local variables
$data = $this->data;
// Get template
include($this->render);
// Get the contents of the buffer and return it
if ($direct_output !== TRUE)
{
return ob_get_clean();
}
}
public function __destruct()
{
}
}
posts.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="../style/style.css" rel="stylesheet" type="text/css" media="screen" />
<title> Posts (View)</title>
</head>
<body>
<div id="main">
<div class="container">
<?=$data['header'];?>
<div id="content">
<div class="content-background">
<h2> <?=$data['title'];?></h2>
<h4> <?=$data['date'];?> </h4>
<p><?=$data['content'];?></p>
</div>
</div>
</div>
</div>
</body>
</html>
Part of the problem is, that your tutorial has a pretty primitive interpretation of MVC-inspired design pattern (you actually cannot implement classical MVC in PHP, but there are patterns, that are based on it).
View is not just a template. Views are supposed to be class instances, which contain all presentation logic and deal with multiple templates. What you actually have there is a layout template which contains posts template.
// class \Application\View\Posts
public function render()
{
$layout = new Template( $this->defaultTemplateDirectory . 'layout.html');
$content = new Template( $this->defaultTemplateDirectory . 'posts.html' );
$layout->assign( 'content' , $content->render() );
return $layout->render();
}
Also, one of the things, that a view instance should do, is requesting information from the model layer.
Few materials that you might find useful:
Model-View-Confusion part 1: Why the model is accessed by the view in MVC
Simple PHP Template Engine
How should a model be structured in MVC?
And if you want to expand you knowledge in OOP, this post contains a list of recommended lectures and books.
There is no good solution in the MVC structure for that. You can find a solution in every framework. In CakePHP for example you can use an AppController, a controller which is always called for every requests. Sort of base controller.
But no, not very nice to do.
Most simple one is to ask the data directly from the view. That sounds weird but it is accepted in the MVC structure. So in your view you call $News->getLatestItems(10); and work with them.
I don't like it but it works.
If you have lots of widgets and blocks MVC alone might just not be the right structure. Then you could take a look at things like: http://techportal.inviqa.com/2010/02/22/scaling-web-applications-with-hmvc/ which is a derivate of MVC.
Another solution which you see more and more: Request it via AJAX calls. So just load them after the page has loaded. That way you also solve the issue since one MVC request then becomes multiple MVC requests.
I need 3 different templates for my Codeigniter application. I had read about Themes' library. But still I didn't get any idea about how to add a template to Codeignier ..
I got about how to involke template in Controller .
Please help
I'm using this template library, is really simple and works well for me.
application/libraries/Template.php
<?php
class Template {
var $template_data = array();
var $use_template = '';
/**
* Set variable for using in the template
*/
function set($name, $value)
{
$this->template_data[$name] = $value;
}
/**
* Set template name
*/
function set_template($name)
{
$this->use_template = $name;
}
/**
* Load view
*/
function load($view = '' , $view_data = array(), $template = '', $return = FALSE)
{
$this->CI =& get_instance();
if (empty($template)) {
$template = $this->CI->config->item('template_master');
}
if (!empty($this->use_template)) {
$template = $this->use_template;
}
$this->set($this->CI->config->item('data_container'), $this->CI->load->view($view, array_merge($view_data, array ('template' => $this->template_data)), true));
return $this->CI->load->view($this->CI->config->item('template_folder') . '/' . $template, $this->template_data, $return);
}
}
application/config/template.php
<?php
$config['template_master'] = 'main';
$config['template_folder'] = 'templates';
$config['data_container'] = 'content';
application/views/templates/main.php
Header<br />
<?php echo $content; ?></br>
Footer
application/controllers/welcome.php
<?php
class Welcome extends CI_Controller
{
public function index()
{
$this->load->config('template');
$this->load->library('template');
$this->template->load('welcome', array('view' => 'data'));
}
}
I usually put the config/library files on autoload, and you can use anytime $this->template->set_template('other_template'); to use another one :)
Hope it helps.
I've used the following setup in a CodeIgniter project:
The different templates along with stylesheets and images are in the following folder:
/templates/1/header.php
/templates/1/footer.php
/templates/1/images/*
/templates/1/style/*
/templates/2/header.php
/templates/2/footer.php
/templates/2/images/*
/templates/2/style/*
In your Controllers determine which template you want to load and pass the path to that template as a variable ( templatepath in this case ) to your View files. Inside the view files you do the following:
<?php include($templatepath.'/header.php'); ?>
at the top and
<?php include($templatepath.'/footer.php'); ?>
at the bottom.