Part 2 – setting up the project and actual start of coding :)
Please, note that this text is written in May 2008. Since then Zend Framework have evolved and now provides Zend_Application class. It is good idea to use it. The user registration and login stuff, presented here is still actual though. Also there are many other ideas presented, which I hope will be usefull for the readers.
In Part 1 of this series we decided our goals – what we hope we will have at the end of this. Now it is time to go into more detailed planning how we will chase these goals with the valuable help of the Zend Framework.
We will use MVC structure – targeting to separate our application login from the presentation logic. Zend_Controller_Front class implements a Front Controller pattern, meaning that all requests to our web application will go through this single place and will be dispatched to appropriate Action Controller based on the parameters of the request. Zend Framework makes adoption ot the MVC pattern to a web application an easy task. We should create suitable directory layout for our application and the Zend Framework manual help us with this (I will abbreviate Zend Framework with ZF from now on) . Of course, as with many things with ZF this directory structure can be chosen in a variety of ways, allowing great flexibility. For our purposes we will go with something like this:
application/
layouts/
models/
modules/
default/
controllers/
views/
filters/
helpers/
scripts/
configuration/
library/
public/
The public/directory will be our document root – so we configure our web server accordingly. The library/directory we will use as placeholder for third party libraries and eventually for the Zend Framework itself if we do not have it somewhere in more common location.
Because we are implementing Front Controller pattern we need to set up a .htaccessfile in our document root – namely ‘public/.htaccess‘, and make sure all requests to our web application go to our single point of entry – ‘public/index.php‘. Of course we will serve images, JS files, CSS files directly. Two approaches are possible here – to give a list of file extensions, for which we don’t want to go to index.php (assuming Apache here):
RewriteEngine on RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
Or to check if the file in the URL exists and if not – to redirect the request to index.php:
RewriteEngine on RewriteCond %{SCRIPT_FILENAME} !-f RewriteCond %{SCRIPT_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1
I will chose the latter, but both will work. Now lets write the index.php itself. It is located in ‘public/index.php‘:
< ?php require '../application/bootstrap.php';
We have single require here and we take the control of the application to ‘application/bootstrap.php‘ file. This is done this way to keep all the application code for our website on one place – in the ‘application/‘ folder.
Now lets see what we have in this ‘application/bootstrap.php‘:
< ?php // For our dev environment we will report all errors to the screen error_reporting(E_ALL | E_STRICT); ini_set('display_startup_errors', 1); ini_set('display_errors', 1); // Set our timezone date_default_timezone_set('Europe/Sofia'); // Add /library and /application directory to our include path $siteRootDir = dirname($_SERVER['DOCUMENT_ROOT']); set_include_path( $siteRootDir . '/library' . PATH_SEPARATOR . $siteRootDir . '/application' . PATH_SEPARATOR . get_include_path() ); // Turn on autoloading, so we do not include each Zend Framework class require_once 'Zend/Loader.php'; Zend_Loader::registerAutoload();; // Create registry object and setting it as the static instance in the Zend_Registry class $registry = new Zend_Registry(); Zend_Registry::setInstance($registry); // Load configuration file and store the data in the registry $configuration = new Zend_Config_Ini($siteRootDir . '/configuration/config.ini', 'main'); Zend_Registry::set('configuration', $configuration); // Construct the database adapter class, connect to the database and store the db object in the registry $db = Zend_Db::factory($configuration->db); $db->query("SET NAMES 'utf8'"); Zend_Registry::set('db', $db); // set this adapter as default for use with Zend_Db_Table Zend_Db_Table_Abstract::setDefaultAdapter($db); // Setup the Front Controller, disable the error handler, set our controller directories $frontController = Zend_Controller_Front::getInstance(); $frontController->throwExceptions(true); $frontController->addModuleDirectory($siteRootDir . '/application/modules'); //we want the front controller to return the response, instead of emitting it automatically $frontController->returnResponse(true); /* * We want to set the encoding to UTF-8, so we won't rely on the ViewRenderer action helper by default, * but will construct view object and deliver it to the ViewRenderer after setting some options. */ $view = new Zend_View(array('encoding'=>'UTF-8')); $viewRendered = new Zend_Controller_Action_Helper_ViewRenderer($view); Zend_Controller_Action_HelperBroker::addHelper($viewRendered); // Now we initialize the Zend_Layout object with MVC support Zend_Layout::startMvc( array( 'layoutPath' => $siteRootDir . '/application/layouts', 'layout' => 'main' ) ); // run the dispatch, get the response and send it to the client $response = $frontController->dispatch(); $response->setHeader('Content-Type', 'text/html; charset=UTF-8', true); $response->sendResponse();
Although I have put comments through the code I’ll walk it here again taking some notes.
First we make sure we will see the errors we produce while working on the screen, to save ourselves the troubles going to error log file and looking there (And indeed we will make some errors while coding – this is for sure). After this we select a timezone. This is important because once our application grows we may need to use date/time functions and without this date_default_timezone_set call we can get unexpected results according to the system ‘s timezone settings.
Next thing is to set our include path so ‘library/‘ and ‘application/‘ directories to be there. If Zend Framework is located somewhere else on the server – ‘/usr/share/Zend‘ for example – make sure you include this path as well.
The first class from ZF which we will use is Zend_Loader – we want to save some typing so we will register auto loading of ZF classes.
Next we create the Registry object – we will use it to store some important values and objects instead of polluting the namespace with global variables.
Next we need to set up the database connection which we will use through our application. For storing the database connection settings we use .ini file in the following format: (configuration/config.ini)
[main] ;Database connection settings db.adapter=Mysqli db.params.host=localhost db.params.username=zfsite db.params.password=123456 db.params.dbname=zfsite
Substitute your db connection settings there for this to work with you. I will use Mysqli as my database adapter, but you can use here Pdo_Mysql if you prefer.
Back in our bootstrap.php – we load the configuration with the parsing help of Zend_Config_Ini, construct our database adapter class, run the “SET NAMES ‘utf8′” query to make sure we talk to our database in the correct encoding, save the adapter in the Registry for later use and finally set it as a default adapter to be used in Zend_Db_Table class and our derived classes from it (more on this – later).
Now we are ready to setup the MVC structure. We will use Zend_Layout class so we can have common site header, footer and menu without pasting it to all possible templates in our site. Also we should note our directory structure again – specially the ‘application/modules/‘ directory – I have decided that I want to have the possibility easy to add new modules to the application (for example if I build social networking site, the forum would be separate module and the image gallery – another one separate module). So I went with this directory structure, where I have explicit modules directory with separate sub directory for each module. For now we have only one module – the ‘default’ module, thus we have only one subdirectory there – ‘application/modules/default‘. We use addModuleDirectorymethod of Zend_Controller_Front to tell the framework where to look for our modules. Because I want to be sure my website is in UTF-8 character set I need to set the encoding option to the Zend_View class so I can’t just rely on the magic of the ViewRenderer action helper, but I need to give it a hint – so we create the Zend_View object explicitly setting the encoding, and then constructing the ViewRenderer also explicitly, giving our Zend_View object as option, so it is used for the actual rendering.
We will use some Zend_Layout magic here also – to make our live easier and to allow us to have common layout pattern, describing our site header, footer, menus and other common elements if any. Including Zend_Layout in the picture is as easy as running its startMVC method telling it that our layout template files will be in ‘/application/layouts’ directory and that we want main.phtml to be used as our default layout template.
Finally we dispatch the front controller, set a UTF-8 charset header to the response and send the response to the client.
So far so good. Lets test what we have done for now. We will need to write simple main.phtml layout template and add default action controller to our application.
‘application/layouts/main.phtml‘:
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <div id="container"> <div id="header"> <h1>Zf Site</h1> </div> <div id="main-holder"> <div id="main"> < ?php echo $this->layout()->content ?></div> <div id="subnav"> <h2>Sub-Nav Column</h2> Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet.</div> </div> <div id="extra"> <h2>Extra Column</h2> Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet. Lorem ipsum sit dolor amet.</div> <div id="footer">footer placeholder</div> </div>
And you may have noticed that we have referenced “style.css” – so here it is:
‘public/style.css‘
body { margin: 0; padding: 0; background-color: #ACBEBF; } #container { width: 760px; margin: 10px auto; background-color: #778384;} #header { width: 760px; float: left; color: #E6FDFF;} #main-holder { width: 600px; float: left; } #extra { width: 150px; float: right; } #main { width: 440px; float: right; } #subnav { width: 150px; float: left; } #footer { width: 760px; float: left; text-align: center;}
Very simple layout, just to illustrate what we have as possibilities. Once we are to the real application – we will give some nice design made from professional designer and put it here
.
2 last files for today – we want to see something live on our web server already, don’t we? So very simple default action controller with one defined default action:
‘application/modules/default/controllers/IndexController.php‘:
< ?php class IndexController extends Zend_Controller_Action { public function indexAction() { } }
And the corresponding template:
‘application/modules/default/views/scripts/index/index.phtml‘
test проба
and thats all. If we develop on localhostport 80, then when we type in browser “http://localhost/” we should see our layout page with
test
проба
as main content.
That’s it for part 2. We have setup the MVC system and made simple layout to use with this sample web site. In next third part of this we will make sure we can maintain session data between requests – we will write session adapter to work with MySQL database (again making heavy use of what ZF have to offer). The reason we want our session data to be in database and not in files – security and scalability. But more on this in the next part.












