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] => 222
    [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] => 		$responseType = $response->getType();

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

            [12] => 

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

        )

    [trace] => #0 /home/www/vvveb/www/system/core/frontcontroller.php(223): call_user_func()
#1 /home/www/vvveb/www/system/core/frontcontroller.php(295): Vvveb\System\Core\FrontController::call()
#2 /home/www/vvveb/www/system/core/frontcontroller.php(368): Vvveb\System\Core\FrontController::redirect()
#3 /home/www/vvveb/www/system/core/startup.php(415): 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] => 	 * Standard Controller constructor.

            [34] => 	 */

            [35] => 	static private $moduleName;

            [36] => 

            [37] => 	static private $actionName;

            [38] => 

            [39] => 	static private $status = 200;

            [40] => 

            [41] => 	/**

            [42] => 	 * Returns current controller name.

            [43] => 	 *

            [44] => 	 * @return string

            [45] => 	 */

            [46] => 	static function getModuleName() {

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

            [48] => 	}

            [49] => 

            [50] => 	/**

            [51] => 	 * Returns current controller name.

            [52] => 	 *

            [53] => 	 * @return string

            [54] => 	 */

            [55] => 	static function getActionName() {

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

            [57] => 	}

            [58] => 

            [59] => 	/**

            [60] => 	 * Returns current status.

            [61] => 	 *

            [62] => 	 * @return string

            [63] => 	 */

            [64] => 	static function getStatus() {

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

            [66] => 	}

            [67] => 

            [68] => 	static function setStatus($status) {

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

            [70] => 	}

            [71] => 

            [72] => 	static private function callAction($controller, $action = 'index') {

            [73] => 		if ($statusCode !== 200) {

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

            [75] => 		}

            [76] => 

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

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

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

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

            [81] => 		}

            [82] => 	}

            [83] => 

            [84] => 	static function notFound($service = false, $message = false, $statusCode = 404) {

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

            [86] => 

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

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

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

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

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

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

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

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

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

            [96] => 			} else {

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

            [98] => 			}

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

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

            [101] => 			die();

            [102] => 			return;

            [103] => 		} else {

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

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

            [106] => 

            [107] => 			http_response_code($statusCode);

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

            [109] => 		}

            [110] => 	}

            [111] => 

            [112] => 	static function closeConnections() {

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

            [114] => 			//fastcgi_finish_request();

            [115] => 		}

            [116] => 		/*

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

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

            [119] => 		}*/

            [120] => 	}

            [121] => 

            [122] => 	/**

            [123] => 	 * Inject dependencies.

            [124] => 	 * 

            [125] => 	 * @param string $controller

            [126] => 	 */

            [127] => 	static function di(&$controller) {

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

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

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

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

            [132] => 	}

            [133] => 

            [134] => 	/**

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

            [136] => 	 * 

            [137] => 	 * @param string $controllerClass

            [138] => 	 * @param string $actionName

            [139] => 	 * @param string $file

            [140] => 	 */

            [141] => 	static function call($controllerClass, $actionName, $file = false) {

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

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

            [144] => 			$message = [

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

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

            [147] => 			];

            [148] => 

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

            [150] => 		}

            [151] => 

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

            [153] => 		$controller = false;

            [154] => 

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

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

            [157] => 

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

            [159] => 				$message = [

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

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

            [162] => 				];

            [163] => 

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

            [165] => 			}

            [166] => 		} else {

            [167] => 			$message = [

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

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

            [170] => 			];

            [171] => 

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

            [173] => 		}

            [174] => 

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

            [176] => 

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

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

            [179] => 

            [180] => 			if ($return) {

            [181] => 				$actionName = $return;

            [182] => 

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

            [184] => 					$message = [

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

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

            [187] => 					];

            [188] => 

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

            [190] => 				}

            [191] => 			}

            [192] => 		}

            [193] => 

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

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

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

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

            [198] => 		$isPlugin = strncmp($template, 'plugins/', 8) === 0;

            [199] => 

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

            [201] => 			if ($isPlugin) {

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

            [203] => 				$p          = strpos($t, DS);

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

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

            [206] => 

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

            [208] => 			} else {

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

            [210] => 			}

            [211] => 

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

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

            [214] => 			}

            [215] => 		}

            [216] => 

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

            [218] => 

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

            [220] => 

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

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

            [223] => 

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

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

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

            [227] => 

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

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

            [230] => 		} else {

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

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

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

            [234] => 			} else {

            [235] => 				if ($template) {

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

            [237] => 				}

            [238] => 			}

            [239] => 		}

            [240] => 

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

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

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

            [244] => 

            [245] => 		return $return;

            [246] => 	}

            [247] => 

            [248] => 	/**

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

            [250] => 	 * it has the ability to http redirect to the specified action

            [251] => 	 * internally used to direct to action.

            [252] => 	 *

            [253] => 	 * @param string $moduleName

            [254] => 	 * @param string $actionName

            [255] => 	 * @param array $parameters

            [256] => 	 * @param bool $httpRedirect

            [257] => 	 * @return bool

            [258] => 	 */

            [259] => 	static function redirect($moduleName , $actionName = 'index') {

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

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

            [262] => 

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

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

            [265] => 		}

            [266] => 

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

            [268] => 

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

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

            [271] => 

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

            [273] => 		if (strpos($moduleName, 'Plugins/') === 0) {

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

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

            [276] => 			$pluginName      = $dir;

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

            [278] => 

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

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

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

            [282] => 			}

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

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

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

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

            [287] => 			//insert Controller namespace

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

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

            [290] => 		} else {

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

            [292] => 		}

            [293] => 

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

            [295] => 	}

            [296] => 

            [297] => 	static public function getRoute() {

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

            [299] => 	}

            [300] => 

            [301] => 	static public function getModule() {

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

            [303] => 	}

            [304] => 

            [305] => 	static public function dispatch(&$site = []) {

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

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

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

            [309] => 

            [310] => 		//subdirectory support

            [311] => 		/*

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

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

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

            [315] => 		*/

            [316] => 

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

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

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

            [320] => 

            [321] => 		$route = false;

            [322] => 		$routesSiteId = null;

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

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

            [325] => 		}

            [326] => 

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

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

            [329] => 		} else {

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

            [331] => 

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

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

            [334] => 			}

            [335] => 		}

            [336] => 

            [337] => 		if ($route) {

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

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

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

            [341] => 			} else {

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

            [343] => 			}

            [344] => 		}

            [345] => 

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

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

            [348] => 		}

            [349] => 		//santize inputs

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

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

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

            [353] => 		}

            [354] => 

            [355] => 		$path = $module;

            [356] => 

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

            [358] => 		$path           = '';

            [359] => 

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

            [361] => 			if ($path) {

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

            [363] => 			}

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

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

            [366] => 

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

            [368] => 	}

            [369] => }

        )

)