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] => }
)
)