summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <LukeShu@sbcglobal.net>2011-09-04 20:40:45 -0400
committerLuke Shumaker <LukeShu@sbcglobal.net>2011-09-04 20:40:45 -0400
commit103332a30f8976fcc224c8f55dc23aba7b99e578 (patch)
tree32337915884fb6217007d569636f418130757df3
parentbca1b20b4fc6dca04368f8c03b5e1faeec5af7d3 (diff)
New router and view selector engine magic coolness.
-rw-r--r--index.php24
-rw-r--r--src/lib/Controller.class.php61
-rw-r--r--src/lib/Mime.class.php10
-rw-r--r--src/lib/Router.class.php4
-rw-r--r--src/lib/View.class.php127
5 files changed, 157 insertions, 69 deletions
diff --git a/index.php b/index.php
index c8f72a6..3a3a646 100644
--- a/index.php
+++ b/index.php
@@ -7,28 +7,34 @@ define('LIBPATH', BASEPATH.'/src/lib'.PATH_SEPARATOR.BASEPATH.'/src/ext')
define('MODELPATH', BASEPATH.'/src/models');
define('VIEWPATH', BASEPATH.'/src/views');// views are not objects
define('CONTROLLERPATH', BASEPATH.'/src/controllers');
+define('PLUGINPATH', BASEPATH.'/src/plugins');
// Modify our include path to catch our class files.
set_include_path(get_include_path()
.PATH_SEPARATOR.LIBPATH
.PATH_SEPARATOR.MODELPATH
.PATH_SEPARATOR.CONTROLLERPATH
+ .PATH_SEPARATOR.PLUGINPATH
);
// Figure what page is trying to be loaded. Don't worry if we're
// looking for a real file, if the requested page exists as a real
// file, .htaccess won't even let us load this file.
@$PAGE_RAW = $_GET['p'];
-preg_match('@(.*)(\.([^./]))?@', $PAGE_RAW, $matches);
-@$PAGE = $matches[1];
-@$EXT = $matches[3];
-@$ACCEPT = $_SERVER['HTTP_ACCEPT'];
-if ($PAGE=='')
- $PAGE = 'index';
-if ($EXT!='')
- $ACCEPT = "$EXT, $ACCEPT";
+$PAGE_PARTS = explode('/', $PAGE_RAW);
+$FILE = array_pop($PAGE_PARTS);
+$regex = '@([^.]*)\\.(.*)@';
+if (preg_match($regex, $FILE, $matches)) {
+ @$FILE = $matches[1];
+ @$EXT = $matches[2];
+ array_push($PAGE_PARTS, $FILE);
+ $PAGE = implode('/', $PAGE_PARTS);
+} else {
+ $PAGE = $PAGE_RAW;
+}
+if ($PAGE=='') $PAGE = 'index';
define('PAGE', $PAGE); unset($PAGE);
-define('ACCEPT', $ACCEPT); unset($ACCEPT);
+define('PAGE_EXT', $EXT); unset($EXT);
// Get ready
require_once('Model.class.php');
diff --git a/src/lib/Controller.class.php b/src/lib/Controller.class.php
index 592ea2c..f9ed59d 100644
--- a/src/lib/Controller.class.php
+++ b/src/lib/Controller.class.php
@@ -1,65 +1,20 @@
<?php
-class Controller {
- /**
- * Find the best view file to include based on file extension and HTTP
- * 'Accept' headers.
- */
- private function _resolveView($view) {
- require_once('Mime.class.php');
- require_once('HTTP_Accept.class.php');
-
- // Make a list of candidate views
- $glob_string = VIEWPATH.'/pages/'.$view.'.*.php';
- $files = glob($glob_string);
-
- // Return false if there were no candidate views.
- if (count($files) < 1) return false;
+require_once('View.class.php');
- // $prefs is a associative array where the key is the file
- // extension, and the value is how much we like that extension.
- // Higher numbers are better.
- $prefs = array();
-
- // $accept will tell us how much we like a given mime type,
- // based on the ACCEPT constant.
- $accept = new HTTP_Accept(ACCEPT);
-
- // Loop through the candidate views, and record how much we
- // like each.
- foreach ($files as $file) {
- $ext = preg_replace('@[^.]*\.(.*)\.php$@','$1', $file);
- $mimes = Mime::ext2mime($ext);
- foreach ($mimes as $mime) {
- $quality = $accept->getQuality($mime);
- if (isset($final[$ext])) {
- $quality = max($final[$ext], $quality);
- }
- $prefs[$ext] = $quality;
- }
- }
-
- // Sort $prefs such that the entry with the highest value will
- // appear first.
- arsort($prefs);
-
- // Return the first entry in $prefs.
- foreach ($prefs as $ext => $quality) {
- return VIEWPATH."/pages/$view.$ext.php";
- }
- }
-
+class Controller {
/**
* Show a $view, in the most appropriate format (according to file
* extension and HTTP Accept header). Pass the array $vars to the view.
*/
protected function showView($view, $vars=null) {
- global $VARS, $mm;
+ global $mm;
+
if ($vars===null) { $vars = array(); }
- $VARS = $vars;
- $VARS['template'] = $mm->template();
- include($this->_resolveView($view));
- unset($VARS);
+ $vars['template'] = $mm->template();
+
+ $obj = new View($view);
+ $obj->show($vars);
}
// Here be default handlers ////////////////////////////////////////////
diff --git a/src/lib/Mime.class.php b/src/lib/Mime.class.php
index 40562b4..f37c1eb 100644
--- a/src/lib/Mime.class.php
+++ b/src/lib/Mime.class.php
@@ -2,13 +2,14 @@
class Mime {
public static $mimes = array(
- 'csv' => array('text/x-comma-separated-values',
+ 'csv' => array(
+ 'text/csv', 'text/x-csv',
+ 'text/x-comma-separated-values',
'text/comma-separated-values',
- 'application/octet-stream',
- 'application/vnd.ms-excel',
- 'text/x-csv', 'text/csv', 'application/csv',
+ 'application/csv',
'application/excel', 'application/vnd.msexcel'),
'xhtml' => array('text/html', 'application/xhtml+xml'),
+ 'html' => array('text/html', 'application/xhtml+xml'),
'bmp' => 'image/bmp',
'gif' => 'image/gif',
'jpeg' => array('image/jpeg', 'image/pjpeg'),
@@ -18,7 +19,6 @@ class Mime {
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'css' => 'text/css',
- 'html' => 'text/html',
'htm' => 'text/html',
'txt' => 'text/plain',
'json' => array('application/json', 'text/json')
diff --git a/src/lib/Router.class.php b/src/lib/Router.class.php
index 459034d..238e3f8 100644
--- a/src/lib/Router.class.php
+++ b/src/lib/Router.class.php
@@ -27,8 +27,8 @@ class Router {
$dirs = explode(PATH_SEPARATOR, $controllerpath);
foreach ($dirs as $dir) {
// Find all files in $dir with the ext `.class.php'
- $controllerfiles = glob($dir.'/*.class.php');
- foreach ($controllerfiles as $file) {
+ $files = glob($dir.'/*.class.php');
+ foreach ($files as $file) {
// and include them
require_once($file);
}
diff --git a/src/lib/View.class.php b/src/lib/View.class.php
new file mode 100644
index 0000000..ea5ad60
--- /dev/null
+++ b/src/lib/View.class.php
@@ -0,0 +1,127 @@
+<?php
+
+require_once('Mime.class.php');
+require_once('HTTP_Accept.class.php');
+
+/**
+ * A class to handle loading and evaluating the appropriateness of different
+ * views.
+ *
+ * Depends on the state of the following variables/constants:
+ * PAGE_EXT
+ * VIEWPATH
+ * $_SERVER['HTTP_ACCEPT']
+ */
+class View {
+ private $extensions = array();
+ private $ext = '';
+ private $view = '';
+
+ /**
+ * Return the filename of the view file with extension $ext
+ */
+ private static function filename($view, $ext) {
+ return VIEWPATH."/pages/$view.$ext.php";
+ }
+
+ /**
+ * Choose between $extensions, which all have equal quality.
+ */
+ private function chooseBetweenEquals($extensions) {
+ if (count($extensions)<1) return false;
+ return $extensions[0]; // XXX: Worst. Solution. Ever.
+ }
+
+ /**
+ * Find the best available extension to use, based on file extension and
+ * HTTP 'Accept' headers.
+ */
+ private function chooseExtension($view) {
+ // Make a list of candidate extensions for this view.
+ $files = glob(self::filename($view, '*'));
+ $this->extensions = array();
+ foreach ($files as $file) {
+ $ext = preg_replace('@[^.]*\.(.*)\.php$@','$1', $file);
+ $this->extensions[] = $ext;
+ }
+ if (count($this->extensions)<1) return false;
+
+ if (PAGE_EXT != '') {
+ // First, do a check if we can just return requested
+ // file extension:
+ if (in_array(PAGE_EXT, $this->extensions)) {
+ return PAGE_EXT;
+ }
+
+ // Check for other extensions with the same mime type as
+ // the requested:
+ $accept_str = implode(', ', Mime::ext2mime(PAGE_EXT));
+ $extensions = $this->parseAccept($view, $accept_str);
+ if ($ext = $this->chooseBetweenEquals($extensions)) return $ext;
+ }
+
+ // Check for other extensions based on HTTP 'Accept' headers:
+ $accept_str = $_SERVER['HTTP_ACCEPT'];
+ $extensions = $this->parseAccept($view, $accept_str);
+ if ($ext = $this->chooseBetweenEquals($extensions)) return $ext;
+
+ // Well, all the good options failed, so let's see what we've
+ // got left:
+ $extensions = $this->extensions;
+ return $this->chooseBetweenEquals($extensions);
+
+ }
+
+ private function parseAccept($view, $accept_str) {
+ // $prefs is a associative array where the key is the file
+ // extension, and the value is how much we like that extension.
+ // Higher numbers are better.
+ $prefs = array();
+
+ $accept = new HTTP_Accept($accept_str);
+
+ // Loop through the candidate views, and record how much we
+ // like each.
+ foreach ($this->extensions as $ext) {
+ $mimes = Mime::ext2mime($ext);
+ foreach ($mimes as $mime) {
+ $quality = $accept->getQuality($mime);
+ if (isset($prefs[$ext])) {
+ $quality = max($prefs[$ext], $quality);
+ }
+ $prefs[$ext] = $quality;
+ }
+ }
+
+ // Create an array of all extensions tied for the top quality.
+ $ret = array();
+ $top_quality = 0.001;// minimum acceptable according to RFC 2616
+ foreach ($prefs as $ext => $quality) {
+ if ($quality > $top_quality) {
+ $top_quality = $quality;
+ $ret = array();
+ }
+ if ($quality == $top_quality) {
+ $ret[] = $ext;
+ }
+ }
+ return $ret;
+ }
+
+ public function __construct($view) {
+ $this->ext = $this->chooseExtension($view);
+ $this->view = $view;
+ }
+
+ public function show($vars) {
+ $file = self::filename($this->view, $this->ext);
+ $mimes = Mime::ext2mime($this->ext);
+
+ header('Content-type: '.$mimes[0]);
+
+ global $VARS;
+ $VARS = $vars;
+ include($file);
+ unset($VARS);
+ }
+}