You are on page 1of 41

Beginning Zend Framework

Or:
How I learned to stop worrying and love the
framework.

Part 1: Setting up
Preparing Zend Framework


Download ZF1.9
– svn co
http://framework.zend.com/svn/framework/standard/tags/release-1.9.1/library/Zend


Add directory containing Zend to php.ini as part of
the path.

Alternately, check out the framework into your pear
directory.
Preparing ZF Contd.


Check out bin (Zend Tool)
– svn co
http://framework.zend.com/svn/framework/standard/tags/release-1.9.1/
bin


Copy zf.php and zf.sh to a directory in your path
(/usr/bin)

Rename zf.sh to zf and make it executable
Using Zend_Tool to set up your project


Create a directory to house your projects
– mkdir projects

Enter directory
– cd projects

Create a project using the zf script
– zf create project {projectname}
Add project to apache


This can vary widely with OS and version, so
you're mostly on your own.

Make the DocumentRoot the “public” directory
within your {projectname} directory.

After reloading apache, you should be able to go to
the site you just set up and see the default zend
framework page!
Normal Application Setup


Normally we would have the domain set up to point
directly to the “public” directory
– Keeps php code from being directly accessible
– NO php should go in public folder unless it’s simple
and framework is overkill for it

Except for index.php
Directory Structure

/application
– application files…more in a moment

/library
– framework files ( /library/Zend )
– Extra classes/libraries used by the app

/public
– index.php, html/js/images/etc, anything that should
be directly accessible by the browser

/tests
– unit tests… another time maybe
Application Directory

Bootstrap.php
– Specific application – framework setup

configs
– Application .ini file (soon)

controllers
– Holds controller classes (gasp!)

models
– Holds model classes (double-gasp!)

views
– You get one guess what goes in here…
– Wrong, not classes, simple php+html files.
index.php


Prepares include path

Specifies application configuration

Load & run bootstrap
Create a database/table


Use whatever tools you're used to
CREATE TABLE `user` (
`user_id` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR( 255 ) NOT NULL ,
`email` VARCHAR( 128 ) NOT NULL ,
`password` VARCHAR( 32 ) NOT NULL ,
`salt` VARCHAR( 32 ) NOT NULL ,
`api_key` VARCHAR( 32 ) NOT NULL ,
`api_secret` VARCHAR( 32 ) NOT NULL ,
`user_type` TINYINT NOT NULL ,
PRIMARY KEY ( `user_id` ),
UNIQUE KEY `username` (`username`)
)
Add database to app config


Edit application/configs/application.ini
# Database
resources.db.adapter = "pdo_mysql"
resources.db.params.host = "localhost"
resources.db.params.username = "zfclass"
resources.db.params.password = "zfclass"
resources.db.params.dbname =
"zfclass_{yourname}"
resources.db.isDefaultTableAdapter = true
application.ini


Note that application.ini has multiple sections
– Production, Staging, Development
– Defined in .htaccess
– Can be used to specify different databases for
different environments
Configuring the layout


What's a layout?
– 2-step way of providing “overall” layout to your app
– View result html will be placed as “content” in
layout
– Layout can house dynamic links for header js, css,
etc
– Easily reached from controller or view.
Layout Contd.


Create directory application/layouts and
application/layouts/scripts

Add the following to your application.ini:
#layout
resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
Module Layouts


We're making an admin module

Let's load a specific admin layout for it
application/plugins/ModuleLayout.php

class Plugin_ModuleLayout extends Zend_Controller_Plugin_Abstract


{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$module = strtolower($request->getParam('module'));
$layout = Zend_Layout::getMvcInstance();

if ($layout->getMvcEnabled())
{
switch($module) {
case 'default':
break;
default:
$layout->setLayoutPath(APPLICATION_PATH .
'/modules/' . $module . '/layouts/scripts');
break;
}
}
}
}
Enable the plugin


Edit application/Bootstrap.php
public function _initLayouts() {
Zend_Layout::startMvc();
$this->getPluginResource('frontcontroller')
->getFrontController()
->registerPlugin(new Plugin_ModuleLayout());
}
Application general layout


applications/layouts/scripts/layout.phtml
<?php echo $this->doctype() ?>
<html>
<head>
    <?php echo $this->headTitle() ?>
    <?php echo $this->headLink() ?>
    <?php echo $this->headStyle() ?>
    <?php echo $this->headScript() ?>
</head>
<body>
    <?php echo $this->layout()->content ?>
</body>
</html>
Create a User model


application/models/DbTable/User.php
<?php
class Model_DbTable_User extends Zend_Db_Table
{
protected $_name = 'user';
protected $_primary = 'user_id';
User Model Cont'd

public function addUser($username, $email, $password, $user_type=1)


{
// generate unique id for the password salt
$salt = strtolower(uniqid(rand(), true));
// and finally...one more for their initial api 'secret' key
$api_secret_key = strtolower(uniqid(rand(), true));
// create a password hash to save in the database
$hashed_pwd = strtolower(md5($password . $salt));
User Model...

$data = array(
'username' => $username,
'email' => $email,
'password' => $hashed_pwd,
'salt' => $salt,
'user_type' => $user_type
);
return $this->insert($data);
}
User Model...
function updateUser($id, $email, $password=null, $user_type=1)
{
$where = array('user_id = ?' => (int)$id);
$data = array('email' => $email,'user_type'=>$user_type);
if ($password !== null){
// generate unique id (again) for the password salt
$salt = strtolower(uniqid(rand(), true));
$hashed_pwd = strtolower(md5($password . $salt));
$data['salt']=$salt;
$data['password']=$hashed_pwd;
}
$this->update($data, $where);
}
} // End class
Autoloader

Allow us to call our model class without having to
include it manually
– In application/Bootstrap.php
public function _initAutoload() {
$autoloader = new Zend_Application_Module_Autoloader(
array(
'namespace'=>'',
'basePath'=>APPLICATION_PATH
)
);
return $autoloader;
}
Database Profiling in Firebug!


Still in Bootstrap.php
public function _initDbprofile() {
if($this->getEnvironment() == 'development') {
$profiler = new Zend_Db_Profiler_Firebug('All DB
Queries');
$db = $this->getPluginResource('db');
$db = $db->getDbAdapter();
$profiler->setEnabled(true);
$db->setProfiler($profiler);
}
}
URL Structure


Defaults to Index controller & Index action
– /public/{controller}/{action}
– /public/{module}/{controller}/{action}
– /public/{controller} (assumes Index action)
– /public/{controller}/{action}/{key}/{value}/{key2}/
{value2}
– /public/admin/user/edit/user_id/3 (admin = module)
URL Routing


You can create your own url structures using
Zend_Controller_Router_*
– Many options

Static

Regex

Hostname

Chain
– http://framework.zend.com/manual/en/zend.controller.router.html
Create Admin Module


Use zf tool
– zf create module admin

Enable module in application.ini
– Add to [production] area
– resources.frontController.moduleDirectory
= APPLICATION_PATH “/modules”
● Copy application/layout/scripts/layout.phtml to
application/modules/admin/layouts/scripts/layout.phtml
Create User Controller

● zf create controller user false admin



One small bug in zf tool:
– Rename admin/controllers/UserController.php to
Admin_UserController.php
– Rename class in file to Admin_UserController
Create Action

● zf create action createuser user 1 admin



Open User controller file in an editor...
Create a form programatically!
public function createuserAction()
{
// create form
$form = new Zend_Form();
$form->setMethod('post');
$form->addElement('text','username', array(
'label' =>'User name',
'required'=>true,
'filters'=>array('StringTrim')
));
$form->addElement('password','password',array(
'label'=>'Password',
'required'=>true,
'filters'=>array('StringTrim')
));
$form->addElement('text','email',array(
'label'=>'Email address',
'required'=>true,
'filters'=>array('StringTrim'),
'validators'=>array('EmailAddress')
));
$form->addElement('captcha','captcha',array(
'label'=>'Enter the letters below',
'required'=>true,
'captcha'=>array(
'captcha'=>'Figlet',
'wordLen'=>5,
'timeout'=>300
)
));
$form->addElement('submit','Save',array(
'ignore'=>true,
'label'=>'Save New User'
));
// End form
$request = $this->getRequest();

if($request->isPost()) {
if($form->isValid($request->getPost())) {
$data = $form->getValues();
$user = new Model_DbTable_User();
if($user->addUser(
$data['username'],
$data['email'],
$data['password'],2)) // 2 for admin
{
$this->view->message = 'User created';
} else {
$this->view->message = 'Something bad happened.';
}
}
}

$this->view->form = $form;
} // End function
Create View

application/modules/admin/views/scripts/user/createuser.php
<?php
if(isset($this->message)) {
?><h1><?=$this->message ?></h1><?php
}
?>
Create your new user.
<?php
$this->form->setAction($this->url());
echo $this->form;
?>
Create your user!


You should now be able to head to
http://{yoursite}/admin/user/createuser

Try it out!
Create a login action


Close the user controller file in your editor
● zf create action login user 1 admin

Open it back up and find the loginAction method
public function loginAction()
{
$form = new Zend_Form();
$form->setMethod('post');
$form->addElement('text','username', array(
'label' =>'User name',
'required'=>true,
'filters'=>array('StringTrim')
));
$form->addElement('password','password',array(
'label'=>'Password',
'required'=>true,
'filters'=>array('StringTrim')
));
$form->addElement('submit','submit',array(
'label'=>'Login',
'ignore'=>true
));
$request = $this->getRequest();
$data = $request->getPost();
if($request->isPost() && $form->isValid($data)) {
$u = new Model_DbTable_User();
$auth = new Zend_Auth_Adapter_DbTable($u->getAdapter()
,'user','username','password',
"MD5(CONCAT(?,salt)) AND user_type=2"
);
$auth->setIdentity($data['username'])->setCredential(
$data['password']
);
$mainauth = Zend_Auth::getInstance();
$result = $mainauth->authenticate($auth);
if($result->isValid()) {
$this->view->message = 'You are now logged in.';
} else {
$m = $result->getMessages();
$this->view->message = $m[0];
}
}
$this->view->form = $form;
}// End function
Create a logout action


Try the initial part yourself to create the action
method.
public function logoutAction() {
$auth=Zend_Auth::getInstance();
$auth->clearIdentity();
$this->_redirect('/admin/user/login');
}
Create a login “helper”
Edit application/modules/admin/views/helpers/LoginLink.php
<?php
class Admin_View_Helper_LoginLink extends Zend_View_Helper_Abstract {
public function loginLink() {
$auth = Zend_Auth::getInstance();
$front = Zend_Controller_Front::getInstance();
if($auth->hasIdentity()) {
$username = $auth->getIdentity();
return "Hello, $username [<a href='".$front->getBaseUrl().
"/admin/user/logout'>Logout</a>]";
} else {
return '[<a href="'.$front->getBaseUrl().
'/admin/user/login">Login</a>]';
}
}
}
Add login helper to layout


Edit application/modules/admin/layouts/scripts/layout.phtml
Add before echo content:
<div id="login">
<?php echo $this->loginLink();?>
</div>
This calls the LoginLink helper we created before.
Try it out: http://{yoursite}/admin/user/login
Enough for now


If we got this far at the meeting, I'm amazed.

If not, I can continue at the next meeting.

You might also like