summaryrefslogtreecommitdiff
path: root/src/lib/View.class.php
blob: f0afa39fc3cc095f9a605063c7dda460774760bb (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
<?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();
		$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);
	}
}