diff --git a/app/Common.php b/app/Common.php index 6ae40b65..1f3b17c2 100644 --- a/app/Common.php +++ b/app/Common.php @@ -2,8 +2,8 @@ declare(strict_types=1); -use App\Libraries\View; use Config\Services; +use Config\View; use ViewThemes\Theme; /** diff --git a/app/Config/Services.php b/app/Config/Services.php index 88da0c41..3fa2e092 100644 --- a/app/Config/Services.php +++ b/app/Config/Services.php @@ -7,13 +7,10 @@ namespace Config; use App\Libraries\Breadcrumb; use App\Libraries\Negotiate; use App\Libraries\Router; -use App\Libraries\View; use CodeIgniter\Config\BaseService; use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\Router\RouteCollectionInterface; -use Config\Services as AppServices; -use Config\View as ViewConfig; /** * Services Configuration file. @@ -48,24 +45,6 @@ class Services extends BaseService return new Router($routes, $request); } - /** - * The Renderer class is the class that actually displays a file to the user. The default View class within - * CodeIgniter is intentionally simple, but this service could easily be replaced by a template engine if the user - * needed to. - */ - public static function renderer(?string $viewPath = null, ?ViewConfig $config = null, bool $getShared = true): View - { - if ($getShared) { - return static::getSharedInstance('renderer', $viewPath, $config); - } - - $viewPath = $viewPath ?: config('Paths') - ->viewDirectory; - $config = $config ?? config('View'); - - return new View($config, $viewPath, AppServices::locator(), CI_DEBUG, AppServices::logger()); - } - /** * The Negotiate class provides the content negotiation features for working the request to determine correct * language, encoding, charset, and more. diff --git a/app/Config/View.php b/app/Config/View.php index 212f28c9..104cdd8d 100644 --- a/app/Config/View.php +++ b/app/Config/View.php @@ -6,6 +6,7 @@ namespace Config; use CodeIgniter\Config\View as BaseView; use CodeIgniter\View\ViewDecoratorInterface; +use ViewComponents\Decorator; class View extends BaseView { @@ -46,5 +47,5 @@ class View extends BaseView * * @var class-string[] */ - public array $decorators = []; + public array $decorators = [Decorator::class]; } diff --git a/app/Libraries/View.php b/app/Libraries/View.php deleted file mode 100644 index 1fbb09ec..00000000 --- a/app/Libraries/View.php +++ /dev/null @@ -1,142 +0,0 @@ -|null $options Reserved for 3rd-party uses since - * it might be needed to pass additional info - * to other template engines. - * @param bool|null $saveData If true, saves data for subsequent calls, - * if false, cleans the data after displaying, - * if null, uses the config setting. - */ - public function render(string $view, ?array $options = null, ?bool $saveData = null): string - { - $this->renderVars['start'] = microtime(true); - - // Store the results here so even if - // multiple views are called in a view, it won't - // clean it unless we mean it to. - $saveData = $saveData ?? $this->saveData; - $fileExt = pathinfo($view, PATHINFO_EXTENSION); - $realPath = $fileExt === '' ? $view . '.php' : $view; // allow Views as .html, .tpl, etc (from CI3) - $this->renderVars['view'] = $realPath; - $this->renderVars['options'] = $options ?? []; - - // Was it cached? - if (isset($this->renderVars['options']['cache'])) { - $cacheName = $this->renderVars['options']['cache_name'] ?? str_replace( - '.php', - '', - $this->renderVars['view'] - ); - $cacheName = str_replace(['\\', '/'], '', $cacheName); - - $this->renderVars['cacheName'] = $cacheName; - - if ($output = cache($this->renderVars['cacheName'])) { - $this->logPerformance($this->renderVars['start'], microtime(true), $this->renderVars['view']); - - return $output; - } - } - - $this->renderVars['file'] = $this->viewPath . $this->renderVars['view']; - - if (! is_file($this->renderVars['file'])) { - $this->renderVars['file'] = $this->loader->locateFile( - $this->renderVars['view'], - 'Views', - $fileExt === '' ? 'php' : $fileExt - ); - } - - // locateFile will return an empty string if the file cannot be found. - if ($this->renderVars['file'] === '') { - throw ViewException::forInvalidFile($this->renderVars['view']); - } - - // Make our view data available to the view. - $this->tempData = $this->tempData ?? $this->data; - - if ($saveData) { - $this->data = $this->tempData; - } - - // Save current vars - $renderVars = $this->renderVars; - - $output = (function (): string { - extract($this->tempData); - ob_start(); - include $this->renderVars['file']; - - return ob_get_clean() ?: ''; - })(); - - // Get back current vars - $this->renderVars = $renderVars; - - // When using layouts, the data has already been stored - // in $this->sections, and no other valid output - // is allowed in $output so we'll overwrite it. - if ($this->layout !== null && $this->sectionStack === []) { - $layoutView = $this->layout; - $this->layout = null; - // Save current vars - $renderVars = $this->renderVars; - $output = $this->render($layoutView, $options, $saveData); - // Get back current vars - $this->renderVars = $renderVars; - } - - $output = service('components') - ->setCurrentView($this->renderVars['file']) - ->render($output); - - $this->logPerformance($this->renderVars['start'], microtime(true), $this->renderVars['view']); - - if (($this->debug && (! isset($options['debug']) || $options['debug'] === true)) - && in_array(DebugToolbar::class, service('filters')->getFiltersClass()['after'], true) - ) { - $toolbarCollectors = config(Toolbar::class)->collectors; - - if (in_array(Views::class, $toolbarCollectors, true)) { - // Clean up our path names to make them a little cleaner - $this->renderVars['file'] = clean_path($this->renderVars['file']); - $this->renderVars['file'] = ++$this->viewsCount . ' ' . $this->renderVars['file']; - - $output = '' . PHP_EOL - . $output . PHP_EOL - . '' . PHP_EOL; - } - } - - // Should we cache? - if (isset($this->renderVars['options']['cache'])) { - cache()->save($this->renderVars['cacheName'], $output, (int) $this->renderVars['options']['cache']); - } - - $this->tempData = null; - - return $output; - } -} diff --git a/app/Libraries/ViewComponents/ComponentRenderer.php b/app/Libraries/ViewComponents/ComponentRenderer.php index 70a42a00..09712615 100644 --- a/app/Libraries/ViewComponents/ComponentRenderer.php +++ b/app/Libraries/ViewComponents/ComponentRenderer.php @@ -14,23 +14,11 @@ class ComponentRenderer { protected ViewComponents $config; - /** - * File name of the view source - */ - protected string $currentView; - public function __construct() { $this->config = config('ViewComponents'); } - public function setCurrentView(string $view): self - { - $this->currentView = $view; - - return $this; - } - public function render(string $output): string { // Try to locate any custom tags, with PascalCase names like: Button, Label, etc. @@ -139,10 +127,7 @@ class ComponentRenderer // TODO: Is there a better way to locate components local to current module? $pathsToDiscover = []; $lookupPaths = $this->config->lookupPaths; - $pathsToDiscover = array_filter($lookupPaths, function ($path): bool { - return str_starts_with($this->currentView, $path); - }); - $pathsToDiscover = array_values($pathsToDiscover); + $pathsToDiscover = array_values($lookupPaths); $pathsToDiscover[] = $this->config->defaultLookupPath; $namePath = str_replace('.', '/', $name); diff --git a/app/Libraries/ViewComponents/Decorator.php b/app/Libraries/ViewComponents/Decorator.php new file mode 100644 index 00000000..9ca40085 --- /dev/null +++ b/app/Libraries/ViewComponents/Decorator.php @@ -0,0 +1,38 @@ +render($html); + } + + /** + * Factory method to create a new instance of ComponentRenderer + */ + private static function factory(): ComponentRenderer + { + if (self::$components === null) { + self::$components = new ComponentRenderer(); + } + + return self::$components; + } +}