WizdomWeb/app/Core/View.php

111 lines
3.8 KiB
PHP

<?php
// ============================================
// File: View.php
// Version: 1.2
// Path: app/Core/View.php
// Purpose: Handles dynamic view rendering with optional layout wrapping
// Project: Wizdom Networks Website
// Usage: View::render('pages/landing', $data, 'arsha')
// ============================================
namespace WizdomNetworks\WizeWeb\Core;
use WizdomNetworks\WizeWeb\Utilities\Logger;
use WizdomNetworks\WizeWeb\Utilities\ErrorHandler;
/**
* View Renderer
*
* Handles view rendering, ensuring proper data passing and error handling.
*/
class View
{
/**
* Renders a view file and optionally wraps it in a layout.
*
* @param string $view The name of the view file (relative to /resources/views/).
* @param array $data Associative array of variables to pass to the view.
* @param string|null $layout The layout to use (relative to /resources/views/layouts/). Default is null (no layout).
* @throws \Exception If the view or layout file is not found.
*/
public static function render(string $view, array $data = [], ?string $layout = null): void
{
Logger::debug("Rendering view: $view");
if (!class_exists('View')) {
class_alias(self::class, 'View');
}
// Extract data to make variables available in the view
extract($data);
$viewPath = realpath(__DIR__ . "/../../resources/views/" . str_replace('.', '/', $view) . ".php");
Logger::debug("Resolved view path: $viewPath");
// If using layout, resolve layout path
if ($layout) {
$layoutPath = realpath(__DIR__ . "/../../resources/views/layouts/" . $layout . ".php");
Logger::debug("Resolved layout path: $layoutPath");
if (!$layoutPath || !file_exists($layoutPath)) {
Logger::error("Layout file not found: $layout");
throw new \Exception("Layout file not found: $layout");
}
}
if (!$viewPath || !file_exists($viewPath)) {
Logger::error("View file not found: $view | Resolved path: $viewPath");
throw new \Exception("View file not found: $view");
}
// If using a layout, buffer content then inject into layout
if ($layout) {
ob_start();
include $viewPath;
$content = ob_get_clean();
include $layoutPath;
Logger::debug("Successfully rendered view: $view into layout: $layout");
} else {
include $viewPath;
Logger::debug("Successfully rendered view: $view (no layout)");
}
}
/**
* Renders a partial view without applying a layout.
*
* Use this for modular components like hero, services, faq, etc.
* Partial views must reside in: /resources/views/partials/
*
* @param string $partial The name of the partial (e.g., 'hero', 'faq').
* You may use dot notation for subdirectories (e.g., 'admin.nav').
* @param array $data Optional associative array of data to be extracted into the view.
*
* @throws \Exception if the partial file does not exist.
*
* @return void
*/
public static function renderPartial(string $partial, array $data = []): void
{
Logger::debug("Rendering partial: $partial");
// Convert dot notation to path and resolve to full filesystem path
$partialPath = realpath(__DIR__ . "/../../resources/views/partials/" . str_replace('.', '/', $partial) . ".php");
Logger::debug("Resolved partial path: $partialPath");
if (!$partialPath || !file_exists($partialPath)) {
Logger::error("Partial view not found: $partial | Resolved path: $partialPath");
throw new \Exception("Partial view not found: $partial");
}
// Extract data and include partial
extract($data);
include $partialPath;
Logger::debug("Successfully rendered partial: $partial");
}
}