Your SlideShare is downloading. ×
0
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Zend Framework Workshop, DPC09
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Zend Framework Workshop, DPC09

25,100

Published on

Zend Framework workshop presented at the Dutch PHP Conference, 2009. This was a six-hour long tutorial showing a number of components and one recommended approach to writing Zend Framework …

Zend Framework workshop presented at the Dutch PHP Conference, 2009. This was a six-hour long tutorial showing a number of components and one recommended approach to writing Zend Framework applications.

Published in: Technology
1 Comment
88 Likes
Statistics
Notes
  • Great Frame work 2011 waiting

    http://www.touchyard.com
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
25,100
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
1,494
Comments
1
Likes
88
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Transcript

    • 1. Zend Framework Workshop Matthew Weier O'Phinney Project Lead Zend Framework Dutch PHP Conference 11 April 2009 Amsterdam
    • 2. About me:
      • ZF Contributor since January 2006
      • 3. Assigned to the ZF team in July 2007
      • 4. Promoted to Software Architect in April 2008
      • 5. Project Lead since April 2009
      Photo © 2009, Chris Shiflett
    • 6. What is Zend Framework?
    • 7. Full Stack Framework?
    • 8. Component Library?
    • 9. Both.
    • 10.  
    • 11. Today's Roadmap
    • 12.
      • Quick Start
      • 13. Models
      • 14. Service Layers
        • Authentication and Authorization
        • 15. Zend_Form
        • 16. Plugin Loading
      • Controllers
      • 17. Views and Layouts
      • 18. Service Endpoints
    • 19. Quick Start or, “How I learned to use and love Zend_Tool”
    • 20.
      • In bin/zf.sh or bin/zf.bat of your ZF install (choose based on your OS)
      • 21. Place bin/ in your path, or create an alias on your path: alias zf=/path/to/bin/zf.sh
      • 22. Or use pear.zfcampus.org PEAR channel
      Locate the zf utility
    • 23. Create the project # Unix: % zf.sh create project quickstart # DOS/Windows: C:> zf.bat create project quickstart
    • 24. Add ZF to the project # Symlink: % cd library; ln -s path/to/ZendFramework/library/Zend . # Copy: % cd library; cp -r path/to/ZendFramework/library/Zend .
    • 25. Create a vhost <VirtualHost *: 80 > ServerAdmin you@atyour.tld DocumentRoot /abs/path/to/quickstart/public ServerName quickstart <Directory /abs/path/to/quickstart/public > DirectoryIndex index.php AllowOverride All Order allow,deny Allow from all </Directory> </VirtualHost>
    • 26. Add a hosts entry 127.0.0.1 quickstart
    • 27. Fire up your browser!
    • 28. Looking under the hood
    • 29. The directory tree quickstart |-- application | |-- Bootstrap.php | |-- configs | | `-- application.ini | |-- controllers | | |-- ErrorController.php | | ` -- IndexController.php | |-- models | `-- views | |-- helpers | ` -- scripts | |-- error | | `-- error.phtml | ` -- index | `-- index.phtml |-- library |-- public | ` -- index.php `-- tests |-- application | ` -- bootstrap.php |-- library | `-- bootstrap.php ` -- phpunit.xml 14 directories, 10 files
    • 30. The bootstrap <?php class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { }
    • 31. Configuration [production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 includePaths.library = APPLICATION_PATH &quot;/../library&quot; bootstrap.path = APPLICATION_PATH &quot;/Bootstrap.php&quot; bootstrap.class = &quot;Bootstrap&quot; resources.frontController.controllerDirectory = APPLICATION_PATH &quot;/controllers&quot; [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1
    • 32. Index (default) controller <?php class IndexController extends Zend_Controller_Action { public function init() { /* Initialize action controller here */ } public function indexAction() { // action body } }
    • 33. Error controller class ErrorController extends Zend_Controller_Action { public function errorAction() { $errors = $this ->_getParam( 'error_handler' ); switch ( $errors ->type) { case 'EXCEPTION_NO_CONTROLLER': case 'EXCEPTION_NO_ACTION': // 404 error -- controller or action not found $this ->getResponse()->setHttpResponseCode( 404 ); $this ->view->message = 'Page not found' ; break ; default: // application error $this ->getResponse()->setHttpResponseCode( 500 ); $this ->view->message = 'Application error' ; break ; } $this ->view->exception = $errors ->exception; $this ->view->request = $errors ->request; } }
    • 34. Index view (home page) <center> <div id = &quot;welcome&quot; > <h1> Welcome to the Zend Framework! </h1> <h3> This is your project's main page </h3> <!-- and a little bit more markup --> </div> </center>
    • 35. Error view <h1>An error occurred</h1> <h2><?php echo $this ->message ?></h2> <?php if ( 'development' == APPLICATION_ENV): ?> <h3>Exception information:</h3> <p> <b>Message:</b> <?php echo $this ->exception->getMessage() ?> </p> <h3>Stack trace:</h3> <pre> <?php echo $this ->exception->getTraceAsString() ?> </pre> <h3>Request Parameters:</h3> <pre> <?php var_dump ( $this ->request->getParams()) ?> </pre> <?php endif ?>
    • 36. .htaccess file SetEnv APPLICATION_ENV development RewriteEngine On RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ index.php [NC,L]
    • 37. index.php (environment) <?php // Define path to application directory defined ( 'APPLICATION_PATH' ) || define ( 'APPLICATION_PATH' , realpath ( dirname (__FILE__) . '/../application' )); // Define application environment defined ( 'APPLICATION_ENV' ) || define ( 'APPLICATION_ENV' , ( getenv ( 'APPLICATION_ENV' ) ? getenv ( 'APPLICATION_ENV' ) : 'production' )); // Ensure library/ is on include_path set_include_path( implode (PATH_SEPARATOR, array ( realpath (APPLICATION_PATH . '/../library' ), get_include_path(), )));
    • 38. 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();
    • 39. Models or, “Classes are an OOP developer's play-dough”
    • 40. First, there is no Zend_Model. Stop asking.
    • 41. What you shouldn't do
    • 42.
      • Never tie your models directly to data access
        • Makes testing hard
        • 43. Makes refactoring later to use caching or an SOA hard
        • 44. Makes restructuring your database problematic (your code could break)
    • 45. Models are just classes. Create classes.
    • 46. Where? quickstart |-- application | |-- Bootstrap.php | |-- configs | | `-- application.ini | |-- controllers | |-- models | | |-- Team.php | | ` -- User.php | `-- views |-- library |-- public ` -- tests
    • 47. Models usually have metadata or attributes; define them
    • 48. Class properties <?php class App_Model_User { protected $_email ; protected $_firstname ; protected $_id ; protected $_lastname ; protected $_password ; protected $_role = 'pig' ; protected $_username ; }
    • 49. Models usually have behavior surrounding the metadata; define accessors and mutators
    • 50. Accessors and mutators <?php class App_Model_User { /* ... properties ... */ public function setEmail( $email ) { } public function getEmail() { } public function setFirstname( $name ) { } public function getFirstname() { } public function setLastname( $name ) { } public function getLastname() { } /* ... and so on ... */ }
    • 51. Models usually have behaviors ; define some methods
    • 52. Methods <?php class App_Model_User { /* ... */ public function walk() { } public function sleep () { } }
    • 53. Now, persist your models
    • 54. Define a schema CREATE TABLE &quot;user&quot; ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, username VARCHAR ( 64 ) NOT NULL UNIQUE , email VARCHAR ( 64 ) NOT NULL , firstname VARCHAR ( 64 ), lastname VARCHAR ( 64 ), role VARCHAR ( 16 ) NOT NULL DEFAULT 'pig' );
    • 55. Tell your application about your database [production] ; ... resources.db.adapter = &quot;pdo_sqlite&quot; resources.db.params.dbname = APPLICATION_PATH &quot;/../data/db/users.db&quot; [staging : production] [testing : production] ; ... resources.db.params.dbname = APPLICATION_PATH &quot;/../data/db/users-test.db&quot; [development : production] ; ... resources.db.params.dbname = APPLICATION_PATH &quot;/../data/db/users-dev.db&quot;
    • 56. Use a Table Data Gateway – Zend_Db_Table <?php class App_Model_DbTable_User extends Zend_Db_Table_Abstract { protected $_name = 'user' ; } quickstart |-- application | |-- models | | |-- DbTable | | | `-- User.php | | |-- Team.php | | ` -- User.php | `-- views |-- library |-- public |-- tests
    • 57. Tangent: a bit about Zend_Db_Table and relational datasets
    • 58. Zend_Db_Table Relations (parent table) <?php class App_Model_DbTable_Team extends Zend_Db_Table_Abstract { protected $_name = 'team' ; protected $_dependentTables = array ( 'App_Model_DbTable_TeamUser ' ); }
    • 59. Zend_Db_Table Relations (child table) <?php class App_Model_DbTable_TeamUser extends Zend_Db_Table_Abstract { protected $_name = 'team_user' ; protected $_referenceMap = array ( 'Team' => array ( 'columns' => 'team_id' , 'refTableClass' => 'App_Model_DbTable_Team' , 'refColumns' => 'id' ), ); }
    • 60. Zend_Db_Table Using Relations <?php $users = $team ->findDependentRowset( 'App_Model_DbTable_TeamUser' ); $team = $teamUser ->findParentRow();
    • 61. Zend_Db_Table Using many-to-many relations <?php $users = $team ->findManyToManyRowset( 'App_Model_DbTable_User' , 'App_Model_DbTable_TeamUser' , );
    • 62. … and now back to our story
    • 63. Create a Data Mapper: map your Model to the DAO <?php class App_Model_UserDataMapper { public function save(App_Model_User $user ) { $dao = $this ->getDao(); $id = $user ->getId(); if (! $id ) { $id = $dao ->insert( $user ->toArray()); $record = $dao ->find( $id )-> current (); } else { $dao ->update( $user ->toArray(), array ( 'id = ?' , $id )); $record = $dao ->find( $id )-> current (); } $user ->setOptions( $record ->toArray()); return $user ; } }
    • 64. Data Mappers: Great for caching! <?php class App_Model_UserDataMapper { public function fetchAll() { $cache = $this ->getCache(); if (! $users = $cache ->load( 'users' )) { $records = $this ->getDao()->fetchAll( '1' ); $users = array (); foreach ( $records as $record ) { $users [] = new App_Model_User( $record ->toArray()); } $cache ->save( $users , 'users' ); } return $users ; } }
    • 65.
      • Data !== Database
      • 66. Your Data Access Object could access a service...
      Note on Data Access Objects
    • 67. Data Access to a service: <?php class App_Model_Dao_User { public function fetchAll( $criteria ) { return $this ->getXmlRpcClient() ->fetch( $criteria ); } }
    • 68. Of names and autoloading
    • 69. Always use a vendor or project prefix
    • 70. Inform the autoloader of library prefixes
    • 71. Registering namespaces with the autoloader <?php require_once 'Zend/Loader/Autoloader.php' ; $autoloader = Zend_Loader_Autoloader::getInstance(); $autoloader ->registerNamespace( 'Scrum_' ); [production] autoloaderNamespaces[] = &quot;Scrum_&quot; ; ...
    • 72. Resources can be autoloaded, too
    • 73. Autoloading standard application resources <?php class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initResourceLoader() { $loader = new Zend_Application_Module_Autoloader( array ( 'namespace' => 'App' , 'basePath' => dirname (__FILE__), ) ); return $loader ; } }
    • 74. Conventional directory structure quickstart |-- application | |-- forms => App_Form_ | |-- models => App_Model_ | | |-- DbTable => App_Model_DbTable | | | `-- User.php => App_Model_DbTable_User | | |-- Team.php => App_Model_User | |-- plugins => App_Plugin_ | |-- services => App_Service_ | |-- views | | |-- filters => App_View_Filter | | |-- helpers => App_View_Helper
    • 75. Service Layers or, “Re-use this!”
    • 76. Applications are like onions; they have layers. Photo © 2008, Mike Chaput-Branson
    • 77. The Service Layer provides application logic on top of your models
    • 78. Service layer in perspective Data Access Objects and Data store(s) Data Mappers Domain Models Service Layer
    • 79.
      • Resource marshalling and dependency injection
      • 80. Application specific logic:
        • Authentication and Authorization
        • 81. Input filtering/data validation
        • 82. Search indexing
        • 83. etc.
      What's found in Service Layers?
    • 84. Authentication: Zend_Auth
    • 85. Authentication is the act of verifying somebody is who they say they are
    • 86.
      • Authentication adapters perform the work of authentication
      • 87. Zend_Auth handles authentication persistence
    • 88. Authentication adapter <?php class App_Model_AuthAdapter implements Zend_Auth_Adapter_Interface { protected $_user ; public function __construct(App_Model_User $user ) { $this ->_user = $user ; } // ... }
    • 89. Authentication adapter (cont.) public function authenticate() { $user = $this ->_user; $mapper = $user ->getDataMapper(); $matches = $mapper ->fetchAll( array ( 'username = ?' => $user ->username, 'password = ?' => md5 ( $user ->password), )); if (empty( $matches )) { $result = new Zend_Auth_Result(- 3 , null); } else { $user = current ( $matches ); $result = new Zend_Auth_Result( 1 , $user ->toArray()); } return $result ; }
    • 90. Initial “user” service class App_Service_User { protected $_userModel ; protected $_userModelOptions ; public function __construct( $options = array ()) { } public function getUserModelOptions() { } public function setUserModelOptions( array $options ) { } public function getUserModel( $newInstance = true) { if ( $newInstance ) { return new App_Model_User( $this ->getUserModelOptions()); } if (null === $this ->_userModel) { $this ->setUserModel(new App_Model_User( $this ->getUserModelOptions())) ; } return $this ->_userModel; } public function setUserModel( $model ) { } }
    • 91. “ Login” method class App_Service_User { // ... public function login( array $data ) { $user = $this ->getUserModel(); $user ->setOptions( $data ); $authAdapter = new App_Model_AuthAdapter( $user ); $auth = Zend_Auth::getInstance(); $result = $auth ->authenticate( $authAdapter ); if (! $result ->isValid()) { return $result ; } return true; } }
    • 92. Retrieving an authenticated user $auth = Zend_Auth::getInstance(); if ( $auth ->hasIdentity()) { $user = new App_Model_User( $auth ->getIdentity() ); }
    • 93. Authorization: Zend_Acl
    • 94. Authorization is the act of determining if somebody has permissions to perform an action on a given resource
    • 95.
      • Roles – what requests the action
      • 96. Resources – what is being acted upon
      • 97. Rights – the privileges a role has for a given resource
      The three “R”s:
    • 98.
      • Implement Zend_Acl_Role_Interface
        • One method: getRoleId()
      • Can simply use Zend_Acl_Role, but this doesn't tie directly to your models
      Roles
    • 99. Revisiting the User model Making it an ACL role <?php class App_Model_User implements Zend_Acl_Role_Interface { // ... protected $_role = 'pig' ; public function getRoleId() { return $this ->_role; } }
    • 100.
      • Implement Zend_Acl_Resource_Interface
        • One method: getResourceId()
      • Can simply use Zend_Acl_Resource, but this doesn't tie directly to your models
      Resources
    • 101. The “sprint” model Making it an ACL resource <?php class Scrum_Model_Sprint implements Zend_Acl_Resource_Interface { // ... public function getResourceId() { return 'sprint' ; } }
    • 102.
      • Zend_Acl denies all access by default
      • 103. You must whitelist role access to resources
      • 104. You can also blacklist , though this is less common or necessary
      Rights
    • 105. Defining ACLs <?php class Scrum_Model_Acl extends Zend_Acl { public function __construct() { $this ->addRole( 'pig' ) ->addRole( 'chicken' ) ->addRole( 'scrummaster' , array ( 'pig' )); $this ->add( 'sprint' ) ->add( 'backlog' ); $this ->allow( 'pig' , 'sprint' , array ( 'read' , 'write' )) ->allow( 'pig' , 'backlog' , array ( 'read' )) ->allow( 'scrummaster' , 'backlog' , array ( 'write' )) ->allow( 'chicken' , 'backlog' , array ( 'read' )) ->allow( 'chicken' , 'sprint' , array ( 'read' )); } }
    • 106.
      • Remember the three “R”s; check that:
        • The Role
        • 107. acting on the resource
        • 108. has rights to perform the action
      • Use the isAllowed() method
      Checking ACLs
    • 109. Authorization <?php class Scrum_Service_Sprint { public function create( array $data ) { $acl = $this ->getAcl(); $sprint = $this ->getSprintModel(); $user = $this ->getCurrentUser(); if (! $acl ->isAllowed( $user , $sprint , 'write' )) { throw new Scrum_Service_InvalidUserException(); } // ... } }
    • 110. Data filtering and Validation: Zend_Form, Zend_Filter, and Zend_Validate
    • 111.
      • Acts as a general purpose normalization and validation filter
      • 112. Form decorators make it trivial to create the markup needed to capture data
      • 113. Encapsulates i18n/l10n concerns for validation error reporting
      Why Zend_Form?
    • 114.
      • Within Zend_Form, provides validation chains
      • 115. Provides validation error reporting
      • 116. Marking an element as “required” prepends a “NotEmpty” validator to the validation chain
      • 117. Can be used standalone
      Zend_Validate
    • 118. Zend_Validate Adding validators to an element <?php // Args: // - validator &quot;short&quot; name // - break on failure flag // - Options to pass to validator constructor $element ->addValidator( 'Regex' , true, array ( '/^[a-z][a-z0-9_.-]{2,}$/' ) );
    • 119. Zend_Validate Adding validators at element creation <?php $form ->addElement( 'text' , 'username' , array ( 'required' => true, 'validators' => array ( array ( 'Regex' , true, array ( '/^[a-z][a-z0-9_.-]{2,}$/' ) ), ), ));
    • 120.
      • Within Zend_Form, provides normalization chains
      • 121. Normalizes input prior to validation, or on requesting the element value
      • 122. Can be used standalone
      Zend_Filter
    • 123. Zend_Filter Adding filters to an element <?php // Arguments: // - String: filter &quot;short&quot; name // - OR Array: // - Filter &quot;short&quot; name // - array of constructor options $element ->addFilter( 'StringToLower' , );
    • 124. Zend_Filter Adding filters at element creation <?php $form ->addElement( 'text' , 'username' , array ( 'filters' => array ( 'StringToLower' , ) ));
    • 125.
      • Zend_Form:
        • Aggregates elements and groups (display groups and sub forms)
        • 126. Provides full and partial validation of the elements
      • Elements:
        • Aggregate metadata
        • 127. Contain filter and validation chains
      Zend_Form
    • 128.
      • Display Groups:
        • Aggregate elements purely for display purposes
      • Sub forms:
        • Aggregate elements related semantically
        • 129. Provides namespacing of elements via array notation
      Zend_Form
    • 130. Zend_Form Defining forms class App_Form_User extends Zend_Form { public function init() { $this ->addElement( 'text' , 'username' , array ( 'label' => 'Username:' , 'required' => true, 'filters' => array ( 'StringToLower' , ), 'validators' => array ( array ( 'Regex' , true, array ( '/^[a-z][a-z0-9_.-]{2,}$/' )), ), )); // ... } }
    • 131. Zend_Form A note on buttons... <?php class App_Form_User extends Zend_Form { public function init() { // ... $this ->addElement( 'submit' , 'submit' , array ( 'label' => 'Done' , 'required' => false, 'ignore' => true, )); } }
    • 132. Zend_Form Variant: Dojo-aware form <?php class App_Form_User extends Zend_Dojo_Form { public function init() { $this ->addElement( 'TextBox' , 'username' , array ( // ...
    • 133. Using forms as validators in your Service Layer
    • 134. Form accessors <?php class App_Service_User { protected $_form = array (); public function setUserForm(Zend_Form $form ) { $this ->_form[ 'user' ] = $form ; } public function getUserForm() { if (empty( $this ->_form[ 'user' ])) { $this ->setUserForm(new App_Form_User()); } return $this ->_form[ 'user' ]; } }
    • 135. Form as validator <?php class App_Service_User { public function add( array $data ) { $form = $this ->getUserForm(); if (! $form ->isValid( $data )) { return false; } $model = $this ->getUserModel(); $model ->setOptions( $form ->getValues()); return $model ->save(); } }
    • 136. Interlude: Plugin architectures or, “Override anything!”
    • 137.
      • Aggregates prefix => path pairs: Zend_Validate_ => Zend/Validate/
      • 138. Acts as a LIFO stack
      • 139. Specify class name minus prefix to load: $class = $loader->load('StringTrim'); // Zend_Filter_StringTrim
      Zend_Loader_PluginLoader
    • 140. Plugin-aware components
    • 147.
      • Use short names instead of Really_Long_Underscored_Names
      • 148. Define plugins via configuration options instead of in your code
      • 149. Drop overrides into your filesystem, and get behavior changes
      Benefits of plugins
    • 150. Example validate plugin <?php // in library/My/Validate/IsFoo.php class My_Validate_IsFoo extends Zend_Validate_Abstract { const NOT_FOO = 'notFoo' ; protected $_messageTemplates = array ( self::NOT_FOO => 'Value %value% is not foo' , ); public function isValid( $value ) { if (! $value == 'foo' ) { $this ->_error(self::NOT_FOO); return false; } return true; } }
    • 151. Registering the prefix-path <?php // General: $loader ->addPrefixPath( 'My_Validate' , 'My/Validate' ); // Specific: Zend_Form_Element: $element ->addPrefixPath( 'My_Validate' , 'My/Validate' , 'validate' );
    • 152. Retrieving the class <?php // returns 'My_Validate_IsFoo' $class = $loader ->load( 'IsFoo' );
    • 153.
      • Create a plugin with the same “short” name as an existing plugin. E.g., to override Zend_Validate_IsInt, create a class My_Validate_IsInt.
      • 154. Register the new prefix-path with the loader. E.g., $loader->addPrefixPath('My_Validate', 'My/Validate');
      • 155. The new class will now be used.
      Override existing plugins
    • 156. Controllers or, “Route this!”
    • 157. How it all works
    • 158.  
    • 159.
      • Receive request
      • 160. Route request
      • 161. Dispatch loop
        • Pre-dispatch
        • 162. Dispatch controller action
        • 163. Post-dispatch
      • Send response
      Or, more simply:
    • 164.
      • Zend_Controller_Front
      • 165. Zend_Controller_Plugin
      • 166. Zend_Controller_Router
      • 167. Zend_Controller_Dispatcher
      • 168. Zend_Controller_Action_Helper
      • 169. Zend_Controller_Action
      Components
    • 170.
      • Handles entire request life-cycle
      • 171. Executes all other components
      • 172. Singleton: Zend_Controller_Front::getInstance()
      Front Controller
    • 173.
      • Bookend each major responsibility:
      • Used for site-wide actions
      • Not handled via PluginLoader (yet!)
      Plugins
    • 177.
      • Default routing: /controller/action[/key/value/k/v]
      • 178. Can register alternate routes:
        • Static routes
        • 179. “ Normal” routes /with/:placeholder/:segments
        • 180. “ Regex” routes for fine-grained control
      • First matched route wins
      • 181. LIFO stack
      Routing
    • 182.
      • Resolves controller to a class
      • 183. Instantiates controller
      • 184. Executes requested action
      Dispatching
    • 185.
      • Obviate the need to create custom base controller classes
      • 186. Re-usable functionality that requires integration with or access from action controllers
      • 187. Have pre-/postDispatch hooks, allowing for task automation
      • 188. Zend_Controller_Action_HelperBroker: Combination static registry and service finder (uses PluginLoader internally)
      Action Helpers
    • 189. Action Helpers Registering prefix paths <?php // Register prefix path My_Foo => My/Foo/ Zend_Controller_Action_HelperBroker::addPrefix( 'My_Foo' ); // Register prefix path My_Foo => some/foo/ Zend_Controller_Action_HelperBroker::addPath( 'some/foo/' , 'My_Foo' );
    • 190. Action Helpers Registering helpers <?php // Register concrete instance Zend_Controller_Action_HelperBroker::addHelper( $helperInstance ); // Implicitly register, by using plugin loader $helper = Zend_Controller_Action_HelperBroker::getStaticHelper( 'ShortName' );
    • 191. Action Helpers Creating helpers <?php class My_Helper_InjectUser extends Zend_Controller_Action_Helper_Abstract { public function preDispatch() { $controller = $this ->getActionController(); if (!isset( $controller ->user)) { $controller ->user = $this ->getUser(); } } }
    • 192.
      • Named “ <name>Controller ”
      • 193. In modules, module name is used as prefix: “ Foo_BarController ”
      • 194. Can use MixedCase; in URL, words are dash-separated: “ FooBarController ” is referred to as “foo-bar”
      Action controllers
    • 195.
      • Named “ <name>Action() ”
      • 196. Can use MixedCase; in URL, words are dash- or dot-separated: “ fooBarAction ” is referred to as “foo-bar” or “foo.bar”
      Action methods
    • 197.
      • Public $view property is the view object
      • 198. Protected $_helper property refers to the helper broker: $this->_helper->foo retrieves “foo” action helper
      • 199. getRequest() and getResponse() provide access to request environment and response payload, respectively
      Features of controllers
    • 200.
      • Injects view object into controllers
      • 201. Renders views during p ostDispatch()
        • Standardizes view script resolution to <controller>/<action>.phtml
      • Simply an action helper; retrieve it using $this->_helper->viewRenderer
      ViewRenderer
    • 202. Using Zend_Tool to create controllers and actions # Create a &quot;foo&quot; controller: zf create controller foo # Create it in the &quot;bar&quot; module: zf create controller foo -m bar # Create a &quot;baz&quot; action method # (and view script) # in the foo controller: zf create action baz foo
    • 203. Tree after using tool quickstart |-- application | |-- controllers | | |-- ErrorController.php | | |-- IndexController.php | | `-- FooController.php | |-- modules | | |-- bar | | | |-- controllers | | | | ` -- FooController.php | `-- views | | |-- scripts | | | |-- error | | | |-- index | | | |-- foo | | | | ` -- bar.phtml
    • 204. FooController <?php class FooController extends Zend_Controller_Action { public function indexAction() { } public function bazAction() { } }
    • 205. Doing some work <?php class UserController extends Zend_Controller_Action { public function init() { $this ->service = new App_Service_User(); } public function listAction() { $this ->view->users = $this ->service->fetchAll(); } }
    • 206. Utilizing the request object <?php class UserController extends Zend_Controller_Action { // ... public function loginAction() { $result = $this ->service->login( $this ->getRequest()->getPost()); if ( $result instanceof App_Model_User) { $this ->redirect( '/' ); } $this ->view->loginForm = $this ->service->getLoginForm(); } }
    • 207. Views or, “Pics, or it didn't happen!”
    • 208.
      • PHP as a template language
      • 209. LIFO stack of view script paths used to resolve script path to render
      • 210. Helper plugins for extending view functionality
        • Helpers called as if they were view object methods
        • 211. Resolve to a class and method
        • 212. Override helpers locally if desired
      Zend_View
    • 213.
      • View variables are registered as object properties
      • 214. View scripts operate in the view object's variable scope; “$this” in a view script is the view object
      • 215. Use PHP shorthand/alternate notations for readability
      Zend_View
    • 216. Example view script <h2>Registered users</h2> <ul> <?php foreach ( $this ->users as $user ): ?> <li><?php echo $this ->escape( $user ->username) ?></li> <?php endforeach ?> </ul>
    • 217. Common helpers
    • 228. Using helpers <?php $this ->doctype( 'XHTML1_STRICT' ); $this ->headTitle( 'Example Helpers' ); ?> <h2><?php echo $this ->translate( 'headers' ) ?></h2> <?php echo $this ->partial( 'content.phtml' ) ?>
    • 229.
      • Aggregate content
      • 230. Rendering the helper concatenates aggregated content
      • 231. Typically used to aggregate information for the layout
      “ Placeholder” helpers
    • 232. Placeholder example <?php $this ->headTitle( 'Foo' ); $this ->headTitle( 'Bar' ); $this ->headTitle()->setSeparator( ' - ' ); echo $this ->headTitle(); // &quot;Foo - Bar&quot;
    • 233. Placeholder helpers
    • 243. Rendering Forms
    • 244. First, a word on Decorators
    • 245.
      • A Decorator typically wraps the functionality of an existing object, and selectively modifies its behavior
      • 246. Alternately, a decorator may be used to create a representation of an object
      • 247. In Zend_Form, decorators pull metadata from forms and elements to create representations. Many decorators proxy to view helpers !
    • 248. The simplest decorator <?php class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract { protected $_format = '<label for=&quot;%s&quot;>%s</label> <input id=&quot;%s&quot; name=&quot;%s&quot; type=&quot;text&quot; value=&quot;%s&quot;/>' ; public function render( $content ) { $element = $this ->getElement(); $name = htmlentities ( $element ->getFullyQualifiedName()); $label = htmlentities ( $element ->getLabel()); $id = htmlentities ( $element ->getId()); $value = htmlentities ( $element ->getValue()); $markup = sprintf ( $this ->_format, $name , $label , $id , $name , $value ); return $markup ; } }
    • 249. … and the output <label for = &quot;bar[foo]&quot; > Foo </label> <input id = &quot;bar-foo&quot; name = &quot;bar[foo]&quot; type = &quot;text&quot; value = &quot;test&quot; />
    • 250.
      • You can layer decorators to aggregate output from multiple decorators
      • 251. Decorators are processed in FIFO order
      • 252. Generated content is passed to the next decorator as input
      • 253. Typically, append, prepend, or replace content
    • 254. Consider two decorators … <?php class My_Decorator_Input extends Zend_Form_Decorator_Abstract { } <?php class My_Decorator_Label extends Zend_Form_Decorator_Abstract { } Layer them: <?php $element ->addPrefixPath( 'My_Decorator' , 'My/Decorator' , 'decorator' ); $element ->setDecorators( array ( 'Input' , 'Label' , ));
    • 255. Typically, then, render the form: <?php echo $this ->form ?>
    • 256.
      • Decorators are plugins
      • 257. Can be rendered individually
        • Retrieve decorator and render
        • 258. Use overloading to render individual decorators
    • 259. Rendering individual decorators <?php $element = $this ->form->foo; echo $element ->getDecorator( 'label' ) ->render( '' ); // or: echo $element ->renderLabel();
    • 260.
      • Either pass the form to the view, or pull it from the model within the view
      • 261. Configure decorators in the view, if customizations are needed (view logic)
      • 262. For truly complex markup, render individual decorators within markup
      Recommendations
    • 263. Form-related view helpers
    • 280. Layouts
    • 281.
      • Zend_Layout implements the Composite View and Two Step View design patterns
      • 282. The internal implementation utilizes front controller plugins, action helpers , and view helpers
      • 283. Layout scripts are simply view scripts
    • 284. Sample layout script <?php echo $this ->doctype() ?> <html xmlns= &quot;http://www.w3.org/1999/xhtml&quot; > <head> <?php echo $this ->headMeta() ?> <?php echo $this ->headTitle() ?> <?php echo $this ->headLink() ?> <?php echo $this ->headScript() ?> </head> <body> <?php echo $this ->layout()->content ?> </body> </html>
    • 285.
      • $this->_helper->viewRenderer->setNoRender(true);
      • 286. $this->_helper->layout->disableLayout();
      Disabling views and layouts
    • 287.
      • View scripts should be concise
      • 288. Hint to the layout script from your view scripts (not your controllers!)
      • 289. Layouts should use placeholders as much as possible
      • 290. Setup common layout elements in a bootstrap resource
      Recommendations
    • 291. Bootstrapping placeholders <?php class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initLayoutPlaceholders() { $this ->bootstrap( 'view' ); $view = $this ->getResource( 'view' ); $view ->doctype( 'XHTML1_STRICT' ); $view ->headTitle() ->setSeparator( ' - ' ) ->append( 'My site' ); } }
    • 292. Service Endpoints or, “Got API?”
    • 293.
      • All server components implement PHP's SoapServer API
      • 294. All public methods of attached classes are exposed
      • 295. Reflection on docblock annotations provides parameter and return value types to the service. You must provide @param for each parameter, and @return always!
    • 296. Example server <?php define ( 'APPLICATION_PATH' , dirname ( dirname (__FILE__)) . '/application' ) require_once 'Zend/Application.php' ; $app = new Zend_Application( getenv ( 'APPLICATION_ENV' ), APPLICATION_PATH . '/configs/xmlrpc.ini' ); $app ->bootstrap(); $server = new Zend_XmlRpc_Server(); $server ->setClass( 'App_Service_User' ); $response = $server ->handle(); echo $response ;
    • 297.
      • Create bootstrap classes specific to your servers
      • 298. Re-use application configuration, when possible
      • 299. Use namespaces when the service protocol allows (XML-RPC, JSON-RPC)
      • 300. Write decorators for your service layer so as not to expose methods related to implementation
      Recommendations
    • 301. Conclusions or, “The fat guy sings”
    • 302.
      • Spend your time on your domain models and service layers
        • Use Zend Framework components judiciously and to aid development
        • 303. Don't confine yourself to ZF
      • Expose your service layer via the MVC and server classes so as to allow applications to be built on top of your work
      Recommendations
    • 304. Questions? or, “Your turn!”
    • 305. Thank you. http://framework.zend.com/ http://twitter.com/weierophinney http://slideshare.net/weierophinney Feedback? http://joind.in/talk/view/603

    ×