Tuesday, July 21, 2009

CakePHP 1.2 - dynamic application’s homepage – another approach.

One of the thing a webmaster has to deal with is to create a main page of a website. It was also my recent problem. I needed to create a prototype of app’s main page that should include some logo, some menu, the newest events (posts with event info added by users), login form and some footer. More or less such prototype:

 1

Some ideas that I found on Internet were:

  • to extend Pages Controller or,
  • replace the default route to point to another page.

More about the above here:
http://teknoid.wordpress.com/2008/11/17/get-yourself-a-new-home-alternative-to-homectp/
http://www.phpfreaks.com/forums/index.php?topic=240370.0
http://www.phpfreaks.com/forums/index.php?topic=240370.0

I chose another solutions: the elements.

First off all we need to have some basic functionality. In my case a basic EventsController and UsersController. First step is to create a layout. It is usual that a website uses at least two layouts. One for a home page and another one (or more) for subpages.

I called my layouts: mainpage.ctp for the main and default.ctp for the rest.

To define a layout for a page we have to go to the page’s controller. In my case I had to change PageController (which by default is in cake\lib\controller folder):

function display() {
    $this->layout = 'mainpage';
    (…)
}

Creating a layout is as easy as creating a website. We can find sample file default.ctp in cake/libs/view/layouts/ and customize it for our needs. We just have to remember about some variables that carry data from controller:

  • $title_for_layout – page title that is defined in controller's functions.
function view($id = null) {
   $this->pageTitle ='Events';
(...)
}
  • $scripts_for_layout – contain external sources for example scripts or css files added by html helper.
  • $content_for_layout - data gathered from controller.

To create the usual html content – meta tags, charset, form etc. we can use html helper. More about it here: http://book.cakephp.org/view/206/Inserting-Well-Formatted-elements

Now is the time to create elements. I needed four. Two for menus that are more or less static and another two dynamic. First one is a login form. Another one displays newest events on the main page. The elements are placed in app/views/elemens/.

menu.ctp:

<?php echo $html->link("home", "/", array(), null, false); ?>
<?php echo $html->link("events", "/events", array(), null, false); ?>

menufooter.ctp

<?php echo $html->link("Contact Us", "/kontakt", array(), null, false); ?>
<?php echo $html->link("Terms of Service", "/zasady", array(), null, false); ?>
<?php echo $html->link("Cooperate", "/wspolpraca", array(), null, false); ?>
<?php echo $html->link("Advertise", "/reklama", array(), null, false); ?>
			
<?php 
echo $html->link(
  $html->image('cake.power.gif', array('alt'=> __("CakePHP: the rapid development php framework", true),   'border'=>"0")),
  'http://www.cakephp.org/',
  array('target'=>'_blank'), null, false);?>

The first two are easy and there is nothing to explain.

For user authentication I used Auth Component (http://book.cakephp.org/view/172/Authentication). The default login action is users/login.

login.ctp

<?php
$session->flash();    
$session->flash('auth');
?>
<?php  
if(!$session->check('Auth.User')){
	echo "<p>Please log in.</p>";
	echo $form->create('User', array('action' => 'login'));    
	echo $form->input('username');    
	echo $form->input('password');    
	echo $form->end('Login');
	}
else{
	echo "<p>Hello ".$session->read('Auth.User.name')."</p>";
	echo $html->link("logout", "/users/logout", array(), null, false);
}
?>

The last element – newest.ctp - must pick up some data from EventsController. For that I created a function in the controller that will provide the data for the element.

function main_show_newest(){
		$events = $this->Event->find('all', array('order' => array('Event.insert_date ASC'),'limit' => 3));
		return $events;
	}

Then in the element we use $this->requestAction('events/main_show_newest') to request data from the controller.

newest.ctp

<?php $events = $this->requestAction('events/main_show_newest');?>

<div id="newest">
<h1><?php echo __("Newest events around......") ?></h1>

<?php foreach($events as $event): ?>
<ul>
  <li>
   <div class="name"><?php echo $event['Event']['name']; ?></div>
   <div class="date"><?php echo $event['Event']['starting_date']; ?>-<?php echo $event['Event']['end_date']; ?></div>
   <?php echo $event['Event']['description']; ?>
   <?php echo $html->link("more", array( 'controller' => 'events', 'action'=>'view', 'id'=>$event['Event']['id']), null, false); ?>
  </li>
</ul>
<?php endforeach; ?>
</div>

There is also another possibility. In controller we use simply $this->paginate() and then in the element $this->requestAction('events/main_show_newest/sort:insert_date/direction:asc/limit:3').

To include an element menu.ctp to the layout use $this->element('menu').

The full mainpage layout:

mainpage.ctp
<?php echo $html->docType(); ?>
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<?php echo $html->charset(); ?>
<title>	Kultura.info.pl - <?php echo $title_for_layout; ?></title>
	
<?php
 echo $html->meta('description','Best event tracker ever!');
 echo $html->meta('keywords', 'event, events');
 echo $html->css('kultura.generic');
 echo $scripts_for_layout;
?>
	
</head>
<body>
<div id="container">

<div id="header">
<?php 
echo $html->image('logo.jpg', array('alt'=> __("kultura.info.pl Strona główna", true), 'border'=>"0")); ?>
</div>

<div id="menu">
<?php echo $this->element('menu');?>
</div>
		
<div id="left">
<?php echo $this->element('login');?>
</div>
		
<div id="content">
<?php $session->flash(); ?>
<?php echo $content_for_layout; ?>
</div>
		
<div id="footer">
<?php echo $this->element('menufooter');?>
</div>

</div>
	
</body>
</html>

The default.ctp layout at this moment has only one difference in comparison to mainpage.ctp layout: it has no login form. I use it everywhere but the main page. Because I left the name default.ctp for this layout I don’t need to declare or configure it anywhere.

And that’s it. I hope it gives a basic overview of this concept.

2 comments:

  1. Hi Tasha,

    Hope you get this e-mail, since the article you wrote is from 2009.

    I followed your tips, but you do not mention how to make the login form in an element the target of the Auth login action, instead of the default /app/views/users/login.ctp view.



    Regards,
    Wim
    South Africa

    ReplyDelete
  2. sssshhhhhhhhhhhh..............

    ReplyDelete