1: <?php
2:
3: /**
4: * Module management classes
5: * @package framework
6: * @subpackage modules
7: */
8:
9: /**
10: * Output module execution methods
11: */
12: trait Hm_Output_Module_Exec {
13:
14: public $output_response;
15: public $output_data = array();
16:
17: /**
18: * Look for translation strings based on the current language setting
19: * return array
20: */
21: abstract public function get_current_language();
22:
23: /**
24: * Setup a default language translation
25: * @return void
26: */
27: abstract public function default_language();
28:
29: /**
30: * Run all the handler modules for a page and merge the results
31: * @param Hm_Request $request details about the request
32: * @param bool $active_session true if the session is active
33: * @param string $page current page request
34: * @param array $handler_response data from handler modules
35: * @return void
36: */
37: public function run_output_modules($request, $active_session, $page, $handler_response) {
38: $input = $handler_response;
39: $protected = array();
40: $modules = Hm_Output_Modules::get_for_page($page);
41: $list_output = array();
42: foreach ($modules as $name => $args) {
43: list($output, $protected, $type) = $this->run_output_module($input, $protected, $name,
44: $args, $active_session, $request->format, $this->get_current_language());
45: if ($type != 'JSON') {
46: $list_output[] = $output;
47: }
48: else {
49: $input = $output;
50: }
51: }
52: if (!empty($list_output)) {
53: $this->output_response = $list_output;
54: $this->output_data = $input;
55: }
56: else {
57: $this->output_response = $input;
58: $this->output_data = $input;
59: }
60: }
61:
62: /**
63: * Run a single output modules and return the results
64: * @param array $input handler output
65: * @param array $protected list of protected output
66: * @param string $name handler module name
67: * @param array $args module arguments
68: * @param bool $active_session true if the session is active
69: * @param string $format HTML5 or JSON format
70: * @param array $lang_str translation lookup array
71: * @return array
72: */
73: public function run_output_module($input, $protected, $name, $args, $active_session, $format, $lang_str) {
74: $name = "Hm_Output_$name";
75: if (!class_exists($name)) {
76: Hm_Debug::add(sprintf('Output module %s activated but not found', $name));
77: return $this->output_result($input, $protected, false);
78: }
79: if ($args[1] && !$active_session) {
80: return $this->output_result($input, $protected, false);
81: }
82: $mod = new $name($input, $protected);
83: return $this->process_result($mod, $format, $lang_str, $protected);
84: }
85:
86: /**
87: * @param object $mod output module
88: * @param string $format output format type
89: * @param array $lang_str translation lookup array
90: * @param array protected output
91: * @return array
92: */
93: private function process_result($mod, $format, $lang_str, $protected) {
94: $mod_output = false;
95: if ($format == 'Hm_Format_JSON') {
96: $mod->output_content($format, $lang_str, $protected);
97: $input = $mod->module_output();
98: $protected = $mod->output_protected();
99: }
100: else {
101: $mod_output = $mod->output_content($format, $lang_str, array());
102: $input = $mod->module_output();
103: }
104: return $this->output_result($input, $protected, $mod_output);
105: }
106:
107: /**
108: * @param array $input module input
109: * @param array $protected protected output
110: * @param string|false http output module result
111: * @return array
112: */
113: private function output_result($input, $protected, $mod_output) {
114: if (!$mod_output) {
115: return array($input, $protected, 'JSON');
116: }
117: return array($mod_output, $protected, 'HTML5');
118: }
119:
120: }
121: /**
122: * Handler module execution methods
123: */
124: trait Hm_Handler_Module_Exec {
125:
126: public $request;
127: public $site_config;
128: public $handler_response = array();
129: public $page = '';
130: public $session;
131: public $cache;
132:
133: /**
134: * Setup a default language translation
135: * @return void
136: */
137: abstract public function default_language();
138:
139: /**
140: * Run all the handler modules for a page and merge the results
141: * @param Hm_Request $request details about the request
142: * @param object $session session interface
143: * @param string $page page id
144: * @return void
145: */
146: public function run_handler_modules($request, $session, $page) {
147: $input = $this->handler_response;
148: $protected = array();
149: $this->request = $request;
150: $this->session = $session;
151: $cache_setup = new Hm_Cache_Setup($this->site_config, $session);
152: $this->cache = $cache_setup->setup_cache();
153: $modules = Hm_Handler_Modules::get_for_page($page);
154: foreach ($modules as $name => $args) {
155: list($input, $protected) = $this->run_handler_module($input, $protected, $name, $args, $session);
156: }
157: if ($input) {
158: $this->handler_response = $input;
159: }
160: $this->default_language();
161: $this->merge_response($request, $session, $page);
162: }
163:
164: /**
165: * Run a single handler and return the results
166: * @param array $input handler output so far for this page
167: * @param array $protected list of protected output
168: * @param string $name handler module name
169: * @param array $args module arguments
170: * @param object $session session interface
171: */
172: public function run_handler_module($input, $protected, $name, $args, $session) {
173: $name = "Hm_Handler_$name";
174: if (class_exists($name)) {
175: if (!$args[1] || ($args[1] && $session->is_active())) {
176: $mod = new $name($this, $this->page, $input, $protected);
177: $mod->process($input);
178: $input = $mod->module_output();
179: $protected = $mod->output_protected();
180: }
181: }
182: else {
183: Hm_Debug::add(sprintf('Handler module %s activated but not found', $name));
184: }
185: return array($input, $protected);
186: }
187:
188: /**
189: * Merge the combined response from the handler modules with some default values
190: * @param Hm_Request $request request details
191: * @param object $session session interface
192: * @param string $page page id
193: * @return void
194: */
195: public function merge_response($request, $session, $page) {
196: $this->handler_response = array_merge($this->handler_response, array(
197: 'router_page_name' => $page,
198: 'router_request_type' => $request->type,
199: 'router_sapi_name' => $request->sapi,
200: 'router_format_name' => $request->format,
201: 'router_login_state' => $session->is_active(),
202: 'router_url_path' => $request->path,
203: 'router_module_list' => $this->site_config->get_modules(),
204: 'router_app_name' => $this->site_config->get('app_name', 'HM3'),
205: 'router_js_exclude_deps' => $this->site_config->get('js_exclude_deps'),
206: ));
207: }
208: }
209:
210: /**
211: * Class to setup, load, and execute module sets
212: */
213: class Hm_Module_Exec {
214:
215: use Hm_Output_Module_Exec;
216: use Hm_Handler_Module_Exec;
217:
218: public $user_config;
219: public $filters = array();
220: public $handlers = array();
221: public $outputs = array();
222:
223: /**
224: * @param object $config site config
225: */
226: public function __construct($config) {
227: $this->site_config = $config;
228: $this->user_config = load_user_config_object($config);
229: $this->process_module_setup();
230: }
231:
232: /**
233: * Build a list of module properties
234: * @return void
235: */
236: public function process_module_setup() {
237: if (DEBUG_MODE or $this->site_config->get('debug_log')) {
238: $this->setup_debug_modules();
239: }
240: else {
241: $this->setup_production_modules();
242: }
243: }
244:
245: /**
246: * Look for translation strings based on the current language setting
247: * return array
248: */
249: public function get_current_language() {
250: $lang = $this->handler_response['language'] ?? DEFAULT_SETTING_LANGUAGE;
251: $strings = [];
252: if (file_exists(APP_PATH."language/{$lang}.php")) {
253: $strings = require APP_PATH."language/{$lang}.php";
254: }
255: return $strings;
256: }
257:
258: /**
259: * Setup a default language translation
260: * @return void
261: */
262: public function default_language() {
263: if (!array_key_exists('language', $this->handler_response)) {
264: $default_lang = $this->site_config->get('default_language', DEFAULT_SETTING_LANGUAGE);
265: if ($default_lang) {
266: $this->handler_response['language'] = $default_lang;
267: }
268: }
269: }
270:
271: /**
272: * Get module data when in production mode
273: * @return void
274: */
275: public function setup_production_modules() {
276: $this->filters = $this->site_config->get('input_filters', array());
277: $this->handlers = $this->site_config->get('handler_modules', array());
278: $this->outputs = $this->site_config->get('output_modules', array());
279: }
280:
281: /**
282: * Get module data when in debug mode
283: * @return void
284: */
285: public function setup_debug_modules() {
286: $filters = array('allowed_output' => array(), 'allowed_get' => array(), 'allowed_cookie' => array(),
287: 'allowed_post' => array(), 'allowed_server' => array(), 'allowed_pages' => array());
288: $modules = $this->site_config->get_modules();
289: foreach ($modules as $name) {
290: $path = sprintf(APP_PATH."modules/%s/setup.php", $name);
291: if (is_readable($path)) {
292: $filters = self::merge_filters($filters, require $path);
293: }
294: }
295: $this->filters = $filters;
296: }
297:
298: /**
299: * Merge input filters from module sets
300: * @param array $existing already collected filters
301: * @param array $new new filters to merge
302: * @return array merged list
303: */
304: static public function merge_filters($existing, $new) {
305: foreach (array('allowed_output', 'allowed_get', 'allowed_cookie', 'allowed_post', 'allowed_server', 'allowed_pages') as $v) {
306: if (array_key_exists($v, $new)) {
307: if ($v == 'allowed_pages' || $v == 'allowed_output') {
308: $existing[$v] = array_merge($existing[$v], $new[$v]);
309: } else {
310: $existing[$v] += $new[$v];
311: }
312: }
313: }
314: return $existing;
315: }
316:
317: /**
318: * Return the subset of active modules from a supplied list
319: * @param array $mod_list list of modules
320: * @return array filter list
321: */
322: public function get_active_mods($mod_list) {
323: return array_unique(array_values(array_map(function($v) { return $v[0]; }, $mod_list)));
324: }
325:
326: /**
327: * Load modules into a module manager
328: * @param string $class name of the module manager to use
329: * @param array $module_sets list of modules by page
330: * @param string $page page id
331: * @return void
332: */
333: public function load_modules($class, $module_sets, $page) {
334: foreach ($module_sets as $mod_page => $modlist) {
335: foreach ($modlist as $name => $vals) {
336: if ($page == $mod_page) {
337: $class::add($mod_page, $name, $vals[1], false, 'after', true, $vals[0]);
338: }
339: }
340: }
341: $class::try_queued_modules();
342: $class::process_all_page_queue();
343: $class::try_queued_modules();
344: $class::process_replace_queue();
345: }
346:
347: /**
348: * Load all module sets and include required modules.php files
349: * @param string $page page id
350: * @return void
351: */
352: public function load_module_sets($page) {
353:
354: $this->load_modules('Hm_Handler_Modules', $this->handlers, $page);
355: $this->load_modules('Hm_Output_Modules', $this->outputs, $page);
356: $active_mods = array_unique(array_merge($this->get_active_mods(Hm_Output_Modules::get_for_page($page)),
357: $this->get_active_mods(Hm_Handler_Modules::get_for_page($page))));
358: if (!count($active_mods)) {
359: Hm_Functions::cease('No module assignments found');
360: }
361: $mods = $this->site_config->get_modules();
362: $this->load_module_set_files($mods, $active_mods);
363: }
364:
365: /**
366: * Load module set definition files
367: * @param array $mods modules to load
368: * @param array $active_mods list of active modules
369: * @return void
370: */
371: public function load_module_set_files($mods, $active_mods) {
372: foreach ($mods as $name) {
373: if (in_array($name, $active_mods, true) && is_readable(sprintf(APP_PATH.'modules/%s/modules.php', $name))) {
374: require_once sprintf(APP_PATH.'modules/%s/modules.php', $name);
375: }
376: }
377: }
378: }
379: