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"> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title>Zf Site</title> <link href="style.css" rel="stylesheet" type="text/css" /> </head> <body> <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> <p>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. </p> </div> </div> <div id="extra"> <h2>Extra Column</h2> <p>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. </p> <p>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. </p> </div> <div id="footer">footer placeholder</div> </div> </body> </html>
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.













Sarah Pearson | 22-May-08 at 2:33 pm | Permalink
Thanks for these 2 parts. As a newcomer to the ZF (but an old timer with php and procedural programming) I am grateful for people to create these tutorials. Looking forward to part 3.
David Arnold | 16-Jun-08 at 7:26 pm | Permalink
Just a few things to note.
The blog seems to mess up the php code in the following ways:
1. Single Quotes
2. a space between <?php so it displays invalid <? php
3. Some of the code for application/layouts/main.phtml seems to be missing.
Thankfully you included all the code in a compressed format, but for the sake of consistency you should make sure all the code you use is also included in the post.
Thanks for putting this up!
-d
admin | 17-Jun-08 at 3:52 pm | Permalink
Hi David,
Thanks for pointing the missing code in application/layouts/main.phtml - I just added it back.
I know about points 1 and 2, it is something from the Wordpress plugin for code highlight. I will try to find another one for this.
Olaf Lugtenburg | 07-Jul-08 at 12:35 am | Permalink
I am really enjoying this tutorial as I am very new to all the PHP stuff. I have erverything working so far (already quite happy), but somehow I have to include ‘public’ in my URL to address my site. I have searched for the problem, but as far as I can see there is a difference between the siterootdir and the document root. The siterootdir is the root of all folders, but the documentroot is the root of the webpages, where index.php should be.
Did I do something wrong?
Hope you can help me out with this one.
Thanks in advance,
Olaf
admin | 07-Jul-08 at 3:01 pm | Permalink
Hi Olaf, assuming you are using Apache web server - you define VirtualHost, where with the DocumentRoot directive you point to the public/ folder.
Knowing how virtual hosts work is good thing anyway, if you want to have overal understanding of the things. Read here:
http://www.apacheweek.com/features/vhost
for simple explanation, or here:
http://httpd.apache.org/docs/1.3/vhosts/
for more in-depth documentation.
If you just want to make it works for you - write me at viperx[at]andreinikolov[dot]com and with more information about your enviroment and I’ll will try to help you.
Alfredo | 08-Jul-08 at 7:56 pm | Permalink
Thank you!!!.
This link may be helpful for ZF newbies:
Error in listTables() in MySQLi adapter if no table exists
http://framework.zend.com/issues/browse/ZF-1501
My error was:
Fatal error: Uncaught exception ‘Zend_Db_Adapter_Mysqli_Exception’ with message ‘Can’t connect to local MySQL server through socket ‘/var/mysql/mysql.sock’ (2)’ in ……
mike | 17-Aug-08 at 4:44 pm | Permalink
I have done all of the above but how do i resolve the following errors?
Warning: require_once(Zend/Loader.php) [function.require-once]: failed to open stream: No such file or directory in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\application\bootstrap.php on line 20
Fatal error: require_once() [function.require]: Failed opening required ‘Zend/Loader.php’ (include_path=’C:/Program Files/Apache Software Foundation/Apache2.2/library;C:/Program Files/Apache Software Foundation/Apache2.2/application;.;C:\php5\pear’) in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\application\bootstrap.php on line 20
viperx | 18-Aug-08 at 11:12 am | Permalink
Hi mike,
It seems that PHP cannot find your Zend Framework library. You must have it in your inlude path. There are two basic ways for this - the first and more simple is to copy Zend Framework files under your
C:/Program Files/Apache Software Foundation/Apache2.2/library
folder
This way you will have one copy of the framework for each project. If you prefer to have only one copy of the framework for all your projects you can put it somewhere of your choice and make sure you have it in your include path - look at this code:
mike | 18-Aug-08 at 10:51 pm | Permalink
I would first and foremost like to say thank you very much for the tutorial and for the quick response to my problem earlier.
I have put my Zendframework files as you stated above in:
C:/Program Files/Apache Software Foundation/Apache2.2/library
folder
Now i am getting the following:
Warning: parse_ini_file(C:/Program Files/Apache Software Foundation/Apache2.2/configuration/config.ini) [function.parse-ini-file]: failed to open stream: No such file or directory in C:\Program Files\Apache Software Foundation\Apache2.2\library\Zend\Config\Ini.php on line 108
Fatal error: Uncaught exception ‘Zend_Config_Exception’ with message ‘Section ‘main’ cannot be found in C:/Program Files/Apache Software Foundation/Apache2.2/configuration/config.ini’ in C:\Program Files\Apache Software Foundation\Apache2.2\library\Zend\Config\Ini.php:163 Stack trace: #0 C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\koba\application\bootstrap.php(28): Zend_Config_Ini->__construct(’C:/Program File…’, ‘main’) #1 C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\koba\web_root\index.php(2): require(’C:\Program File…’) #2 {main} thrown in C:\Program Files\Apache Software Foundation\Apache2.2\library\Zend\Config\Ini.php on line 163
Pavel | 19-Aug-08 at 6:27 am | Permalink
You should go to the ../configuration/config.sample.ini and rename this file to ../configuration/config.ini.
And then remember to create the schema in your mysql database server, set your own username and password.
mike | 19-Aug-08 at 1:00 pm | Permalink
My database schema looks ok with my own username and password.
I also have the config.ini file in the right place. It looks like this:
[main]
;Database connection settings
db.adapter=PDO_MYSQL
db.params.host=localhost
db.params.username=root
db.params.password=123456
db.params.dbname=koba
The error talks of ‘Section ‘main’ cannot be found in….
I am at a loss. I have done some other online tutorials that worked but were hard to follow and i was really following this tutorial as it is clearly laid out.
SOS
viperx | 19-Aug-08 at 1:25 pm | Permalink
Hay mike, I think that there is some problem with your directory structure. I see you use windows version of apache and php - this is ok, if you configure the things right this will work just the same way as it was on Linux.
In your httpd.conf - have you defined virtual host for this project? I strongly recommend to have virtual host for the project, and to not run it from subdirectory in your htdocs folder. Although this is possible it will need some more configurations and understanding of how thinks work. If you are a newbie - just make new virtul host and all will work fine.
When I start new project - no matter how small it is - I always make new virtual host. You do not need to have domain names for virtual hosts - you can just run them on diferent ports in your apache server.
See examples here:
http://httpd.apache.org/docs/1.3/vhosts/examples.html
and pay attention to the “Port-based vhosts” section.
mike | 19-Aug-08 at 4:04 pm | Permalink
I will change the directory stucture and see how this works out.
arnsvel | 28-Aug-08 at 11:29 am | Permalink
Very nice tutorial for beginner that want a kick-start, I am using PostgreSql as my database.
And having a problem configuring the config.ini and bootstap.php. Could someone teach me…お願い致します。。
viperx | 28-Aug-08 at 1:40 pm | Permalink
Hi arnsvel, for PostgreSQL you should use the appropriate DB Adapter and configure it according to its needs - read the manual for your db adapter. Also I’m not sure if the gc() function in My_Session_Manager will work under PostgreSQL because of the DATE_ADD function with INTERVAL.. If PostgreSQL supports this construction it will be OK.
arnsvel | 28-Aug-08 at 3:01 pm | Permalink
Thanks..
I was able to connect on Postgresql by changing the config.ini file and commenting out the My_Session_Manager in bootstap.php.
And the home page appeared in the browser but when I click the register and login link it produce error.
And one more I am using Smarty instead of Zend view…
I suggest you publish a tutorial of this excellent kick-start sample project for those who are using PostgreSQL and Smarty..
I’m sure I’m not the only one dealing this problem..
Thanks in advance…
viperx | 28-Aug-08 at 5:01 pm | Permalink
Personally I don’t like Smarty, nor any other template system. PHP is template system on its own, so I can’t see the benefit of using another layer on top of it. Zend Framework provides options to use 3rd party template systems, so if you like Smarty you can use it, but I can’t show you how to do it, because I don’t have experience with it.
For the PostgreSQL - I think the only problem should be the Session Manager. Indeed in the new releases of Zend Framework there is DB Session Manager included, I think it will work with PostgreSQL out of the box.
But if you will run memcache server for your web application I strongly suggest to use it as session storage.
mike | 05-Sep-08 at 2:07 am | Permalink
I am following an online tutorial . When i try to view a list of names i am getting this message:
Fatal Error: Cannot use string offset as an array in C:\apache\….\user\list.phtml on line ….
How can i address this. Looked everywhere but am not getting any solution.
Part of my the code being referred to looks like so:
datas;
for($i=1;$i
The table i have set with its headers display ok but the sells are the ones generating the above error!
Mike
mike | 05-Sep-08 at 2:10 am | Permalink
The foregoing statement is missing some code. It should read like this:
I am following an online tutorial . When i try to view a list of names i am getting this message:
Fatal Error: Cannot use string offset as an array in C:\apache\….\user\list.phtml on line ….
How can i address this. Looked everywhere but am not getting any solution.
Part of my the code being referred to looks like so:
datas;
for($i=1;$i
The table i have set with its headers display ok but the sells are the ones generating the above error!
Mike
mike | 05-Sep-08 at 2:14 am | Permalink
the 2 queries above are missing some characters. How can i make sure that all i have pasted in here gets displayed?
viperx | 05-Sep-08 at 9:19 am | Permalink
hi
it seems that the code you are trying to paste into the comment is lost by some reason, I don’t know why
send it as mail to me at viperx at andreinikolov.com and I will have a look
mike | 06-Sep-08 at 9:53 am | Permalink
i sent you an email.
mike
alexei | 11-Oct-08 at 12:16 pm | Permalink
What is it? The config.ini file in the right place. Plz help me
Fatal error: Uncaught exception ‘Zend_Config_Exception’ with message ‘parse_ini_file(Z:/home/sms/configuration/config.ini) [function.parse-ini-file]: failed to open stream: No such file or directory’ in Z:\usr\local\php5\Zend\library\Zend\Config\Ini.php:117 Stack trace: #0 Z:\home\sms\www\application\bootstrap.php(34): Zend_Config_Ini->__construct(’Z:/home/sms/con…’, ‘main’) #1 Z:\home\sms\www\public\index.php(3): require(’Z:\home\sms\www…’) #2 {main} thrown in Z:\usr\local\php5\Zend\library\Zend\Config\Ini.php on line 117
viperx | 17-Oct-08 at 4:42 pm | Permalink
Hi alexei,
if you are sure that there is config.ini file, located at
Z:/home/sms/configuration/config.ini
I really don’t know what can be the problem..
Joerg | 31-Oct-08 at 9:23 pm | Permalink
Hi, Andrei,
thank you very much for your great tutorial.
Could you please explain me, why you use the Registry::set method static and not as $registry->set()?
viperx | 12-Nov-08 at 8:09 pm | Permalink
Hi Joerg, sorry for my late answer
no particular reason for this - just a coding style..