Added by Wil Sinclair, last edited by Matthew Weier O'Phinney on Aug 20, 2008  (view change) show comment

Labels

 
(None)




Zend Framework QuickStart

Co-authored by Aldemar Bernal, Bradley Holt, & Wil Sinclair

Zend Framework is an open source, object oriented web application framework for PHP 5. ZF is often called a 'component library' because it has many loosely coupled components that you can use more or less independently, but it also provides an advanced model-view-controller (MVC) implementation that can provide the basic structure for ZF applications. A full list of Zend Framework components along with short descriptions may be found here . This QuickStart will introduce you to some of ZF's most commonly used components: Zend_Controller, Zend_View, Zend_Layout, Zend_Form, and Zend_Db.

Using these components, we will build a simple database-driven blog application within minutes. The complete source code for this application is available in the following archives:



MVC

So what exactly is this MVC pattern everyone keeps talking about, and why should you care? MVC is much more than just a three-letter acronym (TLA) that you can whip out anytime you want to sound smart; it has become something of a standard in the design of modern web applications. And for good reason. Most web application code falls under one of the following three categories: presentation, business logic, and data access. The MVC pattern models this separation of concerns well. The end result is that your presentation code can be consolidated in one part of the application with your business logic in another and your data access code in yet another. Many developers have found this well-defined separation indispensable for keeping their code organized- especially when more than one developer is working on the same application. More Info. . .

Use-at-Will MVC

Zend Framework provides a very simple, yet powerful, MVC implementation around which most ZF developers organize their applications. But- as is the case for all ZF components- our MVC components can be used at will. This means you can still take advantage of ZF's database, forms, web services- even view- components without necessarily consuming all of its MVC components.



Building an Application

Project Structure

Let's first create a basic MVC project structure for our application under the directory QuickStart:

Since the public directory will contain all files that should be directly accessible via our web server, you must set your web server's document root to this directory. Please check your web server's documentation on how to do this.


We will assume that your web server is running on your local machine and that your public directory is accessible at http://localhost/.

You can use the project structure that best suits your needs!

You will soon discover that Zend Framework is very flexible, and the project structure for ZF applications is no exception. There is nothing special about the project structure above, except some of the MVC components we'll be using work without overriding defaults in this structure. See the Zend Framework Reference Guide for more information.


Download and Install Zend Framework

Download the latest version of Zend Framework and extract the contents of the library folder to your project's library directory. You should now find the top-level Zend directory which contains all Zend Framework components under your library directory.
That's it! Zend Framework is now installed and ready to use.

Create a Rewrite Rule

Zend Framework's MVC implementation makes use of the Front Controller pattern. You must therefore rewrite all incoming requests (except those for static resources, which your application need not handle) to a single script that will initialize the FrontController and route the request.
If you're using mod_rewrite for the Apache web server, create the file QuickStart/public/.htaccess with the following contents:

This rewrite rule will cause all requests for URLs that do not end in .js, .ico, .gif, .jpg, .png, or .css to be dispatched to index.php. This is because files with these extensions are static resources; our application must return dynamic content on requests for all URL's that don't end with these extensions, so these requests must be handled by our PHP scripts. Since all requests for dynamic content will be rewritten to it, the index.php file serves as the entry point to our application.


Some web servers may ignore .htaccess files unless otherwise configured. Make sure that your web server is configured to read the .htaccess file in your public directory.

Checkpoint

Let's make sure everything is working so far. Create the file index.php and add the following contents:

Now open your favorite browser and enter the URL http://localhost/ to see a simple page that says "Hello, Zend Framework!" If this does not work, check your web server logs and make sure you have rewrite enabled with the correct rewrite rules for your web server.

Best Practices and Closing Tags

We didn't forget the closing (?>) PHP tag! We intentionally omit it to avoid unintentional output of whitespace in the response in certain cases. In fact, this is one of the best practices recommended in the Zend Framework coding standards.


Create a Bootstrap File

Let's take a quick look at that index.php file now. Replace the contents of QuickStart/public/index.php with the following:

This index.php script doesn't do much, but it is interesting in that it illustrates another best practice for Zend Framework applications. For security reasons, it is advisable to keep your application's scripts in a directory that your web server does not make publicly accessible. In this case, index.php quickly hands over control to the bootstrap.php file, which resides in the more secure application directory.

Now we need to create our bootstrap.php file, so called because it 'bootstraps' the application on each user request. Create the QuickStart/application/bootstrap.php file with the following contents:

At this point you should start to see your application taking shape. The bootstrap.php script sets up the application environment. This script typically should not contain business logic for your application, however.

You may ask why the call to dispatch() is made outside the bootstrap.php file. The rationale is for later down the line when you start functional testing your applications; with the above strategy, you can re-use your bootstrap.php script to setup your application environment when testing. This topic will be covered in a later tutorial.

The action controllers under the directory mentioned in step 3 of bootstrap.php above comprise the part of your application that will process the user request next. Action controllers, also called page controllers, represent the 'controller' part of the model-view-controller pattern. There is obviously a lot that the happens after the dispatch() method takes over and before it hands over control to your action controller, but you don't necessarily need to know the details to write full featured applications. See the Reference Guide for details on how requests are dispatched. For now let's move on to creating the action controllers themselves.

Relative Paths

Remember that QuickStart/public/index.php is the first script to which all requests are rewritten, so we must build our relative paths with respect to this file. That's how we came up with the '../library' and '../application/controllers' paths above.


Create an Action Controller

In Zend Framework's MVC implementation, both the default action controller and the default action are named 'index'. You should therefore set up the default action controller by creating QuickStart/application/controllers/IndexController.php with the following contents:

Because we're using the standard router, requests for http://localhost will be routed to the indexAction method on the IndexController action controller, as will requests to http://localhost/index and http://localhost/index/index.

Controller and Action Name Conventions

To work correctly with the standard router, action method names should follow the lowerCamelCase convention with the suffix 'Action'. Action controller classes, on the other hand, should follow the UpperCamelCase convention with the suffix 'Controller'. While the standard router should work for almost all applications, routing in Zend Framework is completely customizable. See the Reference Guide for details.

It may seem like indexAction() is doing nothing at all, but again Zend Framework is doing useful things for you behind the scenes. In this case it is routing the request to the appropriate view to return the correct response. Unless otherwise configured, the view it will look for is views/scripts/index/index.phtml, where the views directory is contained in the same folder as the controllers directory you passed to Zend_Controller_Front::run(). The file extension for views is yet another best practice recommended for Zend Framework applications; since view templates look suspiciously like PHP scripts in ZF, it is easier to distinguish view templates from other PHP files if you use the .phtml extension instead of .php.

Checkpoint

Let's create the view script now with the following contents:

Now go to http://localhost; you should see 'Hello, Zend Framework MVC!' with very basic formatting.
If you do not see this message, check your server logs and make sure you've created the specified files with the exact contents from above.

Template Engines

Although ZF has its own template engine that renders templates very similar to standard PHP, you can easily configure Zend Framework to use other template engines such as Smarty or PHPTAL. See the reference guide for details.

Create an Error Controller

The last things you want to display to an end-user of your site are either a blank page or exceptions. Zend Framework's MVC recognizes this, and provides an ErrorHandler plugin that will detect exceptions and dispatch an ErrorController so that you can display alternate content.

Additionally, you need some way to handle 404 situations – i.e., situations when the action or controller are not found.

In development, you do want to see exceptions. Fortunately, we can accomodate both.

The ErrorHandler plugin by default will dispatch the errorAction() of the ErrorController. Let's build our controller.

The above may seem a bit esoteric. First, the ErrorHandler plugin stores error information, including the error type, exception caught, and the request that produced it, within a token that is passed in the request. We grab that first.

Second, we do some switching based on the exception type. There are two types of exceptions that represent 404 situations – controller not found and action not found. For these, we change the HTTP response code to 404 to indicate this. All other exceptions are considered application exceptions, and we'll return the appropriate HTTP response code for these – 500.

Third, remember the env variable we pushed into the front controller in the bootstrap file? We're going to pull that and push it into the view. More on this later.

Finally, we pass some information to the view – the exception and request.

Let's look at the related view script, which we'll place in views/scripts/error/error.phtml.

Note the use of the env flag. We're now using it in the view script to determine whether or not to display exception information. In development, you'll get full information; changing the value in your bootstrap.php file will then disable this sensitive information from being displayed, while still providing a reasonable error message to your end users.

You can take a look at what it does by going to a bogus URL in your application. Try one of the following: /bogus or /index/bogus.

Build a Form

Admittedly, our application at this point isn't very interesting. Adding some interactive content would certainly help, so let's start rendering and processing basic HTML forms using Zend_Form. Replace the contents of the IndexController.php file with the following:

Since this form has been built using the Zend_Form component, form handling should be a cinch. Validation, filtering, rendering, displaying errors, and a lot more form-related functionality are dramatically simplified with Zend_Form. By looking closely at the _getCommentForm() method above, you should notice that it returns a form with a required text area for the comment and a button to submit that comment. Let's display this form in our index controller through a new action called 'contact' and view to see how it looks after rendering. Create a new action method in the index controller IndexController.php called commentAction() method in your file with the following:

A few things are happening here. First, we create the form to use in the rest of the method. Next, we check whether the user is submitting the form data- in which case we would expect an HTTP POST request- or loading a blank form- in which case we would expect an HTTP GET request. If the user is submitting a comment, we pass this data in the $_POST variable to the form for validation. If all goes well during validation, we get the filtered values from the form (in this case no filters have been set). We can pass these values to the view by setting the $values on the view object.
You must now alter your view so that it knows what to do with the form and any values that are passed to it. Replace the contents of the scripts/index/index.phtml file with the following:

Now your view is checking if there are any values to display and, if so, listing them. Regardless of whether values are displayed or not, the form is rendered near the end of the view.

Always keep security in mind!

To build secure applications, you must always keep an eye out for vulnerabilities in your code and apply security best practices where appropriate.
For example, in this view we escape user input like so: $this->escape($value);. Neglecting to escape user input before outputting it could create a big vulnerability in your application. Malicious or uninformed users could affect the appearance or behavior of your application's pages. In particular, the user input might invoke scripts that could compromise the security of your application. Always escaping user input before adding it to a response is an important security best practice.

Now, when you go to http://localhost/index/comment you should see something like this:

And if you enter a comment and hit the 'Add Comment' button, you should now see something like this:

And if you do not enter a comment and hit the 'Add Comment' button, you'll see something like this:

This last example should give you a taste of the power that Zend_Form can bring to your applications. Simply by setting the 'required' attribute on your 'comment' form element to true, you have built a validated form that will display an error if the comment text area is empty. The error message itself can be specified during form creation.

Better Looking Forms

No one will be waxing poetic about the beauty of this form anytime soon. No matter- form appearance is fully customizable! See the decorators section in the reference guide for details.

Access a Database

Under Construction!

Congratulations!

You have now built a very simple application using some of the most commonly used Zend Framework components. Zend Framework makes many more components available to you and your applications, including web services, search, PDF reading and writing, authentication, authorization, and much more. You'll find that there are components that address most requirements you are likely to encounter while building a web application. The Reference Guide is a great place to find out more about the components you've used in this QuickStart as well as other Zend Framework components. We hope you find Zend Framework useful and- more importantly- fun!

Only just looked it over, but would like to suggest the hoops to jump through be reduced right down to:

1. download it
2. unpack it
3. run it

Setting up a web server config and also DB per demo seems like overkill to me these days.

I believe all you really need to do is make any links in the demo to be document root aware such that it works from its own subdirectory and at any path depth under document root allowing other demos to share the document root however the user wishes them organised.

The other point is that an instant DB based demo would need to be bundled with an SQLite DB file by default, perhaps with the option of following additional steps to configure own choice DBs where "pear install sqlite" is somehow not an option/desired.

Other project demos work out of the box like this (eg. Xajax) and I think it's kind of becoming expected. I Hope ZF demos go that way too for maximum ease of use.

Anyway, great start to see this. I'm sure ZF newbies to 1.5 will be grateful. I know I would have been!

It's really a balance between simplicity and creating a somewhat realistic example that will actually ramp up newcomers sufficiently so they can start playing around with their own applications. If we over-simplify things to meet the expectation RoR and other projects set, we won't be leaving our newcomers with enough knowledge to do anything. In fact, one could argue that the only reason that RoR and clones have 5-minute time-to-hello-worlds is because they over-simplify web apps on the whole to optimize this relatively insignificant use case (when considered over the entire experience with a application framework). We're already working on tooling that delivers this without the compromises and strict conventions.
I see your point, however. I'll see how we might be able to use the downloadable code to make things simpler. And of course we'll write a separate QuickStart when our CLI tools are available. I've already heard requests to keep the explicit one alongside such a CLI-based QuickStart, however, to underscore our use-at-will architecture- which will include tooling, CLI and otherwise- and foster a deeper understanding of the framework.
I'd be interested in your feedback once we've completed the final version of the QuickStart for 1.5.

I notice you are using regular php tags and then an echo statement in view scripts:

instead of short open tags:

Most (if not all) of the ZF docs I've read so far use short open tags in view scripts. Is this an intentional departure from previous docs?

Not an intentional departure, no. We can use the short tags if you think that almost all users have them enabled and would know what to do if they don't.

I don't really think it's a big deal one way or the other - just noticed it was different than before and I'm sure a lot of people look to the Zend Framework documentation for best practices. I think Matthew had mentioned something on list about adding a stream wrapper for those people who don't have short tags enabled. BTW, the QuickStart looks great!

Here is the link of ZF code standard

http://framework.zend.com/manual/en/coding-standard.coding-style.html

You will see this: "Short tags is NEVER allowed"

However, in the documents, there are some examples did not follow this rule. Maybe they will be revised later.

It is allowed but only in view scripts. Matthew explains it best here: http://www.nabble.com/shouldn't-ZF-promote-not-using-short-tags-td15897713s16154.html

Here's a corrected version of the last index.phtml file:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Zend Framework Quick Start</title>
</head>
<body>
<h1>Basic Blog</h1>
<?php if($this->values)

Unknown macro: { ?> <h3>You just submitted the following values}
?>
<?php echo $this->form; ?>
</body>

There where to endforeach statements..

OK - that didn't work!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
  <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
    <title>Zend Framework Quick Start</title> 
  </head> 
  <body> 
  <h1>Basic Blog</h1>
    <?php if($this->values)

Unknown macro: { ?>    <h3>You just submitted the following values}
?>
    <?= $this->form; ?> 
  </body>

Is what you want.

Yeah that too. The if statement used the curly bracket, I was trying for the brackets.

You can use the code macro to display code with curly braces easily:

{code:php}
// Some PHP code here
{code}

Ok - just take the last endforeach and replace it with a }

Solution for form:
1. step
replace second endforeach; with }

2. step
replace all:
<?=
with:
<?php print

Thats it - this worked for me...
Luke

Second step was caused by php.ini settings, where I have set: short_open_tag = Off

IIRC - Having short_open_tag off is better because:
1.) Will not have issues with XML files.
2.) Less overhead on the PHP engine. Very small overhead, but still overhead.

3.) short_open_tags will be deprecated in PHP6.

Balu

Thank God!

Wil, you should put your name as a co-author as well. You put as least as much work into it as I did, if not more!

It's been more than 2 days, where's the DB part?!

because the db part is still missing, here is how it worked for me (one should know how to perform each step when trying to use the zf, so no in-depth explaining):

if not yet installed: get the pdo db libs from php.net (NOTICE: they are contained inside the ZIP file, not inside the istaller package!) and add the following lines to your php.ini:

extension=php_pdo.dll
extension=php_pdo_mysql.dll

1) create a database "quickstart" and add the user/pass to it like it is configured in quickstart\application\config\quickstart.ini

2) create the table that holds the data (reverse engineered, real struct may differ):

CREATE TABLE `comments` (
`comment_id` int(10) unsigned NOT NULL auto_increment,
`comments` text NOT NULL,
PRIMARY KEY (`comment_id`)
);

3) that's all. i used phpmyadmin for it

hope that helps.

Several comments here. Let's begin with who your expected audience is. People who come to this page do so via the "Quick Start" link on the homepage, so it's safe to assume that none of them will have any experience with Zend Frameworks. You can probably assume that they have some experience in PHP, some knowledge of OOP, and some experiance in web development, but there's no reason to expect much more than that. Indeed for this Quick Start there is no reason that anyone should need to know any more than that.

The reason I mention all that is because anything that you say that is outside the reader's knowledge base will either be meaningless to them or turn them off the product.

>> Let's first create this basic MVC project structure for our application under the directory QuickStart:

It would probably be helpful to link "MVC" somewhere. Not everyone will be familiar with the term, but it's pretty critical to understanding what's going on. This is part of the "know your audience" rule.

>> Since the public directory will contain all files that are made directly accessible by our web server, you must either create a new directory in your web server which points to your public folder or set your default web server document root to this directory. Please check your web server's documentation on how to do this.

I'm not sure what this means especially the part about creating "a new directory in your web server which points to your public folder". I believe that the only thing the user really has do do here is make sure the QuickStart project is created underneath the DocumentRoot.

_>> For the rest of this QuickStart we will assume that your web server is running on your local machine and that your public directory is accessible via the web at http://localhost._

I would move this to the very beginning and have a link to a page discussing how to install an Apache/PHP/MySQL stack for those who haven't done so.

>> Create a Rewrite Rule

I didn't understand any of this and the "Front Controller" link didn't help. I don't know that I need to understand it other than to know that its purpose is to redirect (dispatch?) .html and .php files to index.php.

>> Create the file QuickStart/public/index.php with the following content: <?php require '../application/bootstrap.php'; The code here deviates from that in the index.php file that was downloaded.
 >> Create the QuickStart/application/boootstrap.php file with the following contents:
 Well, there's no bootstrap.php in the quickstart.zip file I just downloaded. At this point the QuickStart guide has deviated so far from the downloaded example that there's no point in going on, at least for me.
 

All good points. I'll read through the existing draft and update it to reflect your feedback. Obviously, this is a work in progress right now. My intention was to finish it very quickly after the 1.5 release, but all those things that we said could wait until 'after the 1.5 drop' have now been coming back to haunt me. I'm very sorry about this and hope you still got something out of the tutorial so far.

There is an error in the Comment example code. In the index.phtml file there is an extra <? endforeach; ?> that should instead be a closing bracket <? } ?>

Other than that, nice guide.

Posted by Adrian at Apr 02, 2008 23:24

I totally agree to Bill Norton.

I use php for several years now in small to mid-sized projects but I never ever had my hands on ZF.

Since there was so much tamtam about the new ZF, I decided to give it a try and - you might guess it - followed the eye catching and very promising Quickstart link. And landed here.

The Quickstart won some contest. The Quickstart id official. The Quickstart itself is pretty useless. And unmaintained. There should be exactly noone who was able to have a running whatever after going through the Quickstart (which even is not complete for months now - in business months) without at least a little reverse engineering of the DB (remember the no-ZF-experience-thingie).

Nothing is explained (the WHYs and HOWs are missing), the firstmost point (creating a rewrite rule) I "have to do" is even not needed at all.

After all, all this is VERY disappointing. Moreover: A Quickstart should be created by the company (and I think ZEND has the bucks to spend them on such a little thing) that wants a bigger market coverage and not by the community which is the market.

I'm sorry that you find the QuickStart so disappointing. We really intended to address a lot of feedback that we've gotten from the 1.0 release, and I'm sure it would have come off better for the 1.5 release if I had found- or just made- more time to finish the QuickStart. That is entirely my fault, and I'll say it again to you personally: I'm very sorry.
But I don't agree with many of your points. We didn't intend to get in to all the why's and how's. This QuickStart is meant to be gone through in 30 minutes if one really concentrates on it. There are other sources for the full background such as the reference guide; this is meant to get developers building functional applications as quickly as possible.
Second, I'm really happy to hear that you have so much confidence in the business aspect of Zend Technologies, but allow me to give you a little more insight in to how things get done at Zend WRT ZF. We have a dedicated team of 5 developers for Zend Framework. AFAIK , this is no more than most other PHP framework projects. Every one of the Zend developers on the ZF project has at least 100 non-trivial things he sees signi