php|architect's Guide to Programming with Zend ... - WordPress.com

3 downloads 448 Views 5MB Size Report
a Zend Framework application can be defined at runtime using simple PHP com- mands. This saves developers ...... explain
php|architect’s

Zend's new PHP 5 Certification Exam represent an excellent tool for professional PHP developers who want to distinguish themselves in their field. php|architect's Zend PHP 5 Certification Study Guide, edited and produced by the publishers of php|architect magazine, provides the most comprehensive and thorough preparation tool for developers who wish to take the exam. This book provides complete coverage of every topic that is part of the exam, including: ✔ PHP Basics ✔ Functions ✔ Arrays ✔ Strings and Patterns ✔ Web Programming ✔ Object Oriented Programming ✔ encoding="UTF-8"?> Keyword Content Analyzer URL To Analyze:



190 ” Appendix A - Zend_Layout and doing the Two-Step

Ok, through this point, we have seen how to set things up and display them. However, without a few minor changes to our controllers, nothing is going to work right. Each of the controllers has minor changes but to conserve space, I’m only going to show snippets that show the changes. First, let’s look at BaseController. In BaseController, the init() changed so much that I’ll just show you the whole thing.

When we were discussing header.phtml, we discussed the fact that we have to store the member object in the placeholder to make it available to both the layout and the view. This used to be stored in $this->view->member. $this->view->headMeta(’my, list, of, cool, keywords, goes, here’,’keywords’);

Back when we were discussing the layout file, main.phtml, we talked about the head*() methods. One of the methods was $this->headMeta()->setIndent(4). This line shows how to add things to the headMeta property. If headMeta is called without any input parameters then it outputs all of the head meta tags that have been defined. However, if it’s called with two parameters then it will add them to the head registry for later output. In the case of headMeta, the first parameter is the content and the second is the keyword. This line will eventually output the following in the final source:

Next we’ll take a look at this: $this->view->headTitle(Globals::getConfig()->title);

Licensed to 39728 - Wei Dai ([email protected])

public function init() { $memberSession = new Zend_Session_Namespace(’member’); if($memberSession->member) { $this->view->layout()->member = $memberSession->member; }

Appendix A - Zend_Layout and doing the Two-Step ” 191

Similar to headMeta(), headTitle(), if passed a parameter will set the title of the page. If called without a parameter, it will output the stored value for the title of the page. $this->view->layout()->footer =

Here is the call to the footer partial. We discussed earlier that displaying footer is conditional. Here in BaseController::init() we execute the partial and store the results in the view property footer. Then, in the actual action we can decide if we want to leave it or clear it. As we will see in IndexController, there is actually one page I don’t want to display it on. This call to partial() illustrates something important though, the ability to pass in parameters and values to the partial. In footer.phtml, we use the variable $this->copyright, since we are executing this as a partial, it doesn’t have the view as a context, therefore, anything we want it to use, we have to pass into the call. The third parameter of partial() is an associative array of view parameters. (The second one is an array of module parameters, if you are interested. I’ve managed to stay away from modules this far and I have no intention of breaking that rule now) Any key you pass in on this parameter will be accessible as $this->key with its value properly populated. Now, let’s take a look at IndexController and the changes that were necessary on the controller level to implement Zend_Layout. The first method that changes is, the indexAction() method. Here’s a snippet: public function indexAction() { $this->view->token = $this->generateToken(); $this->_helper->layout()->body_onload=’onload="document.mainform.url.focus() ;"’;

The last line is where we set the body_onload property we defined back in the main.phtml layout.

Licensed to 39728 - Wei Dai ([email protected])

$this->view->partial(’footer.phtml’, null, array(’copyright’=>"(c) 2008 Cal Evans, All Rights Reserved")) ;

192 ” Appendix A - Zend_Layout and doing the Two-Step

. . . $this->view->layout()->pageTitle = "Home";

$this->view->headScript(’file’,"/js/prototype.js"); $this->view->headScript(’file’,"/js/scriptaculous.js");

Since this is the only action that needs any external JavaScript, we only use the headScript() methods here. headScript() takes five parameters. The first tells it what type of action it will be taking. Passing in FILE tells it that this will be a linked file and generate a simple tag pair with a src option. Passing in SCRIPT tells it that the next parameter (the second parameter) is the contents of a script and should be echoed straight into the file. The third parameter is placement. It determines whether the tag set or script is appended or prepended to the list that will be output. The default for placement is append, similar to adding things to the bottom of an array. In our case, we leave it off because we are adding the scripts in the order we want the output. The fourth parameter is an array of attributes. You can specify three different properties in this array. • charset • defer • language If you specify one of these three, it will be included in the script tag.

Licensed to 39728 - Wei Dai ([email protected])

At the very end of each action, we now set the property pageTitle. We place it in the placeholder because header.phtml is going to use this in the defined H2 tag. So from a controller’s action point of view, the changes are minimal. Our code would have basically worked just as it had been written before but we would have missed the onLoad and we would have had an empty H2 tag set. In riaAction(), we see one new concept, the use of headScript() to pass in JavaScript files to be linked in from our main.phtml.

Appendix A - Zend_Layout and doing the Two-Step ” 193

The fifth parameter of headScript is type. The default for this is text/JavaScript as any other script type is valid here. This is not validated so it is entirely possible to specify a type that a browser cannot understand. Be careful when setting your script type. Beyond the use of headScript(), riaAction() has only one other point of interest, this is the action where we do not show the footer. The reason the footer is not displayed on the RIA page is simple, I needed an example to show this concept. The second to last line in the riaAction() method is: = ’’;

Since we put this in the BaseController::init(), clearing it here, before we build our template, effectively destroys that content and removes it from the page. You can examine the code for the other controllers to see where things have been added or changed but as you will see, most of them are just variations on what we’ve discussed. I’d like to say one final word about Zend_Layout and layout files before moving on to the final section of this Appendix. You have to be careful where you put your .phtml files and where you look for them. In most cases, it acts just like you would expect. However, in the case of header.phtml, we have a problem. This partial is being called from within a controller. Since it is not in the controller action, but in the BaseController::init() Zend_Layout cannot determine where the file should be. Therefore it looks for it in the root scripts directory, not the root layout directory. Zend_Layout considers the partial() a view script, not a layout script and paths it accordingly. The header.phtml however, because it is being called from the layout and not the view, is treated as a layout. If you look at the views/ directory you will see that header.phtml is in layouts while footer.phtml is in scripts. In the final section of this Appendix I want to talk about how Zend_Layout affects our API controller. At first blush, the answer is that it doesn’t. Since the API returns JSON or XML, we don’t really need layouts. This, for the most part, is correct. That is why, in ApiController::init() we’ve added a line. public function init() { $this->_helper->viewRenderer->setNoRender();

Licensed to 39728 - Wei Dai ([email protected])

$this->view->layout()->footer

194 ” Appendix A - Zend_Layout and doing the Two-Step

The second line turns off layouts for all actions in this controller. If you don’t add that then it will take your API payload and wrap it in the main.phtml. I think we can all agree that this is not the desired behavior. So for all but our fetch*Action() methods, we simply turn it off. However, our fetch*Action() methods all return an XML payload. To do this, they all pass their array into our toXml() method that we’ve previously described. However, there is a way to use the new Zend_Layout to do this differently. I’m discussing this because it’s an option, not necessarily a better option. toXml() uses SimpleXML to build the payload and it does a great job. However, the XML we are generating is brain-dead simple and even if it wasn’t, we don’t need to parse it, just build it. I’ve created a new method called ApiController::complexToXML(). It takes the same parameters as ApiController::toXml() and outputs the same XML, only the method has changed. None of the techniques we will show in this piece of code are new, we’ve talked about them previously. However, this is a unique application of the Zend_Layout. Remember, we turned off the default behaviors for layout. So here, we make calls to partial() to build our XML in a string. Here is the new method, complexToXml(), along with a discussion of what is going on. public function complexToXml($dataArray,$callingMethod,$parameterValue) { $words = ’’; $xml = ’’; foreach($dataArray as $keywordArray) { $words .= $this->view->partial(’api/word.phtml’, array(’keyword’ => $keywordArray[’keyword’], ’keyword_count’ => $keywordArray[’keyword_count ’])); } // foreach($results as $keywordArray)

This for/next calls word.phtml. word.phtml, as you will see below is an XML snippet that builds the XML for one word. Here we spin through our array of words and concatenate a string.

Licensed to 39728 - Wei Dai ([email protected])

$this->_helper->layout->disableLayout(); } // public function init()

Appendix A - Zend_Layout and doing the Two-Step ” 195

$xml = $this->view->partial(’api/complex-to-xml.phtml’, array(’words’ => $words, ’callingMethod’ => $callingMethod, ’parameterValue’ => $parameterValue, ’rowCount’ => count($dataArray)));

Now, we take the $words string that we built previously and pass it to complex-to-xmp.phtml along with the other parameters necessary to complete the XML payload.

Now let’s look at the two partial layouts we are using. First word.phtml:

As we discussed, this contains all the XML necessary to deliver a single term. Now the main layout, complex-to-xml.phtml:

This is the entire template with placeholders for each of the parameters and one for the snippet containing the words. That’s it, we are simply using the Zend_Layout to layout our XML instead of our HTML. This concept, using Zend_Layout for non-traditional payload creation, can be

Licensed to 39728 - Wei Dai ([email protected])

return $xml; } // public function complexToXml($dataArray,$callingMethod,$parameterValue)

196 ” Appendix A - Zend_Layout and doing the Two-Step

used in just about any situation. Whether you need JSON, CSV, YAML or a custom payload, Zend_Layout can be used for more than just layouts. Summary:

• Zend_Layout is great for implementing layouts in your design. You can have different layouts for different areas of your site, or, as we did, one ugly layout for the entire site. Zend_Layout can, however, be used for more than that. Anytime you need formatted output to send as a payload, Zend_Layout can help you organize it and reduce or eliminate repeated lines. We showed the source code for modifying the IndexController.php and two of its view scripts. However, to properly implement Zend_Layout we had to touch each view script. Since in almost every case, we did the same thing over and over, it didn’t seem necessary to print each modified view script. If you are curious, you can unpack example9.zip and see what changes were made.

Licensed to 39728 - Wei Dai ([email protected])

• Watch where you store things. Using Zend_Layout introduces an extra level of complexity. Sometimes your normal storage schemes will work and sometimes they won’t. Make sure you know when to use each storage container when passing variables to the view.

Licensed to 39728 - Wei Dai ([email protected])

Licensed to 39728 - Wei Dai ([email protected])

Symbols .htaccess, 9, 15 $_SESSION, 32 __construct, 44, 53 __set, 45 __set(), 60 _data array, 45 A access control, 87 action process, 48 action helpers, 35 direct(), 35 postDispatch(), 35 preDispatch(), 35 ActiveRecord pattern, 4 adapter, 43 addPath(), 37 addPrefix(), 37 addScriptPath(), 60 Ajax, 156, 161 allow_url_fopen, 6 API fetchTerm(), 129 fetchTop(), 129 Flickr, 121 key, 122

supported classes in Zend Framework, 122 with Zend_Layout, 193 Yahoo Term Extraction API, 27, 42 documentation, 23 parsing URLs with, 22 Zend_Service_Flickr, 122 ApiController, 129, 161 application, 9 building your first, 9 arrays converting to XML, 133 populating, 44 authenticate(), 88, 93 authentication, 87, 88 adapters, 88, 91 clearIdentity(), 95 definition, 87 digest, 94 http, 94 persistent storage, 88, 95 Zend_Auth_Adapter_DbTable, 88 Zend_Auth_Adapter_Digest, 88 Zend_Auth_Adapter_Http, 88 Zend_Auth_Adapter_Interface, 88 Zend_Auth_Result, 88, 93 Zend_Auth_Storage_Interface, 88 Zend_Storage, 88

Licensed to 39728 - Wei Dai ([email protected])

Index

B BaseController, 31, 91, 129, 176, 190 BaseController.php, 31, 52, 53 Basecontroller.php, 31 BaseModel, 90, 102 BaseModel.php, 99 basic classes, 13 binding, 76 body_onload, 185 bootstrap, 16, 102, 168, 170 defining for CLI, 173 bootstrap file, 9, 12, 21 bug tracking, 5 business logic, 41, 42, 44, 59, 156 business objects, 22 C cache controller, 124 cacheCleanAction(), 177 caching, 103 backend storage, 104 cache key, 109, 124 ensuring uniqueness, 124 with md5, 124 cleaning, 126 cleaning from CLI, 167 clearing, 111 clearing portion of, 111 conditional execution, 110 invalidating, 112 save, 125 save(), 109 storing in global configuration, 117 tagging, 110 Cal_Controller_Request_Cli, 169, 174 Cal_Controller_Router, 169 camel case, 17 catch blocks, 140 checkEmail(), 44, 76

clearCache.php, 169, 173 CLI, 167 passing options in, 170 code generator, 42 command line processing, 168 passing options in, 170 community communication, 5 programmers, 5 complex-to-xml, 195 complexToXml(), 194 component library, 3 config.ini, 116, 143, 184 configuration, 4, 11, 14 default, 11 error handling, 14 front controller, 14 finding other controllers, 14 parameters, 14 configuration file, 114 congif.ini, 144 Contributors License Agreement, 5 controller, 9, 16, 41, 42, 44, 47, 48 actions, 16 cache, 109 creating, 9 front, 14 helper functions, 17 implementation of, 24 methods, 16 purpose of, 21 core framework components, 38 credential column, 92 CRUD, 42 curl, 168 D database, 42, 73 adapter, 75

Licensed to 39728 - Wei Dai ([email protected])

200 ” INDEX

building SQL dynamically, 130 connecting to, 73, 99 factory method, 74 connection, 90, 101 storing in global configuration, 117 connections, 43 dbname, 74 driver_options, 74 factory method parameters, 73 fetchAll(), 77 fetchAssoc(), 79 fetchCol(), 79 FetchMode, 75 fetchOne(), 81 fetchPairs(), 80 fetchRow(), 80 generating SQL queries, 131 host, 74 MySQL, 42 options, 74 parameters dbname, 43 host, 43 password, 43 username, 43 password, 74 populating, 44 port, 74 profiler, 74, 81, 84 clear(), 83 getElapsedSecs(), 83 getLastQueryProfile(), 83 getQuery(), 83 getQueryParams(), 83 getQueryProfiles(), 83, 84 getTotalElapsedSecs(), 83 getTotalNumQueries(), 83 setFilterElapsedSecs(), 84

setFilterQueryType(), 84 saving data, 44 username, 74 Zend_Db, 43 database adapter, 75 database adapters, 73 database connection object, 43 desktop applications, 155 development environment, 6, 11, 13 error handling, 13 front controller, 14 include_path, 12 directory structure, 9–11, 36, 64, 100 application, 13 htdocs, 11 incubator, 10 index, 22 lib, 13, 169 library, 10, 11 processes, 169 root, 11 scripts, 22 temporary files, 108 web application root, 11 web server root, 11 web site root, 11 www, 11 display logic, 59 DOCTYPE setting, 184 Doctype.php, 184 documentation, 5 download svn, 10 downloading Zend Framework, 9, 10 downloads, 5 DRY, 181 E

Licensed to 39728 - Wei Dai ([email protected])

INDEX ” 201

email address validation, 47 emailCheck(), 48, 50 error handling, 13, 14, 137 logging to error log, 143 error log, 143 Error.log, 143 error.phtml, 142 errorAction(), 141 ErrorController, 141, 142, 144 escaping output, 61 example2.zip, 22, 31 example4.zip, 90, 94 example7.zip, 141, 156 example8.zip, 169 Exception class, 138 parameters, 140 exceptions, 13–15, 137 catching, 140 cause of, 137 result when thrown, 138 extract.phtml, 22, 29, 63, 127 extractAction(), 24, 33, 34 F factory pattern, 43 fetchAll(), 77 fetchAssoc(), 79 fetchCol, 79 FetchMode, 75 fetchOne(), 81 fetchPairs(), 80 fetchRow(), 80, 81 file_get_contents, 26 filtering input, 25, 48, 50, 61 StripTags, 25 flash messenger, 33 FlashMessage, 146 flashMessenger, 33, 52 Flickr, 121

API key, 122 building image tag, 125 integrating with Yahoo Term Extraction API, 123 link to API, 122 searching tags, 123 Zend_Service_Flickr, 122 fluent interfaces, 26, 112, 144 footer, 186 deciding where to store, 186 front controller, 14 configuration, 14 error handling, 14 finding other controllers, 14 noErrorHandler, 15 noViewRenderer, 15 setControllerDirectory, 15 throwExceptions, 15 Front.php, 13 G generateToken(), 34 getopt, 170 parameters, 170 getScriptPaths(), 60 global configuration values, 113 Globals.php, 100 accessing, 102 preventing instantiation of copy, 150 storing configuration values in, 113 using with Zend_Cache, 103 H header.phtml, 185 headMeta, 190 help, 5 HelperBroker, 36 HistoryController, 94, 108 HistoryController.php, 89, 103, 127

Licensed to 39728 - Wei Dai ([email protected])

202 ” INDEX

INDEX ” 203

I identity column, 91 include_path, 11–13 incubator, 10 index.php, 9, 12, 21, 102, 118, 141, 142, 168, 173, 182 index.phtml, 22, 23, 34, 66, 189 indexAction, 17, 149 IndexAction(), 23 IndexController, 23, 24, 33, 160, 191 extractAction(), 24 indexAction(), 24, 33 IndexController.php, 16, 21, 22, 24, 31, 33, 48, 52, 59, 63, 76, 89, 126, 156 INI files, 114 init(), 37, 52, 94, 130, 176, 190 inlineScript(), 186 integrated development environment, 7 intellectual property, 5 J JavaScript, 156, 192 JSON, 163 L layout objects, 187 layout(), 187 lazy connections, 76 libraries, 13, 169 custom, 169 library, 10, 11 license Apache, 5 BSD, 5

commercial applications, 5 Contributors License Agreement, 5 Linux, 11 listResults.phtml, 127 load(), 44, 45 loadClass, 32 Loader.php, 13 login(), 44, 47 M magic methods, 60 mashup, 122 creating, 128 md5, 43 md5 hash, 32 member class, 44, 47, 48 helper functions, 44 member login, 52 Member.php, 102 MemberController, 48, 52 MemberController.php, 51, 89 meta tags storing, 190 methods naming, 17 minimum requirements, 4 mktime(), 32 mod_rewrite, 15, 16 model, 21, 41, 76 building, 41 from database schema, 42 implementation, 41 heavy model, 42 light model, 42 no model, 41 MVC, 2, 3, 59, 62 controller definition, 3 examples, 3

Licensed to 39728 - Wei Dai ([email protected])

htdocs, 11 htmlList(), 63 parameters, 63 htmlspecialchars(), 61

model definition, 2 examples, 2 origin, 2 view definition, 2 MyHelper.php, 66, 90 MySQL, 42 N namespace, 49 global_data, 32, 33 namespaces, 32, 88 naming conventions, 169 new components, 5 proposals, 10 proposing, 5 reviewing, 5 noViewRenderer, 24 O object oriented programming, 6 Object-Relation Mapper, 4 ORM, 4 output, 14 P partial(), 191 password, 43 passwords storing, 92 storing in a database, 43 payload, 162 performance, 103 PHP version compatibility, 4 PHP-GTK, 167 php.ini, 6, 146, 173 PHP/MySQL installers, 6 PHPUnit, 4

plugins, 35 postDispatch(), 35 preDispatch(), 35 POST vs GET, 28 ProcessController.php, 168 processLogin(), 48 processRegistration(), 48 production environment, 10, 11, 25, 31, 77, 93, 94, 113, 141, 148 error handling, 13 front controller, 14 include_path, 13 profiler, 81, 84 Prototype.js, 161, 162 R refactoring, 22 regular expressions, 27 stripping HTML code, 27 render(), 60 requirements, 6 REST, 122, 162 returning JSON, 162 RIA, 155 payload, 162 ria.phtml, 160, 164 riaAction(), 160, 192 Rich Internet Applications, 155 route(), 169 S save(), 45, 125 security, 30, 48, 61 filtering input, 25 using tokens, 31 SEO, 186 session, 32, 49 setCredentialTreatment(), 92 setEscape(), 61

Licensed to 39728 - Wei Dai ([email protected])

204 ” INDEX

setScriptPath(), 60 setView(), 68 sha1, 43 singleton, 14 singleton pattern, 89 SOAP, 122 SQLyog, 43 stack trace, 138, 144 startMVC(), 182 options, 182 static method, 48 static methods, 44 storage property, 101 T tagSearch(), 122 templating system, 59 testDBaction(), 81 testing code coverage, 4 ticketing system, 5 token, 31, 34, 48, 50, 52, 156 checking, 33, 34 generating, 32, 34 regenerating after request, 34 storing, 32 tokenCheck(), 34 try/catch, 13–15, 137, 139 where to include, 145 two-step views, 181 U uncaught exception, 13 URL parsing, 23 retreiving contents of, 23 use at will architecture, 3 components of, 28 V

view, 21, 22, 28, 32, 33, 42, 48, 52 helpers, 61 flash messenger, 33 instantiating, 59 purpose, 59 rendering output, 60 script helper, 9 scripts, 60 view script, 29 view scripts, 21, 22 view helpers custom, 64 rules for creating, 64 default, 62 with Zend_Layout, 189 view script, 52, 60 view scripts, 53 custom, 60 default location, 60 viewRenderer, 130 W web root, 12 web service creating your own, 128 REST, 128 web services, 121 web site, 5 components in core framework, 38 web_property table, 89 web_property_analysis table, 89 web_property_analysis_results, 90 WebProperty, 157 WebProperty.php, 103, 112, 123 WebPropertyAnalysis.php, 103 wget, 168 Windows, 11 word.phtml, 195 working environment, 6

Licensed to 39728 - Wei Dai ([email protected])

INDEX ” 205

working with templates, 183 X XAMPP, 6 XML-RPC, 122 Y Yahoo, 23 appid, 23 Yahoo Term Extraction API, 27, 121 integrating with Flickr, 123 Z Zend Core, 6 installing, 6 use with Apache, 6 use with IIS, 6 Windows, 6 Zend Framework community, 4, 5 history, 4 key concepts, 4 license, 5 Zend PHP Collaborative Project, 4 Zend Studio, 7 Zend_Acl, 87 Zend_Auth, 88, 91 Zend_Cache, 3, 103, 167 automatic serialization, 108 cache key, 109 clean(), 111 conditional execution, 106, 110 frontend storage, 104 key identifier, 106 lifetime, 106 tagging, 110 using with Flickr API, 123 using with Globals.php, 103 Zend_Config, 113, 182

Zend_Config_Ini, 114 parameters, 115 Zend_Config_Xml, 113 Zend_Console_Getopt, 170, 174 Zend_Controller_Action, 32, 53 Zend_Controller_Front, 14 Zend_Controller_Plugin_ErrorHandler, 141 Zend_Controller_Request_Abstract, 169 Zend_Controller_Router, 169 Zend_Db, 43, 47, 73, 101 dbname, 74 driver_options, 74 host, 74 options, 74 AUTO_QUOTE_IDENTIFIERS, 74 CASE_FOLDING, 74 FETCH_ASSOC, 74 FETCH_BOTH, 74 FETCH_COLUMN, 74 FETCH_NUM, 74 FETCH_OBJ, 74 password, 74 port, 74 profiler, 74, 81 username, 74 Zend_Db_Exception, 139 Zend_Db_Select, 84 Zend_Db_Table, 84 Zend_Db_Table_Relationships, 84 Zend_Db_Table_Row, 84 Zend_Db_Table_Rowset, 84 Zend_Exception, 138, 145 Zend_Feed, 3 Zend_Filter, 27, 34, 48, 50 Zend_Json, 164 Zend_Layout, 181, 182 with API controller, 193 with XML, 195 Zend_Loader, 16, 100

Licensed to 39728 - Wei Dai ([email protected])

206 ” INDEX

INDEX ” 207

Licensed to 39728 - Wei Dai ([email protected])

Zend_Log, 3 Zend_Rest_Client, 3, 28, 134, 148 Zend_Rest_Server, 134 Zend_Service_Flickr, 122 Zend_Service_Flickr_ResultSet, 123, 125 Zend_Session, 88 Zend_Session_Namespace, 32 Zend_Validate, 25 Zend_Validate_Email_Address(), 47 Zend_View, 59, 61 Zend_View_Helper_MyHelper, 66