View in MVC, what is a layout and how to create one - php

I dont understand what the layout is, in the view. I asked a question previously on the subject of templating in PHP, but I still dont quite understand. I assume that you create a general layout for the site and then include each specific view within that layout.... I would like to know how to go about doing this. Also, are should the templates be made using just html, because I also looked at these things called helpers.... I'm just confused on the View part of the MVC, and the actual templates and how they're made. I learn best with examples, If you guys have any.
Also, a more important question, lets say I had a form that a user saw only if he was logged in, would I control that in the view, or in the controller?
So Would i do
in the controller
include 'header';
if(isset($_SESSION['userID'])){
include 'form';
}
include 'footer';
or
in the template
<html>
<?php if(isset($_SESSION['user_id'])): ?>
<form>....</form>
<?php endif;?>
</html>
EDIT
So, is there an include statement from within the layout to see the specific view template? how so?

a layout is whatever you have around your main content area. Usually on a normal website it would be any sidebar,header,footer. Most of MVC framework provide the layout to avoid to repeat those parts in all views.
You can imagine if like you have two view cascaded
you actual view is rendered, this content is saved
the layout view (all the items around the content) are rendered and your content is included in that output
for your login question actually your would have to do both
on the controller and the view
$this->view->isLogged = isset($_SESSION['userID']);
in the view
<?php if($isLogged): ?>
<form>....</form>
<?php endif;?>

I hesitate to answer this question only because of the religious fervor that surrounds it.
To get a really good understanding of the issues behind the general concepts see This Wiki Discussion Page This is the discussion page around the wiki MVC article.
Here is the rule of thumb I like to follow (BTW I use CodeIgniter and it kind of sounds like you are too):
The "view" should have virtually no logic. It should only be HTML (in the web world) with peppered PHP that simply echos variables. In your example you would break out the form into its own view and the controller would determine if was loaded or not.
I like to look at it this way: The view should have no concept of where the data comes from or where it is going. The model should be view agnostic. The controller meshes data from the model and provides it to the view - and it takes input from the view and filters it to the model.
Here is a quick and dirty (untested - but it should get the point across) example:
Theapp.php (The App controller)
class Theapp extends Controller
{
var $_authenticated;
var $_user;
var $_menu; // array of menus
function __construct()
{
session_start();
if (isset($_SESSION['authenticated']) && $_SESSION['authenticated'])
{
$this->_authenticated = $_SESSION['authenticated']; // or some such thing
$this->_user = $_SESSION['user'];
}
$this->_menu = array("Logout", "Help", "More");
parent::__construct();
$this->loadView("welcome"); // loads primary welcome view - but not necessarily a complete "html" page
}
function index()
{
if (!$this->_authenticated)
$this->loadView("loginform");
else
{
$viewData['menu'] = $this->_menu;
$viewData['user'] = $this->_user;
$this->loadView("menu", $viewData);
}
}
function login()
{
/* code to authenticate user */
}
function Logout() { /* code to process Logout menu selection */ }
function Help() { /* code to process Help menu selection */ }
function More() { /* code to process More menu selection */ }
}
welcome.php
<h1> Welcome to this quick and dirty app!</h1>
All sorts of good HTML, javascript, etc would be put in here!
loginform.php
<form action"/Theapp/login" method="post">
User: <input id='user' name='user'>
Pass: <input id='pass' name='pass' type='password'>
<input type='submit'>
</form>
menu.php
Hi <?= $user ?>!<br>
Here's your menu<br>
<? foreach ($menu as $option) { ?>
<div class='menuOption'><a href='/Theapp/<?=$option?>'><?=$option?></a></div>
<? } ?>
Hope this helps.

If your not using a framework, then a simple way to have a layout and a view can be like so:
<?php
function layout($layout_params) {
extract($layout_params);
# Remember: $layout_content must be echoed for the view to be seen.
ob_start();
include "layout_page.php";
$html = ob_get_contents();
ob_end_clean();
return $html;
}
function view($view_params) {
extract($view_params);
ob_start();
include "home_page.php";
$html = ob_get_contents();
ob_end_clean();
return $html;
}
#
# The variable $parameters is extracted and $params becomes a variable in the view as an array,
# $logged_in is also now avaiable in the view
#
$parameters = array("params" => array("name" => "joe"), "logged_in" => false);
$view_content = view($parameters); # => Returns the HTML content for home_page.php
# Now we need the layout content to include the view:
# The layout file will expect a variable called $layout_content to be the html view.
# So we need to set $layout_content to be $view_content
$parameters["layout_content"] = $view_content;
# We no longer need $view_content so we can unset the variable
unset($view_content);
# When $paramters is extracted it will have $layout_content as a variable:
$layout_content = layout_view($paramters); # => Returns the HTML content for the layout_page.php
# Now send the results to the browser
echo $layout_content;
?>

Related

Concrete 5 Pagination (Page List Blogs)

Is it possible to have some sort of pagination within the URL in Concrete 5. I see many CMS's such as Wordpress and Drupal etc that have such a feature.
At the moment my blogs are the following:
/blog?ccm_paging_p_b348=2
and the way I want it to be is:
/blog/page/1 ... /blog/page/2 etc (or something similar)
Any tips or advice would be appreciated
Your only choice is to create a custom page type for your blog page and then a custom controller for that which handles the pagination.
Please see this page:
http://www.concrete5.org/documentation/developers/pages/mvc-approach
And particularly the "Page Types" section under "Controllers". It explains how to create your page type controllers. For them, you can create similar functions that you would for normal single pages, so you can paginate the results there according to the parameters you get from the URL.
This example is for 5.6 and earlier:
<?php
class BlogPageTypeController extends Controller {
public function view($page=1) {
$pageIndex = intval($page)-1;
if ($pageIndex < 0) {
$pageIndex = 0;
}
$pageList = new PageList();
$pageList->setItemsPerPage(25);
$this->set('pages', $pageList->getPage($pageIndex));
}
}
And then you would use the $pages variable in your view to go through the pages:
<?php foreach($pages as $page) : ?>
<h2><?php echo $page->getCollectionName()</h2>
<?php endforeach; ?>

CodeIgniter Initial Page Load Variable?

I'm looking for a solution to loading the header/footer/navigation only on the initial page view.
The reasoning behind this is that my navigation panel uses Ajax to render the content of the destination link in the main content div instead of actually loading the page itself.
However, I need to be able to say something along the lines of if its the initial view, load the header, navigation, then the actual page, then the footer. But if its not the initial view and the page is loaded in the content div area so for example a navigation link or a form submit, it doesn't load the header, navigation and footer but only the actual page.
So for example I have these 4 views:
header_view
navigation_view
page_a_view
footer_view
And this controller:
controller_a
The navigation has a link which is 'Page A' and points to http://myurl.com/controller_a. If that link is clicked I only wanted controller_a to load the page_a_view view, because the navigation link will load the data of that page into the div.
However if I directly go to http://myurl.com/controller_a, it needs to render the the header/navigation/footer also.
The solution I thought I was on the right lines with was something like a base controller with a function load_page() which would be something like:
function load_page($page, $data) {
if($this->uri->segment($this->uri->total_segments()) == "initial_page_load") {
$this->load->view('header_view');
$this->load->view('navigation_view');
$this->load->view($page, $data);
$this->load->view('footer_view');
} else {
$this->load->view($page, $data);
}
}
So if I was to go to http://myurl.com/controller_a/initial_page_load it would load the header/navigation/footer but if I went to http://myurl.com/controller_a it wouldn't.
However this doesn't cover all possibilities.
Another way I thought of is checking if there is a referring URL, if there is, don't load the header/navigation/footer. But again, this doesn't cover things such as what if the link was referred by an external website?
Does anyone have any suggestions to how I can achieve what I need?
Let this be your view page for all views. For your other pages, you are going to change the content on div, 'page_content' dynamically via ajax.
**application/views/your_template_view.php**
<?php
$this->load->view('header_view');
$this->load->view('navigation_view');
?>
<a href="javascript:void(0)" id='home' class='my_links'>Home</a>
<a href="javascript:void(0)" id='about_us' class='my_links'>About us</a>
<!--
Make sure the id of the page is same as
the file name of view page for respective pages
-->
<div id='page_content'><?php echo $page_content; ?></div>
<?php
$this->load->view('footer_view');
?>
<script lang='javascript'>
$('.my_links').click(function(){
$.post(
'<?php echo site_url('test_controller/get_page_content') ?>',
{'page_content':$(this).attr('id')},
function(response){
if(response != '')
$('#page_content').text(response);
},'json'
);
});
</script>
Let this be your controller :
**application/controller/test_controller.php**
function your_page($param1 = '', $param2 ='') {
/*this one is for your initial page*/
if($param1)
// send mail
if($param2)
// send mail
$data['page_content'] = $this->load->view('initial_page_load');
$this->load->view('your_template_view', $data);
}
function get_page_content()
{
/*this one is for other pages, this provides page content
for the request made from ajax*/
$page_title = $this->input->post('page_title');
$page_content = $this->load->view($page_title);
echo json_encode($page_content);
}
Make a session variable to denote whether the header/footer is loaded, and if it is, just skip them
if (!$this->session->userdata('nav_loaded')) {
$this->load->view('header_view');
}
etc...
This will work for all your pages, no matter where are they called from, provided that all the post-initial calls are done by AJAX.
EDIT
If you want to mix ajax and non-ajax calls after that, the session varable won't work, of course. Perhaps you could put an ajax parameter in your urls and adjust the controllers according to that.
public function index($ajax = false) {
...
if (!ajax) {
$this->load->view('header_view');
}
etc...
}
So, all the AJAX call will have that additional parameter in the url set to true (almost anything except zero: index/1, index/ajax, etc.).
Although I'm still testing this it seems to be doing exactly what I expect so far! It's one of those ones which is simple but does the complete job so hopefully no problems pop up...
In MY_Controller.php
function load_page($page, $data) {
if(!$this->input->is_ajax_request()) {
$this->load->view('header_view');
$this->load->view('navigation_view');
}
$this->load->view($page, $data);
if(!$this->input->is_ajax_request()) {
$this->load->view('footer_view');
}
}
Managed to stumble across that function when looking in the Input class documentation

Query string, populating a page from DB or file

Is this facebook link populated fully from the DB? Or, is it a physical file with PHP in it? Just, how is this page called?
http://www.facebook.com/profile.php?id=49300915&sk=photos
They probably do something like:
if(isset($_GET['id'], $_GET['sk'])) {
mysql_query("SELECT info, photos FROM users WHERE id = '$id'");
}
I'm trying to ask, how do they include this page? Is it like Drupal / any CMS where the PHP and page is stored in the DB, or is it a physical file on the server? If the latter, what's the best way to get the file (case insensitive URL)?
I would have a class with a single method, which reads 'sk' and runs another method, depending on what it's value is.
One method would be 'photos' which would read 'id' and fetch a photo from the database. It would then run another method, displayPage, which will display a page from that data.
The displayPage method takes a "template" filename and an array of variables to provide to the template. It sets up a smarty object, provides the variables, and instructs it to display the template.
Inside the template, I'd include another template for the global header that's on every page in the site, then i'd have the html page content, using smarty to insert dynamic values, then include a global footer.
Note that i've simplified this system a lot. A real page like that would take me a week to write all the code, since a big website does a lot of stuff just to display a simple page (for example: find out if the logged in user actually has access to the page... i don't have access to the example one you gave).
<?php
// profile.php
class ProfileController
{
public function run()
{
if ($_GET['sk'] == 'photos')
return $this->photosPage();
}
protected function photosPage()
{
$id = (int)$_GET['id'];
$result = mysql_query("select * from photo where id = $id");
$photo = mysql_fetch_object($photo);
$this->displayPage('view-photo.tpl', array('photo' => $photo);
}
protected function displayPage($templateFile, $templateVariables)
{
$smarty = new Smarty();
foreach ($templateVariables as $variableName => $variableValue) {
$smarty->assign($variableName, $variableValue);
}
$smarty->display($templateFile);
}
}
$conntroller = new ProfileController();
$controller->run();
And the smarty code:
<!-- view-photo.tpl -->
{include file='head.tpl'}
<h1>View Photo {$photo->name|escape}</h1>
<img src="{$photo->src|escape}" width="{$photo->width|escape} height="{$photo->height|escape}>
{include file='foot.tpl'}

Codeigniter two param database breadcrumb

I am using the php framework codeigniter.
I am attempting to create a here is an example:
animals/feline/lion
animals/feline/tiger
animals/feline/snow-leopard
animals/canine/wolf
animals/canine/coyote
Where both genus (feline) and species (lion) are both retrieved from a database and animals is a controller. I have models that place genus and species in their respective arrays. I also wish to have views for each step along the breadcrumb as follows:
animals
animals/feline
animals/canine
Any help would be greatly appreciated. I just looked at autocrumb and all it was as for displaying the breadcrumb control structure on the view, and not what I want.
I'd use URi routing., as another approach than __remap(), which is better, but I just wanted to give another choice
$route['animals/(:any)/(:any)'] = "animals/method/$1/$2";
In you animals controller you have
function method($genus,$species)
{
$data['breadcrumb'] = 'animals -> '.$genus.' -> '.$species.
$this->load->view('breadcrumb', $data);
$this->load->view('animals/'.$genus.'/'.$species);
}
view breadcrumb.php:
<div id="breadcrumb">
<?php echo $breadcrumb;?> <!-- Display: animals -> feline -> lion -->
</div>
View folder contains:
breadcrumb.php
animals /
feline /
feline.php
canine/
wolf.php
Is this what you were looking for?
EDIT after comments:
SO looks like we've mistaken what you wanted. If you're retrieving those variables from DB, then you could do like this:
function index()
{
$this->load->view('animals/index');
}
function genus($genus)
{
$data['genus_data'] = $this->your_model->load_genus_data($genus);
$this->load->view('animals/genus',$data);
}
function species($genus,$species)
{
$data['genus_data'] = $this->your_model->load_genus_data($genus);
$data['species_data'] = $this->your_model->load_species_data($species);
$this->load->view('animal/genusspecies',$data);
}
In your view genus.php (in folder animal):
<?php $genus_data->name;?> is an animal that...Here's a pic in its habitat.
In your view genusspecies.php (in folder animal):
<?php $species_data->name;?> is a species of genus <?php $genus_data->name;?>....
all those might be html snippets you load from database;
Your routing might look like this then:
$route['animal'] = "animal";
$route['animal/(:any)'] = "animal/genus/$1";
$route['animal/(:any)/(:any)'] = "animal/species/$1/$2";
If I were you, I'll go about this way. Do I got it better or am I still wrong somewhere?
Add a _remap() function to your animals controller
if($this->uri->segment(3) === FALSE)
{
$this->genus();
}
else
{
$this->species();
}
This assumes you have a method called genus() and a method called species()
_remap() docs:
http://codeigniter.com/user_guide/general/controllers.html#remapping
URI Library docs:
http://codeigniter.com/user_guide/libraries/uri.html
redirect('animals/' . $genus . '/' . $species);

how to ajaxify zend_pagination results (already working with partialoop) using jquery

in the controller i have :
$paginator = Zend_Paginator::factory($mdlPost->getPosts($this->moduleData->accordion, 'name ASC'));
if(isset($params['cities'])) {
$paginator->setCurrentPageNumber(intval($params['cities']));
}
$paginator->setItemCountPerPage(4);
$this->view->posts = $paginator;
in the view's i have some thing like this :
if ($this->posts != null) {?>
<div id="cities_accord" class="news">
<?php echo $this->partialLoop('partials/post-min.phtml', $this->posts); ?>
</div>
<?php echo $this->paginationControl($this->posts,
'Sliding',
'public/pagination_cont.phtml');
}
the partial/post-min.phtml
<?php
$color = array(1=>'spring',2=>'summer',3=>'autumn',4=>'winter');
?>
<div id='<?php echo $color[$this->partialCounter] ?>' class="accordion_post">
<?php
$link = Digitalus_Uri::get(false, false, array('openCity' =>
$this->id));//$color[$this->partialCounter]));
?>
<h1 class="accordion_post_title"><?php echo $this->title ?></h1>
<p><?php echo $this->teaser ?> <i>read more</i></p>
</div>
the pagination_cont.phtml taken from this link zend ( http://framework.zend.com/manual/en/zend.paginator.usage.html )
will show links that will pass params to the controller to fetch the corresponding whole page which is working alright for now
but i want to change this so that i will be able ajaxify the returned ( i.e. only a single paginated value rather than reloading the whole page ) results how can i do that using jquery and what should i change ..
** EDIT: it would be nice to have a fail-save ,if possible, for browsers(users) that disabled javascript to see the same thing by reloading the page (i.e. keeping the current status for if(javascript_not_enabled ))**
This is what I've done in the past.
First, setup the AjaxContext action helper to enable the html context on your controller action.
Add a .ajax.phtml view that just contains the section of markup that may be replaced via AJAX as well as the pagination control links. You can probably just copy this out of your normal view. Replace that section in your normal view with something like
<div id="reloadable-content">
<?php echo $this->render('controller/action.ajax.phtml') ?>
</div>
This will ensure that your initial and any non-AJAX requests will still include the right content. The <div> id is purely for referencing the loadable block in JavaScript.
Also make sure you include your JS file (using headScript) in the normal view only.
Now, in your JS file, unobtrusively add the appropriate event binding to the paginator links. As you'll be replacing the pagination control section in order to reflect the correct current page and other links, it's probably best to do this using the jQuery live binding. I'm also assuming you'll wrap the pagination control with some kind of identifiable element (<div class="pagination-control"> for example)
$('.pagination-control').find('a').live('click', function(e) {
var link = $(this);
$('#reloadable-content').load(link.attr('href'), { format: 'html' });
return false;
});
Keep in mind that in using this method, you will lose the ability to navigate the paged requests using the normal back / forward browser buttons. You will also lose the ability to bookmark pages directly (though you could always provide a permanent link to the current page as part of the AJAX loaded content).
You can use something like the jQuery history plugin if you're really concerned but that will require more client-side work.
Another caveat is that the above will only work with pagination links. If you want to use a form with dropdown page selection, you need to add another event handler for the submission.
GOT IT and big Thanks to #Phil Brown :
in the controller int() change the response type to json
class NewsController extends Zend_Controller_Action
{
public function init()
{
$contextSwitch = $this->_helper->getHelper('contextSwitch');
$contextSwitch->addActionContext('list', 'JSON')
->initContext();
}
// ...
}
public listAtcion() {
// .............
$paginator = Zend_Paginator::factory($mdlPost->getPosts($this->moduleData->accordion, 'name ASC'));
if(isset($params['cities'])) {
$paginator->setCurrentPageNumber(intval($params['cities']));
}
$paginator->setItemCountPerPage(4);
$post = array();
foreach($paginator as $post ) {
$post[] = $post;
}
$this->view->post = $paginator;
#TODO //add a check here for non-ajax requests (#improvment)
$this->view->posts = $paginator;
}
in one of the views (most probably in the pagination_cont.phtml) on the pagination controller add the ajax links
<?= $this->ajaxLink (
$this->url('cities'=>$this->page_num),array('id'=>'div_id','complete'=>'js_method(json_data)','method'=>post) ,array('format'=>'JSON'));
and add a JavaScript function of js_method(json_data) to modify the div with id = 'div_id' with a json data
function js_method(json_data) {
var content = parse.JSON(json_data);
$('#div_id').html('');
//fill it with the reposnse content some thing like $('#div_id').append(content);
}

Categories