Zend Framework Workshop, DPC09

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    39 Favorites & 1 Event

    Zend Framework Workshop, DPC09 - Presentation 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
      • Assigned to the ZF team in July 2007
      • Promoted to Software Architect in April 2008
      • Project Lead since April 2009
      Photo © 2009, Chris Shiflett
    3. What is Zend Framework?
    4. Full Stack Framework?
    5. Component Library?
    6. Both.
    7.  
    8. Today's Roadmap
      • Quick Start
      • Models
      • Service Layers
        • Authentication and Authorization
        • Zend_Form
        • Plugin Loading
      • Controllers
      • Views and Layouts
      • Service Endpoints
    9. Quick Start or, “How I learned to use and love Zend_Tool”
      • In bin/zf.sh or bin/zf.bat of your ZF install (choose based on your OS)
      • Place bin/ in your path, or create an alias on your path: alias zf=/path/to/bin/zf.sh
      • Or use pear.zfcampus.org PEAR channel
      Locate the zf utility
    10. Create the project # Unix: % zf.sh create project quickstart # DOS/Windows: C:> zf.bat create project quickstart
    11. 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 .
    12. 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>
    13. Add a hosts entry 127.0.0.1 quickstart
    14. Fire up your browser!
    15. Looking under the hood
    16. 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
    17. The bootstrap <?php class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { }
    18. 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
    19. Index (default) controller <?php class IndexController extends Zend_Controller_Action { public function init() { /* Initialize action controller here */ } public function indexAction() { // action body } }
    20. 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; } }
    21. 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>
    22. 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 ?>
    23. .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]
    24. 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(), )));
    25. 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();
    26. Models or, “Classes are an OOP developer's play-dough”
    27. First, there is no Zend_Model. Stop asking.
    28. What you shouldn't do
      • Never tie your models directly to data access
        • Makes testing hard
        • Makes refactoring later to use caching or an SOA hard
        • Makes restructuring your database problematic (your code could break)
    29. Models are just classes. Create classes.
    30. Where? quickstart |-- application | |-- Bootstrap.php | |-- configs | | `-- application.ini | |-- controllers | |-- models | | |-- Team.php | | ` -- User.php | `-- views |-- library |-- public ` -- tests
    31. Models usually have metadata or attributes; define them
    32. Class properties <?php class App_Model_User { protected $_email ; protected $_firstname ; protected $_id ; protected $_lastname ; protected $_password ; protected $_role = 'pig' ; protected $_username ; }
    33. Models usually have behavior surrounding the metadata; define accessors and mutators
    34. 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 ... */ }
    35. Models usually have behaviors ; define some methods
    36. Methods <?php class App_Model_User { /* ... */ public function walk() { } public function sleep () { } }
    37. Now, persist your models
    38. 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' );
    39. 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;
    40. 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
    41. Tangent: a bit about Zend_Db_Table and relational datasets
    42. 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 ' ); }
    43. 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' ), ); }
    44. Zend_Db_Table Using Relations <?php $users = $team ->findDependentRowset( 'App_Model_DbTable_TeamUser' ); $team = $teamUser ->findParentRow();
    45. Zend_Db_Table Using many-to-many relations <?php $users = $team ->findManyToManyRowset( 'App_Model_DbTable_User' , 'App_Model_DbTable_TeamUser' , );
    46. … and now back to our story
    47. 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 ; } }
    48. 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 ; } }
      • Data !== Database
      • Your Data Access Object could access a service...
      Note on Data Access Objects
    49. Data Access to a service: <?php class App_Model_Dao_User { public function fetchAll( $criteria ) { return $this ->getXmlRpcClient() ->fetch( $criteria ); } }
    50. Of names and autoloading
    51. Always use a vendor or project prefix
    52. Inform the autoloader of library prefixes
    53. 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; ; ...
    54. Resources can be autoloaded, too
    55. 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 ; } }
    56. 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
    57. Service Layers or, “Re-use this!”
    58. Applications are like onions; they have layers. Photo © 2008, Mike Chaput-Branson
    59. The Service Layer provides application logic on top of your models
    60. Service layer in perspective Data Access Objects and Data store(s) Data Mappers Domain Models Service Layer
      • Resource marshalling and dependency injection
      • Application specific logic:
        • Authentication and Authorization
        • Input filtering/data validation
        • Search indexing
        • etc.
      What's found in Service Layers?
    61. Authentication: Zend_Auth
    62. Authentication is the act of verifying somebody is who they say they are
      • Authentication adapters perform the work of authentication
      • Zend_Auth handles authentication persistence
    63. Authentication adapter <?php class App_Model_AuthAdapter implements Zend_Auth_Adapter_Interface { protected $_user ; public function __construct(App_Model_User $user ) { $this ->_user = $user ; } // ... }
    64. 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 ; }
    65. 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 ) { } }
    66. “ 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; } }
    67. Retrieving an authenticated user $auth = Zend_Auth::getInstance(); if ( $auth ->hasIdentity()) { $user = new App_Model_User( $auth ->getIdentity() ); }
    68. Authorization: Zend_Acl
    69. Authorization is the act of determining if somebody has permissions to perform an action on a given resource
      • Roles – what requests the action
      • Resources – what is being acted upon
      • Rights – the privileges a role has for a given resource
      The three “R”s:
      • Implement Zend_Acl_Role_Interface
        • One method: getRoleId()
      • Can simply use Zend_Acl_Role, but this doesn't tie directly to your models
      Roles
    70. 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; } }
      • Implement Zend_Acl_Resource_Interface
        • One method: getResourceId()
      • Can simply use Zend_Acl_Resource, but this doesn't tie directly to your models
      Resources
    71. The “sprint” model Making it an ACL resource <?php class Scrum_Model_Sprint implements Zend_Acl_Resource_Interface { // ... public function getResourceId() { return 'sprint' ; } }
      • Zend_Acl denies all access by default
      • You must whitelist role access to resources
      • You can also blacklist , though this is less common or necessary
      Rights
    72. 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' )); } }
      • Remember the three “R”s; check that:
        • The Role
        • acting on the resource
        • has rights to perform the action
      • Use the isAllowed() method
      Checking ACLs
    73. 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(); } // ... } }
    74. Data filtering and Validation: Zend_Form, Zend_Filter, and Zend_Validate
      • Acts as a general purpose normalization and validation filter
      • Form decorators make it trivial to create the markup needed to capture data
      • Encapsulates i18n/l10n concerns for validation error reporting
      Why Zend_Form?
      • Within Zend_Form, provides validation chains
      • Provides validation error reporting
      • Marking an element as “required” prepends a “NotEmpty” validator to the validation chain
      • Can be used standalone
      Zend_Validate
    75. 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,}$/' ) );
    76. 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,}$/' ) ), ), ));
      • Within Zend_Form, provides normalization chains
      • Normalizes input prior to validation, or on requesting the element value
      • Can be used standalone
      Zend_Filter
    77. 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' , );
    78. Zend_Filter Adding filters at element creation <?php $form ->addElement( 'text' , 'username' , array ( 'filters' => array ( 'StringToLower' , ) ));
      • Zend_Form:
        • Aggregates elements and groups (display groups and sub forms)
        • Provides full and partial validation of the elements
      • Elements:
        • Aggregate metadata
        • Contain filter and validation chains
      Zend_Form
      • Display Groups:
        • Aggregate elements purely for display purposes
      • Sub forms:
        • Aggregate elements related semantically
        • Provides namespacing of elements via array notation
      Zend_Form
    79. 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,}$/' )), ), )); // ... } }
    80. 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, )); } }
    81. Zend_Form Variant: Dojo-aware form <?php class App_Form_User extends Zend_Dojo_Form { public function init() { $this ->addElement( 'TextBox' , 'username' , array ( // ...
    82. Using forms as validators in your Service Layer
    83. 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' ]; } }
    84. 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(); } }
    85. Interlude: Plugin architectures or, “Override anything!”
      • Aggregates prefix => path pairs: Zend_Validate_ => Zend/Validate/
      • Acts as a LIFO stack
      • Specify class name minus prefix to load: $class = $loader->load('StringTrim'); // Zend_Filter_StringTrim
      Zend_Loader_PluginLoader
      • Zend_Application_Bootstrap
      • Zend_Form
      • Zend_View
      • Zend_Amf_Server
      • Zend_Paginator
      • Zend_Controller_Action_HelperBroker
      • More...
      Plugin-aware components
      • Use short names instead of Really_Long_Underscored_Names
      • Define plugins via configuration options instead of in your code
      • Drop overrides into your filesystem, and get behavior changes
      Benefits of plugins
    86. 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; } }
    87. Registering the prefix-path <?php // General: $loader ->addPrefixPath( 'My_Validate' , 'My/Validate' ); // Specific: Zend_Form_Element: $element ->addPrefixPath( 'My_Validate' , 'My/Validate' , 'validate' );
    88. Retrieving the class <?php // returns 'My_Validate_IsFoo' $class = $loader ->load( 'IsFoo' );
      • 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.
      • Register the new prefix-path with the loader. E.g., $loader->addPrefixPath('My_Validate', 'My/Validate');
      • The new class will now be used.
      Override existing plugins
    89. Controllers or, “Route this!”
    90. How it all works
    91.  
      • Receive request
      • Route request
      • Dispatch loop
        • Pre-dispatch
        • Dispatch controller action
        • Post-dispatch
      • Send response
      Or, more simply:
      • Zend_Controller_Front
      • Zend_Controller_Plugin
      • Zend_Controller_Router
      • Zend_Controller_Dispatcher
      • Zend_Controller_Action_Helper
      • Zend_Controller_Action
      Components
      • Handles entire request life-cycle
      • Executes all other components
      • Singleton: Zend_Controller_Front::getInstance()
      Front Controller
      • Bookend each major responsibility:
        • Routing
        • Dispatch loop
        • Dispatch
      • Used for site-wide actions
        • Layouts
        • Error handling
      • Not handled via PluginLoader (yet!)
      Plugins
      • Default routing: /controller/action[/key/value/k/v]
      • Can register alternate routes:
        • Static routes
        • “ Normal” routes /with/:placeholder/:segments
        • “ Regex” routes for fine-grained control
      • First matched route wins
      • LIFO stack
      Routing
      • Resolves controller to a class
      • Instantiates controller
      • Executes requested action
      Dispatching
      • Obviate the need to create custom base controller classes
      • Re-usable functionality that requires integration with or access from action controllers
      • Have pre-/postDispatch hooks, allowing for task automation
      • Zend_Controller_Action_HelperBroker: Combination static registry and service finder (uses PluginLoader internally)
      Action Helpers
    92. 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' );
    93. 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' );
    94. 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(); } } }
      • Named “ <name>Controller ”
      • In modules, module name is used as prefix: “ Foo_BarController ”
      • Can use MixedCase; in URL, words are dash-separated: “ FooBarController ” is referred to as “foo-bar”
      Action controllers
      • Named “ <name>Action() ”
      • Can use MixedCase; in URL, words are dash- or dot-separated: “ fooBarAction ” is referred to as “foo-bar” or “foo.bar”
      Action methods
      • Public $view property is the view object
      • Protected $_helper property refers to the helper broker: $this->_helper->foo retrieves “foo” action helper
      • getRequest() and getResponse() provide access to request environment and response payload, respectively
      Features of controllers
      • Injects view object into controllers
      • Renders views during p ostDispatch()
        • Standardizes view script resolution to <controller>/<action>.phtml
      • Simply an action helper; retrieve it using $this->_helper->viewRenderer
      ViewRenderer
    95. 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
    96. 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
    97. FooController <?php class FooController extends Zend_Controller_Action { public function indexAction() { } public function bazAction() { } }
    98. 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(); } }
    99. 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(); } }
    100. Views or, “Pics, or it didn't happen!”
      • PHP as a template language
      • LIFO stack of view script paths used to resolve script path to render
      • Helper plugins for extending view functionality
        • Helpers called as if they were view object methods
        • Resolve to a class and method
        • Override helpers locally if desired
      Zend_View
      • View variables are registered as object properties
      • View scripts operate in the view object's variable scope; “$this” in a view script is the view object
      • Use PHP shorthand/alternate notations for readability
      Zend_View
    101. 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>
    102. Common helpers
      • Json
      • Navigation
      • PaginationControl
      • ServerUrl
      • Translate
      • Url
      • Cycle
      • HtmlFlash
      • HtmlList
      • HtmlObject
      • HtmlPage
      • HtmlQuicktime
    103. Using helpers <?php $this ->doctype( 'XHTML1_STRICT' ); $this ->headTitle( 'Example Helpers' ); ?> <h2><?php echo $this ->translate( 'headers' ) ?></h2> <?php echo $this ->partial( 'content.phtml' ) ?>
      • Aggregate content
      • Rendering the helper concatenates aggregated content
      • Typically used to aggregate information for the layout
      “ Placeholder” helpers
    104. Placeholder example <?php $this ->headTitle( 'Foo' ); $this ->headTitle( 'Bar' ); $this ->headTitle()->setSeparator( ' - ' ); echo $this ->headTitle(); // &quot;Foo - Bar&quot;
    105. Placeholder helpers
      • InlineScript
      • Layout
      • Partial
      • PartialLoop
      • Placeholder
      • Doctype
      • HeadLink
      • HeadMeta
      • HeadScript
      • HeadStyle
      • HeadTitle
    106. Rendering Forms
    107. First, a word on Decorators
      • A Decorator typically wraps the functionality of an existing object, and selectively modifies its behavior
      • Alternately, a decorator may be used to create a representation of an object
      • In Zend_Form, decorators pull metadata from forms and elements to create representations. Many decorators proxy to view helpers !
    108. 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 ; } }
    109. … 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; />
      • You can layer decorators to aggregate output from multiple decorators
      • Decorators are processed in FIFO order
      • Generated content is passed to the next decorator as input
      • Typically, append, prepend, or replace content
    110. 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' , ));
    111. Typically, then, render the form: <?php echo $this ->form ?>
      • Decorators are plugins
      • Can be rendered individually
        • Retrieve decorator and render
        • Use overloading to render individual decorators
    112. Rendering individual decorators <?php $element = $this ->form->foo; echo $element ->getDecorator( 'label' ) ->render( '' ); // or: echo $element ->renderLabel();
      • Either pass the form to the view, or pull it from the model within the view
      • Configure decorators in the view, if customizations are needed (view logic)
      • For truly complex markup, render individual decorators within markup
      Recommendations
    113. Form-related view helpers
      • FormPassword
      • Form
      • FormRadio
      • FormReset
      • FormSelect
      • FormSubmit
      • FormTextarea
      • FormText
      • Fieldset
      • FormButton
      • FormCheckbox
      • FormErrors
      • FormFile
      • FormHidden
      • FormImage
      • FormLabel
      • FormMultiCheckbox
      • FormNote
    114. Layouts
      • Zend_Layout implements the Composite View and Two Step View design patterns
      • The internal implementation utilizes front controller plugins, action helpers , and view helpers
      • Layout scripts are simply view scripts
    115. 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>
      • $this->_helper->viewRenderer->setNoRender(true);
      • $this->_helper->layout->disableLayout();
      Disabling views and layouts
      • View scripts should be concise
      • Hint to the layout script from your view scripts (not your controllers!)
      • Layouts should use placeholders as much as possible
      • Setup common layout elements in a bootstrap resource
      Recommendations
    116. 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' ); } }
    117. Service Endpoints or, “Got API?”
      • All server components implement PHP's SoapServer API
      • All public methods of attached classes are exposed
      • Reflection on docblock annotations provides parameter and return value types to the service. You must provide @param for each parameter, and @return always!
    118. 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 ;
      • Create bootstrap classes specific to your servers
      • Re-use application configuration, when possible
      • Use namespaces when the service protocol allows (XML-RPC, JSON-RPC)
      • Write decorators for your service layer so as not to expose methods related to implementation
      Recommendations
    119. Conclusions or, “The fat guy sings”
      • Spend your time on your domain models and service layers
        • Use Zend Framework components judiciously and to aid development
        • 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
    120. Questions? or, “Your turn!”
    121. Thank you. http://framework.zend.com/ http://twitter.com/weierophinney http://slideshare.net/weierophinney Feedback? http://joind.in/talk/view/603

    + Matthew Weier O'PhinneyMatthew Weier O'Phinney, 5 months ago

    custom

    8012 views, 39 favs, 7 embeds more stats

    Zend Framework workshop presented at the Dutch PHP more

    More info about this document

    CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

    Go to text version

    • Total Views 8012
      • 7871 on SlideShare
      • 141 from embeds
    • Comments 0
    • Favorites 39
    • Downloads 392
    Most viewed embeds
    • 111 views on http://mateusztymek.pl
    • 20 views on http://kbs.kimbs.cn
    • 3 views on http://www.kimbs-local.info
    • 2 views on http://static.slidesharecdn.com
    • 2 views on http://kimbs-local.info

    more

    All embeds
    • 111 views on http://mateusztymek.pl
    • 20 views on http://kbs.kimbs.cn
    • 3 views on http://www.kimbs-local.info
    • 2 views on http://static.slidesharecdn.com
    • 2 views on http://kimbs-local.info
    • 2 views on http://kimbs.info
    • 1 views on http://www.mefeedia.com

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories

    Groups / Events