diff --git a/ecs.php b/ecs.php index 3ae60220..ff05957f 100644 --- a/ecs.php +++ b/ecs.php @@ -6,13 +6,14 @@ use Symplify\EasyCodingStandard\Config\ECSConfig; use Symplify\EasyCodingStandard\ValueObject\Set\SetList; -return function (ECSConfig $ecsConfig): void { +return function (ECSConfig $ecsConfig): void +{ $ecsConfig->paths([ - __DIR__ . '/app', - __DIR__ . '/public', - __DIR__ . '/tests', - __DIR__ . '/themes', - __DIR__ . '/webfiori', + __DIR__.'/app', + __DIR__.'/public', + __DIR__.'/tests', + __DIR__.'/themes', + __DIR__.'/webfiori', ]); // this way you add a single rule diff --git a/tests/webfiori/framework/test/cli/CreateTableTest.php b/tests/webfiori/framework/test/cli/CreateTableTest.php index 27ca07bf..357aa397 100644 --- a/tests/webfiori/framework/test/cli/CreateTableTest.php +++ b/tests/webfiori/framework/test/cli/CreateTableTest.php @@ -496,6 +496,7 @@ public function testCreateTable05() { $this->assertEquals(DataType::INT, $idCol->getDatatype()); $this->assertTrue($idCol->isPrimary()); $this->assertTrue($idCol->isUnique()); + return $clazz; } /** @@ -546,7 +547,7 @@ public function testCreateTable06($refTable) { $output = $runner->getOutput(); $clazz = '\\app\\database\\Cool06Table'; $this->assertTrue(class_exists($clazz)); - + $this->removeClass($clazz); $this->assertEquals(array_merge([ "Database type:\n", @@ -597,7 +598,7 @@ public function testCreateTable06($refTable) { "Would you like to create an entity class that maps to the database table?(y/N)\n", 'Info: New class was created at "'.ROOT_PATH.DS.'app'.DS."database\".\n", ]), $output); - + $instance = new $clazz(); $instance instanceof Table; $this->assertEquals(1, $instance->getForeignKeysCount()); diff --git a/tests/webfiori/framework/test/cli/RunSQLCommandTest.php b/tests/webfiori/framework/test/cli/RunSQLCommandTest.php index 349f3136..f7b4396a 100644 --- a/tests/webfiori/framework/test/cli/RunSQLCommandTest.php +++ b/tests/webfiori/framework/test/cli/RunSQLCommandTest.php @@ -88,7 +88,6 @@ public function testCLIQuery01() { * @test */ public function testCLIQuery02() { - JsonDriver::setConfigFileName('run-sql-test'); App::setConfigDriver(JsonDriver::class); @@ -97,11 +96,11 @@ public function testCLIQuery02() { App::getConfig()->addOrUpdateDBConnection($conn); $driver = new JsonDriver(); $driver->setConfigFileName('run-sql-test'); - + Controller::setDriver($driver); - + $this->assertTrue(get_class(App::getConfig()) == JsonDriver::class); - + $runner = App::getRunner(); $runner->setArgsVector([ 'webfiori', diff --git a/tests/webfiori/framework/test/cli/SchedulerCommandTest.php b/tests/webfiori/framework/test/cli/SchedulerCommandTest.php index a0b436d1..be96bea3 100644 --- a/tests/webfiori/framework/test/cli/SchedulerCommandTest.php +++ b/tests/webfiori/framework/test/cli/SchedulerCommandTest.php @@ -184,6 +184,7 @@ public function test05() { "Skip"]; $actual = $runner->getOutput(); $idx = 0; + foreach ($expected as $item) { if ($item == 'Skip') { break; diff --git a/tests/webfiori/framework/test/router/RouterTest.php b/tests/webfiori/framework/test/router/RouterTest.php index 97d8b122..ceab4fe2 100644 --- a/tests/webfiori/framework/test/router/RouterTest.php +++ b/tests/webfiori/framework/test/router/RouterTest.php @@ -25,13 +25,13 @@ public function test00() { */ public function testAddAPIRoute00() { $this->assertTrue(Router::api([ - RouteOption::PATH => '/call-api-00', - RouteOption::TO => '/my-api.php'])); + RouteOption::PATH => '/call-api-00', + RouteOption::TO => '/my-api.php'])); $this->assertFalse(Router::page([ - RouteOption::PATH => '/call-api-00', - RouteOption::TO => '/my-other-api.php'])); + RouteOption::PATH => '/call-api-00', + RouteOption::TO => '/my-other-api.php'])); $this->assertTrue(Router::page([ - RouteOption::PATH => '/call-api-01', + RouteOption::PATH => '/call-api-01', RouteOption::TO => '/my-api.php'])); } /** @@ -45,20 +45,20 @@ public function testAddClosureRoute00() { { }; $this->assertTrue(Router::closure([ - RouteOption::PATH => '/call', - RouteOption::TO => $c1 + RouteOption::PATH => '/call', + RouteOption::TO => $c1 ])); $this->assertFalse(Router::closure([ - RouteOption::PATH => '/call', - RouteOption::TO => $c2 + RouteOption::PATH => '/call', + RouteOption::TO => $c2 ])); $this->assertTrue(Router::closure([ - RouteOption::PATH => '/call-2', - RouteOption::TO => $c1 + RouteOption::PATH => '/call-2', + RouteOption::TO => $c1 ])); $this->assertFalse(Router::closure([ - RouteOption::PATH => '/call', - RouteOption::TO => 'Not Func' + RouteOption::PATH => '/call', + RouteOption::TO => 'Not Func' ])); } /** @@ -66,14 +66,14 @@ public function testAddClosureRoute00() { */ public function testAddViewRoute00() { $this->assertTrue(Router::page([ - RouteOption::PATH => '/view-something', - RouteOption::TO => 'my-view.php'])); + RouteOption::PATH => '/view-something', + RouteOption::TO => 'my-view.php'])); $this->assertFalse(Router::page([ - RouteOption::PATH => '/view-something', - RouteOption::TO => '/my-other-view.php'])); + RouteOption::PATH => '/view-something', + RouteOption::TO => '/my-other-view.php'])); $this->assertTrue(Router::page([ - RouteOption::PATH => '/view-something-2', - RouteOption::TO => '/my-view.php'])); + RouteOption::PATH => '/view-something-2', + RouteOption::TO => '/my-view.php'])); } /** * @test @@ -84,8 +84,8 @@ public function testOptionalParam00() { { }); Router::closure([ - RouteOption::PATH => '{var-1}/{var-2?}', - RouteOption::TO => function() + RouteOption::PATH => '{var-1}/{var-2?}', + RouteOption::TO => function() { }, RouteOption::VALUES => [ @@ -110,8 +110,8 @@ public function testOptionalParam01() { Router::removeAll(); Router::closure([ - RouteOption::PATH => '{var-1}/{var-2?}', - RouteOption::TO => function() + RouteOption::PATH => '{var-1}/{var-2?}', + RouteOption::TO => function() { } ]); @@ -132,8 +132,8 @@ public function testRoute00() { { }); Router::closure([ - RouteOption::PATH => '{var-1}/{var-2}', - RouteOption::TO => function() + RouteOption::PATH => '{var-1}/{var-2}', + RouteOption::TO => function() { } ]); @@ -155,8 +155,8 @@ public function testRoute01() { { }); Router::closure([ - RouteOption::PATH => '{var-1}/{var-2}/{var-1}', - RouteOption::TO => function() + RouteOption::PATH => '{var-1}/{var-2}/{var-1}', + RouteOption::TO => function() { } ]); @@ -172,37 +172,37 @@ public function testRoute01() { public function testRoutesGroup00() { Router::removeAll(); Router::page([ - RouteOption::PATH => 'users', + RouteOption::PATH => 'users', RouteOption::CASE_SENSITIVE => false, RouteOption::MIDDLEWARE => 'M1', RouteOption::LANGS => ['EN'], RouteOption::REQUEST_METHODS => RequestMethod::POST, - RouteOption::SUB_ROUTES => [ + RouteOption::SUB_ROUTES => [ [ - RouteOption::PATH => 'view-user/{user-id}', - RouteOption::TO => 'ViewUserPage.php', - RouteOption::LANGS => ['AR'] + RouteOption::PATH => 'view-user/{user-id}', + RouteOption::TO => 'ViewUserPage.php', + RouteOption::LANGS => ['AR'] ], [ - RouteOption::PATH => 'get-users', - RouteOption::LANGS => ['AR'], + RouteOption::PATH => 'get-users', + RouteOption::LANGS => ['AR'], RouteOption::CASE_SENSITIVE => true, - RouteOption::SUB_ROUTES => [ + RouteOption::SUB_ROUTES => [ [ - RouteOption::PATH => 'by-name', - RouteOption::TO => 'GetUserByName.php', - RouteOption::LANGS => ['FR'], + RouteOption::PATH => 'by-name', + RouteOption::TO => 'GetUserByName.php', + RouteOption::LANGS => ['FR'], RouteOption::CASE_SENSITIVE => false, ], [ - RouteOption::PATH => 'by-email', - RouteOption::TO => 'GetUserByEmail.php' + RouteOption::PATH => 'by-email', + RouteOption::TO => 'GetUserByEmail.php' ] ], ], [ - RouteOption::PATH => '/', - RouteOption::TO => 'ListUsers.php', + RouteOption::PATH => '/', + RouteOption::TO => 'ListUsers.php', RouteOption::CASE_SENSITIVE => true, RouteOption::REQUEST_METHODS => [RequestMethod::OPTIONS, RequestMethod::GET] ] diff --git a/webfiori/framework/App.php b/webfiori/framework/App.php index 90d2e972..c6c33018 100644 --- a/webfiori/framework/App.php +++ b/webfiori/framework/App.php @@ -45,31 +45,6 @@ * */ class App { - /** - * Sets the class that will be used as configuration driver. - * - * This method must be used before calling the method 'App::start()' in order - * to set proper configuration driver. - * - * @param string $clazz The full name of the class including namespace. - */ - public static function setConfigDriver(string $clazz) { - self::$ConfigDriver = $clazz; - } - /** - * Returns the class that represents configuration driver. - * - * @return string The full name of the class including namespace. - */ - public static function getConfigDriver() : string { - return self::$ConfigDriver; - } - /** - * A string which points to the class that represents configuration driver. - * - * @var string - */ - private static $ConfigDriver = 'webfiori\\framework\\config\\ClassDriver'; /** * A constant that indicates that the status of the class is 'initialized'. * @@ -106,6 +81,12 @@ public static function getConfigDriver() : string { * @var Runner */ private static $CliRunner; + /** + * A string which points to the class that represents configuration driver. + * + * @var string + */ + private static $ConfigDriver = 'webfiori\\framework\\config\\ClassDriver'; /** * A single instance of the class. * @@ -295,14 +276,23 @@ public static function getClassStatus() { */ public static function getConfig(): ConfigurationDriver { $driver = Controller::getDriver(); - + if (get_class($driver) != self::$ConfigDriver) { Controller::setDriver(new self::$ConfigDriver()); Controller::get()->updateEnv(); $driver = Controller::getDriver(); } + return $driver; } + /** + * Returns the class that represents configuration driver. + * + * @return string The full name of the class including namespace. + */ + public static function getConfigDriver() : string { + return self::$ConfigDriver; + } /** * Returns an instance which represents the class that is used to run the @@ -368,6 +358,17 @@ public static function getRunner() : Runner { return self::$CliRunner; } + /** + * Sets the class that will be used as configuration driver. + * + * This method must be used before calling the method 'App::start()' in order + * to set proper configuration driver. + * + * @param string $clazz The full name of the class including namespace. + */ + public static function setConfigDriver(string $clazz) { + self::$ConfigDriver = $clazz; + } /** * Start your WebFiori application. @@ -420,7 +421,7 @@ private function checkAppDir() { /** * Directory separator. */ - define('DS', DIRECTORY_SEPARATOR); + define('DS', DIRECTORY_SEPARATOR); } if (!defined('APP_DIR')) { @@ -437,13 +438,14 @@ private function checkAppDir() { http_response_code(500); die('Error: Unable to initialize the application. Invalid application directory name: "'.APP_DIR.'".'); } + if (!defined('APP_PATH')) { /** * The absolute path to application directory. * * @var string */ - define('APP_PATH', ROOT_PATH.DIRECTORY_SEPARATOR.APP_DIR.DIRECTORY_SEPARATOR); + define('APP_PATH', ROOT_PATH.DIRECTORY_SEPARATOR.APP_DIR.DIRECTORY_SEPARATOR); } } diff --git a/webfiori/framework/DB.php b/webfiori/framework/DB.php index 56c8f5c2..caa6a3ed 100644 --- a/webfiori/framework/DB.php +++ b/webfiori/framework/DB.php @@ -62,7 +62,7 @@ public function __construct($connName) { } if (!($conn instanceof ConnectionInfo)) { - throw new DatabaseException("No connection was found which has the name '$connName'. Driver: ". get_class(App::getConfig()).'.'); + throw new DatabaseException("No connection was found which has the name '$connName'. Driver: ".get_class(App::getConfig()).'.'); } } parent::__construct($conn); diff --git a/webfiori/framework/EmailMessage.php b/webfiori/framework/EmailMessage.php index 859f5585..978fc46e 100644 --- a/webfiori/framework/EmailMessage.php +++ b/webfiori/framework/EmailMessage.php @@ -10,10 +10,10 @@ */ namespace webfiori\framework; +use webfiori\email\Email; use webfiori\email\exceptions\SMTPException; use webfiori\email\SMTPAccount; use webfiori\framework\exceptions\MissingLangException; -use webfiori\email\Email; /** * A class that can be used to write HTML formatted Email messages. * @@ -82,13 +82,12 @@ public function getTranslation() { * * @return Email The method will return same instance at which the method is * called on. - * + * * @throws MissingLangException */ public function setLang(string $lang = 'EN') : Email { if (parent::setLang($lang)) { $this->usingLanguage(); - } return $this; diff --git a/webfiori/framework/Ini.php b/webfiori/framework/Ini.php index e79a5c95..8ead27dc 100644 --- a/webfiori/framework/Ini.php +++ b/webfiori/framework/Ini.php @@ -34,10 +34,32 @@ class Ini { */ private static $singleton; private function __construct() { - } - + + /** + * Creates all directories at which the application needs to run. + */ + public static function createAppDirs() { + $DS = DIRECTORY_SEPARATOR; + self::mkdir(ROOT_PATH.$DS.APP_DIR); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'ini'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'ini'.$DS.'routes'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'pages'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'commands'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'tasks'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'middleware'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'langs'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'apis'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'config'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'.$DS.'uploads'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'.$DS.'logs'); + self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'.$DS.'sessions'); + self::mkdir(ROOT_PATH.$DS.'public'); + } + + /** * Creates initialization class. @@ -126,29 +148,6 @@ public static function get(): Ini { return self::$singleton; } - - - /** - * Creates all directories at which the application needs to run. - */ - public static function createAppDirs() { - $DS = DIRECTORY_SEPARATOR; - self::mkdir(ROOT_PATH.$DS.APP_DIR); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'ini'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'ini'.$DS.'routes'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'pages'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'commands'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'tasks'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'middleware'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'langs'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'apis'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'config'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'.$DS.'uploads'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'.$DS.'logs'); - self::mkdir(ROOT_PATH.$DS.APP_DIR.$DS.'sto'.$DS.'sessions'); - self::mkdir(ROOT_PATH.$DS.'public'); - } public static function mkdir($dir) { if (!is_dir($dir)) { set_error_handler(function (int $errno, string $errstr) diff --git a/webfiori/framework/ThemeLoader.php b/webfiori/framework/ThemeLoader.php index 2b1b1ed1..9056e06c 100644 --- a/webfiori/framework/ThemeLoader.php +++ b/webfiori/framework/ThemeLoader.php @@ -55,7 +55,7 @@ private function __construct() { * * This method will return an associative array. The key is the theme * name and the value is an object of type Theme that contains theme info. - * + * * @param bool $updateCache If set to true, cached data of descovered themes * will reset and search will be performed again. * @@ -251,7 +251,7 @@ private static function scanDir($filesInDir, $pathToScan, $dirName) { $ns = require_once $pathToScan.DS.$fileName; $aNs = gettype($ns) == 'string' ? $ns.'\\' : '\\'; $aCName = $aNs.$cName; - + if (!class_exists($aCName)) { $aCName = '\\'.self::THEMES_DIR.'\\'.$dirName.'\\'.$cName; } diff --git a/webfiori/framework/cli/helpers/CreateWebService.php b/webfiori/framework/cli/helpers/CreateWebService.php index fd501530..9cca0a82 100644 --- a/webfiori/framework/cli/helpers/CreateWebService.php +++ b/webfiori/framework/cli/helpers/CreateWebService.php @@ -33,6 +33,21 @@ public function __construct(CreateCommand $command) { $this->serviceObj = new ServiceHolder(); parent::__construct($command, new WebServiceWriter($this->serviceObj)); } + public function addRequestMethods() { + $toSelect = RequestMethod::getAll(); + $addOne = true; + + while ($addOne) { + array_multisort($toSelect); + $this->serviceObj->addRequestMethod($this->select('Request method:', $toSelect, 2)); + + if (count($toSelect) > 1) { + $addOne = $this->confirm('Would you like to add another request method?', false); + } else { + $addOne = false; + } + } + } public function readClassInfo() { $this->setClassInfo(APP_DIR.'\\apis', 'Service'); @@ -48,21 +63,6 @@ public function readClassInfo() { $this->writeClass(); $this->info('Don\'t forget to add the service to a services manager.'); } - public function addRequestMethods() { - $toSelect = RequestMethod::getAll(); - $addOne = true; - - while ($addOne) { - - array_multisort($toSelect); - $this->serviceObj->addRequestMethod($this->select('Request method:', $toSelect, 2)); - if (count($toSelect) > 1) { - $addOne = $this->confirm('Would you like to add another request method?', false); - } else { - $addOne = false; - } - } - } private function addParamsToService() { do { $paramObj = new RequestParameter('h'); @@ -71,14 +71,16 @@ private function addParamsToService() { $paramObj->setDescription($this->getInput('Description:')); $added = $this->serviceObj->addParameter($paramObj); $paramObj->setIsOptional($this->confirm('Is this parameter optional?', true)); + if ($paramObj->getType() == ParamType::STRING || $paramObj->getType() == ParamType::URL || $paramObj->getType() == ParamType::EMAIL) { $paramObj->setIsEmptyStringAllowed($this->confirm('Are empty values allowed?', false)); $this->setMinAndMaxLength($paramObj); } + if ($paramObj->getType() == ParamType::INT || $paramObj->getType() == ParamType::DOUBLE) { $this->setMinAndMax($paramObj); } - + if ($added) { $this->success('New parameter added.'); } else { @@ -87,41 +89,43 @@ private function addParamsToService() { $addMore = $this->confirm('Would you like to add another parameter?', false); } while ($addMore); } - private function setMinAndMaxLength(RequestParameter $param) { - $setMinMax = $this->confirm('Would you like to set minimum and maximum length?', false); - + private function setMinAndMax(RequestParameter $param) { + $setMinMax = $this->confirm('Would you like to set minimum and maximum limites?', false); + if (!$setMinMax) { return; } $isValid = false; - + $method = $param->getType() == ParamType::INT ? 'readInteger' : 'readFloat'; + while (!$isValid) { - $min = $this->getCommand()->readInteger('Minimum length:'); - $max = $this->getCommand()->readInteger('Maximum length:'); + $min = $this->getCommand()->$method('Minimum value:'); + $max = $this->getCommand()->$method('Maximum value:'); + if ($min < $max) { - $param->setMinLength($min); - $param->setMaxLength($max); + $param->setMinValue($min); + $param->setMaxValue($max); $isValid = true; } else { $this->error('Minimum and maximum should not overlap.'); } } } - private function setMinAndMax(RequestParameter $param) { - $setMinMax = $this->confirm('Would you like to set minimum and maximum limites?', false); - + private function setMinAndMaxLength(RequestParameter $param) { + $setMinMax = $this->confirm('Would you like to set minimum and maximum length?', false); + if (!$setMinMax) { return; } $isValid = false; - $method = $param->getType() == ParamType::INT ? 'readInteger' : 'readFloat'; - + while (!$isValid) { - $min = $this->getCommand()->$method('Minimum value:'); - $max = $this->getCommand()->$method('Maximum value:'); + $min = $this->getCommand()->readInteger('Minimum length:'); + $max = $this->getCommand()->readInteger('Maximum length:'); + if ($min < $max) { - $param->setMinValue($min); - $param->setMaxValue($max); + $param->setMinLength($min); + $param->setMaxLength($max); $isValid = true; } else { $this->error('Minimum and maximum should not overlap.'); diff --git a/webfiori/framework/config/ClassDriver.php b/webfiori/framework/config/ClassDriver.php index 90236dc7..43b3209d 100644 --- a/webfiori/framework/config/ClassDriver.php +++ b/webfiori/framework/config/ClassDriver.php @@ -33,6 +33,26 @@ public function __construct() { $this->docEmptyLine = " * "; $this->initDefaultConfig(); } + public static function a($file, $str, $tabSize = 0) { + $isResource = is_resource($file); + $tabStr = $tabSize > 0 ? ' ' : ''; + + if (gettype($str) == 'array') { + foreach ($str as $subStr) { + if ($isResource) { + fwrite($file, str_repeat($tabStr, $tabSize).$subStr.self::NL); + } else { + $file->append(str_repeat($tabStr, $tabSize).$subStr.self::NL); + } + } + } else { + if ($isResource) { + fwrite($file, str_repeat($tabStr, $tabSize).$str.self::NL); + } else { + $file->append(str_repeat($tabStr, $tabSize).$str.self::NL); + } + } + } /** * Adds application environment variable to the configuration. * @@ -54,15 +74,6 @@ public function addEnvVar(string $name, $value, string $description = null) { ]; $this->writeAppConfig(); } - /** - * Removes specific application environment variable given its name. - * - * @param string $name The name of the variable. - */ - public function removeEnvVar(string $name) { - unset($this->configVars['env-vars'][$name]); - $this->writeAppConfig(); - } /** * Adds new database connections information or update existing connection. * @@ -362,6 +373,15 @@ public function removeDBConnection(string $connectionName) { $this->configVars['database-connections'] = $updated; $this->writeAppConfig(); } + /** + * Removes specific application environment variable given its name. + * + * @param string $name The name of the variable. + */ + public function removeEnvVar(string $name) { + unset($this->configVars['env-vars'][$name]); + $this->writeAppConfig(); + } public function removeSMTPAccount(string $accountName) { if (isset($this->configVars['smtp-connections'][$accountName])) { @@ -861,26 +881,6 @@ public function writeAppConfig() { self::a($cFile, "}"); $cFile->write(false, true); } - public static function a($file, $str, $tabSize = 0) { - $isResource = is_resource($file); - $tabStr = $tabSize > 0 ? ' ' : ''; - - if (gettype($str) == 'array') { - foreach ($str as $subStr) { - if ($isResource) { - fwrite($file, str_repeat($tabStr, $tabSize).$subStr.self::NL); - } else { - $file->append(str_repeat($tabStr, $tabSize).$subStr.self::NL); - } - } - } else { - if ($isResource) { - fwrite($file, str_repeat($tabStr, $tabSize).$str.self::NL); - } else { - $file->append(str_repeat($tabStr, $tabSize).$str.self::NL); - } - } - } private function initDefaultConfig() { $this->configVars = [ 'smtp-connections' => [], diff --git a/webfiori/framework/config/ConfigurationDriver.php b/webfiori/framework/config/ConfigurationDriver.php index 40fcd411..367eade9 100644 --- a/webfiori/framework/config/ConfigurationDriver.php +++ b/webfiori/framework/config/ConfigurationDriver.php @@ -27,12 +27,6 @@ interface ConfigurationDriver { * of the constant. */ public function addEnvVar(string $name, $value, string $description = null); - /** - * Removes specific application environment variable given its name. - * - * @param string $name The name of the variable. - */ - public function removeEnvVar(string $name); /** * Adds new database connections information or update existing connections. * @@ -257,6 +251,12 @@ public function removeAllDBConnections(); * */ public function removeDBConnection(string $connectionName); + /** + * Removes specific application environment variable given its name. + * + * @param string $name The name of the variable. + */ + public function removeEnvVar(string $name); /** * Removes SMTP account if it exists. * diff --git a/webfiori/framework/config/JsonDriver.php b/webfiori/framework/config/JsonDriver.php index e457b380..4fd096fc 100644 --- a/webfiori/framework/config/JsonDriver.php +++ b/webfiori/framework/config/JsonDriver.php @@ -19,10 +19,6 @@ * @author Ibrahim */ class JsonDriver implements ConfigurationDriver { - /** - * The name of JSON configuration file. - */ - private static $configFileName = 'app-config'; /** * The location at which the configuration file will be kept at. * @@ -30,29 +26,9 @@ class JsonDriver implements ConfigurationDriver { */ const JSON_CONFIG_FILE_PATH = APP_PATH.'config'.DIRECTORY_SEPARATOR; /** - * Sets the name of the file that configuration values will be taken from. - * - * The file must exist on the directory [APP_PATH]/config/ . - * - * @param string $name - */ - public static function setConfigFileName(string $name) { - $split = explode('.', trim($name)); - if (count($split) == 2) { - self::$configFileName = $split[0]; - } else if (count($split) == 1) { - self::$configFileName = trim($name); - } - } - /** - * Returns the name of the file at which the application is using to - * read configuration. - * - * @return string + * The name of JSON configuration file. */ - public static function getConfigFileName() : string { - return self::$configFileName; - } + private static $configFileName = 'app-config'; private $json; /** * Creates new instance of the class. @@ -118,15 +94,6 @@ public function addEnvVar(string $name, $value, string $description = null) { ])); $this->writeJson(); } - /** - * Removes specific application environment variable given its name. - * - * @param string $name The name of the variable. - */ - public function removeEnvVar(string $name) { - $this->json->get('env-vars')->remove($name); - $this->writeJson(); - } public function addOrUpdateDBConnection(ConnectionInfo $dbConnectionsInfo) { $connectionJAsJson = new Json([ 'type' => $dbConnectionsInfo->getDatabaseType(), @@ -190,19 +157,30 @@ public function getAppVersionType() : string { } /** * Returns the base URL of the application. - * + * * Note that if the base is set so 'DYNAMIC' in the configuration, it will * be auto-generated at run time. - * + * * @return string A string such as 'http://example.com:8989'. */ public function getBaseURL(): string { $val = $this->json->get('base-url'); + if ($val == '' || $val == 'DYNAMIC') { return Uri::getBaseURL(); } + return $val; } + /** + * Returns the name of the file at which the application is using to + * read configuration. + * + * @return string + */ + public static function getConfigFileName() : string { + return self::$configFileName; + } public function getDBConnection(string $conName) { $jsonObj = $this->json->get('database-connections')->get($conName); @@ -210,11 +188,13 @@ public function getDBConnection(string $conName) { if ($jsonObj !== null) { $extras = $jsonObj->get('extras'); $extrasArr = []; + if ($extras instanceof Json) { foreach ($extras->getProperties() as $prop) { $extrasArr[$prop->getName()] = $prop->getValue(); } } + return new ConnectionInfo( $jsonObj->get('type'), $jsonObj->get('username'), @@ -239,15 +219,15 @@ public function getDBConnections(): array { $name = $propObj->getName(); $jsonObj = $propObj->getValue(); $acc = new ConnectionInfo( - $this->getProp($jsonObj, 'type', $name), - $this->getProp($jsonObj, 'username', $name), - $this->getProp($jsonObj, 'password', $name), - $this->getProp($jsonObj, 'database', $name)); + $this->getProp($jsonObj, 'type', $name), + $this->getProp($jsonObj, 'username', $name), + $this->getProp($jsonObj, 'password', $name), + $this->getProp($jsonObj, 'database', $name)); $extrasObj = $jsonObj->get('extras'); - + if ($extrasObj !== null && $extrasObj instanceof Json) { $extrasArr = []; - + foreach ($extrasObj->getProperties() as $prop) { $extrasArr[$prop->getName()] = $prop->getValue(); } @@ -261,13 +241,6 @@ public function getDBConnections(): array { return $retVal; } - private function getProp(Json $j, $name, string $connName) { - $val = $j->get($name); - if ($val === null) { - throw new InitializationException('The property "'.$name.'" of the connection "'.$connName.'" is missing.'); - } - return $val; - } public function getDescription(string $langCode) { return $this->json->get('app-descriptions')->get(strtoupper(trim($langCode))); @@ -305,17 +278,19 @@ public function getEnvVars(): array { } /** * Returns a string that represent the home page of the application. - * + * * Note that if home page is set to 'BASE_URL' in configuration, the * method will use the base URL as the home page. - * + * * @return string */ public function getHomePage() : string { $home = $this->json->get('home-page') ?? ''; + if ($home == 'BASE_URL') { return $this->getBaseURL(); } + return $home; } @@ -367,7 +342,7 @@ public function getSMTPConnection(string $name) { } /** * Returns an array that contains all added SMTP accounts. - * + * * @return array An array that contains all added SMTP accounts. */ public function getSMTPConnections(): array { @@ -406,11 +381,11 @@ public function getTheme(): string { public function getTitle(string $lang) : string { $titles = $this->json->get('titles'); $langU = strtoupper(trim($lang)); - + if (strlen($langU) == 0) { return ''; } - + foreach ($titles->getProperties() as $prob) { if ($prob->getName() == $langU) { return $prob->getValue(); @@ -465,6 +440,15 @@ public function removeAllDBConnections() { public function removeDBConnection(string $connectionName) { } + /** + * Removes specific application environment variable given its name. + * + * @param string $name The name of the variable. + */ + public function removeEnvVar(string $name) { + $this->json->get('env-vars')->remove($name); + $this->writeJson(); + } public function removeSMTPAccount(string $accountName) { $this->json->add('smtp-connections', new Json()); @@ -509,6 +493,22 @@ public function setAppVersion(string $vNum, string $vType, string $releaseDate) public function setBaseURL(string $url) { } + /** + * Sets the name of the file that configuration values will be taken from. + * + * The file must exist on the directory [APP_PATH]/config/ . + * + * @param string $name + */ + public static function setConfigFileName(string $name) { + $split = explode('.', trim($name)); + + if (count($split) == 2) { + self::$configFileName = $split[0]; + } else if (count($split) == 1) { + self::$configFileName = trim($name); + } + } /** * Sets or update default description of the application that will be used * by web pages. @@ -595,7 +595,7 @@ public function setTitle(string $title, string $langCode) { return; } $trimmedTitle = trim($title); - + if (strlen($trimmedTitle) == 0) { return; } @@ -612,7 +612,7 @@ public function setTitle(string $title, string $langCode) { */ public function setTitleSeparator(string $separator) { $trimmed = trim($separator); - + if (strlen($trimmed) != 0) { $this->json->add('name-separator', $separator); $this->writeJson(); @@ -621,6 +621,15 @@ public function setTitleSeparator(string $separator) { public function toJSON() : Json { return $this->json; } + private function getProp(Json $j, $name, string $connName) { + $val = $j->get($name); + + if ($val === null) { + throw new InitializationException('The property "'.$name.'" of the connection "'.$connName.'" is missing.'); + } + + return $val; + } private function isValidLangCode($langCode) { $code = strtoupper(trim($langCode)); @@ -638,6 +647,4 @@ private function writeJson() { $file->setRawData($json.''); $file->write(false, true); } - - } diff --git a/webfiori/framework/router/RouteOption.php b/webfiori/framework/router/RouteOption.php index c97bc121..0a3827d7 100644 --- a/webfiori/framework/router/RouteOption.php +++ b/webfiori/framework/router/RouteOption.php @@ -8,7 +8,6 @@ * https://github.com/WebFiori/.github/blob/main/LICENSE * */ - namespace webfiori\framework\router; /** @@ -18,55 +17,55 @@ */ class RouteOption { /** - * An option that represents the path part of the URI. - */ - const PATH = 'path'; - /** - * An option which is used to set the resource at which the route will point to. + * An option which is used to set the name of controller action that will be invoked (MVC). */ - const TO = 'route-to'; + const ACTION = 'action'; /** - * An option which is used to set route type. + * An option which is used to treat the route as an API call. */ - const TYPE = 'type'; + const API = 'as-api'; /** * An option which is used to indicate if path is case sensitive or not. */ const CASE_SENSITIVE = 'case-sensitive'; /** - * An option which is used to tell if the route should be part of auto-generated sitemap or not. + * An option which is used to set an array as closure parameters (applies to routes of type closure only) */ - const SITEMAP = 'in-sitemap'; + const CLOSURE_PARAMS = 'closure-params'; /** - * An option which is used to treat the route as an API call. + * An option which is used to set the languages at which the route will be available at (used in building sitemap). */ - const API = 'as-api'; + const LANGS = 'languages'; /** - * An option which is used to set an array as closure parameters (applies to routes of type closure only) + * An option which is used to set the middleware that will be applied to the route. */ - const CLOSURE_PARAMS = 'closure-params'; + const MIDDLEWARE = 'middleware'; /** - * An option which is used to set the name of controller action that will be invoked (MVC). + * An option that represents the path part of the URI. */ - const ACTION = 'action'; + const PATH = 'path'; /** * An option which is used to set an array of allowed request methods. */ const REQUEST_METHODS = 'methods'; /** - * An option which is used to set the languages at which the route will be available at (used in building sitemap). + * An option which is used to tell if the route should be part of auto-generated sitemap or not. */ - const LANGS = 'languages'; + const SITEMAP = 'in-sitemap'; /** - * An option which is used to set an array of allowed values to route parameters. + * An option which is used to set sub-routes. */ - const VALUES = 'vars-values'; + const SUB_ROUTES = 'routes'; /** - * An option which is used to set the middleware that will be applied to the route. + * An option which is used to set the resource at which the route will point to. */ - const MIDDLEWARE = 'middleware'; + const TO = 'route-to'; /** - * An option which is used to set sub-routes. + * An option which is used to set route type. */ - const SUB_ROUTES = 'routes'; + const TYPE = 'type'; + /** + * An option which is used to set an array of allowed values to route parameters. + */ + const VALUES = 'vars-values'; } diff --git a/webfiori/framework/router/Router.php b/webfiori/framework/router/Router.php index 795eed6c..3285bf05 100644 --- a/webfiori/framework/router/Router.php +++ b/webfiori/framework/router/Router.php @@ -1103,6 +1103,16 @@ private function fixUriPath(string $path): string { return $path; } + private function getFileDirAndName($absDir): array { + $explode = explode(DS, $absDir); + $fileName = $explode[count($explode) - 1]; + $dir = substr($absDir, 0, strlen($absDir) - strlen($fileName)); + + return [ + 'name' => $fileName, + 'dir' => $dir + ]; + } /** * Creates and Returns a single instance of the router. * @@ -1118,16 +1128,6 @@ private static function getInstance(): Router { return self::$router; } - private function getFileDirAndName($absDir): array { - $explode = explode(DS, $absDir); - $fileName = $explode[count($explode) - 1]; - $dir = substr($absDir, 0, strlen($absDir) - strlen($fileName)); - - return [ - 'name' => $fileName, - 'dir' => $dir - ]; - } /** * Returns an array that holds allowed request methods for fetching the * specified resource. diff --git a/webfiori/framework/scheduler/TasksManager.php b/webfiori/framework/scheduler/TasksManager.php index 142ea81f..932a0f4a 100644 --- a/webfiori/framework/scheduler/TasksManager.php +++ b/webfiori/framework/scheduler/TasksManager.php @@ -281,6 +281,20 @@ public static function get(): TasksManager { return self::$tasksManager; } + /** + * Returns the number of current hour in the day as integer. + * + * This method is used by the class 'AbstractTask' to validate task + * execution time. The method will always return a value between 0 and 23 + * inclusive. + * + * @return int An integer that represents current hour number in + * the day. + * @since 1.0.2 + */ + public static function getHour() : int { + return self::get()->timestamp['hour']; + } /** * Returns the array that contains logged messages. * @@ -294,6 +308,48 @@ public static function get(): TasksManager { public static function getLogArray() : array { return self::get()->logsArray; } + /** + * Returns the number of current minute in the current hour as integer. + * + * This method is used by the class 'AbstractTask' to validate task + * execution time. The method will always return a value between 0 and 59 + * inclusive. + * + * @return int An integer that represents current minute number in + * the current hour. + * + * @since 1.0.2 + */ + public static function getMinute() : int { + return self::get()->timestamp['minute']; + } + /** + * Returns the number of current month as integer. + * + * This method is used by the class 'AbstracTask' to validate task + * execution time. The method will always return a value between 1 and 12 + * inclusive. + * + * @return int An integer that represents current month's number. + * @since 1.0.2 + */ + public static function getMonth() : int { + return self::get()->timestamp['month']; + } + /** + * Gets the password that is used to protect tasks execution. + * + * The password is used to prevent unauthorized access to execute tasks. + * The provided password must be 'sha256' hashed string. It is recommended + * to hash the password externally then use the hash inside your code. + * + * @return string If the password is set, the method will return it. + * If not set, the method will return the string 'NO_PASSWORD'. + * + */ + public static function getPassword() : string { + return self::get()->getPasswordHelper(); + } /** * Returns a task given its name. * @@ -338,18 +394,42 @@ public static function getTasksNames() : array { return self::get()->tasksNamesArr; } /** - * Returns the number of current hour in the day as integer. + * Returns the time at which tasks check was initialized. * - * This method is used by the class 'AbstractTask' to validate task - * execution time. The method will always return a value between 0 and 23 - * inclusive. + * @return string The method will return a time string in the format + * 'YY-DD HH:MM' where: + * * - * @return int An integer that represents current hour number in - * the day. - * @since 1.0.2 + * @since 1.0.7 */ - public static function getHour() : int { - return self::get()->timestamp['hour']; + public static function getTimestamp() : string { + $month = self::getMonth(); + + if ($month < 10) { + $month = '0'.$month; + } + $day = self::dayOfMonth(); + + if ($day < 10) { + $day = '0'.$day; + } + $hour = self::getHour(); + + if ($hour < 10) { + $hour = '0'.$hour; + } + $minute = self::getMinute(); + + if ($minute < 10) { + $minute = '0'.$minute; + } + + return $month.'-'.$day.' '.$hour.':'.$minute; } /** * Creates routes to tasks web interface pages. @@ -409,34 +489,6 @@ public static function log(string $message) { self::get()->command->println("%s", $message); } } - /** - * Returns the number of current minute in the current hour as integer. - * - * This method is used by the class 'AbstractTask' to validate task - * execution time. The method will always return a value between 0 and 59 - * inclusive. - * - * @return int An integer that represents current minute number in - * the current hour. - * - * @since 1.0.2 - */ - public static function getMinute() : int { - return self::get()->timestamp['minute']; - } - /** - * Returns the number of current month as integer. - * - * This method is used by the class 'AbstracTask' to validate task - * execution time. The method will always return a value between 1 and 12 - * inclusive. - * - * @return int An integer that represents current month's number. - * @since 1.0.2 - */ - public static function getMonth() : int { - return self::get()->timestamp['month']; - } /** * Create a task that will be executed once every month. * @@ -479,33 +531,6 @@ public static function monthlyTask(int $dayNumber, string $time, string $name, c return false; } - /** - * Gets the password that is used to protect tasks execution. - * - * The password is used to prevent unauthorized access to execute tasks. - * The provided password must be 'sha256' hashed string. It is recommended - * to hash the password externally then use the hash inside your code. - * - * @return string If the password is set, the method will return it. - * If not set, the method will return the string 'NO_PASSWORD'. - * - */ - public static function getPassword() : string { - - return self::get()->getPasswordHelper(); - } - /** - * Sets the password that is used to protect tasks execution. - * - * The password is used to prevent unauthorized access to execute tasks. - * The provided password must be 'sha256' hashed string. It is recommended - * to hash the password externally then use the hash inside your code. - * - * @param string $pass The password that will be used. - */ - public static function setPassword(string $pass) { - self::get()->setPasswordHelper($pass); - } /** * Register any task which exist in the folder 'tasks' of the application. * @@ -719,52 +744,26 @@ public static function setMonth(int $month) { } } /** - * Returns a queue of all queued tasks. + * Sets the password that is used to protect tasks execution. * - * @return Queue An object of type 'Queue' which contains all queued tasks. + * The password is used to prevent unauthorized access to execute tasks. + * The provided password must be 'sha256' hashed string. It is recommended + * to hash the password externally then use the hash inside your code. * - * @since 1.0 + * @param string $pass The password that will be used. */ - public static function tasksQueue() : Queue { - return self::get()->getQueueHelper(); + public static function setPassword(string $pass) { + self::get()->setPasswordHelper($pass); } /** - * Returns the time at which tasks check was initialized. + * Returns a queue of all queued tasks. * - * @return string The method will return a time string in the format - * 'YY-DD HH:MM' where: - * + * @return Queue An object of type 'Queue' which contains all queued tasks. * - * @since 1.0.7 + * @since 1.0 */ - public static function getTimestamp() : string { - $month = self::getMonth(); - - if ($month < 10) { - $month = '0'.$month; - } - $day = self::dayOfMonth(); - - if ($day < 10) { - $day = '0'.$day; - } - $hour = self::getHour(); - - if ($hour < 10) { - $hour = '0'.$hour; - } - $minute = self::getMinute(); - - if ($minute < 10) { - $minute = '0'.$minute; - } - - return $month.'-'.$day.' '.$hour.':'.$minute; + public static function tasksQueue() : Queue { + return self::get()->getQueueHelper(); } /** * Creates a task that will be executed on specific time weekly. diff --git a/webfiori/framework/session/Session.php b/webfiori/framework/session/Session.php index cbd2d8bc..91f70bc8 100644 --- a/webfiori/framework/session/Session.php +++ b/webfiori/framework/session/Session.php @@ -591,7 +591,7 @@ public function serialize() : string { // Serialize => Encode => [Encrypt] $serializedSession = base64_encode(trim(serialize($this))); $len = strlen($serializedSession); - + $cipherMeth = 'aes-256-ctr'; if (in_array($cipherMeth, openssl_get_cipher_methods())) { diff --git a/webfiori/framework/ui/WebPage.php b/webfiori/framework/ui/WebPage.php index add4271b..c4baf81f 100644 --- a/webfiori/framework/ui/WebPage.php +++ b/webfiori/framework/ui/WebPage.php @@ -767,21 +767,6 @@ public function render(bool $formatted = false, bool $returnResult = false) { return $this->getDocument(); } - private function invokeBeforeRender(int $current = 0) { - $currentCount = count($this->beforeRenderCallbacks); - - if ($currentCount == 0 || $currentCount == $current) { - return; - } - $this->beforeRenderCallbacks->get($current)->call($this); - $newCount = count($this->beforeRenderCallbacks); - if ($newCount != $currentCount) { - $this->beforeRenderCallbacks->insertionSort(false); - $this->invokeBeforeRender(); - } else { - $this->invokeBeforeRender($current + 1); - } - } /** * Resets page attributes to default values. * @@ -1223,6 +1208,22 @@ private function getHead() { return $headNode; } + private function invokeBeforeRender(int $current = 0) { + $currentCount = count($this->beforeRenderCallbacks); + + if ($currentCount == 0 || $currentCount == $current) { + return; + } + $this->beforeRenderCallbacks->get($current)->call($this); + $newCount = count($this->beforeRenderCallbacks); + + if ($newCount != $currentCount) { + $this->beforeRenderCallbacks->insertionSort(false); + $this->invokeBeforeRender(); + } else { + $this->invokeBeforeRender($current + 1); + } + } private function resetBeforeLoaded() { $this->beforeRenderCallbacks = new LinkedList(); $this->addBeforeRender(function (WebPage $page) diff --git a/webfiori/framework/writers/TableClassWriter.php b/webfiori/framework/writers/TableClassWriter.php index 1e9e57b2..c9fa28c9 100644 --- a/webfiori/framework/writers/TableClassWriter.php +++ b/webfiori/framework/writers/TableClassWriter.php @@ -10,6 +10,8 @@ */ namespace webfiori\framework\writers; +use const APP_DIR; +use const APP_PATH; use webfiori\database\ColOption; use webfiori\database\Column; use webfiori\database\DataType; @@ -20,8 +22,6 @@ use webfiori\database\mysql\MySQLColumn; use webfiori\database\mysql\MySQLTable; use webfiori\database\Table; -use const APP_DIR; -use const APP_PATH; /** * A class which is used to write database table classes. @@ -250,11 +250,41 @@ private function addColsHelper() { } $this->append(']);', 2); } + private function addFKOption(Column $colObj) { + $fks = $this->getTable()->getForeignKeys(); + + foreach ($fks as $fk) { + $fk instanceof FK; + $sourceCols = array_values($fk->getOwnerCols()); + + if (count($sourceCols) == 1 && $sourceCols[0]->getNormalName() == $colObj->getNormalName()) { + $this->addFKOptionHelper($colObj, $fk); + } + } + } + private function addFKOptionHelper(Column $col, FK $fk) { + $refTableNs = get_class($fk->getSource()); + $cName = $this->getNamespace().'\\'.$this->getName(); + $refTableClassName = '$this'; + + if ($cName != $refTableNs) { + $nsSplit = explode('\\', $refTableNs); + $refTableClassName = 'new '.$nsSplit[count($nsSplit) - 1].'()'; + } + $keyName = $fk->getKeyName(); + $sourceCol = array_keys($fk->getSourceCols())[0]; + $this->append("ColOption::FK => [", 4); + $this->append("ColOption::FK_NAME => '".$keyName."',", 5); + $this->append("ColOption::FK_TABLE => ".$refTableClassName.",", 5); + $this->append("ColOption::FK_COL => '".$sourceCol."',", 5); + $this->append("ColOption::FK_ON_UPDATE => ".$this->getFkCond($fk->getOnUpdate()).",", 5); + $this->append("ColOption::FK_ON_DELETE => ".$this->getFkCond($fk->getOnDelete()).",", 5); + $this->append("],", 4); + } private function addFksHelper() { $fks = $this->tableObj->getForeignKeys(); foreach ($fks as $fkObj) { - if (count($fkObj->getSourceCols()) == 1) { continue; } @@ -280,6 +310,7 @@ private function addFksHelper() { private function addFksUseTables() { if ($this->tableObj !== null) { $fks = $this->tableObj->getForeignKeys(); + if (count($fks) != 0) { $this->addUseStatement(FK::class); } @@ -295,91 +326,6 @@ private function addFksUseTables() { } } } - private function getType(string $dataType) { - switch ($dataType) { - case 'bigint' : { - return 'DataType::BIGINT'; - } - case 'binary' : { - return 'DataType::BINARY'; - } - case 'bit' : { - return 'DataType::BIT'; - } - case 'blob' : { - return 'DataType::BLOB'; - } - case 'longblob' : { - return 'DataType::BLOB_LONG'; - } - case 'mediumblob' : { - return 'DataType::BLOB_MEDIUM'; - } - case 'tinyblob' : { - return 'DataType::BLOB_TINY'; - } - case 'bool' : { - return 'DataType::BOOL'; - } - case 'boolean' : { - return 'DataType::BOOL'; - } - case 'char' : { - return 'DataType::CHAR'; - } - case 'date' : { - return 'DataType::DATE'; - } - case 'datetime' : { - return 'DataType::DATETIME'; - } - case 'datetime2' : { - return 'DataType::DATETIME2'; - } - case 'decimal' : { - return 'DataType::DECIMAL'; - } - case 'double' : { - return 'DataType::DOUBLE'; - } - case 'float' : { - return 'DataType::FLOAT'; - } - case 'int' : { - return 'DataType::INT'; - } - case 'money' : { - return 'DataType::MONEY'; - } - case 'nchar' : { - return 'DataType::NCHAR'; - } - case 'nvarchar' : { - return 'DataType::NVARCHAR'; - } - case 'text' : { - return 'DataType::TEXT'; - } - case 'medumtext' : { - return 'DataType::TEXT_MEDIUM'; - } - case 'time' : { - return 'DataType::TIME'; - } - case 'timestamp' : { - return 'DataType::TIMESTAMP'; - } - case 'varbinary' : { - return 'DataType::VARBINARY'; - } - case 'varchar' : { - return 'DataType::VARCHAR'; - } - default : { - return "'mixed'"; - } - } - } /** * * @param MySQLColumn $colObj @@ -399,7 +345,6 @@ private function appendColObj($key, $colObj) { || $dataType == 'char' || $dataType == 'nchar' || $dataType == 'nvarchar') { - $this->append("ColOption::SIZE => '".$colObj->getSize()."',", 4); if ($dataType == 'decimal') { @@ -444,34 +389,23 @@ private function appendColObj($key, $colObj) { $this->addFKOption($colObj); $this->append("],", 3); } - private function addFKOption(Column $colObj) { - $fks = $this->getTable()->getForeignKeys(); - foreach ($fks as $fk) { - $fk instanceof FK; - $sourceCols = array_values($fk->getOwnerCols()); - if (count($sourceCols) == 1 && $sourceCols[0]->getNormalName() == $colObj->getNormalName()) { - $this->addFKOptionHelper($colObj, $fk); - } - } - } - private function addFKOptionHelper(Column $col, FK $fk) { - $refTableNs = get_class($fk->getSource()); - $cName = $this->getNamespace().'\\'.$this->getName(); - $refTableClassName = '$this'; + /** + * Extract and return the name of table class based on associated table object. + * + */ + private function extractAndSetTableClassName() { + $clazz = get_class($this->getTable()); - if ($cName != $refTableNs) { - $nsSplit = explode('\\', $refTableNs); - $refTableClassName = 'new '.$nsSplit[count($nsSplit) - 1].'()'; + $split = explode('\\', $clazz); + $count = count($split); + + if ($count > 1) { + $this->setClassName($split[$count - 1]); + array_pop($split); + $this->setNamespace(implode('\\', $split)); + } else { + $this->setClassName($split[0]); } - $keyName = $fk->getKeyName(); - $sourceCol = array_keys($fk->getSourceCols())[0]; - $this->append("ColOption::FK => [", 4); - $this->append("ColOption::FK_NAME => '".$keyName."',", 5); - $this->append("ColOption::FK_TABLE => ".$refTableClassName.",", 5); - $this->append("ColOption::FK_COL => '".$sourceCol."',", 5); - $this->append("ColOption::FK_ON_UPDATE => ".$this->getFkCond($fk->getOnUpdate()).",", 5); - $this->append("ColOption::FK_ON_DELETE => ".$this->getFkCond($fk->getOnDelete()).",", 5); - $this->append("],", 4); } private function getFkCond(string $txt) { switch ($txt) { @@ -492,22 +426,89 @@ private function getFkCond(string $txt) { } } } - /** - * Extract and return the name of table class based on associated table object. - * - */ - private function extractAndSetTableClassName() { - $clazz = get_class($this->getTable()); - - $split = explode('\\', $clazz); - $count = count($split); - - if ($count > 1) { - $this->setClassName($split[$count - 1]); - array_pop($split); - $this->setNamespace(implode('\\', $split)); - } else { - $this->setClassName($split[0]); + private function getType(string $dataType) { + switch ($dataType) { + case 'bigint' : { + return 'DataType::BIGINT'; + } + case 'binary' : { + return 'DataType::BINARY'; + } + case 'bit' : { + return 'DataType::BIT'; + } + case 'blob' : { + return 'DataType::BLOB'; + } + case 'longblob' : { + return 'DataType::BLOB_LONG'; + } + case 'mediumblob' : { + return 'DataType::BLOB_MEDIUM'; + } + case 'tinyblob' : { + return 'DataType::BLOB_TINY'; + } + case 'bool' : { + return 'DataType::BOOL'; + } + case 'boolean' : { + return 'DataType::BOOL'; + } + case 'char' : { + return 'DataType::CHAR'; + } + case 'date' : { + return 'DataType::DATE'; + } + case 'datetime' : { + return 'DataType::DATETIME'; + } + case 'datetime2' : { + return 'DataType::DATETIME2'; + } + case 'decimal' : { + return 'DataType::DECIMAL'; + } + case 'double' : { + return 'DataType::DOUBLE'; + } + case 'float' : { + return 'DataType::FLOAT'; + } + case 'int' : { + return 'DataType::INT'; + } + case 'money' : { + return 'DataType::MONEY'; + } + case 'nchar' : { + return 'DataType::NCHAR'; + } + case 'nvarchar' : { + return 'DataType::NVARCHAR'; + } + case 'text' : { + return 'DataType::TEXT'; + } + case 'medumtext' : { + return 'DataType::TEXT_MEDIUM'; + } + case 'time' : { + return 'DataType::TIME'; + } + case 'timestamp' : { + return 'DataType::TIMESTAMP'; + } + case 'varbinary' : { + return 'DataType::VARBINARY'; + } + case 'varchar' : { + return 'DataType::VARCHAR'; + } + default : { + return "'mixed'"; + } } } private function writeConstructor() { diff --git a/webfiori/framework/writers/WebServiceWriter.php b/webfiori/framework/writers/WebServiceWriter.php index 5bc189ed..d322499c 100644 --- a/webfiori/framework/writers/WebServiceWriter.php +++ b/webfiori/framework/writers/WebServiceWriter.php @@ -148,53 +148,19 @@ public function writeClassComment() { public function writeClassDeclaration() { $this->append('class '.$this->getName().' extends EAbstractWebService {'); } - private function getType(string $type) { - switch ($type) { - case 'int': { - return 'ParamType::INT'; - } - case 'integer': { - return 'ParamType::INT'; - } - case 'string': { - return 'ParamType::STRING'; - } - case 'array': { - return 'ParamType::ARR'; - } - case 'bool': { - return 'ParamType::BOOL'; - } - case 'boolean': { - return 'ParamType::BOOL'; - } - case 'double': { - return 'ParamType::DOUBLE'; - } - case 'email': { - return 'ParamType::EMAIL'; - } - case 'json-obj': { - return 'ParamType::JSON_OBJ'; - } - case 'url': { - return 'ParamType::URL'; - } - } - } /** * * @param RequestParameter $param */ private function appendParam($param) { $this->append("'".$param->getName()."' => [", 3); - + $this->append("ParamOption::TYPE => ".$this->getType($param->getType()).",", 4); if ($param->isOptional()) { $this->append("ParamOption::OPTIONAL => true,", 4); } - + if ($param->getDefault() !== null) { $toAppend = "ParamOption::DEFAULT => ".$param->getDefault().","; @@ -210,22 +176,26 @@ private function appendParam($param) { if ($param->isEmptyStringAllowed()) { $this->append("ParamOption::EMPTY => true,", 4); } + if ($param->getMinLength() !== null) { $this->append("ParamOption::MIN_LENGTH => ".$param->getMinLength().",", 4); } + if ($param->getMaxLength() !== null) { $this->append("ParamOption::MAX_LENGTH => ".$param->getMaxLength().",", 4); } } - + 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)) { $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); } @@ -246,6 +216,71 @@ private function appendParams($paramsArray) { $this->append(']);', 2); } } + private function getMethod($method) { + switch ($method) { + case RequestMethod::CONNECT:{ + return "RequestMethod::CONNECT"; + } + case RequestMethod::DELETE:{ + return "RequestMethod::DELETE"; + } + case RequestMethod::GET:{ + return "RequestMethod::GET"; + } + case RequestMethod::HEAD:{ + return "RequestMethod::HEAD"; + } + case RequestMethod::OPTIONS:{ + return "RequestMethod::OPTIONS"; + } + case RequestMethod::PATCH:{ + return "RequestMethod::PATCH"; + } + case RequestMethod::POST:{ + return "RequestMethod::POST"; + } + case RequestMethod::PUT:{ + return "RequestMethod::PUT"; + } + case RequestMethod::TRACE:{ + return "RequestMethod::TRACE"; + } + } + } + private function getType(string $type) { + switch ($type) { + case 'int': { + return 'ParamType::INT'; + } + case 'integer': { + return 'ParamType::INT'; + } + case 'string': { + return 'ParamType::STRING'; + } + case 'array': { + return 'ParamType::ARR'; + } + case 'bool': { + return 'ParamType::BOOL'; + } + case 'boolean': { + return 'ParamType::BOOL'; + } + case 'double': { + return 'ParamType::DOUBLE'; + } + case 'email': { + return 'ParamType::EMAIL'; + } + case 'json-obj': { + return 'ParamType::JSON_OBJ'; + } + case 'url': { + return 'ParamType::URL'; + } + } + } private function implementMethods() { $name = $this->servicesObj->getName(); $this->append([ @@ -290,8 +325,9 @@ private function writeConstructor() { $this->f('__construct'), ], 1); $this->append('parent::__construct(\''.$this->servicesObj->getName().'\');', 2); - $this->append('$this->setDescription(\''. str_replace("'", "\\'", $this->servicesObj->getDescription()).'\');', 2); + $this->append('$this->setDescription(\''.str_replace("'", "\\'", $this->servicesObj->getDescription()).'\');', 2); $this->append('$this->setRequestMethods([', 2); + foreach ($this->servicesObj->getRequestMethods() as $method) { $this->append($this->getMethod($method).',', 3); } @@ -299,37 +335,6 @@ private function writeConstructor() { $this->appendParams($this->servicesObj->getParameters()); $this->append('}', 1); } - private function getMethod($method) { - switch ($method) { - case RequestMethod::CONNECT:{ - return "RequestMethod::CONNECT"; - } - case RequestMethod::DELETE:{ - return "RequestMethod::DELETE"; - } - case RequestMethod::GET:{ - return "RequestMethod::GET"; - } - case RequestMethod::HEAD:{ - return "RequestMethod::HEAD"; - } - case RequestMethod::OPTIONS:{ - return "RequestMethod::OPTIONS"; - } - case RequestMethod::PATCH:{ - return "RequestMethod::PATCH"; - } - case RequestMethod::POST:{ - return "RequestMethod::POST"; - } - case RequestMethod::PUT:{ - return "RequestMethod::PUT"; - } - case RequestMethod::TRACE:{ - return "RequestMethod::TRACE"; - } - } - } private function writeServiceDoc($service) { $docArr = [];