function($prop, &$context) { $context['current_component_id'] = $prop['id']; return('
'); }, 'end' => function($prop) { ?>'); }, 'render' => function($prop, &$context) { return($context['begin']($prop, $context) . $context['end']($prop)); }, 'about' => 'This is an example component that wraps content in a div and logs when it is finalized.', ]; */ $GLOBALS['render_funcs'] = array(); function component_component_error_banner($s) { ?> function($prop) { ... }]; */ function component_get_func($file_name, $return_false_if_not_found = false, $search_path = false) { $result = []; // Check if component is already loaded in global registry if(!isset($GLOBALS['render_funcs'][$file_name])) { if(file_exists($file_name.'.php')) { $result['component_file'] = $file_name.'.php'; } else { // Component file not found - create error component if($return_false_if_not_found) return(false); $result['component_file'] = false; $result['error'] = 'Component not found: '.$file_name; $result['render'] = function() use($file_name, $rcontent, $search_path) { return(''); }; } if($result['component_file']) foreach(require($result['component_file']) as $k => $v) $result[$k] = $v; // Register component in global registry for future use $GLOBALS['render_funcs'][$file_name] = $result; } return($GLOBALS['render_funcs'][$file_name]); } /** * Checks if a component exists without loading it * Returns true if component file can be found, false otherwise */ function component_exists($file_name) { $caller_dir = dirname(debug_backtrace()[0]['file']); return(component_get_func($file_name, true, $caller_dir) !== false); } /** * Loads a component and returns its definition * Same as component_get_func but with caller directory detection */ function component_load($file_name) { $caller_dir = dirname(debug_backtrace()[0]['file']); return(component_get_func($file_name, true, $caller_dir)); } /** * Declares an inline component directly in code (not from file) * * @param string $file_name - Component name for registry * @param array $render_prop - Component definition with render functions * * Example: * component_declare('my-button', [ * 'render' => function($prop) { return ""; } * ]); */ function component_declare($file_name, $render_prop) { // Register the inline component directly in global registry $GLOBALS['render_funcs'][$file_name] = $render_prop; } /** * Main component rendering function - the heart of the component system * * @param string $file_name - Component name (can include render method like 'comp:method') * @param array $prop - Properties/data to pass to component * @return mixed - Component output (HTML string or structured data) * * Component calling examples: * component('button', ['text' => 'Click me']) * component('section:begin', ['options' => [...]]) use the 'begin' render function * component('section:end']) use the 'end' render function * component('form', ['return_struct' => true]) // Returns structured data */ function component($file_name, $prop = array()) { Profiler::log('component '.$file_name, 1); $caller_dir = dirname(debug_backtrace()[0]['file']); if($file_name == '') return(component_error_banner('[component name empty]')); // Default render method is 'render', but can be overridden $prop['render_call'] = first($prop['render_call'], 'render'); // Support for calling specific render methods: 'component:method' if(stristr($file_name, ':')) // you can specify which render function to call { $prop['render_call'] = $file_name; $file_name = nibble(':', $prop['render_call']); } // Get component definition from registry (load if not already loaded) $renderer = &$GLOBALS['render_funcs'][$file_name]; if(!$renderer) { // Component not in registry - try to load from file component_get_func($file_name, false, $caller_dir); $renderer = &$GLOBALS['render_funcs'][$file_name]; } // Generate unique ID for component instance if not provided $prop['id'] = $prop['id'] ? $prop['id'] : 'c'.($GLOBALS['id_counter']++); $prop['filename'] = $file_name; if(is_callable($renderer[$prop['render_call']])) $result = ($renderer[$prop['render_call']]($prop, $renderer)); else $result = ($renderer[$prop['render_call']]); Profiler::log(false, -1); return($result); }