1. Trang chủ
  2. » Công Nghệ Thông Tin

PHP in Action phần 7 potx

55 388 0

Đ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

Thông tin cơ bản

Định dạng
Số trang 55
Dung lượng 680,8 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Another way of putting it would be that a lot of different programming languages andenvironments, including PHP, have tools available for parsing and generating XML.Therefore, XML can be

Trang 1

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 HTMLediting tools generally ignore unknown attributes, and PHPTAL lets you insert dummycontent 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 aPHPTAL 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 disappearswhen 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"

Figure 13.4 PHPTAL template viewed in web browser

Listing 13.5 PHPTAL template for user list

b

Trang 2

<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

Trang 3

example content that makes the template easier to understand and to view in a WYG editor.

WYSI-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 iswhat 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 inthe template—the one that contains tal:repeat—generates all the table rows inthe output The dummy row is only there for the sake of the template: it makes thetemplate resemble the web page that’s generated when the application is run We canadd any number of such dummy rows if we want They will all disappear when thetemplate 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 withdynamic content tal:replace removes what’s between the tags and the tags

we just echo the results of template processing

One of the advantages of PHPTAL is that the templates are XML and can be cessed using other XML-based tools This is even more applicable to the next item onour agenda: XSLT

pro-Listing 13.6 Processing the PHPTAL template

Trang 4

13.3 T RANSFORMATION : XSLT

XSLT stylesheets are another popular way of expressing the HTML tag content of aweb 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 useXSLT as templates in a PHP application, we first generate XML code, transform thatusing XSLT, and output it to the browser Figure 13.5 shows how XSLT works whengenerating web pages The stylesheet can be similar to the templates we’ve seenbefore, 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 Butit’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 andenvironments, 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 implementingview logic that the temptation may be hard to resist

Figure 13.5 XSLT works by transforming an XML data file using an XSL stylesheet.

Trang 5

13.3.1 “XMLizing” a web page

When you want to produce an XSLT stylesheet from an existing PHP file or from asample HTML file, the first thing to do is to create something that’s valid XML Oneway to do this is the following:

• Replace the PHP processing instructions (<?php ?>) with somethingthat 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 intoXHTML 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 torun it would be as follows:

tidy -indent -asxml -wrap 150 userlist.xhtml

-indent produces indented output -asxml specifies that the output should beXML -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 thatrequire you to change the file manually For instance, browsers are usually willing torender 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 commandline utility called xmllint It’s part of libxml2, the Gnome XML toolkit The XMLsupport in PHP 5 is based on libxml2 It’s included in several Linux distributionsand is also available for Windows

The command-line XSLT tool for libxml2 is called xsltproc You can run it as follows:

$ xsltproc userlist.xsl userlist.xml

Trang 6

You can generate the XML test file or write it manually It’s typically a very simplerepresentation of the data from the database Listing 13.7 shows how the user listmay be represented.

Listing 13.7 XML file for testing XSLT template processing

Listing 13.8 XSLT stylesheet for the user list

b

Trang 7

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 anXPath 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 Inthis 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 thiscontext 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 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

rea-g

Trang 8

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

Trang 9

$xsldom = new domDocument();

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 adata structure

Again, we are escaping all the data This is to be processed through XSLT, and XSLTwill usually ignore HTML tags, so the risk of cross-site scripting attacks is less It’s morelikely 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 ofthe 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 astring, since we have the XML code as a string and the XSLT stylesheet in a file That’snatural 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 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 templatesgoes a long way toward achieving separation between HTML and PHP code Butthere is still the risk that we will start undermining the separation by adding toomuch programming logic to the template itself, either by using the template engine’sbuilt-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 nextsection, we’ll study some tricks that will help us resist that temptation in particularlydifficult cases

Most web application pages have a relatively simple structure, such as a form or a ple list A loop and perhaps a few simple conditionals will suffice as logic for the

sim-g h

Trang 10

presentation That’s no big problem in a template, since this minimal logic doesn’tobscure the HTML layout of the page much.

But there are a few challenges that are harder to manage without putting more logicinto 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 pagebut 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 thiswith 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 alsopossible with the JavaScript DOM.)

Unless the template engine has a special feature that will help us with it, we needsomething like an if test embedded in a loop That makes the logic in the templatemore complex and harder to read and manage

Template designers can live with looping and simple conditionals But when youstart to get nested loops and complex conditionals, they find it at best annoyingbecause it gets in the way of their work At worst, it’s confusing to designers and opensthe 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 handlinglogic that is part of the Presentation layer but is too complex to fit comfortably in atemplate Then we’ll look at a series of real-life situations that challenge our ability tokeep 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 classesoutside the template (see figure 13.6) We can keep them in separate classes that onlyhandle 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 asthe depth of an item in a hierarchical display or CSS classes to allow alternating rowcolors 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

Trang 11

convert or translate the information in domain and data objects into a form that can

be used in a template

This approach makes it possible to use a very simple template language In fact, youcould probably make your own with little effort Simple variable substitution, condi-tionals, and loops should be sufficient

13.4.2 Alternating row colors

Alternating colors in the rows of a table is a popular way to make it easier to distinguishthe rows in the browser You might think this needs to be implemented with program-ming logic in the template because a designer might need to change it The colorsmight change, or the designer might decide not to have alternating colors after all.Some template engines have facilities that make this easier For example, Smartyhas a function called cycle that lets you alternate automatically between a set of val-ues The alternative, which will work with any template engine, is to do the alternationlogic in PHP before passing the values to the template

We definitely want to avoid having explicit color names or codes in the PHP gram 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 Thenthe colors can be defined in CSS, and the only thing that’s left for PHP is the abstractalternation logic The HTML code would look like this example:

13.4.3 Handling date and time formats

Date and time formats are another challenge when we try to separate the mer’s job from the web designer’s The choice of format is purely a presentation issue;

Trang 12

program-there is no reason why it should depend on technical considerations But, as withalternating colors, it has no native syntax in HTML and/or CSS So ideally, we shouldprovide the web designer with a way to specify the format inside the template (There

is an exception to this: if we know there is only one date format we ever want to use,

we can just generate it in the PHP code.)

One way to do this is to use a modifier Smarty has a built-in variable modifiercalled date_format that allows a designer to specify a date format using strf-time() syntax:

{$smarty.now|date_format:"%H:%M:%S"}

But it would be less cryptic and probably more practical if the date format had aname A web site will probably be using only a few different date formats that areused repeatedly on different web pages So having two or three named date formatswould make them easier to remember and make it possible to change a date formatglobally For example, we might have a standard date and time format, one format forjust the time, and a short format for cramped spaces on the page

If the template engine has the ability to define custom modifiers, you could use that

to define named date formats But a solution which is more general—more dent of which template engine you’re using—is to give the template a PHP object whichhas a method to generate the appropriate date format For some reason, objects that rep-resent date and time have not been common in PHP, but they’re useful for this kind oftask Listing 13.10 shows a simplified class resembling the examples in chapter 8

b The DateAndTime object is constructed from a specified timestamp If no timestamp

is specified, the object represents the current time when it was created

c The isoformat() and rfcformat() methods return the formatted date and time

as a string

Listing 13.10 A simplified date and time class

c

Trang 13

So we could use the object like this:

$now = new DateAndTime;

echo $now->isoformat()."\n";

This is interesting, but the real practical value starts to appear when we use the AndTime object to replace other ways of representing the date and time.Listing 13.11 shows a class representing a DiscussionMessage object that contains theknowledge of when it was created

function isotime() { return $this->created->isoformat(); }

function rfctime() { return $this->created->rfcformat(); }

function getSubject() { return $this->subject; }

function getText() { return $this->text; }

function getCreated() { return $this->created; }

}

b To make sure we construct the object correctly, let’s use a type hint to require that the

$created argument is already a DateAndTime object Using a type hint is larly appropriate in this case It’s easy to make a mistake and use an integer time-stamp, and the mistake won’t become apparent during construction

particu-C The isotime() and rfctime() methods just call the corresponding methods inthe DateAndTime objects They are not strictly needed if we have a convenient way

to call a method on the DateAndTime object itself Since we’re using it in a template,that depends on the template engine

The DiscussionMessage class can be used like this in PHP 5 code:

$message = new DiscussionMessage(

Trang 14

Since a template engine won’t necessarily let us do the equivalent of that last line, it’sconvenient to be able to do this instead:

13.4.4 Generating hierarchical displays

Threaded discussion forums—such as the one in figure 13.7—are good examples ofhierarchical data to display on a web page

An object-oriented tree structure is useful for processing this type of data But howcan we insert it into a template? The problem is that we don’t know how many levels

of replies we need to handle So even a very complex (and not very readable) set ofnested loops is inadequate for the task

Figure 13.7 A threaded discussion view

Trang 15

Recursion is the normal way to process tree

structures So one possibility is to give the

tem-plate engine the ability to do recursion This

will still not be very readable, nor will it be easy

to test Another way to do it is to simplify the

data structure by first transforming it into a

simple two-dimensional array or an array of

objects To show the threaded list using HTML,

we need to insert it into rows and columns

any-way Figure 13.8 depicts 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 separationbetween presentation and domain logic while keeping the template from containingmuch more than the usual presentation logic The class in listing 13.12 does the job

of generating this plainer data structure The most crucial part of the job is done bythe getList() method, which operates on a discussion node, getting a sequentiallist of descendant nodes by recursion getList() is what is known as a foreignmethod It does something the node object might have done itself The reason we don’tlet the node object do it is because we want to keep the presentation logic out of thediscussion node

Listing 13.12 shows the DiscussionView class The list it generates is an array ofarrays; so it’s not an object-oriented structure at all, but it’s a structure that’s simple touse in a template (You can use a simplified object-oriented structure instead if yourtemplate engine supports this.)

is easier to display

Listing 13.12 The DiscussionView class transforms a hierarchical threaded

dis-cussion into a linear data structure

Trang 16

get-C To get the data from the database, we use a Data Mapper called DiscussionMapper.Although we haven’t introduced Data Mappers yet, to understand this example, youjust need to know that it’s a class that can be used for getting data from the database.

D The mapper’s find() method takes the discussion ID and retrieves the discussionfrom the database The discussion is an object-oriented tree structure composed ofdiscussion nodes

E Now we call the method that converts the Composite structure into a simple list inthe form of an array

F We remove the first element of the list It’s the root node representing the entire cussion, and we don’t want that to show up on the web page We just want the indi-vidual threads, which are the children of the root node

dis-G The getList() method returns the contents of the discussion as an array in theorder the posts will be listed on the web page This is where the recursion happens

H We have a $depth variable to keep track of the current level in the hierarchy Whenthe method is called initially (on the root node), $depth is set to -1 and thenincremented So the root node’s depth is 0 Then, when we call the method on the

1)

1!

Trang 17

children of the root node, we pass $depth on and it gets incremented to 1 And so itkeeps increasing as we move recursively to deeper levels.

An inelegant but relatively flexible way to use this is to generate separate CSS classes for each level (level1, level2, and so on) Assuming a limited number of levels, they can

be separately styled in this manner:

table#AdminList tr.level2 td.threaded { padding-left: 2em; }

table#AdminList tr.level3 td.threaded { padding-left: 4em; }

table#AdminList tr.level4 td.threaded { padding-left: 6em; }

table#AdminList tr.level5 td.threaded { padding-left: 8em; }

I $array is an associative array representing a single node The asArray() methodconverts the node from an object, potentially with children, to a plain associative array

J $result is the list that will contain this node and all its descendants We build thelist starting with the current node

1) Each child generates a list of nodes, and we append the list to the result list

1! Since a plain array is relatively easy to use with any template engine, generating anarray from an object, as we’re doing here, may be reasonable However, if we can, itmight be better to use the object directly or via a decorator An object-oriented datastructure is more flexible and easier to modify

13.4.5 Preventing updates from the template

If we represent our data as objects, it’s convenient to be able to pass the object to thetemplate and use methods inside the template to display the data inside it But what

if this allows a template designer to modify the object and perhaps even store it in thedatabase? Now we have the same kind of security problem as with template languagesthat allow PHP code, although perhaps to a lesser degree In principle, a templateshould not be allowed to change anything It should only have access to read-onlydata, or to its own copies that are not used anywhere else

This is a case where the PHP 5 object model may be a hindrance rather than a help

In PHP 4, objects were copied by default, so a template would always get its own copies

of the objects So even if a template designer were to modify the object, it would notaffect anything outside the processing of the template

We can solve that problem by explicitly cloning the objects This can be built into

a template engine by decorating it or extending it with a subclass (I would normallyprefer a decorator to reduce the dependency on the template engine API, but we’reusing inheritance here to illustrate the possibility.)

class Template extends PHPTAL {

public function set($name,$data) {

if (is_object($data)) $data = clone $data;

parent::set($name,$data);

}

}

Trang 18

But there is another, potentially worse problem: The object may have methods thataffect the outside world In particular, it might have methods to insert, update, ordelete itself in the database A clone would have the same power to do that as theoriginal object.

There are several ways we might handle this problem We might

• Use Data Mappers Data Mappers are specialized objects that handle databaseinteraction So a User object would not be able to insert itself into the database.Instead, we would have to use a UserMapper And there would be no way to gethold of the UserMapper from the template unless it was PHP-enabled

• Use a template engine-specific way to restrict access to methods Smarty allows you

to specify a list of allowed methods in Smarty’s register_object() method

• Decorate the object or copy it to a specialized View object containing the samedata but having fewer capabilities

Security considerations have been mentioned along the way in this chapter, but in thenext section, we’ll summarize and complete them

The most important issue is the danger of cross-site scripting (XSS) attacks (For anintroduction to this and other security-related concepts, see appendix B.) To preventthis, we need to escape all output The template engines described in this chapter arevery different in how they escape output Preferably, we want the template engine toescape output by default In other words, output escaping should be the easiestoption for the programmer and/or designer Template engines support this to differ-ent degrees and in different ways In this section, we’ll take a closer look at how itworks in PHPTAL, Smarty, and XSLT

13.5.1 PHPTAL

PHPTAL escapes all output variables by default This is excellent for security Butusing the structure keyword disables escaping for a variable:

<p tal:content="structure introduction">dummy intro</p>

Obviously, we should be careful when using structure If the variable containsdata that may come from the user, there is a risk In addition, you should make sureoutput is escaped with the correct character encoding The encoding should matchthe encoding set in the HTTP header PHPTAL’s default is UTF-8, which is often agood choice However, if you do need to use a different encoding, you can set it withthe constant PHPTAL_DEFAULT_ENCODING:

define('PHPTAL_DEFAULT_ENCODING', 'ISO-8859-1');

$tpl = new PHPTAL('abc.html');

Trang 19

Although this is probably less relevant, it’s also possible to set the encoding for a gle template:

This can be achieved by using the $default_modifiers variable:

There is one exception: xsl:copy-of makes a deep copy of the current node inthe 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 errors The file to be transformed has to bevalid XML or the XML parser will complain If it contains arbitrary text, there is a highrisk that the text will contain some characters that will make it invalid

One of the central dogmas of modern web programming is the need to separateHTML markup from program code Although many believe this can be done effec-tively with plain PHP, others find it more appropriate to use a template engine All thetemplate engines meet roughly the same challenges, but they do so in syntacticallydifferent ways Some, such as Smarty, use a custom syntax exclusively XSLT, althoughnot strictly a template engine, is a specialized programming language that transforms

Trang 20

an XML file containing the data to be displayed, adding markup to it PHPTAL usesXML attributes to specify dynamic content.

A powerful template engine typically has the ability to execute PHP code or otherpotentially advanced constructs This makes it all too easy to slip back into an exces-sively strong mixture of markup and program code Fortunately, there are additionaltechniques for handling the challenges—such as alternating row colors and date andtime formatting—that tend to lead you into that particular swamp

Templates pose particular challenges to security To guard against attacks, we need

to make sure we escape all output This is always possible, though easier with sometemplate engines than with others

Web presentation becomes even more demanding when the web page is composed

of many interacting components In the next chapter, we will look into what is oftencalled the Composite View pattern We will see how to gain layout and content flex-ibility both for the whole web page and its parts and how to integrate existing appli-cations into a Composite View

Trang 21

C H A P T E R 1 4

Constructing complex

web pages

14.1 Combining templates (Composite View) 325

14.2 Implementing a straightforward composite view 326

14.3 Composite View examples 332

14.4 Summary 337

A complex web page is like a zoo There may be all sorts of different creatures, allwith different habits and requiring different care, cleaning, and feeding Some ofthem are in cages (typically the stuff that surrounds the main content, such as ban-ners, ads, menus, and various kinds of sidebars); some of them range freely on themain expanse of the page

Keeping all these coordinated is one of the great challenges of web programming

In addition, different species play together A menu may need to communicatewith a news list as well as with itself Making this work properly is actually a challengethat goes beyond the scope of this chapter, since that challenge involves user interac-tion Here, we will focus mostly on the display or View part of the job

In this chapter, we’ll first introduce and discuss the Composite View pattern Thenwe’ll show how to implement a simple, straightforward composite template usingSmarty or PHPTAL Finally, we’ll see how to solve a few more advanced challenges

Modern web pages are not just complex; they tend to grow increasingly complex But

we have some tools to help us

Trang 22

Assembling a page is not really difficult with PHP include files You just use oneinclude file for each part of the page, and one file that includes all of them Most tem-plates have include capabilities as well There is no magic or rocket science involved.But careful thinking is needed to develop a structured approach that gets you the nec-essary flexibility and avoids inelegant hacks even when solving problems such as sep-arate print-friendly views of a page That’s what we’ll develop in this chapter.

14.1.1 Composite View: one or several design patterns?

The book Core J2EE Patterns (and its companion online pattern catalog) [Alur et al.]

has Composite View listed as a design pattern and demonstrates several differentstrategies for implementing it The Composite View itself is the idea of assembling aweb page from pluggable, reusable components The solutions to this problem arepresented as different strategies that are actually completely different solutions to thesame problem This may be confusing if you’re used to design patterns that give a rea-sonably specific solution to a problem

That need not trouble us too much, though The challenge is to achieve 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 keyidea that is not widely recognized is this: assembling the template from componentsand assembling the data that goes into it (parts of the Model in Model-View-Con-troller terms) are two separate challenges You can have a monolithic class that doesthe whole job of creating the data for the template even if the template itself is assem-bled from several pieces And you can have a complex composite or collection of PHPcomponents that assemble and insert the data into a template, even if the template is

a single sheet of HTML with slots for dynamic information

The following sections will focus mostly on creating the composite template We’llfirst see how to do it in a typical, straightforward case

To design a strategy for assembling web pages, we need to know the requirements.How much and what flexibility do we need? The solution featured in the J2EE book[Alur et al.] is based on the idea of pluggable components and pluggable layout, anduses custom tags to achieve it

In this section, we’ll first define more specifically what we need to do Then we’llsee how it can be implemented with two template engines; first Smarty, then PHPTAL.We’ll also look at an additional, PHPTAL-specific way of doing it

Trang 23

14.2.1 What we need to achieve

To get an idea of what it takes to implement a Composite View, let’s do a simple ple in plain PHP, starting with the simplest-possible implementation Figure 14.1shows the kind of layout we want

exam-We have four different components here: the banner, the menu, the main text, andthe sidebar containing the news list To implement this in “naive” PHP, we use plaininclude statements:

We should be able to replace the overall layout of the page with a different one Againstaying within plain, blunt PHP, all we need to do is make a separate file out of thepreceding code and include that from our main script:

Figure 14.1 Composite View-type page layout with several different components

Trang 24

// Find out which $layout to use

//

include "$layout.php";

Wait a minute, you might say There’s no layout at all in the layout file! No HTMLtags Yes—and no The only layout that’s present is the presence and sequence of thecomponents We will assume that the rest is in CSS Each of the included files will be

an HTML<div> element with contents such as this:

<div id="banner">

<img src="hazycrazy2.png" width="519"/>

</div>

Each of these <div>s, and individual elements

within them, can be styled, positioned, even

hid-den, using CSS In fact, since CSS can be used

for positioning and hiding, you might even

question whether there is a need for the layout

file at all With CSS, you can position <div>s

accurately and (somewhat) freely regardless of

their sequence in the HTML markup And you

can hide them using display:none But the

hidden elements will still be present in the web page that is downloaded to thebrowser So they will still consume bandwidth, potentially making response timeslonger for the user

Figure 14.2 shows how we’ve named the parts of the page

14.2.2 Using Smarty

In our Composite View implementation, we want something that satisfies therequirements and leverages the tools we have available to make the solution as simple,easy, and maintainable as possible We can use Smarty to do something similar towhat we did with plain PHP in the previous section:

Trang 25

b Using $current this way is not as dangerous as using it in a PHP include Still, ifthe variable can be altered by a user, there is a potential for retrieving a file from any-where in the file system.

There is one more thing we might like to do We need to handle the title of theHTML document as well Frequently, the main content area has a heading, for example:

be updated and not the other Having them both in one file would be better.What we can do is use Smarty’s capture feature to define a template section as

a variable that can be used somewhere else We would define the title and tent sections in the same file as follows:

Figure 14.3 We want the same text for the title and the main heading,

even though they are in separate parts of the page.

Trang 26

<link rel="STYLESHEET" href="hazycrazy.css"

In PHPTAL, we also need to use macros in place of the plain includes This is a goodthing, since we can choose to have several macros per file, or just one

Using one file for the pluggable content and one for the other macros, our maintemplate file looks like this:

Trang 27

Unlike many attributes used in PHPTAL (such as tal:content), macro accepts a string by default, not a variable So to access the file name in thecontent variable, we have to use ${content}.

metal:use-14.2.4 Using page macros with PHPTAL

The PHPTAL solution shown in the previous example is the one that follows the samestrategy we used for Smarty This strategy is useful since it’s generally applicable tomost, if not all, template engines In addition, PHPTAL allows us to be even more flex-ible by using what is known as a page macro The web page as a whole can be defined

as a macro, making it possible to handle the parts and the whole in one uniform ion

fash-Listing 14.1 is a page macro example Note first that this is not a template; it’s a

macro that defines what’s common between many pages If we forget that it’s a macroand try to use it as a template, we get no output

The general idea is that the page macro contains all of these elements:

• Static parts of the page such as the menu

• “Slots” that can be filled by the template that uses the macro

• Default content for the slots if the macro doesn’t fill them

No default content d

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

TỪ KHÓA LIÊN QUAN