Location: PHPKode > projects > Pronto > jvinet-pronto-25f287e/doc/manual.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="generator" content="AsciiDoc 8.5.1" />
<title>PRONTO WEB FRAMEWORK</title>
<style type="text/css">
/* Debug borders */
p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
/*
  border: 1px solid red;
*/
}

body {
  margin: 1em 5% 1em 5%;
}

a {
  color: blue;
  text-decoration: underline;
}
a:visited {
  color: fuchsia;
}

em {
  font-style: italic;
  color: navy;
}

strong {
  font-weight: bold;
  color: #083194;
}

tt {
  color: navy;
}

h1, h2, h3, h4, h5, h6 {
  color: #527bbd;
  font-family: sans-serif;
  margin-top: 1.2em;
  margin-bottom: 0.5em;
  line-height: 1.3;
}

h1, h2, h3 {
  border-bottom: 2px solid silver;
}
h2 {
  padding-top: 0.5em;
}
h3 {
  float: left;
}
h3 + * {
  clear: left;
}

div.sectionbody {
  font-family: serif;
  margin-left: 0;
}

hr {
  border: 1px solid silver;
}

p {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

ul, ol, li > p {
  margin-top: 0;
}

pre {
  padding: 0;
  margin: 0;
}

span#author {
  color: #527bbd;
  font-family: sans-serif;
  font-weight: bold;
  font-size: 1.1em;
}
span#email {
}
span#revnumber, span#revdate, span#revremark {
  font-family: sans-serif;
}

div#footer {
  font-family: sans-serif;
  font-size: small;
  border-top: 2px solid silver;
  padding-top: 0.5em;
  margin-top: 4.0em;
}
div#footer-text {
  float: left;
  padding-bottom: 0.5em;
}
div#footer-badges {
  float: right;
  padding-bottom: 0.5em;
}

div#preamble {
  margin-top: 1.5em;
  margin-bottom: 1.5em;
}
div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
div.admonitionblock {
  margin-top: 0.25em;
  margin-bottom: 1.5em;
}
div.admonitionblock {
  margin-top: 2.5em;
  margin-bottom: 2.5em;
}

div.content { /* Block element content. */
  padding: 0;
}

/* Block element titles. */
div.title, caption.title {
  color: #527bbd;
  font-family: sans-serif;
  font-weight: bold;
  text-align: left;
  margin-top: 1.0em;
  margin-bottom: 0.5em;
}
div.title + * {
  margin-top: 0;
}

td div.title:first-child {
  margin-top: 0.0em;
}
div.content div.title:first-child {
  margin-top: 0.0em;
}
div.content + div.title {
  margin-top: 0.0em;
}

div.sidebarblock > div.content {
  background: #ffffee;
  border: 1px solid silver;
  padding: 0.5em;
}

div.listingblock > div.content {
  border: 1px solid silver;
  background: #f4f4f4;
  padding: 0.5em;
}

div.quoteblock {
  padding-left: 2.0em;
  margin-right: 10%;
}
div.quoteblock > div.attribution {
  padding-top: 0.5em;
  text-align: right;
}

div.verseblock {
  padding-left: 2.0em;
  margin-right: 10%;
}
div.verseblock > div.content {
  white-space: pre;
}
div.verseblock > div.attribution {
  padding-top: 0.75em;
  text-align: left;
}
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
div.verseblock + div.attribution {
  text-align: left;
}

div.admonitionblock .icon {
  vertical-align: top;
  font-size: 1.1em;
  font-weight: bold;
  text-decoration: underline;
  color: #527bbd;
  padding-right: 0.5em;
}
div.admonitionblock td.content {
  padding-left: 0.5em;
  border-left: 2px solid silver;
}

div.exampleblock > div.content {
  border-left: 2px solid silver;
  padding: 0.5em;
}

div.imageblock div.content { padding-left: 0; }
span.image img { border-style: none; }
a.image:visited { color: white; }

dl {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
dt {
  margin-top: 0.5em;
  margin-bottom: 0;
  font-style: normal;
  color: navy;
}
dd > *:first-child {
  margin-top: 0.1em;
}

ul, ol {
    list-style-position: outside;
}
ol.arabic {
  list-style-type: decimal;
}
ol.loweralpha {
  list-style-type: lower-alpha;
}
ol.upperalpha {
  list-style-type: upper-alpha;
}
ol.lowerroman {
  list-style-type: lower-roman;
}
ol.upperroman {
  list-style-type: upper-roman;
}

div.compact ul, div.compact ol,
div.compact p, div.compact p,
div.compact div, div.compact div {
  margin-top: 0.1em;
  margin-bottom: 0.1em;
}

div.tableblock > table {
  border: 3px solid #527bbd;
}
thead {
  font-family: sans-serif;
  font-weight: bold;
}
tfoot {
  font-weight: bold;
}
td > div.verse {
  white-space: pre;
}
p.table {
  margin-top: 0;
}
/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
  border-style: none;
}
div.tableblock > table[frame="hsides"] {
  border-left-style: none;
  border-right-style: none;
}
div.tableblock > table[frame="vsides"] {
  border-top-style: none;
  border-bottom-style: none;
}


div.hdlist {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
div.hdlist tr {
  padding-bottom: 15px;
}
dt.hdlist1.strong, td.hdlist1.strong {
  font-weight: bold;
}
td.hdlist1 {
  vertical-align: top;
  font-style: normal;
  padding-right: 0.8em;
  color: navy;
}
td.hdlist2 {
  vertical-align: top;
}
div.hdlist.compact tr {
  margin: 0;
  padding-bottom: 0;
}

.comment {
  background: yellow;
}

.footnote, .footnoteref {
  font-size: 0.8em;
}

span.footnote, span.footnoteref {
  vertical-align: super;
}

#footnotes {
  margin: 20px 0 20px 0;
  padding: 7px 0 0 0;
}

#footnotes div.footnote {
  margin: 0 0 5px 0;
}

#footnotes hr {
  border: none;
  border-top: 1px solid silver;
  height: 1px;
  text-align: left;
  margin-left: 0;
  width: 20%;
  min-width: 100px;
}


@media print {
  div#footer-badges { display: none; }
}

div#toctitle {
  color: #527bbd;
  font-family: sans-serif;
  font-size: 1.1em;
  font-weight: bold;
  margin-top: 1.0em;
  margin-bottom: 0.1em;
}

div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
  margin-top: 0;
  margin-bottom: 0;
}
div.toclevel2 {
  margin-left: 2em;
  font-size: 0.9em;
}
div.toclevel3 {
  margin-left: 4em;
  font-size: 0.9em;
}
div.toclevel4 {
  margin-left: 6em;
  font-size: 0.9em;
}
/* Workarounds for IE6's broken and incomplete CSS2. */

div.sidebar-content {
  background: #ffffee;
  border: 1px solid silver;
  padding: 0.5em;
}
div.sidebar-title, div.image-title {
  color: #527bbd;
  font-family: sans-serif;
  font-weight: bold;
  margin-top: 0.0em;
  margin-bottom: 0.5em;
}

div.listingblock div.content {
  border: 1px solid silver;
  background: #f4f4f4;
  padding: 0.5em;
}

div.quoteblock-attribution {
  padding-top: 0.5em;
  text-align: right;
}

div.verseblock-content {
  white-space: pre;
}
div.verseblock-attribution {
  padding-top: 0.75em;
  text-align: left;
}

div.exampleblock-content {
  border-left: 2px solid silver;
  padding-left: 0.5em;
}

/* IE6 sets dynamically generated links as visited. */
div#toc a:visited { color: blue; }
</style>
<script type="text/javascript">
/*<![CDATA[*/
window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
var asciidoc = {  // Namespace.

/////////////////////////////////////////////////////////////////////
// Table Of Contents generator
/////////////////////////////////////////////////////////////////////

/* Author: Mihai Bazon, September 2002
 * http://students.infoiasi.ro/~mishoo
 *
 * Table Of Content generator
 * Version: 0.4
 *
 * Feel free to use this script under the terms of the GNU General Public
 * License, as long as you do not remove or alter this notice.
 */

 /* modified by Troy D. Hanson, September 2006. License: GPL */
 /* modified by Stuart Rackham, 2006, 2009. License: GPL */

// toclevels = 1..4.
toc: function (toclevels) {

  function getText(el) {
    var text = "";
    for (var i = el.firstChild; i != null; i = i.nextSibling) {
      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
        text += i.data;
      else if (i.firstChild != null)
        text += getText(i);
    }
    return text;
  }

  function TocEntry(el, text, toclevel) {
    this.element = el;
    this.text = text;
    this.toclevel = toclevel;
  }

  function tocEntries(el, toclevels) {
    var result = new Array;
    var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
    // Function that scans the DOM tree for header elements (the DOM2
    // nodeIterator API would be a better technique but not supported by all
    // browsers).
    var iterate = function (el) {
      for (var i = el.firstChild; i != null; i = i.nextSibling) {
        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
          var mo = re.exec(i.tagName);
          if (mo)
            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
          iterate(i);
        }
      }
    }
    iterate(el);
    return result;
  }

  var toc = document.getElementById("toc");
  var entries = tocEntries(document.getElementById("content"), toclevels);
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    if (entry.element.id == "")
      entry.element.id = "_toc_" + i;
    var a = document.createElement("a");
    a.href = "#" + entry.element.id;
    a.appendChild(document.createTextNode(entry.text));
    var div = document.createElement("div");
    div.appendChild(a);
    div.className = "toclevel" + entry.toclevel;
    toc.appendChild(div);
  }
  if (entries.length == 0)
    toc.parentNode.removeChild(toc);
},


/////////////////////////////////////////////////////////////////////
// Footnotes generator
/////////////////////////////////////////////////////////////////////

/* Based on footnote generation code from:
 * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
 */

footnotes: function () {
  var cont = document.getElementById("content");
  var noteholder = document.getElementById("footnotes");
  var spans = cont.getElementsByTagName("span");
  var refs = {};
  var n = 0;
  for (i=0; i<spans.length; i++) {
    if (spans[i].className == "footnote") {
      n++;
      // Use [\s\S] in place of . so multi-line matches work.
      // Because JavaScript has no s (dotall) regex flag.
      note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
      noteholder.innerHTML +=
        "<div class='footnote' id='_footnote_" + n + "'>" +
        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
        n + "</a>. " + note + "</div>";
      spans[i].innerHTML =
        "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
        "' title='View footnote' class='footnote'>" + n + "</a>]";
      var id =spans[i].getAttribute("id");
      if (id != null) refs["#"+id] = n;
    }
  }
  if (n == 0)
    noteholder.parentNode.removeChild(noteholder);
  else {
    // Process footnoterefs.
    for (i=0; i<spans.length; i++) {
      if (spans[i].className == "footnoteref") {
        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
        href = href.match(/#.*/)[0];  // Because IE return full URL.
        n = refs[href];
        spans[i].innerHTML =
          "[<a href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
      }
    }
  }
}

}
/*]]>*/
</script>
</head>
<body>
<div id="header">
<h1>PRONTO WEB FRAMEWORK</h1>
<span id="author">Judd Vinet</span><br />
<span id="email"><tt>&lt;<a href="mailto:hide@address.com">hide@address.com</a>&gt;</tt></span><br />
<span id="revnumber">version 0.6,</span>
<span id="revdate">January 2010</span>
<div id="toc">
  <div id="toctitle">Table of Contents</div>
  <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
</div>
</div>
<h2 id="X0">1. Quick Start</h2>
<div class="sectionbody">
<div class="paragraph"><p>Most of this manual will be long and boring, so for those of you who
already know everything about everything, here are the barebones steps
necessary to get Pronto up and running.</p></div>
<div class="paragraph"><p>We&#8217;ll assume you&#8217;re using MySQL and Apache.  Also, make sure AllowOverrides
is enabled for your Pronto directory, so Apache will honor the .htaccess
files within.</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Untar the Pronto archive into your web root or a subdirectory thereof.
   We&#8217;ll assume <tt>/var/www/html/pronto</tt>.
</p>
</li>
<li>
<p>
Edit <tt>app/config/config.php</tt> and change the <tt>DIR_*_BASE</tt> constants to
   match the location of your Pronto installation.
</p>
</li>
<li>
<p>
Create a database for Pronto, then edit <tt>app/config/databases.php</tt> and
   change the settings to match the access credentials for your new Pronto
   database.
</p>
</li>
<li>
<p>
Create the necessary tables from the schema files in <tt>app/config/sql</tt>.
   You can use the <tt>load_schemas.php</tt> script for this.
</p>
</li>
<li>
<p>
Point your browser to the Pronto directory, eg,
   <tt>http://localhost/pronto/</tt>.
</p>
</li>
</ol></div>
<div class="paragraph"><p>That&#8217;s it!  You should see a Pronto web page staring you in the face.</p></div>
<div class="listingblock">
<div class="title">Setting up Pronto</div>
<div class="content">
<pre><tt>$ cd /var/www/html
$ tar zxf ~/pronto.tar.gz
$ cd pronto/app
$ vi config/config.php
$ vi config/databases.php
$ mysqladmin -u root create pronto
$ php ../pronto/bin/load_schemas.php -a
$ firefox http://localhost/pronto/</tt></pre>
</div></div>
</div>
<h2 id="X1">2. Philosophy</h2>
<div class="sectionbody">
<div class="paragraph"><p>Like most web frameworks, Pronto is designed to ease the development of
web applications by eliminating redundant code and promoting a logical
separation of application logic, business logic, and presentation.</p></div>
<div class="paragraph"><p>Pronto strives to maintain a loosely-coupled set of components that,
when combined, form a a powerful web development stack.  The reasoning
behind our "loosely-coupled" mandate is that this encourages Pronto
to <em>assist</em> the developer, not take over for her.  If a developer prefers
to forgo some of the facilities provided by Pronto, it should be
relatively easy for her to do so, without having to step out of the
framework entirely.</p></div>
<div class="paragraph"><p>Keep this in mind as you learn the framework.  It&#8217;s entirely probable
that, as you delve into it, you will find aspects that you will never use.
Just ignore them and carry on with your business.  They are present
because they are useful to some developers.</p></div>
</div>
<h2 id="X2">3. Components</h2>
<div class="sectionbody">
<div class="paragraph"><p>There are four core elements to Pronto.</p></div>
<div class="ulist"><div class="title">Core Elements:</div><ul>
<li>
<p>
Dispatcher
</p>
</li>
<li>
<p>
Page Controller (or simply "controller")
</p>
</li>
<li>
<p>
Model
</p>
</li>
<li>
<p>
Template
</p>
</li>
</ul></div>
<div class="paragraph"><p>Pronto also has plugin support for some layers.</p></div>
<div class="ulist"><div class="title">Plugins:</div><ul>
<li>
<p>
Controller Plugins (aka "plugins")
</p>
</li>
<li>
<p>
Template Plugins (aka "helpers")
</p>
</li>
</ul></div>
<div class="paragraph"><p>Underneath the four high-level components, there are additional elements
that support the framework.</p></div>
<div class="ulist"><div class="title">Utility Elements:</div><ul>
<li>
<p>
Database Abstraction (with protection for SQL injection attacks)
</p>
</li>
<li>
<p>
Data Sanitization (protection for XSS attacks)
</p>
</li>
<li>
<p>
Access Control
</p>
</li>
<li>
<p>
Input Validation
</p>
</li>
<li>
<p>
Cache Layer
</p>
</li>
<li>
<p>
Internationalization (I18N)
</p>
</li>
<li>
<p>
Registry for global object storage
</p>
</li>
<li>
<p>
Factory for creating new objects
</p>
</li>
</ul></div>
</div>
<h2 id="X3">4. The Dispatcher</h2>
<div class="sectionbody">
<h3 id="_the_life_of_a_web_request">4.1. The Life of a Web Request</h3><div style="clear:left"></div>
<div class="paragraph"><p>The following diagram outlines the typical flow of execution when a web
request is received:</p></div>
<div class="literalblock">
<div class="content">
<pre><tt>  Entry script    Dispatcher  --&gt; Page Controller --&gt; Template
   (index.php)        ^                |  ^              |
       |              |                |  |              |
       |              |                v  |              v
       +--&gt; Execution Profile       Data Model       Web Browser</tt></pre>
</div></div>
<div class="paragraph"><p>The dispatcher is the traffic cop.  It examines the request URI and
decides which page controller it should pass control to, based on a
series of regular expressions that define the URL&#8594;Controller mapping.
The primary URL map is set in <tt>app/config/urls.php</tt>.</p></div>
<h3 id="X3-2">4.2. The <tt>$web</tt> object</h3><div style="clear:left"></div>
<div class="paragraph"><p>There is exactly one dispatch object at any point in the framework, and it
is typically referred to as <tt>$web</tt>.  The dispatcher receives control from
the <strong>web</strong> execution profile and is charged with the task of determining
which page controller it should pass control to.</p></div>
<div class="paragraph"><p>The dispatcher also provides many lower-level facilities to controllers
and plugins, such as:</p></div>
<div class="ulist"><ul>
<li>
<p>
context (information about the web request)
</p>
</li>
<li>
<p>
non-standard status code messages (403, 404, 500)
</p>
</li>
<li>
<p>
http header control
</p>
</li>
<li>
<p>
javascript execution queueing
</p>
</li>
<li>
<p>
debug messages
</p>
</li>
</ul></div>
<h3 id="X3-3">4.3. URL Configuration</h3><div style="clear:left"></div>
<div class="paragraph"><p>Despite the numerous facilities the dispatcher provides, its core mission
is to direct control to the proper page controller.  This is configured
using an array that maps URL patterns to their respective page
controllers.</p></div>
<div class="listingblock">
<div class="title">URL Routing</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #009900">$URLS</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">'/user/(.*)'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'User'</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">'/book/(.*)'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Book'</span><span style="color: #990000">,</span>

        <span style="color: #FF0000">'/login/'</span>    <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'login'</span><span style="color: #990000">),</span>
        <span style="color: #FF0000">'/logout/'</span>   <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'logout'</span><span style="color: #990000">),</span>

        <span style="color: #FF0000">'/'</span>          <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Home'</span>
<span style="color: #990000">);</span></tt></pre></div></div>
<div class="paragraph"><p>As the example suggests, each key in the <tt>$URLS</tt> associative array is a
regular expression, and each value in the array is either the name of a
specific controller class (string) or the name of a specific action within
a specific controller class (array).</p></div>
<div class="paragraph"><p>When routing a request, the dispatcher will choose the first array element
that matches the current URL being requested.  If the target is an entire
controller (such as the <tt>/user/(.*)</tt> and <tt>/book(.*)</tt> examples above) then
the portion of the regular expression surrounded by parentheses will be
used to determine the action handler to be called within the page
controller.</p></div>
<div class="paragraph"><p>For example, if the browser issues a GET request to <tt>/user/list</tt> then
the dispatcher will match the first rule in the <tt>$URLS</tt> array.  It will
then see that the <tt>list</tt> portion of the URL is the action handler
requested, and will dispatch a request to <tt>pUser::GET_list()</tt>.</p></div>
<div class="paragraph"><p>If the action handler requested does not exist in the class, then the
dispatcher will look for a "catch-all" handler for that request type.  For
example, if the browser issues a POST request for <tt>/user/list</tt> and the
dispatcher cannot find a <tt>pUser::POST_list()</tt> method, then it will look
for a <tt>pUser::POST()</tt> method instead.</p></div>
<h4 id="X3-3-a">4.3.1. Named Subpatterns</h4>
<div class="paragraph"><p>While most URL routes use the basic <tt>(.*)</tt> subpattern, it is possible to
use more.  One such use is a <strong>named subpattern</strong>, which binds the
subpattern to a name.  When a route matches, Pronto will merge the values
of the named subpatterns into the standard request argument list
(see <a href="#X4-2-a">Where Input Variables Come From</a>).  The controller can then
access these values through the regular <tt>Page::param()</tt> method.</p></div>
<div class="listingblock">
<div class="title">Using named subpatterns</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #009900">$URLS</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">'/user/(?&lt;uid&gt;[0-9]+)/'</span>     <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'view'</span><span style="color: #990000">),</span>
        <span style="color: #FF0000">'/blog/(?&lt;name&gt;[^/]+)/(.*)'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Blog'</span><span style="color: #990000">,</span>

        <span style="color: #FF0000">'/'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Home'</span>
<span style="color: #990000">);</span></tt></pre></div></div>
<h3 id="X3-4">4.4. Generating URLs</h3><div style="clear:left"></div>
<div class="paragraph"><p>Throughout any web application, you&#8217;re going to need to create links and
forms that send the browser to other areas of the application.  The
simplest method is to just hardcode these URLs into your application (eg,
<tt>&lt;a href="/pronto/user/create"&gt;Create a User&lt;/a&gt;</tt>).</p></div>
<div class="paragraph"><p>But what if the application gets installed to a different sub-directory
than <tt>/pronto</tt>?  Or what if you decide to move all user management to
<tt>/admin/user</tt> instead of <tt>/user</tt>?  Then you have to update all your code
to reflect the change.</p></div>
<div class="paragraph"><p>Pronto&#8217;s solution is contained within the globally-accessible <tt>url()</tt>
function.  This function works in two contexts.</p></div>
<h4 id="X3-4-a">4.4.1. URL Fragments</h4>
<div class="paragraph"><p>In the first context, you simply pass it the relative URL fragment, and it
will resolve it into the full relative URL, including any sub-directory in
which your application is installed.  For example, if the application is
accessible via <tt>http://localhost/blog</tt>, then calling <tt>url('/user/create')</tt>
will return <tt>/blog/user/create</tt>.</p></div>
<div class="paragraph"><p>Simple enough, but this only solves the problem of a varying install
location.  What if you decide to change the URL location of your <tt>User</tt>
controller from <tt>/user</tt> to <tt>/admin/user</tt>?</p></div>
<h4 id="X3-4-b">4.4.2. Controller/Action Tuples</h4>
<div class="paragraph"><p>The second context handles this.  If you pass the <tt>url()</tt> function two
parameters, the controller and the action, then it will use these to
search through your URL route configuration (set in
<tt>app/config/urls.php</tt>).  Once it finds the correct URL route that matches
the controller/action tuple, it will return it.  Basically, the function
is using your URL map <em>backwards</em>, looking through the <strong>values</strong> for a
matching controller/action tuple, then returning the associated <strong>key</strong> when
a match is found.</p></div>
<div class="paragraph"><p>Adapting our former example, we now have this: <tt>url('User','create')</tt>.
This call would return the same code as the last one
(<tt>/blog/user/create</tt>).  But, if we alter our URL routes to point the
<strong>User</strong> controller to <tt>/admin/user</tt> instead, our new <tt>url()</tt> call will
see this and return the new URL automatically.</p></div>
<div class="paragraph"><p>If you need to generate an absolute URL instead, you can use the sister
function <tt>absolute_url()</tt>.  It does the same thing, but returns a full
URL, which can be useful when sending out links to external sources, such
as an email recipient.</p></div>
</div>
<h2 id="X4">5. Page Controllers</h2>
<div class="sectionbody">
<div class="paragraph"><p>The page controller is where most of your application logic will go.  They
are typically organized by the data entities they operate on, or a common
theme of functionality.  For example, one page controller may be
responsible for allowing a user to register an account, login, change
his/her password, etc.  Another page controller may be used to manipulate
blog posts, post comments, or both.</p></div>
<div class="paragraph"><p>A page controller will receive control from the dispatcher and is
responsible for a few things:</p></div>
<div class="ulist"><ul>
<li>
<p>
processing GET/POST input variables
</p>
</li>
<li>
<p>
validating authentication and access levels
</p>
</li>
<li>
<p>
interacting with data models (<em>business logic</em>)
</p>
</li>
<li>
<p>
setting template variables
</p>
</li>
<li>
<p>
rendering templates or redirecting to new URLs
</p>
</li>
</ul></div>
<div class="paragraph"><p>Page controllers are located in the <tt>app/pages</tt> directory.  Each
controller class name will be prefixed with a lowercase <strong>p</strong>, followed by
the name of the controller itself.  The file itself can technically be
named anything you like, but conventionally it shares the same name as the
controller.  For example, the <tt>User</tt> page would have a class name of
<tt>pUser</tt> and would be located in <tt>app/pages/user.php</tt>.</p></div>
<h3 id="X4-1">5.1. Controller Action Handlers</h3><div style="clear:left"></div>
<div class="paragraph"><p>Within each page controller are a number of methods called <strong>action
handlers</strong>.  These methods are responsible for performing the logic
required for the request(s) they are linked to.</p></div>
<div class="paragraph"><p>To elucidate, let&#8217;s begin with a simple example of a page controller.</p></div>
<div class="listingblock">
<div class="title">A basic controller</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_hello</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'greeting'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Hello World! You issued a GET request.'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/hello.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">POST_hello</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'greeting'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Hello World! You issued a POST request.'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/hello.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Notice that action handler methods are prefixed with the type of HTTP
request that was issued.  This separation concept is adopted from the
WebPY framework and its subsequent PHP clone, WebPHP.</p></div>
<div class="paragraph"><p>While at first glance this may seem tedious, it actually proves to be a
very effective way of logically separating your processes based on the
type of request.  Take a minute and think about the typical uses for a GET
and POST, especially when handling form data.  The GET request is
responsible for loading the record, populating the form, and showing it to
the visitor.  The POST request receives input back from the user and is in
charge of validating and possibly updating the record.</p></div>
<div class="paragraph"><p>There have been many PHP projects and frameworks that will use a GET/POST
variable such as <tt>$op</tt> or <tt>$action</tt> to denote the current mode being
requested (eg, <tt>if($op == 'edit') {} else if($op == 'update') {}</tt>).</p></div>
<div class="paragraph"><p>By splitting our logic into separate methods, we avoid the cumbersome
<tt>$action</tt> variable entirely.  As a bonus, we can easily hook into other,
lesser-used HTTP verbs if need be.  For example, if you&#8217;re writing an
RSS-friendly blog, you may want to implement a HEAD request for your blog,
as some readers will use this to retrieve the <tt>Last-Modified</tt> header or the
<tt>E-Tag</tt> header.  Or perhaps you&#8217;d like to write a RESTful API and need to
respond to the PUT and DELETE verbs.</p></div>
<h3 id="X4-2">5.2. Parameters</h3><div style="clear:left"></div>
<div class="paragraph"><p>Before we talk about retrieving input data, let&#8217;s see where it comes from
and how Pronto deals with it.</p></div>
<h4 id="X4-2-a">5.2.1. Where Input Variables Come From</h4>
<div class="paragraph"><p>Before passing control to a page controller, the dispatcher will collect
data from a few different places.  They are listed here, in order of
precedence.  Latter entries override previous ones.</p></div>
<div class="ulist"><div class="title">Input Data: Sources</div><ul>
<li>
<p>
URL arguments (eg, <tt>/user/123/edit</tt>)
</p>
</li>
<li>
<p>
GET variables
</p>
</li>
<li>
<p>
POST variables
</p>
</li>
<li>
<p>
Parameters from the URL route (defined in <tt>app/config/urls.php</tt>)
</p>
</li>
</ul></div>
<h4 id="X4-2-b">5.2.2. Retrieving Input Data</h4>
<div class="paragraph"><p>There are a few ways to collect GET/POST data from within a controller.
The first method is through the use of two convenience methods in the
base <tt>Page</tt> class.</p></div>
<div class="listingblock">
<div class="title">Retrieving and Setting parameters</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_hello</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$name</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">param</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Joe'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'recipient'</span><span style="color: #990000">,</span> <span style="color: #009900">$name</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/hello.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p><tt>Page::param()</tt> is the quickest way to grab a specific parameter from the
input data.  If the variable requested is blank or
does not exist, then the second parameter will be used as a default.</p></div>
<div class="paragraph"><p>If you&#8217;d like to load the entire input data set into an associative
array, then you can use <tt>Page::load_input()</tt>.</p></div>
<div class="listingblock">
<div class="title">Retrieving all parameters with <tt>Page::load_input()</tt></div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_hello</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$data</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">load_input</span></span><span style="color: #990000">();</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'recipient'</span><span style="color: #990000">,</span> <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'name'</span><span style="color: #990000">]);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/hello.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Of course, you&#8217;re free to access variables directly through the <tt>$_GET</tt>
and <tt>$_POST</tt> superglobals, but Pronto will take care of any <tt>magic_quotes</tt>
nonsense if you go through the Page class.</p></div>
<div class="paragraph"><p>If you&#8217;d like to access the raw, un-filtered aggregation of all incoming
request arguments, you can also retrieve them through the Registry.</p></div>
<div class="listingblock">
<div class="title">Retrieving all parameters through the Registry</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_hello</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$args</span> <span style="color: #990000">=</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:request_args'</span><span style="color: #990000">);</span>
                <span style="font-weight: bold"><span style="color: #000000">debug</span></span><span style="color: #990000">(</span><span style="color: #009900">$args</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h3 id="X4-3">5.3. Wildcard Handlers, Inline Variables</h3><div style="clear:left"></div>
<div class="paragraph"><p>Using <a href="#X3-3-a">named subpatterns</a> is one way to use URLs that contain
variables <em>inline</em>, ie, variables occur in the URL path itself, not in
the query string.</p></div>
<div class="paragraph"><p>For example, <tt>/user/edit?id=3</tt> would become <tt>/user/edit/3</tt>.  Assuming
you&#8217;ve named the subpattern "id" in the URL route config, you can still
access the parameter using the <tt>Page::param()</tt> method.</p></div>
<div class="paragraph"><p>Another way to handle situations like these (and more), is through use of
<strong>wildcard action handlers</strong>.  These function like a typical action handler,
except they can be called when only the <em>beginning</em> of the URL request
matches the regexp in the <tt>$URLS</tt> routing table.</p></div>
<div class="paragraph"><p>Once again, an example will elucidate.</p></div>
<div class="listingblock">
<div class="title">Inline Variables</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_hello__</span></span><span style="color: #990000">(</span><span style="color: #009900">$name</span><span style="color: #990000">=</span><span style="color: #FF0000">'Joe'</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'recipient'</span><span style="color: #990000">,</span> <span style="color: #009900">$name</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/hello.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Notice the two underscores trailing the method name.  This denotes the
action handler as a wildcard one.  It means that, if an exact match cannot
be found for the request (in this case, <tt>GET_hello()</tt>) then the dispatcher
will look for a wildcard handler that matches.  If it finds one,
everything trailing after the matching portion will be treated as a
variable, and passed into the action handler as such.  So if the browser
calls <tt>/user/hello/john</tt>, the dispatcher will call
<tt>pUser::GET_hello__('john')</tt>.</p></div>
<div class="paragraph"><p>If a specific action cannot be found and a wildcard action cannot be
found, then the dispatcher will default to the "catch-all" handler for
that request type.  In this case it would be <tt>GET()</tt>.  If the catch-all
does not exist either, then a 404 is issued.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">It is important to provide a default value for any inline variable
arguments in your action handler&#8217;s method prototype.  If you don&#8217;t, then
a visitor could inadvertently trigger an error if they made a request that
did not include the variable (eg, <tt>/user/hello/</tt>).</td>
</tr></table>
</div>
<h3 id="X4-4">5.4. Validating GET/POST data</h3><div style="clear:left"></div>
<div class="paragraph"><p>It&#8217;s very important to validate all data coming in from the web browser,
both to ensure data integrity and maintain security.</p></div>
<div class="paragraph"><p>Most validation is delegated to the data models, but there are times when
it&#8217;s necessary to validate some data that isn&#8217;t destined for a data model.
In these cases, you can validate the directory from within the page
controller.</p></div>
<div class="paragraph"><p>The class in charge of data validation is predictably called <tt>Validator</tt>.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 1: Data Validation Methods</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>Validator::required()</tt></p></td>
<td align="left" valign="top"><p class="table">Check a number of _REQUEST parameters to ensure that all are present and non-empty</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>Validator::validate()</tt></p></td>
<td align="left" valign="top"><p class="table">Validate a _REQUEST parameter against a regular expression</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>Validator::is_valid()</tt></p></td>
<td align="left" valign="top"><p class="table">Same as <tt>validate()</tt> but just return a true/false, don&#8217;t populate the <tt>$errors</tt> array if validation fails</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>When using <tt>Validator::validate()</tt> and <tt>Validator::is_valid()</tt>, you can pass in any
Perl-compatible regular expression.  You can also use one of the regular
expressions defined at the top of <tt>pronto/core/validator.php</tt>.</p></div>
<div class="paragraph"><p>When validating data in a Page Controller, you can use the convenience
functions in the Page class itself.  These ultimately call the same
methods in the Validator class, but they provide some additional
functionality as well (eg, populating an <tt>$errors</tt> array).</p></div>
<div class="listingblock">
<div class="title">Validating Data from a Page Controller</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">POST_save</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$errors</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">();</span>
                <span style="font-style: italic"><span style="color: #9A1900">// We use the shortcut methods here, though we could</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// alternately call them through $this-&gt;validator. Same thing.</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">required</span></span><span style="color: #990000">(</span><span style="color: #009900">$errors</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">,</span><span style="color: #FF0000">'address'</span><span style="color: #990000">));</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">validate</span></span><span style="color: #990000">(</span><span style="color: #009900">$errors</span><span style="color: #990000">,</span> <span style="color: #FF0000">'email'</span><span style="color: #990000">,</span> VALID_EMAIL<span style="color: #990000">,</span> <span style="color: #FF0000">'Invalid email address'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">validate</span></span><span style="color: #990000">(</span><span style="color: #009900">$errors</span><span style="color: #990000">,</span> <span style="color: #FF0000">'age'</span><span style="color: #990000">,</span> VALID_NUMBER<span style="color: #990000">,</span> <span style="color: #FF0000">'Please provide a valid integer'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h3 id="X4-5">5.5. Calling controller elements from other controllers</h3><div style="clear:left"></div>
<div class="paragraph"><p>The typical flow of a Pronto web request usually only involves a single
page controller, but there are some scenarios where it makes sense to
call an action from another page controller.  This is possible with the
<tt>Page::render_element()</tt> method.</p></div>
<div class="paragraph"><p>Most methods in a page controller start with an HTTP verb, such as <tt>GET_</tt>,
<tt>POST_</tt>, or the lesser-used <tt>PUT_</tt>, <tt>DELETE_</tt>, etc.  Page controllers can
also provide <strong>elements</strong> which are methods intended to be called from other
page controllers.  These methods must have a prefix of <tt>ELEM_</tt>.</p></div>
<div class="listingblock">
<div class="title">Calling a controller element - the first controller</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pBlog <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">ELEM_view</span></span><span style="color: #990000">(</span><span style="color: #009900">$user_id</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// load data from model (this will be explained later)</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'blog_data'</span><span style="color: #990000">,</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>blog<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">find</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"user_id=%i"</span><span style="color: #990000">,</span> <span style="color: #009900">$user_id</span><span style="color: #990000">)-&gt;</span><span style="font-weight: bold"><span style="color: #000000">load</span></span><span style="color: #990000">());</span>

                <span style="font-style: italic"><span style="color: #9A1900">// elements don't usually render() their content, but simply</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// fetch() it and return it to the caller, who can then insert</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// the content into a full template.</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">fetch</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'blog/elem.view.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="listingblock">
<div class="title">Calling a controller element - the second controller</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_profile</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$id</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">param</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user_id'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$blog</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render_element</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Blog'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'view'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">));</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'blog_content'</span><span style="color: #990000">,</span> <span style="color: #009900">$blog</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/profile.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
</div>
<h2 id="X5">6. The Template</h2>
<div class="sectionbody">
<div class="paragraph"><p>Templates serve as the presentation layer of Pronto.  When a page
controller has finished its business, it will typically render a template
via the <tt>Page::render()</tt> or <tt>Page::ajax_render()</tt> methods.</p></div>
<div class="paragraph"><p>Templates are unique within Pronto, in that they aren&#8217;t classes
themselves, and they don&#8217;t have access to other areas of Pronto, such as
the dispatcher, controllers, models, or the database (<tt>$db</tt>).  However,
template files are managed by the <tt>Template</tt> class, which is ultimately in
charge of setting/getting template variables, as well as the
fetching/processing of templates themselves.</p></div>
<div class="paragraph"><p>Pronto&#8217;s template system is rather standard.  You can use plain HTML and
PHP as you wish.  However, the only variables accessible are those set by
the page controller via the <tt>Template::set()</tt> method.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">Technically, it possible to access outside variables through the
<strong>Registry</strong> or <tt>$this</tt> variable, but it&#8217;s not encouraged.</td>
</tr></table>
</div>
<div class="paragraph"><p>Templates can also use any active <strong>template plugins</strong>, also called
<strong>helpers</strong>.  These will be covered later, though the example below makes
use of the <tt>$html</tt> helper.</p></div>
<div class="listingblock">
<div class="title">A Simple Template</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;</span>p<span style="color: #990000">&gt;</span>Hello<span style="color: #990000">,</span> <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$name</span> <span style="color: #990000">?&gt;!&lt;/</span>p<span style="color: #990000">&gt;</span>
<span style="color: #990000">&lt;</span>p<span style="color: #990000">&gt;</span>I am a template<span style="color: #990000">.&lt;/</span>p<span style="color: #990000">&gt;</span>
<span style="color: #990000">&lt;</span>p<span style="color: #990000">&gt;&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">link</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Go home'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/'</span><span style="color: #990000">))</span> <span style="color: #990000">?&gt;&lt;/</span>p<span style="color: #990000">&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Although most helpers are loaded from the framework config or from a page
controller, it is possible to load helpers from within templates.
Template files do have access to the <tt>$this</tt>, and so they can call methods
in the Template object itself.</p></div>
<div class="listingblock">
<div class="title">Loading a helper in a template</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #009900">$form</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_helper</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'form'</span><span style="color: #990000">);</span>
<span style="color: #990000">?</span>php <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$form</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">text</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">)</span> <span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Templates are usually organized by page controller, since that&#8217;s who
typically renders them.  The logical structure is to have subdirectories
within the <tt>app/templates</tt> directory that match the names of the page
controllers that will be rendering them.  This is recommended but not
required.</p></div>
<h3 id="X5-1">6.1. Template Variables</h3><div style="clear:left"></div>
<div class="paragraph"><p>As shown in the example above, templates can reference their variables in
the global scope, but they are limited only to variables that have been
set using <tt>Template::set()</tt>, <tt>Page::tset()</tt>, or objects that serve as
template plugins.</p></div>
<div class="paragraph"><p>The <tt>Template</tt> class offers methods for setting, getting, and testing the
existence of template variables.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">While <tt>Template::set()</tt> is the real variable setter, you&#8217;re also free to
use <tt>Page::tset()</tt> which is a shortcut method to the real one.  Likewise,
there are shortcuts for <tt>Template::get()</tt>, <tt>Template::is_set()</tt>, and
<tt>Template::un_set()</tt>.</td>
</tr></table>
</div>
<div class="listingblock">
<div class="title">Template Variables</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// set it...</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Joe'</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// get it back...</span></span>
                <span style="color: #009900">$name</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">;</span>
                <span style="font-style: italic"><span style="color: #9A1900">// has it been set?</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">is_set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// then unset it</span></span>
                        <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">un_set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">);</span>
                <span style="color: #FF0000">}</span>

                <span style="font-style: italic"><span style="color: #9A1900">// alternately, we can use the shortcuts...</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'John'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$name</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tget</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h3 id="X5-2">6.2. Rendering a Template</h3><div style="clear:left"></div>
<div class="paragraph"><p>There are three functions that can be used to render templates.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 2: Rendering Functions</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>Page::render()</tt></p></td>
<td align="left" valign="top"><p class="table">Parse a template and render it to the browser</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>Page::fetch()</tt></p></td>
<td align="left" valign="top"><p class="table">Parse a template and return the output to the caller</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>Page::ajax_render()</tt></p></td>
<td align="left" valign="top"><p class="table">Render a template as an AJAX response (covered later)</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>You&#8217;ll probably use the <tt>Page::render()</tt> function the most, but
<tt>Page::fetch()</tt> can be useful if you&#8217;re combining templates, or rendering
them somewhere other than the browser (eg, email).  Both functions allow
you to pass in additional template variables that are not set globally via
<tt>Template::set()</tt> or <tt>Page::tset()</tt>.</p></div>
<div class="listingblock">
<div class="title">Rendering a Template</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Joe'</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// this path is relative the app/templates directory</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/hello.php'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'age'</span><span style="color: #990000">=&gt;</span><span style="color: #993399">27</span><span style="color: #990000">));</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Like the methods for settings template variables, the real functionality
is actually in the <tt>Template</tt> class itself.  The methods in <tt>Page</tt> are
merely convenience methods that call the real ones.</p></div>
<h3 id="X5-3">6.3. Layouts</h3><div style="clear:left"></div>
<div class="paragraph"><p>Layouts provide a way of establishing one or more outer structures to the
presentation/look-and-feel of your web application.  Most of the
application&#8217;s structure and styling will be relegated to the layout,
leaving the core content in the templates themselves.  While not
considered a regular template, layouts still have access to template
variables and plugins.</p></div>
<div class="listingblock">
<div class="title">A Typical Layout</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;!</span>DOCTYPE HTML PUBLIC <span style="color: #FF0000">"-//W3C//DTD HTML 4.01 Transitional//EN"</span>
<span style="color: #FF0000">"http://www.w3.org/TR/html4/loose.dtd"</span><span style="color: #990000">&gt;</span>
<span style="color: #990000">&lt;</span>html<span style="color: #990000">&gt;</span>
<span style="color: #990000">&lt;</span>head<span style="color: #990000">&gt;</span>
        <span style="color: #990000">&lt;</span>meta http<span style="color: #990000">-</span>equiv<span style="color: #990000">=</span><span style="color: #FF0000">"Content-Type"</span> content<span style="color: #990000">=</span><span style="color: #FF0000">"text/html; charset=&lt;?php echo CHARSET ?&gt;"</span><span style="color: #990000">&gt;</span>
        <span style="color: #990000">&lt;</span>title<span style="color: #990000">&gt;&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> SITE_NAME <span style="color: #990000">?&gt;&lt;/</span>title<span style="color: #990000">&gt;</span>
        <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">favicon</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'favicon'</span><span style="color: #990000">)</span> <span style="color: #990000">?&gt;</span>
        <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">css</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'main'</span><span style="color: #990000">)</span> <span style="color: #990000">?&gt;</span>
        <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">js</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'jq/jquery'</span><span style="color: #990000">)</span> <span style="color: #990000">?&gt;</span>
        <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$HTML_HEAD</span> <span style="color: #990000">?&gt;</span>
<span style="color: #990000">&lt;/</span>head<span style="color: #990000">&gt;</span>

<span style="color: #990000">&lt;</span>body<span style="color: #990000">&gt;</span>
        <span style="color: #990000">&lt;</span>div id<span style="color: #990000">=</span><span style="color: #FF0000">"header"</span><span style="color: #990000">&gt;</span>
                Super Cool Web App v1<span style="color: #990000">.</span><span style="color: #993399">0</span>
        <span style="color: #990000">&lt;/</span>div<span style="color: #990000">&gt;</span>
        <span style="color: #990000">&lt;</span>div id<span style="color: #990000">=</span><span style="color: #FF0000">"content"</span><span style="color: #990000">&gt;</span>
                <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$CONTENT_FOR_LAYOUT</span> <span style="color: #990000">?&gt;</span>
        <span style="color: #990000">&lt;/</span>div<span style="color: #990000">&gt;</span>
<span style="color: #990000">&lt;/</span>body<span style="color: #990000">&gt;</span>
<span style="color: #990000">&lt;/</span>html<span style="color: #990000">&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>As you can see, all the "outer" stuff gets thrown in the layout.  When a
template is rendered within a layout, it will be substituted for the
variable <tt>$CONTENT_FOR_LAYOUT</tt>.  The other special layout variable is
<tt>$HTML_HEAD</tt>, a placeholder variable for any additional tags that may need
to be inserted into the <tt>&lt;head&gt;</tt> of your document.</p></div>
<div class="paragraph"><p>Multiple layouts are supported.  You can bind to a specific layout with
the <tt>Page::render()</tt> method, or you can set a layout in a page
controller&#8217;s <tt>__init__()</tt> method.</p></div>
<div class="listingblock">
<div class="title">Rendering a template within a different layout</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// set a different layout for this page.</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// path is relative to app/templates.</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_layout</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'layout.other.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Joe'</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// render this template in a specific layout</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/hello.php'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(),</span> <span style="color: #FF0000">'layout.new.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
</div>
<h2 id="X6">7. The Model</h2>
<div class="sectionbody">
<div class="paragraph"><p>Models are responsible for any logic that surrounds the manipulation of a
data entity.  Its typical responsibilities are to faciliate create,
retrieve, update and delete (CRUD) operations.  If more advanced
manipulation/processing functions are required for an entity, they will
also be located here.</p></div>
<div class="paragraph"><p>The model layer actually consists of two classes, <strong>RecordModel</strong> and
<strong>RecordSelector</strong>.  The RecordModel class is the one that your application
will actually extend to create entity-specific data models.  The
RecordSelector class is used to create search/query critieria through a
fluent API.</p></div>
<div class="paragraph"><p>We&#8217;ll cover RecordModel first.</p></div>
<div class="paragraph"><p>The RecordModel is the parent class for all data models in Pronto.  You
will extend this class whenever you create a new data model, overriding
any public/callable methods that require customization.</p></div>
<h3 id="X6-1">7.1. The Core Operations</h3><div style="clear:left"></div>
<div class="paragraph"><p>The base <tt>RecordModel</tt> class provides an interface for the common operations
associated with a simple data entity.  These are the methods that will be
called by your controllers.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 3: Common data entity operations</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>validate</tt></p></td>
<td align="left" valign="top"><p class="table">Validate form data for an insert or update operation</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>sanitize</tt></p></td>
<td align="left" valign="top"><p class="table">Perform any necessary data sanitization prior to operating</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>create</tt></p></td>
<td align="left" valign="top"><p class="table">Return a "default" set of data to populate a form for entity creation</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>load</tt></p></td>
<td align="left" valign="top"><p class="table">Return a full data record, retrieved by Primary Key (PK)</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>delete</tt></p></td>
<td align="left" valign="top"><p class="table">Delete a record by PK</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>save</tt></p></td>
<td align="left" valign="top"><p class="table">Save a record to the DB (insert/update)</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>enum_schema</tt></p></td>
<td align="left" valign="top"><p class="table">Provide parameters necessary to enumerate (list)
                        or search for records</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>Some of the methods listed above are actually frontends to other,
lower-order methods that do the real work.  These lower-order methods are
the ones you should override in your model classes.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 4: Base model methods to be overridden</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>validate</tt></p></td>
<td align="left" valign="top"><p class="table">Validate form data for an insert or update operation</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>sanitize</tt></p></td>
<td align="left" valign="top"><p class="table">Perform any necessary data sanitization prior to operating</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>create_record</tt></p></td>
<td align="left" valign="top"><p class="table">Return a "default" set of data to populate a form for entity creation</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>load_record</tt></p></td>
<td align="left" valign="top"><p class="table">Return a full data record, retrieved by Primary Key (PK)</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>delete_record</tt></p></td>
<td align="left" valign="top"><p class="table">Delete a record by PK</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>save_record</tt></p></td>
<td align="left" valign="top"><p class="table">Save a record to the DB (insert/update)</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>enum_schema</tt></p></td>
<td align="left" valign="top"><p class="table">Provide parameters necessary to enumerate (list)
                        or search for records</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>The reason for the separation is because of the cache.  The frontend
methods (i.e., the ones called by other components of the application) are
responsible for transparently caching data records and expiring the
cache entries when they are no longer valid.</p></div>
<div class="paragraph"><p>By only overriding the lower-order methods, you are free to write your
model code with very little concern for the cache management.  There are
times when you may need to consider the effect of a cache (if you enable
it), but for the most part, this architecture buys you caching for free.</p></div>
<div class="paragraph"><p>Depending on your data entity, some or all of these methods may not be
relevant.  If you are using the specialized controller <tt>Page_CRUD</tt>, then
it will expect these functions to be complete.</p></div>
<div class="paragraph"><p>For extremely simple entities, the implementation within the base
<tt>RecordModel</tt> class will probably suffice.  For all others, you will want
to override the functionality within your own model class.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">Very simple models may benefit from the <a href="#X6-8">fly-model</a> facility as well.</td>
</tr></table>
</div>
<div class="paragraph"><p>Model class names are prefixed with a lowercase <tt>m</tt>.</p></div>
<h3 id="X6-2">7.2. Accessing the Database</h3><div style="clear:left"></div>
<div class="paragraph"><p>Database connection parameters are stored in <tt>app/config/databases.php</tt>.
Pronto supports multiple databases, though one database is expected to be
the primary/default.  Unless set otherwise, data models will use the
primary database.</p></div>
<div class="paragraph"><p>Like most framework objects, database objects are stored in the Registry
under the pattern <tt>pronto:db:&lt;name&gt;</tt> where <tt>&lt;name&gt;</tt> is the name of the
database connection as set in the configuration file.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">The primary/default database connection should be called <tt>main</tt>.</td>
</tr></table>
</div>
<div class="paragraph"><p>The database class provides some simple convenience methods for selects,
inserts, and updates, while using the third-party <strong>SafeSQL</strong> library for
parameter substitution and protection against SQL injection attacks.</p></div>
<div class="paragraph"><p>An example is below, though it is a bit contrived.  You would normally
perform these functions through the model layer, not directly on the
database.</p></div>
<div class="paragraph"><p>You&#8217;ll want to consult the API documentation for a full list of methods
available.</p></div>
<div class="listingblock">
<div class="title">Using the <tt>$db</tt> object</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> RecordModel
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">do_stuff</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// get a full record...</span></span>
                <span style="color: #009900">$data</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_item</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"SELECT * FROM users WHERE id=%i"</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">));</span>
                <span style="font-style: italic"><span style="color: #9A1900">// this works too...</span></span>
                <span style="color: #009900">$data</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_item_by_pk</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'users'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'id'</span><span style="color: #990000">,</span> <span style="color: #009900">$id</span><span style="color: #990000">);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// update it with new data...</span></span>
                        <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'last_login'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">date</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Y-m-d'</span><span style="color: #990000">);</span>
                        <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">update_row</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'users'</span><span style="color: #990000">,</span> <span style="color: #009900">$data</span><span style="color: #990000">,</span> <span style="color: #FF0000">'id=%i'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">));</span>
                <span style="color: #FF0000">}</span>
                <span style="font-style: italic"><span style="color: #9A1900">// count users who logged in today...</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_value</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"SELECT COUNT(*) FROM users WHERE last_login=CURDATE()"</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>As you can see, you can use placeholders within your SQL queries to denote
variables that can be substituted by SafeSQL when it&#8217;s time to execute the
query.  This is the recommended method of using variables in your queries,
as SafeSQL can ensure that any malicious SQL (or other poorly-formed data)
is properly escaped before being passed to the database engine.</p></div>
<div class="paragraph"><p>There are different types of placeholders you can use, depending on what
type of data you&#8217;ll be passing in.  If the variable type does not match
the placeholder, SafeSQL will attempt to cast it.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 5: SafeSQL Variable Placeholders</caption>
<col width="20%" />
<col width="80%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>%s</tt></p></td>
<td align="left" valign="top"><p class="table">string</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>%i</tt></p></td>
<td align="left" valign="top"><p class="table">integer</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>%f</tt></p></td>
<td align="left" valign="top"><p class="table">float</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>%c</tt></p></td>
<td align="left" valign="top"><p class="table">comma-separated list, each element casted to integer</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>%l</tt></p></td>
<td align="left" valign="top"><p class="table">comma-separated list, no quotes or casting</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>%q</tt></p></td>
<td align="left" valign="top"><p class="table">comma-separated list, each element quoted (string)</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>%n</tt></p></td>
<td align="left" valign="top"><p class="table">wrap the value in quotes unless it is NULL</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>In a well-organized application, almost all of your DB work will be in the
models themselves.  But just in case, <tt>$db</tt> is available to the dispatch
and page controllers.  It can be passed to plugins as well, though there
are usually better ways of doing this.</p></div>
<h3 id="X6-3">7.3. Accessing a non-primary database</h3><div style="clear:left"></div>
<div class="paragraph"><p>By default, Pronto will use the database connection labeled as <tt>main</tt>.
This object appears in the registry as <tt>pronto:db:main</tt>.</p></div>
<div class="listingblock">
<div class="title">Fetch your own database object</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> RecordModel
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">do_stuff</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$db</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:db:main'</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// $db is the same as $this-&gt;db</span></span>

                <span style="font-style: italic"><span style="color: #9A1900">// now fetch a different database object</span></span>
                <span style="color: #009900">$db2</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:db:myotherdb'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$data</span> <span style="color: #990000">=</span> <span style="color: #009900">$db2</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_item_by_pk</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'users'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'id'</span><span style="color: #990000">,</span> <span style="color: #009900">$id</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>If you have an entire data model that should be using a different database
than <tt>main</tt>, you can set this in the model&#8217;s <tt>__init__()</tt> class.</p></div>
<div class="listingblock">
<div class="title">Linking a model to a different database</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> RecordModel
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:db:myotherdb'</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// now all methods will use this database</span></span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h3 id="X6-4">7.4. Defining parameters for enumeration</h3><div style="clear:left"></div>
<div class="paragraph"><p>Of all the operations listed in the beginning of this section, the one
that probably stands out is the last one, <tt>enum_schema()</tt>.  Within
the Pronto framework itself, this method is only used by one method, and
that is <tt>Page_CRUD::GET_list()</tt>.  The <tt>Page_CRUD</tt> class will be covered
later, but <tt>enum_schema()</tt> can be used by application code that you
write as well, so we&#8217;ll cover it here.</p></div>
<div class="paragraph"><p>The purpose of <tt>enum_schema()</tt> is to return the information
required to construct a SQL query that will return a useful dataset to
populate a record listing.  It is often used in conjuction with
<tt>SQL_Generator::enumerate()</tt>, which can convert list parameters into full
SQL code.</p></div>
<div class="paragraph"><p>That&#8217;s a bit of a mouthful, so perhaps a well-contrived example will serve
us better.</p></div>
<div class="paragraph"><p>Let&#8217;s say you need to show a tabled list of records for a data entity.  In
a perfect world, you could just issue a <tt>"SELECT * FROM $table"</tt> and pass
it to a template plugin that generates the table.  But what if some
columns are not mapped directly to a column in your table?  What if you
need to join against other tables, or restrict your data with a <tt>WHERE</tt>
clause?</p></div>
<div class="paragraph"><p>All of this is a cinch to do with SQL (that&#8217;s what it was designed for,
after all), but if a plugin or controller action is in charge of deciding
which field to sort by or which data to restrict, then it can be easier to
start by separating your query into its logical segments.  That&#8217;s what
<tt>enum_schema()</tt> does.</p></div>
<div class="paragraph"><p><tt>enum_schema()</tt> returns an associative array that contains nine
elements.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">Like the rest of the RecordModel interface, you only need to implement this
method if you&#8217;re actually going to use it.</td>
</tr></table>
</div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 6: Elements of <tt>RecordModel::enum_schema()</tt></caption>
<col width="25%" />
<col width="25%" />
<col width="50%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>from</tt></p></td>
<td align="left" valign="top"><p class="table"><em>string</em></p></td>
<td align="left" valign="top"><p class="table">The FROM clause that will be used.  This should be well-formed SQL.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>exprs</tt></p></td>
<td align="left" valign="top"><p class="table"><em>array</em></p></td>
<td align="left" valign="top"><p class="table">Zero or more SQL expressions that will be used in the SELECT clause of the query.  These are typically pieces of data that aren&#8217;t regular data columns, but are passed through some SQL functions or similar.  When creating a WHERE clause to filter a result set, Pronto will check this array first.  If a match is found, it will use the SQL expression instead of the literal column name.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>gexprs</tt></p></td>
<td align="left" valign="top"><p class="table"><em>array</em></p></td>
<td align="left" valign="top"><p class="table">Like <tt>exprs</tt>, except Pronto will use this when building a HAVING clause for a SQL query.  Not usually needed unless you&#8217;re also using <tt>group_by</tt>.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>select</tt></p></td>
<td align="left" valign="top"><p class="table"><em>string</em></p></td>
<td align="left" valign="top"><p class="table">The main SELECT clause of the query.  Can be as simple as <tt>*</tt> or you can select certain columns (eg, <tt>u.id,u.name</tt>).</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>where</tt></p></td>
<td align="left" valign="top"><p class="table"><em>mixed</em></p></td>
<td align="left" valign="top"><p class="table">An array or string of elements that will construct your WHERE clause.  If an array, these will be AND&#8217;ed together, along with any other filter data that might be added by your controller. (eg, <tt>array('status="active"', 'confirmed=1')</tt>)</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>group_by</tt></p></td>
<td align="left" valign="top"><p class="table"><em>string</em></p></td>
<td align="left" valign="top"><p class="table">The column(s) to group by, if any.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>having</tt></p></td>
<td align="left" valign="top"><p class="table"><em>string</em></p></td>
<td align="left" valign="top"><p class="table">The column(s) to sort by.  If not specified, your model&#8217;s <tt>default_sort</tt> will be used.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>order</tt></p></td>
<td align="left" valign="top"><p class="table"><em>string</em></p></td>
<td align="left" valign="top"><p class="table">The column(s) to sort by.  If not specified, your model&#8217;s <tt>default_sort</tt> will be used.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>limit</tt></p></td>
<td align="left" valign="top"><p class="table"><em>string</em></p></td>
<td align="left" valign="top"><p class="table">The amount of records to return, if you choose to limit them.  If not specified, your model&#8217;s <tt>per_page</tt> will be used.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">You can optionally pass any of the query chunks through <tt>$this-&gt;db-&gt;query()</tt>
first to do proper argument substitution.  <tt>$this-&gt;db-&gt;query()</tt> will not
actually execute a query, it simply performs the variable substitution that
should occur before a query is executed.</td>
</tr></table>
</div>
<div class="listingblock">
<div class="title">Using <tt>enum_schema()</tt></div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mPost <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> RecordModel
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">enum_schema</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                        <span style="color: #FF0000">'from'</span>       <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'posts p INNER JOIN blogs b ON b.id=p.blog_id'</span><span style="color: #990000">,</span>
                        <span style="color: #FF0000">'exprs'</span>      <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'posted_at'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"CONCAT(p.post_date,' ',p.post_time)"</span><span style="color: #990000">),</span>
                        <span style="color: #FF0000">'gexprs'</span>     <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(),</span>
                        <span style="color: #FF0000">'select'</span>     <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'p.*,b.name'</span><span style="color: #990000">,</span>
                        <span style="color: #FF0000">'where'</span>      <span style="color: #990000">=&gt;</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">query</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'b.user_id=%i'</span><span style="color: #990000">,</span> ACCESS_ID<span style="color: #990000">),</span>
                        <span style="color: #FF0000">'group_by'</span>   <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">''</span><span style="color: #990000">,</span>
                        <span style="color: #FF0000">'having'</span>     <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">''</span><span style="color: #990000">,</span>
                        <span style="color: #FF0000">'order'</span>      <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'p.post_date DESC'</span><span style="color: #990000">,</span>
                        <span style="color: #FF0000">'limit'</span>      <span style="color: #990000">=&gt;</span> <span style="color: #993399">50</span>
                <span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>If you&#8217;d like to see how this data is used, take a look at the
<tt>SQL_Generator::enumerate()</tt> method in <tt>pronto/core/sql.php</tt>.</p></div>
<h3 id="X6-5">7.5. Finding Records</h3><div style="clear:left"></div>
<div class="paragraph"><p>So we&#8217;ve shown how you define the behavior around a data entity.  Now how
do we actually <em>find</em> records?</p></div>
<div class="paragraph"><p>We use the <strong>RecordSelector</strong> facility.</p></div>
<div class="paragraph"><p>RecordSelector is a simple class that provides a fluent API for building
record queries, also known as <strong>selectors</strong>.  You can build a selector by
calling the <tt>find()</tt> method of any model object.</p></div>
<div class="listingblock">
<div class="title">Example uses of RecordSelector</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> RecordModel
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">do_stuff</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// build a selector that finds the first 50 active users,</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// sorted by the date they joined.</span></span>
                <span style="color: #009900">$s</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">find</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"status='active'"</span><span style="color: #990000">)-&gt;</span><span style="font-weight: bold"><span style="color: #000000">order</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'created_on'</span><span style="color: #990000">)-&gt;</span><span style="font-weight: bold"><span style="color: #000000">limit</span></span><span style="color: #990000">(</span><span style="color: #993399">50</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// now use the selector to fetch all records, then delete them</span></span>
                <span style="color: #009900">$users</span> <span style="color: #990000">=</span> <span style="color: #009900">$s</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">load</span></span><span style="color: #990000">();</span>
                <span style="color: #009900">$s</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">delete</span></span><span style="color: #990000">();</span>

                <span style="font-style: italic"><span style="color: #9A1900">// now find all inactive users with a certain first name</span></span>
                <span style="color: #009900">$s</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">find</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"status='inactive' AND first_name='%s'"</span><span style="color: #990000">,</span> <span style="color: #009900">$name</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// iterate through each, flagging them as we go</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">while</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span> <span style="color: #990000">=</span> <span style="color: #009900">$s</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">one</span></span><span style="color: #990000">())</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// do stuff with $user</span></span>
                        <span style="font-style: italic"><span style="color: #9A1900">// ...</span></span>

                        <span style="font-style: italic"><span style="color: #9A1900">// now set a flag column in the database by creating a new selector</span></span>
                        <span style="font-style: italic"><span style="color: #9A1900">// that isolates this specific user.</span></span>
                        <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">find</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"id=%i"</span><span style="color: #990000">,</span> <span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">])-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'sent_mail'</span><span style="color: #990000">,</span> <span style="color: #993399">1</span><span style="color: #990000">);</span>
                <span style="color: #FF0000">}</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>As you may have noticed, the arguments passed to the various
RecordSelector methods are just SQL-legal chunks that will be assembled
together and passed to the database engine.  So you will still need to
know SQL to be effective in Pronto.</p></div>
<div class="paragraph"><p>Also note that this API can only build basic queries.  If you have more
advanced work to do at the database level, you will definitely want to
write your SQL manually and query the database through <tt>$db</tt>.</p></div>
<h3 id="X6-6">7.6. Example: A model and its use</h3><div style="clear:left"></div>
<div class="paragraph"><p>Let&#8217;s look at a simple example of a model and how it might be used from a
page controller.</p></div>
<div class="listingblock">
<div class="title">A simple model</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> RecordModel
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">validate</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// all our errors will be returned in this array</span></span>
                <span style="color: #009900">$errors</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">();</span>
                <span style="font-style: italic"><span style="color: #9A1900">// we can use the Validator::validate() and Validator::required() functions</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>validator<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">required</span></span><span style="color: #990000">(</span><span style="color: #009900">$errors</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'first_name'</span><span style="color: #990000">,</span><span style="color: #FF0000">'last_name'</span><span style="color: #990000">,</span><span style="color: #FF0000">'password'</span><span style="color: #990000">),</span> <span style="color: #009900">$data</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>validator<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">validate</span></span><span style="color: #990000">(</span><span style="color: #009900">$errors</span><span style="color: #990000">,</span> <span style="color: #FF0000">'email'</span><span style="color: #990000">,</span> VALID_EMAIL<span style="color: #990000">,</span> <span style="color: #FF0000">'Valid email required'</span><span style="color: #990000">,</span> <span style="color: #009900">$data</span><span style="color: #990000">);</span>

                <span style="font-style: italic"><span style="color: #9A1900">// only perform this part if we're inserting a new user, not updating</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// an existing one...</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(!</span><span style="font-weight: bold"><span style="color: #0000FF">isset</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">]))</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// make sure passwords match</span></span>
                        <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(!</span><span style="font-weight: bold"><span style="color: #0000FF">empty</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'password'</span><span style="color: #990000">])</span> <span style="color: #990000">&amp;&amp;</span> <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'password'</span><span style="color: #990000">]</span> <span style="color: #990000">!=</span> <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'password2'</span><span style="color: #990000">])</span> <span style="color: #FF0000">{</span>
                                <span style="color: #009900">$errors</span><span style="color: #990000">[</span><span style="color: #FF0000">'password2'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="color: #FF0000">'Passwords do not match'</span><span style="color: #990000">;</span>
                        <span style="color: #FF0000">}</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// check for a duplicate username</span></span>
                        <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_value</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"SELECT id FROM users WHERE email='%s'"</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'email'</span><span style="color: #990000">])))</span> <span style="color: #FF0000">{</span>
                                <span style="color: #009900">$errors</span><span style="color: #990000">[</span><span style="color: #FF0000">'email'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="color: #FF0000">'This email address is already in use.'</span><span style="color: #990000">;</span>
                        <span style="color: #FF0000">}</span>
                <span style="color: #FF0000">}</span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #009900">$errors</span><span style="color: #990000">;</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">load_record</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$data</span> <span style="color: #990000">=</span> parent<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">load_record</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// we don't need the password, remove it before giving</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// data back to the caller...</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">unset</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'password'</span><span style="color: #990000">]);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #009900">$data</span><span style="color: #990000">;</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">save_record</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// is this an insert?</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(!</span><span style="font-weight: bold"><span style="color: #0000FF">isset</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">]))</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// set some metadata...</span></span>
                        <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'created_on'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">date</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Y-m-d'</span><span style="color: #990000">);</span>
                        <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'status'</span><span style="color: #990000">]</span>     <span style="color: #990000">=</span> <span style="color: #FF0000">'active'</span><span style="color: #990000">;</span>
                <span style="color: #FF0000">}</span> <span style="font-weight: bold"><span style="color: #0000FF">else</span></span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// it's an update - don't let the user change these fields</span></span>
                        <span style="font-weight: bold"><span style="color: #0000FF">unset</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'status'</span><span style="color: #990000">],</span> <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'created_on'</span><span style="color: #990000">]);</span>
                <span style="color: #FF0000">}</span>

                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">isset</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'password'</span><span style="color: #990000">]))</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// encrypt password</span></span>
                        <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'password'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">sha1</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'password'</span><span style="color: #990000">]);</span>
                <span style="color: #FF0000">}</span>

                <span style="font-style: italic"><span style="color: #9A1900">// return the ID of the record</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> parent<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">save_record</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">delete_record</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// we employ lazy deletion...</span></span>

                <span style="font-style: italic"><span style="color: #9A1900">// you don't to use a selector here, since this is *the* authoritative</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// place where the real deletion happens.</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">execute</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"UPDATE users SET status='deleted' WHERE id=%i"</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">));</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">The <tt>delete_record()</tt> method looks like a good place to do something like
this: <tt>$this-&gt;find("id=%i", $id)-&gt;delete()</tt>.  The problem is that the
<tt>delete_record</tt> is the one place that must perform the actual record
deletion.  The selector will actually call <tt>delete_record</tt> to do the work,
so if we were to call the selector we would introduce an infinite cycle.</td>
</tr></table>
</div>
<div class="paragraph"><p>Now that our model is ready, we can create a page controller that uses
these methods.  Our basic controller will provide a registration facility
for new users.</p></div>
<div class="listingblock">
<div class="title">Using the model from a page controller</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// import the model so it can be accessed via $this-&gt;models</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_signup</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(!</span><span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">is_set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'data'</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// no form data is set yet, give it some defaults</span></span>
                        <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>template<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'data'</span><span style="color: #990000">,</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>user<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">create</span></span><span style="color: #990000">());</span>
                <span style="color: #FF0000">}</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/signup.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">POST_signup</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// grab the POST data into an associative array</span></span>
                <span style="color: #009900">$data</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">load_input</span></span><span style="color: #990000">();</span>
                <span style="font-style: italic"><span style="color: #9A1900">// validate</span></span>
                <span style="color: #009900">$errors</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>user<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">validate</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">,</span> false<span style="color: #990000">);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(!</span><span style="font-weight: bold"><span style="color: #0000FF">empty</span></span><span style="color: #990000">(</span><span style="color: #009900">$errors</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// validation failed... return the visitor to the signup</span></span>
                        <span style="font-style: italic"><span style="color: #9A1900">// form... The Page class provides a mechanism for this.  It will</span></span>
                        <span style="font-style: italic"><span style="color: #9A1900">// pass the form data and the errors back through the session and</span></span>
                        <span style="font-style: italic"><span style="color: #9A1900">// issue a redirect to the signup form.</span></span>
                        <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">return_to_form</span></span><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/signup'</span><span style="color: #990000">),</span> <span style="color: #009900">$data</span><span style="color: #990000">,</span> <span style="color: #009900">$errors</span><span style="color: #990000">);</span>
                        <span style="font-weight: bold"><span style="color: #0000FF">return</span></span><span style="color: #990000">;</span>
                <span style="color: #FF0000">}</span>
                <span style="font-style: italic"><span style="color: #9A1900">// validation passed, do the insert</span></span>
                <span style="color: #009900">$id</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>user<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">save</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// now send them to their profile page</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">redirect</span></span><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/profile?id=$id"</span><span style="color: #990000">));</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>As you can see, the separation of data logic and controller logic makes
for some well-organized, readable code, and the GET/POST split in the
controller makes it easy to tell which stage we&#8217;re at in the signup
process.</p></div>
<h3 id="X6-7">7.7. Using other models from within a model</h3><div style="clear:left"></div>
<div class="paragraph"><p>It&#8217;s possible for a model to depend on other models.  This occurs a lot
when you have entities that link to each other.  A model for managing
users probably shouldn&#8217;t directly modify another entity type, so instead
it can ask the respective model to do the work on its behalf.</p></div>
<div class="listingblock">
<div class="title">Using other models</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> RecordModel
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">delete_record</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// load the Blog model as a dependency so we can delete this user's</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// blog record as well.</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">depend</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'blog'</span><span style="color: #990000">);</span>

                <span style="color: #009900">$user</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">);</span>

                <span style="font-style: italic"><span style="color: #9A1900">// note that we call the other model's higher-order frontend function</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// delete() instead of delete_record()</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>depends<span style="color: #990000">-&gt;</span>blog<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">delete</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'blog_id'</span><span style="color: #990000">]);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// now delete ourself</span></span>
                parent<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">delete_record</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h3 id="X6-8">7.8. Using fly-models</h3><div style="clear:left"></div>
<div class="paragraph"><p>In some cases, it may be overkill to actually build a model class around
a DB table when there&#8217;s no need to override any methods.  In cases like
these, you can adopt the base model functionality in the form of a
<strong>fly-model</strong>.  A fly-model gives you a model object that is instantiated
directly from the base RecordModel class.</p></div>
<div class="listingblock">
<div class="title">Using a fly-model</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pPerson <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// fly-models required one argument: the name of the DB table</span></span>
                <span style="color: #009900">$m</span> <span style="color: #990000">=&amp;</span> Factory<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">fly_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'people'</span><span style="color: #990000">);</span>

                <span style="font-style: italic"><span style="color: #9A1900">// now use the object as any other model</span></span>
                <span style="color: #009900">$s</span> <span style="color: #990000">=</span> <span style="color: #009900">$m</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">find</span></span><span style="color: #990000">()-&gt;</span><span style="font-weight: bold"><span style="color: #000000">order</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">while</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span> <span style="color: #990000">=</span> <span style="color: #009900">$s</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">one</span></span><span style="color: #990000">())</span> <span style="color: #FF0000">{</span>
                        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">"Person: "</span> <span style="color: #990000">.</span> <span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'name'</span><span style="color: #990000">]</span> <span style="color: #990000">.</span> <span style="color: #FF0000">"&lt;br /&gt;"</span><span style="color: #990000">;</span>
                <span style="color: #FF0000">}</span>

                <span style="color: #009900">$m</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">save</span></span><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'name'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'John Doe'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'age'</span><span style="color: #990000">=&gt;</span><span style="color: #993399">30</span><span style="color: #990000">));</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
</div>
<h2 id="X7">8. Sessions and Authentication</h2>
<div class="sectionbody">
<div class="paragraph"><p>There is no special facility in place for storing and retrieving session
data, so you can use the standard PHP superglobal <tt>$_SESSION</tt> just as you
would in a basic PHP script.</p></div>
<div class="listingblock">
<div class="title">Storing session variables</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
        <span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'rocket_science'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> false<span style="color: #990000">;</span>
        <span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'other_stuff'</span><span style="color: #990000">]</span>    <span style="color: #990000">=</span> <span style="color: #FF0000">'Pretty basic...'</span><span style="color: #990000">;</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Likewise, there is no policy on authentication either, though Pronto does
provide a facility for access control lists (ACLs) and access checks.</p></div>
<div class="paragraph"><p>What this means is that you&#8217;re free to authenticate your users however you
like.  Once authenticated, you can use Pronto&#8217;s access control features to
keep track of whether a user is logged in or not, and what areas of the
web application they are allowed to access.</p></div>
<h3 id="X7-1">8.1. Access Control</h3><div style="clear:left"></div>
<div class="paragraph"><p>In Pronto, there are two pieces of data that constitute your access policy
framework: The <strong>access model</strong> and the <strong>access keys</strong>.</p></div>
<div class="paragraph"><p>An access key, when assigned to a user, gives that user access to parts
of the site that require it.  The access model determines how the access
key structure will be interpreted and used.</p></div>
<div class="paragraph"><p>There are two primary <strong>access models</strong> in Pronto: <strong>roles</strong> and <strong>discrete</strong>.
In both models, your <strong>access keys</strong> will be an associative array of
<em>keys</em> and <em>values</em>.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">Unfortunately, the term <em>key</em> is used for two meanings here: as an
access key, and as an array key.  Pay close attention to which one we&#8217;re
talking about.</td>
</tr></table>
</div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 7: Access Models</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><strong>roles</strong></p></td>
<td align="left" valign="top"><p class="table">Within your access key set, each array key is a role or group name, and the array value is an array of access keys (strings) that will be assigned to that role.  A user can be assigned to zero or more roles.  The role names themselves should be stored in the DB record for the user.  At login time, they will be resolved to the individual access keys and assigned.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><strong>discrete</strong></p></td>
<td align="left" valign="top"><p class="table">The structure of your access key set is the same as in the <strong>roles</strong> model. However, in this model, the actual keys themselves should be assigned to the user within the DB, so you can pick and choose which keys from which modules get assigned.  This provides a higher level of control for each user, but is slightly more complicated to conceptualize and implement.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>If you&#8217;re not sure which one to use, start with the <strong>roles</strong> model.
Conceptually, it is simpler, analagous to assigning a "rank" to each user
in the system.</p></div>
<div class="paragraph"><p>Both the <strong>access model</strong> and the <strong>access_keys</strong> are configured in
<tt>app/config/access.php</tt>.</p></div>
<div class="listingblock">
<div class="title">A default access policy</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>

<span style="font-weight: bold"><span style="color: #000000">define</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'ACCESS_MODEL'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'roles'</span><span style="color: #990000">);</span>

<span style="font-style: italic"><span style="color: #9A1900">// Though the roles model can support each user having more than one role,</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// our application will only assign one role per user.  If the user's</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// record says they are a "User", then we assign them the 'USER' access</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// key.  If they're marked as an "Administrator", then we assign them both</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// the 'USER' and the 'ADMIN' access keys.</span></span>

<span style="color: #009900">$ACCESS_KEYS</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">'User'</span>          <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">),</span>
        <span style="color: #FF0000">'Administrator'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">,</span><span style="color: #FF0000">'ADMIN'</span><span style="color: #990000">)</span>
<span style="color: #990000">);</span>

<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Once a user is logged in, Pronto&#8217;s access layer will set the
constant <tt>ACCESS_ID</tt> to the unique ID of that user.  You can use this
constant throughout the web application to check if a user is logged in
(regardless of access keys assigned) and to link entities to the logged-in
user.</p></div>
<div class="paragraph"><p>To protect your controllers (or actions within) against unauthorized
access, you can use the <tt>Web::check_access()</tt> and <tt>Access::has_access()</tt>
methods.</p></div>
<div class="listingblock">
<div class="title">Checking for valid access</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_edit_profile</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// check that this person has the 'USER' key... if not, then one of</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// two things will happen:</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">//   1. if the user isn't logged in, they'll be sent to the login page</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">//   2. if the user is logged in but doesn't have this key, they will</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">//      see a "403 Forbidden" page.</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">//</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>web<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">check_access</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">);</span>

                <span style="font-style: italic"><span style="color: #9A1900">// okay, they're logged in and they have the 'USER' access key, so</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// grab their profile data</span></span>
                <span style="color: #009900">$profile</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>user<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span>ACCESS_ID<span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'profile'</span><span style="color: #990000">,</span> <span style="color: #009900">$profile</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user/edit_profile.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>You can also use <tt>Access::has_access()</tt> if you merely want to see if the user
has valid access, but not act on the result.  There is also a global
shortcut function to <tt>Access::has_access()</tt> called <tt>a()</tt>, which can be used
anywhere in Pronto.</p></div>
<div class="listingblock">
<div class="title">Using Access::has_access()</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-style: italic"><span style="color: #9A1900">// All three methods below are equivalent</span></span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_stuff</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// fetch the access object from the registry</span></span>
                <span style="color: #009900">$access</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:access'</span><span style="color: #990000">);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>web<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">has_access</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
                        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">"You are allowed"</span><span style="color: #990000">;</span>
                <span style="color: #FF0000">}</span>

                <span style="font-style: italic"><span style="color: #9A1900">// the Web object contains a shortcut method to Access::has_access()</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>web<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">has_access</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
                        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">"You are allowed"</span><span style="color: #990000">;</span>
                <span style="color: #FF0000">}</span>

                <span style="font-style: italic"><span style="color: #9A1900">// this would do the same</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #000000">a</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
                        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">"You are allowed"</span><span style="color: #990000">;</span>
                <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h3 id="X7-2">8.2. User Authentication</h3><div style="clear:left"></div>
<div class="paragraph"><p>So now that we know how to test for proper access, how do we tell Pronto
that a user is authenticated?</p></div>
<div class="paragraph"><p>The <tt>$web</tt> object holds a reference to the <tt>Access</tt> class, which is the
brains of Pronto&#8217;s access control facility.  To set, get, or clear keys,
you can go through <tt>$web-&gt;access</tt> or get a reference to the object by
asking the registry.</p></div>
<div class="listingblock">
<div class="title">Getting an object from the Registry</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
        <span style="color: #009900">$access</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:access'</span><span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Let&#8217;s add a couple methods to our <tt>mUser</tt> model class that can handle
authentication.</p></div>
<div class="listingblock">
<div class="title">Authenticating a user</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Model
<span style="color: #FF0000">{</span>
        <span style="font-style: italic"><span style="color: #9A1900">/**</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         * Returns true if the user is authenticated, else returns an error</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         * string to be passed back to the browser.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         */</span></span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">authenticate</span></span><span style="color: #990000">(</span><span style="color: #009900">$email</span><span style="color: #990000">,</span> <span style="color: #009900">$password</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$user</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_item</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"SELECT * FROM users WHERE email='%s'"</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$email</span><span style="color: #990000">));</span>

                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(!</span><span style="color: #009900">$user</span><span style="color: #990000">)</span>                               <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #FF0000">'Invalid email/password'</span><span style="color: #990000">;</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'password'</span><span style="color: #990000">]</span> <span style="color: #990000">!=</span> <span style="font-weight: bold"><span style="color: #000000">sha1</span></span><span style="color: #990000">(</span><span style="color: #009900">$password</span><span style="color: #990000">))</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #FF0000">'Invalid email/password'</span><span style="color: #990000">;</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'status'</span><span style="color: #990000">]</span> <span style="color: #990000">!=</span> <span style="color: #FF0000">'active'</span><span style="color: #990000">)</span>          <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #FF0000">'This account is not active'</span><span style="color: #990000">;</span>

                <span style="font-style: italic"><span style="color: #9A1900">// Okay, everything checks out, so assign the user's access id and</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// his/her keys...</span></span>
                <span style="color: #009900">$access</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:access'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$access</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_id</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">]);</span>
                <span style="color: #009900">$access</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_keys</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'access_keys'</span><span style="color: #990000">]);</span>

                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">execute</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"UPDATE users SET last_login=CURDATE() WHERE id=%i"</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">]));</span>

                <span style="font-style: italic"><span style="color: #9A1900">// Now we'll store the user's record in the session so we don't have</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// to fetch it from the DB each time</span></span>
                <span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #009900">$user</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">]);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> true<span style="color: #990000">;</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">clear_authentication</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$access</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:access'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$access</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">clear_authentication</span></span><span style="color: #990000">();</span>
                <span style="font-weight: bold"><span style="color: #0000FF">unset</span></span><span style="color: #990000">(</span><span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'USER'</span><span style="color: #990000">]);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>As you can see, we&#8217;ve stored the user&#8217;s access in a database column called
<tt>access_keys</tt>.  It&#8217;s just a <tt>VARCHAR</tt> field, so it could be a
comma-delimited list of keys if we chose to use the <strong>discrete</strong> access
model instead.  Our <tt>authenticate</tt> method above will work for both models,
but we&#8217;ll stick with <strong>roles</strong> for now.</p></div>
<div class="paragraph"><p>When a user logs out, we call the model&#8217;s <tt>clear_authentication</tt> method,
which in turn calls the one in <tt>$access</tt>, which will clear out the
user&#8217;s access id and access keys, returning them to a "visitor" state,
completely unauthenticated.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">To track access variables across page loads, Pronto uses a special session
variable called <tt>_ACCESS</tt> to store them.  You can see what this looks like
by throwing this in a page controller: <tt>debug($_SESSION['_ACCESS']);</tt></td>
</tr></table>
</div>
</div>
<h2 id="X8">9. Specialized Controllers</h2>
<div class="sectionbody">
<div class="paragraph"><p>The <tt>Page</tt> class is the one that you will extend most of your page
controllers from, but Pronto does provide a couple other page controller
classes that serve a more specialized purpose.  If their features appeal
to you, you can always extend your page controller from one of them.</p></div>
<div class="paragraph"><p>Currently there are only two specialized controllers.</p></div>
<h3 id="X8-1">9.1. The Static Controller</h3><div style="clear:left"></div>
<div class="paragraph"><p>The beautiful harmony of page controllers, models, and templates can be a
wonderful thing, but if all you want to do is render a simple template,
then it feels a little overkill to have to do something like this:</p></div>
<div class="listingblock">
<div class="title">The lame way of rendering static content</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pHome <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_about</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'home/about.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_contact</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'home/contact.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_features</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">render</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'home/features.php'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span></tt></pre></div></div>
<div class="paragraph"><p>This method works fine and still looks clean, but do we really need to
explicitly list each action when all we need to do is render the
corresponding template?</p></div>
<div class="paragraph"><p>No.  We can use the <tt>Page_Static</tt> class.</p></div>
<div class="listingblock">
<div class="title">The better way of rendering static content</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pHome <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page_Static
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// Set the template directory where all our templates live.</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// Once again, this is relative to the app/templates directory.</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_dir</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'home'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span></tt></pre></div></div>
<div class="paragraph"><p>Done.  Now, whenever a URL is routed to this page controller, it will
examine the URL and look for a corresponding template.  So if you surf to
<tt>/about</tt> in your application, the <tt>Page_Static</tt> class will look for a
<tt>about.php</tt> template in the directory set by the <tt>Page_Static::set_dir()</tt>
method.  If the template isn&#8217;t found, a 404 will be issued.</p></div>
<div class="paragraph"><p>To route URLs to your page server, you can simply put a "catch-all" at the
bottom of your routing table.</p></div>
<div class="listingblock">
<div class="title">Routing to the page server (<tt>app/config/urls.php</tt>)</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #009900">$URLS</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">'/user/(.*)'</span>       <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'User'</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">'/book/(.*)'</span>       <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Book'</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">'/login/'</span>          <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'login'</span><span style="color: #990000">),</span>
        <span style="color: #FF0000">'/logout/'</span>         <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'logout'</span><span style="color: #990000">),</span>

        <span style="font-style: italic"><span style="color: #9A1900">// send the rest to our Home controller</span></span>

        <span style="color: #FF0000">'/(.*)'</span>            <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Home'</span>
<span style="color: #990000">);</span></tt></pre></div></div>
<h3 id="X8-2">9.2. The CRUD Controller</h3><div style="clear:left"></div>
<div class="paragraph"><p>Most web developers recognize the common operations around a data entity.
We lovingly call them CRUD, and they stand for <strong>Create</strong>, <strong>Retrieve</strong>,
<strong>Update</strong>, and <strong>Delete</strong>.</p></div>
<div class="paragraph"><p>The <tt>Page_CRUD</tt> class provides a generic facility to fulfill these
operations.  It will provide the following actions:</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>GET_create()</tt></p></td>
<td align="left" valign="top"><p class="table">Render a create form</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>POST_create()</tt></p></td>
<td align="left" valign="top"><p class="table">Validate and insert a new record</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>GET_edit()</tt></p></td>
<td align="left" valign="top"><p class="table">Retrieve a record and populate it into a edit form (usually same template as the create one)</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>POST_edit()</tt></p></td>
<td align="left" valign="top"><p class="table">Validate and update an existing record</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>GET_delete()</tt></p></td>
<td align="left" valign="top"><p class="table">Delete a record</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>GET_list()</tt></p></td>
<td align="left" valign="top"><p class="table">List records</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>GET_file__preview()</tt></p></td>
<td align="left" valign="top"><p class="table">If a file is associated with the record, this optional method can be used to preview it.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>GET_file__remove()</tt></p></td>
<td align="left" valign="top"><p class="table">If a file is associated with the record, this optional method can delete it.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>Of course, like any page controller, you can override these actions and/or
add your own if the basic <tt>Page_CRUD</tt> ones do not fulfill your needs.</p></div>
<h4 id="X8-2-a">9.2.1. Setting the Entity</h4>
<div class="paragraph"><p>When using <tt>Page_CRUD</tt>, the first thing you need to do is to tell it which
entity it should be managing.  This is done with the
<tt>Page_CRUD::set_entity()</tt> method.</p></div>
<div class="listingblock">
<div class="title">Setting up Page_CRUD</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pBook <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page_CRUD
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// First import the model...</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">);</span>

                <span style="font-style: italic"><span style="color: #9A1900">// This tells Page_CRUD to use the 'book' model, and to use the human</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// name "Book" when referencing the entity in human-readable messages.</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_entity</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Book'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Technically, this is all that&#8217;s required at the controller level.
<tt>Page_CRUD</tt> will implement the actions described in the table above and it
will render templates in the <tt>app/templates/&lt;entity_name&gt;</tt> directory.</p></div>
<div class="paragraph"><p>Even though <tt>Page_CRUD</tt> will do the controller logic for you, you still
have to create the templates yourself, as they will certainly vary from
entity to entity.  Use the <a href="#X8-2-d">CRUD generator</a> to automate this task.</p></div>
<h4 id="X8-2-b">9.2.2. Controlling Access to Actions</h4>
<div class="paragraph"><p>Most entities should be protected by some sort of access checks.  Since
<tt>Page_CRUD</tt> handles most of the actions for us, we can&#8217;t insert a call to
<tt>$this-&gt;web-&gt;check_access()</tt> in each one.  Instead, simply override the
<tt>Page_CRUD::authenticate()</tt> method.</p></div>
<div class="listingblock">
<div class="title">Protecting CRUD operations</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pBook <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page_CRUD
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_entity</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Book'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">authenticate</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>web<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">check_access</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'ADMIN'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>If various operations will require different access, then you can use the
<tt>auth_*</tt> methods instead.  There are three.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 8: Operation-specific CRUD authentication methods</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>auth_create()</tt></p></td>
<td align="left" valign="top"><p class="table">Called for <strong>create</strong> and <strong>edit</strong> operations</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>auth_delete()</tt></p></td>
<td align="left" valign="top"><p class="table">Called for <strong>delete</strong> operations</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>auth_list()</tt></p></td>
<td align="left" valign="top"><p class="table">Called for <strong>list</strong> operations</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>In some circumstances, you may actually want to block access to certain
operations of <tt>Page_CRUD</tt> while allowing the rest.  There are two ways to
do this.  You can either override the specific actions with empty methods,
or you can change the value of the <tt>$enabled_actions</tt> instance variable.</p></div>
<div class="listingblock">
<div class="title">Disabling specific operations</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pBook <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page_CRUD
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_entity</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Book'</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// we'll leave out 'delete' and 'edit' to disable them</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>enabled_actions <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'create'</span><span style="color: #990000">,</span><span style="color: #FF0000">'list'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h4 id="X8-2-c">9.2.3. Process Hooks</h4>
<div class="paragraph"><p><tt>Page_CRUD</tt> does a good job at covering the fundamental operations of a
data entity.  However, every entity is different, and there are often
times when you need to add a little code at certain points in the process.</p></div>
<div class="paragraph"><p>In Pronto parlance, this points are called <strong>process hooks</strong>.  There are a
number process hooks that <tt>Page_CRUD</tt> uses.  To access one of them, you
simply need to implement that particular method name in your controller
class.</p></div>
<div class="paragraph"><p>Listed below are all the process hooks available to the <tt>Page_CRUD</tt> class.
Their names are rough indication of when they are called within each
process, but it&#8217;s recommended that you consult the actual code in
<tt>pronto/core/page_crud.php</tt> to see the exact points at which each hook is
called.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 9: CRUD process hooks</caption>
<col width="50%" />
<col width="50%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook__pre_edit</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong>/<strong>edit</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook__failed_validation</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong>/<strong>edit</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook__pre_save</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong>/<strong>edit</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook__post_save</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong>/<strong>edit</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_create__pre_edit</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_create__failed_validation</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_edit__pre_edit</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>edit</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_edit__failed_validation</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>edit</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_insert__pre_save</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_insert__post_save</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>create</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_update__pre_save</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>update</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_update__post_save</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>update</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_delete__pre_delete</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>delete</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_delete__post_delete</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>delete</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_list__params</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>list</strong></p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>hook_list__post_select</tt></p></td>
<td align="left" valign="top"><p class="table"><strong>list</strong></p></td>
</tr>
</tbody>
</table>
</div>
<div class="listingblock">
<div class="title">Using process hooks</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pBook <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page_CRUD
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">,</span><span style="color: #FF0000">'category'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_entity</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Book'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">hook__pre_edit</span></span><span style="color: #990000">(&amp;</span><span style="color: #009900">$data</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// Each book belongs to a category, so we have to pull a list</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// of them and pass them to the template so we can populate</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// the dropdown widget.</span></span>
                <span style="color: #009900">$cats</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>category<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_list</span></span><span style="color: #990000">();</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'categories'</span><span style="color: #990000">,</span> <span style="color: #009900">$cats</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">hook__pre_save</span></span><span style="color: #990000">(&amp;</span><span style="color: #009900">$data</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// If we want, we can actually change things in the current record</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// before they are passed to the template.</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">//</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// This should probably be in the model itself, but we'll put here for</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// example's sake.</span></span>
                <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'last_edited_by'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> ACCESS_ID<span style="color: #990000">;</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span></tt></pre></div></div>
<h4 id="X8-2-d">9.2.4. Using the CRUD generator</h4>
<div class="paragraph"><p>The <tt>Page_CRUD</tt> class can greatly speed up development.  While it serves
as a great scaffolding method in early stages of development, it&#8217;s also
featureful enough to work with entities in later development and
production.</p></div>
<div class="paragraph"><p>But for each entity, you still have to manually create your page
controller, your model, and your two template files (one for
creating/editing and one for listing).</p></div>
<div class="paragraph"><p>Fear not, lazy coder.  The CRUD generator can do the mundane part for you.
It will create these four files for you from a template, so all you need
to do is modify them to suit the entity you&#8217;re CRUD&#8217;ing.</p></div>
<div class="paragraph"><p>The CRUD generator is a PHP script intended to be run from the
commandline.  It takes at least two arguments, <tt>entity</tt> and <tt>db_table</tt>.
<tt>entity</tt> tells it the name of the entity it is generating files for, and
<tt>db_table</tt> tells it which database table it should use for basic
introspection.</p></div>
<div class="paragraph"><p>The generator will then look at all the columns in the database table and
use this data to build form and grid widgets for you.  They won&#8217;t be very
useful right out of the box, but it&#8217;s much quicker to tweak an existing
template than it is to create one from scratch.</p></div>
<div class="paragraph"><p>Let&#8217;s look at an example. The first thing we do is create the database
table.  Here is our database schema for the purposes of this example:</p></div>
<div class="listingblock">
<div class="title">Our "books" table</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">CREATE</span></span> <span style="font-weight: bold"><span style="color: #0000FF">TABLE</span></span> <span style="color: #FF0000">"books"</span> <span style="color: #990000">(</span>
    <span style="color: #FF0000">"id"</span> <span style="color: #009900">INT</span> <span style="color: #009900">UNSIGNED</span> <span style="font-weight: bold"><span style="color: #0000FF">NOT</span></span> <span style="font-weight: bold"><span style="color: #0000FF">NULL</span></span> <span style="font-weight: bold"><span style="color: #0000FF">AUTO_INCREMENT</span></span><span style="color: #990000">,</span>

    <span style="color: #FF0000">"title"</span> <span style="color: #009900">VARCHAR</span><span style="color: #990000">(</span><span style="color: #993399">128</span><span style="color: #990000">)</span> <span style="font-weight: bold"><span style="color: #0000FF">NOT</span></span> <span style="font-weight: bold"><span style="color: #0000FF">NULL</span></span><span style="color: #990000">,</span>
    <span style="color: #FF0000">"category"</span> <span style="color: #009900">VARCHAR</span><span style="color: #990000">(</span><span style="color: #993399">128</span><span style="color: #990000">)</span> <span style="font-weight: bold"><span style="color: #0000FF">NOT</span></span> <span style="font-weight: bold"><span style="color: #0000FF">NULL</span></span><span style="color: #990000">,</span>
    <span style="color: #FF0000">"author"</span> <span style="color: #009900">VARCHAR</span><span style="color: #990000">(</span><span style="color: #993399">128</span><span style="color: #990000">)</span> <span style="font-weight: bold"><span style="color: #0000FF">NOT</span></span> <span style="font-weight: bold"><span style="color: #0000FF">NULL</span></span><span style="color: #990000">,</span>
    <span style="color: #FF0000">"excerpt"</span> <span style="color: #009900">MEDIUMTEXT</span> <span style="font-weight: bold"><span style="color: #0000FF">NOT</span></span> <span style="font-weight: bold"><span style="color: #0000FF">NULL</span></span><span style="color: #990000">,</span>

    <span style="color: #FF0000">"created_on"</span> <span style="color: #009900">DATE</span> <span style="font-weight: bold"><span style="color: #0000FF">NOT</span></span> <span style="font-weight: bold"><span style="color: #0000FF">NULL</span></span><span style="color: #990000">,</span>
    <span style="color: #FF0000">"status"</span> <span style="color: #009900">ENUM</span><span style="color: #990000">(</span><span style="color: #FF0000">'active'</span><span style="color: #990000">,</span><span style="color: #FF0000">'deleted'</span><span style="color: #990000">)</span> <span style="font-weight: bold"><span style="color: #0000FF">NOT</span></span> <span style="font-weight: bold"><span style="color: #0000FF">NULL</span></span> <span style="font-weight: bold"><span style="color: #0000FF">DEFAULT</span></span> <span style="color: #FF0000">'active'</span><span style="color: #990000">,</span>

    <span style="font-weight: bold"><span style="color: #0000FF">PRIMARY</span></span> <span style="font-weight: bold"><span style="color: #0000FF">KEY</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"id"</span><span style="color: #990000">),</span>
    <span style="font-weight: bold"><span style="color: #0000FF">KEY</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"title"</span><span style="color: #990000">)</span>
<span style="color: #990000">)</span> <span style="font-weight: bold"><span style="color: #0000FF">DEFAULT</span></span> CHARACTER <span style="font-weight: bold"><span style="color: #0000FF">SET</span></span> utf8 COLLATE utf8_general_ci<span style="color: #990000">;</span></tt></pre></div></div>
<div class="paragraph"><p>Now let&#8217;s use the CRUD generator to bootstrap this entity.</p></div>
<div class="listingblock">
<div class="title">Using the CRUD generator</div>
<div class="content">
<pre><tt>$ php pronto/bin/generators/crud/generate.php book books
Entity:   book
DB Table: books

Examining DB table for data introspection...

New Model:           models/book.php
New Page Controller: pages/book.php
New Template:        templates/book/list.php
New Template:        templates/book/create.php</tt></pre>
</div></div>
<div class="paragraph"><p>Voila.  Take a look at the files the generator outputs and you&#8217;ll see you
have the basic functionality for this entity already done for you.  It
uses the <tt>tpTable</tt> and <tt>tpForm</tt> template plugins to build forms and grids
for you.</p></div>
<div class="paragraph"><p>The generator can&#8217;t be smart enough to style your forms/grids and to know
which fields should be which data types, etc.  This is where your tweaking
skills come in.  Modify the files to complete the functionality and
carry on the to the next entity.  Both the <tt>tpTable</tt> and <tt>tpForm</tt> plugins
support a number of customizations and control, but if they don&#8217;t suit
your needs, you can always do things the old-fashioned way.</p></div>
</div>
<h2 id="X9">10. Plugins</h2>
<div class="sectionbody">
<div class="paragraph"><p>Pronto makes avid use of plugins both at the <strong>controller</strong> and the
<strong>template</strong> layers.  The interface between controllers/templates and their
plugins is very light, so you&#8217;re free to use them in pretty much any way
you want.</p></div>
<div class="paragraph"><p>In Pronto parlance, plugins at the template layer are called template
plugins or <strong>helpers</strong>.  Plugins at the controller layer are called page
plugins or simply <strong>plugins</strong>.</p></div>
<div class="paragraph"><p>You can control which plugins are active by changing the <tt>PLUGINS</tt>
and <tt>HELPERS</tt> values in <tt>app/config/config.php</tt>.</p></div>
<div class="paragraph"><p>To access a loaded plugin from within a page controller, simply reference
its name through <tt>$this-&gt;plugins</tt>.</p></div>
<div class="listingblock">
<div class="title">Accessing a page plugin</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_send_email</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$email</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">param</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'email'</span><span style="color: #990000">);</span>
                <span style="font-style: italic"><span style="color: #9A1900">// use the 'mailer' page plugin</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>plugins<span style="color: #990000">-&gt;</span>mailer<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">send</span></span><span style="color: #990000">(</span><span style="color: #009900">$email</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Hello World'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Hello from Pronto!'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>To access a helper from within a template, simply reference it as
if it were a regular template variable (though it will be an object).</p></div>
<div class="listingblock">
<div class="title">Accessing a template plugin</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;p&gt;</span></span>We're in a template<span style="font-weight: bold"><span style="color: #0000FF">&lt;/p&gt;</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">&lt;p&gt;</span></span>Here is a link: &lt;?php echo $html-&gt;link('Go Home', url('/')) ?&gt;<span style="font-weight: bold"><span style="color: #0000FF">&lt;/p&gt;</span></span></tt></pre></div></div>
<h3 id="X9-1">10.1. Template Plugins</h3><div style="clear:left"></div>
<div class="paragraph"><p>There are currently six helpers included with Pronto.  Each class name is
prefixed with a <tt>tp</tt>.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 10: Helpers</caption>
<col width="20%" />
<col width="80%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>tpHTML</tt></p></td>
<td align="left" valign="top"><p class="table">Convenience methods for basic HTML elements: URLs, Links, JS, CSS, etc.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>tpForm</tt></p></td>
<td align="left" valign="top"><p class="table">Generate individual form elements and full, tableless forms</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>tpTable</tt></p></td>
<td align="left" valign="top"><p class="table">Generate simple data tables and full-featured grids for record listings</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>tpAJAX</tt></p></td>
<td align="left" valign="top"><p class="table">Some AJAX-y functionality such as modal dialogs</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>tpNavigation</tt></p></td>
<td align="left" valign="top"><p class="table">Generate a two-tiered, tabbed navigation menu</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>tpPager</tt></p></td>
<td align="left" valign="top"><p class="table">Generate a pager control for enumerating records</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>We will cover each of these in brief.  For a more thorough understanding,
it&#8217;s not a bad idea to examine the API docs or the plugin code itself.</p></div>
<h4 id="X9-1-a">10.1.1. The <tt>html</tt> Plugin</h4>
<div class="paragraph"><p>Most of the methods in the <tt>html</tt> plugin are pretty self-explanatory.  The
API Reference will probably serve you best.</p></div>
<div class="paragraph"><p>The more interesting methods in this plugin are probably the Javascript
and CSS queuing methods.  These methods can insert Javascript files/code
or CSS files into a document, without having to resort to setting more
variables in your template layout.</p></div>
<div class="paragraph"><p>The best part is that these queueing mechanisms will work with regular
<em>and</em> AJAX reponses, so you can code your templates in an agnostic
fashion, without having to worry how they&#8217;ll be rendered.  Bonus!</p></div>
<div class="paragraph"><p>All code chunks use a basic key/value hash method, which ensures that
files are not loaded more than once per page, as long as you are
consistent with your key names.</p></div>
<div class="listingblock">
<div class="title">Using the queueing methods</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
        <span style="font-style: italic"><span style="color: #9A1900">// If this is a regular response, all this stuff will show up in</span></span>
        <span style="font-style: italic"><span style="color: #9A1900">// the document &lt;head&gt;.  If it's an AJAX response, then it will</span></span>
        <span style="font-style: italic"><span style="color: #9A1900">// be loaded dynamically.</span></span>

        <span style="font-style: italic"><span style="color: #9A1900">// this will load css/style.css (autogenerated key)</span></span>
        <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">css_load</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'style'</span><span style="color: #990000">);</span>

        <span style="font-style: italic"><span style="color: #9A1900">// this will load js/stuff.js with a key of "misc"</span></span>
        <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">js_load</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'misc'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'stuff'</span><span style="color: #990000">);</span>

        <span style="font-style: italic"><span style="color: #9A1900">// execute a little chunk of JS (the blank key means Pronto will</span></span>
        <span style="font-style: italic"><span style="color: #9A1900">// autogenerate one)</span></span>
        <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">js_run</span></span><span style="color: #990000">(</span><span style="color: #FF0000">''</span><span style="color: #990000">,</span> <span style="color: #FF0000">"alert('Hello World!');"</span><span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h4 id="X9-1-b">10.1.2. The <tt>form</tt> Plugin</h4>
<div class="paragraph"><p>The <tt>form</tt> plugin is used to build fully-functional forms or to generate
individual form elements.  It&#8217;s pretty smart and robust, but don&#8217;t expect
it to be smart enough to generate every fancy form you can think of.</p></div>
<div class="listingblock">
<div class="title">Generating an individual form element</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>Username<span style="color: #990000">:</span> <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$form</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">text</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'username'</span><span style="color: #990000">)</span> <span style="color: #990000">?&gt;&lt;</span>br <span style="color: #990000">/&gt;</span>
Password<span style="color: #990000">:</span> <span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$form</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">password</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'password'</span><span style="color: #990000">)</span> <span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>What&#8217;s the advantage of this over typing out the raw HTML?  It may save
you a few seconds, but it can also do a few other things to save you time.
If you open a new form (with <tt>tpForm::open_form()</tt>) you can preload your
form with any relevant error messages, and they will be displayed
beside/below their respective form elements.</p></div>
<div class="paragraph"><p>Also, using a structured interface like this allows us to build full forms
without carving out the HTML ourselves.  <tt>tpForm::build_form()</tt> will
generate tableless HTML.</p></div>
<div class="listingblock">
<div class="title">A basic single-column form</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-style: italic"><span style="color: #9A1900">// 'action'   will be used for the form's "action=" attribute.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'submit'   contains two strings used as labels for the Submit button, one</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            for the creation of a new item and one for the update of an</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            existing one.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'data_id'  points to the PK of this entity, so build_form() knows if it</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            is updating or creating.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'layout'   defines the columnar layout of the resulting form.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'elements' is a sub-array that describes the elements that will be used</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            in this form (can be separated into multiple columns).</span></span>

<span style="color: #009900">$f</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">'action'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span>CURRENT_URL<span style="color: #990000">),</span>
        <span style="color: #FF0000">'submit'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Create User'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Update User'</span><span style="color: #990000">),</span>
        <span style="color: #FF0000">'data_id'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">],</span>
        <span style="color: #FF0000">'layout'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                <span style="color: #FF0000">'col1'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'colspan'</span><span style="color: #990000">=&gt;</span><span style="color: #993399">1</span><span style="color: #990000">,</span> <span style="color: #FF0000">'label_width'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'auto'</span><span style="color: #990000">),</span>
                <span style="color: #FF0000">'col2'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'colspan'</span><span style="color: #990000">=&gt;</span><span style="color: #993399">1</span><span style="color: #990000">,</span> <span style="color: #FF0000">'label_width'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'auto'</span><span style="color: #990000">),</span>
        <span style="color: #990000">),</span>
        <span style="color: #FF0000">'elements'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                <span style="color: #FF0000">'col1'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                        <span style="color: #FF0000">'first_name'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'prompt'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'First Name:'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'text'</span><span style="color: #990000">),</span>
                        <span style="color: #FF0000">'last_name'</span>   <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'prompt'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Last Name:'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'text'</span><span style="color: #990000">),</span>
                        <span style="color: #FF0000">'email'</span>       <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'prompt'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Email Address:'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'text'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'help'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Email address must be unique.'</span><span style="color: #990000">),</span>
                <span style="color: #990000">),</span>
                <span style="color: #FF0000">'col2'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                        <span style="color: #FF0000">'language'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'prompt'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">__</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Language:'</span><span style="color: #990000">),</span> <span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'select'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'options'</span><span style="color: #990000">=&gt;</span><span style="color: #009900">$languages</span><span style="color: #990000">),</span>
                        <span style="color: #FF0000">'password'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'prompt'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">__</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Login Password:'</span><span style="color: #990000">),</span> <span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'password'</span><span style="color: #990000">),</span>
                        <span style="color: #FF0000">'password2'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'prompt'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">__</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Confirm Password:'</span><span style="color: #990000">),</span> <span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'password'</span><span style="color: #990000">),</span>
                <span style="color: #990000">),</span>
        <span style="color: #990000">)</span>
<span style="color: #990000">);</span>

<span style="font-style: italic"><span style="color: #9A1900">// along with the form definition, we pass build_form() the form data and</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// any relevant errors, so it can prefill data and position errors</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// accordingly.</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$form</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">build_form</span></span><span style="color: #990000">(</span><span style="color: #009900">$f</span><span style="color: #990000">,</span> <span style="color: #009900">$data</span><span style="color: #990000">,</span> <span style="color: #009900">$errors</span><span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p><tt>tpForm::build_form()</tt> is the plugin&#8217;s main method.  It will construct the
various <tt>&lt;form&gt;</tt> and <tt>&lt;div&gt;</tt> tags for the form, then call the individual
form element generators for each element, depending on the value of the
<tt>type</tt> field within each element of the <tt>elements</tt> sub-array.</p></div>
<div class="paragraph"><p>There are many more options that can be provided to the <tt>build_form()</tt>
method, both at the form level and at the element level.  We suggest you
read through the code and comments in <tt>pronto/plugins/template/form.php</tt>
to see them.  Also consult the example applications provided on the Pronto
website, as they can elucidate.</p></div>
<h4 id="X9-1-c">10.1.3. The <tt>table</tt> Plugin</h4>
<div class="paragraph"><p>The <tt>table</tt> plugin only provides two primary methods: <tt>build_table()</tt> and
<tt>build_grid()</tt>.</p></div>
<div class="paragraph"><p><tt>tpTable::build_table()</tt> is just a dumb table generator, but can be useful
for assembling simple tables.  It will handle zebra-coloured rows and a
highlighting hover effect.</p></div>
<div class="paragraph"><p><tt>tpTable::build_grid()</tt> is another table generator, but it generates what
we call a <strong>grid</strong>.  A <strong>grid</strong> is a smarter table, one that provides sorting,
filtering, pagination, and totals.</p></div>
<div class="paragraph"><p>Grid definitions somewhat resemble the form definitions we saw in the
<tt>tpForm::build_form()</tt> example.  We&#8217;ll pass one giant array to
<tt>tpTable::build_grid()</tt> and it will figure out what goes where.</p></div>
<div class="listingblock">
<div class="title">A grid for record listings</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;</span>h1<span style="color: #990000">&gt;</span>Users<span style="color: #990000">&lt;/</span>h1<span style="color: #990000">&gt;</span>

<span style="color: #990000">&lt;?php</span>
<span style="font-style: italic"><span style="color: #9A1900">// 'options'  is an array that contains options that override default grid</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            behavior.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'columns'  is the primary sub-array - it defines each column, what data</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            it will be using, and what sort of search filter to use.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            The special '_OPTIONS_' column contains action icons that</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            can be clicked on to operate on specific rows.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'data'     is the actual record data we're listing, probably passed to</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            us from a GET_list() action.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'perpage'  tells the grid how many records to display per page.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'curpage'  tells the grid what page we're currently on.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 'rows'     tells the grid how many total rows there are so it can build</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//            the pagination links accordingly.</span></span>

<span style="color: #009900">$t</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">'options'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'ajax'</span><span style="color: #990000">=&gt;</span>true<span style="color: #990000">),</span>
        <span style="color: #FF0000">'columns'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                <span style="color: #FF0000">'_OPTIONS_'</span>   <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                        <span style="color: #FF0000">'edit'</span>   <span style="color: #990000">=&gt;</span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">link</span></span><span style="color: #990000">(</span><span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">image</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'icons/edit.gif'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'title'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Edit User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'class'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'ajax_action'</span><span style="color: #990000">)),</span> <span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'edit'</span><span style="color: #990000">).</span><span style="color: #FF0000">'?id=&lt;id&gt;'</span><span style="color: #990000">),</span>
                        <span style="color: #FF0000">'delete'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">link</span></span><span style="color: #990000">(</span><span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">image</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'icons/delete.gif'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'title'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Delete User'</span><span style="color: #990000">)),</span> <span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'delete'</span><span style="color: #990000">).</span><span style="color: #FF0000">'?id=&lt;id&gt;'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Are you sure?'</span><span style="color: #990000">)),</span>
                <span style="color: #FF0000">'first_name'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'label'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'First Name'</span><span style="color: #990000">),</span>
                <span style="color: #FF0000">'last_name'</span>   <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'label'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Last Name'</span><span style="color: #990000">),</span>
                <span style="color: #FF0000">'email'</span>       <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'label'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Email'</span><span style="color: #990000">),</span>
                <span style="color: #FF0000">'language'</span>    <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'label'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Language'</span><span style="color: #990000">,</span><span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'select'</span><span style="color: #990000">,</span><span style="color: #FF0000">'options'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'en'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'English'</span><span style="color: #990000">,</span><span style="color: #FF0000">'fr'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'French'</span><span style="color: #990000">)),</span>
                <span style="color: #FF0000">'last_login'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'label'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Last Login'</span><span style="color: #990000">,</span><span style="color: #FF0000">'type'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'date'</span><span style="color: #990000">,</span><span style="color: #FF0000">'display_map'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'0000-00-00'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Never'</span><span style="color: #990000">))</span>
        <span style="color: #990000">),</span>
        <span style="color: #FF0000">'data'</span>    <span style="color: #990000">=&gt;</span> <span style="color: #009900">$data</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">'perpage'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$perpage</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">'curpage'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$curpage</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">'rows'</span>    <span style="color: #990000">=&gt;</span> <span style="color: #009900">$totalrows</span>
<span style="color: #990000">));</span>

<span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$table</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">build_grid</span></span><span style="color: #990000">(</span><span style="color: #009900">$t</span><span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Most of this is hopefully self-explanatory, but there are a couple
interesting points.  Firstly, you can see we&#8217;ve enable "AJAX mode" for
this grid.  This means that any links that hava class of <tt>ajax_action</tt>
will be treated as an AJAX request instead of a regular one.  When
clicked, the data will be fetched through an AJAX channel and populated
<em>within</em> the grid itself, incurring no page loads.</p></div>
<div class="paragraph"><p>Also, notice how we&#8217;re generating our relative URLs for the "edit" and
"delete" actions:</p></div>
<div class="listingblock">
<div class="title">Dynamic URL Generation</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>        <span style="color: #FF0000">'edit'</span>   <span style="color: #990000">=&gt;</span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">link</span></span><span style="color: #990000">(</span><span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">image</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'icons/edit.gif'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'title'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Edit User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'class'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'ajax_action'</span><span style="color: #990000">)),</span> <span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'edit'</span><span style="color: #990000">).</span><span style="color: #FF0000">'?id=&lt;id&gt;'</span><span style="color: #990000">),</span>
        <span style="color: #FF0000">'delete'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">link</span></span><span style="color: #990000">(</span><span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">image</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'icons/delete.gif'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'title'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'Delete User'</span><span style="color: #990000">)),</span> <span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'User'</span><span style="color: #990000">,</span><span style="color: #FF0000">'delete'</span><span style="color: #990000">).</span><span style="color: #FF0000">'?id=&lt;id&gt;'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Are you sure?'</span><span style="color: #990000">)),</span></tt></pre></div></div>
<div class="paragraph"><p>We&#8217;re using the globally-available <tt>url()</tt> function in its second context,
which can take a controller/action pair and generate a valid URL for it.
Then we append the variable portion of the URL, such as <tt>?id=&lt;id&gt;</tt>.  The
<tt>&lt;id&gt;</tt> token will be replaced with the <tt>id</tt> element of the record that
is displayed on this line of the grid.  You&#8217;re free to use other elements
as well.</p></div>
<div class="paragraph"><p>For example, if you want to use SEO-friendly URLs for your blog, you may
want to use a "slug" in the article URL instead of a numeric ID.  Assuming you
have a column in your table called "slug" that stores this, you could generate
an URL like so:</p></div>
<div class="listingblock">
<div class="title">A new URL pattern</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$html</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">link</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Read Article'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Article'</span><span style="color: #990000">,</span><span style="color: #FF0000">'view'</span><span style="color: #990000">).</span><span style="color: #FF0000">'/&lt;slug&gt;'</span><span style="color: #990000">);</span></tt></pre></div></div>
<div class="paragraph"><p>Depending on your URL route configuration (set in <tt>app/config/urls.php</tt>),
the generated URL would look something like this:
<tt>/article/view/My_Article_Slug</tt>.</p></div>
<div class="paragraph"><p>The final interesting activity in this grid is the use of the
<tt>display_map</tt> directive in the <tt>last_login</tt> column.  Using this, we can
override the default display behavior of that column for specific values.
We pass in an array of key/values.  If the record&#8217;s value is found within
the array keys, then the corresponding array value will be displayed
instead.  We use this to display "Never" instead of "0000-00-00" if that
user has never logged in.</p></div>
<div class="paragraph"><p>Like <tt>tpForm::build_form()</tt>, there are many more options available, and
it&#8217;s best to consult the API documentation, examples apps, or the code
itself to see how they work.</p></div>
<h4 id="X9-1-d">10.1.4. The <tt>ajax</tt> Plugin</h4>
<div class="paragraph"><p>The <tt>ajax</tt> plugin provides widgets that have an AJAX/DHTML element to
them, such as a find-as-you-type autocomplete widget or a modal dialog
window.</p></div>
<div class="paragraph"><p>See the API Reference for a list of all methods in this plugin.  As an
example, here&#8217;s a way of displaying a little popup next to the item that
triggered it, then loading new content into the popup based on the button
clicked.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">We&#8217;ll skip the controller logic for now and just show you the templates,
since that&#8217;s the focus of this section.</td>
</tr></table>
</div>
<div class="listingblock">
<div class="title">Hot popup action: the main template</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;</span>div id<span style="color: #990000">=</span><span style="color: #FF0000">"mypop"</span> <span style="font-weight: bold"><span style="color: #0000FF">class</span></span><span style="color: #990000">=</span><span style="color: #FF0000">"popup"</span><span style="color: #990000">&gt;</span>
        Do you want to proceed<span style="color: #990000">?</span>
<span style="color: #990000">&lt;/</span>div<span style="color: #990000">&gt;</span>

<span style="color: #990000">&lt;</span>div<span style="color: #990000">&gt;</span>
        <span style="color: #990000">&lt;</span>a href<span style="color: #990000">=</span><span style="color: #FF0000">"#"</span> id<span style="color: #990000">=</span><span style="color: #FF0000">"pop_link"</span><span style="color: #990000">&gt;</span>Pop It<span style="color: #990000">!&lt;/</span>a<span style="color: #990000">&gt;</span>
        <span style="color: #990000">&lt;?php</span>
                <span style="color: #009900">$ajax</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">popup_bind</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'mypop'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'#pop_link'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                        <span style="color: #FF0000">'OK'</span>     <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'action'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'ajax_load'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'url'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/proceed'</span><span style="color: #990000">)),</span>
                        <span style="color: #FF0000">'Cancel'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'action'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'close'</span><span style="color: #990000">)</span>
                <span style="color: #990000">));</span>
        <span style="color: #990000">?&gt;</span>
<span style="color: #990000">&lt;/</span>div<span style="color: #990000">&gt;</span></tt></pre></div></div>
<div class="listingblock">
<div class="title">Hot popup action: the template rendered if "OK" is clicked</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>You proceeded<span style="color: #990000">!</span>  What a brave soul<span style="color: #990000">.</span>
<span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$ajax</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">popup_buttons</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Close'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'action'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'close'</span><span style="color: #990000">))</span> <span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>The <tt>ajax</tt> plugin is still in a state of flux, but its modest offering has
already proven to be very useful for building rich user interfaces.</p></div>
<h4 id="X9-1-e">10.1.5. The <tt>navigation</tt> Plugin</h4>
<div class="paragraph"><p>The <tt>navigation</tt> plugin provides a simple method of defining and rendering
a two-level nagivation menu.  It&#8217;s understood that most applications will
have a customized public-facing layout, but many applications may want to
use the default Pronto layout for the private backend/administration
section.  The <tt>navigation</tt> plugin works nicely for administration menus.</p></div>
<div class="paragraph"><p>You can configure the navigation menu by editing
<tt>app/config/navigation.php</tt>.</p></div>
<div class="listingblock">
<div class="title">A basic navigation menu</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="color: #009900">$NAV_MENU</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">'Home'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'access'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">''</span><span style="color: #990000">,</span> <span style="color: #FF0000">'url'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/'</span><span style="color: #990000">)),</span>
        <span style="color: #FF0000">'Users'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'access'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'ADMIN'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'menu'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
                <span style="color: #FF0000">'New'</span>   <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'url'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/user/create'</span><span style="color: #990000">)),</span>
                <span style="color: #FF0000">'List'</span>  <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'url'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/user/list'</span><span style="color: #990000">)))),</span>
        <span style="color: #FF0000">'Books'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'access'</span><span style="color: #990000">=&gt;</span><span style="color: #FF0000">'ADMIN'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'url'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/book/list'</span><span style="color: #990000">),</span> <span style="color: #FF0000">'base'</span><span style="color: #990000">=&gt;</span><span style="font-weight: bold"><span style="color: #000000">url</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'/book/'</span><span style="color: #990000">))</span>
<span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>As you can see, the array keys are the labels for each menu item, while
the value arrays define the destination URL, access requirements, and an
optional submenu.  Submenus can have infinite depth. You can also set the
<tt>base</tt> field which tells the plugin when to highlight a tab as the active
one.</p></div>
<div class="paragraph"><p>To render a navigation element, you simply call the <tt>menu()</tt> method from
within your template or layout.</p></div>
<div class="listingblock">
<div class="title">Rendering the navigation element</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span> <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$navigation</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">menu</span></span><span style="color: #990000">()</span> <span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h4 id="X9-1-f">10.1.6. The <tt>pager</tt> Plugin</h4>
<div class="paragraph"><p>Most web applications will, at some point, need to provide some sort of
record listing.  If there are many records to list, then it makes sense to
break these up into sections.  The <tt>pager</tt> plugin will render a pagination
control that creates links to other pages.</p></div>
<div class="listingblock">
<div class="title">Using the <tt>pager</tt> plugin</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-style: italic"><span style="color: #9A1900">// list some records</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">foreach</span></span><span style="color: #990000">(</span><span style="color: #009900">$data</span> <span style="font-weight: bold"><span style="color: #0000FF">as</span></span> <span style="color: #009900">$row</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">"{$row['name']}&lt;br /&gt;\n"</span><span style="color: #990000">;</span>
<span style="color: #FF0000">}</span>
<span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$pager</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">generate</span></span><span style="color: #990000">(</span>CURRENT_URL<span style="color: #990000">,</span> <span style="color: #993399">10</span><span style="color: #990000">,</span> <span style="color: #009900">$curpage</span><span style="color: #990000">,</span> <span style="color: #009900">$totalrow</span><span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>You can adjust the styling of the pagination control by modifying the
<tt>pagination</tt> classes in <tt>css/main.css</tt>.</p></div>
<h3 id="X9-2">10.2. Page Plugins</h3><div style="clear:left"></div>
<div class="paragraph"><p>Page plugins are just like template plugins except that they operate at
the page controller level.  As such, they have a little more leeway in
what they can do.  For example, if you really wanted, you could pass in
the <tt>$db</tt> object or some models and let them do some work with them, or
you might just use them to do some common tasks that you don&#8217;t want to
keep implementing in specific page controllers.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">While they are named "page plugins", these plugins are actually accessible
from data models as well.  In fact, they are stored in the global registry
and so can be used by anything that can access the registry, including
commandline scripts.  All plugins are stored in a <tt>stdClass</tt> object under
the registry key <tt>plugins</tt>.</td>
</tr></table>
</div>
<div class="paragraph"><p>There are currently six page plugins included with Pronto.  Each
page plugin class name is prefixed with a <tt>pp</tt>.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 11: Plugins</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>ppFile</tt></p></td>
<td align="left" valign="top"><p class="table">Handles file uploads that come through a &lt;form&gt;</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>ppImage</tt></p></td>
<td align="left" valign="top"><p class="table">Handles image uploads: format conversion and resizing</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>ppMailer</tt></p></td>
<td align="left" valign="top"><p class="table">A frontend to SwiftMailer, an email facility</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>ppOS</tt></p></td>
<td align="left" valign="top"><p class="table">A couple useful OS-level methods</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>ppPHPMailer</tt></p></td>
<td align="left" valign="top"><p class="table">A frontend to PHPMailer, deprecated in favor of SwiftMailer</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>ppPDF</tt></p></td>
<td align="left" valign="top"><p class="table">Converts HTML to PDF using either DOMPDF or PrinceXML</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>The usage of these plugins is a little easier to understand than some of
the helpers, so we won&#8217;t spend too much time on them.</p></div>
<div class="paragraph"><p>Here are a couple examples to get you started, though.</p></div>
<div class="listingblock">
<div class="title">Using ppFile and ppMailer</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pBook <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page_CRUD
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set_entity</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Book'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">hook__post_save</span></span><span style="color: #990000">(&amp;</span><span style="color: #009900">$data</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// if an image was uploaded with this record, convert/resize and store</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// it somewhere</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(</span><span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>plugins<span style="color: #990000">-&gt;</span>file<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">is_uploaded</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book_image'</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
                        <span style="color: #009900">$fn</span> <span style="color: #990000">=</span> DIR_FS_IMAGES <span style="color: #990000">.</span> DS <span style="color: #990000">.</span> <span style="color: #009900">$data</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">]</span> <span style="color: #990000">.</span> <span style="color: #FF0000">'.jpg'</span><span style="color: #990000">;</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// the ppFile plugin will use the ppImage plugin for image operations</span></span>
                        <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>plugins<span style="color: #990000">-&gt;</span>file<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">process_image</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book_image'</span><span style="color: #990000">,</span> <span style="color: #009900">$fn</span><span style="color: #990000">,</span> <span style="color: #993399">150</span><span style="color: #990000">,</span> <span style="color: #993399">150</span><span style="color: #990000">);</span>
                <span style="color: #FF0000">}</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_email_image</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// for fun, let's email a book's image to someone</span></span>
                <span style="font-weight: bold"><span style="color: #0000FF">list</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">,</span><span style="color: #009900">$email</span><span style="color: #990000">)</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">params</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'id'</span><span style="color: #990000">,</span><span style="color: #FF0000">'email'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$book</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>book<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #009900">$id</span><span style="color: #990000">);</span>
                <span style="color: #009900">$fn</span>   <span style="color: #990000">=</span> DIR_FS_IMAGES <span style="color: #990000">.</span> DS <span style="color: #990000">.</span> <span style="color: #009900">$book</span><span style="color: #990000">[</span><span style="color: #FF0000">'id'</span><span style="color: #990000">]</span> <span style="color: #990000">.</span> <span style="color: #FF0000">'.jpg'</span><span style="color: #990000">;</span>
                <span style="color: #009900">$mail</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>plugins<span style="color: #990000">-&gt;</span>mailer<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">create</span></span><span style="color: #990000">(</span><span style="color: #009900">$email</span><span style="color: #990000">,</span> <span style="color: #FF0000">'Book Image'</span><span style="color: #990000">,</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">fetch</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'book/email/book_image.php'</span><span style="color: #990000">));</span>
                <span style="color: #009900">$mail</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">add_attachment</span></span><span style="color: #990000">(</span><span style="color: #009900">$fn</span><span style="color: #990000">);</span>
                <span style="color: #009900">$mail</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">send</span></span><span style="color: #990000">();</span>
        <span style="color: #FF0000">}</span>

<span style="color: #FF0000">}</span></tt></pre></div></div>
<h3 id="X9-3">10.3. Custom Plugins</h3><div style="clear:left"></div>
<div class="paragraph"><p>It&#8217;s easy to write your own plugins for Pronto.  To create your own
page/template plugin, simply copy one of the existing ones to get the
class structure, then add your own functionality.  To activate it, add
your plugin name to the <tt>PLUGINS</tt> or <tt>HELPERS</tt> constants in
<tt>app/config/config.php</tt>.</p></div>
<h4 id="X9-3-a">10.3.1. Depending on other plugins</h4>
<div class="paragraph"><p>Like models, plugins can depend on each other for cross-functionality.
The format is the same as with models.</p></div>
<div class="listingblock">
<div class="title">Depending on other plugins</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ppFoo <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Plugin
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">do_stuff</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// the 'bar' plugin will help us out...</span></span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">depend</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'bar'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$stuff</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>depends<span style="color: #990000">-&gt;</span>bar<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">do_stuff</span></span><span style="color: #990000">();</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
</div>
<h2 id="X10">11. Internationalization</h2>
<div class="sectionbody">
<div class="paragraph"><p>Pronto provides its own facility for internationalization (hereon referred
to as <strong>i18n</strong>).  Currently it only supports string translation, but in the
future we plan to support other forms of localization, such as date/time
formats, currency, numbers, etc.</p></div>
<div class="paragraph"><p>I18n can be a real pain to do, but if you start your application with it
in mind, it can smooth the process significantly.</p></div>
<div class="paragraph"><p>The process goes something like this:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Make sure all your strings are passed through <tt>__()</tt> or <tt>_e()</tt>
</p>
</li>
<li>
<p>
When ready, run <tt>pronto/bin/i18n_scan.php</tt> to generate a <strong>messages</strong>
   file.  It will scan your code and pluck out all strings enclosed in either
   of the i18n functions.
</p>
</li>
<li>
<p>
Translate your messages file into other languages.
</p>
</li>
<li>
<p>
Reap the benefits of using a multilingual web application.
</p>
</li>
</ol></div>
<div class="paragraph"><p>The first trick with i18n is to run <em>all</em> your static strings through one
of the i18n string functions, <tt>\_\_()</tt> or <tt>\_e()</tt>.  These functions will take
in a string, look at the current language in use, and translate the string
to that language, if such a translation exists.  The only functional
difference between these two functions is that <tt>\_\_()</tt> will return the
translated string, while <tt>\_e()</tt> will <tt>echo</tt> it to the output buffer.
<tt>\_e()</tt> can be useful in templates so you don&#8217;t have to write <tt>echo
\_\_("foo")</tt> all the time.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">It is highly recommended that you keep the default <strong>UTF-8</strong> character set
in Pronto (it is set in <tt>app/config/config.php</tt>), as this will ensure you
don&#8217;t run into encoding issues when changing languages.</td>
</tr></table>
</div>
<h3 id="X10-1">11.1. Using <tt>__()</tt> and <tt>_e()</tt></h3><div style="clear:left"></div>
<div class="paragraph"><p>These functions both act somewhat akin to the way <tt>printf()</tt> style functions
do.  They accept a regular string, and optionally, can take a number of
arguments that will be substituted into the string, just as <tt>printf()</tt>
would.</p></div>
<div class="paragraph"><p>These functions are global, so they can be accessed at any layer of the
framework.</p></div>
<div class="listingblock">
<div class="title">Using <tt>__()</tt></div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="font-weight: bold"><span style="color: #000000">__</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'You have %d bottles of beer on the wall'</span><span style="color: #990000">,</span> <span style="color: #009900">$num</span><span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Why not just write the number in the string itself?  If you think about
it, the reason will be obvious.</p></div>
<div class="paragraph"><p>When you compile your messages file, each string needs to be represented.
If you introduce a variable into your string, then the string itself will
be different for every possible value of the variable within.  In the
interest of saving your translators some headache, you probably don&#8217;t want
them to have to translate the "bottles of beer" string 99 times, once for
each number.</p></div>
<div class="paragraph"><p>By using printf-style placeholders, we ensure the string itself only
appears once in the messages file.</p></div>
<h3 id="X10-2">11.2. Compiling the messages file</h3><div style="clear:left"></div>
<div class="paragraph"><p>Okay, so now all your strings are enclosed in <tt>__()</tt> or <tt>_e()</tt>.  The next
step is to generate the messages file.</p></div>
<div class="paragraph"><p>I18n messages files are stored in <tt>app/config/i18n</tt>.  Each file resides in
a subdirectory named after the ISO language code.  So the messages file
for the English language will be found at
<tt>app/config/i18n/en/messages.php</tt>.</p></div>
<div class="paragraph"><p>So with all your strings nicely i18n&#8217;ed, you can now generate the messages
file using the <tt>i18n_scan.php</tt> script.</p></div>
<div class="listingblock">
<div class="title">Using the I18N Scanner</div>
<div class="content">
<pre><tt>$ php ../pronto/bin/i18n_scan.php en English</tt></pre>
</div></div>
<div class="paragraph"><p>If <tt>i18n_scan.php</tt> finishes without error, you should have a nice big array
of strings in <tt>app/config/i18n/en/messages.php</tt> now.  This file can then
be passed to translaters, who will translate the array <em>values</em> into the
new language.  The array <em>keys</em> must stay as they are, so the i18n system
can use them for string lookups.</p></div>
<div class="paragraph"><p>Here&#8217;s an excerpt of a messages file for French.</p></div>
<div class="listingblock">
<div class="title"><tt>app/config/i18n/fr/messages.php</tt></div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-style: italic"><span style="color: #9A1900">/*</span></span>
<span style="font-style: italic"><span style="color: #9A1900"> * Generated by i18n_scan.php at 2007-12-20 12:57:24</span></span>
<span style="font-style: italic"><span style="color: #9A1900"> */</span></span>

<span style="color: #009900">$LANGUAGE_CODE</span> <span style="color: #990000">=</span> <span style="color: #FF0000">'fr'</span><span style="color: #990000">;</span>
<span style="color: #009900">$LANGUAGE_NAME</span> <span style="color: #990000">=</span> <span style="color: #FF0000">'French'</span><span style="color: #990000">;</span>

<span style="color: #009900">$MESSAGES</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="color: #FF0000">"Access"</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Accès"</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">"Access Level"</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Niveau d'accès:"</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">"Access levels determine the amount of control a user will have."</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Niveaux d'accès déterminer le montant de contrôle auront un utilisateur."</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">"An error occurred during file upload.  Please try again."</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Une erreur s'est produite pendant le téléchargement de fichiers. Veuillez réessayer."</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">"An error occurred while uploading - please try again"</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Une erreur s'est produite lors du transfert - Réessayez"</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">"Are you sure you want to remove this file?"</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Etes-vous sûr de vouloir supprimer ce fichier?"</span><span style="color: #990000">,</span>
        <span style="color: #FF0000">"Are you sure?"</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Etes-vous sûr?"</span><span style="color: #990000">,</span>
<span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<h4 id="X10-2-a">11.2.1. Using Google Translate for Translations</h4>
<div class="paragraph"><p>Pronto provides two scripts that use Google Translate to translate
messages files into new language.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 12: Translation scripts</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>google_translate.php</tt></p></td>
<td align="left" valign="top"><p class="table">Translate a messages file from English to another language.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>translate_all.php</tt></p></td>
<td align="left" valign="top"><p class="table">Translate the English messages file into all other languages supported by Google Translate.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">Translations provided by machines ("robot translations") are rarely
accurate enough for a production-quality site.  However, they can be quite
useful in earlier stages of development.</td>
</tr></table>
</div>
<div class="listingblock">
<div class="title">Using <tt>google_translate.php</tt></div>
<div class="content">
<pre><tt>$ mkdir config/i18n/fr
$ cp config/i18n/en/messages.php config/i18n/fr/
&lt;edit config/i18n/fr/messages.php and change $LANGUAGE_CODE to 'fr'&gt;
$ php ../pronto/bin/google_translate.php config/i18n/fr/messages.php</tt></pre>
</div></div>
<div class="listingblock">
<div class="title">Using <tt>translate_all.php</tt></div>
<div class="content">
<pre><tt>$ php ../pronto/bin/translate_all.php
Translating English to Arabic...
Translating English to Chinese Simplified...
Translating English to Chinese Traditional...
Translating English to Dutch...
Translating English to French...
Translating English to German...
Translating English to Greek...
Translating English to Italian...
Translating English to Japanese...
Translating English to Korean...
Translating English to Portuguese...
Translating English to Russian...
Translating English to Spanish...</tt></pre>
</div></div>
<h3 id="X10-3">11.3. The <tt>i18n</tt> Class</h3><div style="clear:left"></div>
<div class="paragraph"><p>Like the <tt>Access</tt> class and others, the <tt>I18N</tt> class is a utility-level
class that is instantiated only once per Pronto invocation.  The object is
held by the <tt>$web</tt> object, so it can be referenced through that.</p></div>
<div class="paragraph"><p>You typically won&#8217;t have to use the <tt>$web-&gt;i18n</tt> object.  When Pronto
starts processing a web request, it will try to autoset the language of
choice, based on a few values available.  Here are the values it will look
for, in this order:</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Table 13: Values used for setting a language</caption>
<col width="33%" />
<col width="66%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table"><tt>$_SESSION['LANGUAGE']</tt></p></td>
<td align="left" valign="top"><p class="table">The application is responsible for setting this.  It is intended to be used by site visitors who likely have no user/preferences record in the DB.  Perhaps your application has a "Language" select dropdown that the visitor can choose from.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>$_SESSION['USER']['language']</tt></p></td>
<td align="left" valign="top"><p class="table">When a user logs in, typically their record is stored in <tt>$_SESSION[\'USER\']</tt>.  If a <tt>language</tt> field is present, it would be found here.</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table"><tt>$_SERVER['HTTP_ACCEPT_LANGUAGE']</tt></p></td>
<td align="left" valign="top"><p class="table">If the visitor&#8217;s browser provides an <tt>Accept-Language</tt> HTTP header, Pronto will look through it for languages that your application supports, and choose the first it finds.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>The one function you&#8217;ll probably need the <tt>$i18n</tt> object for is
retrieving a list of languages that your application supports.  You can
use the results to populate a dropdown widget or equivalent, so the user
can choose his/her preferred language.</p></div>
<div class="listingblock">
<div class="title">Retrieving a list of all languages</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET_languages</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// fetch the i18n object from the registry...</span></span>
                <span style="color: #009900">$i18n</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'i18n'</span><span style="color: #990000">);</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">tset</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'languages'</span><span style="color: #990000">,</span> <span style="color: #009900">$i18n</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_languages</span></span><span style="color: #990000">());</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
</div>
<h2 id="X11">12. Logging</h2>
<div class="sectionbody">
<div class="paragraph"><p>Pronto provides a robust logging facility for debugging, error handling,
and any other uses you may forsee.</p></div>
<div class="paragraph"><p>To activate logging, you first tell Pronto where log files will exist.  To
do so, uncomment the line in <tt>app/config/config.php</tt> that defines the
<strong>DIR_FS_LOG</strong> constant.  By default, this is set to <tt>app/log</tt>.</p></div>
<div class="paragraph"><p>Once the configuration directive is set, you must create the directory and
ensure it is writable by the UID that will be executing the web requests
(usually this is the UID of the web server).</p></div>
<h3 id="X11-2">12.1. Making a Log Entry</h3><div style="clear:left"></div>
<div class="paragraph"><p>Log entries require three parameters: A facility, a priority, and the log
message.  A globally-accessible shortcut function exists that can be used
to create log entries from any point in the application.  This function
can accept one, two, or three arguments.  If the facility or priority is
omitted, defaults will be used.</p></div>
<div class="listingblock">
<div class="title">Making a Log Entry</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="font-style: italic"><span style="color: #9A1900">// create a log message with facility=test and priority=urgent</span></span>
                <span style="font-weight: bold"><span style="color: #000000">l</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'test'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'urgent'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'I am a log message!'</span><span style="color: #990000">);</span>

                <span style="font-style: italic"><span style="color: #9A1900">// create a log message with facility=app (default) and priority=low</span></span>
                <span style="font-weight: bold"><span style="color: #000000">l</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'low'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'I am a low-priority message'</span><span style="color: #990000">);</span>

                <span style="font-style: italic"><span style="color: #9A1900">// create a log message with facility=app (default) and</span></span>
                <span style="font-style: italic"><span style="color: #9A1900">// priority=info (default)</span></span>
                <span style="font-weight: bold"><span style="color: #000000">l</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'I am a very default log message'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">If you require direct access to the Log object, you can retrieve it via
the Registry: <tt>$log =&amp; Registry::get('pronto:logger')</tt></td>
</tr></table>
</div>
<h3 id="X11-3">12.2. Log Routing</h3><div style="clear:left"></div>
<div class="paragraph"><p>So based on facilities and priorities, where do these log entries actually
end up?  The ultimate destination for these messages depends on the <strong>log
routes</strong>, which is similar to URL routing.</p></div>
<div class="paragraph"><p>Log routes are configured via the <tt>$LOG_ROUTES</tt> array in
<tt>app/config/log.php</tt>.  The key for each element is a regular expression
that must match the facility name.  Facility names can be a regular
alphanumeric string (eg, "app" or "mymodule"), or they can contain one or
more facility subsections, separated by colons (eg, "app:controller").
This format is a convention, not a requirement.</p></div>
<div class="paragraph"><p>The element of each array can be a string (the log filename), or an array
itself.  If it is an array, then each key of this array is the priority,
and each value is the log filename.</p></div>
<div class="listingblock">
<div class="title">Configuring log routes</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="color: #009900">$LOG_ROUTES</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
        <span style="font-style: italic"><span style="color: #9A1900">// log all framework-related messages here</span></span>
        <span style="color: #FF0000">'pronto(:.*)*'</span> <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'.*'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'pronto.log'</span><span style="color: #990000">),</span>

        <span style="font-style: italic"><span style="color: #9A1900">// log all app-related messages here</span></span>
        <span style="color: #FF0000">'app(:.*)*'</span>    <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'.*'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'app.log'</span><span style="color: #990000">),</span>

        <span style="font-style: italic"><span style="color: #9A1900">// use the subpattern of the regex to log each sub-facility</span></span>
        <span style="font-style: italic"><span style="color: #9A1900">// to a separate file</span></span>
        <span style="color: #FF0000">'mymod:(.*)'</span>   <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'mymod_\1.log'</span><span style="color: #990000">,</span>
<span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>See <tt>app/config/log.php</tt> for more examples.</p></div>
</div>
<h2 id="X12">13. Modules</h2>
<div class="sectionbody">
<div class="paragraph"><p>Most of your page controllers, models, and templates will sit in their
respective subdirectories under the <tt>app</tt> directory.  But it&#8217;s also
possible to localize related controllers/models/templates into a more
modular layout, so they can be easily packaged and used in different
Pronto applications.</p></div>
<div class="paragraph"><p>Modules are basically just that&#8201;&#8212;&#8201;collections of page controllers,
models, and templates, located in a subdirectory of <tt>app/modules</tt>.  The
Pronto distribution code includes a sample module called <tt>dummy</tt> that can
be used as a template.  There is also a module generator available in the
<tt>pronto/bin/generators</tt> directory.</p></div>
<h3 id="X12-1">13.1. Enabling Modules</h3><div style="clear:left"></div>
<div class="paragraph"><p>Once you have a module you want to include in your application, you must
enable it by adding it to the <tt>MODULES</tt> constant in <tt>app/config.php</tt>.</p></div>
<div class="paragraph"><p>Each module typically comes with its own URL routing rules, which are
stored in <tt>app/modules/&lt;module_name&gt;/config/urls.php</tt>.  These rules will
be automatically prepended to the master URL routing table.</p></div>
<h3 id="X12-2">13.2. Using The Module Generator</h3><div style="clear:left"></div>
<div class="paragraph"><p>Like the CRUD generator, the module generator can save you a few minutes
of copy/paste time by setting up the basic file structure for a new
Pronto module.</p></div>
<div class="listingblock">
<div class="title">Using the Module generator</div>
<div class="content">
<pre><tt>$ php pronto/bin/generators/module/generate.php my_module
Module:  my_module
Path:    /home/jvinet/work/pronto/app/modules/my_module

New Config:          app/modules/my_module/config/config.php
New Config:          app/modules/my_module/config/urls.php
New Page Controller: app/modules/my_module/pages/page.php

To enable this module, add it to the MODULES constant in app/config/config.php</tt></pre>
</div></div>
</div>
<h2 id="X13">14. Caching</h2>
<div class="sectionbody">
<div class="paragraph"><p>Caching is a very effective way of getting more performance out of your
application.  In a stateless environment such as the web, it becomes
necessary to make many queries to the database to retrieve all the data
required to fulfill a page request, and each time the page is requested,
this data needs to be fetched again.</p></div>
<div class="paragraph"><p>By caching the data entities after the first request, additional trips to
the database can be avoided by using the cached version instead.  Pronto
supports transparent caching of data entities for which this feature is
enabled, and also provides a generic caching facility for explicit caching
of other data.</p></div>
<h3 id="X13-1">14.1. Enabling the Cache Layer</h3><div style="clear:left"></div>
<div class="paragraph"><p>To enable caching, you must edit <tt>app/config/cache.php</tt>.  In it you can
enable caching and define the cache driver you wish to use as well as any
additional driver-specific configuration options.</p></div>
<div class="listingblock">
<div class="title">Enabling the <tt>files</tt> cache driver</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #000000">define</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'USE_CACHE'</span><span style="color: #990000">,</span>        true<span style="color: #990000">);</span>
<span style="font-weight: bold"><span style="color: #000000">define</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'CACHE_DRIVER'</span><span style="color: #990000">,</span>    <span style="color: #FF0000">'files'</span><span style="color: #990000">);</span>
<span style="font-weight: bold"><span style="color: #000000">define</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'CACHE_FILES_DIR'</span>  DIR_FS_CACHE<span style="color: #990000">.</span>DS<span style="color: #990000">.</span><span style="color: #FF0000">'cache'</span><span style="color: #990000">);</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Make sure you create the <tt>cache</tt> directory in the appropriate location.
Also make sure that your web server has write permission to this
directory, or you will see an error.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">The <tt>files</tt> cache driver is functional, but there are other
memory-baesd caches that will probably be faster for you.  If
you have other caches available such as Memcache or APC, it&#8217;s
recommended to use one of those instead.</td>
</tr></table>
</div>
<h3 id="X13-2">14.2. Caching in Data Models</h3><div style="clear:left"></div>
<div class="paragraph"><p>Pronto&#8217;s data models support automatic caching at the entity level, but to
use it, you must enable this feature for each data model.</p></div>
<div class="listingblock">
<div class="title">Enabling Caching for a Data Model</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Model
<span style="color: #FF0000">{</span>
        <span style="font-style: italic"><span style="color: #9A1900">// to enable data caching, simply set $enable_cache to true in the</span></span>
        <span style="font-style: italic"><span style="color: #9A1900">// model class.</span></span>
        <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> <span style="color: #009900">$enable_cache</span> <span style="color: #990000">=</span> true<span style="color: #990000">;</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>While this is all it takes to enable the caching for a data model, you
must also program your data models with caching in mind.</p></div>
<div class="paragraph"><p>What does this mean?  Well, you have to be diligent about <em>invalidating</em>
a cached data record whenever you modify it, or else Pronto will not know
when to use the cached version or the "live" version from the database.</p></div>
<div class="listingblock">
<div class="title">Invalidating a cached record</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> mUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Model
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> <span style="color: #009900">$enable_cache</span> <span style="color: #990000">=</span> true<span style="color: #990000">;</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">set_password</span></span><span style="color: #990000">(</span><span style="color: #009900">$user_id</span><span style="color: #990000">,</span> <span style="color: #009900">$password</span><span style="color: #990000">)</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>db<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">execute</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"UPDATE users SET password=SHA1('%s') WHERE id=%i"</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #009900">$password</span><span style="color: #990000">,</span> <span style="color: #009900">$user_id</span><span style="color: #990000">));</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">invalidate</span></span><span style="color: #990000">(</span><span style="color: #009900">$user_id</span><span style="color: #990000">);</span> <span style="font-style: italic"><span style="color: #9A1900">// invalidate/expire this cache entry</span></span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
<div class="paragraph"><p>Also, whenever you want to fetch an entity (either from controllers, other
data models, or the model for which we&#8217;re caching entries), you should go
through the model&#8217;s <tt>get()</tt> method.  This is because <tt>Model::get()</tt> will
automatically check the cache.  If a cached record exists, it will be
returned.  If it doesn&#8217;t exist, then <tt>get_record()</tt> will be called to
fetch the entity from the database.  It will then be stored in the cache
and returned.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">This is why your data models should never override <tt>Model::get()</tt>, only
<tt>Model::get_record()</tt>.  <tt>Model::get()</tt> should be left alone, as it
contains the special cache-handling logic.  If you do need to override
<tt>Model::get()</tt>, then make sure to call <tt>parent::get($id)</tt> within it.</td>
</tr></table>
</div>
<h3 id="X13-3">14.3. Explicit Caching</h3><div style="clear:left"></div>
<div class="paragraph"><p>You can also use Pronto&#8217;s caching facility directly if you wish to cache
other types of data.  The cache object can be acquired through
the global <tt>Registry</tt> class.  It is a simple key/value system with the
normal access methods you would find in such a class.</p></div>
<div class="listingblock">
<div class="title">Using the <tt>cache</tt> object</div>
<div class="content"><!-- Generator: GNU source-highlight 3.0.1
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">&lt;?php</span>
<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> pUser <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Page
<span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">__init__</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">import_model</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'user'</span><span style="color: #990000">);</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">GET</span></span><span style="color: #990000">()</span>
        <span style="color: #FF0000">{</span>
                <span style="color: #009900">$cache</span> <span style="color: #990000">=&amp;</span> Registry<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'pronto:cache'</span><span style="color: #990000">);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span><span style="color: #990000">(!(</span><span style="color: #009900">$data</span> <span style="color: #990000">=</span> <span style="color: #009900">$cache</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'my_unique_key'</span><span style="color: #990000">)))</span> <span style="color: #FF0000">{</span>
                        <span style="font-style: italic"><span style="color: #9A1900">// cache miss, get the live record from the DB</span></span>
                        <span style="color: #009900">$data</span> <span style="color: #990000">=</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>models<span style="color: #990000">-&gt;</span>user<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">get_stuff</span></span><span style="color: #990000">();</span>

                        <span style="font-style: italic"><span style="color: #9A1900">// now store the record in the cache for next time</span></span>
                        <span style="color: #009900">$cache</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">set</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'my_unique_key'</span><span style="color: #990000">,</span> <span style="color: #009900">$data</span><span style="color: #990000">);</span>
                <span style="color: #FF0000">}</span>
        <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span>
<span style="color: #990000">?&gt;</span></tt></pre></div></div>
</div>
<h2 id="X14">15. Extending Pronto</h2>
<div class="sectionbody">
<div class="paragraph"><p>Pronto attempts to provide a good base on which to develop, but sometimes
its desireable to be able to modify some of the underlying functionality.</p></div>
<div class="paragraph"><p>You&#8217;ll rarely have to do this, but Pronto does provide a few areas that
can be easily overridden.</p></div>
<h3 id="X14-1">15.1. Overriding base functionality of Models, Pages, and Plugins</h3><div style="clear:left"></div>
<div class="paragraph"><p>The base classes for page controllers, data models, and plugins can be
found in the <tt>pronto/core</tt> directory.  However, you&#8217;ll notice that these
classes are actually named <tt>Page_Base</tt>, <tt>Model_Base</tt>, and <tt>Plugin_Base</tt>,
respectively.</p></div>
<div class="paragraph"><p>The <em>real</em> base classes are actually in the <tt>app/core</tt> directory, and
they&#8217;re intended to be modified by you if need be.  To add any base-level
methods or override existing ones, simply add them to these classes.</p></div>
<h3 id="X14-2">15.2. Execution Profiles</h3><div style="clear:left"></div>
<div class="paragraph"><p>By now, we all know that the life of a Pronto request begins at
<tt>index.php</tt>.  But this script&#8217;s primary job is to pass control to an
<strong>execution profile</strong>, which is in charge of setting up the runtime
environment before passing control to the next phase (which is usually the
dispatcher for a web request).</p></div>
<div class="paragraph"><p>There are two execution profiles included with Pronto: <tt>web</tt> and
<tt>cmdline</tt>.  You can probably guess what each profile is for, but in case
you can&#8217;t&#8201;&#8212;&#8201;<tt>web</tt> is called from <tt>index.php</tt> and handles web requests,
while the <tt>cmdline</tt> profile is used for commandline scripts, typically
stored in <tt>app/bin</tt> or <tt>pronto/bin</tt>.</p></div>
<div class="paragraph"><p>The standard execution profiles are stored in <tt>pronto/profiles</tt>, but you
can extend them by modifying their counterpart files in <tt>app/profiles</tt>.
Again, this is intended so you can safely modify Pronto code without
actually modifying any files in the <tt>pronto</tt> directory, which eases the
pain of upgrading the framework code at a later time.</p></div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Version 0.6<br />
Last updated 2010-01-13 09:05:35 ADT
</div>
</div>
</body>
</html>
Return current item: Pronto