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, host |
---|
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 | static function create_from_type($type, $baseconf=null) { |
---|
51 | global $lib, $webroot, $host; |
---|
52 | $conf = $host->get_ressources($type, $webroot, isset($baseconf['debug']) && $baseconf['debug']); |
---|
53 | if($conf === null) return null; |
---|
54 | |
---|
55 | return new $conf['class']($conf); |
---|
56 | } |
---|
57 | |
---|
58 | function get_page_specific_urls($seiten_id) { |
---|
59 | global $webroot; |
---|
60 | $file = sprintf("%s/%s.%s", $this->conf['page_dir'], $seiten_id, $this->conf['type']); |
---|
61 | // TODO: This is hacky. Same in get_urls. |
---|
62 | $file_rel2webroot = str_replace($webroot, '', $file); |
---|
63 | return file_exists($file) ? array($file_rel2webroot) : array(); |
---|
64 | } |
---|
65 | |
---|
66 | /** |
---|
67 | * Return a list of URLs appropriate for being included in a website. In general this |
---|
68 | * should be a list with one element, like array("/lib/loader.php?type=js"), which can |
---|
69 | * be directly expanded to a <script src="$1"></script> tag. Same applies for CSS. |
---|
70 | * In debug mode, the list will contain all base files. |
---|
71 | * |
---|
72 | * The URLs are relative to the t29 web document root, that is, no host specific web prefix |
---|
73 | * handling here. |
---|
74 | * |
---|
75 | * There is especially an issue with web prefixes and debug mode: Since clean untouched CSS/JS |
---|
76 | * files are passed there, there cannot be any rewriting in progress. |
---|
77 | * |
---|
78 | * @returns array |
---|
79 | **/ |
---|
80 | function get_urls($debug=null) { |
---|
81 | global $webroot; |
---|
82 | if(($debug !== null && $debug) || !$this->conf['debug']) { |
---|
83 | return array(self::default_include_url . '?type=' . $this->conf['type']); |
---|
84 | } else { |
---|
85 | $module_dir_rel2webroot = str_replace($webroot, '', $this->conf['module_dir']); |
---|
86 | return array_map(function($i)use($module_dir_rel2webroot){ return $module_dir_rel2webroot.$i; }, $this->conf['filenames']); |
---|
87 | } |
---|
88 | } |
---|
89 | |
---|
90 | /** |
---|
91 | * Print out debug messages, only if debug switch is given. |
---|
92 | **/ |
---|
93 | protected function print_debug($string) { |
---|
94 | if($this->conf['debug']) |
---|
95 | echo $string; |
---|
96 | } |
---|
97 | |
---|
98 | /** |
---|
99 | * Module hooking: By overwriting this method and looking at $mod_filename, |
---|
100 | * you can inject any output before that given file. |
---|
101 | * |
---|
102 | * Example: |
---|
103 | * class YourRessourceLoader extends t29RessourceLoader {[ |
---|
104 | * function print_before_file($file, $i) { |
---|
105 | * parent::print_before_file($file, $i); |
---|
106 | * print "Make a boo boo loading the ${i}. file named ${file}!"; |
---|
107 | * } |
---|
108 | * } |
---|
109 | * This will prepend that string before the output of the file. |
---|
110 | * |
---|
111 | * Always call the parent function when overwriting so that output is printed, |
---|
112 | * too! (See example) |
---|
113 | * |
---|
114 | * @param $mod_filename Filename of module, like "foo.js". |
---|
115 | * @param $dir_index Iteration index while traversing the directory (see run()). Not so important. |
---|
116 | * @returns String that |
---|
117 | **/ |
---|
118 | function print_before_file($mod_filename, $dir_index) { |
---|
119 | $this->print_debug("\n\n/*** t29v6-RessourceLoader[$dir_index]: Start of $mod_filename ***/\n\n"); |
---|
120 | } |
---|
121 | |
---|
122 | /** |
---|
123 | * Same as print_before_file but will append your content to the file. |
---|
124 | * Obey calling parent::print_after_file at first so that corrections in |
---|
125 | * the super class can be done! |
---|
126 | * |
---|
127 | * The implementation in t29RessourceLoader prints some newlines to make sure |
---|
128 | * JavaScript oneliner comments at the end of a file won't comment out another |
---|
129 | * file's first line. |
---|
130 | * |
---|
131 | **/ |
---|
132 | function print_after_file($mod_filename, $dir_index) { |
---|
133 | echo "\n\n"; // JS: for being sure no former "//" comment in last line wipes out code |
---|
134 | $this->print_debug("\n\n/*** t29v6-RessourceLoader[$dir_index]: End of $mod_filename ***/\n\n"); |
---|
135 | } |
---|
136 | |
---|
137 | /** |
---|
138 | * A generic print_header function which will be called at first. Give out some |
---|
139 | * stuff you want to prepend to your overall output. This method provides you a |
---|
140 | * generic JS/CSS compilant message where you can give your own $title string |
---|
141 | * or use no title (it will use your class name instead). If called with $title != null, |
---|
142 | * the C++ style multi line comment won't be closed so you can append your own |
---|
143 | * stuff. |
---|
144 | **/ |
---|
145 | function print_header($title=null) { |
---|
146 | if(!$title) $title = __CLASS__; |
---|
147 | ?> |
---|
148 | /*! |
---|
149 | * t29v6 <?=$title; ?> - http://technikum29.de/ |
---|
150 | * $Id: ressourceloader.php 516 2014-02-19 11:39:35Z sven $ |
---|
151 | * |
---|
152 | * Copyright 2012, Sven Koeppel <sven@te...29.de> |
---|
153 | * Licensed under any of Apache, MIT, GPL, LGPL |
---|
154 | * |
---|
155 | * Packed: <?php echo implode(' ', $this->conf['filenames']); ?> |
---|
156 | * Arguments: ?debug=true - skip cache and just cat everything |
---|
157 | * ?purge_cache=true - force rebuild of compressed cache file |
---|
158 | * Gen Date: <?php echo date('r'), PHP_EOL; |
---|
159 | if($title == __CLASS__) print " **/\n"; |
---|
160 | } |
---|
161 | |
---|
162 | /** |
---|
163 | * The main run() function will print out the header and concatenate all |
---|
164 | * modules contents. Expects OutputBuffering running! |
---|
165 | **/ |
---|
166 | function run() { |
---|
167 | $this->print_header(); |
---|
168 | $this->conf['header'] = ob_get_contents(); // for prepending it to minified code |
---|
169 | |
---|
170 | foreach($this->conf['modules'] as $i => $mod) { |
---|
171 | $modfile = $this->conf['filenames'][$i]; |
---|
172 | $this->print_before_file($modfile, $i); |
---|
173 | readfile($mod); |
---|
174 | $this->print_after_file($modfile, $i); |
---|
175 | } |
---|
176 | } // run |
---|
177 | |
---|
178 | /** |
---|
179 | * Overwrite compression_filter for filtering the whole output made by this |
---|
180 | * class. It is used as a shutdown filter in t29Cache, see usage in loader.php. |
---|
181 | * @param $output The output string fetched by OutputBuffering |
---|
182 | * @returns The filtered String. The default implementation just returns $output. |
---|
183 | **/ |
---|
184 | function compression_filter($output) { |
---|
185 | return $output; |
---|
186 | } |
---|
187 | } // class t29RessourceLoader |
---|
188 | |
---|
189 | |
---|
190 | class t29JavaScriptRessourceLoader extends t29RessourceLoader { |
---|
191 | function print_after_file($mod_filename, $dir_index) { |
---|
192 | global $lib; |
---|
193 | parent::print_after_file($mod_filename, $dir_index); |
---|
194 | if($mod_filename == "msg.js") { |
---|
195 | // append system messages to the special msg.js file |
---|
196 | // to inject PHP code to JS userspace. |
---|
197 | $this->print_debug("\n/*** Auto appended ***/\n"); |
---|
198 | require "$lib/messages.php"; |
---|
199 | echo "t29.msg.data="; |
---|
200 | echo t29Messages::create_json('/^js-/'); |
---|
201 | echo ";\n"; |
---|
202 | } |
---|
203 | } |
---|
204 | |
---|
205 | function get_page_specific_urls($seiten_id) { |
---|
206 | $urls = parent::get_page_specific_urls($seiten_id); |
---|
207 | switch($seiten_id) { |
---|
208 | case 'impressum': |
---|
209 | $urls[] = 'http://maps.google.com/maps?file=api&v=2&sensor=false&key=ABQIAAAAraTKZ5cINardZ8ITNVssKhRcOoEBtCgYLJRQznXYEV8m1M3fRRRT9wMSvFwhyo62fD3KyiwQxe5ruw'; |
---|
210 | break; |
---|
211 | } |
---|
212 | return $urls; |
---|
213 | } |
---|
214 | |
---|
215 | function print_header($title=null) { |
---|
216 | parent::print_header('JavaScript Code'); |
---|
217 | echo " * Depends heavily on jQuery\n **/\n"; |
---|
218 | } |
---|
219 | |
---|
220 | function compression_filter($code) { |
---|
221 | global $lib; |
---|
222 | // reduces code size about 1/2 - before: 23kB, after: 12kB |
---|
223 | require "$lib/JavaScriptMinifier.php"; |
---|
224 | $minified = JavaScriptMinifier::minify($code); |
---|
225 | return $this->conf['header'] . $minified; |
---|
226 | } |
---|
227 | } // class t29JavaScriptRessourceLoader |
---|
228 | |
---|
229 | class t29StyleSheetRessourceLoader extends t29RessourceLoader { |
---|
230 | function print_header($title=null) { |
---|
231 | parent::print_header('StyleSheet'); |
---|
232 | echo " **/\n"; |
---|
233 | } |
---|
234 | |
---|
235 | function compression_filter($code) { |
---|
236 | global $lib, $host; |
---|
237 | if($host->has_web_prefix) |
---|
238 | // rewrite CSS image includes |
---|
239 | $code = preg_replace('#(url\(["\']?)/#i', '\\1'.$host->web_prefix.'/', $code); |
---|
240 | |
---|
241 | |
---|
242 | require "$lib/CSSMin.php"; |
---|
243 | # compression: 40kb to 16kb |
---|
244 | $minified = CSSMin::minify($code); |
---|
245 | return $this->conf['header'] . $minified; |
---|
246 | |
---|
247 | } |
---|
248 | } // t29StyleSheetRessourceLoader |
---|