Merge lp:~awbush/lightvc/devel into lp:~brandonlamb/lightvc/devel

Proposed by Brandon Lamb
Status: Needs review
Proposed branch: lp:~awbush/lightvc/devel
Merge into: lp:~brandonlamb/lightvc/devel
Diff against target: 2551 lines (+2430/-0)
19 files modified
.bzrignore (+2/-0)
classes/AppController.class.php (+49/-0)
classes/AppView.class.php (+21/-0)
classes/Autoloader.class.php (+183/-0)
classes/HttpStatusCode.class.php (+92/-0)
classes/SimpleReflector.class.php (+299/-0)
config/application.php (+39/-0)
config/routes.php (+41/-0)
controllers/error.php (+20/-0)
controllers/page.php (+16/-0)
modules/lightvc/LICENSE.txt (+21/-0)
modules/lightvc/README.txt (+8/-0)
modules/lightvc/lightvc.php (+1441/-0)
views/error/404.php (+1/-0)
views/layouts/default.php (+44/-0)
views/page/home.php (+36/-0)
webroot/.htaccess (+6/-0)
webroot/css/master.css (+69/-0)
webroot/index.php (+42/-0)
To merge this branch: bzr merge lp:~awbush/lightvc/devel
Reviewer Review Type Date Requested Status
LightVC Pending
Review via email: mp+2486@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Brandon Lamb (brandonlamb) wrote :

Trying to figure out how to start a branch, think i did the wrong thing

lp:~awbush/lightvc/devel updated
6. By Anthony Bush

Aded Autoloader, SimpleReflector.

7. By Anthony Bush

Merged in changes from AS branch:
* Added ability to set customer headers when redirecting, e.g. 'HTTP/1.1 301 Moved Permanently'.
* Allow mapping of controller names with slashes in them to class names (e.g. report/orders => ReportOrdersController).

8. By Anthony Bush

Merged in changes from AS branch:
* Changed redirect() to explicitly invoke afterAction() and exit().

9. By Anthony Bush

Autoloader and SimpleReflector must be explicitly enabled.

Unmerged revisions

9. By Anthony Bush

Autoloader and SimpleReflector must be explicitly enabled.

8. By Anthony Bush

Merged in changes from AS branch:
* Changed redirect() to explicitly invoke afterAction() and exit().

7. By Anthony Bush

Merged in changes from AS branch:
* Added ability to set customer headers when redirecting, e.g. 'HTTP/1.1 301 Moved Permanently'.
* Allow mapping of controller names with slashes in them to class names (e.g. report/orders => ReportOrdersController).

6. By Anthony Bush

Aded Autoloader, SimpleReflector.

5. By Anthony Bush

Darkened gray note text on home page.

4. By Anthony Bush

* Several small non-core changes:
 * Moved reset.css into single line at top of master.css (performance).
 * Split out HTTP error codes from the error controller.
 * Added simple AppController methods: requireJsInHead, redirectToAction, etc.
 * Added requireJs and requireJsInHead to AppView. Thus, views can now specify their JS dependencies in addition to their CSS ones.

3. By Anthony Bush

Moved lightvc files into its own modules sub-folder, where it should have been all along.

2. By Anthony Bush

Ported changes from A.S. branch: Fixed LightVC errors caused by visiting urls like '/%00'.

1. By Anthony Bush

initial BZR import (LightVC 1.0.4 with skeleton app).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.bzrignore'
2--- .bzrignore 1970-01-01 00:00:00 +0000
3+++ .bzrignore 2010-09-26 21:45:54 +0000
4@@ -0,0 +1,2 @@
5+.DS_Store
6+*Release Notes.markdown
7
8=== added directory 'classes'
9=== added file 'classes/AppController.class.php'
10--- classes/AppController.class.php 1970-01-01 00:00:00 +0000
11+++ classes/AppController.class.php 2010-09-26 21:45:54 +0000
12@@ -0,0 +1,49 @@
13+<?php
14+
15+class AppController extends Lvc_PageController
16+{
17+ protected $layout = 'default';
18+
19+ protected function beforeAction()
20+ {
21+ $this->setLayoutVar('pageTitle', 'Untitled');
22+ $this->requireCss('master.css');
23+ }
24+
25+ public function requireCss($cssFile)
26+ {
27+ $this->layoutVars['requiredCss'][$cssFile] = true;
28+ }
29+
30+ public function requireJs($jsFile)
31+ {
32+ $this->layoutVars['requiredJs'][$jsFile] = true;
33+ }
34+
35+ public function requireJsInHead($jsFile)
36+ {
37+ $this->layoutVars['requiredJsInHead'][$jsFile] = true;
38+ }
39+
40+ protected function loadPageNotFound()
41+ {
42+ $this->sendHttpStatusHeader('404');
43+ $this->loadView('error/404');
44+ }
45+
46+ public function sendHttpStatusHeader($code)
47+ {
48+ include_once('HttpStatusCode.class.php');
49+ $statusCode = new HttpStatusCode($code);
50+ header('HTTP 1.1 ' . $statusCode->getCode() . ' ' . $statusCode->getDefinition());
51+ return $statusCode;
52+ }
53+
54+ public function redirectToAction($actionName)
55+ {
56+ $this->redirect(WWW_BASE_PATH . $this->getControllerName() . '/' . $actionName);
57+ }
58+
59+}
60+
61+?>
62\ No newline at end of file
63
64=== added file 'classes/AppView.class.php'
65--- classes/AppView.class.php 1970-01-01 00:00:00 +0000
66+++ classes/AppView.class.php 2010-09-26 21:45:54 +0000
67@@ -0,0 +1,21 @@
68+<?php
69+
70+class AppView extends Lvc_View
71+{
72+ public function requireCss($cssFile)
73+ {
74+ $this->controller->requireCss($cssFile);
75+ }
76+
77+ public function requireJs($jsFile)
78+ {
79+ $this->controller->requireJs($jsFile);
80+ }
81+
82+ public function requireJsInHead($jsFile)
83+ {
84+ $this->controller->requireJsInHead($jsFile);
85+ }
86+}
87+
88+?>
89\ No newline at end of file
90
91=== added file 'classes/Autoloader.class.php'
92--- classes/Autoloader.class.php 1970-01-01 00:00:00 +0000
93+++ classes/Autoloader.class.php 2010-09-26 21:45:54 +0000
94@@ -0,0 +1,183 @@
95+<?php
96+
97+/**
98+ * Autoloader is a class scanner with caching.
99+ *
100+ * Sample Usage:
101+ *
102+ * <code>
103+ * include_once('coughphp/extras/Autoloader.class.php');
104+ * Autoloader::addClassPath('app_path/classes/');
105+ * Autoloader::addClassPath('shared_path/classes/');
106+ * Autoloader::setCacheFilePath('app_path/tmp/class_path_cache.txt');
107+ * Autoloader::excludeFolderNamesMatchingRegex('/^CVS|\..*$/');
108+ * spl_autoload_register(array('Autoloader', 'loadClass'));
109+ * </code>
110+ *
111+ * @package default
112+ * @author Anthony Bush, Wayne Wight
113+ * @copyright 2006-2008 Academic Superstore. This software is open source protected by the FreeBSD License.
114+ * @version 2008-09-22
115+ **/
116+class Autoloader {
117+ protected static $classPaths = array();
118+ protected static $classFileSuffix = '.class.php';
119+ protected static $cacheFilePath = null;
120+ protected static $cachedPaths = null;
121+ protected static $excludeFolderNames = '/^CVS|\..*$/'; // CVS directories and directories starting with a dot (.).
122+ protected static $hasSaver = false;
123+
124+ /**
125+ * Sets the paths to search in when looking for a class.
126+ *
127+ * @param array $paths
128+ * @return void
129+ **/
130+ public static function setClassPaths($paths) {
131+ self::$classPaths = $paths;
132+ }
133+
134+ /**
135+ * Adds a path to search in when looking for a class.
136+ *
137+ * @param string $path
138+ * @return void
139+ **/
140+ public static function addClassPath($path) {
141+ self::$classPaths[] = $path;
142+ }
143+
144+ /**
145+ * Set the full file path to the cache file to use.
146+ *
147+ * Example:
148+ *
149+ * <code>
150+ * Autoloader::setCacheFilePath('/tmp/class_path_cache.txt');
151+ * </code>
152+ *
153+ * @param string $path
154+ * @return void
155+ **/
156+ public static function setCacheFilePath($path) {
157+ self::$cacheFilePath = $path;
158+ }
159+
160+ /**
161+ * Sets the suffix to append to a class name in order to get a file name
162+ * to look for
163+ *
164+ * @param string $suffix - $className . $suffix = filename.
165+ * @return void
166+ **/
167+ public static function setClassFileSuffix($suffix) {
168+ self::$classFileSuffix = $suffix;
169+ }
170+
171+ /**
172+ * When searching the {@link $classPaths} recursively for a matching class
173+ * file, folder names matching $regex will not be searched.
174+ *
175+ * Example:
176+ *
177+ * <code>
178+ * Autoloader::excludeFolderNamesMatchingRegex('/^CVS|\..*$/');
179+ * </code>
180+ *
181+ * @param string $regex
182+ * @return void
183+ **/
184+ public static function excludeFolderNamesMatchingRegex($regex) {
185+ self::$excludeFolderNames = $regex;
186+ }
187+
188+ /**
189+ * Returns true if the class file was found and included, false if not.
190+ *
191+ * @return boolean
192+ **/
193+ public static function loadClass($className) {
194+
195+ $filePath = self::getCachedPath($className);
196+ if ($filePath && file_exists($filePath)) {
197+ // Cached location is correct
198+ include($filePath);
199+ return true;
200+ } else {
201+ // Scan for file
202+ foreach (self::$classPaths as $path) {
203+ if ($filePath = self::searchForClassFile($className, $path)) {
204+ self::$cachedPaths[$className] = $filePath;
205+ if (!self::$hasSaver) {
206+ register_shutdown_function(array('Autoloader', 'saveCachedPaths'));
207+ self::$hasSaver = true;
208+ }
209+ include($filePath);
210+ return true;
211+ }
212+ }
213+
214+ }
215+ return false;
216+ }
217+
218+ protected static function getCachedPath($className) {
219+ self::loadCachedPaths();
220+ if (isset(self::$cachedPaths[$className])) {
221+ return self::$cachedPaths[$className];
222+ } else {
223+ return false;
224+ }
225+ }
226+
227+ protected static function loadCachedPaths() {
228+ if (is_null(self::$cachedPaths)) {
229+ if (self::$cacheFilePath && is_file(self::$cacheFilePath)) {
230+ self::$cachedPaths = unserialize(file_get_contents(self::$cacheFilePath));
231+ }
232+ }
233+ }
234+
235+ /**
236+ * Write cached paths to disk.
237+ *
238+ * @return void
239+ **/
240+ public static function saveCachedPaths() {
241+ if (!file_exists(self::$cacheFilePath) || is_writable(self::$cacheFilePath)) {
242+ $fileContents = serialize(self::$cachedPaths);
243+ $bytes = file_put_contents(self::$cacheFilePath, $fileContents);
244+ if ($bytes === false) {
245+ trigger_error('Autoloader could not write the cache file: ' . self::$cacheFilePath, E_USER_ERROR);
246+ }
247+ } else {
248+ trigger_error('Autoload cache file not writable: ' . self::$cacheFilePath, E_USER_ERROR);
249+ }
250+ }
251+
252+ protected static function searchForClassFile($className, $directory) {
253+ if (is_dir($directory) && is_readable($directory)) {
254+ $d = dir($directory);
255+ while ($f = $d->read()) {
256+ $subPath = $directory . $f;
257+ if (is_dir($subPath)) {
258+ // Found a subdirectory
259+ if (!preg_match(self::$excludeFolderNames, $f)) {
260+ if ($filePath = self::searchForClassFile($className, $subPath . '/')) {
261+ return $filePath;
262+ }
263+ }
264+ } else {
265+ // Found a file
266+ if ($f == $className . self::$classFileSuffix) {
267+ return $subPath;
268+ }
269+ }
270+ }
271+ }
272+ return false;
273+ }
274+
275+}
276+
277+?>
278\ No newline at end of file
279
280=== added file 'classes/HttpStatusCode.class.php'
281--- classes/HttpStatusCode.class.php 1970-01-01 00:00:00 +0000
282+++ classes/HttpStatusCode.class.php 2010-09-26 21:45:54 +0000
283@@ -0,0 +1,92 @@
284+<?php
285+
286+class HttpStatusCode
287+{
288+ /**
289+ * Hash of error code -> error message mappings.
290+ *
291+ * @var array
292+ * @see http://www.faqs.org/rfcs/rfc2616
293+ **/
294+ protected static $errorString = array(
295+ 100 => 'Continue',
296+ 101 => 'Switching Protocols',
297+ 200 => 'OK',
298+ 201 => 'Created',
299+ 202 => 'Accepted',
300+ 203 => 'Non-Authoritative Information',
301+ 204 => 'No Content',
302+ 205 => 'Reset Content',
303+ 206 => 'Partial Content',
304+ 300 => 'Multiple Choices',
305+ 301 => 'Moved Permanently',
306+ 302 => 'Found',
307+ 303 => 'See Other',
308+ 304 => 'Not Modified',
309+ 305 => 'Use Proxy',
310+ 307 => 'Temporary Redirect',
311+ 400 => 'Bad Request',
312+ 401 => 'Unauthorized',
313+ 402 => 'Payment Required',
314+ 403 => 'Forbidden',
315+ 404 => 'Not Found',
316+ 405 => 'Method Not Allowed',
317+ 406 => 'Not Acceptable',
318+ 407 => 'Proxy Authentication Required',
319+ 408 => 'Request Timeout',
320+ 409 => 'Conflict',
321+ 410 => 'Gone',
322+ 411 => 'Length Required',
323+ 412 => 'Precondition Failed',
324+ 413 => 'Request Entity Too Large',
325+ 414 => 'Request-URI Too Long',
326+ 415 => 'Unsupported Media Type',
327+ 416 => 'Requested Range Not Satisfiable',
328+ 417 => 'Expectation Failed',
329+ 500 => 'Internal Server Error',
330+ 501 => 'Not Implemented',
331+ 502 => 'Bad Gateway',
332+ 503 => 'Service Unavailable',
333+ 504 => 'Gateway Timeout',
334+ 505 => 'HTTP Version Not Supported',
335+ );
336+
337+ protected $code = '';
338+ protected $defintion = '';
339+
340+ public function __construct($code)
341+ {
342+ if (isset(self::$errorString[$code]))
343+ {
344+ $this->setCode($code);
345+ $this->setDefinition(self::$errorString[$code]);
346+ }
347+ else
348+ {
349+ $this->setCode(404);
350+ $this->setDefinition(self::$errorString[404]);
351+ }
352+ }
353+
354+ public function getCode()
355+ {
356+ return $this->code;
357+ }
358+
359+ public function getDefinition()
360+ {
361+ return $this->defintion;
362+ }
363+
364+ public function setCode($code)
365+ {
366+ $this->code = $code;
367+ }
368+
369+ public function setDefinition($defintion)
370+ {
371+ $this->defintion = $defintion;
372+ }
373+}
374+
375+?>
376\ No newline at end of file
377
378=== added file 'classes/SimpleReflector.class.php'
379--- classes/SimpleReflector.class.php 1970-01-01 00:00:00 +0000
380+++ classes/SimpleReflector.class.php 2010-09-26 21:45:54 +0000
381@@ -0,0 +1,299 @@
382+<?php
383+
384+/**
385+ * An easy-to-use reflection class for exposing an object's identity so
386+ * problems can be debugged quickly.
387+ *
388+ * It does correct null/true/false/empty string detection. A string just gets
389+ * output directly, whereas objects will have their class interfaces exposed.
390+ * Everything dumped to screen is correctly escaped for HTML output so the rest
391+ * of the page doesn't break.
392+ *
393+ * The following information is displayed for objects:
394+ *
395+ * - Class file/line location (especially useful when the same name class is defined multiple times in the filesystem)
396+ * - Methods in the class, including parameter names.
397+ * - Contents of the object (simple print_r that is HTML escaped)
398+ *
399+ * Example Usage:
400+ *
401+ * <code>
402+ * SimpleReflector::jam($object); // echo info to screen
403+ * $str = SimpleReflector::jam($object, true); // returns info as a string
404+ * SimpleReflector::jam($object, false, 'crazy object'); // echo info to screen with a custom title instead of "SimpleReflector"
405+ * </code>
406+ *
407+ * For quicker use, consider adding a short function to your applications:
408+ *
409+ * <code>
410+ * function jam() { $args = func_get_args(); call_user_func_array(array('SimpleReflector', 'jam'), $args); }
411+ * </code>
412+ *
413+ * Then instead of typing `SimpleReflector::jam(...)` you can just type `jam(...)`.
414+ *
415+ * @package default
416+ * @author Anthony Bush
417+ * @copyright Academic Superstore 2006-2008, FreeBSD (revised) licensed
418+ * @version 1.0 (2008-10-20) - First public release after 2 years of internal-only use.
419+ **/
420+class SimpleReflector
421+{
422+ /**
423+ * Completely expose the contents of the given item in a way that makes it
424+ * easy to find out more about that item.
425+ *
426+ * It displays invisible characters (nulls, boolean, empty strings) and
427+ * builds collapsable tables out of arrays and objects.
428+ *
429+ * @param mixed $var the object / variable to dump
430+ * @param boolean $return set to true if you want it to return the output rather than echo it (just like print_r)
431+ * @return mixed if $return is true, returns the output as string, otherwise it returns true.
432+ * @author Anthony Bush
433+ **/
434+ public static function jam($var, $return = false, $overrideTitle = '') {
435+ $html = '';
436+ if (is_array($var)) {
437+ $html .= self::jamObject($var, true, $overrideTitle);
438+ } else if (is_object($var)) {
439+ $html .= self::jamObject($var, true, $overrideTitle);
440+ } else {
441+ $html .= '<pre>';
442+ if (strlen($overrideTitle) > 0) {
443+ $html .= htmlentities($overrideTitle);
444+ } else {
445+ $html .= 'SimpleReflector';
446+ }
447+ $html .= ': ' . self::getVisual($var) . '</pre>';
448+ }
449+
450+ if ($return) {
451+ return $html;
452+ } else {
453+ echo $html;
454+ return true;
455+ }
456+ }
457+
458+ /**
459+ * Shows where item is defined (if it's an object) dumps it's contents, and
460+ * lists the public / private methods in a collapsable format.
461+ *
462+ * @param mixed $var the object / variable to dump
463+ * @param boolean $return set to true if you want it to return the output rather than echo it (just like print_r)
464+ * @return mixed if $return is true, returns the output as string, otherwise it returns true.
465+ * @author Anthony Bush
466+ **/
467+ protected static function jamObject($var, $return = false, $overrideTitle = '') {
468+ $html = '';
469+ static $num = 0;
470+
471+ if (is_object($var))
472+ {
473+
474+ $reflector = new ReflectionClass($var);
475+
476+ $html .= self::getShowHideJavascript();
477+
478+ $html .= '<div class="debug">';
479+ $html .= '<a class="title" href="javascript:void(showHide(\'superjam' . $num . '\'))">';
480+ if (strlen($overrideTitle) > 0) {
481+ $html .= htmlentities($overrideTitle);
482+ } else {
483+ $html .= 'SimpleReflector: ' . $reflector->getName();
484+ }
485+ $html .= '</a>';
486+ $html .= '<div id="superjam' . $num . '" class="superjam_results" style="display:none">';
487+
488+ // Show where this class is defined:
489+ $html .= 'Definition: ' . $reflector->getFileName() . ':' . $reflector->getStartLine() . "<br />\n";
490+
491+ // Get methods
492+ $methods = array(
493+ 'public' => array()
494+ , 'private' => array()
495+ , 'protected' => array()
496+ );
497+ foreach ($reflector->getMethods() as $method) {
498+ if ($method->isPrivate()) {
499+ $access = 'private';
500+ } elseif ($method->isProtected()) {
501+ $access = 'protected';
502+ } else {
503+ $access = 'public';
504+ }
505+ $methods[$access][$method->getName()] = $method;
506+ }
507+ foreach ($methods as $access => $accessMethods) {
508+ ksort($methods[$access]);
509+ }
510+
511+ // Show methods
512+ ob_start();
513+ foreach ($methods as $access => $accessMethods) {
514+ if ( ! empty($accessMethods)) {
515+ echo '<a class="' . $access . '" href="javascript:void(showHide(\'superjam_' . $access . $num . '\'))">Show/Hide ' . ucwords($access) . ' Methods</a>' . "<br />\n";
516+ echo '<pre id="superjam_' . $access . $num . '" class="superjam_methods" style="display:none">';
517+ foreach ($accessMethods as $method) {
518+ $params = array();
519+ foreach ($method->getParameters() as $param) {
520+ $params[] = '<span class="methodParam">$' . $param->getName() . '</span>';
521+ }
522+ $paramNames = implode(', ', $params);
523+ printf(
524+ '<div class="method ' . $access . '">'
525+ . "%s%s%s "
526+ . '<span class="methodName">'
527+ . "%s</span>("
528+ . $paramNames
529+ . ');</div>'
530+ , $method->isAbstract() ? ' abstract' : ''
531+ , $method->isFinal() ? ' final' : ''
532+ , $method->isStatic() ? ' static' : ''
533+ , $method->getName()
534+ );
535+ }
536+ echo '</pre>';
537+ }
538+ }
539+ $html .= ob_get_clean();
540+
541+
542+ // Show contents
543+ $html .= '<a class="superjam_contents" href="javascript:void(showHide(\'superjam_contents' . $num . '\'))">Show/Hide Contents</a>' . "<br />\n";
544+ $html .= '<pre id="superjam_contents' . $num . '" style="display:none">';
545+ $html .= htmlentities(print_r($var, true));
546+ $html .= '</pre>';
547+
548+ $html .= '</div>'; // superjam . $num
549+ $html .= '</div>'; // debug
550+
551+ $num++;
552+ }
553+ else if (is_array($var))
554+ {
555+
556+ // Just show contents
557+ $html .= self::getShowHideJavascript();
558+ $html .= '<div class="debug" style="border: 1px solid #000; background: #fff">';
559+ $html .= '<a class="title" style="display: block; background: #ddd; padding: 5px; font-weight: bold;" href="javascript:void(showHide(\'superjam' . $num . '\'))">';
560+ if (strlen($overrideTitle) > 0) {
561+ $html .= htmlentities($overrideTitle);
562+ } else {
563+ $html .= 'SimpleReflector: PHP Array';
564+ }
565+ $html .= '</a>';
566+ $html .= '<pre id="superjam' . $num . '" style="display:none; padding: 5px">';
567+ $html .= htmlentities(print_r($var, true));
568+ $html .= '</pre>';
569+ $html .= '</div>'; // debug
570+
571+ $num++;
572+ }
573+
574+ if ($return) {
575+ return $html;
576+ } else {
577+ echo $html;
578+ return true;
579+ }
580+
581+ }
582+
583+ protected static function getAncestors($class) {
584+ $classes = array($class);
585+ while ($class = get_parent_class($class)) {
586+ $classes[] = $class;
587+ }
588+ return $classes;
589+ }
590+
591+ protected static function getVisual($var) {
592+ if (is_null($var)) {
593+ return '[null]';
594+ } else if ($var === true) {
595+ return '[true]';
596+ } else if ($var === false) {
597+ return '[false]';
598+ } else if ($var === '') {
599+ return '[empty string]';
600+ } else if (is_array($var)) {
601+ return self::jamObject($var, true);
602+ } else if (is_object($var)) {
603+ return self::jamObject($var, true);
604+ } else {
605+ return htmlentities($var);
606+ }
607+ }
608+
609+ /**
610+ * Internal function for printing out style / javascript that makes the
611+ * collapsing features work.
612+ *
613+ * @return string
614+ * @author Anthony Bush
615+ **/
616+ protected static function getShowHideJavascript() {
617+ static $called = false;
618+ if ($called) {
619+ return;
620+ }
621+ $called = true;
622+ ob_start();
623+ ?>
624+ <style type="text/css" media="screen">
625+ /* <![CDATA[ */
626+ .debug {
627+ border: 1px solid #000;
628+ background: #fff;
629+ color: #000;
630+ }
631+ .debug,
632+ .debug table td {
633+ text-align: left;
634+ }
635+ .debug table {
636+ margin: .5em 0;
637+ }
638+ .debug .title {
639+ display: block;
640+ background: #ddd;
641+ padding: 5px;
642+ font-weight: bold;
643+ }
644+ .debug a:link,
645+ .debug a:visited,
646+ .debug a:hover,
647+ .debug a:active {
648+ color: #0000A2;
649+ font-weight: bold;
650+ }
651+ .debug .superjam_methods {
652+ display: none;
653+ }
654+ .debug .superjam_results {
655+ display: none;
656+ padding: 5px;
657+ }
658+ .debug .methodName {
659+ color: #9D6F38;
660+ }
661+ /* ]]> */
662+ </style>
663+ <script type="text/javascript" language="javascript" charset="utf-8">
664+ // <![CDATA[
665+ function showHide(elementId) {
666+ e = document.getElementById(elementId);
667+ if (e.style.display == 'none') {
668+ e.style.display = 'block';
669+ } else {
670+ e.style.display = 'none';
671+ }
672+ }
673+ // ]]>
674+ </script>
675+ <?php
676+ return ob_get_clean();
677+ }
678+}
679+
680+?>
681\ No newline at end of file
682
683=== added directory 'config'
684=== added file 'config/application.php'
685--- config/application.php 1970-01-01 00:00:00 +0000
686+++ config/application.php 2010-09-26 21:45:54 +0000
687@@ -0,0 +1,39 @@
688+<?php
689+
690+// Derived Constants
691+define('APP_PATH', dirname(dirname(__FILE__)) . '/');
692+define('WWW_BASE_PATH', str_replace('index.php', '', $_SERVER['SCRIPT_NAME']));
693+define('WWW_CSS_PATH', WWW_BASE_PATH . 'css/');
694+define('WWW_JS_PATH', WWW_BASE_PATH . 'js/');
695+define('WWW_IMAGE_PATH', WWW_BASE_PATH . 'images/');
696+// set_include_path(get_include_path() . PATH_SEPARATOR . APP_PATH . PATH_SEPARATOR . SHARED_PATH);
697+// set_include_path(get_include_path() . PATH_SEPARATOR . APP_PATH);
698+
699+// Include and configure the LighVC framework (http://lightvc.org/)
700+include_once(APP_PATH . 'modules/lightvc/lightvc.php');
701+Lvc_Config::addControllerPath(APP_PATH . 'controllers/');
702+Lvc_Config::addControllerViewPath(APP_PATH . 'views/');
703+Lvc_Config::addLayoutViewPath(APP_PATH . 'views/layouts/');
704+Lvc_Config::addElementViewPath(APP_PATH . 'views/elements/');
705+Lvc_Config::setViewClassName('AppView');
706+include(APP_PATH . 'classes/AppController.class.php');
707+include(APP_PATH . 'classes/AppView.class.php');
708+include(dirname(__FILE__) . '/routes.php');
709+
710+/* Enable the optional Autoloader and/or SimpleReflector helpers by uncommenting the following:
711+// Setup Autoloader (http://anthonybush.com/projects/autoloader/)
712+include(APP_PATH . 'classes/Autoloader.class.php');
713+Autoloader::setCacheFilePath(APP_PATH . 'tmp/class_path_cache.txt');
714+Autoloader::excludeFolderNamesMatchingRegex('/^CVS|\..*$/');
715+Autoloader::setClassPaths(array(
716+ APP_PATH . 'classes/',
717+ // APP_PATH . 'models/'
718+));
719+spl_autoload_register(array('Autoloader', 'loadClass'));
720+
721+// Setup SimpleReflector alias (http://anthonybush.com/projects/simplereflector/)
722+// call this to debug a variable/object, e.g. jam($var);
723+function jam() { call_user_func_array(array('SimpleReflector', 'jam'), func_get_args()); }
724+//*/
725+
726+?>
727\ No newline at end of file
728
729=== added file 'config/routes.php'
730--- config/routes.php 1970-01-01 00:00:00 +0000
731+++ config/routes.php 2010-09-26 21:45:54 +0000
732@@ -0,0 +1,41 @@
733+<?php
734+
735+// Format of regex => parseInfo
736+$regexRoutes = array(
737+
738+ // Map nothing to the home page.
739+ '#^$#' => array(
740+ 'controller' => 'page',
741+ 'action' => 'view',
742+ 'action_params' => array(
743+ 'page_name' => 'home',
744+ ),
745+ ),
746+
747+ // Allow direct access to all pages via a "/page/page_name" URL.
748+ '#^page/(.*)$#' => array(
749+ 'controller' => 'page',
750+ 'action' => 'view',
751+ 'action_params' => array(
752+ 'page_name' => 1,
753+ ),
754+ ),
755+
756+ // Map controler/action/params
757+ '#^([^/]+)/([^/]+)/?(.*)$#' => array(
758+ 'controller' => 1,
759+ 'action' => 2,
760+ 'additional_params' => 3,
761+ ),
762+
763+ // Map controllers to a default action (not needed if you use the
764+ // Lvc_Config static setters for default controller name, action
765+ // name, and action params.)
766+ '#^([^/]+)/?$#' => array(
767+ 'controller' => 1,
768+ 'action' => 'index',
769+ ),
770+
771+);
772+
773+?>
774\ No newline at end of file
775
776=== added directory 'controllers'
777=== added file 'controllers/error.php'
778--- controllers/error.php 1970-01-01 00:00:00 +0000
779+++ controllers/error.php 2010-09-26 21:45:54 +0000
780@@ -0,0 +1,20 @@
781+<?php
782+
783+class ErrorController extends AppController
784+{
785+ public function actionView($errorNum = '404')
786+ {
787+ if (strpos($errorNum, '../') !== false)
788+ {
789+ $errorNum = '404';
790+ }
791+
792+ include_once('../classes/HttpStatusCode.class.php');
793+ $statusCode = new HttpStatusCode($errorNum);
794+ $this->setLayoutVar('pageTitle', $statusCode->getDefinition());
795+ $this->loadView($this->getControllerName() . '/' . $statusCode->getCode());
796+ }
797+
798+}
799+
800+?>
801\ No newline at end of file
802
803=== added file 'controllers/page.php'
804--- controllers/page.php 1970-01-01 00:00:00 +0000
805+++ controllers/page.php 2010-09-26 21:45:54 +0000
806@@ -0,0 +1,16 @@
807+<?php
808+
809+class PageController extends AppController
810+{
811+ public function actionView($pageName = 'home')
812+ {
813+ if (strpos($pageName, '../') !== false)
814+ {
815+ throw new Lvc_Exception('File Not Found: ' . $sourceFile);
816+ }
817+
818+ $this->loadView('page/' . rtrim($pageName, '/'));
819+ }
820+}
821+
822+?>
823\ No newline at end of file
824
825=== added directory 'modules'
826=== added directory 'modules/lightvc'
827=== added file 'modules/lightvc/LICENSE.txt'
828--- modules/lightvc/LICENSE.txt 1970-01-01 00:00:00 +0000
829+++ modules/lightvc/LICENSE.txt 2010-09-26 21:45:54 +0000
830@@ -0,0 +1,21 @@
831+Copyright (c) 2007, Anthony Bush
832+
833+All rights reserved.
834+
835+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
836+
837+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
838+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
839+ * Neither the name LightVC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
840+
841+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
842+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
843+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
844+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
845+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
846+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
847+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
848+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
849+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
850+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
851+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
852\ No newline at end of file
853
854=== added file 'modules/lightvc/README.txt'
855--- modules/lightvc/README.txt 1970-01-01 00:00:00 +0000
856+++ modules/lightvc/README.txt 2010-09-26 21:45:54 +0000
857@@ -0,0 +1,8 @@
858+Visit the Web site at:
859+http://lightvc.org/
860+
861+View the docs at:
862+http://lightvc.org/docs/
863+
864+View the change log at:
865+http://lightvc.org/docs/changelog/
866
867=== added file 'modules/lightvc/lightvc.php'
868--- modules/lightvc/lightvc.php 1970-01-01 00:00:00 +0000
869+++ modules/lightvc/lightvc.php 2010-09-26 21:45:54 +0000
870@@ -0,0 +1,1441 @@
871+<?php
872+/**
873+ * LightVC - A lightweight view-controller framework.
874+ * http://lightvc.org/
875+ *
876+ * You provide your own model/ORM. We recommend Cough <http://coughphp.com>.
877+ *
878+ * The purpose of this framework is to provide just a "view-controller"
879+ * setup without all the other junk. Ideally, the classes from other frameworks
880+ * should be reusable but instead they are mostly coupled with their frameworks.
881+ * It's up to you to go get those classes if you need them, or provide your own.
882+ *
883+ * Additionally, we've decoupled it from any sort of Model so that you can use
884+ * the one you already know and love. And if you don't know one, now is a great
885+ * time to check out CoughPHP. Other ORMs can be found at:
886+ *
887+ * http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software#PHP
888+ *
889+ * By providing just the VC, we increase the reusability of not only the
890+ * framework itself, but non-framework components as well.
891+ *
892+ * The framework is fast. Currently the speed of this framework is unmatched by
893+ * any other PHP framework available today.
894+ *
895+ * You get to use the classes you've already been using without worrying about
896+ * naming conflicts or inefficiencies from loading both your classes and the
897+ * classes from some other framework.
898+ *
899+ * LightVC aims to be easier to use, more configurable, and light in footprint.
900+ *
901+ * @author Anthony Bush
902+ * @version 1.0.4 (2008-03-15)
903+ * @package lightvc
904+ * @see http://lightvc.org/
905+ **/
906+
907+/**
908+ * Configuration class for the LVC suite of classes.
909+ *
910+ * @package lightvc
911+ * @author Anthony Bush
912+ * @since 2007-04-20
913+ **/
914+class Lvc_Config {
915+ protected static $controllerPaths = array();
916+ protected static $controllerSuffix = '.php'; // e.g. _controller.php
917+ protected static $controllerViewPaths = array();
918+ protected static $controllerViewSuffix = '.php'; // e.g. .tpl.php
919+ protected static $layoutViewPaths = array();
920+ protected static $layoutViewSuffix = '.php'; // e.g. .tpl.php
921+ protected static $elementViewPaths = array();
922+ protected static $elementViewSuffix = '.php'; // e.g. .tpl.php
923+ protected static $viewClassName = 'Lvc_View'; // e.g. AppView
924+ protected static $layoutContentVarName = 'layoutContent'; // e.g. content_for_layout
925+
926+ /**
927+ * Sets whether or not to send action params as an array or as arguments
928+ * to the function.
929+ *
930+ * true => action($params)
931+ * false => action($param1, $param2, $param3, ...)
932+ *
933+ * @var boolean
934+ **/
935+ protected static $sendActionParamsAsArray = false;
936+
937+ // These may be moved into some sort of routing thing later. For now:
938+
939+ /**
940+ * The controller name to use if no controller name can be gathered from the request.
941+ *
942+ * @var string
943+ **/
944+ protected static $defaultControllerName = 'page';
945+ /**
946+ * The action name to call on the defaultControllerName if no controller name can be gathered from the request.
947+ *
948+ * @var string
949+ **/
950+ protected static $defaultControllerActionName = 'view';
951+ /**
952+ * The action params to use when calling defaultControllerActionName if no controller name can be gathered from the request.
953+ *
954+ * @var string
955+ **/
956+ protected static $defaultControllerActionParams = array('page_name' => 'home');
957+ /**
958+ * The default action name to call on a controller if the controller name
959+ * was gathered from the request, but the action name couldn't be.
960+ *
961+ * @var string
962+ **/
963+ protected static $defaultActionName = 'index';
964+
965+ // Configuration Methods
966+
967+ public static function addControllerPath($path) {
968+ self::$controllerPaths[] = $path;
969+ }
970+ public static function setControllerSuffix($suffix) {
971+ self::$controllerSuffix = $suffix;
972+ }
973+ public static function addControllerViewPath($path) {
974+ self::$controllerViewPaths[] = $path;
975+ }
976+ public static function setControllerViewSuffix($suffix) {
977+ self::$controllerViewSuffix = $suffix;
978+ }
979+ public static function addLayoutViewPath($path) {
980+ self::$layoutViewPaths[] = $path;
981+ }
982+ public static function setLayoutViewSuffix($suffix) {
983+ self::$layoutViewSuffix = $suffix;
984+ }
985+ public static function addElementViewPath($path) {
986+ self::$elementViewPaths[] = $path;
987+ }
988+ public static function setElementViewSuffix($suffix) {
989+ self::$elementViewSuffix = $suffix;
990+ }
991+ public static function setViewClassName($className) {
992+ self::$viewClassName = $className;
993+ }
994+ public static function setLayoutContentVarName($varName) {
995+ self::$layoutContentVarName = $varName;
996+ }
997+ public static function getLayoutContentVarName() {
998+ return self::$layoutContentVarName;
999+ }
1000+ public static function setSendActionParamsAsArray($bool) {
1001+ self::$sendActionParamsAsArray = $bool;
1002+ }
1003+ public static function getSendActionParamsAsArray() {
1004+ return self::$sendActionParamsAsArray;
1005+ }
1006+ public static function setDefaultControllerName($defaultControllerName) {
1007+ self::$defaultControllerName = $defaultControllerName;
1008+ }
1009+ public static function setDefaultControllerActionName($defaultControllerActionName) {
1010+ self::$defaultControllerActionName = $defaultControllerActionName;
1011+ }
1012+ public static function setDefaultControllerActionParams($defaultControllerActionParams) {
1013+ self::$defaultControllerActionParams = $defaultControllerActionParams;
1014+ }
1015+ public static function setDefaultActionName($defaultActionName) {
1016+ self::$defaultActionName = $defaultActionName;
1017+ }
1018+ public static function getDefaultControllerName() {
1019+ return self::$defaultControllerName;
1020+ }
1021+ public static function getDefaultControllerActionName() {
1022+ return self::$defaultControllerActionName;
1023+ }
1024+ public static function getDefaultControllerActionParams() {
1025+ return self::$defaultControllerActionParams;
1026+ }
1027+ public static function getDefaultActionName() {
1028+ return self::$defaultActionName;
1029+ }
1030+
1031+ // Retrieval Methods
1032+
1033+ public static function getController($controllerName) {
1034+ foreach (self::$controllerPaths as $path) {
1035+ $file = $path . $controllerName . self::$controllerSuffix;
1036+ if (file_exists($file)) {
1037+ include_once($file);
1038+ $controllerClass = self::getControllerClassName($controllerName);
1039+ $controller = new $controllerClass();
1040+ $controller->setControllerName($controllerName);
1041+ return $controller;
1042+ }
1043+ }
1044+ return null;
1045+ }
1046+
1047+ public static function getControllerClassName($controllerName) {
1048+ return str_replace(' ', '', ucwords(str_replace(array('_', '/'), ' ', $controllerName))) . 'Controller';
1049+ }
1050+
1051+ public static function getActionFunctionName($actionName) {
1052+ return 'action' . str_replace(' ', '', ucwords(str_replace('_', ' ', $actionName)));
1053+ }
1054+
1055+ public static function getControllerView($viewName, &$data = array()) {
1056+ return self::getView($viewName, $data, self::$controllerViewPaths, self::$controllerViewSuffix);
1057+ }
1058+
1059+ public static function getElementView($elementName, &$data = array()) {
1060+ return self::getView($elementName, $data, self::$elementViewPaths, self::$elementViewSuffix);
1061+ }
1062+
1063+ public static function getLayoutView($layoutName, &$data = array()) {
1064+ return self::getView($layoutName, $data, self::$layoutViewPaths, self::$layoutViewSuffix);
1065+ }
1066+
1067+ /**
1068+ * As an Lvc developer, you'll probably want to use `getControllerView`,
1069+ * `getElementView`, or `getLayoutView`.
1070+ *
1071+ * Example usage:
1072+ *
1073+ * // Pass the whole file name and leave off the last parameters
1074+ * getView('/full/path/to/file/file.php', $data);
1075+ *
1076+ * // Pass the view name and specify the paths to scan and the suffix to append.
1077+ * getView('file', $data, array('/full/path/to/file/'), '.php');
1078+ *
1079+ * @var mixed Lvc_View object if one is found, otherwise null.
1080+ * @see getControllerView(), getElementView(), getLayoutView(), Lvc_Config::setViewClassName()
1081+ **/
1082+ public static function getView($viewName, &$data = array(), &$paths = array(''), $suffix = '') {
1083+ foreach ($paths as $path) {
1084+ $file = $path . $viewName . $suffix;
1085+ if (file_exists($file)) {
1086+ return new self::$viewClassName($file, $data);
1087+ }
1088+ }
1089+ return null;
1090+ }
1091+
1092+ public static function dump() {
1093+ echo '<pre>';
1094+
1095+ echo '<strong>Controller Paths:</strong>' . "\n";
1096+ print_r(self::$controllerPaths);
1097+ echo '<strong>Controller Suffix:</strong> ' . self::$controllerSuffix . "\n\n";
1098+
1099+ echo '<strong>Layout View Paths:</strong>' . "\n";
1100+ print_r(self::$layoutViewPaths);
1101+ echo '<strong>Layout View Suffix:</strong> ' . self::$layoutViewSuffix . "\n\n";
1102+
1103+ echo '<strong>Controller View Paths:</strong>' . "\n";
1104+ print_r(self::$controllerViewPaths);
1105+ echo '<strong>Controller View Suffix:</strong> ' . self::$controllerViewSuffix . "\n\n";
1106+
1107+ echo '<strong>Element View Paths:</strong>' . "\n";
1108+ print_r(self::$elementViewPaths);
1109+ echo '<strong>Element View Suffix:</strong> ' . self::$elementViewSuffix . "\n\n";
1110+
1111+ echo '</pre>';
1112+ }
1113+}
1114+
1115+/**
1116+ * Lvc classes throw this type of exception.
1117+ *
1118+ * @package lightvc
1119+ * @author Anthony Bush
1120+ * @since 2007-04-20
1121+ **/
1122+class Lvc_Exception extends Exception {
1123+
1124+}
1125+
1126+/**
1127+ * A request provides information about what controller and action to run and
1128+ * what parameters to run them with.
1129+ *
1130+ * @package lightvc
1131+ * @author Anthony Bush
1132+ * @since 2007-04-20
1133+ **/
1134+class Lvc_Request {
1135+ protected $controllerName = '';
1136+ protected $controllerParams = array();
1137+ protected $actionName = '';
1138+ protected $actionParams = array();
1139+
1140+ public function getControllerName() {
1141+ return $this->controllerName;
1142+ }
1143+ public function &getControllerParams() {
1144+ return $this->controllerParams;
1145+ }
1146+ public function getActionName() {
1147+ return $this->actionName;
1148+ }
1149+ public function &getActionParams() {
1150+ return $this->actionParams;
1151+ }
1152+
1153+ public function setControllerName($controllerName) {
1154+ $this->controllerName = trim($controllerName);
1155+ }
1156+ public function setControllerParams(&$controllerParams) {
1157+ $this->controllerParams = $controllerParams;
1158+ }
1159+ public function setActionName($actionName) {
1160+ $this->actionName = trim($actionName);
1161+ }
1162+ public function setActionParams($actionParams) {
1163+ $this->actionParams = $actionParams;
1164+ }
1165+
1166+ /**
1167+ * Override this in sub request objects to have custom error messages appended to
1168+ * LightVC messages. For example, when HTTP Requests error, it might be useful
1169+ * to put the requested URL in the error log with the "Unable to load controller"
1170+ * message.
1171+ *
1172+ * @return string
1173+ * @since 2008-03-14
1174+ **/
1175+ public function getAdditionalErrorInfo() {
1176+ return '';
1177+ }
1178+}
1179+
1180+/**
1181+ * An HTTP request contains parameters from the GET, POST, PUT, and
1182+ * DELETE arena.
1183+ *
1184+ * @package lightvc
1185+ * @author Anthony Bush
1186+ * @since 2007-04-20
1187+ **/
1188+class Lvc_HttpRequest extends Lvc_Request {
1189+ protected $params = array();
1190+
1191+ public function __construct() {
1192+
1193+ $params = array();
1194+
1195+ // Save GET data
1196+ if (isset($_GET)) {
1197+ $params['get'] =& $_GET;
1198+ } else {
1199+ $params['get'] = array();
1200+ }
1201+
1202+ // Ensure that we have some mode_rewritten url.
1203+ if (!isset($params['get']['url'])) {
1204+ $params['get']['url'] = '';
1205+ }
1206+
1207+ // Save POST data
1208+ $params['post'] =& $_POST;
1209+
1210+ // Save FILE data (consolidate it with _POST data)
1211+ foreach ($_FILES as $name => $data) {
1212+ if ($name != 'data') {
1213+ $params['post'][$name] = $data;
1214+ } else {
1215+ // Convert _FILE[data][key][model][field] -> [data][model][field][key]
1216+ // so that it matches up with _POST "data"
1217+ foreach ($data as $key => $modelData) {
1218+ foreach ($modelData as $model => $fields) {
1219+ foreach ($fields as $field => $value) {
1220+ $params['post']['data'][$model][$field][$key] = $value;
1221+ }
1222+ }
1223+ }
1224+ }
1225+ }
1226+
1227+ // Set params that will be used by routers.
1228+ $this->setParams($params);
1229+ // An HTTP request will default to passing all the parameters to the controller.
1230+ $this->setControllerParams($params);
1231+ }
1232+
1233+ public function &getParams() {
1234+ return $this->params;
1235+ }
1236+ public function setParams(&$params) {
1237+ $this->params = $params;
1238+ }
1239+
1240+ /**
1241+ * Provides additional error information that might be useful when debugging
1242+ * errors.
1243+ *
1244+ * @return string
1245+ * @since 2008-03-14
1246+ **/
1247+ public function getAdditionalErrorInfo() {
1248+ if (isset($_SERVER['REQUEST_URI'])) {
1249+ return 'Request URL was ' . $_SERVER['REQUEST_URI'];
1250+ } else {
1251+ return parent::getAdditionalErrorInfo();
1252+ }
1253+ }
1254+}
1255+
1256+/**
1257+ * A router interface must at least provide a route() function that takes a
1258+ * request object.
1259+ *
1260+ * @package lightvc
1261+ * @author Anthony Bush
1262+ * @since 2007-04-22
1263+ **/
1264+interface Lvc_RouterInterface {
1265+ /**
1266+ * Set the appropriate controller, action, and action parameters to use on
1267+ * the request object and return true. If no appropriate controller info
1268+ * can be found, return false.
1269+ *
1270+ * @param mixed $request A request object to route.
1271+ * @return boolean
1272+ * @author Anthony Bush
1273+ * @since 2007-04-22
1274+ **/
1275+ public function route($request);
1276+}
1277+
1278+/**
1279+ * Routes a request using only GET data.
1280+ *
1281+ * You can change the default keys for controller and action detection using
1282+ * {@link setControllerKey()} and {@link setActionKey()} respectively.
1283+ *
1284+ * @package lightvc
1285+ * @author Anthony Bush
1286+ * @since 2007-04-22
1287+ **/
1288+class Lvc_GetRouter implements Lvc_RouterInterface {
1289+ protected $controllerKey = 'controller';
1290+ protected $actionKey = 'action';
1291+ protected $actionParamsKey = null;
1292+ protected $routes = array();
1293+
1294+ public function setControllerKey($controllerKey) {
1295+ $this->controllerKey = $controllerKey;
1296+ }
1297+ public function setActionKey($actionKey) {
1298+ $this->actionKey = $actionKey;
1299+ }
1300+ public function setActionParamsKey($actionParamsKey) {
1301+ $this->actionParamsKey = $actionParamsKey;
1302+ }
1303+
1304+ /**
1305+ * Add a param order for a controller / action.
1306+ *
1307+ * For example:
1308+ *
1309+ * $router->addRoute('pages', 'show_page', array('page_name'));
1310+ *
1311+ * will route:
1312+ *
1313+ * ?controller=pages&action=show_page&page_name=about
1314+ *
1315+ * to:
1316+ *
1317+ * PagesController::actionShowPage('about');
1318+ *
1319+ * whereas without the route the controller would be invoked with:
1320+ *
1321+ * PagesController::actionShowPage();
1322+ *
1323+ * and you'd have to access the page_name via $this->get['page_name'].
1324+ *
1325+ * @return void
1326+ * @author Anthony Bush
1327+ * @since 2007-05-10
1328+ **/
1329+ public function addRoute($controllerName, $actionName, $actionParamsOrder = array()) {
1330+ $this->routes[$controllerName][$actionName] = $actionParamsOrder;
1331+ }
1332+
1333+ /**
1334+ * Set all routes at once. Useful if you want to specify routes in a
1335+ * config file and then pass them to this router all at once. See
1336+ * {@link addRoute()} for routing specifications.
1337+ *
1338+ * @return void
1339+ * @author Anthony Bush
1340+ * @since 2007-05-10
1341+ **/
1342+ public function setRoutes(&$routes) {
1343+ $this->routes = $routes;
1344+ }
1345+
1346+ /**
1347+ * Construct the router and set all routes at once. See {@link setRoutes()}
1348+ * for more info.
1349+ *
1350+ * @return void
1351+ * @author Anthony Bush
1352+ * @see setRoutes()
1353+ * @since 2007-05-10
1354+ **/
1355+ public function __construct(&$routes = null) {
1356+ if ( ! is_null($routes)) {
1357+ $this->setRoutes($routes);
1358+ }
1359+ }
1360+
1361+ /**
1362+ * Attempts to routes a request using only the GET data.
1363+ *
1364+ * @param Lvc_HttpRequest $request A request object to route.
1365+ * @return boolean
1366+ * @author Anthony Bush
1367+ * @since 2007-04-22
1368+ **/
1369+ public function route($request) {
1370+ $params = $request->getParams();
1371+
1372+ // Use GET parameters to set controller, action, and action params
1373+ if (isset($params['get'][$this->controllerKey])) {
1374+
1375+ $request->setControllerName($params['get'][$this->controllerKey]);
1376+
1377+ if (isset($params['get'][$this->actionKey])) {
1378+ $request->setActionName($params['get'][$this->actionKey]);
1379+ } else {
1380+ $request->setActionName(Lvc_Config::getDefaultActionName());
1381+ }
1382+
1383+ // Using paramsKey method?
1384+ if ( ! is_null($this->actionParamsKey) && isset($params['get'][$this->actionParamsKey])) {
1385+ $request->setActionParams($params['get'][$this->actionParamsKey]);
1386+ }
1387+ // Using routes?
1388+ else if ( ! empty($this->routes)) {
1389+ if (isset($this->routes[$request->getControllerName()])
1390+ && isset($this->routes[$request->getControllerName()][$request->getActionName()])
1391+ ) {
1392+ $actionParams = array();
1393+ foreach ($this->routes[$request->getControllerName()][$request->getActionName()] as $paramName) {
1394+ $actionParams[$paramName] = @$params['get'][$paramName];
1395+ }
1396+ $request->setActionParams($actionParams);
1397+ }
1398+ }
1399+
1400+ return true;
1401+ } else {
1402+ return false;
1403+ }
1404+ }
1405+}
1406+
1407+/**
1408+ * Attempts to route a request using the GET value for the 'url' key, which
1409+ * should be set by the mod_rewrite rules. Any additional "directories" are
1410+ * used as parameters for the action (using numeric indexes). Any extra GET
1411+ * data is also amended to the action parameters.
1412+ *
1413+ * If you need the numeric indexes to map to specific parameter names, use
1414+ * the {@link Lvc_ParamOrderRewriteRouter} instead.
1415+ *
1416+ * @package lightvc
1417+ * @author Anthony Bush
1418+ * @since 2007-04-22
1419+ **/
1420+class Lvc_RewriteRouter implements Lvc_RouterInterface {
1421+ /**
1422+ * Attempts to route a request using the GET value for the 'url' key, which
1423+ * should be set by the mod_rewrite rules. Any additional "directories" are
1424+ * used as parameters for the action (using numeric indexes). Any extra GET
1425+ * data is also amended to the action parameters.
1426+ *
1427+ * @param Lvc_HttpRequest $request A request object to route.
1428+ * @return boolean
1429+ * @author Anthony Bush
1430+ * @since 2007-04-22
1431+ **/
1432+ public function route($request) {
1433+ $params = $request->getParams();
1434+
1435+ if (isset($params['get']['url'])) {
1436+
1437+ // Use mod_rewrite's url
1438+ $url = explode('/', $params['get']['url']);
1439+ $count = count($url);
1440+
1441+ // Set controller, action, and some action params from the segmented URL.
1442+ if ($count > 0) {
1443+ $request->setControllerName($url[0]);
1444+
1445+ $actionParams = array();
1446+ if ($count > 1) {
1447+ $request->setActionName($url[1]);
1448+ if ($count > 2) {
1449+ for ($i = 2; $i < $count; $i++) {
1450+ if ( ! empty($url[$i])) {
1451+ $actionParams[] = $url[$i];
1452+ }
1453+ }
1454+ }
1455+ }
1456+
1457+ $request->setActionParams($actionParams);
1458+ return true;
1459+ }
1460+ }
1461+ return false;
1462+ }
1463+}
1464+
1465+/**
1466+ * Routes a request using mod_rewrite data and regular expressions specified by
1467+ * the LightVC user.
1468+ *
1469+ * Specify routes using {@link addRoute()}.
1470+ *
1471+ * @package lightvc
1472+ * @author Anthony Bush
1473+ * @since 2007-05-08
1474+ **/
1475+class Lvc_RegexRewriteRouter implements Lvc_RouterInterface {
1476+ protected $routes = array();
1477+
1478+ /**
1479+ * Specify a regular expression and how it should be routed.
1480+ *
1481+ * For example:
1482+ *
1483+ * $regexRouter->addRoute('|^wee/([^/]+)/?$|', array(
1484+ * 'controller' => 'hello_world',
1485+ * 'action' => 'index',
1486+ * 'action_params' => array(1, 'constant_value')
1487+ * ));
1488+ *
1489+ * would map "wee/anything" and "wee/anything/" to:
1490+ *
1491+ * HelloWorldController::actionIndex('anything', 'constant_value');
1492+ *
1493+ * but would not map "wee/anything/anything_else".
1494+ *
1495+ * The format of the $parsingInfo parameter is as follows:
1496+ *
1497+ * 'controller' => a hard coded controller name or an integer specifying which match in the regex to use.
1498+ * 'action' => a hard coded action name or an integer specifying which match in the regex to use.
1499+ * 'action_params' => array(
1500+ * a hard coded action value or an integer specifying which match in the regex to use,
1501+ * repeat above line as needed,
1502+ * ),
1503+ * 'additional_params' => a hard coded integer specifying which match in the regex to use for additional parameters. These will be exploded by "/" and added to the action params.
1504+ *
1505+ * or
1506+ *
1507+ * 'redirect' => a replacement string that will be used to redirect to. You can have parts of the original url mapped into the new one (like IDs). See http://www.php.net/manual/en/function.preg-replace.php's documentation for the replacement parameter.
1508+ *
1509+ * You can specify as much or as little as you want in the $parsingInfo.
1510+ * That is, if you don't specify the controller name or action name, then
1511+ * the defaults will be used by the Lvc_FrontController.
1512+ *
1513+ * @param $regex regular expression to match the rewritten part with.
1514+ * @param $parsingInfo an array containing any custom routing info.
1515+ * @return void
1516+ * @author Anthony Bush
1517+ * @since 2007-05-08
1518+ **/
1519+ public function addRoute($regex, $parsingInfo = array()) {
1520+ $this->routes[$regex] = $parsingInfo;
1521+ }
1522+
1523+ /**
1524+ * Set all routes at once. Useful if you want to specify routes in a
1525+ * config file and then pass them to this router all at once. See
1526+ * {@link addRoute()} for routing specifications.
1527+ *
1528+ * @return void
1529+ * @author Anthony Bush
1530+ * @since 2007-05-08
1531+ **/
1532+ public function setRoutes(&$routes) {
1533+ $this->routes = $routes;
1534+ }
1535+
1536+ /**
1537+ * Construct the router and set all routes at once. See {@link setRoutes()}
1538+ * for more info.
1539+ *
1540+ * @return void
1541+ * @author Anthony Bush
1542+ * @see setRoutes()
1543+ * @since 2007-05-09
1544+ **/
1545+ public function __construct(&$routes = null) {
1546+ if ( ! is_null($routes)) {
1547+ $this->setRoutes($routes);
1548+ }
1549+ }
1550+
1551+ /**
1552+ * Routes like {@link Lvc_RewriteRouter} does, with the additional check to
1553+ * routes for specifying custom routes based on regular expressions.
1554+ *
1555+ * @param Lvc_HttpRequest $request A request object to route.
1556+ * @return boolean
1557+ * @author Anthony Bush
1558+ * @since 2007-05-08
1559+ **/
1560+ public function route($request) {
1561+ $params = $request->getParams();
1562+
1563+ if (isset($params['get']['url'])) {
1564+
1565+ // Use mod_rewrite's url
1566+ $url = $params['get']['url'];
1567+
1568+ $matches = array();
1569+ foreach ($this->routes as $regex => $parsingInfo) {
1570+ if (preg_match($regex, $url, $matches)) {
1571+
1572+ // Check for redirect action first
1573+ if (isset($parsingInfo['redirect'])) {
1574+ $redirectUrl = preg_replace($regex, $parsingInfo['redirect'], $url);
1575+ // Output any custom headers, e.g. "HTTP/1.1 301 Moved Permanently"
1576+ if (isset($parsingInfo['headers']))
1577+ {
1578+ if (is_array($parsingInfo['headers']))
1579+ {
1580+ foreach ($parsingInfo['headers'] as $header)
1581+ {
1582+ header($header);
1583+ }
1584+ }
1585+ else
1586+ {
1587+ header($parsingInfo['headers']);
1588+ }
1589+ }
1590+ header('Location: ' . $redirectUrl);
1591+ exit();
1592+ }
1593+
1594+ // Get controller name if available
1595+ if (isset($parsingInfo['controller'])) {
1596+ if (is_int($parsingInfo['controller'])) {
1597+ // Get the controller name from the regex matches
1598+ $request->setControllerName(@$matches[$parsingInfo['controller']]);
1599+ } else {
1600+ // Use the constant value
1601+ $request->setControllerName($parsingInfo['controller']);
1602+ }
1603+ }
1604+
1605+ // Get action name if available
1606+ if (isset($parsingInfo['action'])) {
1607+ if (is_int($parsingInfo['action'])) {
1608+ // Get the action from the regex matches
1609+ $request->setActionName(@$matches[$parsingInfo['action']]);
1610+ } else {
1611+ // Use the constant value
1612+ $request->setActionName($parsingInfo['action']);
1613+ }
1614+ }
1615+
1616+ // Get action parameters
1617+ $actionParams = array();
1618+ if (isset($parsingInfo['action_params'])) {
1619+ foreach ($parsingInfo['action_params'] as $key => $value) {
1620+ if (is_int($value)) {
1621+ // Get the value from the regex matches
1622+ if (isset($matches[$value])) {
1623+ $actionParams[$key] = $matches[$value];
1624+ } else {
1625+ $actionParams[$key] = null;
1626+ }
1627+ } else {
1628+ // Use the constant value
1629+ $actionParams[$key] = $value;
1630+ }
1631+ }
1632+ }
1633+ if (isset($parsingInfo['additional_params'])) {
1634+ if (is_int($parsingInfo['additional_params'])) {
1635+ // Get the value from the regex matches
1636+ if (isset($matches[$parsingInfo['additional_params']])) {
1637+ $actionParams = $actionParams + explode('/', $matches[$parsingInfo['additional_params']]);
1638+ }
1639+ }
1640+ }
1641+
1642+
1643+ $request->setActionParams($actionParams);
1644+ return true;
1645+ } // route matched
1646+ } // loop through routes
1647+ } // url _GET value set
1648+ return false;
1649+ }
1650+}
1651+
1652+/**
1653+ * FrontController takes a Request object and invokes the appropriate controller
1654+ * and action.
1655+ *
1656+ * Example Usage:
1657+ *
1658+ * $fc = new Lvc_FrontController();
1659+ * $fc->addRouter(new Lvc_GetRouter());
1660+ * $fc->processRequest(new Lvc_HttpRequest());
1661+ *
1662+ * @package lightvc
1663+ * @author Anthony Bush
1664+ * @since 2007-04-20
1665+ **/
1666+class Lvc_FrontController {
1667+ protected $routers = array();
1668+
1669+ /**
1670+ * Add a router to give it a chance to route the request.
1671+ *
1672+ * The first router to return true to the {@link route()} call
1673+ * will be the last router called, so add them in the order you want them
1674+ * to run.
1675+ *
1676+ * @return void
1677+ * @author Anthony Bush
1678+ **/
1679+ public function addRouter(Lvc_RouterInterface $router) {
1680+ $this->routers[] = $router;
1681+ }
1682+
1683+ /**
1684+ * Processes the request data by instantiating the appropriate controller and
1685+ * running the appropriate action.
1686+ *
1687+ * @return void
1688+ * @throws Lvc_Exception
1689+ * @author Anthony Bush
1690+ **/
1691+ public function processRequest(Lvc_Request $request) {
1692+ try
1693+ {
1694+ // Give routers a chance to (re)-route the request.
1695+ foreach ($this->routers as $router) {
1696+ if ($router->route($request)) {
1697+ break;
1698+ }
1699+ }
1700+
1701+ // If controller name or action name are not set, set them to default.
1702+ $controllerName = $request->getControllerName();
1703+ if (empty($controllerName)) {
1704+ $controllerName = Lvc_Config::getDefaultControllerName();
1705+ $actionName = Lvc_Config::getDefaultControllerActionName();
1706+ $actionParams = $request->getActionParams() + Lvc_Config::getDefaultControllerActionParams();
1707+ $request->setActionParams($actionParams);
1708+ } else {
1709+ $actionName = $request->getActionName();
1710+ if (empty($actionName)) {
1711+ $actionName = Lvc_Config::getDefaultActionName();
1712+ }
1713+ }
1714+
1715+ $controller = Lvc_Config::getController($controllerName);
1716+ if (is_null($controller)) {
1717+ throw new Lvc_Exception('Unable to load controller "' . $controllerName . '"');
1718+ }
1719+ $controller->setControllerParams($request->getControllerParams());
1720+ $controller->runAction($actionName, $request->getActionParams());
1721+ }
1722+ catch (Lvc_Exception $e)
1723+ {
1724+ // Catch exceptions and append additional error info if the request object has anything to say.
1725+ $moreInfo = $request->getAdditionalErrorInfo();
1726+ if (!empty($moreInfo)) {
1727+ throw new Lvc_Exception($e->getMessage() . '. ' . $moreInfo);
1728+ } else {
1729+ throw $e;
1730+ }
1731+ }
1732+ }
1733+}
1734+
1735+/**
1736+ * The base class that all other PageControllers should extend. Depending on the setup,
1737+ * you might want an AppController to extend this one, and then have all your controllers
1738+ * extend your AppController.
1739+ *
1740+ * @package lightvc
1741+ * @author Anthony Bush
1742+ * @todo Finish up documentation in here...
1743+ * @since 2007-04-20
1744+ **/
1745+class Lvc_PageController {
1746+ /**
1747+ * Params is typically a combination of:
1748+ * _GET (stored in params['get'])
1749+ * _POST (stored in params['post'])
1750+ * _FILE (also stored in params['post'])
1751+ *
1752+ * @var array
1753+ **/
1754+ protected $params = array();
1755+
1756+ /**
1757+ * A reference to $params['post']['data'], typically a combination of:
1758+ * _POST['data'] (usually holds [Model][field])
1759+ * _FILE['data'] (usually holds [key][Model][field], but the request object should remap it to [Model][field][key])
1760+ *
1761+ * @var array
1762+ **/
1763+ protected $postData = array();
1764+
1765+ /**
1766+ * Reference to post data (i.e. $this->params['post'])
1767+ *
1768+ * @var array
1769+ **/
1770+ protected $post = array();
1771+
1772+ /**
1773+ * Reference to get data (i.e. $this->params['get'])
1774+ *
1775+ * @var array
1776+ **/
1777+ protected $get = array();
1778+
1779+ /**
1780+ * Controller Name (e.g. controller_name, not ControllerNameController)
1781+ *
1782+ * @var string
1783+ **/
1784+ protected $controllerName = null;
1785+
1786+ /**
1787+ * Action Name (e.g. action_name, not actionActionName)
1788+ *
1789+ * @var string
1790+ **/
1791+ protected $actionName = null;
1792+
1793+ /**
1794+ * Variables we will pass to the view.
1795+ *
1796+ * @var array()
1797+ **/
1798+ protected $viewVars = array();
1799+
1800+ /**
1801+ * Have we loaded the view yet?
1802+ *
1803+ * @var boolean
1804+ **/
1805+ protected $hasLoadedView = false;
1806+
1807+ /**
1808+ * Specifies whether or not to load the default view for the action. If the
1809+ * action should not render any view, set it to false in the sub controller.
1810+ *
1811+ * @var boolean
1812+ **/
1813+ protected $loadDefaultView = true;
1814+
1815+ /**
1816+ * Don't set this yourself. It's used internally by parent controller /
1817+ * actions to determine whether or not to use the layout value in
1818+ * $layoutOverride rather than in $layout when requesting a sub action.
1819+ *
1820+ * @var string
1821+ * @see setLayoutOverride(), $layoutOverride
1822+ **/
1823+ protected $useLayoutOverride = false;
1824+
1825+ /**
1826+ * Don't set this yourself. It's used internally by parent controller /
1827+ * actions to determine which layout to use when requesting a sub action.
1828+ *
1829+ * @var string
1830+ * @see setLayoutOverride(), $useLayoutOverride
1831+ **/
1832+ protected $layoutOverride = null;
1833+
1834+ /**
1835+ * Set this in your controller to use a layout.
1836+ *
1837+ * @var string
1838+ **/
1839+ protected $layout = null;
1840+
1841+ /**
1842+ * An array of view variables specifically for the layout file.
1843+ *
1844+ * @var array
1845+ **/
1846+ protected $layoutVars = array();
1847+
1848+ /**
1849+ * Set the parameters of the controller.
1850+ * Actions will get their parameters through params['get'].
1851+ * Actions can access the post data as needed.
1852+ *
1853+ * @param array $params an array of [paramName] => [paramValue] pairs
1854+ * @return void
1855+ * @author Anthony Bush
1856+ **/
1857+ public function setControllerParams(&$params) {
1858+ $this->params = $params;
1859+ // Make a reference to the form data so we can get to it easier.
1860+ if (isset($this->params['post']['data'])) {
1861+ $this->postData =& $this->params['post']['data'];
1862+ }
1863+ if (isset($this->params['post'])) {
1864+ $this->post =& $this->params['post'];
1865+ }
1866+ if (isset($this->params['get'])) {
1867+ $this->get =& $this->params['get'];
1868+ }
1869+ }
1870+
1871+ /**
1872+ * Don't call this yourself. It's used internally when creating new
1873+ * controllers so the controllers are aware of their name without
1874+ * needing any help from a user setting a member variable or from some
1875+ * reflector class.
1876+ *
1877+ * @return void
1878+ * @author Anthony Bush
1879+ **/
1880+ public function setControllerName($controllerName) {
1881+ $this->controllerName = $controllerName;
1882+ }
1883+
1884+ /**
1885+ * Set a variable for the view to use.
1886+ *
1887+ * @param string $varName variable name to make available in the view
1888+ * @param $value value of the variable.
1889+ * @return void
1890+ * @author Anthony Bush
1891+ **/
1892+ public function setVar($varName, $value) {
1893+ $this->viewVars[$varName] = $value;
1894+ }
1895+
1896+ /**
1897+ * Set variables for the view in masse.
1898+ *
1899+ * @param $varArray an array of [varName] => [value] pairs.
1900+ * @return void
1901+ * @author Anthony Bush
1902+ **/
1903+ public function setVars(&$varArray) {
1904+ $this->viewVars = $varArray + $this->viewVars;
1905+ }
1906+
1907+ /**
1908+ * Get the current value for a view variable.
1909+ *
1910+ * @param string $varName
1911+ * @return mixed
1912+ * @author Anthony Bush
1913+ * @since 2007-11-13
1914+ **/
1915+ public function getVar($varName) {
1916+ if (isset($this->viewVars[$varName])) {
1917+ return $this->viewVars[$varName];
1918+ } else {
1919+ return null;
1920+ }
1921+ }
1922+
1923+ /**
1924+ * Set a variable for the layout view.
1925+ *
1926+ * @param $varName variable name to make available in the view
1927+ * @param $value value of the variable.
1928+ * @return void
1929+ * @author Anthony Bush
1930+ * @since 2007-05-17
1931+ **/
1932+ public function setLayoutVar($varName, $value) {
1933+ $this->layoutVars[$varName] = $value;
1934+ }
1935+
1936+ /**
1937+ * Get the current value for a layout variable.
1938+ *
1939+ * @param string $varName
1940+ * @return mixed
1941+ * @author Anthony Bush
1942+ * @since 2007-11-13
1943+ **/
1944+ public function getLayoutVar($varName) {
1945+ if (isset($this->layoutVars[$varName])) {
1946+ return $this->layoutVars[$varName];
1947+ } else {
1948+ return null;
1949+ }
1950+ }
1951+
1952+ /**
1953+ * Set the layout to use for the view.
1954+ *
1955+ * @return void
1956+ * @author Anthony Bush
1957+ **/
1958+ public function setLayout($layout) {
1959+ $this->layout = $layout;
1960+ }
1961+
1962+ /**
1963+ * Don't call this yourself. It's used internally when requesting sub
1964+ * actions in order to avoid loading the layout multiple times.
1965+ *
1966+ * @return void
1967+ * @see $useLayoutOverride, $layoutOverride
1968+ * @author Anthony Bush
1969+ **/
1970+ public function setLayoutOverride($layout) {
1971+ $this->useLayoutOverride = true;
1972+ $this->layoutOverride = $layout;
1973+ }
1974+
1975+ /**
1976+ * Returns the action name of this controller
1977+ *
1978+ * @return string
1979+ * @author lzhang
1980+ **/
1981+ public function getActionName()
1982+ {
1983+ return $this->actionName;
1984+ }
1985+
1986+ /**
1987+ * Determine whether or not the the controller has the specified action.
1988+ *
1989+ * @param string $actionName the action name to check for.
1990+ * @return boolean
1991+ * @author Anthony Bush
1992+ **/
1993+ public function hasAction($actionName) {
1994+ if (method_exists($this, Lvc_Config::getActionFunctionName($actionName))) {
1995+ return true;
1996+ } else {
1997+ return false;
1998+ }
1999+ }
2000+
2001+ /**
2002+ * Runs the requested action and returns the output from it.
2003+ *
2004+ * Typically called by the FrontController.
2005+ *
2006+ * @param string $actionName the action name to run.
2007+ * @param array $actionParams the parameters to pass to the action.
2008+ * @return string output from running the action.
2009+ * @author Anthony Bush
2010+ **/
2011+ public function getActionOutput($actionName, &$actionParams = array()) {
2012+ ob_start();
2013+ $this->runAction($actionName, $actionParams);
2014+ return ob_get_clean();
2015+ }
2016+
2017+ /**
2018+ * Runs the requested action and outputs its results.
2019+ *
2020+ * Typically called by the FrontController.
2021+ *
2022+ * @param string $actionName the action name to run.
2023+ * @param array $actionParams the parameters to pass to the action.
2024+ * @return void
2025+ * @throws Lvc_Exception
2026+ * @author Anthony Bush
2027+ **/
2028+ public function runAction($actionName, &$actionParams = array()) {
2029+ $this->actionName = $actionName;
2030+ $func = Lvc_Config::getActionFunctionName($actionName);
2031+ if (method_exists($this, $func)) {
2032+ $this->beforeAction();
2033+
2034+ // Call the action
2035+ if (Lvc_Config::getSendActionParamsAsArray()) {
2036+ $this->$func($actionParams);
2037+ } else {
2038+ call_user_func_array(array($this, $func), $actionParams);
2039+ }
2040+
2041+ // Load the view
2042+ if ( ! $this->hasLoadedView && $this->loadDefaultView) {
2043+ $this->loadView($this->controllerName . '/' . $actionName);
2044+ }
2045+
2046+ $this->afterAction();
2047+ return true;
2048+ } else {
2049+ throw new Lvc_Exception('No action `' . $actionName . '`. Write the `' . $func . '` method');
2050+ }
2051+ }
2052+
2053+ /**
2054+ * Load the requested controller view.
2055+ *
2056+ * For example, you can load another view in your controller with:
2057+ *
2058+ * $this->loadView($this->getControllerName() . '/some_other_action');
2059+ *
2060+ * Or some other controller with:
2061+ *
2062+ * $this->loadView('some_other_controller/some_other_action');
2063+ *
2064+ * Remember, the view for your action will be rendered automatically.
2065+ *
2066+ * @param string $controllerViewName 'controller_name/action_name' format.
2067+ * @return void
2068+ * @throws Lvc_Exception
2069+ * @author Anthony Bush
2070+ **/
2071+ protected function loadView($controllerViewName) {
2072+
2073+ $view = Lvc_Config::getControllerView($controllerViewName, $this->viewVars);
2074+ if (is_null($view)) {
2075+ throw new Lvc_Exception('Unable to load controller view "' . $controllerViewName . '" for controller "' . $this->controllerName . '"');
2076+ } else {
2077+ $view->setController($this);
2078+ $viewContents = $view->getOutput();
2079+ }
2080+
2081+ if ($this->useLayoutOverride) {
2082+ $this->layout = $this->layoutOverride;
2083+ }
2084+ if ( ! empty($this->layout)) {
2085+ // Use an explicit name for this data so we don't override some other variable...
2086+ $this->layoutVars[Lvc_Config::getLayoutContentVarName()] = $viewContents;
2087+ $layoutView = Lvc_Config::getLayoutView($this->layout, $this->layoutVars);
2088+ if (is_null($layoutView)) {
2089+ throw new Lvc_Exception('Unable to load layout view "' . $this->layout . '" for controller "' . $this->controllerName . '"');
2090+ } else {
2091+ $layoutView->setController($this);
2092+ $layoutView->output();
2093+ }
2094+ } else {
2095+ echo($viewContents);
2096+ }
2097+ $this->hasLoadedView = true;
2098+ }
2099+
2100+ /**
2101+ * Redirect to the specified url. NOTE that this function does not stop
2102+ * execution.
2103+ *
2104+ * @param string $url URL to redirect to.
2105+ * @return void
2106+ * @author Anthony Bush
2107+ **/
2108+ protected function redirect($url) {
2109+ header('Location: ' . $url);
2110+ $this->afterAction();
2111+ exit();
2112+ }
2113+
2114+ /**
2115+ * Execute code before every action.
2116+ * Override this in sub classes
2117+ *
2118+ * @return void
2119+ * @author Anthony Bush
2120+ **/
2121+ protected function beforeAction() {
2122+
2123+ }
2124+
2125+ /**
2126+ * Execute code after every action.
2127+ * Override this in sub classes
2128+ *
2129+ * @return void
2130+ * @author Anthony Bush
2131+ **/
2132+ protected function afterAction() {
2133+
2134+ }
2135+
2136+ /**
2137+ * Use this inside a controller action to get the output from another
2138+ * controller's action. By default, the layout functionality will be
2139+ * disabled for this "sub" action.
2140+ *
2141+ * Example Usage:
2142+ *
2143+ * $enrollmentVerifyBox = $this->requestAction('enrollment_verify', array(), 'eligibility');
2144+ *
2145+ * @param string $actionName name of action to invoke.
2146+ * @param array $actionParams parameters to invoke the action with.
2147+ * @param string $controllerName optional controller name. Current controller will be used if not specified.
2148+ * @param array $controllerParams optional controller params. Current controller params will be passed on if not specified.
2149+ * @param string $layout optional layout to force for the sub action.
2150+ * @return string output from requested controller's action.
2151+ * @throws Lvc_Exception
2152+ * @author Anthony Bush
2153+ **/
2154+ protected function requestAction($actionName, $actionParams = array(), $controllerName = null, $controllerParams = null, $layout = null) {
2155+ if (empty($controllerName)) {
2156+ $controllerName = $this->controllerName;
2157+ }
2158+ if (is_null($controllerParams)) {
2159+ $controllerParams = $this->params;
2160+ }
2161+ $controller = Lvc_Config::getController($controllerName);
2162+ if (is_null($controller)) {
2163+ throw new Lvc_Exception('Unable to load controller "' . $controllerName . '"');
2164+ }
2165+ $controller->setControllerParams($controllerParams);
2166+ $controller->setLayoutOverride($layout);
2167+ return $controller->getActionOutput($actionName, $actionParams);
2168+ }
2169+
2170+ /**
2171+ * Get the controller name. Mostly used internally...
2172+ *
2173+ * @return string controller name
2174+ * @author Anthony Bush
2175+ **/
2176+ public function getControllerName() {
2177+ return $this->controllerName;
2178+ }
2179+
2180+ /**
2181+ * Get the controller params. Mostly used internally...
2182+ *
2183+ * @return array controller params
2184+ * @author Anthony Bush
2185+ **/
2186+ public function getControllerParams() {
2187+ return $this->params;
2188+ }
2189+}
2190+
2191+/**
2192+ * A View can be outputted or have its output returned (i.e. it's renderable).
2193+ * It can not be executed.
2194+ *
2195+ * $inc = new Lvc_View('foo.php', array());
2196+ * $inc->output();
2197+ * $output = $inc->getOutput();
2198+ *
2199+ * @package lightvc
2200+ * @author Anthony Bush
2201+ * @since 2007-04-20
2202+ **/
2203+class Lvc_View {
2204+ /**
2205+ * Full path to file name to be included.
2206+ *
2207+ * @var string
2208+ **/
2209+ protected $fileName;
2210+
2211+ /**
2212+ * Data to be exposed to the view template file.
2213+ *
2214+ * @var array
2215+ **/
2216+ protected $data;
2217+
2218+ /**
2219+ * A reference to the parent controller
2220+ *
2221+ * @var Lvc_Controller
2222+ **/
2223+ protected $controller;
2224+
2225+ /**
2226+ * Construct a view to be rendered.
2227+ *
2228+ * @param string $fileName Full path to file name of the view template file.
2229+ * @param array $data an array of [varName] => [value] pairs. Each varName will be made available to the view.
2230+ * @return void
2231+ * @author Anthony Bush
2232+ **/
2233+ public function __construct($fileName, &$data) {
2234+ $this->fileName = $fileName;
2235+ $this->data = $data;
2236+ }
2237+
2238+ /**
2239+ * Output the view (aka render).
2240+ *
2241+ * @return void
2242+ * @author Anthony Bush
2243+ **/
2244+ public function output() {
2245+ extract($this->data, EXTR_SKIP);
2246+ include($this->fileName);
2247+ }
2248+
2249+ /**
2250+ * Return the output of the view.
2251+ *
2252+ * @return string output of view
2253+ * @author Anthony Bush
2254+ **/
2255+ public function getOutput() {
2256+ ob_start();
2257+ $this->output();
2258+ return ob_get_clean();
2259+ }
2260+
2261+ /**
2262+ * Render a sub element from within a view.
2263+ *
2264+ * Views are not allowed to have business logic, but they can call upon
2265+ * other generic, shared, views, called elements here.
2266+ *
2267+ * @param string $elementName name of element to render
2268+ * @param array $data optional data to pass to the element.
2269+ * @return void
2270+ * @throws Lvc_Exception
2271+ * @author Anthony Bush
2272+ **/
2273+ protected function renderElement($elementName, $data = array()) {
2274+ $view = Lvc_Config::getElementView($elementName, $data);
2275+ if (!is_null($view)) {
2276+ $view->setController($this->controller);
2277+ $view->output();
2278+ } else {
2279+ error_log('Unable to render element "' . $elementName . '"');
2280+ // throw new Lvc_Exception('Unable to render element "' . $elementName . '"');
2281+ }
2282+ }
2283+
2284+ /**
2285+ * Set the controller when constructing a view if you want {@link setLayoutVar()}
2286+ * to be callable from a view.
2287+ *
2288+ * @return void
2289+ * @author Anthony Bush
2290+ * @since 2007-05-17
2291+ **/
2292+ public function setController($controller) {
2293+ $this->controller = $controller;
2294+ }
2295+
2296+ /**
2297+ * Set a variable for the layout file. You can set the page title from a static
2298+ * page's view file this way.
2299+ *
2300+ * @param $varName variable name to make available in the view
2301+ * @param $value value of the variable.
2302+ * @return void
2303+ * @author Anthony Bush
2304+ * @since 2007-05-17
2305+ **/
2306+ public function setLayoutVar($varName, $value) {
2307+ $this->controller->setLayoutVar($varName, $value);
2308+ }
2309+}
2310+
2311+?>
2312
2313=== added directory 'views'
2314=== added directory 'views/elements'
2315=== added directory 'views/error'
2316=== added file 'views/error/404.php'
2317--- views/error/404.php 1970-01-01 00:00:00 +0000
2318+++ views/error/404.php 2010-09-26 21:45:54 +0000
2319@@ -0,0 +1,1 @@
2320+<h1>Page Not Found</h1>
2321
2322=== added directory 'views/layouts'
2323=== added file 'views/layouts/default.php'
2324--- views/layouts/default.php 1970-01-01 00:00:00 +0000
2325+++ views/layouts/default.php 2010-09-26 21:45:54 +0000
2326@@ -0,0 +1,44 @@
2327+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2328+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2329+
2330+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
2331+<head>
2332+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
2333+ <title><?php echo $pageTitle ?></title>
2334+ <?php
2335+
2336+ if (isset($requiredCss)) {
2337+ foreach ($requiredCss as $css => $use) {
2338+ echo '<link rel="stylesheet" href="' . WWW_CSS_PATH . $css . '" type="text/css" media="all" charset="utf-8" />' . "\n";
2339+ }
2340+ }
2341+
2342+ if (isset($requiredJsInHead)) {
2343+ foreach ($requiredJsInHead as $js => $use) {
2344+ echo '<script type="text/javascript" charset="utf-8" src="' . WWW_JS_PATH . $js . '"></script>' . "\n";
2345+ }
2346+ }
2347+
2348+ ?>
2349+
2350+</head>
2351+<body>
2352+
2353+ <div id="header">
2354+ Congratulations! LightVC is working :)
2355+ </div>
2356+
2357+ <div id="content">
2358+ <?php echo $layoutContent ?>
2359+ </div>
2360+
2361+ <?php
2362+ if (isset($requiredJs)) {
2363+ foreach ($requiredJs as $js => $use) {
2364+ echo '<script type="text/javascript" charset="utf-8" src="' . WWW_JS_PATH . $js . '"></script>' . "\n";
2365+ }
2366+ }
2367+ ?>
2368+
2369+</body>
2370+</html>
2371
2372=== added directory 'views/page'
2373=== added file 'views/page/home.php'
2374--- views/page/home.php 1970-01-01 00:00:00 +0000
2375+++ views/page/home.php 2010-09-26 21:45:54 +0000
2376@@ -0,0 +1,36 @@
2377+<?php
2378+$this->setLayoutVar('pageTitle', 'LightVC Skeleton App');
2379+?>
2380+
2381+<h1>Skeleton App</h1>
2382+
2383+<p>You have a skeleton app setup with reasonable defaults. &nbsp;You can customize these defaults (such as where things are located) in the <span class="path">config/application.php</span> file.</p>
2384+
2385+<p>This skeleton app uses mod_rewrite (rules specified in the <span class="path">webroot/.htaccess</span> file) and sets up the following routes (specified in <span class="path">config/routes.php</span>) out of the box:</p>
2386+
2387+<ul>
2388+ <li>"/" actives the page controller's view action with "home" for the page_name parameter.</li>
2389+ <li>"/page/page_name" actives the page controller's view action with "page_name" for the page_name parameter.</li>
2390+ <li>"/controller/action/params" actives the "controller" controller's "action" action with the remaining URL used to populate the action method's arguments.</li>
2391+</ul>
2392+
2393+<p>If you need to, consult LightVC documentation on <a href="http://lightvc.org/docs/user_guide/configuration/web_server/">configuring your web server</a>, such as how to setup lighttpd rewrite rules.</p>
2394+
2395+<h2>Your action items:</h2>
2396+
2397+<ul>
2398+ <li>Customize and add layouts to <span class="path">views/layouts/</span>.</li>
2399+ <li>Customize and add styles to <span class="path">webroot/css/</span>.</li>
2400+ <li>Customize and add static pages in <span class="path">views/page/</span>.</li>
2401+ <li>
2402+ Create new controllers in <span class="path">controllers/</span>.
2403+ <ul class="note">
2404+ <li>There is already an AppController (<span class="path">classes/AppController.class.php</span>) which is specifying the default layout and CSS to use across all controllers.</li>
2405+ </ul>
2406+ </li>
2407+ <li>Add to your application level config in <span class="path">config/application.php</span>.</li>
2408+ <li>Add to your route config in <span class="path">config/routes.php</span>.</li>
2409+ <li>Add your own model/ORM (e.g. <a href="http://coughphp.com">CoughPHP</a>, <a href="http://propel.phpdb.org/trac/">Propel</a>, <a href="http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software#PHP">etc.</a>).</li>
2410+</ul>
2411+
2412+<p>Have Fun!<br /><a href="http://lightvc.org/">LightVC Website</a></p>
2413
2414=== added directory 'webroot'
2415=== added file 'webroot/.htaccess'
2416--- webroot/.htaccess 1970-01-01 00:00:00 +0000
2417+++ webroot/.htaccess 2010-09-26 21:45:54 +0000
2418@@ -0,0 +1,6 @@
2419+<IfModule mod_rewrite.c>
2420+ RewriteEngine On
2421+ RewriteCond %{REQUEST_FILENAME} !-d
2422+ RewriteCond %{REQUEST_FILENAME} !-f
2423+ RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
2424+</IfModule>
2425\ No newline at end of file
2426
2427=== added directory 'webroot/css'
2428=== added file 'webroot/css/master.css'
2429--- webroot/css/master.css 1970-01-01 00:00:00 +0000
2430+++ webroot/css/master.css 2010-09-26 21:45:54 +0000
2431@@ -0,0 +1,69 @@
2432+/* reset */
2433+body{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup,sub{line-height:-1px;vertical-align:text-top;}sub{vertical-align:text-bottom;}input, textarea, select{font-family:inherit;font-size:inherit;font-weight:inherit;}
2434+
2435+body
2436+{
2437+ padding: 0 1em;
2438+ font-family: sans-serif;
2439+ background: #fff;
2440+ width: 700px;
2441+ margin: 0 auto;
2442+}
2443+h1
2444+{
2445+ font-weight: bold;
2446+ font-size: 120%;
2447+ margin-bottom: 1em;
2448+}
2449+h2
2450+{
2451+ font-weight: bold;
2452+ font-size: 110%;
2453+ margin: 1em 0;
2454+}
2455+p
2456+{
2457+ margin: 1em 0;
2458+}
2459+ul,
2460+ol
2461+{
2462+ margin-left: 1em;
2463+ padding-left: 2em;
2464+}
2465+pre
2466+{
2467+ margin: 1em 0;
2468+ padding: .5em;
2469+ border: 1px solid #D5D4B9;
2470+ background: #F1F0DD;
2471+}
2472+a:visited
2473+{
2474+ color: #800000;
2475+}
2476+.path
2477+{
2478+ font-weight: bold;
2479+}
2480+.note
2481+{
2482+ color: #999;
2483+ font-size: 90%;
2484+}
2485+#header
2486+{
2487+ background: #008040;
2488+ color: #fff;
2489+ letter-spacing: 2px;
2490+ margin: 1em auto;
2491+ padding: 1em;
2492+ text-align: center;
2493+}
2494+#content
2495+{
2496+ margin: 1em auto;
2497+ padding: 1em;
2498+ border: 5px solid #D5D4B9;
2499+ background: #fff;
2500+}
2501
2502=== added directory 'webroot/images'
2503=== added file 'webroot/index.php'
2504--- webroot/index.php 1970-01-01 00:00:00 +0000
2505+++ webroot/index.php 2010-09-26 21:45:54 +0000
2506@@ -0,0 +1,42 @@
2507+<?php
2508+
2509+if (isset($_GET['url']) && $_GET['url'] === 'favicon.ico') {
2510+
2511+ // Avoid "not found" errors for favicon, which is automatically requested by most browsers.
2512+
2513+} else {
2514+
2515+ // Load core application config
2516+ include_once('../config/application.php');
2517+
2518+ try {
2519+
2520+ // Process the HTTP request using only the routers we need for this application.
2521+ $fc = new Lvc_FrontController();
2522+ $fc->addRouter(new Lvc_RegexRewriteRouter($regexRoutes));
2523+ $fc->processRequest(new Lvc_HttpRequest());
2524+
2525+ } catch (Lvc_Exception $e) {
2526+
2527+ // Log the error message
2528+ error_log($e->getMessage());
2529+
2530+ // Get a request for the 404 error page.
2531+ $request = new Lvc_Request();
2532+ $request->setControllerName('error');
2533+ $request->setActionName('view');
2534+ $request->setActionParams(array('error' => '404'));
2535+
2536+ // Get a new front controller without any routers, and have it process our handmade request.
2537+ $fc = new Lvc_FrontController();
2538+ $fc->processRequest($request);
2539+
2540+ } catch (Exception $e) {
2541+
2542+ // Some other error, output "technical difficulties" message to user?
2543+ error_log($e->getMessage());
2544+
2545+ }
2546+}
2547+
2548+?>
2549\ No newline at end of file
2550
2551=== added directory 'webroot/js'

Subscribers

People subscribed via source and target branches

to all changes: