<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section
[
<!ENTITY % xinclude SYSTEM "../../en/xinclude.mod">
%xinclude;
<!-- Add translated specific definitions and snippets -->
<!ENTITY % language-snippets SYSTEM "../standalone/language-snippets.xml">
%language-snippets;
<!-- Fallback to English definitions and snippets (in case of missing translation) -->
<!ENTITY % language-snippets.default SYSTEM "../../en/standalone/language-snippets.xml">
%language-snippets.default;
]>
<section id="themes.view.helpers">
<title>View Helpers</title>
<para>
<emphasis>View helpers</emphasis> are <acronym>PHP</acronym> functions that assist in
generating markup. Some view helpers are required to enable &product.longname; to operate
correctly, and others are provided (or can be created) to assist with repetitive markup
tasks. View helpers are used in <link linkend="themes.view.scripts">view
scripts</link> and <link linkend="themes.layouts">layouts</link>. Place view helpers
in the <filename>helpers</filename> folder, within the theme's folder.
</para>
<para>
For detailed information about view helpers, refer to the
<ulink url="http://framework.zend.com/manual/1.11/en/zend.view.helpers.html">Zend Framework
documentation.</ulink>
</para>
<note>
<title>Class Prefix</title>
<para>
If you are creating a view helper for your theme, the class prefix is
<classname>Theme_Helper_</classname>. For a helper called <methodname>Foo</methodname>,
the full classname would be <classname>Theme_Helper_Foo</classname>.
</para>
</note>
<section id="themes.view.helpers.escape">
<title>Escaping Values for Presentation and Security</title>
<para>
&product.name; provides three view helpers that escape values included in view scripts,
both to ensure that the values do not mess up the presentation, and to prevent
cross-site scripting (<acronym>XSS</acronym>) attacks. <acronym>PHP</acronym> developers
should already be familar with the <command>htmlspecialchars</command> command that
converts selected characters to their equivalent <acronym>HTML</acronym> entities.
&product.name;'s view helpers do a more thorough job of entity conversion, and take into
account the current character encoding.
</para>
<para>
Values that are to be displayed to users should be handled as follows:
</para>
<programlisting language="php">
<?= $this->escape($value); ?>
</programlisting>
<para>
Values that need to be included within <acronym>HTML</acronym> attributes should be
handled as follows:
</para>
<programlisting language="php">
<a href="<?= $this->escapeAttr($url); ?>">A link</a>
</programlisting>
<warning>
<title>URL Validation</title>
<para>
When you use <command>escapeAttr</command> for <acronym>URL</acronym>s, be aware
that only escaping is performed. To fully protect against <acronym>XSS</acronym>
attacks, validation of the URL must also be performed. Please see
<ulink url="https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.235_-_URL_Escape_Before_Inserting_Untrusted_Data_into_HTML_URL_Parameter_Values">The
OWASP XSS (Cross Site Scripting) Prevention Cheat Sheet</ulink> for more details.
</para>
</warning>
<para>
Values that need to be included within <acronym>javascript</acronym> code should be
handled as follows:
</para>
<programlisting language="php">
<script type="text/javascript">var x='<?= $this->escapeJs($data); ?>';</script>
</programlisting>
</section>
<section id="themes.view.helpers.url">
<title>Composing <acronym>URL</acronym>s</title>
<para>
To compose a <acronym>URL</acronym> that points to an asset within the theme's folder,
you can use: <code><?= $this->theme()->getBaseUrl()</code>. Here are a few
examples:
</para>
<programlisting language="php">
<a href="<?= $this->theme()->getBaseUrl() ?>/binary_files/example.document">Download the example</a>
<img src="<?= $this->theme()->getBaseUrl() ?>/images/photo.jpg" alt="a photo">
</programlisting>
<para>
To compose a <acronym>URL</acronym> that points to a &product.name; content entry, you
can use the <emphasis>url</emphasis> view helper. For example, to produce a
<acronym>URL</acronym> that targets the <emphasis>content</emphasis> module's
<emphasis>index</emphasis> controller's <emphasis>view</emphasis> action, with the
parameter <emphasis>id=123</emphasis>, include the following <acronym>PHP</acronym> code
in your view script or layout:
</para>
<programlisting language="php">
<?= $this->url(array(
'module' => 'content',
'controller' => 'index',
'action' => 'view',
'id' => '123'
)) ?>
</programlisting>
<para>
This approach ignores any custom <acronym>URL</acronym> that may have been assigned to
a content entry. The alternative approach, when your view script has a content entry
object available (or fetches a particular one), is to produce its possibly-custom
<acronym>URL</acronym> as follows:
</para>
<programlisting language="php">
<?
$entry = P4Cms_Content::fetch(123);
echo $this->escape($entry->getUri());
?>
</programlisting>
<para>
If the content entry is a binary file, instead of producing a link to the content
entry's web page, you might prefer to make the link download the content:
</para>
<programlisting language="php">
<a href="<?= $this->url(array(
'module' => 'content',
'controller' => 'index',
'action' => 'download',
'id' => '123'
)) ?>">Download item #123</a>
<!-- or from an object, possibly with a custom URL -->
<a href="<? $entry = P4Cms_Content::fetch(123); echo $entry->getUri('download'); ?>">
Download item #123</a>
</programlisting>
<para>
For the display of Image content entries (or that include an image), the code would be:
</para>
<programlisting language="php">
<img src="<?= $this->url(array(
'module' => 'content',
'controller' => 'index',
'action' => 'image',
'id' => '123'
)) ?>/>
<!-- or from an object, possibly with a custom URL -->
<img src="<? $entry = P4Cms_Content::fetch(123); echo $entry->getUri('image'); ?>"/>
</programlisting>
<para>
Additionally, images can be scaled on the server by adding additional parameter when
generating the <acronym>URL</acronym>:
</para>
<programlisting language="php">
<img src="<?= $this->url(array(
'module' => 'content',
'controller' => 'index',
'action' => 'image',
'id' => '123',
'width' => 90,
'height' => 72
)) ?>/>
<!-- or from an object -->
<img src="<? $entry = P4Cms_Content::fetch(123);
echo $entry->getUri('image', array('width' => 90, 'height' => 72)); ?>"/>
</programlisting>
<note>
<title>Image Aspect Ratio, Constraints, and Sharpening</title>
<para>
To preserve an image's <term4gloss>aspect ratio</term4gloss>, you can include just
one of the dimension parameters, either <command>width</command> or
<command>height</command>, and the other dimension is computed.
</para>
<para>
For example, if the original image's size is 5184x3456 pixels, if you specify a
width of 90 pixels, the height of the resized image is 67 pixels. Alternatively, if
you specify a height of 72 pixels, the width of the resized image is 108 pixels.
</para>
<para>
Sometimes, the image you are resizing is extremely wide or tall. For a very wide
image when you only specify the desired height, the danger is that after resizing
the image is much too wide for your layout. Here we want to constrain the image even
further. In this case, you should add the parameter
<command>'maxWidth' => <replaceable>xxx</replaceable></command>
(<replaceable>xxx</replaceable> is the maximum width in pixels). Alternatively, for
a very tall image when you only specify the desired width, you should add the
parameter <command>'maxHeight' => <replaceable>yyy</replaceable></command>
(<replaceable>yyy</replaceable> is the maximum height in pixels).
</para>
<para>
Finally, some large images can look blurry when resized to thumbnail size. In
these cases, you should add the parameter <command>'sharpen' => 1</command>. This
applies a predetermined amount of sharpening to the thumbnail that can reduce the
blurring.
</para>
</note>
</section>
<section id="themes.view.helpers.region">
<title>Managing Regions</title>
<para>
<emphasis>Regions</emphasis> specify rectangular areas on a web page where widgets can
be displayed. Regions can be used in a layout or a view script. Wherever a region's
markup is generated, the widgets configured to appear in that region also have their
markup generated and included in the region's markup. To define a region, include the
following <acronym>PHP</acronym> code in your layout:
</para>
<programlisting language="text">
<?= $this->region('<emphasis>region_name</emphasis>') ?>
</programlisting>
<para>
The <emphasis>region_name</emphasis> is a unique name that you assign to distinguish
between regions. For example, you might have regions named "header," "footer," and
"sidebar," to represent the appropriate areas of the pages you are designing for your
theme.
</para>
<para>
If widgets are configured for a region and you switch your site to use a different theme
that contains a region with the same name, the widgets are displayed. If region names
are unique to the theme, the only widgets initially displayed are default widgets that
have been specified in the second theme's <filename>theme.ini</filename> file.
</para>
</section>
<section id="themes.view.helpers.navigation">
<title>Navigation</title>
<para>
Navigation in &product.name; uses an enhanced implementation of
<classname>Zend_Navigation</classname>. For background information about terminology and
navigation, refer to the
<ulink url="http://framework.zend.com/manual/en/zend.navigation.introduction.html">Zend_Navigation
documentation</ulink>.
</para>
<section id="themes.view.helpers.navigation.breadcrumb">
<title>Rendering A Breadcrumb</title>
<para>
A <emphasis>Breadcrumb</emphasis> is a navigational aid that displays the active
selection within navigation. The following example shows how to activate the display
of the breadcrumb. The code checks whether the "manage-toolbar" navigation exists
and if so: fetches it, expands any dynamic sections and attempts to locate a page
called <command>Manage Content</command>. If that page exists, the page is made
active. Finally, the navigation is rendered as a breadcrumb.
</para>
<programlisting language="php">
<?php
if (P4Cms_Menu::exists('manage-toolbar')) {
$menu = P4Cms_Menu::fetch('manage-toolbar');
$expanded = $menu->getExpandedContainer();
$page = $expanded->findBy('label', 'Manage Content');
if ($page) {
$page->setActive(true);
}
echo $this->breadcrumbs($expanded);
}
?>
</programlisting>
<para>
The following example links the last item in the breadcrumb:
</para>
<programlisting language="php">
<?= $this->breadcrumbs($expanded)->setLinkLast(true) ?>
</programlisting>
<para>
The following example displays an arrow as the separator between breadcrumbs:
</para>
<programlisting language="php">
<?= $this->breadcrumbs($expanded)->setSeparator(' -> ') ?>
</programlisting>
<para>
Options can be combined; for example:
</para>
<programlisting language="php">
<?= $this->breadcrumbs($expanded)->setLinkLast(true)->setSeparator('--') ?>
</programlisting>
<para>
For more information about breadcrumb rendering, see the
<ulink url="http://framework.zend.com/manual/1.11/en/zend.view.helpers.html#zend.view.helpers.initial.navigation.breadcrumbs">Zend
Framework documentation</ulink>.
</para>
</section>
</section>
<section id="themes.view.helpers.contentlist">
<title>Content List</title>
<para>
A list of content in &product.name; can be displayed using the Content List view helper
to query for content and provide information regarding display options. By default, the
view helper shows the title of each content entry, wrapped in a link to the content
page. For example, to show the latest 10 pieces of content sorted so the newest is
first:
</para>
<programlisting language="php">
<?= $this->contentList(
P4Cms_Record_Query::create()
->setMaxRows(10)
->setSortBy(P4Cms_Record_Query::SORT_DATE)
->setReverseOrder(true)
);
>
</programlisting>
<para>
An additional array of options can be passed to the view helper, allowing for more
granular control of the presentation of the content list. This array contains two parts:
a list of fields, with filters and decorators to control their display, and an optional
view script used to render the list. For more information on filters and decorators,
refer to the Zend
<ulink url="http://framework.zend.com/manual/en/zend.form.standardDecorators.html">filter
</ulink> and
<ulink url="http://framework.zend.com/manual/en/zend.filter.set.html">decorator
</ulink> documentation.
This example provides links to the 5 last uploaded files:
</para>
<programlisting language="php">
<?= $this->contentList(
$this->view->query = P4Cms_Record_Query::create()
->setMaxRows($this->getOption('count'))
->setSortBy(P4Cms_Record_Query::SORT_DATE)
->setReverseOrder(true)
->setFilter(P4Cms_Record_Filter::create()->add('contentType', 'file')),
array(
'fields' => array(
'file' => array(
'decorators' => array(
'displayFileLink'
)
)
)
)
);
?>
</programlisting>
<para>
This example uses an optional template to apply custom html. All fields are available
to the template for use, and additional filters or decorators can be applied.
</para>
<programlisting language="php">
<?= $this->contentList(
$this->view->query = P4Cms_Record_Query::create()
->setMaxRows($this->getOption('count'))
->setSortBy(P4Cms_Record_Query::SORT_DATE)
->setReverseOrder(true),
array(
'template' => 'foo.phtml'
)
);
?>
</programlisting>
<para>
The template file:
</para>
<programlisting language="php">
<? foreach ($this->entries as $entry) { ?>
<div class = "myClass"><?= $entry->title ?></div>
<? } ?>
</programlisting>
<para>
Options can be added to the P4Cms_Record_Filter object to allow other modules to
influence the query. So far, only <command>lucene</command> search and
<command>categories</command> are supported.
</para>
<programlisting language="php">
<?= $this->contentList(
$this->view->query = P4Cms_Record_Query::create()
->setMaxRows($this->getOption('count'))
->setSortBy(P4Cms_Record_Query::SORT_DATE)
->setReverseOrder(true)
->setFilter(
P4Cms_Record_Filter::create(
'lucene' => 'search keywords',
'categories' => array('category1', 'category2')
)
)
)
);
?>
</programlisting>
</section>
</section>
<!--
vim:se ts=4 sw=4 et:
-->