PHP in Action phần 7 potx

55 387 0
PHP in Action phần 7 potx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

WHICH TEMPLATE ENGINE?305 the PHPTAL equivalent would be <td tal:content="username">Dummy user name</td> PHPTAL is supremely friendly from a web designer’s point of view. WYSIWYG HTML editing tools generally ignore unknown attributes, and PHPTAL lets you insert dummy content that will make the template look like the real web page when viewed in a WYSI- WYG HTML editor—or in a web browser for that matter. Figure 13.4 shows what a PHPTAL template for the user list looks like when opened as a file in a web browser. This is possible because of PHPTAL’s ability to insert example content that disappears when the real application is run. Let’s look at the PHPTAL template (see listing 13.5). <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> c <head> <title> User administration </title> </head> <body> <div id="content"> <h1> User administration </h1> <table id="AdminList" cellspacing="0"> <tr> <th>Login name</th> <th>First Name</th> <th>Last name</th> <th>Email address</th> <th>Role</th> <th> </th> </tr> <tr tal:repeat="user users"> d Figure 13.4 PHPTAL template viewed in web browser Listing 13.5 PHPTAL template for user list b 306 CHAPTER 13 USING TEMPLATES TO MANAGE WEB PRESENTATION <td tal:content="user/getUsername">victor</td> <td tal:content="user/getFirstname">Victor</td> <td tal:content="user/getLastname">Ploctor</td> <td tal:content="user/getEmail">victor@example.com</td> <td tal:content="user/getRole">regular</td> <td> <a href="userform.php?id=$user/getID" f class="CommandLink">Edit</a> </td> </tr> <tr tal:replace=""> <td>elietta</td> <td>Elietta</td> <td>Floon</td> <td>elietta@example.com</td> <td>webmaster</td> <td> <a href="userform.php?id=42" class="CommandLink">Edit</a> </td> </tr> </table> </div> </body> </html> b The DOCTYPE declaration was generated by HTML Tidy. It expresses the fact that this is an XHTML document. PHPTAL will be just as happy if we replace it with a plain XML declaration such as <? xml version="1.0">. In fact, PHPTAL seems to accept the file without the declaration, but it’s better to have a file that can be checked by an XML parser. C The xmlns attribute, generated by Tidy, declares the XHTML namespace to be the default namespace for this document. That means that all tags and attributes without an explicit namespace should be interpreted as belonging to the XHTML namespace. D The tal:repeat attribute is technically an XML attribute belonging to the TAL namespace. The namespace is a way of making sure an attribute is distinct from all other attributes. This makes it possible for us to use another repeat attribute from another namespace if we should happen to need it. What tal:repeat does in PHPTAL may be obvious: it iterates over the array of user objects in exactly the same way that foreach in PHP or Smarty does. The dif- ference is that because tal:repeat is an attribute, we don’t need to place a separate tag for it. Nor do we need an end tag; the </tr> tag is the end tag for tal:repeat. E tal:content replaces everything between the tags with the content taken from our user object. So the user name and other data inside the tags is only dummy or e g WHICH TEMPLATE ENGINE?307 example content that makes the template easier to understand and to view in a WYSI- WYG editor. No escaping is required, since PHPTAL does this by default. F Most of the dynamic content in PHPTAL templates is represented as TAL attributes. To add content to an attribute, it’s more intuitive to use a different syntax, which is what you can see here. To insert the user ID into the href attribute, we represent it as $user/getID. Again, the template is as close to the plain HTML representation as possible. G Because of the tal:replace attribute, this entire table row is thrown out— replaced with an empty string—when the template is processed. The first table row in the template—the one that contains tal:repeat—generates all the table rows in the output. The dummy row is only there for the sake of the template: it makes the template resemble the web page that’s generated when the application is run. We can add any number of such dummy rows if we want. They will all disappear when the template is processed. The difference between tal:replace and tal:content is the following: tal:content removes the material between the HTML tags and replaces it with dynamic content. tal:replace removes what’s between the tags and the tags themselves. When we want to write the PHP code to process the template, we find that PHP- TAL is similar to Smarty and other template engines (see listing 13.6). <?php require_once 'HTML/Template/PHPTAL.php'; require_once 'UserFinder.php'; $finder = new UserFinder; $users = $finder->findAll(); $template = new PHPTAL('userlist.tal'); $template->set("users",$users); echo $template->execute(); The difference between this and the Smarty example is slight. The methods are named differently and PHPTAL has no method for displaying the output directly, so we just echo the results of template processing. One of the advantages of PHPTAL is that the templates are XML and can be pro- cessed using other XML-based tools. This is even more applicable to the next item on our agenda: XSLT. Listing 13.6 Processing the PHPTAL template 308 CHAPTER 13 USING TEMPLATES TO MANAGE WEB PRESENTATION 13.3 TRANSFORMATION: XSLT XSLT stylesheets are another popular way of expressing the HTML tag content of a web page. XSLT, the XML stylesheet language, is a way of transforming XML docu- ments into HTML documents or into other XML documents. So if we want to use XSLT as templates in a PHP application, we first generate XML code, transform that using XSLT, and output it to the browser. Figure 13.5 shows how XSLT works when generating web pages. The stylesheet can be similar to the templates we’ve seen before, but is officially a recipe for the transformation of the XML file into HTML. XSLT is very different from the other template systems. It’s a powerful, non-pro- cedural programming language. You can do all sorts of advanced things with it. But it’s not necessarily the answer to all your template prayers. Its main advantage is its sta- tus as a cross-platform standard. Martin Fowler says: You can use XSLT to transform XML created from J2EE or .NET, which can help in putting a common HTML view on data from different sources. Another way of putting it would be that a lot of different programming languages and environments, including PHP, have tools available for parsing and generating XML. Therefore, XML can be used to communicate between these languages and environ- ments, and XSLT is a natural tool to use when you already have data in XML format. Fowler also thinks that XSLT makes it “easier to keep the transform focused only on rendering HTML, thus avoiding having too much logic in the view.” My experience is exactly the opposite: XSLT offers such interesting opportunities for implementing view logic that the temptation may be hard to resist. Figure 13.5 XSLT works by transforming an XML data file using an XSL stylesheet. TRANSFORMATION: XSLT 309 13.3.1 “XMLizing” a web page When you want to produce an XSLT stylesheet from an existing PHP file or from a sample HTML file, the first thing to do is to create something that’s valid XML. One way to do this is the following: • Replace the PHP processing instructions (<?php ?>) with something that an XML parser will take to be a plain string. For example, you can replace <? with [ and ?> with ]. •Run HTML Tidy to generate valid XML (XHTML). HTML Tidy is a utility program that helps clean up HTML and convert it into XHTML. It’s available at http://tidy.sourceforge.net. There is also a PHP Tidy exten- sion. But for our current purposes, the command-line utility is fine. A typical way to run it would be as follows: tidy -indent -asxml -wrap 150 userlist.xhtml -indent produces indented output. -asxml specifies that the output should be XML. -wrap 150 makes Tidy wrap lines at 150 characters rather than the default 68. With very complex web pages, this may be helpful, since they will sometimes be so deeply indented that there is little room left on the line. Tidy sometimes only gives warnings. At other times, it reports fatal errors that require you to change the file manually. For instance, browsers are usually willing to render a web page even if table markup is incorrectly and inconsistently placed. Tidy (not to mention XML parsers) is not so forgiving. After using Tidy, you can test the result using an XML parser such as the command line utility called xmllint. It’s part of libxml2, the Gnome XML toolkit. The XML support in PHP 5 is based on libxml2. It’s included in several Linux distributions and is also available for Windows. 13.3.2 Setting up XSLT When setting up a PHP application based on XSLT, we can start by making the trans- formation work independently of PHP. To do that, we need •An XML test file that is a representative sample of the XML the PHP application will generate •The XSLT stylesheet •A command-line XSLT tool The command-line XSLT tool for libxml2 is called xsltproc. You can run it as follows: $ xsltproc userlist.xsl userlist.xml 310 CHAPTER 13 USING TEMPLATES TO MANAGE WEB PRESENTATION You can generate the XML test file or write it manually. It’s typically a very simple representation of the data from the database. Listing 13.7 shows how the user list may be represented. <?xml version="1.0" ?> <userlist> <user> <username>victor</username> <firstname>Victor</firstname> <lastname>Ploctor</lastname> <email>victor@example.com</email> <role>regular</role> <id>1</id> </user> <! More users on the same format >1 </userlist> 13.3.3 The XSLT stylesheet If you’re not used to XSLT, the real challenge is in the XSLT stylesheet itself. The stylesheet shown in listing 13.8 tries to approximate ordinary HTML as much as pos- sible. That means that using HTML-like constructs is more important than idiomatic XSLT. The reason for this is the same as with all the other templates: we want a web designer to find it easy to use. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"> c <xsl:template match="/"> d <html xmlns="http://www.w3.org/1999/xhtml"> e <head> <title> User administration </title> </head> <body> <div id="content"> <h1> User administration </h1> <table id="AdminList" cellspacing="0"> <tr> <th>Login name</th> <th>First Name</th> <th>Last name</th> <th>Email address</th> <th>Role</th> Listing 13.7 XML file for testing XSLT template processing Listing 13.8 XSLT stylesheet for the user list b TRANSFORMATION: XSLT 311 <th> </th> </tr> <xsl:for-each select="/userlist/user"> f <tr> <td><xsl:value-of select="username"/></td> <td><xsl:value-of select="firstname"/></td> <td><xsl:value-of select="lastname"/></td> <td><xsl:value-of select="email"/></td> <td><xsl:value-of select="role"/></td> <td> <a class="CommandLink" href="{concat('userform.php?id=',id)}"> h Edit </a> </td> </tr> </xsl:for-each> </table> </div> </body> </html> </xsl:template> </xsl:stylesheet> b Yes, you have to insert all this stuff just to get a valid XSL stylesheet. XSL is verbose. C The output method is html, as we want to generate HTML code. D xsl:template is where the real XSLT processing starts. The match expression is an XPath expression capable of matching a node or a set of nodes in the input XML doc- ument. The template is processed whenever XSLT encounters a node that matches. In this case, the template matches the root node. Since processing starts at the root node, XSLT will start on this template immediately. And since there are no other templates, processing this one is all it will do. E All namespaces have to be declared. This goes for the html namespace as well. F The xsl:for-each selects all the user elements and tells XSLT to process each one. From an XSLT-purist point of view, this is sinful: using xslt:for-each in this context is not idiomatic in XSLT. XSLT is a non-procedural programming language, and for-each is a procedural mode of expression, foreign to XSLT. The typical way to do it in XSLT would be to use a separate template for the repeating section. The rea- son for using for-each is not to make it cozy and familiar for PHP programmers. Instead, the intention is to make a single template that will resemble an HTML page. g 312 CHAPTER 13 USING TEMPLATES TO MANAGE WEB PRESENTATION G xsl:value-of is the XSLT equivalent of echo or print in PHP. Again, the select expression is an XPath expression. The expression is interpreted relative to the current node, so while XSLT is processing one of the user nodes, it outputs the content of, say, the username element in that user node. H The expression that defines the link URL may be an ugly brute, but it’s more HTML- like than some alternatives. The outer braces mean that what’s inside is an XPath expression instead of a string. The concat() function is simple string concatena- tion. In this case, it concatenates the literal string userform.php?id= with the result of the XPath expression id, which happens to be the user ID. 13.3.4 Running XSLT from PHP Although the functions needed to run XSLT from PHP are documented in the PHP manual, we’ll see them in context using the user list again for a complete example. First we generate the XML code and then we transform it (see listing 13.9). $finder = new UserFinder; $users = $finder->findAll(); ob_start(); b ?> <?php echo '<?xml version="1.0" ?>'."\n"; ?> <userlist> <?php foreach ($users as $u) : ?> <user> <username> <?php echo htmlentities($u->getUserName()) ?> </username> <firstname> <?php echo htmlentities($u->getFirstName()) ?> </firstname> <lastname> <?php echo htmlentities($u->getLastName()) ?> </lastname> <email><?php echo htmlentities($u->getEmail()) ?></email> <role><?php echo htmlentities($u->getRole()) ?></role> <id><?php echo htmlentities($u->getID()) ?></id> </user> <?php endforeach; ?> </userlist> <?php $xml = ob_get_contents(); ob_end_clean(); print processXslt($xml,'userlist.xsl'); e function processXslt($xml,$xslfile) { $dom = new DomDocument; $dom->loadXML($xml); Listing 13.9 Generating the user list with XSLT c d f KEEPING LOGIC OUT OF TEMPLATES 313 $xsldom = new domDocument(); $xsldom->load($xslfile); $proc = new xsltprocessor; $proc->importStylesheet($xsldom); return $proc->transformToXml($dom); } b Output buffering is an extremely versatile feature of PHP. Here we’re using it to avoid having to put quotes around all the XML code. Instead, we can have an XML section, similar to the usual HTML sections. Instead of being output, it’s kept until we ask for it. C The XML section is basically a simplified version of an HTML section in a PHP file. All presentation-related elements have been stripped away, and all that’s left is a data structure. Again, we are escaping all the data. This is to be processed through XSLT, and XSLT will usually ignore HTML tags, so the risk of cross-site scripting attacks is less. It’s more likely that suspicious content could generate a fatal syntax error, and using htmlen- tities() helps prevent that. D We get the buffered XML code and turn off output buffering. E The XSLT processing is packaged into a function that takes XML text and the name of the stylesheet file as arguments. F Create a DOM based on the XML document in $xml. G Create another DOM based on the stylesheet. We read this from a file instead of a string, since we have the XML code as a string and the XSLT stylesheet in a file. That’s natural since the stylesheet is relatively constant, while the XML code contains data- base data that may change at any time. H Instantiate an XSLT processor. Tell the XSLT processor to use the stylesheet repre- sented by our second DOM. Then transform the XML using the XSL stylesheet. We’ve seen how to use template engines based on various principles. Using templates goes a long way toward achieving separation between HTML and PHP code. But there is still the risk that we will start undermining the separation by adding too much programming logic to the template itself, either by using the template engine’s built-in programming capabilities ( XSLT has a lot of that), or by sneaking in signifi- cant amounts of PHP code (Smarty and PHTAL both have that option). In the next section, we’ll study some tricks that will help us resist that temptation in particularly difficult cases. 13.4 KEEPING LOGIC OUT OF TEMPLATES Most web application pages have a relatively simple structure, such as a form or a sim- ple list. A loop and perhaps a few simple conditionals will suffice as logic for the g h 314 CHAPTER 13 USING TEMPLATES TO MANAGE WEB PRESENTATION presentation. That’s no big problem in a template, since this minimal logic doesn’t obscure the HTML layout of the page much. But there are a few challenges that are harder to manage without putting more logic into the templates. Presentation logic is a gray area between domain logic and pure lay- out and design: logic that only determines how the data is presented on the web page but is still program logic. These are the cases in which presentation logic gets more complex. An example that is often cited is alternating colors for table rows. There is no way (currently) to do this with HTML or CSS only. (It should be possible with the nth-child() pseudo-class in CSS 3, but browser support for this is practically nonexistent at this writing. It’s also possible with the JavaScript DOM.) Unless the template engine has a special feature that will help us with it, we need something like an if test embedded in a loop. That makes the logic in the template more complex and harder to read and manage. Template designers can live with looping and simple conditionals. But when you start to get nested loops and complex conditionals, they find it at best annoying because it gets in the way of their work. At worst, it’s confusing to designers and opens the door to the dreaded tangle of HTML markup and program code. In this section, we’ll first deal with a general pattern (View Helper) for handling logic that is part of the Presentation layer but is too complex to fit comfortably in a template. Then we’ll look at a series of real-life situations that challenge our ability to keep program logic out of templates and suggest a solution to each of these situations. 13.4.1 View Helper A common strategy for dealing with this is to put presentation logic in PHP classes outside the template (see figure 13.6). We can keep them in separate classes that only handle the View and do not touch the Domain layer. These classes should not gener- ate any HTML code, but they can generate presentation-related information such as the depth of an item in a hierarchical display or CSS classes to allow alternating row colors in a table. This is often considered a form of the View Helper design pattern. View Helper is a somewhat vague concept. But in this context, it has a specific responsibility: to Figure 13.6 Presentation logic can be han- dled by a specialized view class [...]... simple example in plain PHP, starting with the simplest-possible implementation Figure 14.1 shows the kind of layout we want We have four different components here: the banner, the menu, the main text, and the sidebar containing the news list To implement this in “naive” PHP, we use plain include statements: < ?php include < ?php include < ?php include < ?php include ... 'banner .php' ?> 'menu .php' ?> 'welcome .php' ?> 'news .php' ?> So now we’ve assembled the page from a number of components But they’re not yet pluggable We can fix that by replacing one or more of the file names with variables: < ?php < ?php < ?php < ?php include include include include 'banner .php' ?> 'menu .php' ?> "$content .php" ?> "$sidebar .php" ?> Pretty basic, but we want basic (As it stands, it's insecure... list That’s relatively easy to do; eliminating interaction simplifies our job as programmers greatly When we do need interaction, there are challenges that are specific to creating that interaction, and it’s a different kind of challenge with web interfaces than with other kinds of user interfaces I am not referring to interaction design in the sense of user interface design to improve usability That... one Again staying within plain, blunt PHP, all we need to do is make a separate file out of the preceding code and include that from our main script: Figure 14.1 Composite View-type page layout with several different components IMPLEMENTING A STRAIGHTFORWARD COMPOSITE VIEW 3 27 < ?php // Find out which $layout to use // include "$layout .php" ; Wait a minute, you might say There’s no layout at all in the... template engine, is to do the alternation logic in PHP before passing the values to the template We definitely want to avoid having explicit color names or codes in the PHP program code We don’t want to have to change a PHP file for the sake of a styling change The way to do it is to generate a table with alternating CSS classes for the rows Then the colors can be defined in CSS, and the only thing that’s... that goes inside the header, such as a tag containing a page description or specialized CSS stylesheets or JavaScript 14.2.3 Using PHPTAL We can do the same thing in PHPTAL using PHPTAL’s macro feature Instead of captures, we define macros that can be used elsewhere: Welcome to Hazycrazy.com ... this process A tree, identical in structure to the one implied by figure 13 .7, is transformed into an array By using a separate View-oriented class to do this, we can maintain the separation between presentation and domain logic while keeping the template from containing much more than the usual presentation logic The class in listing 13.12 does the job of generating this plainer data structure The most... the kinds of flexibility we need for developing complex layouts In PHP, this is typically achieved by using the built -in features of PHP or template engines 14.1.2 Composite data and composite templates The Composite View is one of the harder challenges in web programming One key idea that is not widely recognized is this: assembling the template from components and assembling the data that goes into... escaped with the correct character encoding The encoding should match the encoding set in the HTTP header PHPTAL’s default is UTF-8, which is often a good choice However, if you do need to use a different encoding, you can set it with the constant PHPTAL_DEFAULT_ENCODING: define('PHPTAL_DEFAULT_ENCODING', 'ISO-8859-1'); $tpl = new PHPTAL('abc.html'); 322 CHAPTER 1 3 USING TEMPLATES TO MANAGE WEB PRESENTATION... separate stylesheets for media="print" and media="screen", the printfriendly layout will automatically be applied when printing, with no need for an extra link to the print-friendly version Here, we’ll take the slightly more powerful and complex route of controlling part of the layout from PHP by using a different template for printing Creating a printfriendly layout will be a test to make sure our layout . copy of the current node in the input XML file, including child nodes. As mentioned in the comments to listing 13.9, escaping variables from PHP may be necessary mainly to avoid XML syntax. One way to do this is the following: • Replace the PHP processing instructions (< ?php ?>) with something that an XML parser will take to be a plain string. For example, you can replace <?. using an XML parser such as the command line utility called xmllint. It’s part of libxml2, the Gnome XML toolkit. The XML support in PHP 5 is based on libxml2. It’s included in several Linux

Ngày đăng: 12/08/2014, 21:21

Từ khóa liên quan

Mục lục

  • PHP in Action

    • Using templates to manage web presentation

      • 13.3 Transformation: XSLT

      • 13.3.1 “XMLizing” a web page

      • 13.3.2 Setting up XSLT

      • 13.3.3 The XSLT stylesheet

      • 13.3.4 Running XSLT from PHP

      • 13.4 Keeping logic out of templates

      • 13.4.1 View Helper

      • 13.4.2 Alternating row colors

      • 13.4.3 Handling date and time formats

      • 13.4.4 Generating hierarchical displays

      • 13.4.5 Preventing updates from the template

      • 13.5 Templates and security

      • 13.5.1 PHPTAL

      • 13.5.2 Smarty

      • 13.5.3 XSLT

      • 13.6 Summary

      • Constructing complex web pages

        • 14.1 Combining templates (Composite View)

        • 14.1.1 Composite View: one or several design patterns?

        • 14.1.2 Composite data and composite templates

        • 14.2 Implementing a straightforward composite view

Tài liệu cùng người dùng

Tài liệu liên quan