You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
9.3 KiB
282 lines
9.3 KiB
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* @author Robert Strutts
|
|
* @copyright (c) 2026, Robert Strutts
|
|
* @license MIT
|
|
*/
|
|
|
|
namespace IOcornerstone\Framework;
|
|
|
|
use IOcornerstone\Framework\Enum\ViewType;
|
|
use IOcornerstone\Framework\{
|
|
Common,
|
|
Configure,
|
|
Requires,
|
|
Registry,
|
|
};
|
|
|
|
final class View
|
|
{
|
|
|
|
public $white_space_control = false;
|
|
public $page_output;
|
|
private $vars = [];
|
|
private $files = [];
|
|
private $template = false;
|
|
private $use_template_engine = false;
|
|
private $use_template_engine_twig = false;
|
|
private $use_template_engine_liquid = false;
|
|
private $template_type = 'tpl';
|
|
protected $tempalte_engine_twig = null;
|
|
protected $tempalte_engine_liquid = null;
|
|
|
|
private function getFile(string $view_file, string $default): string
|
|
{
|
|
$file = (empty($default)) ? "views/{$view_file}" : "views/{$default}/{$view_file}";
|
|
$path = IO_CORNERSTONE_PROJECT;
|
|
$vf = $path . $file;
|
|
if (Requires::saferFileExists($vf) !== false) {
|
|
return $file;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Alias to set_view
|
|
*/
|
|
public function include(string $file, ViewType $type = ViewType::PHP): void
|
|
{
|
|
$this->setView($file, $type);
|
|
}
|
|
|
|
/**
|
|
* Alias to set_view
|
|
*/
|
|
public function addView(string $file, ViewType $type = ViewType::PHP): void
|
|
{
|
|
$this->setView($file, $type);
|
|
}
|
|
|
|
/**
|
|
* Check the $_GET['render'] for which folder to use to render the view
|
|
* @param string $viewFile
|
|
* @return file | false
|
|
*/
|
|
private function findViewPath(string $viewFile): string|false
|
|
{
|
|
$found = false;
|
|
|
|
$defaultPaths = Configure::get('view_mode', 'default_paths');
|
|
$get = $_GET['render'];
|
|
if (in_array($get, $defaultPaths)) {
|
|
if (($key = array_search($get, $defaultPaths)) !== false) {
|
|
unset($defaultPaths[$key]); // Remove as we'll make it first later...
|
|
}
|
|
array_unshift($defaultPaths, $get); // Make First in Array!
|
|
}
|
|
|
|
foreach ($defaultPaths as $default) {
|
|
$file = $this->getFile($viewFile, $default);
|
|
if (!empty($file)) {
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
return ($found) ? $file : false;
|
|
}
|
|
|
|
/**
|
|
* Use View File
|
|
* @param string $viewFile
|
|
* @param string $render_path
|
|
* @throws Exception
|
|
*/
|
|
public function setView(?string $viewFile = null, ViewType $type = ViewType::PHP): void
|
|
{
|
|
if ($viewFile === null) {
|
|
return;
|
|
}
|
|
|
|
$file_ext = ViewType::get_file_extension_for($type);
|
|
$file = $this->findViewPath($viewFile . $file_ext);
|
|
if ($type == ViewType::TWIG) {
|
|
$this->use_template_engine_twig = true;
|
|
$this->template_type = str_replace('.', '', $file_ext);
|
|
$path = IO_CORNERSTONE_PROJECT;
|
|
if ($file !== false) {
|
|
$file = str_replace("views/twig", "", $file); // Remove Path, as it is defined in the service file
|
|
}
|
|
}
|
|
if ($type == ViewType::LIQUID) {
|
|
$this->use_template_engine_liquid = true;
|
|
$this->template_type = str_replace('.', '', $file_ext);
|
|
if ($file !== false) {
|
|
$file = ltrim(str_replace("views/liquid", "", $file), "/"); // Remove Path, as it is defined in the service file
|
|
}
|
|
}
|
|
|
|
if ($file === false) {
|
|
echo "No view file exists for: {$viewFile}!";
|
|
throw new \Exception("View File does not exist: " . $viewFile);
|
|
} else {
|
|
$this->files[] = array('file' => $file, 'path' => bootstrap\UseDir::PROJECT, 'file_type' => $file_ext);
|
|
}
|
|
}
|
|
|
|
public function clearTemplate(): void
|
|
{
|
|
$this->template = false;
|
|
}
|
|
|
|
/**
|
|
* Use PHP Template with view
|
|
* @param string $render_page
|
|
* @return bool was found
|
|
*/
|
|
public function setPhpTemplate(string $render_page): bool
|
|
{
|
|
if (!empty($render_page)) {
|
|
$render_page = str_replace('.php', '', $render_page);
|
|
$templ = "/templates/{$render_page}";
|
|
if (bootstrap\requires::safer_file_exists(IO_CORNERSTONE_PROJECT . $templ . '.php') !== false) {
|
|
$this->template = $templ;
|
|
return true;
|
|
}
|
|
}
|
|
$this->template = false;
|
|
return false;
|
|
}
|
|
|
|
private function clearOb(int $saved_ob_level): void
|
|
{
|
|
while (ob_get_level() > $saved_ob_level) {
|
|
ob_end_flush();
|
|
}
|
|
}
|
|
|
|
private function obStart(): void
|
|
{
|
|
if (extension_loaded('mbstring')) {
|
|
ob_start('mb_output_handler');
|
|
} else {
|
|
ob_start();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets a variable in this view with the given name and value
|
|
*
|
|
* @param mixed $name Name of the variable to set in the view, or an array of key/value pairs where each key is the variable and each value is the value to set.
|
|
* @param mixed $value Value of the variable to set in the view.
|
|
*/
|
|
public function set($name, mixed $value = null): void
|
|
{
|
|
if (is_array($name)) {
|
|
foreach ($name as $var_name => $value) {
|
|
$this->vars[$var_name] = $value;
|
|
}
|
|
} else {
|
|
$this->vars[$name] = $value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alias to fetch with Built-in echo
|
|
* @param type $local
|
|
* @param string $file
|
|
*/
|
|
public function render($local, ?string $file = null, ViewType $type = ViewType::PHP)
|
|
{
|
|
echo $this->fetch($local, $file, $type);
|
|
}
|
|
|
|
/**
|
|
* Outputs view
|
|
* @param type $local = $this
|
|
* @param $file (optional view file)
|
|
*/
|
|
public function fetch($local, ?string $file = null, ViewType $type = ViewType::PHP): string
|
|
{
|
|
$page_output = ob_get_clean(); // Get echos before View
|
|
$this->obStart();
|
|
$saved_ob_level = ob_get_level();
|
|
$this->setView($file, $type);
|
|
|
|
unset($file);
|
|
|
|
if (!is_object($local)) {
|
|
$local = $this; // FALL Back, please use fetch($this);
|
|
}
|
|
|
|
if ($this->use_template_engine_liquid) {
|
|
$this->tempalte_engine_liquid = Registry::get('di')->get_service('liquid', [$this->template_type]);
|
|
if ($this->white_space_control) {
|
|
$this->tempalte_engine->whitespace_control();
|
|
}
|
|
}
|
|
|
|
if ($this->use_template_engine_twig) {
|
|
$this->tempalte_engine_twig = Registry::get('di')->get_service('twig', [$this->template_type]);
|
|
}
|
|
|
|
if (count($this->files) > 0) {
|
|
foreach ($this->files as $view_file) {
|
|
if ($view_file['file_type'] == '.php') {
|
|
Requires::secureInclude($view_file['file'], UseDir::PROJECT, $local, $this->vars); // Include the PHP file
|
|
} else if ($view_file['file_type'] == '.tpl') {
|
|
// Liquid uses .tpl by default, so remove that File Ext
|
|
$template_file = str_replace('.tpl', '', $view_file['file']);
|
|
$this->tempalte_engine_liquid->parse_file($template_file);
|
|
|
|
$assigns = $this->vars['template_assigns'] ?? [];
|
|
$filters = $this->vars['template_filters'] ?? null;
|
|
$registers = $this->vars['template_registers'] ?? [];
|
|
$assigns['production'] = (isLive());
|
|
echo $this->tempalte_engine_liquid->render($assigns, $filters, $registers);
|
|
} else if ($view_file['file_type'] == '.twig') {
|
|
$fns = $this->vars['twig_functions'] ?? [];
|
|
if (Common::getCount($fns)) {
|
|
foreach ($fns as $fn_label => $fn_name) {
|
|
$this->tempalte_engine_twig->addFunction(new \Twig\TwigFunction($fn_label, $fn_name));
|
|
}
|
|
}
|
|
$twig_data = $this->vars['twig_data'] ?? [];
|
|
echo $this->tempalte_engine_twig->render($view_file['file'], $twig_data);
|
|
} else {
|
|
throw new \Exception("Unable View File Type");
|
|
}
|
|
}
|
|
}
|
|
$this->clear_ob($saved_ob_level);
|
|
$page_output .= ob_get_clean();
|
|
|
|
if (Configure::get('CodeHydrater', 'check_HTML_tags') === true) {
|
|
$tags = TagMatches::checkTags($page_output);
|
|
if (!empty($tags['output'])) {
|
|
$page_output .= $tags['output'];
|
|
$page_output .= '<script type="text/javascript">' . $tags['alert'] . '</script>';
|
|
foreach ($this->files as $bad) {
|
|
$page_output .= "<script type=\"text/javascript\">console.log'In view file:{$bad['file']}');\r\n</script>";
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($this->template !== false && Requires::saferFileExists(IO_CORNERSTONE_PROJECT . $this->template . ".php") !== false) {
|
|
$this->obStart();
|
|
$saved_ob_level = ob_get_level();
|
|
$local->page_output = $page_output;
|
|
Requires::secureInclude($this->template, UseDir::PROJECT, $local, $this->vars);
|
|
$this->clear_ob($saved_ob_level);
|
|
$page_output = ob_get_clean();
|
|
}
|
|
|
|
// Reset Files to zero, as they were outputed....
|
|
unset($this->files);
|
|
$this->files = [];
|
|
|
|
return $page_output;
|
|
}
|
|
}
|
|
|