summaryrefslogtreecommitdiff
path: root/src/lib/View.class.php
blob: 33a9c4ea22e67107ccfb0224cb9c6540726a2507 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?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;
		$pref = array('html');
		foreach ($pref as $ext) {
			if (in_array($ext, $extensions)) return $ext;
		}
		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();
		$regex = '@'.preg_quote(VIEWPATH,'@').'[^.]*\.(.*)\.php$@';
		foreach ($files as $file) {
			$ext = preg_replace($regex, '$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);
	}
}