Building A Zend Framework Application - Akrabat

Transcription

Building a ZendFramework applicationRob Allen

Rob Allen? PHP developer since 1999Wrote Zend ConfigTutorial at akrabat.comBook!TEK·X 2010Rob Allen http://akrabat.com

What weʼll cover Overview of Zend Framework Getting and installing it The basics of a ZF MVC application An application: todolist MVC application: DB access, layouts etcForms, caching, authentication Please ask questions as we go!TEK·X 2010Rob Allen http://akrabat.com

ZF overview

What is ZF? PHP5 component library MVC Components make a “framework” Open source - BSD license Documented Quality assured Certification Actively maintained by ZendTEK·X 2010Rob Allen http://akrabat.com

ZF Philosophy Use-at-will Simple usage 80% of the time Showcase current trends OO best practiceweb servicesdev best practice: unit testing, documentationfor 2.0: PHP 5.3 namespaces & closuresTEK·X 2010Rob Allen http://akrabat.com

TEK·X 2010Rob Allen http://akrabat.com

The MVC systemTEK·X 2010Rob Allen http://akrabat.com

Routing: 1//news/2008/11 route new Zend Controller Router Route('news/:year/:month',array('controller' 'news','action' 'archive'),);TEK·X 2010Rob Allen http://akrabat.com

Getting andinstalling ZF

Installation http://framework.zend.com/download/latestTEK·X 2010Rob Allen http://akrabat.com

Install Unzip or untar: tar -zxf ZendFramework-1.10.3-minimal.tar.gzunzip ZendFramework-1.10.3-minimal.zip /usr/local/include/zendframeworkc:\zendframework Store in a common placeTEK·X 2010Rob Allen http://akrabat.com

Add to include path# Apache: VirtualHost , Directory or .htaccess:php value include path ".:/usr/local/include/zendframework/library"# or PHP:set include path(implode(PATH SEPARATOR, array('.','c:/zendframework/library',get include path(),)));TEK·X 2010Rob Allen http://akrabat.com

Install zf utility bin/zf.sh or bin/zf.bat Place on path (or create alias): aliaszf /usr/local/include/zendframework/bin/zf.shTEK·X 2010Rob Allen http://akrabat.com

or use PEAR#pear channel-discover pear.zfcampus.orgAdding channel "pear.zfcampus.org" succeededDiscovery of channel "pear.zfcampus.org" succeeded#pear install zfcampus/downloading ZF-1.10.2.tgz .Starting to download ZF-1.10.2.tgz (3,520,994 bytes). done : 3,520,994 bytesinstall ok: channel://pear.zfcampus.org/ZF-1.10.2#which zf/usr/bin/zfTEK·X 2010Rob Allen http://akrabat.com

A Zend FrameworkMVC application

A to-do list application Create a list of todo items with optional notes and due dates Single tasks database table Main list shows open tasks Logged in user sees only their own tasksTEK·X 2010Rob Allen http://akrabat.com

SpecificationA todo item consists of:taskstring (required)notesstring (optional)due datedatetime (optional)completedboolean (required)identifierinteger (required - primary key)created byinteger (for use later)TEK·X 2010Rob Allen http://akrabat.com

Create the projectzf create project todolist# if ZF is not on your path:cd todolist/libraryln -s /usr/local/include/zendframework/library/Zend .# orcp -r /usr/local/include/zendframework/library/Zend .TEK·X 2010Rob Allen http://akrabat.com

Apache vhostvim /etc/apache2/extra/httpd-vhosts.conf# From todolist/docs/README.txt VirtualHost *:80 DocumentRoot "/www/todolist/public"ServerName todolist.localhost# This should be omitted in the production environmentSetEnv APPLICATION ENV development Directory "/www/todolist/public" Options Indexes MultiViews FollowSymLinksAllowOverride AllOrder allow,denyAllow from all /Directory /VirtualHost TEK·X 2010Rob Allen http://akrabat.com

hosts filevim /etc/hostsor notepad c:\windows\system32/drivers/etc/hosts127.0.0.1 todolist.localhostTEK·X 2010Rob Allen http://akrabat.com

Run it!TEK·X 2010Rob Allen http://akrabat.com

DirectoriesTEK·X 2010Rob Allen http://akrabat.com

DirectoriesTEK·X 2010Website filesRob Allen http://akrabat.com

DirectoriesTEK·X 2010BootstrappingRob Allen http://akrabat.com

DirectoriesTEK·X 2010MVCRob Allen http://akrabat.com

DirectoriesTEK·X 2010Unit testingRob Allen http://akrabat.com

n.iniTEK·X 2010Rob Allen http://akrabat.com

.htaccessRewriteEngine OnRewriteCond %{REQUEST FILENAME} -s [OR]RewriteCond %{REQUEST FILENAME} -l [OR]RewriteCond %{REQUEST FILENAME} -dRewriteRule .* - [NC,L]RewriteRule .* index.php [NC,L]TEK·X 2010Rob Allen http://akrabat.com

index.php (environment) ?php// Define path to application directorydefined('APPLICATION PATH') define('APPLICATION PATH',realpath(dirname( FILE ) . '/./application'));// Define application environmentdefined('APPLICATION ENV') define('APPLICATION ENV',(getenv('APPLICATION ENV') ? getenv('APPLICATION ENV') :'production'));// Ensure library/ is on include pathset include path(implode(PATH SEPARATOR, array(realpath(APPLICATION PATH . '/./library'),get include path())));TEK·X 2010Rob Allen http://akrabat.com

index.php (application)/** Zend Application */require once 'Zend/Application.php';// Create application, bootstrap, and run application new Zend Application(APPLICATION ENV,APPLICATION PATH . '/configs/application.ini'); application- bootstrap()- run();TEK·X 2010Rob Allen http://akrabat.com

Bootstrap.phpclass Bootstrap extends Zend Application Bootstrap Bootstrap{}TEK·X 2010Rob Allen http://akrabat.com

play startup errors 0phpSettings.display errors 0includePaths.library APPLICATION PATH "/./library"bootstrap.path APPLICATION PATH "/Bootstrap.php"bootstrap.class "Bootstrap"appnamespace irectory APPLICATION PATH playExceptions 0[staging : production][development : production]phpSettings.display startup errors 1phpSettings.display errors s 1TEK·X 2010Rob Allen http://akrabat.com

Action controllers Contain your application workflow Map requests to models and views. Class name: NewsController Action methods: listAction() Home: IndexController::indexAction() ErrorController::errorAction() for 404and 500sTEK·X 2010Rob Allen http://akrabat.com

Views Controller integration using ViewRenderer view property in controller: Folder: application/views/scripts/ Script naming: In view scripts:NewsController::detailAction() news/detail.phtml ? this- escape( this- item- title); ? TEK·X 2010Rob Allen http://akrabat.com

Model There is no Zend Model! Database adapters: Zend Db Table row gateway: Zend Db Table Web services: Zend Service Xxx, Zend Soap ORMs: Doctrine, Propel NoSQL: CouchDB, MongoDB, CassandraTEK·X 2010Rob Allen http://akrabat.com

Letʼs build an app

Database tableCREATE TABLE IF NOT EXISTS tasks (id int NOT NULL AUTO INCREMENT,title varchar(200) NOT NULL,notes text,due date datetime,completed tinyint(1) NOT NULL DEFAULT '0',date created datetime NOT NULL,PRIMARY KEY (id)) ENGINE InnoDB DEFAULT CHARSET utf8;INSERT INTO tasks (title, due date, date created)VALUES ('Task 1', '2010-05-30', NOW());INSERT INTO tasks (title, due date, date created) VALUES('Task 2', '2010-05-010', NOW());TEK·X 2010Rob Allen http://akrabat.com

Zend Db Table modelTEK·X 2010Rob Allen http://akrabat.com

Configure db access[production].resources.db.adapter "Pdo Mysql"resources.db.params.charset "utf8"resources.db.params.host "localhost"resources.db.params.username "todolist"resources.db.params.password "password"resources.db.params.dbname "todolist"resources.db.params.profiler.enabled false[development : production].TEK·X 2010Rob Allen http://akrabat.com

Zend Db Table model zf create db-table Tasks tasksCreating a DbTable at Updating project profile '/www/todolist/.zfproject.xml'class Application Model DbTable Tasksextends Zend Db Table Abstract{protected name 'tasks';protected rowClass 'Application Model DbTable Task';}TEK·X 2010Rob Allen http://akrabat.com

Row objectclass Application Model DbTable Taskextends Zend Db Table Row Abstract{protected function insert(){ this- date created date('Y-m-d H:i:s');}}TEK·X 2010Rob Allen http://akrabat.com

Model access method// Application Model DbTable Taskspublic function fetchOutstanding(){ select this- select(); select- where('completed 0'); select- order(array('date created DESC', 'id ASC'));return this- fetchAll( select);}TEK·X 2010Rob Allen http://akrabat.com

Index controllerclass IndexController extends Zend Controller Action{public function indexAction(){ this- view- title 'Outstanding tasks'; tasksGateway new Application Model DbTable Tasks(); this- view- tasks tasksGateway- fetchOutstanding();}}TEK·X 2010Rob Allen http://akrabat.com

indexAction() view script h1 ?php echo this- escape( this- title); ? /h1 table tr th Task /th th Due /th /tr ?php foreach ( this- tasks as task) : ? tr td ?php echo this- escape( task- title);? /td td ?php echo task- due date ?date('d m Y', strtotime( task- due date)) : '-';? /td /tr ?php endforeach;? /table TEK·X 2010Rob Allen http://akrabat.com

Layouts: Composite viewTEK·X 2010Rob Allen http://akrabat.com

Enable layout zf enable layoutLayouts have been enabled, and a default layout created .phtmlA layout entry has been added to the application config file. ?php echo this- layout()- content; ? TEK·X 2010Rob Allen http://akrabat.com

Layout placeholders// controller action method html view- render('sidebar.phtml'); layout- sidebar html;// view script ?php echo this- layout()- sidebar; ? TEK·X 2010Rob Allen http://akrabat.com

Site-wide layout file ?php this- headMeta()- appendHttpEquiv('Content-Type', 'text/html;charset utf-8'); this- headTitle('Todo List')- setSeparator(' - ');echo this- doctype(); ? html xmlns "http://www.w3.org/1999/xhtml" head ?php echo this- headMeta(); ? ?php echo this- headTitle(); ? ?php echo this- headLink()- appendStylesheet( this- baseUrl().'/css/site.css'); ? /head body div id "content" ?php echo this- layout()- content; ? /div /body /html TEK·X 2010Rob Allen http://akrabat.com

TEK·X 2010Rob Allen http://akrabat.com

Forms

Zend Form architecture Forms: the centre piece Forms are made up of: Elements, Display groups, Sub-forms Each element is made up of: Filters, Validators, DecoratorsTEK·X 2010Rob Allen http://akrabat.com

Create a form zf create form taskCreating a form at /www/todolist/application/forms/Task.phpUpdating project profile '/www/todolist/.zfproject.xml'class Application Form Task extends Zend Form{public function init(){/* Form Elements & Other Definitions Here . */}}TEK·X 2010Rob Allen http://akrabat.com

Add an element title new Zend Form Element Text('title'); title- setRequired(true); title- setLabel('Title'); title- addFilters(array('StringTrim', 'StripTags')); title- addValidators(array(new Zend Validate StringLength(array('min' 5)))); title- addElement( email);TEK·X 2010Rob Allen http://akrabat.com

Submit button element new Zend Form Element Submit('submit-button'); element- setIgnore(true); element- setLabel('Add task'); this- addElement( element);TEK·X 2010Rob Allen http://akrabat.com

Action codepublic function addAction(){ request this- getRequest(); form new Application Form Task();if ( request- isPost()) {if ( form- isValid( request- getPost())) {// success formData form- getValues();}} this- view- form form;}TEK·X 2010Rob Allen http://akrabat.com

View script h1 Add task /h1 ?php this- form- setAction( this- url());echo this- form;? TEK·X 2010Rob Allen http://akrabat.com

Store to model// IndexController::addAction()if ( request- isPost()) {if ( form- isValid( request- getPost())) {// success formData form- getValues(); tasks new Application Model DbTable Tasks(); tasks- addTask( formData); this- helper- redirector('index');}}TEK·X 2010Rob Allen http://akrabat.com

Model methods// Application Model DbTable Taskspublic function addTask(array taskData){ data array('title' taskData['title'],'due date' taskData['due date']); this- insert( data);}public function updateTask( id, taskData){ data array('title' taskData['title'],'due date' taskData['due date']); this- update( data, 'id ' . (int) id);}TEK·X 2010Rob Allen http://akrabat.com

Custom form element// Application Form Task due new Application Form Element Date('due date'); due- setRequired(false); due- setLabel('Due'); this- addElement( due);TEK·X 2010Rob Allen http://akrabat.com

The date element (1)// application/form/element/Date.phpclass Application Form Element Dateextends Zend Form Element Xhtml{public helper 'formDate';public function init (){ this- addValidator(new Zend Validate Date());}TEK·X 2010Rob Allen http://akrabat.com

The date element (2)public function isValid ( value, context null){if (is array( value)) { value value['year'] . '-' . value['month'] . '-' . value['day'];}if( value '--') { value null;}return parent::isValid( value, context);}TEK·X 2010Rob Allen http://akrabat.com

Date view helperclass Zend View Helper FormDate extends Zend View Helper FormElement{public function formDate ( name, value null, attribs null){ day value['day']; dayMultiOptions array('' '');for ( i 1; i 31; i ) { key str pad( i, 2, '0', STR PAD LEFT); dayMultiOptions[ key] str pad( i, 2, '0', STR PAD LEFT);}return this- view- formSelect( name . '[day]', day, dayAttribs, dayMultiOptions) . ' ' . this- view- formSelect( name . '[month]', month, monthAttribs, monthMultiOptions) . ' ' . this- view- formSelect( name . '[year]',TEK·X 2010Rob Allen http://akrabat.com

Caching

PrincipleTEK·X 2010Rob Allen http://akrabat.com

Bootstrap initialisationclass Bootstrap extends Zend Application Bootstrap Bootstrap{function initCache(){ frontendOptions array('lifetime' '7200','automatic serialization' true); backendOptions array('cache dir' APPLICATION PATH . '/./var/cache'); cache Zend Cache::factory('Core', 'File', frontendOptions, backendOptions);return cache;}}TEK·X 2010Rob Allen http://akrabat.com

Current code// Application Model DbTable Taskspublic function fetchOutstanding(){ select this- select(); select- where('completed 0'); select- order(array('due date ASC', 'id ASC'));return this- fetchAll( select);}TEK·X 2010Rob Allen http://akrabat.com

Zend Cache in useUnique idpublic function fetchOutstanding(){ cacheId 'outstandingTasks'; cache this- getCache();Re-use rows cache- load( cacheId);existingif ( rows false) {code select this- select(); select- where('completed 0'); select- order(array('due date ASC', 'id DESC')); rows this- fetchAll( select); cache- save( rows, cacheId, array('tasks'));}return rows;Tag}Store to cacheTEK·X 2010Rob Allen http://akrabat.com

Zend Cache in use// Application Model DbTable Taskspublic function getCache(){if (! this- cache) { fc Zend Controller Front::getInstance(); cache fc- getParam('bootstrap')- getResource('cache'); this- cache cache;}return this- cache;}TEK·X 2010Rob Allen http://akrabat.com

Emptying Zend Cache// Application Model DbTable Tasksprotected function cleanCache(){ this- getCache()- clean(Zend Cache::CLEANING MODE MATCHING TAG,array('tasks'));}TEK·X 2010Rob Allen http://akrabat.com

Authentication

Zend Auth processTEK·X 2010Rob Allen http://akrabat.com

AuthController zf create controller AuthCreating a controller at er.phpCreating an index action method in controller AuthCreating a view script for the index action method at .phtmlCreating a controller test file at ntrollerTest.phpUpdating project profile '/www/todolist/.zfproject.xml' zf create form LoginCreating a form at /www/todolist/application/forms/Login.phpUpdating project profile '/www/todolist/.zfproject.xml'TEK·X 2010Rob Allen http://akrabat.com

Users tableCREATE TABLE IF NOT EXISTS users (id int NOT NULL AUTO INCREMENT,username varchar(50) NOT NULL,password varchar(50) NOT NULL,date created datetime NOT NULL,PRIMARY KEY (id)) ENGINE InnoDB DEFAULT CHARSET utf8;-- insert first userINSERT INTO users (username, password, date created) VALUES('admin', SHA1('vF%sdf&A!agDktpassword'), NOW());TEK·X 2010Rob Allen http://akrabat.com

application.iniauth.salt "vF%sdf&A!agDkt"TEK·X 2010Rob Allen http://akrabat.com

Reverse SHA1 lookupsSHA1('password') df&A!agDktpassword') e6ff3f23138c2975220f93b3ef7ffd159fb9171bTEK·X 2010Rob Allen http://akrabat.com

Login formclass Application Form Login extends Zend Form{public function init(){ this- addElement('text', 'username', array('filters' array('StringTrim', 'StringToLower'),'required' true,'label' 'Username:',)); this- addElement('password', 'password', array('filters' array('StringTrim'),'required' true,'label' 'Password:',));// There's also a submit buttonTEK·X 2010Rob Allen http://akrabat.com

AuthControllerclass AuthController extends Zend Controller Action{public function indexAction(){ form new Application Form Login(); request this- getRequest();if ( request- isPost()) {if ( form- isValid( request- getPost())) {if ( this- process( form- getValues())) {// Success Redirect to the home page this- helper- redirector('index', 'index');}}} this- view- form form;}TEK·X 2010Rob Allen http://akrabat.com

Login formTEK·X 2010Rob Allen http://akrabat.com

AuthControllerprotected function process( values){// Get our authentication adapter and check credentials adapter this- getAuthAdapter( values); auth Zend Auth::getInstance(); result auth- authenticate( adapter);if ( result- isValid()) { data adapter- getResultRowObject(); auth- getStorage()- write( data);return true;}return false;}TEK·X 2010Rob Allen http://akrabat.com

AuthControllerprotected function getAuthAdapter( formData) { dbAdapter Zend Db Table::getDefaultAdapter(); authAdapter new Zend Auth Adapter DbTable( dbAdapter); authAdapter- setTableName('users')- setIdentityColumn('username')- setCredentialColumn('password')- setCredentialTreatment('SHA1(?)'); fc Zend Controller Front::getInstance(); options fc- getParam('bootstrap')- getOptions(); password options['auth']['salt']. formData['password']; authAdapter- setIdentity( formData['username']); authAdapter- setCredential( password);return authAdapter;}TEK·X 2010Rob Allen http://akrabat.com

LoggedInAs view helperclass Zend View Helper LoggedInAs extends Zend View Helper Abstract{public function loggedInAs (){ auth Zend Auth::getInstance();if ( auth- hasIdentity()) { username auth- getIdentity()- username; url this- url(array('controller' 'auth','action' 'logout'), null, true);return 'Welcome '. username.' a href "'. url.'" Logout /a ';} url this- url(array('controller' 'auth', 'action' 'index'));return ' a href "'. url.'" Login /a ';}}TEK·X 2010Rob Allen http://akrabat.com

Layout.phtml div id "header" div id "logged-in-as" ?php echo this- loggedInAs(); ? /div /div TEK·X 2010Rob Allen http://akrabat.com

LoggedInAs in actionTEK·X 2010Rob Allen http://akrabat.com

Access control

ACL JargonRoleTEK·X 2010PrivilegeResourceRob Allen http://akrabat.com

ACL processTEK·X 2010Rob Allen http://akrabat.com

Front Controller plugin// application/plugins/Acl.phpclass Application Plugin Acl extends Zend Controller Plugin Abstract{public function dispatchLoopStartup(Zend Controller Request Abstract request){}}// Controller.plugins.acl Application Plugin AclTEK·X 2010Rob Allen http://akrabat.com

Acl pluginpublic function dispatchLoopStartup(Zend Controller Request Abstract request){ acl this- getAcl(); role this- getRole(); resource request- getControllerName(); privilege request- getActionName(); allowed acl- isAllowed( role, resource, privilege);if (! allowed) { controller 'auth'; action 'index'; redirector new Zend Controller Action Helper Redirector(); redirector- gotoSimpleAndExit( action, controller);}}TEK·X 2010Rob Allen http://akrabat.com

Setup Zend Acl (1)protected function getAcl(){if (null this- acl) { acl new Zend Acl();// Roles acl- addRole('guest'); acl- addRole('user', 'guest'); acl- addRole('admin', 'user');// Resources acl- add(new Zend Acl Resource('index')); acl- add(new Zend Acl Resource('auth')); acl- add(new Zend Acl Resource('error'));TEK·X 2010Rob Allen http://akrabat.com

Setup Zend Acl (2)RoleResourcePrivileges// Rules acl- deny(); acl- allow('user', 'index',array('index', 'add', 'edit', 'view')); acl- allow('admin', 'index', array('delete')); acl- allow('guest', 'auth', null); acl- allow('guest', 'error', null); this- acl acl;}return this- acl;}TEK·X 2010Rob Allen http://akrabat.com

Get current roleprotected function getRole(){ auth Zend Auth::getInstance();if ( auth- hasIdentity()) { identity auth- getIdentity(); role empty( identity- role) ? 'user': identity- role;} else { role 'guest';}return role;}TEK·X 2010Rob Allen http://akrabat.com

Zend Framework simplifiesdevelopment and maintenanceDevote your time to yourdomain models as they are key.

Questions?TEK·X 2010Rob Allen http://akrabat.com

Thank youfeedback: http://joind.in/1562email: rob@akrabat.comtwitter: @akrabatQR CodeTEK·X 2010Rob Allen http://akrabat.com

Overview of Zend Framework Getting and installing it The basics of a ZF MVC application An application: todolist MVC application: DB access, layouts etc Forms, caching, authentication Please ask questions as we go!