Exception:
Array
(
    [message] => call_user_func(): Argument #1 ($callback) must be a valid callback, cannot access protected method Vvveb\Controller\Content\Category::language()
    [file] => /home/www/vvveb/www/system/core/frontcontroller.php
    [line_no] => 263
    [line] => 		$template     = call_user_func([$controller, $actionName]);	 // <==

    [lines] => Array
        (
            [0] => 		}

            [1] => 

            [2] => 		$controller->view->template($template . '.html'); //default html that can be overwritten

            [3] => 

            [4] => 		//list($template) = Event :: trigger($controllerClass, "$actionName:before", $template);

            [5] => 

            [6] => 		//$controller->view->template($template . '.html'); //default html

            [7] => 		$template     = call_user_func([$controller, $actionName]);	 // <==

            [8] => 

            [9] => 		list($template, $controller, $actionName) = Event::trigger(__CLASS__, __FUNCTION__, $template, $controller, $actionName);

            [10] => 		//list($template) = Event :: trigger($controllerClass, "$actionName:after", $template);

            [11] => 		//list($responseType) = Event :: trigger($controllerClass, "$actionName:after", $response->getType('json'));

            [12] => 

            [13] => 		$responseType = $response->getType();

        )

    [trace] => #0 /home/www/vvveb/www/system/core/frontcontroller.php(264): call_user_func()
#1 /home/www/vvveb/www/system/core/frontcontroller.php(337): Vvveb\System\Core\FrontController::call()
#2 /home/www/vvveb/www/system/core/frontcontroller.php(426): Vvveb\System\Core\FrontController::redirect()
#3 /home/www/vvveb/www/system/core/startup.php(514): Vvveb\System\Core\FrontController::dispatch()
#4 /home/www/vvveb/www/index.php(102): Vvveb\System\Core\start()
#5 /home/www/vvveb/www/index.php(146): Vvveb\saveCache()
#6 /home/www/vvveb/www/public/index.php(28): include('...')
#7 {main}
    [code] => Array
        (
            [0] =>  

            [2] => /**

            [3] =>  * Vvveb

            [4] =>  *

            [5] =>  * Copyright (C) 2022  Ziadin Givan

            [6] =>  *

            [7] =>  * This program is free software: you can redistribute it and/or modify

            [8] =>  * it under the terms of the GNU Affero General Public License as

            [9] =>  * published by the Free Software Foundation, either version 3 of the

            [10] =>  * License, or (at your option) any later version.

            [11] =>  *

            [12] =>  * This program is distributed in the hope that it will be useful,

            [13] =>  * but WITHOUT ANY WARRANTY; without even the implied warranty of

            [14] =>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

            [15] =>  * GNU Affero General Public License for more details.

            [16] =>  *

            [17] =>  * You should have received a copy of the GNU Affero General Public License

            [18] =>  * along with this program.  If not, see .

            [19] =>  *

            [20] =>  */

            [21] => 

            [22] => namespace Vvveb\System\Core;

            [23] => 

            [24] => use function Vvveb\__;

            [25] => use Vvveb\System\Event;

            [26] => use Vvveb\System\PageCache;

            [27] => use Vvveb\System\Routes;

            [28] => use Vvveb\System\Session;

            [29] => 

            [30] => #[\AllowDynamicProperties]

            [31] => class FrontController {

            [32] => 	/**

            [33] => 	 * Current module (controller) name.

            [34] => 	 *

            [35] => 	 * @var ?string

            [36] => 	 */

            [37] => 	private static ?string $moduleName = null;

            [38] => 

            [39] => 	/**

            [40] => 	 * Current action name.

            [41] => 	 *

            [42] => 	 * @var ?string

            [43] => 	 */

            [44] => 	private static ?string $actionName = null;

            [45] => 

            [46] => 	/**

            [47] => 	 * Current HTTP status code.

            [48] => 	 *

            [49] => 	 * @var int

            [50] => 	 */

            [51] => 	private static int $status = 200;

            [52] => 

            [53] => 	/**

            [54] => 	 * Returns current controller name.

            [55] => 	 *

            [56] => 	 * @return string

            [57] => 	 */

            [58] => 	public static function getModuleName(): string {

            [59] => 		return self::$moduleName;

            [60] => 	}

            [61] => 

            [62] => 	/**

            [63] => 	 * Returns current action name.

            [64] => 	 *

            [65] => 	 * @return string

            [66] => 	 */

            [67] => 	public static function getActionName(): string {

            [68] => 		return self::$actionName;

            [69] => 	}

            [70] => 

            [71] => 	/**

            [72] => 	 * Returns current HTTP status code.

            [73] => 	 *

            [74] => 	 * @return int

            [75] => 	 */

            [76] => 	public static function getStatus(): int {

            [77] => 		return self::$status;

            [78] => 	}

            [79] => 

            [80] => 	/**

            [81] => 	 * Sets the current HTTP status code.

            [82] => 	 *

            [83] => 	 * @param  int $status

            [84] => 	 * @return int

            [85] => 	 */

            [86] => 	public static function setStatus(int $status): int {

            [87] => 		return self::$status = $status;

            [88] => 	}

            [89] => 

            [90] => 	/**

            [91] => 	 * Calls a controller action directly.

            [92] => 	 *

            [93] => 	 * @param  string $controller

            [94] => 	 * @param  string $action

            [95] => 	 * @return void

            [96] => 	 */

            [97] => 	private static function callAction(string $controller, string $action = 'index'): void {

            [98] => 		if (self::$status !== 200) {

            [99] => 			header(' ', true, self::$status);

            [100] => 		}

            [101] => 

            [102] => 		if (include_once DIR_APP . DS . 'controller' . DS . "$controller.php") {

            [103] => 			$controller = 'Vvveb\Controller\\' . $controller;

            [104] => 			self::$moduleName = $controller;

            [105] => 		}

            [106] => 	}

            [107] => 

            [108] => 	/**

            [109] => 	 * Handles 404 (or other error) responses.

            [110] => 	 *

            [111] => 	 * @param  mixed              $service

            [112] => 	 * @param  string|array|false $message

            [113] => 	 * @param  int                $statusCode

            [114] => 	 * @return never

            [115] => 	 */

            [116] => 	public static function notFound(mixed $service = false, string|array|false $message = false, int $statusCode = 404): never {

            [117] => 		self::$status = $statusCode;

            [118] => 

            [119] => 		$file = DIR_APP . DS . 'controller' . DS . "error$statusCode.php";

            [120] => 		if (file_exists($file)) {

            [121] => 			$controller = 'Vvveb\Controller\Error' . $statusCode;

            [122] => 			self::$moduleName = 'error' . $statusCode;

            [123] => 			//http_response_code($statusCode);

            [124] => 			$view = View::getInstance();

            [125] => 			if (is_array($message)) {

            [126] => 				$view->set($message);

            [127] => 			} else {

            [128] => 				$view->message = $message;

            [129] => 			}

            [130] => 

            [131] => 			$view->file = '';

            [132] => 			$view->trace = [];

            [133] => 

            [134] => 			self::call($controller, 'index', $file);

            [135] => 			PageCache::getInstance()->cleanUp();

            [136] => 			die();

            [137] => 		} else {

            [138] => 			//header(' ', true, $statusCode);

            [139] => 			PageCache::getInstance()->cleanUp();

            [140] => 

            [141] => 			http_response_code($statusCode);

            [142] => 			die("Http error $statusCode");

            [143] => 		}

            [144] => 	}

            [145] => 

            [146] => 	/**

            [147] => 	 * Closes open connections (e.g. database) after response is sent.

            [148] => 	 *

            [149] => 	 * @return void

            [150] => 	 */

            [151] => 	public static function closeConnections(): void {

            [152] => 		if (function_exists('fastcgi_finish_request')) {

            [153] => 			//fastcgi_finish_request();

            [154] => 		}

            [155] => 		/*

            [156] => 		if (defined('DB_ENGINE') && ($instance = \Vvveb\System\Db::getInstance())) {

            [157] => 			$instance->close();

            [158] => 		}*/

            [159] => 	}

            [160] => 

            [161] => 	/**

            [162] => 	 * Inject dependencies into a controller instance.

            [163] => 	 *

            [164] => 	 * @param  object &$controller

            [165] => 	 * @return void

            [166] => 	 */

            [167] => 	public static function di(object &$controller): void {

            [168] => 		$controller->request  = Request::getInstance();

            [169] => 		$controller->response = Response::getInstance();

            [170] => 		$controller->view     = View::getInstance();

            [171] => 		$controller->session  = Session::getInstance();

            [172] => 	}

            [173] => 

            [174] => 	/**

            [175] => 	 * Initializes the controller class and calls the action.

            [176] => 	 *

            [177] => 	 * @param  string       $controllerClass

            [178] => 	 * @param  string       $actionName

            [179] => 	 * @param  string|false $file

            [180] => 	 * @return mixed

            [181] => 	 */

            [182] => 	public static function call(string $controllerClass, string $actionName, string|false $file = false): mixed {

            [183] => 		if ((! @include_once(DIR_APP . DS . 'controller' . DS . 'base.php')) ||

            [184] => 			 (! file_exists($file) || ! @include_once($file))) {

            [185] => 			$message = [

            [186] => 				'message' => __('Controller file not found!'),

            [187] => 				'file'    => $file,

            [188] => 			];

            [189] => 

            [190] => 			return self::notFound(false, $message);

            [191] => 		}

            [192] => 

            [193] => 		// We check if the controller's class really exists

            [194] => 		$controller = false;

            [195] => 

            [196] => 		if (class_exists($controllerClass , false)) {// if the controller does not exist route to controller main

            [197] => 			$controller = new $controllerClass();

            [198] => 

            [199] => 			if (! $controller || ! method_exists($controller , $actionName) || $actionName === 'init') {

            [200] => 				$message = [

            [201] => 					'message' => __('Method does not exist!'),

            [202] => 					'file'    => "$controllerClass :: $actionName",

            [203] => 				];

            [204] => 

            [205] => 				return self::notFound(false, $message);

            [206] => 			}

            [207] => 		} else {

            [208] => 			$message = [

            [209] => 				'message' => __('Controller does not exist!'),

            [210] => 				'file'    => $controllerClass,

            [211] => 			];

            [212] => 

            [213] => 			return self::notFound(false, $message);

            [214] => 		}

            [215] => 

            [216] => 		self::di($controller);

            [217] => 

            [218] => 		if (method_exists($controller, 'init')) {

            [219] => 			$return = $controller->init();

            [220] => 

            [221] => 			if ($return) {

            [222] => 				$actionName = $return;

            [223] => 

            [224] => 				if (! method_exists($controller , $actionName)) {

            [225] => 					$message = [

            [226] => 						'message' => __('Method does not exist!'),

            [227] => 						'file'    => "$controllerClass :: $actionName",

            [228] => 					];

            [229] => 

            [230] => 					return self::notFound(false, $message);

            [231] => 				}

            [232] => 			}

            [233] => 		}

            [234] => 

            [235] => 		$response = Response::getInstance();

            [236] => 		$template = str_replace('/', DS, strtolower(self::$moduleName));

            [237] => 		$theme 	  = $controller->view->getTheme();

            [238] => 		$path     = DIR_THEME . $theme . DS;

            [239] => 		$isPlugin = str_starts_with($template, 'plugins/');

            [240] => 

            [241] => 		if ($actionName && $actionName !== 'index') {

            [242] => 			if ($isPlugin) {

            [243] => 				$t          = str_replace('plugins' . DS, '', $template);

            [244] => 				$p          = str_contains($t, DS) ? strpos($t, DS) : false;

            [245] => 				$pluginName = substr($t, 0, $p);

            [246] => 				$nameSpace  = substr($t, $p + 1);

            [247] => 

            [248] => 				$html = DIR_PLUGINS . $pluginName . DS . 'public' . DS . APP . DS . $nameSpace . DS . strtolower($actionName) . '.html';

            [249] => 			} else {

            [250] => 				$html = $path . $template . DS . strtolower($actionName) . '.html';

            [251] => 			}

            [252] => 

            [253] => 			if (is_file($html)) {

            [254] => 				$template .= DS . strtolower($actionName);

            [255] => 			}

            [256] => 		}

            [257] => 

            [258] => 		$controller->view->template($template . '.html'); //default html that can be overwritten

            [259] => 

            [260] => 		//list($template) = Event :: trigger($controllerClass, "$actionName:before", $template);

            [261] => 

            [262] => 		//$controller->view->template($template . '.html'); //default html

            [263] => 		$template     = call_user_func([$controller, $actionName]);	 // <==

            [264] => 

            [265] => 		list($template, $controller, $actionName) = Event::trigger(__CLASS__, __FUNCTION__, $template, $controller, $actionName);

            [266] => 		//list($template) = Event :: trigger($controllerClass, "$actionName:after", $template);

            [267] => 		//list($responseType) = Event :: trigger($controllerClass, "$actionName:after", $response->getType('json'));

            [268] => 

            [269] => 		$responseType = $response->getType();

            [270] => 		$controller->view->setType($responseType);

            [271] => 

            [272] => 		if ($template === false) {

            [273] => 			$controller->view->template(false);

            [274] => 		} else {

            [275] => 			if (is_array($template)) {

            [276] => 				$response->output($template);

            [277] => 				//echo json_encode($template);

            [278] => 			} else {

            [279] => 				if ($template) {

            [280] => 					$controller->view->template($template);

            [281] => 				}

            [282] => 			}

            [283] => 		}

            [284] => 

            [285] => 		$response->setStatus(self::$status);

            [286] => 		$return = $response->output();

            [287] => 		self::closeConnections();

            [288] => 

            [289] => 		return $return;

            [290] => 	}

            [291] => 

            [292] => 	/**

            [293] => 	 * Redirect or direct to a action or default controller action and parameters.

            [294] => 	 * It has the ability to http redirect to the specified action.

            [295] => 	 * Internally used to direct to action.

            [296] => 	 *

            [297] => 	 * @param  string $moduleName

            [298] => 	 * @param  string $actionName

            [299] => 	 * @return mixed

            [300] => 	 */

            [301] => 	public static function redirect(string $moduleName, string $actionName = 'index'): mixed {

            [302] => 		self::$moduleName = $moduleName;

            [303] => 		self::$actionName = $actionName;

            [304] => 

            [305] => 		if (is_dir(DIR_APP . DS . 'controller' . DS . strtolower($moduleName))) {

            [306] => 			self::$moduleName = $moduleName .= '/Index';

            [307] => 		}

            [308] => 

            [309] => 		$dir = strtolower(str_replace('/', DS, $moduleName));

            [310] => 

            [311] => 		$className       = \Vvveb\dashesToCamelCase(str_replace(['/', DS], '\\',  $moduleName));

            [312] => 		$controllerClass = 'Vvveb\Controller\\' . $className;

            [313] => 

            [314] => 		//change file paths for plugins

            [315] => 		if (str_starts_with($moduleName, 'Plugins/')) {

            [316] => 			$dir             = str_replace('plugins' . DS, '', $dir);

            [317] => 			$p               = strpos($dir, DS);

            [318] => 			$pluginName      = $dir;

            [319] => 			$nameSpace       = 'index';

            [320] => 

            [321] => 			if ($p !== false) {

            [322] => 				$pluginName      = substr($dir, 0, $p);

            [323] => 				$nameSpace       = substr($dir, $p + 1);

            [324] => 			}

            [325] => 			//$className       = str_replace('Plugins\\', '', $className);

            [326] => 			$file            = DIR_PLUGINS . $pluginName . DS . APP .

            [327] => 							   DS . 'controller' . DS . "$nameSpace.php";

            [328] => 			$pluginName      = \Vvveb\dashesToCamelCase($pluginName);

            [329] => 			//insert Controller namespace

            [330] => 			$className  	    = str_replace('Plugins\\' . $pluginName, $pluginName . '\Controller', $className);

            [331] => 			$controllerClass = 'Vvveb\Plugins\\' . $className;

            [332] => 		} else {

            [333] => 			$file = DIR_APP . 'controller' . DS . $dir . '.php';

            [334] => 		}

            [335] => 

            [336] => 		return self::call($controllerClass, $actionName, $file);

            [337] => 	}

            [338] => 

            [339] => 	/**

            [340] => 	 * Returns the current route from the query string.

            [341] => 	 *

            [342] => 	 * @return string

            [343] => 	 */

            [344] => 	public static function getRoute(): string {

            [345] => 		return $_GET['route'] ?? '';

            [346] => 	}

            [347] => 

            [348] => 	/**

            [349] => 	 * Returns the current module from the query string.

            [350] => 	 *

            [351] => 	 * @return string

            [352] => 	 */

            [353] => 	public static function getModule(): string {

            [354] => 		return $_GET['module'] ?? '';

            [355] => 	}

            [356] => 

            [357] => 	/**

            [358] => 	 * Dispatches the request to the appropriate controller/action.

            [359] => 	 *

            [360] => 	 * @param  array &$site

            [361] => 	 * @return mixed

            [362] => 	 */

            [363] => 	public static function dispatch(array &$site = []): mixed {

            [364] => 		$module   = $_GET['module'] ?? $_POST['module'] ?? null;

            [365] => 		$action   = $_GET['action'] ?? $_POST['action'] ?? null;

            [366] => 		$_REQUEST = array_merge($_GET, $_REQUEST);

            [367] => 

            [368] => 		//subdirectory support

            [369] => 		/*

            [370] => 		$subdir = \Vvveb\pregMatch('@(.+)/index.php@',$_SERVER['SCRIPT_NAME'], 1);

            [371] => 		$subdir = str_replace(['/public', '/admin'], '', $subdir);

            [372] => 		define('V_SUBDIR_INSTALL', $subdir);

            [373] => 		*/

            [374] => 

            [375] => 		//remove GET parameters to allow correct matching,

            [376] => 		$uri = SITE_URI ?? $_SERVER['REQUEST_URI'] ?? '/';

            [377] => 		$uri   = preg_replace('/\?.*$/', '', $uri);

            [378] => 

            [379] => 		$route = false;

            [380] => 		$routesSiteId = null;

            [381] => 		if (isset($site['route'])) {

            [382] => 			$routesSiteId = $site['site_id'];

            [383] => 		}

            [384] => 

            [385] => 		if (! $module && (APP !== 'admin' && APP !== 'install' && (Routes::init(APP, $routesSiteId) && $route = Routes::match($uri)))) {

            [386] => 			$_GET = array_merge($route, $_GET);

            [387] => 		} else {

            [388] => 			$module         = $module ?? ((APP === 'install' || APP === 'admin') ? 'index' : false);

            [389] => 

            [390] => 			if (! $module && APP === 'app') {

            [391] => 				return self::notFound(false, ['message' => 'No route!']);

            [392] => 			}

            [393] => 		}

            [394] => 

            [395] => 		if ($route) {

            [396] => 			if (preg_match('@(^.+?)/(\w+$)@', $_GET['module'], $routeMatch)) {

            [397] => 				$module = $routeMatch[1];

            [398] => 				$action = $action ?? $routeMatch[2];

            [399] => 			} else {

            [400] => 				$module = trim($_GET['module'], '/');

            [401] => 			}

            [402] => 		}

            [403] => 

            [404] => 		if (empty($action)) {

            [405] => 			$action = 'index';

            [406] => 		}

            [407] => 		//santize inputs

            [408] => 		if (($module && ! preg_match('@^[a-zA-Z_/0-9\-]{4,70}$@', $module)) ||

            [409] => 			($action && ! preg_match('@^[a-zA-Z_/0-9\-]{3,70}$@', $action))) {

            [410] => 			return self::notFound(false, ['message' => 'Invalid request!'], 500);

            [411] => 		}

            [412] => 

            [413] => 		$path = $module;

            [414] => 

            [415] => 		$module         = ucfirst($module);

            [416] => 		$path           = '';

            [417] => 

            [418] => 		array_map(function ($value) use (&$path) {

            [419] => 			if ($path) {

            [420] => 				$path .= '/';

            [421] => 			}

            [422] => 			$path .= ucfirst($value);

            [423] => 		}, explode('/', $module));

            [424] => 

            [425] => 		return self::redirect($path, $action);

            [426] => 	}

            [427] => }

        )

)