From f8af600f2fd2e70f3a34f2d0b8614021a84db79f Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 6 Nov 2025 18:44:14 +0300 Subject: [PATCH 01/25] chore: Pump-Up Database to V1.2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7f43b55de..83131b449 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "webfiori/jsonx": "v4.0.*", "webfiori/ui": "v4.0.*", "webfiori/collections": "v2.0.*", - "webfiori/database": "v1.1.*", + "webfiori/database": "v1.2.*", "webfiori/cli": "v2.0.*", "webfiori/mailer": "v2.1.*", "webfiori/err": "v2.0.*" From 44940b62e2ead9c7cbc30110d89ff007bedb6d4d Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 10 Nov 2025 23:25:54 +0300 Subject: [PATCH 02/25] refactor: Removal of `SettingsCommand` --- WebFiori/Framework/App.php | 4 +- .../Cli/Commands/SettingsCommand.php | 75 --- .../Cli/Commands/UpdateSettingsCommand.php | 213 -------- .../Framework/Tests/Cli/HelpCommandTest.php | 24 +- .../Tests/Cli/SettingsCommandTest.php | 50 -- .../Tests/Cli/UpdateSettingsCommandTest.php | 490 ------------------ 6 files changed, 14 insertions(+), 842 deletions(-) delete mode 100644 WebFiori/Framework/Cli/Commands/SettingsCommand.php delete mode 100644 WebFiori/Framework/Cli/Commands/UpdateSettingsCommand.php delete mode 100644 tests/WebFiori/Framework/Tests/Cli/SettingsCommandTest.php delete mode 100644 tests/WebFiori/Framework/Tests/Cli/UpdateSettingsCommandTest.php diff --git a/WebFiori/Framework/App.php b/WebFiori/Framework/App.php index ed7857ee1..2dad1fae6 100644 --- a/WebFiori/Framework/App.php +++ b/WebFiori/Framework/App.php @@ -423,14 +423,14 @@ public static function getRunner() : Runner { $commands = [ '\\WebFiori\\Framework\\Cli\\Commands\\WHelpCommand', '\\WebFiori\\Framework\\Cli\\Commands\\VersionCommand', - '\\WebFiori\\Framework\\Cli\\Commands\\SettingsCommand', + '\\WebFiori\\Framework\\Cli\\Commands\\SchedulerCommand', '\\WebFiori\\Framework\\Cli\\Commands\\CreateCommand', '\\WebFiori\\Framework\\Cli\\Commands\\AddCommand', '\\WebFiori\\Framework\\Cli\\Commands\\ListRoutesCommand', '\\WebFiori\\Framework\\Cli\\Commands\\ListThemesCommand', '\\WebFiori\\Framework\\Cli\\Commands\\RunSQLQueryCommand', - '\\WebFiori\\Framework\\Cli\\Commands\\UpdateSettingsCommand', + '\\WebFiori\\Framework\\Cli\\Commands\\UpdateTableCommand', '\\WebFiori\\Framework\\Cli\\Commands\\RunMigrationsCommand', ]; diff --git a/WebFiori/Framework/Cli/Commands/SettingsCommand.php b/WebFiori/Framework/Cli/Commands/SettingsCommand.php deleted file mode 100644 index 181f57a87..000000000 --- a/WebFiori/Framework/Cli/Commands/SettingsCommand.php +++ /dev/null @@ -1,75 +0,0 @@ -println("Framework Version Settings:", $format); - $this->println(" Framework Version %".($spaces - strlen('Framework Version'))."s %s",':',WF_VERSION); - $this->println(" Version Type %".($spaces - strlen('Version Type'))."s %s",':',WF_VERSION_TYPE); - $this->println(" Release Date %".($spaces - strlen('Release Date'))."s %s",':',WF_RELEASE_DATE); - - $this->println("AppConfig.php Settings:", $format); - $this->println(" Application Path %".($spaces - strlen('Application Path'))."s %s",':',APP_PATH); - $this->println(" Application Version %".($spaces - strlen('Application Version'))."s %s",':',$C->getAppVersion()); - $this->println(" Version Type %".($spaces - strlen('Version Type'))."s %s",':',$C->getAppVersionType()); - $this->println(" Application Release Date %".($spaces - strlen('Application Release Date'))."s %s",':',$C->getAppReleaseDate()); - $this->println(" Base CLI URL %".($spaces - strlen('Base CLI URL'))."s %s",':',$C->getBaseURL()); - $this->println(" Base Theme %".($spaces - strlen('Base Theme'))."s %s",':',$C->getTheme()); - $this->println(" Title Separator %".($spaces - strlen('Title Separator'))."s %s",':',$C->getTitleSeparator()); - $this->println(" Home Page %".($spaces - strlen('Home Page'))."s %s",':',$C->getHomePage()); - $this->println(" Website Names:",':'); - $names = $C->getAppNames(); - - foreach ($names as $langCode => $name) { - $this->println(" $langCode => $name"); - } - $this->println(" Website Descriptions:",':'); - - foreach ($C->getDescriptions() as $langCode => $desc) { - $this->println(" $langCode => $desc"); - } - - $this->println(" Pages Titles:",':'); - - foreach ($C->getTitles() as $langCode => $title) { - $this->println(" $langCode => $title"); - } - - return 0; - } -} diff --git a/WebFiori/Framework/Cli/Commands/UpdateSettingsCommand.php b/WebFiori/Framework/Cli/Commands/UpdateSettingsCommand.php deleted file mode 100644 index e18f49122..000000000 --- a/WebFiori/Framework/Cli/Commands/UpdateSettingsCommand.php +++ /dev/null @@ -1,213 +0,0 @@ -addOption($options,'version', 'Update application version info.'); - $this->addOption($options,'app-name', 'Update application name.'); - $this->addOption($options,'scheduler-pass', 'Update scheduler password.'); - $this->addOption($options,'page-title', 'Update default page title.'); - $this->addOption($options,'page-description', 'Update default page description.'); - $this->addOption($options,'primary-lang', 'Change primary language.'); - $this->addOption($options,'title-sep', 'Change title separator.'); - $this->addOption($options,'home-page', 'Set home page.'); - $this->addOption($options,'theme', 'Set primay theme.'); - $this->addOption($options,'q', 'Quit.'); - - $what = $this->getArgValue('--w'); - $answer = null; - - if ($what !== null) { - $answer = isset($options[$what]) ? $options[$what] : null; - - if ($answer === null) { - $this->warning('The argument --w has invalid value.'); - } - } - - - - if ($answer === null) { - $answer = $this->select('What would you like to update?', $options, count($options) - 1); - } - - if ($answer == 'Quit.') { - return 0; - } else if ($answer == 'Update application name.') { - $this->updateName(); - } else if ($answer == 'Update default page title.') { - $this->updateTitle(); - } else if ($answer == 'Update scheduler password.') { - $this->updateSchedulerPass(); - } else if ($answer == 'Change title separator.') { - $this->updateTitleSep(); - } else if ($answer == 'Update default page description.') { - $this->updateDescription(); - } else if ($answer == 'Change primary language.') { - $this->updatePrimaryLang(); - } else if ($answer == 'Set primay theme.') { - $this->setAdminTheme(); - } else if ($answer == 'Set home page.') { - $this->setHome(); - } else if ($answer == 'Update application version info.') { - $this->updateVersionInfo(); - } - - return 0; - } - private function addOption(&$optArr, $key, $txt) { - $optArr[$key] = $txt; - } - private function getThemeNs() { - return $this->getInput('Enter theme class name with namespace:', null, new InputValidator(function ($themeNs) - { - if (!class_exists($themeNs)) { - return false; - } - try { - $instance = new $themeNs(); - - if ($instance instanceof Theme) { - return true; - } - - return false; - } catch (Throwable $exc) { - return false; - } - })); - } - private function setAdminTheme() { - $classNs = $this->getThemeNs(); - Controller::getDriver()->setTheme($classNs); - $this->success('Theme successfully updated.'); - } - private function setHome() { - $routes = array_keys(Router::routes()); - - if (count($routes) == 0) { - $this->info('Router has no routes. Nothing to change.'); - - return; - } - $home = $this->select('Select home page route:', $routes); - Controller::getDriver()->setHomePage(substr($home, strlen(Router::base()) + 1)); - $this->success('Home page successfully updated.'); - } - private function updateDescription() { - $lang = $this->whichLang(); - $newName = $this->getInput('Enter new description:', null, new InputValidator(function ($val) - { - return strlen(trim($val)) != 0; - })); - Controller::getDriver()->setDescription($newName, $lang); - $this->success('Description successfully updated.'); - } - private function updateName() { - $lang = $this->whichLang(); - $newName = $this->getInput('Enter new name:', null, new InputValidator(function ($val) - { - return strlen(trim($val)) != 0; - })); - Controller::getDriver()->setAppName($newName, $lang); - $this->println('Name successfully updated.'); - } - private function updatePrimaryLang() { - $langs = array_keys(App::getConfig()->getAppNames()); - $newPrimary = $this->select('Select new primary language:', $langs); - Controller::getDriver()->setPrimaryLanguage($newPrimary); - $this->success('Primary language successfully updated.'); - } - private function updateSchedulerPass() { - $newPass = $this->getInput('Enter new password:', null, new InputValidator(function (string $val) - { - return strlen(trim($val)) != 0; - }, 'Empty string is not allowed.')); - - Controller::getDriver()->setSchedulerPassword(hash('sha256',$newPass)); - $this->success('Password successfully updated.'); - } - private function updateTitle() { - $lang = $this->whichLang(); - $newName = $this->getInput('Enter new title:', null, new InputValidator(function ($val) - { - return strlen(trim($val)) != 0; - })); - Controller::getDriver()->setTitle($newName, $lang); - $this->success('Title successfully updated.'); - } - private function updateTitleSep() { - $newSep = $this->getInput('Enter new title separator string:', '|', new InputValidator(function ($val) - { - return strlen(trim($val)) != 0; - })); - Controller::getDriver()->setTitleSeparator($newSep); - $this->success('Title separator successfully updated.'); - } - private function updateVersionInfo() { - $versionNum = $this->getInput('Application version:', App::getConfig()->getAppVersion(), new InputValidator(function ($val) - { - return strlen(trim($val)) != 0; - })); - $versionType = $this->getInput('Application version type:', App::getConfig()->getAppVersionType(), new InputValidator(function ($val) - { - return strlen(trim($val)) != 0; - })); - $versionReleaseDate = $this->getInput('Release date (YYYY-MM-DD):', date('Y-m-d'), new InputValidator(function ($val) - { - $expl = explode('-', $val); - - if (count($expl) != 3) { - return false; - } - - return intval($expl[0]) > 0 - && intval($expl[0]) < 10000 - && intval($expl[1]) > 0 - && intval($expl[1]) < 13 - && intval($expl[2]) > 0 - && intval($expl[2]) < 32; - })); - Controller::getDriver()->setAppVersion($versionNum, $versionType, date('Y-m-d', strtotime($versionReleaseDate))); - $this->println('Version information successfully updated.'); - } - private function whichLang() { - $langs = array_keys(App::getConfig()->getAppNames()); - - return $this->select('In which language you would like to update?', $langs); - } -} diff --git a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php index 917064faf..61fec5df9 100644 --- a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php @@ -17,18 +17,18 @@ public function test00() { "Global Arguments:\n", " --ansi:[Optional] Force the use of ANSI output.\n", "Available Commands:\n", - " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", - " v: Display framework version info.\n", - " show-settings: Display application configuration.\n", - " scheduler: Run tasks scheduler.\n", - " create: Creates a system entity (middleware, web service, background process ...).\n", - " add: Add a database connection or SMTP account.\n", - " list-routes: List all created routes and which resource they point to.\n", - " list-themes: List all registered themes.\n", - " run-query: Execute SQL query on specific database.\n", - " update-settings: Update application settings which are stored in specific configuration driver.\n", - " update-table: Update a database table.\n", - " migrations: Execute database migrations.\n", + " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", + " v: Display framework version info.\n", + + " scheduler: Run tasks scheduler.\n", + " create: Creates a system entity (middleware, web service, background process ...).\n", + " add: Add a database connection or SMTP account.\n", + " list-routes: List all created routes and which resource they point to.\n", + " list-themes: List all registered themes.\n", + " run-query: Execute SQL query on specific database.\n", + + " update-table: Update a database table.\n", + " migrations: Execute database migrations.\n", ], $this->executeMultiCommand([ 'help', ])); diff --git a/tests/WebFiori/Framework/Tests/Cli/SettingsCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/SettingsCommandTest.php deleted file mode 100644 index 1ffe500b8..000000000 --- a/tests/WebFiori/Framework/Tests/Cli/SettingsCommandTest.php +++ /dev/null @@ -1,50 +0,0 @@ -remove(); - App::getConfig()->initialize(true); - $runner = App::getRunner(); - $runner->setInputs(); - $runner->setArgsVector([ - 'WebFiori', - 'show-settings' - ]); - $runner->start(); - $config = App::getConfig(); - $this->assertEquals([ - "Framework Version Settings:\n", - " Framework Version : ".WF_VERSION."\n", - " Version Type : ".WF_VERSION_TYPE."\n", - " Release Date : ".WF_RELEASE_DATE."\n", - "AppConfig.php Settings:\n", - " Application Path : ".APP_PATH."\n", - " Application Version : ".$config->getAppVersion()."\n", - " Version Type : ".$config->getAppVersionType()."\n", - " Application Release Date : ".$config->getAppReleaseDate()."\n", - " Base CLI URL : ".$config->getBaseURL()."\n", - " Base Theme : ".$config->getTheme()."\n", - " Title Separator : ".$config->getTitleSeparator()."\n", - " Home Page : ".$config->getHomePage()."\n", - " Website Names:\n", - " AR => تطبيق\n", - " EN => Application\n", - " Website Descriptions:\n", - " AR => \n", - " EN => \n", - " Pages Titles:\n", - " AR => افتراضي\n", - " EN => Default\n", - - ], $runner->getOutput()); - } -} diff --git a/tests/WebFiori/Framework/Tests/Cli/UpdateSettingsCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/UpdateSettingsCommandTest.php deleted file mode 100644 index 43538d969..000000000 --- a/tests/WebFiori/Framework/Tests/Cli/UpdateSettingsCommandTest.php +++ /dev/null @@ -1,490 +0,0 @@ -remove(); - JsonDriver::setConfigFileName('app-config.json'); - App::getConfig()->initialize(true); - $runner = App::getRunner(); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'q' - ]); - $runner->setInputs([]); - - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - ], $runner->getOutput()); - } - - /** - * @test - */ - public function testUpdateAppName00() { - $runner = App::getRunner(); - $runner->setInputs([ - 'EN', - 'Super App', - ]); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'app-name' - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Enter new name:\n", - "Name successfully updated.\n", - ], $runner->getOutput()); - - $this->assertEquals('Super App', Controller::getDriver()->getAppName('EN')); - } - /** - * @test - */ - public function testUpdateAppName01() { - $runner = App::getRunner(); - $runner->setInputs([ - '', - 'XC', - '0', - 'Super App', - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'app-name' - ]); - $exitCode = $runner->start(); - - //$this->assertEquals(0, $exitCode); - $this->assertEquals([ - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Error: Invalid answer.\n", - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Error: Invalid answer.\n", - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Enter new name:\n", - "Name successfully updated.\n", - ], $runner->getOutput()); - } - /** - * @test - */ - public function testUpdateAppName02() { - $runner = App::getRunner(); - $runner->setInputs([ - '0', - '', - ' ', - ' Super App X ' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'app-name' - ]); - - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Enter new name:\n", - "Error: Invalid input is given. Try again.\n", - "Enter new name:\n", - "Error: Invalid input is given. Try again.\n", - "Enter new name:\n", - "Name successfully updated.\n", - ], $runner->getOutput()); - $this->assertEquals('Super App X', Controller::getDriver()->getAppName('AR')); - } - /** - * @test - */ - public function testUpdateHomePage00() { - $runner = App::getRunner(); - $runner->setInputs(); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'home-page' - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Info: Router has no routes. Nothing to change.\n", - ], $runner->getOutput()); - } - /** - * @test - */ - public function testUpdateHomePage01() { - Router::page([ - 'path' => 'x/y/z', - 'route-to' => 'test.txt' - ]); - $runner = App::getRunner(); - $runner->setInputs([ - '0' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'home-page' - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Select home page route:\n", - "0: https://127.0.0.1/x/y/z\n", - "Success: Home page successfully updated.\n", - ], $runner->getOutput()); - $this->assertEquals('x/y/z', Controller::getDriver()->getHomePage()); - } - /** - * @test - */ - public function testUpdatePageDescription00() { - $runner = App::getRunner(); - $runner->setInputs([ - 'EN', - 'NEW PAGE DESCRIPTION' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'page-description' - ]); - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Enter new description:\n", - "Success: Description successfully updated.\n" - ], $runner->getOutput()); - - $this->assertEquals('NEW PAGE DESCRIPTION', App::getConfig()->getDescription('EN')); - } - /** - * @test - */ - public function testUpdatePageTitle00() { - $runner = App::getRunner(); - $runner->setInputs([ - 'EN', - 'NEW PAGE' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'page-title' - ]); - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Enter new title:\n", - "Success: Title successfully updated.\n" - ], $runner->getOutput()); - - $this->assertEquals('NEW PAGE', App::getConfig()->getTitle('EN')); - } - public function testUpdatePrimaryLang() { - $runner = App::getRunner(); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'primary-lang' - ]); - $runner->setInputs(['0']); - $runner->start(); - //$this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Select new primary language:\n", - "0: AR\n", - "1: EN\n", - "Success: Primary language successfully updated.\n" - ], $runner->getOutput()); - $this->assertEquals('AR', Controller::getDriver()->getPrimaryLanguage()); - } - /** - * @test - */ - public function testUpdatePrimaryLang00() { - $runner = App::getRunner(); - $runner->setInputs([ - 'EN', - 'NEW PAGE DESCRIPTION' - ]); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'page-description' - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "In which language you would like to update?\n", - "0: AR\n", - "1: EN\n", - "Enter new description:\n", - "Success: Description successfully updated.\n" - ], $runner->getOutput()); - $this->assertEquals('NEW PAGE DESCRIPTION', App::getConfig()->getDescription('EN')); - } - /** - * @test - */ - public function testUpdatePrimaryTheme00() { - $runner = App::getRunner(); - $runner->setInputs([ - 'Themes\\FioriTheme2\\NewTestTheme2' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'theme' - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Enter theme class name with namespace:\n", - "Success: Theme successfully updated.\n" - ], $runner->getOutput()); - - $this->assertEquals('Themes\\FioriTheme2\\NewTestTheme2', App::getConfig()->getTheme()); - } - /** - * @test - */ - public function testUpdatePrimaryTheme01() { - $runner = App::getRunner(); - $runner->setInputs([ - 'themes\\greeny\\NotATheme', - '', - 'Themes\\FioriTheme2\\NewTestTheme2' - ]); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'theme' - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Enter theme class name with namespace:\n", - "Error: Invalid input is given. Try again.\n", - "Enter theme class name with namespace:\n", - "Error: Invalid input is given. Try again.\n", - "Enter theme class name with namespace:\n", - "Success: Theme successfully updated.\n" - ], $runner->getOutput()); - - $this->assertEquals('Themes\\FioriTheme2\\NewTestTheme2', App::getConfig()->getTheme()); - } - /** - * @test - */ - public function testUpdatePrimaryTheme02() { - $runner = App::getRunner(); - $runner->setInputs([ - 'WebFiori\\Framework\\Privilege', - 'Themes\\FioriTheme2\\NewTestTheme2' - ]); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'theme' - ]); - $runner->start(); - //$this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Enter theme class name with namespace:\n", - "Error: Invalid input is given. Try again.\n", - "Enter theme class name with namespace:\n", - "Success: Theme successfully updated.\n" - ], $runner->getOutput()); - - $this->assertEquals('Themes\\FioriTheme2\\NewTestTheme2', App::getConfig()->getTheme()); - } - /** - * @test - */ - public function testUpdatePrimaryTheme03() { - $runner = App::getRunner(); - $runner->setInputs([ - 'WebFiori\\Framework\\App', - 'Themes\\FioriTheme2\\NewTestTheme2' - ]); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'theme' - ]); - $runner->start(); - //$this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Enter theme class name with namespace:\n", - "Error: Invalid input is given. Try again.\n", - "Enter theme class name with namespace:\n", - "Success: Theme successfully updated.\n" - ], $runner->getOutput()); - - $this->assertEquals('Themes\\FioriTheme2\\NewTestTheme2', App::getConfig()->getTheme()); - } - /** - * @test - */ - public function testUpdateSchedulerPass00() { - $runner = App::getRunner(); - $runner->setInputs([ - '123456' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'scheduler-pass', - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Enter new password:\n", - "Success: Password successfully updated.\n" - ], $runner->getOutput()); - $this->assertEquals(hash('sha256', '123456'), App::getConfig()->getSchedulerPassword()); - } - /** - * @test - */ - public function testUpdateSchedulerPass01() { - $runner = App::getRunner(); - $runner->setInputs([ - '', - '123' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'scheduler-pass', - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Enter new password:\n", - "Error: Empty string is not allowed.\n", - "Enter new password:\n", - "Success: Password successfully updated.\n" - ], $runner->getOutput()); - $this->assertEquals(hash('sha256', '123'), App::getConfig()->getSchedulerPassword()); - } - /** - * @test - */ - public function testUpdateTitleSep00() { - $runner = App::getRunner(); - $runner->setInputs([ - '6', - '+-+' - ]); - - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'xyz' - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - "Warning: The argument --w has invalid value.\n", - "What would you like to update?\n", - "0: Update application version info.\n", - "1: Update application name.\n", - "2: Update scheduler password.\n", - "3: Update default page title.\n", - "4: Update default page description.\n", - "5: Change primary language.\n", - "6: Change title separator.\n", - "7: Set home page.\n", - "8: Set primay theme.\n", - "9: Quit. <--\n", - "Enter new title separator string: Enter = '|'\n", - "Success: Title separator successfully updated.\n" - ], $runner->getOutput()); - $this->assertEquals('+-+', Controller::getDriver()->getTitleSeparator()); - } - /** - * @test - */ - public function testUpdateVersion00() { - $runner = App::getRunner(); - $runner->setArgsVector([ - 'WebFiori', - 'update-settings', - '--w' => 'version' - ]); - $runner->setInputs([ - '2.0.1', - 'Beta', - '99', - '99-99-99', - ' ', - ]); - - $this->assertEquals(0, $runner->start()); - $this->assertEquals([ - - "Application version: Enter = '1.0'\n", - "Application version type: Enter = 'Stable'\n", - "Release date (YYYY-MM-DD): Enter = '".date('Y-m-d')."'\n", - "Error: Invalid input is given. Try again.\n", - "Release date (YYYY-MM-DD): Enter = '".date('Y-m-d')."'\n", - "Error: Invalid input is given. Try again.\n", - "Release date (YYYY-MM-DD): Enter = '".date('Y-m-d')."'\n", - "Version information successfully updated.\n" - ], $runner->getOutput()); - - $this->assertEquals('2.0.1', App::getConfig()->getAppVersion()); - $this->assertEquals('Beta', App::getConfig()->getAppVersionType()); - $this->assertEquals(date('Y-m-d'), App::getConfig()->getAppReleaseDate()); - } -} From 69cc5a2d3f1342f26488113d5b3d3ec37a5d3365 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 10 Nov 2025 23:30:13 +0300 Subject: [PATCH 03/25] refactor: Removal of the Command `ListRoutes` --- WebFiori/Framework/App.php | 2 +- .../Cli/Commands/ListRoutesCommand.php | 56 ------------------- .../Framework/Tests/Cli/HelpCommandTest.php | 2 +- .../Tests/Cli/ListRoutesCommandTest.php | 55 ------------------ 4 files changed, 2 insertions(+), 113 deletions(-) delete mode 100644 WebFiori/Framework/Cli/Commands/ListRoutesCommand.php delete mode 100644 tests/WebFiori/Framework/Tests/Cli/ListRoutesCommandTest.php diff --git a/WebFiori/Framework/App.php b/WebFiori/Framework/App.php index 2dad1fae6..52ec2324f 100644 --- a/WebFiori/Framework/App.php +++ b/WebFiori/Framework/App.php @@ -427,7 +427,7 @@ public static function getRunner() : Runner { '\\WebFiori\\Framework\\Cli\\Commands\\SchedulerCommand', '\\WebFiori\\Framework\\Cli\\Commands\\CreateCommand', '\\WebFiori\\Framework\\Cli\\Commands\\AddCommand', - '\\WebFiori\\Framework\\Cli\\Commands\\ListRoutesCommand', + '\\WebFiori\\Framework\\Cli\\Commands\\ListThemesCommand', '\\WebFiori\\Framework\\Cli\\Commands\\RunSQLQueryCommand', diff --git a/WebFiori/Framework/Cli/Commands/ListRoutesCommand.php b/WebFiori/Framework/Cli/Commands/ListRoutesCommand.php deleted file mode 100644 index 7bd0db0ec..000000000 --- a/WebFiori/Framework/Cli/Commands/ListRoutesCommand.php +++ /dev/null @@ -1,56 +0,0 @@ - $routeTo) { - $len = strlen($requestedUrl); - - if ($len > $maxRouteLen) { - $maxRouteLen = $len; - } - } - $maxRouteLen += 4; - - foreach ($routesArr as $requestedUrl => $routeTo) { - $location = $maxRouteLen - strlen($requestedUrl); - $this->println("$requestedUrl %".$location."s $routeTo"," => "); - } - - return 0; - } -} diff --git a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php index 61fec5df9..394dff4ff 100644 --- a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php @@ -23,7 +23,7 @@ public function test00() { " scheduler: Run tasks scheduler.\n", " create: Creates a system entity (middleware, web service, background process ...).\n", " add: Add a database connection or SMTP account.\n", - " list-routes: List all created routes and which resource they point to.\n", + " list-themes: List all registered themes.\n", " run-query: Execute SQL query on specific database.\n", diff --git a/tests/WebFiori/Framework/Tests/Cli/ListRoutesCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/ListRoutesCommandTest.php deleted file mode 100644 index bb6efee5e..000000000 --- a/tests/WebFiori/Framework/Tests/Cli/ListRoutesCommandTest.php +++ /dev/null @@ -1,55 +0,0 @@ -setInputs(); - $runner->setArgsVector([ - 'WebFiori', - 'list-routes' - ]); - $runner->start(); - $this->assertEquals([ - - ], $runner->getOutput()); - } - /** - * @test - */ - public function test01() { - $runner = App::getRunner(); - $runner->setInputs(); - $runner->setArgsVector([ - 'WebFiori', - 'list-routes' - ]); - Router::addRoute([ - 'path' => 'xyz', - 'route-to' => Router::class - ]); - Router::addRoute([ - 'path' => 'xyzb', - 'route-to' => new WebPage() - ]); - $runner->start(); - $this->assertEquals([ - "https://127.0.0.1/xyz => ".Router::class."\n", - "https://127.0.0.1/xyzb => ".WebPage::class."\n" - ], $runner->getOutput()); - Router::removeAll(); - } -} From d64ff59937954de1425bd8e620aa34b6bc040bab Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 10 Nov 2025 23:32:33 +0300 Subject: [PATCH 04/25] refactor: Removal of `ListThemesCommand` --- WebFiori/Framework/App.php | 2 +- .../Cli/Commands/ListThemesCommand.php | 100 ------------------ .../Framework/Tests/Cli/HelpCommandTest.php | 2 +- .../Tests/Cli/ListThemesCommandTest.php | 66 ------------ 4 files changed, 2 insertions(+), 168 deletions(-) delete mode 100644 WebFiori/Framework/Cli/Commands/ListThemesCommand.php delete mode 100644 tests/WebFiori/Framework/Tests/Cli/ListThemesCommandTest.php diff --git a/WebFiori/Framework/App.php b/WebFiori/Framework/App.php index 52ec2324f..70bf213a8 100644 --- a/WebFiori/Framework/App.php +++ b/WebFiori/Framework/App.php @@ -428,7 +428,7 @@ public static function getRunner() : Runner { '\\WebFiori\\Framework\\Cli\\Commands\\CreateCommand', '\\WebFiori\\Framework\\Cli\\Commands\\AddCommand', - '\\WebFiori\\Framework\\Cli\\Commands\\ListThemesCommand', + '\\WebFiori\\Framework\\Cli\\Commands\\RunSQLQueryCommand', '\\WebFiori\\Framework\\Cli\\Commands\\UpdateTableCommand', diff --git a/WebFiori/Framework/Cli/Commands/ListThemesCommand.php b/WebFiori/Framework/Cli/Commands/ListThemesCommand.php deleted file mode 100644 index f3ad23b6a..000000000 --- a/WebFiori/Framework/Cli/Commands/ListThemesCommand.php +++ /dev/null @@ -1,100 +0,0 @@ - - *
  • theme-name: If specified, only information about given theme - * will be shown.
  • - * - */ - public function __construct() { - parent::__construct('list-themes', [ - new Argument('--theme-name', 'An optional theme name. If provided, only given theme information will be shown.', true) - ], 'List all registered themes.'); - } - /** - * Execute the command. - * @return int If the command executed without any errors, the - * method will return 0. Other than that, it will return false. - * @since 1.0 - */ - public function exec() : int { - $themesArr = ThemeManager::getRegisteredThemes(); - - $themsCount = count($themesArr); - $themeName = $this->getArgValue('--theme-name'); - - $index = 1; - - if ($themeName === null) { - $this->println("Total Number of Themes: $themsCount ."); - - foreach ($themesArr as $themeObj) { - $number = $index < 10 ? '0'.$index : $index; - - $this->println("--------- Theme #$number ---------\n", [ - 'color' => 'light-blue', - 'bold' => true - ]); - $this->printThemeObj($themeObj); - $index++; - } - - return 0; - } - - if (!isset($themesArr[$themeName])) { - $this->error("No theme was registered which has the name '$themeName'."); - - return -1; - } - $this->printThemeObj($themesArr[$themeName]); - - return 0; - } - private function isSet($var) { - if (strlen($var) == 0) { - return ''; - } - - return $var; - } - - private function printThemeObj($themeObj) { - $spaceSize = 15; - $len00 = $spaceSize - strlen('Theme Name'); - $len01 = $spaceSize - strlen('Author'); - $len02 = $spaceSize - strlen('Author URL'); - $len03 = $spaceSize - strlen('License'); - $len04 = $spaceSize - strlen('License URL'); - - $this->println("Theme Name: %".$len00."s %s",':', $this->isSet($themeObj->getName())); - $this->println("Author: %".$len01."s %s",':', $this->isSet($themeObj->getAuthor())); - $this->println("Author URL: %".$len02."s %s",':', $this->isSet($themeObj->getAuthorUrl())); - $this->println("License: %".$len03."s %s",':', $this->isSet($themeObj->getLicenseName())); - $this->println("License URL: %".$len04."s %s",':', $this->isSet($themeObj->getLicenseUrl())); - $this->println("Theme Desription: %s", $this->isSet($themeObj->getDescription())); - } -} diff --git a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php index 394dff4ff..5245d32ee 100644 --- a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php @@ -24,7 +24,7 @@ public function test00() { " create: Creates a system entity (middleware, web service, background process ...).\n", " add: Add a database connection or SMTP account.\n", - " list-themes: List all registered themes.\n", + " run-query: Execute SQL query on specific database.\n", " update-table: Update a database table.\n", diff --git a/tests/WebFiori/Framework/Tests/Cli/ListThemesCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/ListThemesCommandTest.php deleted file mode 100644 index 53357ae3b..000000000 --- a/tests/WebFiori/Framework/Tests/Cli/ListThemesCommandTest.php +++ /dev/null @@ -1,66 +0,0 @@ -setInputs(); - $runner->setArgsVector([ - 'WebFiori', - 'list-themes' - ]); - $runner->start(); - $output = $runner->getOutput(); - $this->assertContains("Total Number of Themes: 2 .\n", $output); - $this->assertContains("Theme Name: : New Super Theme\n", $output); - $this->assertContains("Theme Name: : New Theme 2\n", $output); - } - /** - * @test - */ - public function test01() { - $runner = App::getRunner(); - $runner->setInputs(); - $runner->setArgsVector([ - 'WebFiori', - 'list-themes', - '--theme-name' => "New Super Theme" - ]); - $runner->start(); - $this->assertEquals([ - "Theme Name: : New Super Theme\n", - "Author: : \n", - "Author URL: : \n", - "License: : \n", - "License URL: : \n", - "Theme Desription: \n", - ], $runner->getOutput()); - } - /** - * @test - */ - public function test02() { - $runner = App::getRunner(); - $runner->setInputs(); - $runner->setArgsVector([ - 'WebFiori', - 'list-themes', - '--theme-name="Not Exist"' - ]); - $runner->start(); - $this->assertEquals([ - "Error: No theme was registered which has the name 'Not Exist'.\n", - ], $runner->getOutput()); - } -} From aeb768824296a85c73802ed869d74397353eb815 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 10 Nov 2025 23:37:00 +0300 Subject: [PATCH 05/25] refactor: Removal of the Class `RunSQLCommand` --- WebFiori/Framework/App.php | 2 +- .../Cli/Commands/RunSQLQueryCommand.php | 318 ------------------ .../Framework/Tests/Cli/HelpCommandTest.php | 2 +- .../Framework/Tests/Cli/RunSQLCommandTest.php | 163 --------- 4 files changed, 2 insertions(+), 483 deletions(-) delete mode 100644 WebFiori/Framework/Cli/Commands/RunSQLQueryCommand.php delete mode 100644 tests/WebFiori/Framework/Tests/Cli/RunSQLCommandTest.php diff --git a/WebFiori/Framework/App.php b/WebFiori/Framework/App.php index 70bf213a8..9a3df81e0 100644 --- a/WebFiori/Framework/App.php +++ b/WebFiori/Framework/App.php @@ -429,7 +429,7 @@ public static function getRunner() : Runner { '\\WebFiori\\Framework\\Cli\\Commands\\AddCommand', - '\\WebFiori\\Framework\\Cli\\Commands\\RunSQLQueryCommand', + '\\WebFiori\\Framework\\Cli\\Commands\\UpdateTableCommand', '\\WebFiori\\Framework\\Cli\\Commands\\RunMigrationsCommand', diff --git a/WebFiori/Framework/Cli/Commands/RunSQLQueryCommand.php b/WebFiori/Framework/Cli/Commands/RunSQLQueryCommand.php deleted file mode 100644 index da514fda4..000000000 --- a/WebFiori/Framework/Cli/Commands/RunSQLQueryCommand.php +++ /dev/null @@ -1,318 +0,0 @@ -getDBConnections()); - $schema = $this->getArgValue('--schema'); - - if (count($dbConnections) != 0) { - if ($schema !== null) { - if (class_exists($schema)) { - return $this->schemaBased($schema); - } else { - $this->warning('Schema not found: '.$schema); - - return $this->connectionBased($dbConnections); - } - } else { - return $this->connectionBased($dbConnections); - } - } else { - $this->error('No database connections available. Add connections to application configuration or use the command "add".'); - - return -1; - } - } - /** - * - * @param type $schema - * @param type $selectedQuery - * @param type $colsKeys - * @param Table $tableObj - */ - private function colQuery(&$schema, $selectedQuery, $colsKeys, $tableObj) { - $selectedCol = $this->select('Select the column:', $colsKeys); - - if ($selectedQuery == 'Add Column.') { - $schema->table($tableObj->getNormalName())->addCol($selectedCol); - } else if ($selectedQuery == 'Modify Column.') { - $schema->table($tableObj->getNormalName())->modifyCol($selectedCol); - } else if ($selectedQuery == 'Drop Column.') { - $schema->table($tableObj->getNormalName())->dropCol($selectedCol); - } - } - private function confirmExecute(Database $schema) { - $noConfirmExec = $this->isArgProvided('--no-confirm'); - $dbName = $schema->getConnectionInfo()->getDBName(); - - if ($this->isArgProvided('--show-sql') || !$noConfirmExec) { - $this->println("The following query will be executed on the database '$dbName':"); - $this->println($schema->getLastQuery(), [ - 'color' => 'blue' - ]); - } - - if ($noConfirmExec) { - return $this->executeQ($schema); - } - - if ($this->confirm('Continue?', true)) { - return $this->executeQ($schema); - } else { - $this->info('Nothing to execute.'); - - return 0; - } - } - private function connectionBased($dbConnections) : int { - $connName = $this->getArgValue('--connection'); - $file = $this->getArgValue('--file'); - - if ($connName === null) { - $connName = $this->select('Select database connection:', $dbConnections, 0); - } else if (!in_array($connName, $dbConnections)) { - $this->error('No connection with name "'.$connName.'" was found!'); - - return -1; - } - $schema = new DB($connName); - - if ($file !== null) { - $fileObj = new File(ROOT_PATH.DS.$file); - - if (!$fileObj->isExist()) { - $fileObj = new File($file); - } - - if ($fileObj->isExist()) { - $fileObj->read(); - $mime = $fileObj->getMIME(); - - if ($mime == 'application/sql' || $mime == 'application/x-sql') { - return $this->runFileQuery($schema, $fileObj); - } else { - $this->error('Provided file is not SQL file!'); - - return -1; - } - } else { - $path = $fileObj->getAbsolutePath(); - - if (strlen($path) == 0) { - $path = $file; - } - $this->error('No such file: '.$path); - - return -1; - } - } - - - return $this->generalQuery($schema); - } - private function executeQ(DB $schema) { - $this->info('Executing query on database '.$schema->getConnectionInfo()->getDBName().'...'); - try { - $schema->execute(); - $this->success('Query executed without errors.'); - - return 0; - } catch (DatabaseException $ex) { - $this->error($ex->getMessage()); - - return $ex->getCode(); - } - } - private function fkQuery($schema, $selectedQuery, Table $tableObj) { - $keys = $tableObj->getForeignKeys(); - $keysNamesArr = []; - - foreach ($keys as $fkObj) { - $keysNamesArr[] = $fkObj->getName(); - } - $fkName = $this->select('Select the forign key:', $keysNamesArr); - - if ($selectedQuery == 'Add Forign Key.') { - $schema->table($tableObj->getNormalName())->addForeignKey($fkName); - } else { - $schema->table($tableObj->getNormalName())->dropForeignKey($fkName); - } - } - private function generalQuery(DB $schema) { - $options = [ - 'Run general query.', - 'Run query on table instance.', - 'Run query from file.' - ]; - $selected = $this->select('What type of query you would like to run?', $options); - - if ($selected == 'Run general query.') { - $query = $this->getInput('Please type in SQL query:'); - $schema->setQuery($query); - - return $this->confirmExecute($schema); - } else if ($selected == 'Run query on table instance.') { - $tableObj = CLIUtils::readTable($this); - - $schema->addTable($tableObj); - - return $this->tableQuery($schema, $tableObj); - } else if ($selected == 'Run query from file.') { - return $this->queryFromFile($schema); - } - } - private function queryFromFile($schema) { - $filePath = ''; - $file = null; - - while (!File::isFileExist($filePath)) { - $filePath = $this->getInput('File path:'); - $modified = ROOT_PATH.DS.$filePath; - - if (File::isFileExist($modified)) { - $filePath = $modified; - } - - if (File::isFileExist($filePath)) { - $file = new File($filePath); - $file->read(); - $mime = $file->getMIME(); - - if ($mime == 'application/sql' || $mime == 'application/x-sql') { - break; - } else { - $this->error('Provided file is not SQL file!'); - } - } else { - $this->error('No such file: '.$filePath); - } - } - - return $this->runFileQuery($schema, $file); - } - - private function queryOnSchema(DB $schema) { - if ($this->isArgProvided('--create')) { - $schema->createTables(); - - return $this->confirmExecute($schema); - } - $options = [ - 'Create Database.', - 'Run Query on Specific Table.' - ]; - $selected = $this->select('Select an option:', $options); - - if ($selected == 'Create Database.') { - $schema->createTables(); - - return $this->confirmExecute($schema); - } else { - $selectedTable = $this->select('Select database table:', array_keys($schema->getTables())); - - return $this->tableQuery($schema, $schema->getTable($selectedTable)); - } - } - private function runFileQuery(DB $schema, File $f) : int { - $schema->setQuery($f->getRawData()); - - return $this->confirmExecute($schema); - } - private function schemaBased($schema) { - $schemaInst = new $schema(); - - if ($schemaInst instanceof DB) { - return $this->queryOnSchema($schemaInst); - } else { - $this->error('Given class is not an instance of "WebFiori\\Framework\\DB"!'); - - return -1; - } - } - /** - * - * @param DB $schema - * @param Table $tableObj - */ - private function tableQuery($schema, $tableObj) { - if ($this->isArgProvided('--create')) { - $schema->table($tableObj->getNormalName())->createTable(); - - return $this->confirmExecute($schema); - } - $queryTypes = [ - 'Create database table.', - 'Drop database table.', - 'Drop and create table.', - 'Add Column.', - 'Modify Column.', - 'Drop Column.' - ]; - - if ($tableObj->getForeignKeysCount() != 0) { - $queryTypes[] = 'Add Forign Key.'; - $queryTypes[] = 'Drop Forign Key.'; - } - $selectedQuery = $this->select('Select query type:', $queryTypes); - - if ($selectedQuery == 'Add Column.' || $selectedQuery == 'Modify Column.' || $selectedQuery == 'Drop Column.') { - $this->colQuery($schema, $selectedQuery, $tableObj->getColsKeys(), $tableObj); - } else if ($selectedQuery == 'Add Forign Key.' || $selectedQuery == 'Drop Forign Key.') { - $this->fkQuery($schema, $selectedQuery, $tableObj); - } else if ($selectedQuery == 'Create database table.') { - $schema->table($tableObj->getNormalName())->createTable(); - } else if ($selectedQuery == 'Drop database table.') { - $schema->table($tableObj->getNormalName())->drop(); - } else if ($selectedQuery == 'Drop and create table.') { - $schema->table($tableObj->getNormalName())->drop(); - $query1 = $schema->getLastQuery(); - $schema->table($tableObj->getNormalName())->createTable(); - $schema->getQueryGenerator()->setQuery($query1."\n".$schema->getLastQuery(), true); - } - - return $this->confirmExecute($schema); - } -} diff --git a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php index 5245d32ee..6ef669037 100644 --- a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php @@ -25,7 +25,7 @@ public function test00() { " add: Add a database connection or SMTP account.\n", - " run-query: Execute SQL query on specific database.\n", + " update-table: Update a database table.\n", " migrations: Execute database migrations.\n", diff --git a/tests/WebFiori/Framework/Tests/Cli/RunSQLCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/RunSQLCommandTest.php deleted file mode 100644 index 30641d498..000000000 --- a/tests/WebFiori/Framework/Tests/Cli/RunSQLCommandTest.php +++ /dev/null @@ -1,163 +0,0 @@ -removeAllDBConnections(); - $conn = new ConnectionInfo('mysql', 'root', '123456', 'testing_db', '127.0.0.1'); - $conn->setName('testing-connection'); - App::getConfig()->addOrUpdateDBConnection($conn); - - $output = $this->executeSingleCommand(new RunSQLQueryCommand(), ['run-query'], [ - '0', - '0', - 'select * from hello;', - 'y' - ]); - - $this->assertEquals(1146, $this->getExitCode()); - $this->assertEquals([ - "Select database connection:\n", - "0: testing-connection <--\n", - "What type of query you would like to run?\n", - "0: Run general query.\n", - "1: Run query on table instance.\n", - "2: Run query from file.\n", - "Please type in SQL query:\n", - "The following query will be executed on the database 'testing_db':\n", - "select * from hello;\n", - "Continue?(Y/n)\n", - "Info: Executing query on database testing_db...\n", - "Error: 1146 - Table 'testing_db.hello' doesn't exist\n" - ], $output); - } - - /** - * @test - */ - public function testCLIQuery01() { - $conn = new ConnectionInfo('mysql', 'root', '123456', 'testing_db', '127.0.0.1'); - $conn->setName('testing-connection'); - App::getConfig()->addOrUpdateDBConnection($conn); - - $output = $this->executeSingleCommand(new RunSQLQueryCommand(), [ - 'run-query', - '--connection' => 'testing-connection', - ], [ - '0', - 'drop table test2_x;', - 'y' - ]); - - $this->assertEquals(1051, $this->getExitCode()); - $this->assertEquals([ - "What type of query you would like to run?\n", - "0: Run general query.\n", - "1: Run query on table instance.\n", - "2: Run query from file.\n", - "Please type in SQL query:\n", - "The following query will be executed on the database 'testing_db':\n", - "drop table test2_x;\n", - "Continue?(Y/n)\n", - "Info: Executing query on database testing_db...\n", - "Error: 1051 - Unknown table 'testing_db.test2_x'\n" - ], $output); - } - - /** - * @test - */ - public function testQueryFromFile00() { - App::getConfig()->removeAllDBConnections(); - - $output = $this->executeSingleCommand(new RunSQLQueryCommand(), [ - 'WebFiori', - 'run-query', - '--connection' => 'testing-connection', - '--no-confirm', - '--file' => 'not-exist' - ], []); - - $this->assertEquals(-1, $this->getExitCode()); - $this->assertEquals([ - 'Error: No database connections available. Add connections to application configuration or use the command "add"'.".\n" - ], $output); - } - - /** - * @test - */ - public function testQueryFromFile01() { - $conn = new ConnectionInfo('mysql', 'root', '123456', 'testing_db', '127.0.0.1'); - $conn->setName('testing-connection'); - App::getConfig()->addOrUpdateDBConnection($conn); - - $output = $this->executeSingleCommand(new RunSQLQueryCommand(), [ - 'WebFiori', - 'run-query', - '--connection' => 'testing-connection', - '--no-confirm', - '--file' => 'not-exist' - ], []); - - $this->assertEquals(-1, $this->getExitCode()); - $this->assertEquals([ - "Error: No such file: not-exist\n" - ], $output); - } - - /** - * @test - */ - public function testQueryFromFile02() { - $conn = new ConnectionInfo('mysql', 'root', '123456', 'testing_db', '127.0.0.1'); - $conn->setName('testing-connection'); - App::getConfig()->addOrUpdateDBConnection($conn); - - $output = $this->executeSingleCommand(new RunSQLQueryCommand(), [ - 'run-query', - '--connection' => 'testing-connection', - '--no-confirm', - '--file' => 'App\\Database\\Test2Table.php' - ], []); - - $this->assertEquals(-1, $this->getExitCode()); - $this->assertEquals([ - "Error: Provided file is not SQL file!\n" - ], $output); - } - - /** - * @test - */ - public function testQueryFromFile03() { - $conn = new ConnectionInfo('mysql', 'root', '123456', 'testing_db', '127.0.0.1'); - $conn->setName('testing-connection'); - App::getConfig()->addOrUpdateDBConnection($conn); - - $output = $this->executeSingleCommand(new RunSQLQueryCommand(), [ - 'run-query', - '--connection' => 'testing-connection', - '--no-confirm', - '--file' => 'App\\Database\\sql-file.sql' - ], []); - - $this->assertEquals(0, $this->getExitCode()); - $this->assertEquals([ - "Info: Executing query on database testing_db...\n", - "Success: Query executed without errors.\n" - ], $output); - } -} From ba1e132731124ccb8c48daf017f1e544467c833c Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 10 Nov 2025 23:54:40 +0300 Subject: [PATCH 06/25] refactor: Removal of `UpdateTable` Command --- WebFiori/Framework/App.php | 2 +- .../Cli/Commands/UpdateTableCommand.php | 69 ------ .../Framework/Tests/Cli/HelpCommandTest.php | 14 +- .../Tests/Cli/UpdateTableCommandTest.php | 205 ------------------ 4 files changed, 8 insertions(+), 282 deletions(-) delete mode 100644 WebFiori/Framework/Cli/Commands/UpdateTableCommand.php delete mode 100644 tests/WebFiori/Framework/Tests/Cli/UpdateTableCommandTest.php diff --git a/WebFiori/Framework/App.php b/WebFiori/Framework/App.php index 9a3df81e0..4d85e38c8 100644 --- a/WebFiori/Framework/App.php +++ b/WebFiori/Framework/App.php @@ -431,7 +431,7 @@ public static function getRunner() : Runner { - '\\WebFiori\\Framework\\Cli\\Commands\\UpdateTableCommand', + '\\WebFiori\\Framework\\Cli\\Commands\\RunMigrationsCommand', ]; diff --git a/WebFiori/Framework/Cli/Commands/UpdateTableCommand.php b/WebFiori/Framework/Cli/Commands/UpdateTableCommand.php deleted file mode 100644 index ad238f16c..000000000 --- a/WebFiori/Framework/Cli/Commands/UpdateTableCommand.php +++ /dev/null @@ -1,69 +0,0 @@ -getWriter()->setTable($tableObj); - $tableHelper = new TableObjHelper($create, $tableObj); - - - - $whatToDo = $this->select('What operation whould you like to do with the table?', [ - 'Add new column.', - 'Add foreign key.', - 'Update existing column.', - 'Drop column.', - 'Drop foreign key.' - ]); - - if ($whatToDo == 'Add new column.') { - $tableHelper->addColumn(); - } else if ($whatToDo == 'Drop column.') { - $tableHelper->dropColumn(); - } else if ($whatToDo == 'Add foreign key.') { - $tableHelper->addForeignKey(); - } else if ($whatToDo == 'Update existing column.') { - $tableHelper->updateColumn(); - } else if ($whatToDo == 'Drop foreign key.') { - $tableHelper->removeForeignKey(); - } - - return 0; - } -} diff --git a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php index 6ef669037..2f3941bbe 100644 --- a/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/HelpCommandTest.php @@ -17,18 +17,18 @@ public function test00() { "Global Arguments:\n", " --ansi:[Optional] Force the use of ANSI output.\n", "Available Commands:\n", - " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", - " v: Display framework version info.\n", + " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", + " v: Display framework version info.\n", - " scheduler: Run tasks scheduler.\n", - " create: Creates a system entity (middleware, web service, background process ...).\n", - " add: Add a database connection or SMTP account.\n", + " scheduler: Run tasks scheduler.\n", + " create: Creates a system entity (middleware, web service, background process ...).\n", + " add: Add a database connection or SMTP account.\n", - " update-table: Update a database table.\n", - " migrations: Execute database migrations.\n", + + " migrations: Execute database migrations.\n", ], $this->executeMultiCommand([ 'help', ])); diff --git a/tests/WebFiori/Framework/Tests/Cli/UpdateTableCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/UpdateTableCommandTest.php deleted file mode 100644 index cfa412ef4..000000000 --- a/tests/WebFiori/Framework/Tests/Cli/UpdateTableCommandTest.php +++ /dev/null @@ -1,205 +0,0 @@ -executeSingleCommand(new UpdateTableCommand(), [ - 'WebFiori', - 'update-table', - ], [ - ' ', // Invalid class name - 'ok\\y\\Super', // Invalid class name - 'App\\Database\\TestTable', - '0', - 'new-col', - '1', - '9', - 'n', - 'n', - "\n", // Hit Enter to pick default value (empty default) - 'n', - 'Cool new column.', - 'y', - 'ModifiedO', - "\n" // Hit Enter to pick default value (App\database) - ]); - - $this->assertEquals(0, $this->getExitCode()); - $this->assertEquals([ - "Enter database table class name (include namespace):\n", - "Error: Class not found.\n", - "Enter database table class name (include namespace):\n", - "Error: Class not found.\n", - "Enter database table class name (include namespace):\n", - "What operation whould you like to do with the table?\n", - "0: Add new column.\n", - "1: Add foreign key.\n", - "2: Update existing column.\n", - "3: Drop column.\n", - "4: Drop foreign key.\n", - "Enter a name for column key:\n", - "Column data type:\n", - "0: mixed <--\n", - "1: int\n", - "2: char\n", - "3: varchar\n", - "4: timestamp\n", - "5: tinyblob\n", - "6: blob\n", - "7: mediumblob\n", - "8: longblob\n", - "9: datetime\n", - "10: text\n", - "11: mediumtext\n", - "12: decimal\n", - "13: double\n", - "14: float\n", - "15: boolean\n", - "16: bool\n", - "17: bit\n", - "Enter column size:\n", - "Is this column primary?(y/N)\n", - "Is this column unique?(y/N)\n", - "Enter default value (Hit \"Enter\" to skip): Enter = ''\n", - "Can this column have null values?(y/N)\n", - "Enter your optional comment about the column:\n", - "Would you like to update same class or create a copy with the update?(y/N)\n", - "Enter a name for the new class:\n", - "Enter an optional namespace for the class: Enter = 'App\Database'\n", - "Success: Column added.\n", - ], $output); - - $clazz = '\\App\\Database\\ModifiedOTable'; - $this->assertTrue(class_exists($clazz)); - $file = new File(ROOT_PATH.$clazz.'.php'); - $file->remove(); - $obj = new $clazz(); - $this->assertTrue($obj instanceof Table); - $col = $obj->getColByKey('new-col'); - $this->assertEquals('int', $col->getDatatype()); - $this->assertEquals(9, $col->getSize()); - $this->assertEquals('Cool new column.', $col->getComment()); - } - - /** - * @test - */ - public function test01() { - $output = $this->executeSingleCommand(new UpdateTableCommand(), [ - 'WebFiori', - 'update-table', - ], [ - 'App\\Database\\TestTable', - '2', - 'id', - 'user-id', - 'int', - '10', - 'n', - 'n', - "\n", // Hit Enter to pick default value (empty default) - 'n', - 'Cool modifiyed column.', - 'y', - 'Modified', - "\n" // Hit Enter to pick default value (App\database) - ]); - - $this->assertEquals(0, $this->getExitCode()); - $this->assertEquals([ - "Enter database table class name (include namespace):\n", - "What operation whould you like to do with the table?\n", - "0: Add new column.\n", - "1: Add foreign key.\n", - "2: Update existing column.\n", - "3: Drop column.\n", - "4: Drop foreign key.\n", - "Which column would you like to update?\n", - "0: id\n", - "Enter a new name for column key: Enter = 'id'\n", - "Select column data type:\n", - "0: mixed <--\n", - "1: int\n", - "2: char\n", - "3: varchar\n", - "4: timestamp\n", - "5: tinyblob\n", - "6: blob\n", - "7: mediumblob\n", - "8: longblob\n", - "9: datetime\n", - "10: text\n", - "11: mediumtext\n", - "12: decimal\n", - "13: double\n", - "14: float\n", - "15: boolean\n", - "16: bool\n", - "17: bit\n", - "Enter column size:\n", - "Is this column primary?(y/N)\n", - "Is this column unique?(y/N)\n", - "Enter default value (Hit \"Enter\" to skip): Enter = ''\n", - "Can this column have null values?(y/N)\n", - "Enter your optional comment about the column:\n", - "Would you like to update same class or create a copy with the update?(y/N)\n", - "Enter a name for the new class:\n", - "Enter an optional namespace for the class: Enter = 'App\Database'\n", - "Success: Column updated.\n", - ], $output); - - $clazz = '\\App\\Database\\ModifiedTable'; - $this->assertTrue(class_exists($clazz)); - $file = new File(ROOT_PATH.$clazz.'.php'); - $file->remove(); - $obj = new $clazz(); - $this->assertTrue($obj instanceof Table); - $col = $obj->getColByKey('user-id'); - $this->assertEquals('int', $col->getDatatype()); - $this->assertEquals(10, $col->getSize()); - $this->assertEquals('Cool modifiyed column.', $col->getComment()); - } - - public function test02() { - $output = $this->executeSingleCommand(new UpdateTableCommand(), [ - 'WebFiori', - 'update-table', - ], [ - 'App\\Database\\Test2Table', - '4', - '0', - 'y', - 'Modified2', - "\n" // Hit Enter to pick default value (App\database) - ]); - - $this->assertEquals(0, $this->getExitCode()); - $this->assertEquals([ - "Enter database table class name (include namespace):\n", - "What operation whould you like to do with the table?\n", - "0: Add new column.\n", - "1: Add foreign key.\n", - "2: Update existing column.\n", - "3: Drop column.\n", - "4: Drop foreign key.\n", - "Select the key that you would like to remove:\n", - "0: user_id_fk\n", - "Would you like to update same class or create a copy with the update?(y/N)\n", - "Enter a name for the new class:\n", - "Enter an optional namespace for the class: Enter = 'App\Database'\n", - "Success: Table updated.\n", - ], $output); - - $clazz = '\\App\\Database\\Modified2Table'; - $this->assertTrue(class_exists($clazz)); - $file = new File(ROOT_PATH.$clazz.'.php'); - $file->remove(); - $obj = new $clazz(); - $this->assertTrue($obj instanceof Table); - } -} From 3a388884fbe2a0127f39e3afc954c8b098fc5eee Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 10 Nov 2025 23:55:25 +0300 Subject: [PATCH 07/25] test: Updated Config --- tests/phpunit.xml | 12 ++++++------ tests/phpunit10.xml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 61b04087b..2bf75fb6a 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -41,13 +41,13 @@ ../WebFiori/Framework/Cli/Commands/AddCommand.php ../WebFiori/Framework/Cli/Commands/CreateCommand.php - ../WebFiori/Framework/Cli/Commands/ListRoutesCommand.php - ../WebFiori/Framework/Cli/Commands/ListThemesCommand.php - ../WebFiori/Framework/Cli/Commands/RunSQLQueryCommand.php + + + ../WebFiori/Framework/Cli/Commands/SchedulerCommand.php - ../WebFiori/Framework/Cli/Commands/SettingsCommand.php - ../WebFiori/Framework/Cli/Commands/UpdateSettingsCommand.php - ../WebFiori/Framework/Cli/Commands/UpdateTableCommand.php + + + ../WebFiori/Framework/Cli/Commands/VersionCommand.php ../WebFiori/Framework/Cli/Commands/WHelpCommand.php ../WebFiori/Framework/Cli/Commands/RunMigrationsCommand.php diff --git a/tests/phpunit10.xml b/tests/phpunit10.xml index ff5539c00..0b3ba63de 100644 --- a/tests/phpunit10.xml +++ b/tests/phpunit10.xml @@ -78,13 +78,13 @@ ../WebFiori/Framework/Session/SessionDB.php ../WebFiori/Framework/Cli/Commands/AddCommand.php ../WebFiori/Framework/Cli/Commands/CreateCommand.php - ../WebFiori/Framework/Cli/Commands/ListRoutesCommand.php - ../WebFiori/Framework/Cli/Commands/ListThemesCommand.php - ../WebFiori/Framework/Cli/Commands/RunSQLQueryCommand.php + + + ../WebFiori/Framework/Cli/Commands/SchedulerCommand.php - ../WebFiori/Framework/Cli/Commands/SettingsCommand.php - ../WebFiori/Framework/Cli/Commands/UpdateSettingsCommand.php - ../WebFiori/Framework/Cli/Commands/UpdateTableCommand.php + + + ../WebFiori/Framework/Cli/Commands/VersionCommand.php ../WebFiori/Framework/Cli/Commands/WHelpCommand.php ../WebFiori/Framework/Cli/Commands/RunMigrationsCommand.php From 641c4cf1b134f6ccdcb89b68a37617d7306b8da2 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Tue, 13 Jan 2026 00:14:34 +0300 Subject: [PATCH 08/25] chore: Updated Core Libraries --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 83131b449..057e01a32 100644 --- a/composer.json +++ b/composer.json @@ -23,13 +23,13 @@ "ext-fileinfo": "*", "ext-openssl": "*", "webfiori/cache": "v2.0.*", - "webfiori/http": "v4.0.*", + "webfiori/http": "v5.0.*", "webfiori/file": "v2.0.*", "webfiori/jsonx": "v4.0.*", "webfiori/ui": "v4.0.*", "webfiori/collections": "v2.0.*", - "webfiori/database": "v1.2.*", - "webfiori/cli": "v2.0.*", + "webfiori/database": "v2.0.*", + "webfiori/cli": "v2.1.*", "webfiori/mailer": "v2.1.*", "webfiori/err": "v2.0.*" }, From dc3d8b68c503d04580adc7e75fbee2541658af96 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Tue, 13 Jan 2026 23:43:53 +0300 Subject: [PATCH 09/25] refactor: Add Request and Response to `App` --- WebFiori/Framework/App.php | 42 +++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/WebFiori/Framework/App.php b/WebFiori/Framework/App.php index 4d85e38c8..100eaf4ee 100644 --- a/WebFiori/Framework/App.php +++ b/WebFiori/Framework/App.php @@ -100,6 +100,18 @@ class App { * @since 1.0 */ private static $LC; + /** + * Current request instance. + * + * @var Request + */ + private static $Request; + /** + * Current response instance. + * + * @var Response + */ + private static $Response; /** * The entry point for initiating the system. @@ -124,6 +136,10 @@ private function __construct() { //Initialize CLI self::getRunner(); + + //Initialize Request and Response + self::$Request = Request::createFromGlobals(); + self::$Response = new Response(); $this->initThemesPath(); @@ -137,7 +153,7 @@ private function __construct() { $this->initMiddleware(); $this->initRoutes(); $this->initScheduler(); - Response::beforeSend(function () + self::getResponse()->beforeSend(function () { register_shutdown_function(function() { @@ -146,7 +162,7 @@ private function __construct() { $mdArr = $uriObj->getMiddleware(); for ($x = count($mdArr) - 1 ; $x > 0 ; $x--) { - $mdArr[$x]->afterSend(Request::get(), Response::get()); + $mdArr[$x]->afterSend(self::getRequest(), self::getResponse()); } } }); @@ -157,7 +173,7 @@ private function __construct() { $mdArr = $uriObj->getMiddleware(); for ($x = count($mdArr) - 1 ; $x > 0 ; $x--) { - $mdArr[$x]->after(Request::get(), Response::get()); + $mdArr[$x]->after(self::getRequest(), self::getResponse()); } } }); @@ -305,8 +321,8 @@ public static function handle() { App::getRunner()->start(); } else { //route user request. - Router::route(Request::getRequestedURI()); - Response::send(); + Router::route(self::getRequest()->getRequestedURI()); + self::getResponse()->send(); } } } @@ -764,4 +780,20 @@ private function setHandlers() { // Handler::registerHandler(new HTTPErrHandler()); // Handler::unregisterHandler(Handler::getHandler('Default')); } + /** + * Returns the current request instance. + * + * @return Request + */ + public static function getRequest() : Request { + return self::$Request; + } + /** + * Returns the current response instance. + * + * @return Response + */ + public static function getResponse() : Response { + return self::$Response; + } } From 79f47a8682a5ffd15c604b6e9138ec912c391c3a Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Tue, 13 Jan 2026 23:46:30 +0300 Subject: [PATCH 10/25] fix: Getting Requested URI --- WebFiori/Framework/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebFiori/Framework/App.php b/WebFiori/Framework/App.php index 100eaf4ee..df2feecc0 100644 --- a/WebFiori/Framework/App.php +++ b/WebFiori/Framework/App.php @@ -740,7 +740,7 @@ private function initRoutes() { * @throws FileException */ private function initScheduler() { - $uriObj = new RouterUri(Request::getRequestedURI(), ''); + $uriObj = new RouterUri(self::getRequest()->getUri()->getUri(true, true), ''); $pathArr = $uriObj->getPathArray(); if (!class_exists(APP_DIR.'\Init\InitTasks')) { From a27c9db99bd8a5dcc875c328e4a4efcda24b33dd Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Tue, 13 Jan 2026 23:46:56 +0300 Subject: [PATCH 11/25] refactor: Add Return Type --- WebFiori/Framework/Writers/ServiceHolder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebFiori/Framework/Writers/ServiceHolder.php b/WebFiori/Framework/Writers/ServiceHolder.php index 4b9ca3510..0280077cb 100644 --- a/WebFiori/Framework/Writers/ServiceHolder.php +++ b/WebFiori/Framework/Writers/ServiceHolder.php @@ -30,7 +30,7 @@ public function __construct(string $name = '') { * * @return boolean Always return false. */ - public function isAuthorized() { + public function isAuthorized(): bool { return false; } /** From 5962d7017f2a0a18a729e6b69e2e623f9a0763cf Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Tue, 13 Jan 2026 23:47:18 +0300 Subject: [PATCH 12/25] refactor: Add Return Type --- WebFiori/Framework/Writers/WebServiceWriter.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WebFiori/Framework/Writers/WebServiceWriter.php b/WebFiori/Framework/Writers/WebServiceWriter.php index ff34e67a5..ef1a19214 100644 --- a/WebFiori/Framework/Writers/WebServiceWriter.php +++ b/WebFiori/Framework/Writers/WebServiceWriter.php @@ -288,14 +288,15 @@ private function implementMethods() { " *", " * @return boolean If the client is authorized, the method will return true.", " */", - $this->f('isAuthorized'), + $this->f('isAuthorized', [], 'bool'), ], 1); $this->append([ '// TODO: Check if the client is authorized to call the service \''.$name.'\'.', '// You can ignore this method or remove it.', '//$authHeader = $this->getAuthHeader();', '//$authType = $authHeader[\'type\'];', - '//$token = $authHeader[\'credentials\'];' + '//$token = $authHeader[\'credentials\'];', + 'return true;' ], 2); $this->append('}', 1); From f4900b5e70a48da8394e275d7ce5f1c4cfcdf45c Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 00:19:50 +0300 Subject: [PATCH 13/25] refactor: Fixes --- WebFiori/Framework/Lang.php | 3 +- WebFiori/Framework/Session/Session.php | 10 +-- .../Framework/Session/SessionsManager.php | 3 +- WebFiori/Framework/Ui/WebPage.php | 4 +- tests/Apis/Multiple/WebService00.php | 3 +- tests/Apis/Multiple/WebService01.php | 3 +- .../WebFiori/Framework/Tests/ResponseTest.php | 81 ++++++++++--------- 7 files changed, 56 insertions(+), 51 deletions(-) diff --git a/WebFiori/Framework/Lang.php b/WebFiori/Framework/Lang.php index 54113e361..40d32ba57 100644 --- a/WebFiori/Framework/Lang.php +++ b/WebFiori/Framework/Lang.php @@ -13,6 +13,7 @@ use WebFiori\Framework\Exceptions\MissingLangException; use WebFiori\Framework\Session\SessionsManager; use WebFiori\Http\Request; +use WebFiori\Framework\App; /** * A class that is can be used to make the application ready for @@ -240,7 +241,7 @@ public static function getLabel(string $dir, ?string $langCode = null) { if ($session !== null) { $langCode = $session->getLangCode(true); } else { - $langCode = Request::getParam('lang'); + $langCode = App::getRequest()->getParam('lang'); if ($langCode === null || strlen($langCode) != 2) { $langCode = App::getConfig()->getPrimaryLanguage(); diff --git a/WebFiori/Framework/Session/Session.php b/WebFiori/Framework/Session/Session.php index 6aac552c3..99a20fecb 100644 --- a/WebFiori/Framework/Session/Session.php +++ b/WebFiori/Framework/Session/Session.php @@ -10,10 +10,10 @@ */ namespace WebFiori\Framework\Session; -use WebFiori\Framework\App; use WebFiori\Framework\Exceptions\SessionException; use WebFiori\Http\HttpCookie; use WebFiori\Http\Request; +use WebFiori\Framework\App; use WebFiori\Json\Json; use WebFiori\Json\JsonI; /** @@ -161,11 +161,11 @@ public function __construct(array $options = []) { $this->startedAt = 0; $this->sessionVariables = []; $this->passedTime = 0; - $this->ipAddr = Request::getClientIP(); + $this->ipAddr = App::getRequest()->getClientIP(); $this->getCookie()->setSameSite('Lax'); - Request::getUri()->getScheme(); + App::getRequest()->getUri()->getScheme(); - if ((defined('USE_HTTP') && USE_HTTP === true) || Request::getUri()->getScheme() == 'http') { + if ((defined('USE_HTTP') && USE_HTTP === true) || App::getRequest()->getUri()->getScheme() == 'http') { $this->getCookie()->setIsSecure(false); } else { $this->getCookie()->setIsSecure(true); @@ -786,7 +786,7 @@ private function cloneHelper(Session $session) { */ private function getLangFromRequest() { $langIdx = 'lang'; - $lang = Request::getParam($langIdx); + $lang = App::getRequest()->getParam($langIdx); if ($lang === null) { $lang = filter_input(INPUT_COOKIE, $langIdx); diff --git a/WebFiori/Framework/Session/SessionsManager.php b/WebFiori/Framework/Session/SessionsManager.php index 6d9905559..67106ccff 100644 --- a/WebFiori/Framework/Session/SessionsManager.php +++ b/WebFiori/Framework/Session/SessionsManager.php @@ -10,6 +10,7 @@ */ namespace WebFiori\Framework\Session; +use WebFiori\Framework\App; use WebFiori\Framework\Exceptions\SessionException; use WebFiori\Http\Request; /** @@ -228,7 +229,7 @@ public static function getSessionIDFromRequest(string $sessionName) { $sid = self::getSessionIDFromCookie($trimmedSName); if ($sid === false) { - $sid = Request::getParam($sessionName); + $sid = App::getRequest()->getParam($sessionName); if ($sid === null) { return false; diff --git a/WebFiori/Framework/Ui/WebPage.php b/WebFiori/Framework/Ui/WebPage.php index 2e0dc3f04..b04c7cef7 100644 --- a/WebFiori/Framework/Ui/WebPage.php +++ b/WebFiori/Framework/Ui/WebPage.php @@ -826,7 +826,7 @@ public function reset() { $this->theme = null; $this->incAside = true; $this->setWritingDir(); - $this->setCanonical(Request::getRequestedURI()); + $this->setCanonical(App::getRequest()->getRequestedURI()); $this->document->setLanguage($this->getLangCode()); $headNode = $this->getHead(); $this->document->setHeadNode($headNode); @@ -1197,7 +1197,7 @@ private function checkLang() { $langCodeFromSession = $session !== null ? $session->getLangCode(true) : null; if ($langCodeFromSession === null) { - $langCodeFromRequest = Request::getParam('lang'); + $langCodeFromRequest = App::getRequest()->getParam('lang'); if ($langCodeFromRequest === null) { $this->setLang($this->getConfigVar('getPrimaryLanguage', 'EN')); diff --git a/tests/Apis/Multiple/WebService00.php b/tests/Apis/Multiple/WebService00.php index 39860c736..9d0ea0581 100644 --- a/tests/Apis/Multiple/WebService00.php +++ b/tests/Apis/Multiple/WebService00.php @@ -47,12 +47,13 @@ public function __construct() { * * @return boolean If the client is authorized, the method will return true. */ - public function isAuthorized() { + public function isAuthorized(): bool { // TODO: Check if the client is authorized to call the service 'say-hi-service'. // You can ignore this method or remove it. //$authHeader = $this->getAuthHeader(); //$authType = $authHeader['type']; //$token = $authHeader['credentials']; + return true; } /** * Process the request. diff --git a/tests/Apis/Multiple/WebService01.php b/tests/Apis/Multiple/WebService01.php index b2b4ad8df..75786a123 100644 --- a/tests/Apis/Multiple/WebService01.php +++ b/tests/Apis/Multiple/WebService01.php @@ -25,12 +25,13 @@ public function __construct() { * * @return boolean If the client is authorized, the method will return true. */ - public function isAuthorized() { + public function isAuthorized(): bool { // TODO: Check if the client is authorized to call the service 'say-hi-service'. // You can ignore this method or remove it. //$authHeader = $this->getAuthHeader(); //$authType = $authHeader['type']; //$token = $authHeader['credentials']; + return true; } /** * Process the request. diff --git a/tests/WebFiori/Framework/Tests/ResponseTest.php b/tests/WebFiori/Framework/Tests/ResponseTest.php index 35b963ed7..bc3c02bec 100644 --- a/tests/WebFiori/Framework/Tests/ResponseTest.php +++ b/tests/WebFiori/Framework/Tests/ResponseTest.php @@ -2,6 +2,7 @@ namespace WebFiori\Framework\Test; use PHPUnit\Framework\TestCase; +use WebFiori\Framework\App; use WebFiori\Http\Response; /** @@ -14,79 +15,79 @@ class ResponseTest extends TestCase { * @test */ public function testAddHeader00() { - $this->assertFalse(Response::hasHeader('content-type')); - $this->assertTrue(Response::addHeader('content-type', 'application/json')); - $this->assertTrue(Response::hasHeader('content-type', 'application/json')); - $this->assertFalse(Response::hasHeader('content-type', 'text/js')); + $this->assertFalse(App::getResponse()->hasHeader('content-type')); + $this->assertTrue(App::getResponse()->addHeader('content-type', 'application/json')); + $this->assertTrue(App::getResponse()->hasHeader('content-type', 'application/json')); + $this->assertFalse(App::getResponse()->hasHeader('content-type', 'text/js')); } /** * @test */ public function testAddHeader01() { - $this->assertFalse(Response::hasHeader('Set-Cookie')); - $this->assertTrue(Response::addHeader('Set-Cookie', 'name=ok')); - $this->assertTrue(Response::hasHeader('Set-Cookie')); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=ok')); + $this->assertFalse(App::getResponse()->hasHeader('Set-Cookie')); + $this->assertTrue(App::getResponse()->addHeader('Set-Cookie', 'name=ok')); + $this->assertTrue(App::getResponse()->hasHeader('Set-Cookie')); + $this->assertTrue(App::getResponse()->hasHeader('Set-Cookie','name=ok')); - $this->assertTrue(Response::addHeader('Set-Cookie', 'name=good')); - $this->assertTrue(Response::hasHeader('Set-cookie','name=good')); + $this->assertTrue(App::getResponse()->addHeader('Set-Cookie', 'name=good')); + $this->assertTrue(App::getResponse()->hasHeader('Set-cookie','name=good')); - $this->assertTrue(Response::addHeader('Set-Cookie', 'name=no')); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=no')); + $this->assertTrue(App::getResponse()->addHeader('Set-Cookie', 'name=no')); + $this->assertTrue(App::getResponse()->hasHeader('Set-Cookie','name=no')); } /** * @test */ public function testClearBody() { - Response::write('Hello World!'); - $this->assertEquals('Hello World!', Response::getBody()); - Response::clearBody(); - $this->assertEquals('', Response::getBody()); + App::getResponse()->write('Hello World!'); + $this->assertEquals('Hello World!', App::getResponse()->getBody()); + App::getResponse()->clearBody(); + $this->assertEquals('', App::getResponse()->getBody()); } /** * @test * @depends testAddHeader00 */ public function testRemoveHeader00() { - $this->assertTrue(Response::hasHeader('content-type')); - Response::removeHeader('content-type'); - $this->assertFalse(Response::hasHeader('content-type')); + $this->assertTrue(App::getResponse()->hasHeader('content-type')); + App::getResponse()->removeHeader('content-type'); + $this->assertFalse(App::getResponse()->hasHeader('content-type')); } /** * @test * @depends testAddHeader01 */ public function testRemoveHeader01() { - $this->assertTrue(Response::hasHeader('Set-Cookie')); - $this->assertTrue(Response::removeHeader('Set-cookie', 'name=good')); - $this->assertFalse(Response::hasHeader('Set-cookie','name=good')); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=no')); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=ok')); - Response::removeHeader('Set-cookie'); - $this->assertFalse(Response::hasHeader('Set-Cookie')); + $this->assertTrue(App::getResponse()->hasHeader('Set-Cookie')); + $this->assertTrue(App::getResponse()->removeHeader('Set-cookie', 'name=good')); + $this->assertFalse(App::getResponse()->hasHeader('Set-cookie','name=good')); + $this->assertTrue(App::getResponse()->hasHeader('Set-Cookie','name=no')); + $this->assertTrue(App::getResponse()->hasHeader('Set-Cookie','name=ok')); + App::getResponse()->removeHeader('Set-cookie'); + $this->assertFalse(App::getResponse()->hasHeader('Set-Cookie')); } /** * @test */ public function testRemoveHeaders() { - Response::addHeader('content-type', 'application/json'); - $this->assertTrue(Response::hasHeader('content-type')); - $this->assertFalse(Response::hasHeader('content-type','text/plain')); - Response::clearHeaders(); - $this->assertEquals(0, count(Response::getHeaders())); + App::getResponse()->addHeader('content-type', 'application/json'); + $this->assertTrue(App::getResponse()->hasHeader('content-type')); + $this->assertFalse(App::getResponse()->hasHeader('content-type','text/plain')); + App::getResponse()->clearHeaders(); + $this->assertEquals(0, count(App::getResponse()->getHeaders())); } /** * @test */ public function testSetResponseCode() { - $this->assertEquals(200, Response::getCode()); - Response::setCode(99); - $this->assertEquals(200, Response::getCode()); - Response::setCode(100); - $this->assertEquals(100, Response::getCode()); - Response::setCode(599); - $this->assertEquals(599, Response::getCode()); - Response::setCode(600); - $this->assertEquals(599, Response::getCode()); + $this->assertEquals(200, App::getResponse()->getCode()); + App::getResponse()->setCode(99); + $this->assertEquals(200, App::getResponse()->getCode()); + App::getResponse()->setCode(100); + $this->assertEquals(100, App::getResponse()->getCode()); + App::getResponse()->setCode(599); + $this->assertEquals(599, App::getResponse()->getCode()); + App::getResponse()->setCode(600); + $this->assertEquals(599, App::getResponse()->getCode()); } } From d87928cacef7b41840ab6df3adf2b8504f1b7ac1 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 00:32:00 +0300 Subject: [PATCH 14/25] refactor: Extends `RequestUri` instead of `Uri` --- WebFiori/Framework/Router/Router.php | 2 +- WebFiori/Framework/Router/RouterUri.php | 6 ++-- .../Framework/Tests/Router/RouterUriTest.php | 36 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/WebFiori/Framework/Router/Router.php b/WebFiori/Framework/Router/Router.php index e59ac5034..d0dc41dbd 100644 --- a/WebFiori/Framework/Router/Router.php +++ b/WebFiori/Framework/Router/Router.php @@ -781,7 +781,7 @@ private function addRouteHelper0($options): bool { } foreach ($options[RouteOption::VALUES] as $varName => $varValues) { - $routeUri->addVarValues($varName, $varValues); + $routeUri->addAllowedParameterValues($varName, $varValues); } $path = $routeUri->isCaseSensitive() ? $routeUri->getPath() : strtolower($routeUri->getPath()); diff --git a/WebFiori/Framework/Router/RouterUri.php b/WebFiori/Framework/Router/RouterUri.php index 1651116a4..b8bd5955e 100644 --- a/WebFiori/Framework/Router/RouterUri.php +++ b/WebFiori/Framework/Router/RouterUri.php @@ -13,7 +13,7 @@ use Closure; use InvalidArgumentException; use WebFiori\Framework\Middleware\MiddlewareManager; -use WebFiori\Http\Uri; +use WebFiori\Http\RequestUri; use WebFiori\Ui\HTMLNode; /** * A class that is used to split URIs and get their parameters. @@ -35,7 +35,7 @@ * * @version 1.5.0 */ -class RouterUri extends Uri { +class RouterUri extends RequestUri { /** * The action (class method) that will be performed. * @@ -522,7 +522,7 @@ public function setType(string $type) { private function _($originalUriWithVars, $uriVars, $varIndex, &$nodesArr) { $varName = $uriVars[$varIndex]; - $varValues = $this->getParameterValues($varName); + $varValues = $this->getAllowedParameterValues($varName); foreach ($varValues as $varValue) { $uriWithVarsReplaced = str_replace('{'.$varName.'}', $varValue, $originalUriWithVars); diff --git a/tests/WebFiori/Framework/Tests/Router/RouterUriTest.php b/tests/WebFiori/Framework/Tests/Router/RouterUriTest.php index 40aff9616..c184138ba 100644 --- a/tests/WebFiori/Framework/Tests/Router/RouterUriTest.php +++ b/tests/WebFiori/Framework/Tests/Router/RouterUriTest.php @@ -183,7 +183,7 @@ public function testGetSitemapNode04() { */ public function testGetSitemapNode05() { $uri = new RouterUri('https://example.com/{var}', ''); - $uri->addVarValue('var', 'hello'); + $uri->addAllowedParameterValue('var', 'hello'); $this->assertEquals(1, count($uri->getSitemapNodes())); $this->assertEquals('https://example.com/hello', $uri->getSitemapNodes()[0]->toHTML()); } @@ -192,7 +192,7 @@ public function testGetSitemapNode05() { */ public function testGetSitemapNode06() { $uri = new RouterUri('https://example.com/{var}', ''); - $uri->addVarValue('var', 'hello'); + $uri->addAllowedParameterValue('var', 'hello'); $uri->addLanguage('ar'); $this->assertEquals(1, count($uri->getSitemapNodes())); $this->assertEquals('https://example.com/hello' @@ -204,7 +204,7 @@ public function testGetSitemapNode06() { */ public function testGetSitemapNode07() { $uri = new RouterUri('https://example.com/{var}', ''); - $uri->addVarValues('var', ['hello', 'world']); + $uri->addAllowedParameterValues('var', ['hello', 'world']); $uri->addLanguage('ar'); $this->assertEquals(2, count($uri->getSitemapNodes())); $this->assertEquals('https://example.com/hello' @@ -219,7 +219,7 @@ public function testGetSitemapNode07() { */ public function testGetSitemapNode08() { $uri = new RouterUri('https://example.com/{var}/world/ok/{another-var}', ''); - $uri->addVarValues('var', ['hello', 'world']); + $uri->addAllowedParameterValues('var', ['hello', 'world']); $uri->addLanguage('ar'); $this->assertEquals(0, count($uri->getSitemapNodes())); } @@ -228,8 +228,8 @@ public function testGetSitemapNode08() { */ public function testGetSitemapNode09() { $uri = new RouterUri('https://example.com/{var}/world/ok/{another-var}', ''); - $uri->addVarValues('var', ['hello', 'world']); - $uri->addVarValue('another-var', 'good'); + $uri->addAllowedParameterValues('var', ['hello', 'world']); + $uri->addAllowedParameterValue('another-var', 'good'); $uri->addLanguage('ar'); $this->assertEquals(2, count($uri->getSitemapNodes())); $this->assertEquals('https://example.com/hello/world/ok/good' @@ -304,8 +304,8 @@ public function testSetRequestedURI01() { */ public function testSetUriPossibleVar00() { $uri = new RouterUri('https://example.com/{first-var}', ''); - $uri->addVarValue('first-var', 'Hello World'); - $this->assertEquals(['Hello World'], $uri->getParameterValues('first-var')); + $uri->addAllowedParameterValue('first-var', 'Hello World'); + $this->assertEquals(['Hello World'], $uri->getAllowedParameterValues('first-var')); $this->assertEquals('/{first-var}', $uri->getPath()); $this->assertEquals(['{first-var}'], $uri->getPathArray()); } @@ -314,28 +314,28 @@ public function testSetUriPossibleVar00() { */ public function testSetUriPossibleVar01() { $uri = new RouterUri('https://example.com/{first-var}', ''); - $uri->addVarValue(' first-var ', ' Hello World '); - $this->assertEquals(['Hello World'], $uri->getParameterValues('first-var')); + $uri->addAllowedParameterValue(' first-var ', ' Hello World '); + $this->assertEquals(['Hello World'], $uri->getAllowedParameterValues('first-var')); } /** * @test */ public function testSetUriPossibleVar02() { $uri = new RouterUri('https://example.com/{first-var}', ''); - $uri->addVarValues('first-var', ['Hello','World']); - $this->assertEquals(['Hello','World'], $uri->getParameterValues('first-var')); + $uri->addAllowedParameterValues('first-var', ['Hello','World']); + $this->assertEquals(['Hello','World'], $uri->getAllowedParameterValues('first-var')); } /** * @test */ public function testSetUriPossibleVar03() { $uri = new RouterUri('https://example.com/{first-var}/ok/{second-var}', ''); - $uri->addVarValues('first-var', ['Hello','World']); - $uri->addVarValues(' second-var ', ['hell','is','not','heven']); - $uri->addVarValues(' secohhnd-var ', ['hell','is']); - $this->assertEquals(['Hello','World'], $uri->getParameterValues('first-var')); - $this->assertEquals(['hell','is','not','heven'], $uri->getParameterValues('second-var')); - $this->assertEquals([], $uri->getParameterValues('secohhnd-var')); + $uri->addAllowedParameterValues('first-var', ['Hello','World']); + $uri->addAllowedParameterValues(' second-var ', ['hell','is','not','heven']); + $uri->addAllowedParameterValues(' secohhnd-var ', ['hell','is']); + $this->assertEquals(['Hello','World'], $uri->getAllowedParameterValues('first-var')); + $this->assertEquals(['hell','is','not','heven'], $uri->getAllowedParameterValues('second-var')); + $this->assertEquals([], $uri->getAllowedParameterValues('secohhnd-var')); } /** * @test From 49b134b26c5eb1f18d402a804b8e61432ef32fc5 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 00:36:26 +0300 Subject: [PATCH 15/25] refactor: Namespace Correction --- WebFiori/Framework/Writers/DBClassWriter.php | 2 +- WebFiori/Framework/Writers/TableClassWriter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WebFiori/Framework/Writers/DBClassWriter.php b/WebFiori/Framework/Writers/DBClassWriter.php index 8ab043da5..7fd187896 100644 --- a/WebFiori/Framework/Writers/DBClassWriter.php +++ b/WebFiori/Framework/Writers/DBClassWriter.php @@ -11,7 +11,7 @@ namespace WebFiori\Framework\Writers; use WebFiori\Database\Column; -use WebFiori\Database\EntityMapper; +use WebFiori\Database\Entity\EntityMapper; use WebFiori\Database\MsSql\MSSQLColumn; use WebFiori\Database\MsSql\MSSQLTable; use WebFiori\Database\Table; diff --git a/WebFiori/Framework/Writers/TableClassWriter.php b/WebFiori/Framework/Writers/TableClassWriter.php index 13aec8e6b..911fc32a0 100644 --- a/WebFiori/Framework/Writers/TableClassWriter.php +++ b/WebFiori/Framework/Writers/TableClassWriter.php @@ -15,7 +15,7 @@ use WebFiori\Database\ColOption; use WebFiori\Database\Column; use WebFiori\Database\DataType; -use WebFiori\Database\EntityMapper; +use WebFiori\Database\Entity\EntityMapper; use WebFiori\Database\FK; use WebFiori\Database\mssql\MSSQLColumn; use WebFiori\Database\MsSql\MSSQLTable; From 1803a9232ae0c2c97dbece8a9821c352b5f11e61 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 00:47:20 +0300 Subject: [PATCH 16/25] refactor: Use of `getAll` Instead of `METHODS` --- WebFiori/Framework/Router/Router.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WebFiori/Framework/Router/Router.php b/WebFiori/Framework/Router/Router.php index d0dc41dbd..dd00b3504 100644 --- a/WebFiori/Framework/Router/Router.php +++ b/WebFiori/Framework/Router/Router.php @@ -20,6 +20,7 @@ use WebFiori\Framework\Ui\StarterPage; use WebFiori\Framework\Ui\WebPage; use WebFiori\Http\Request; +use WebFiori\Http\RequestMethod; use WebFiori\Http\Response; use WebFiori\Http\Uri; use WebFiori\Http\WebServicesManager; @@ -1162,7 +1163,7 @@ private function getRequestMethodsHelper(array $options): array { foreach ($options[RouteOption::REQUEST_METHODS] as $reqMethod) { $upper = strtoupper(trim($reqMethod)); - if (in_array($upper, Request::METHODS)) { + if (in_array($upper, RequestMethod::getAll())) { $requestMethodsArr[] = $upper; } } @@ -1170,7 +1171,7 @@ private function getRequestMethodsHelper(array $options): array { if ($methTypes == 'string') { $upper = strtoupper(trim($options[RouteOption::REQUEST_METHODS])); - if (in_array($upper, Request::METHODS)) { + if (in_array($upper, RequestMethod::getAll())) { $requestMethodsArr[] = $upper; } } From 8d09e6e035bb5def194423d3bec0cb9a722907a8 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 00:47:44 +0300 Subject: [PATCH 17/25] refactor: Add Return Type --- .../Framework/Scheduler/WebServices/PrivateSchedulerService.php | 2 +- .../Framework/Scheduler/WebServices/SetupPasswordService.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WebFiori/Framework/Scheduler/WebServices/PrivateSchedulerService.php b/WebFiori/Framework/Scheduler/WebServices/PrivateSchedulerService.php index 09ebe6eb5..1a4cbaa6f 100644 --- a/WebFiori/Framework/Scheduler/WebServices/PrivateSchedulerService.php +++ b/WebFiori/Framework/Scheduler/WebServices/PrivateSchedulerService.php @@ -19,7 +19,7 @@ abstract class PrivateSchedulerService extends AbstractWebService { * * @return bool */ - public function isAuthorized() { + public function isAuthorized(): bool { return SessionsManager::getActiveSession()->get('scheduler-is-logged-in') === true; } } diff --git a/WebFiori/Framework/Scheduler/WebServices/SetupPasswordService.php b/WebFiori/Framework/Scheduler/WebServices/SetupPasswordService.php index 270ff73f8..2c9fda933 100644 --- a/WebFiori/Framework/Scheduler/WebServices/SetupPasswordService.php +++ b/WebFiori/Framework/Scheduler/WebServices/SetupPasswordService.php @@ -27,7 +27,7 @@ public function __construct() { $this->addRequestMethod('post'); $this->addParameter(new RequestParameter('password')); } - public function isAuthorized() { + public function isAuthorized(): bool { return TasksManager::getPassword() == 'NO_PASSWORD'; } From 3673e32ba32e4aa9cd44635dabebe5fa41fd2c8b Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 00:52:23 +0300 Subject: [PATCH 18/25] refactor: Use `App` for Request and Response --- WebFiori/Framework/Router/Router.php | 9 +++++---- WebFiori/Framework/Router/RouterUri.php | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/WebFiori/Framework/Router/Router.php b/WebFiori/Framework/Router/Router.php index dd00b3504..f3ee9d91f 100644 --- a/WebFiori/Framework/Router/Router.php +++ b/WebFiori/Framework/Router/Router.php @@ -15,6 +15,7 @@ use WebFiori\Cli\Runner; use WebFiori\File\exceptions\FileException; use WebFiori\File\File; +use WebFiori\Framework\App; use WebFiori\Framework\Exceptions\RoutingException; use WebFiori\Framework\Ui\HTTPCodeView; use WebFiori\Framework\Ui\StarterPage; @@ -1381,7 +1382,7 @@ private function routeFound(RouterUri $route, bool $loadResource) { $this->uriObj = $route; foreach ($route->getMiddleware() as $mw) { - $mw->before(Request::get(), Response::get()); + $mw->before(App::getRequest(), App::getResponse()); } if ($route->getType() == self::API_ROUTE && !defined('API_CALL')) { @@ -1423,12 +1424,12 @@ private function routeFound(RouterUri $route, bool $loadResource) { } } else { if ($loadResource === true) { - $message = 'The resource "'.Request::getRequestedURI().'" was available. ' + $message = 'The resource "'.App::getRequest()->getRequestedURI().'" was available. ' .'but its route is not configured correctly. ' .'The resource which the route is pointing to was not found.'; if (defined('WF_VERBOSE') && WF_VERBOSE) { - $message = 'The resource "'.Request::getRequestedURI().'" was available. ' + $message = 'The resource "'.App::getRequest()->getRequestedURI().'" was available. ' .'but its route is not configured correctly. ' .'The resource which the route is pointing to was not found ('.$file.').'; } @@ -1465,7 +1466,7 @@ private function routeFound(RouterUri $route, bool $loadResource) { private function searchRoute(RouterUri $routeUri, string $uri, bool $loadResource, bool $withVars = false): bool { $pathArray = $routeUri->getPathArray(); - $requestMethod = Request::getMethod(); + $requestMethod = App::getRequest()->getMethod(); $indexToSearch = 'static'; if ($withVars) { diff --git a/WebFiori/Framework/Router/RouterUri.php b/WebFiori/Framework/Router/RouterUri.php index b8bd5955e..6999193c8 100644 --- a/WebFiori/Framework/Router/RouterUri.php +++ b/WebFiori/Framework/Router/RouterUri.php @@ -14,6 +14,7 @@ use InvalidArgumentException; use WebFiori\Framework\Middleware\MiddlewareManager; use WebFiori\Http\RequestUri; +use WebFiori\Http\Uri; use WebFiori\Ui\HTMLNode; /** * A class that is used to split URIs and get their parameters. From bd09605110e17c2516200f78040bbcf1aca94a35 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 01:27:03 +0300 Subject: [PATCH 19/25] fix: Multiple Fixes --- .../Framework/Cli/Helpers/CreateMigration.php | 2 +- WebFiori/Framework/Router/Router.php | 24 +++---- WebFiori/Framework/Ui/WebPage.php | 2 +- .../EmptyService/EmptyServicesManager.php | 2 +- tests/Apis/Multiple/ServicesManager00.php | 2 +- .../Tests/Cli/CreateWebServiceTest.php | 4 +- .../Framework/Tests/Router/RouterTest.php | 69 ++++++++++--------- .../Writers/DatabaseMigrationWriterTest.php | 21 +++--- 8 files changed, 64 insertions(+), 62 deletions(-) diff --git a/WebFiori/Framework/Cli/Helpers/CreateMigration.php b/WebFiori/Framework/Cli/Helpers/CreateMigration.php index b208ce1e8..2dc0c16a6 100644 --- a/WebFiori/Framework/Cli/Helpers/CreateMigration.php +++ b/WebFiori/Framework/Cli/Helpers/CreateMigration.php @@ -34,7 +34,7 @@ public function __construct(CreateCommand $command) { $ns = CLIUtils::readNamespace($command, $ns , 'Migration namespace:'); } - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new \WebFiori\Database\ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); parent::__construct($command, new DatabaseMigrationWriter($runner)); $this->setNamespace($ns); diff --git a/WebFiori/Framework/Router/Router.php b/WebFiori/Framework/Router/Router.php index f3ee9d91f..47d0d8f0a 100644 --- a/WebFiori/Framework/Router/Router.php +++ b/WebFiori/Framework/Router/Router.php @@ -157,7 +157,7 @@ private function __construct() { !defined('DS') ? define('DS', DIRECTORY_SEPARATOR) : ''; $this->onNotFound = function () { - Response::setCode(404); + App::getResponse()->setCode(404); if (!defined('API_CALL')) { $notFoundView = new HTTPCodeView(404); @@ -167,7 +167,7 @@ private function __construct() { 'message' => 'Requested resource was not found.', 'type' => 'error' ]); - Response::write($json); + App::getResponse()->write($json); } }; @@ -505,8 +505,8 @@ public static function incSiteMapRoute() { } $retVal = ''; $retVal .= $urlSet->toHTML(); - Response::write($retVal); - Response::addHeader('content-type','text/xml'); + App::getResponse()->write($retVal); + App::getResponse()->addHeader('content-type','text/xml'); }; self::closure([ RouteOption::PATH => '/sitemap.xml', @@ -607,11 +607,11 @@ public static function redirect(string $path, string $to, int $code = 301) { if (!in_array($httpCode, $allowedCodes)) { $httpCode = 301; } - Response::addHeader('location', $to); - Response::setCode($httpCode); + App::getResponse()->addHeader('location', $to); + App::getResponse()->setCode($httpCode); if (!Runner::isCLI()) { - Response::send(); + App::getResponse()->send(); } }, 'closure-params' => [ @@ -1295,7 +1295,7 @@ private function loadResourceHelper(RouterUri $route) { * @param RouterUri $uriObj */ private function redirectToNonWWW(RouterUri $uriObj) { - Response::setCode(301); + App::getResponse()->setCode(301); $path = ''; $host = substr($uriObj->getHost(), strpos($uriObj->getHost(), '.')); @@ -1318,8 +1318,8 @@ private function redirectToNonWWW(RouterUri $uriObj) { if (strlen($uriObj->getPort()) > 0) { $port = ':'.$uriObj->getPort(); } - Response::addHeader('location', $uriObj->getScheme().'://'.$host.$port.$path.$queryString.$fragment); - Response::send(); + App::getResponse()->addHeader('location', $uriObj->getScheme().'://'.$host.$port.$path.$queryString.$fragment); + App::getResponse()->send(); } /** * Route a given URI to its specified resource. @@ -1439,7 +1439,7 @@ private function routeFound(RouterUri $route, bool $loadResource) { } } } else { - Response::setCode(405); + App::getResponse()->setCode(405); if (!defined('API_CALL')) { $notFoundView = new HTTPCodeView(405); @@ -1449,7 +1449,7 @@ private function routeFound(RouterUri $route, bool $loadResource) { 'message' => 'Request method not allowed.', 'type' => 'error' ]); - Response::write($json); + App::getResponse()->write($json); } } } diff --git a/WebFiori/Framework/Ui/WebPage.php b/WebFiori/Framework/Ui/WebPage.php index b04c7cef7..d751492cb 100644 --- a/WebFiori/Framework/Ui/WebPage.php +++ b/WebFiori/Framework/Ui/WebPage.php @@ -788,7 +788,7 @@ public function render(bool $formatted = false, bool $returnResult = false) { if (!$returnResult) { $formatted = $formatted === true || (defined('WF_VERBOSE') && WF_VERBOSE); - Response::write($this->getDocument()->toHTML($formatted)); + App::getResponse()->write($this->getDocument()->toHTML($formatted)); return null; } diff --git a/tests/Apis/EmptyService/EmptyServicesManager.php b/tests/Apis/EmptyService/EmptyServicesManager.php index aba06f4cc..0b005a225 100644 --- a/tests/Apis/EmptyService/EmptyServicesManager.php +++ b/tests/Apis/EmptyService/EmptyServicesManager.php @@ -8,6 +8,6 @@ */ class EmptyServicesManager extends WebServicesManager { public function __construct(string $version = '1.0.0') { - parent::__construct($version); + parent::__construct(null, $version); } } diff --git a/tests/Apis/Multiple/ServicesManager00.php b/tests/Apis/Multiple/ServicesManager00.php index 565f2e3d2..60701b854 100644 --- a/tests/Apis/Multiple/ServicesManager00.php +++ b/tests/Apis/Multiple/ServicesManager00.php @@ -8,7 +8,7 @@ */ class ServicesManager00 extends WebServicesManager { public function __construct(string $version = '1.0.0') { - parent::__construct($version); + parent::__construct(null, $version); $this->addService(new WebService00()); $this->addService(new WebService01()); } diff --git a/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php b/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php index 8c7f5d941..d06ef2e85 100644 --- a/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php @@ -206,9 +206,9 @@ public function test01() { ParamOption::DESCRIPTION => 'Random\'s desc', ParamOption::DEFAULT => null, ParamOption::EMPTY => false, - ParamOption::MAX => defined('PHP_FLOAT_MAX') ? PHP_FLOAT_MAX : 1.7976931348623E+308, + ParamOption::MAX => 999999999.99, ParamOption::MAX_LENGTH => null, - ParamOption::MIN => defined('PHP_FLOAT_MIN') ? PHP_FLOAT_MIN : 2.2250738585072E-308, + ParamOption::MIN => -999999999.99, ParamOption::MIN_LENGTH => null, ParamOption::OPTIONAL => false, ]); diff --git a/tests/WebFiori/Framework/Tests/Router/RouterTest.php b/tests/WebFiori/Framework/Tests/Router/RouterTest.php index d63919f1f..e1e865894 100644 --- a/tests/WebFiori/Framework/Tests/Router/RouterTest.php +++ b/tests/WebFiori/Framework/Tests/Router/RouterTest.php @@ -2,6 +2,7 @@ namespace WebFiori\Framework\Test\Router; use PHPUnit\Framework\TestCase; +use WebFiori\Framework\App; use WebFiori\Framework\Router\RouteOption; use WebFiori\Framework\Router\Router; use WebFiori\Framework\Router\RouterUri; @@ -262,8 +263,8 @@ public function testRedirect() { Router::redirect('home', 'home2'); Router::route('https://127.0.0.1/home'); - $this->assertEquals(301, Response::getCode()); - $locHeader = Response::getHeader('location'); + $this->assertEquals(301, App::getResponse()->getCode()); + $locHeader = App::getResponse()->getHeader('location'); $this->assertEquals(['home2'], $locHeader); } @@ -271,22 +272,22 @@ public function testRedirect() { * @test */ public function testRedirect01() { - Response::removeHeader('location'); + App::getResponse()->removeHeader('location'); Router::redirect('home', 'home2', 308); Router::route('https://127.0.0.1/home'); - $this->assertEquals(308, Response::getCode()); - $locHeader = Response::getHeader('location'); + $this->assertEquals(308, App::getResponse()->getCode()); + $locHeader = App::getResponse()->getHeader('location'); $this->assertEquals(['home2'], $locHeader); } /** * @test */ public function testRedirect03() { - Response::removeHeader('location'); + App::getResponse()->removeHeader('location'); Router::redirect('home/{id}', 'https://google.com', 3099); Router::route('https://127.0.0.1/home/55'); - $this->assertEquals(301, Response::getCode()); - $locHeader = Response::getHeader('location'); + $this->assertEquals(301, App::getResponse()->getCode()); + $locHeader = App::getResponse()->getHeader('location'); $this->assertEquals(['https://google.com'], $locHeader); $this->assertEquals(55, Router::getParameterValue('id')); $this->assertTrue(Router::removeRoute('home/{id}')); @@ -295,13 +296,13 @@ public function testRedirect03() { * @test */ public function testRedirect04() { - Response::setCode(404); - Response::removeHeader('location'); + App::getResponse()->setCode(404); + App::getResponse()->removeHeader('location'); Router::removeAll(); Router::redirect('home/{id?}', 'https://google.com', 400); Router::route('https://127.0.0.1/home'); - $this->assertEquals(301, Response::getCode()); - $locHeader = Response::getHeader('location'); + $this->assertEquals(301, App::getResponse()->getCode()); + $locHeader = App::getResponse()->getHeader('location'); $this->assertEquals(['https://google.com'], $locHeader); $this->assertNull(Router::getParameterValue('id')); $this->assertTrue(Router::removeRoute('home/{id?}')); @@ -312,9 +313,9 @@ public function testRedirect04() { public function testSitemap00() { Router::removeAll(); Router::incSiteMapRoute(); - Response::clear(); + App::getResponse()->clear(); Router::route('https://127.0.0.1/sitemap'); - $this->assertEquals(['text/xml'], Response::getHeader('content-type')); + $this->assertEquals(['text/xml'], App::getResponse()->getHeader('content-type')); $this->assertEquals('' . '' . '' @@ -323,13 +324,13 @@ public function testSitemap00() { . '' . 'https://127.0.0.1/sitemap' . '' - . '', Response::getBody()); + . '', App::getResponse()->getBody()); } /** * @test */ public function testSitemap01() { - Response::clear(); + App::getResponse()->clear(); Router::removeAll(); Router::incSiteMapRoute(); Router::closure([ @@ -340,7 +341,7 @@ public function testSitemap01() { RouteOption::SITEMAP => true ]); Router::route('https://127.0.0.1/sitemap'); - $this->assertEquals(['text/xml'], Response::getHeader('content-type')); + $this->assertEquals(['text/xml'], App::getResponse()->getHeader('content-type')); $this->assertEquals('' . '' . '' @@ -352,13 +353,13 @@ public function testSitemap01() { . '' . 'https://127.0.0.1/home' . '' - . '', Response::getBody()); + . '', App::getResponse()->getBody()); } /** * @test */ public function testSitemap02() { - Response::clear(); + App::getResponse()->clear(); Router::removeAll(); Router::incSiteMapRoute(); Router::closure([ @@ -369,7 +370,7 @@ public function testSitemap02() { RouteOption::SITEMAP => true ]); Router::route('https://127.0.0.1/sitemap'); - $this->assertEquals(['text/xml'], Response::getHeader('content-type')); + $this->assertEquals(['text/xml'], App::getResponse()->getHeader('content-type')); $this->assertEquals('' . '' . '' @@ -378,13 +379,13 @@ public function testSitemap02() { . '' . 'https://127.0.0.1/sitemap' . '' - . '', Response::getBody()); + . '', App::getResponse()->getBody()); } /** * @test */ public function testSitemap03() { - Response::clear(); + App::getResponse()->clear(); Router::removeAll(); Router::incSiteMapRoute(); Router::closure([ @@ -398,7 +399,7 @@ public function testSitemap03() { ] ]); Router::route('https://127.0.0.1/sitemap'); - $this->assertEquals(['text/xml'], Response::getHeader('content-type')); + $this->assertEquals(['text/xml'], App::getResponse()->getHeader('content-type')); $this->assertEquals('' . '' . '' @@ -413,13 +414,13 @@ public function testSitemap03() { . '' . 'https://127.0.0.1/home/2' . '' - . '', Response::getBody()); + . '', App::getResponse()->getBody()); } /** * @test */ public function testSitemap04() { - Response::clear(); + App::getResponse()->clear(); Router::removeAll(); Router::incSiteMapRoute(); Router::closure([ @@ -434,7 +435,7 @@ public function testSitemap04() { RouteOption::LANGS => ['en'] ]); Router::route('https://127.0.0.1/sitemap'); - $this->assertEquals(['text/xml'], Response::getHeader('content-type')); + $this->assertEquals(['text/xml'], App::getResponse()->getHeader('content-type')); $this->assertEquals('' . '' . '' @@ -451,13 +452,13 @@ public function testSitemap04() { . 'https://127.0.0.1/home/2' . '' . '' - . '', Response::getBody()); + . '', App::getResponse()->getBody()); } /** * @test */ public function testSitemap05() { - Response::clear(); + App::getResponse()->clear(); Router::removeAll(); Router::incSiteMapRoute(); Router::closure([ @@ -472,7 +473,7 @@ public function testSitemap05() { RouteOption::LANGS => ['en', 'ar'] ]); Router::route('https://127.0.0.1/sitemap'); - $this->assertEquals(['text/xml'], Response::getHeader('content-type')); + $this->assertEquals(['text/xml'], App::getResponse()->getHeader('content-type')); $this->assertEquals('' . '' . '' @@ -491,26 +492,26 @@ public function testSitemap05() { . '' . '' . '' - . '', Response::getBody()); + . '', App::getResponse()->getBody()); } /** * @test */ public function testClassRoute00() { - Response::clear(); + App::getResponse()->clear(); Router::addRoute([ RouteOption::PATH => 'home', RouteOption::TO => \App\Apis\RoutingTestClass::class ]); Router::route('https://127.0.0.1/home'); - $this->assertEquals("I'm inside the class.", Response::getBody()); + $this->assertEquals("I'm inside the class.", App::getResponse()->getBody()); } /** * @test */ public function testClassRoute02() { - Response::clear(); + App::getResponse()->clear(); Router::removeAll(); Router::addRoute([ RouteOption::PATH => 'home', @@ -519,7 +520,7 @@ public function testClassRoute02() { ]); Router::route('https://127.0.0.1/home'); - $this->assertEquals("I'm doing something.", Response::getBody()); + $this->assertEquals("I'm doing something.", App::getResponse()->getBody()); } } diff --git a/tests/WebFiori/Framework/Tests/Writers/DatabaseMigrationWriterTest.php b/tests/WebFiori/Framework/Tests/Writers/DatabaseMigrationWriterTest.php index e02dab022..9c3adaaf5 100644 --- a/tests/WebFiori/Framework/Tests/Writers/DatabaseMigrationWriterTest.php +++ b/tests/WebFiori/Framework/Tests/Writers/DatabaseMigrationWriterTest.php @@ -2,6 +2,7 @@ namespace WebFiori\Framework\Test\Writers; use PHPUnit\Framework\TestCase; +use WebFiori\Database\ConnectionInfo; use WebFiori\Database\Schema\AbstractMigration; use WebFiori\Database\Schema\SchemaRunner; use WebFiori\File\File; @@ -44,7 +45,7 @@ public function test00() { $ns = '\\App\\Database\\Migrations'; $clazz = "\\App\\Database\\Migrations\\Migration000"; $this->removeClass($clazz); - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); $writter = new DatabaseMigrationWriter($runner); $this->assertEquals('Migration000', $writter->getName()); $this->assertEquals('App\\Database\\Migrations', $writter->getNamespace()); @@ -68,14 +69,14 @@ public function test00() { $this->assertTrue($m00 instanceof AbstractMigration); $this->assertEquals('App\\Database\\Migrations\\Migration000', $m00->getName()); $this->removeClass($clazz); - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); } /** * @test */ public function test01() { DatabaseMigrationWriter::resetCounter(); - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); $path = APP_PATH.DS.'Database'.DS.'Migrations'; $ns = '\\App\\Database\\Migrations'; $writter = new DatabaseMigrationWriter($runner); @@ -99,14 +100,14 @@ public function test01() { $this->assertTrue($m00 instanceof AbstractMigration); $this->assertEquals('App\\Database\\Migrations\\MyMigration', $m00->getName()); $this->removeClass($clazz); - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); } /** * @test */ public function test02() { DatabaseMigrationWriter::resetCounter(); - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); $path = APP_PATH.DS.'Database'.DS.'Migrations'; $ns = '\\App\\Database\\Migrations'; $writter = new DatabaseMigrationWriter($runner); @@ -121,7 +122,7 @@ public function test02() { $this->assertTrue(class_exists($clazz)); $runner->register($clazz); $allClasses[] = $clazz; - $runner2 = new SchemaRunner(null); + $runner2 = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); $runner2->register($clazz); $migrations = $runner2->getChanges(); $this->assertEquals(1, count($migrations)); @@ -141,7 +142,7 @@ public function test02() { $this->assertTrue(class_exists($clazz2)); $runner->register($clazz); $allClasses[] = $clazz; - $runner3 = new SchemaRunner(null); + $runner3 = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); $runner3->register($clazz); $runner3->register($clazz2); $migrations2 = $runner3->getChanges(); @@ -150,7 +151,7 @@ public function test02() { $this->assertTrue($m00 instanceof AbstractMigration); $this->assertEquals('App\\Database\\Migrations\\Migration001', $m01->getName()); $this->removeClass($clazz); - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); $this->removeClass($clazz2); } /** @@ -158,7 +159,7 @@ public function test02() { */ public function test03() { DatabaseMigrationWriter::resetCounter(); - $runner = new SchemaRunner(null); + $runner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); $path = APP_PATH.DS.'Database'.DS.'Migrations'; $ns = '\\App\\Database\\Migrations'; $allClasses = []; @@ -182,7 +183,7 @@ public function test03() { $this->assertTrue(class_exists($clazz)); $runner->register($clazz); $allClasses[] = $clazz; - $xRunner = new SchemaRunner(null); + $xRunner = new SchemaRunner(new ConnectionInfo('mysql', 'test_user', 'test_pass', 'test_db')); foreach ($allClasses as $cls) { $xRunner->register($cls); } From 54ee12580e5e6f6ca8cf37a9ce9f69f4385b6bb5 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 15:50:01 +0300 Subject: [PATCH 20/25] test: Fix Test Cases --- App/Apis/RoutingTestClass.php | 12 ++++++------ .../WebFiori/Framework/Tests/Session/SessionTest.php | 9 +++++---- .../Framework/Tests/Session/SessionsManagerTest.php | 6 +++--- tests/bootstrap.php | 1 + 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/App/Apis/RoutingTestClass.php b/App/Apis/RoutingTestClass.php index f605ba9ee..557d8be65 100644 --- a/App/Apis/RoutingTestClass.php +++ b/App/Apis/RoutingTestClass.php @@ -1,18 +1,18 @@ write("I'm inside the class."); } public function doSomething() { - Response::clear(); - Response::write("I'm doing something."); + App::getResponse()->clear(); + App::getResponse()->write("I'm doing something."); } public function doSomethingExtra(?string $p1 = null, ?string $p2 = null) { - Response::clear(); - Response::write("I'm doing something."); + App::getResponse()->clear(); + App::getResponse()->write("I'm doing something."); } } diff --git a/tests/WebFiori/Framework/Tests/Session/SessionTest.php b/tests/WebFiori/Framework/Tests/Session/SessionTest.php index 1b6475a40..5a9a1247d 100644 --- a/tests/WebFiori/Framework/Tests/Session/SessionTest.php +++ b/tests/WebFiori/Framework/Tests/Session/SessionTest.php @@ -3,6 +3,7 @@ use PHPUnit\Framework\TestCase; use WebFiori\File\File; +use WebFiori\Framework\App; use WebFiori\Framework\Exceptions\SessionException; use WebFiori\Framework\Session\Session; use WebFiori\Framework\Session\SessionStatus; @@ -199,7 +200,7 @@ public function testSetVar00() { */ public function testStart00() { $_POST['lang'] = 'EN'; - putenv('REQUEST_METHOD=POST'); + App::getRequest()->setRequestMethod('POST'); $session = new Session(['name' => 'new']); $this->assertEquals(SessionStatus::INACTIVE,$session->getStatus()); $this->assertEquals(0,$session->getStartedAt()); @@ -212,7 +213,7 @@ public function testStart00() { $this->assertEquals('EN', $session->getLangCode()); $this->assertEquals('EN', $session->getLangCode(true)); $_POST['lang'] = 'AR'; - putenv('REQUEST_METHOD=POST'); + App::getRequest()->setRequestMethod('POST'); $this->assertEquals('EN', $session->getLangCode()); $this->assertEquals('AR', $session->getLangCode(true)); $this->assertEquals(0,$session->getPassedTime()); @@ -247,7 +248,7 @@ public function testStart01($session) { */ public function testToJsonTest00() { $_POST['lang'] = 'fr'; - $_SERVER['REQUEST_METHOD'] = 'POST'; + App::getRequest()->setRequestMethod('POST'); $s = new Session(['name' => 'session','duration' => 1]); $j = $s->toJSON(); $j->setPropsStyle('snake'); @@ -286,7 +287,7 @@ public function testToJsonTest00() { */ public function testToJsonTest01() { $_POST['lang'] = 'fr'; - $_SERVER['REQUEST_METHOD'] = 'POST'; + App::getRequest()->setRequestMethod('POST'); $s = new Session(['name' => 'session','duration' => 1]); $j = $s->toJSON(); $j->setPropsStyle('snake'); diff --git a/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php b/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php index e2fb4b3ee..0d5f3549c 100644 --- a/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php +++ b/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php @@ -144,7 +144,7 @@ public function testCookiesHeaders() { SessionsManager::start('hello'); $sessions = SessionsManager::getSessions(); $this->assertEquals([ - 'hello='.$sessions[0]->getId().'; expires='.$sessions[0]->getCookie()->getLifetime().'; domain=127.0.0.1; path=/; Secure; HttpOnly; SameSite=Lax' + 'hello='.$sessions[0]->getId().'; expires='.$sessions[0]->getCookie()->getLifetime().'; path=/; Secure; HttpOnly; SameSite=Lax' ], SessionsManager::getCookiesHeaders()); } /** @@ -303,12 +303,12 @@ public function testDropDbTables00() { public function testGetSessionIDFromRequest() { unset($_POST["my-s"]); $this->assertFalse(SessionsManager::getSessionIDFromRequest('my-s')); - putenv('REQUEST_METHOD=GET'); + App::getRequest()->setRequestMethod('GET'); $_GET['my-s'] = 'super'; $this->assertEquals('super', SessionsManager::getSessionIDFromRequest('my-s')); $_POST['my-s'] = 'xyz'; - putenv('REQUEST_METHOD=POST'); + App::getRequest()->setRequestMethod('POST'); $this->assertEquals('xyz', SessionsManager::getSessionIDFromRequest('my-s')); } /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 16ef1fe6e..f007c3bee 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -97,6 +97,7 @@ fprintf(STDOUT,"Initializing application...\n"); App::initiate('App', 'public', $ROOT); App::start(); +putenv('REQUEST_METHOD=GET'); fprintf(STDOUT,'Done.'."\n"); fprintf(STDOUT,'Autoload Root Directory: \''.ClassLoader::get()->root().'\'.'."\n"); define('TESTS_PATH', ClassLoader::get()->root().$DS.TESTS_DIRECTORY); From 5751948f95810074c2e93e6a237fe7e3d9ce63fc Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 16:03:06 +0300 Subject: [PATCH 21/25] test: Expected Max and Min to Null --- tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php b/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php index d06ef2e85..5a1239fc0 100644 --- a/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php @@ -206,9 +206,9 @@ public function test01() { ParamOption::DESCRIPTION => 'Random\'s desc', ParamOption::DEFAULT => null, ParamOption::EMPTY => false, - ParamOption::MAX => 999999999.99, + ParamOption::MAX => null, ParamOption::MAX_LENGTH => null, - ParamOption::MIN => -999999999.99, + ParamOption::MIN => null, ParamOption::MIN_LENGTH => null, ParamOption::OPTIONAL => false, ]); From 602a5ba1b8e202f67e06eb13952a71ec2ea41d71 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 16:09:04 +0300 Subject: [PATCH 22/25] Update RunMigrationsCommandTest.php --- .../Framework/Tests/Cli/RunMigrationsCommandTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/WebFiori/Framework/Tests/Cli/RunMigrationsCommandTest.php b/tests/WebFiori/Framework/Tests/Cli/RunMigrationsCommandTest.php index 0a8adc45b..ba8bd931d 100644 --- a/tests/WebFiori/Framework/Tests/Cli/RunMigrationsCommandTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/RunMigrationsCommandTest.php @@ -160,7 +160,6 @@ public function testExecuteMigrationsWithValidRunner(): void { '--connection' => 'test-connection', '--runner' => 'TestMigrationRunner' ]); - // Debug: Print actual output // The test runner has no migrations, so it should report no migrations found $this->assertContains("Info: No migrations found.\n", $output); $this->assertEquals(0, $this->getExitCode()); @@ -191,7 +190,8 @@ private function createTestMigrationRunner(): void { $code = 'getDBConnection("test-connection"); + parent::__construct($conn); } }'; file_put_contents(APP_PATH . 'TestMigrationRunner.php', $code); @@ -208,7 +208,8 @@ private function createFaultyMigrationRunner(): void { $code = 'getDBConnection("test-connection"); + parent::__construct($conn); throw new \Exception("Test exception"); } }'; From b57b6bc51de36c579cd9a3dd1ebc065e06be18fe Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 18:43:26 +0300 Subject: [PATCH 23/25] fix: Max/Min Values Issue --- WebFiori/Framework/Writers/WebServiceWriter.php | 12 ++++-------- .../Framework/Tests/Cli/CreateWebServiceTest.php | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/WebFiori/Framework/Writers/WebServiceWriter.php b/WebFiori/Framework/Writers/WebServiceWriter.php index ef1a19214..d659e812b 100644 --- a/WebFiori/Framework/Writers/WebServiceWriter.php +++ b/WebFiori/Framework/Writers/WebServiceWriter.php @@ -186,17 +186,13 @@ private function appendParam($param) { } if ($param->getType() == ParamType::INT || $param->getType() == ParamType::DOUBLE) { - $minFloat = defined('PHP_FLOAT_MIN') ? PHP_FLOAT_MIN : 2.2250738585072E-308; - $maxFloat = defined('PHP_FLOAT_MAX') ? PHP_FLOAT_MAX : 1.7976931348623E+308; - - if ($param->getMinValue() !== null && ($param->getMinValue() != $minFloat && $param->getMinValue() != $maxFloat)) { + + if ($param->getMinValue() !== null && $param->getMinValue() != -1e50) { $this->append("ParamOption::MIN => ".$param->getMinValue().",", 4); } - $maxInt = PHP_INT_MAX; - $minInt = defined('PHP_INT_MIN') ? PHP_INT_MIN : ~PHP_INT_MAX; - if ($param->getMaxValue() !== null && ($param->getMaxValue() != $maxInt && $param->getMinValue() != $minInt)) { - $this->append("ParamOption::MAX => ".$param->getMinValue().",", 4); + if ($param->getMaxValue() !== null && $param->getMaxValue() != PHP_INT_MAX && $param->getMaxValue() != 1e50) { + $this->append("ParamOption::MAX => ".$param->getMaxValue().",", 4); } } diff --git a/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php b/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php index 5a1239fc0..ffbe44ae9 100644 --- a/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php +++ b/tests/WebFiori/Framework/Tests/Cli/CreateWebServiceTest.php @@ -206,9 +206,9 @@ public function test01() { ParamOption::DESCRIPTION => 'Random\'s desc', ParamOption::DEFAULT => null, ParamOption::EMPTY => false, - ParamOption::MAX => null, + ParamOption::MAX => 1e50, ParamOption::MAX_LENGTH => null, - ParamOption::MIN => null, + ParamOption::MIN => -1e50, ParamOption::MIN_LENGTH => null, ParamOption::OPTIONAL => false, ]); @@ -319,8 +319,16 @@ private function assertRequestParameter(RequestParameter $param, array $expected $this->assertEquals($expected[ParamOption::DESCRIPTION], $param->getDescription()); $this->assertEquals($expected[ParamOption::MIN_LENGTH], $param->getMinLength()); $this->assertEquals($expected[ParamOption::MAX_LENGTH], $param->getMaxLength()); - $this->assertEquals($expected[ParamOption::MIN], $param->getMinValue()); - $this->assertEquals($expected[ParamOption::MAX], $param->getMaxValue()); + + // Compare MIN/MAX as strings for DOUBLE to avoid PHPUnit Exporter issues with large floats + if ($param->getType() == ParamType::DOUBLE) { + $this->assertEquals((string)$expected[ParamOption::MIN], (string)$param->getMinValue()); + $this->assertEquals((string)$expected[ParamOption::MAX], (string)$param->getMaxValue()); + } else { + $this->assertEquals($expected[ParamOption::MIN], $param->getMinValue()); + $this->assertEquals($expected[ParamOption::MAX], $param->getMaxValue()); + } + $this->assertEquals($expected[ParamOption::EMPTY], $param->isEmptyStringAllowed()); $this->assertEquals($expected[ParamOption::OPTIONAL], $param->isOptional()); $this->assertEquals($expected[ParamOption::DEFAULT], $param->getDefault()); From f318ba4204c45d49717b7dea85f5fbda5645b070 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 14 Jan 2026 18:43:57 +0300 Subject: [PATCH 24/25] fix: Fix Session Tables Creation --- tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php b/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php index 0d5f3549c..97676cae5 100644 --- a/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php +++ b/tests/WebFiori/Framework/Tests/Session/SessionsManagerTest.php @@ -323,7 +323,7 @@ public function testInitSessionsDb() { App::getConfig()->addOrUpdateDBConnection($conn); SessionsManager::reset(); $sto = new DatabaseSessionStorage(); - $sto->getController()->createTables()->execute(); + $sto->getController()->createTables(); $sto->getController()->clear(); $sto->getController()->table('session_data')->selectCount()->execute(); $sto->getController()->table('sessions')->selectCount()->execute(); From 7d230c97f58fc17cd02f723fa6ac361e7a2072ba Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 15 Jan 2026 12:34:10 +0300 Subject: [PATCH 25/25] chore: Update Sonar Config --- sonar-project.properties | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 2d761c3bd..726b07101 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -4,11 +4,8 @@ sonar.organization=webfiori # This is the name and version displayed in the SonarCloud UI. sonar.projectName=framework #sonar.projectVersion=1.0 -sonar.exclusions=app/**, themes/** , tests/**, public/** -sonar.coverage.exclusions=app -sonar.coverage.exclusions=framework/exceptions/**, framework/cli/** , framework/ui/** -sonar.coverage.exclusions=framework/mail/**, framework/cron/** -sonar.coverage.exclusions=framework/ConfigController.php +sonar.exclusions=App/**, Themes/** , tests/**, public/** +sonar.coverage.exclusions=App # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. #sonar.sources=. sonar.php.coverage.reportPaths=clover.xml