1 | <?php |
---|
2 | /** |
---|
3 | * t29RessourceLoader classes. |
---|
4 | * |
---|
5 | * The t29 ressource loading system features full caching, directory file input, |
---|
6 | * OOP style file type specific functions, pre/post per file injection hooks |
---|
7 | * (AOP style) and post output content filtering where compression tools for |
---|
8 | * JavaScript and CSS are used. |
---|
9 | * |
---|
10 | * The architecture and compression technique is highly inspired by the |
---|
11 | * RessourceLoader framework of MediaWiki 1.20. |
---|
12 | * |
---|
13 | * These classes make usage of class inheritance, heavy PHP output buffering, the |
---|
14 | * t29v6 caching subsystem and the general t29v6 variable convencience. |
---|
15 | * |
---|
16 | * This file defines classes t29{,JavaScript,StyleSheet}RessourceLoader. |
---|
17 | * Libs JavaScriptMinifier.php and CSSMin.php are included on per-method |
---|
18 | * level for minification. |
---|
19 | * |
---|
20 | * 2012 Sven Koeppel |
---|
21 | * |
---|
22 | **/ |
---|
23 | |
---|
24 | /* |
---|
25 | // test it: |
---|
26 | $lib = dirname(__FILE__); |
---|
27 | $webroot = realpath("$lib/../"); |
---|
28 | $js = t29RessourceLoader::create_from_type('css'); |
---|
29 | $js->run(); |
---|
30 | */ |
---|
31 | |
---|
32 | class t29RessourceLoader { |
---|
33 | /** |
---|
34 | * expects: type, cache_file, module_dir, page_dir, glob_pattern, content_types, class, modules, debug |
---|
35 | **/ |
---|
36 | public $conf; |
---|
37 | |
---|
38 | const default_include_url = '/lib/loader.php'; // rel to webroot |
---|
39 | |
---|
40 | /** |
---|
41 | * Construct with configuration array. See loader.php for contents of |
---|
42 | * that array. See above for minimum elements which must be present. |
---|
43 | * @param $conf Configuration array |
---|
44 | **/ |
---|
45 | function __construct($conf) { |
---|
46 | $this->conf = $conf; |
---|
47 | $this->conf['filenames'] = array_map('basename', $this->conf['modules']); // filenames like foo.js |
---|
48 | } |
---|
49 | |
---|
50 | private static $conf_for_type; |
---|
51 | static function create_from_type($type, $baseconf=null) { |
---|
52 | global $lib, $webroot; |
---|
53 | if(!self::$conf_for_type) { |
---|
54 | define('T29_GRAB_LOADER_DEFS', true); |
---|
55 | include "$lib/loader.php"; |
---|
56 | self::$conf_for_type = $conf_for_type; |
---|
57 | } |
---|
58 | |
---|
59 | $conf = call_user_func(self::$conf_for_type, $type, isset($baseconf['debug']) && $baseconf['debug']); |
---|
60 | if($conf === null) return null; |
---|
61 | |
---|
62 | return new $conf['class']($conf); |
---|
63 | } |
---|
64 | |
---|
65 | function get_page_specific_urls($seiten_id) { |
---|
66 | global $webroot; |
---|
67 | $file = sprintf("%s/%s.%s", $this->conf['page_dir'], $seiten_id, $this->conf['type']); |
---|
68 | // TODO: This is hacky. Same in get_urls. |
---|
69 | $file_rel2webroot = str_replace($webroot, '', $file); |
---|
70 | return file_exists($file) ? array($file_rel2webroot) : array(); |
---|
71 | } |
---|
72 | |
---|
73 | function get_urls($debug=null) { |
---|
74 | global $webroot; |
---|
75 | if(($debug !== null && $debug) || !$this->conf['debug']) { |
---|
76 | return array(self::default_include_url . '?type=' . $this->conf['type']); |
---|
77 | } else { |
---|
78 | $module_dir_rel2webroot = str_replace($webroot, '', $this->conf['module_dir']); |
---|
79 | return array_map(function($i)use($module_dir_rel2webroot){ return $module_dir_rel2webroot.$i; }, $this->conf['filenames']); |
---|
80 | } |
---|
81 | } |
---|
82 | |
---|
83 | /** |
---|
84 | * Print out debug messages, only if debug switch is given. |
---|
85 | **/ |
---|
86 | protected function print_debug($string) { |
---|
87 | if($this->conf['debug']) |
---|
88 | echo $string; |
---|
89 | } |
---|
90 | |
---|
91 | /** |
---|
92 | * Module hooking: By overwriting this method and looking at $mod_filename, |
---|
93 | * you can inject any output before that given file. |
---|
94 | * |
---|
95 | * Example: |
---|
96 | * class YourRessourceLoader extends t29RessourceLoader {[ |
---|
97 | * function print_before_file($file, $i) { |
---|
98 | * parent::print_before_file($file, $i); |
---|
99 | * print "Make a boo boo loading the ${i}. file named ${file}!"; |
---|
100 | * } |
---|
101 | * } |
---|
102 | * This will prepend that string before the output of the file. |
---|
103 | * |
---|
104 | * Always call the parent function when overwriting so that output is printed, |
---|
105 | * too! (See example) |
---|
106 | * |
---|
107 | * @param $mod_filename Filename of module, like "foo.js". |
---|
108 | * @param $dir_index Iteration index while traversing the directory (see run()). Not so important. |
---|
109 | * @returns String that |
---|
110 | **/ |
---|
111 | function print_before_file($mod_filename, $dir_index) { |
---|
112 | $this->print_debug("\n\n/*** t29v6-RessourceLoader[$dir_index]: Start of $mod_filename ***/\n\n"); |
---|
113 | } |
---|
114 | |
---|
115 | /** |
---|
116 | * Same as print_before_file but will append your content to the file. |
---|
117 | * Obey calling parent::print_after_file at first so that corrections in |
---|
118 | * the super class can be done! |
---|
119 | * |
---|
120 | * The implementation in t29RessourceLoader prints some newlines to make sure |
---|
121 | * JavaScript oneliner comments at the end of a file won't comment out another |
---|
122 | * file's first line. |
---|
123 | * |
---|
124 | **/ |
---|
125 | function print_after_file($mod_filename, $dir_index) { |
---|
126 | echo "\n\n"; // JS: for being sure no former "//" comment in last line wipes out code |
---|
127 | $this->print_debug("\n\n/*** t29v6-RessourceLoader[$dir_index]: End of $mod_filename ***/\n\n"); |
---|
128 | } |
---|
129 | |
---|
130 | /** |
---|
131 | * A generic print_header function which will be called at first. Give out some |
---|
132 | * stuff you want to prepend to your overall output. This method provides you a |
---|
133 | * generic JS/CSS compilant message where you can give your own $title string |
---|
134 | * or use no title (it will use your class name instead). If called with $title != null, |
---|
135 | * the C++ style multi line comment won't be closed so you can append your own |
---|
136 | * stuff. |
---|
137 | **/ |
---|
138 | function print_header($title=null) { |
---|
139 | if(!$title) $title = __CLASS__; |
---|
140 | ?> |
---|
141 | /*! |
---|
142 | * t29v6 <?=$title; ?> - http://technikum29.de/ |
---|
143 | * $Id: ressourceloader.php 301 2012-09-19 22:18:45Z sven $ |
---|
144 | * |
---|
145 | * Copyright 2012, Sven Koeppel <sven@te...29.de> |
---|
146 | * Licensed under any of Apache, MIT, GPL, LGPL |
---|
147 | * |
---|
148 | * Packed: <?php echo implode(' ', $this->conf['filenames']); ?> |
---|
149 | * Arguments: ?debug=true - skip cache and just cat everything |
---|
150 | * ?purge_cache=true - force rebuild of compressed cache file |
---|
151 | * Gen Date: <?php echo date('r'), PHP_EOL; |
---|
152 | if($title == __CLASS__) print " **/\n"; |
---|
153 | } |
---|
154 | |
---|
155 | /** |
---|
156 | * The main run() function will print out the header and concatenate all |
---|
157 | * modules contents. Expects OutputBuffering running! |
---|
158 | **/ |
---|
159 | function run() { |
---|
160 | $this->print_header(); |
---|
161 | $this->conf['header'] = ob_get_contents(); // for prepending it to minified code |
---|
162 | |
---|
163 | foreach($this->conf['modules'] as $i => $mod) { |
---|
164 | $modfile = $this->conf['filenames'][$i]; |
---|
165 | $this->print_before_file($modfile, $i); |
---|
166 | readfile($mod); |
---|
167 | $this->print_after_file($modfile, $i); |
---|
168 | } |
---|
169 | } // run |
---|
170 | |
---|
171 | /** |
---|
172 | * Overwrite compression_filter for filtering the whole output made by this |
---|
173 | * class. It is used as a shutdown filter in t29Cache, see usage in loader.php. |
---|
174 | * @param $output The output string fetched by OutputBuffering |
---|
175 | * @returns The filtered String. The default implementation just returns $output. |
---|
176 | **/ |
---|
177 | function compression_filter($output) { |
---|
178 | return $output; |
---|
179 | } |
---|
180 | } // class t29RessourceLoader |
---|
181 | |
---|
182 | |
---|
183 | class t29JavaScriptRessourceLoader extends t29RessourceLoader { |
---|
184 | function print_after_file($mod_filename, $dir_index) { |
---|
185 | global $lib; |
---|
186 | parent::print_after_file($mod_filename, $dir_index); |
---|
187 | if($mod_filename == "msg.js") { |
---|
188 | // append system messages to the special msg.js file |
---|
189 | // to inject PHP code to JS userspace. |
---|
190 | $this->print_debug("\n/*** Auto appended ***/\n"); |
---|
191 | require "$lib/messages.php"; |
---|
192 | echo "t29.msg.data="; |
---|
193 | echo t29Messages::create_json('/^js-/'); |
---|
194 | echo ";\n"; |
---|
195 | } |
---|
196 | } |
---|
197 | |
---|
198 | function get_page_specific_urls($seiten_id) { |
---|
199 | $urls = parent::get_page_specific_urls($seiten_id); |
---|
200 | switch($seiten_id) { |
---|
201 | case 'impressum': |
---|
202 | $urls[] = 'http://maps.google.com/maps?file=api&v=2&sensor=false&key=ABQIAAAAraTKZ5cINardZ8ITNVssKhRcOoEBtCgYLJRQznXYEV8m1M3fRRRT9wMSvFwhyo62fD3KyiwQxe5ruw'; |
---|
203 | break; |
---|
204 | } |
---|
205 | return $urls; |
---|
206 | } |
---|
207 | |
---|
208 | function print_header($title=null) { |
---|
209 | parent::print_header('JavaScript Code'); |
---|
210 | echo " * Depends heavily on jQuery\n **/\n"; |
---|
211 | } |
---|
212 | |
---|
213 | function compression_filter($code) { |
---|
214 | global $lib; |
---|
215 | // reduces code size about 1/2 - before: 23kB, after: 12kB |
---|
216 | require "$lib/JavaScriptMinifier.php"; |
---|
217 | $minified = JavaScriptMinifier::minify($code); |
---|
218 | return $this->conf['header'] . $minified; |
---|
219 | } |
---|
220 | } // class t29JavaScriptRessourceLoader |
---|
221 | |
---|
222 | class t29StyleSheetRessourceLoader extends t29RessourceLoader { |
---|
223 | function print_header($title=null) { |
---|
224 | parent::print_header('StyleSheet'); |
---|
225 | echo " **/\n"; |
---|
226 | } |
---|
227 | |
---|
228 | function compression_filter($code) { |
---|
229 | global $lib; |
---|
230 | require "$lib/CSSMin.php"; |
---|
231 | # compression: 40kb to 16kb |
---|
232 | $minified = CSSMin::minify($code); |
---|
233 | return $this->conf['header'] . $minified; |
---|
234 | |
---|
235 | } |
---|
236 | } // t29StyleSheetRessourceLoader |
---|