diff --git a/composer.json b/composer.json
index b25882f..3351aac 100644
--- a/composer.json
+++ b/composer.json
@@ -28,6 +28,7 @@
"require": {
"php": ">=7.2.5",
"ext-json": "*",
+ "eftec/clione": "^1.5",
"ext-pdo": "*",
"ext-readline": "*",
"eftec/messagecontainer": "^2.4"
diff --git a/examples/clitest/cli2.php b/examples/clitest/cli2.php
new file mode 100644
index 0000000..09d57fa
--- /dev/null
+++ b/examples/clitest/cli2.php
@@ -0,0 +1,17 @@
+";
+}
+*/
+$txt='
"; +$color=$cli->replaceColor($txt); +echo $color."\n"; +echo $cli->colorLess($color)."\n"; +echo $cli->colorMask($color)."\n"; +echo $cli->removechar($color,3)."\n"; +echo ""; diff --git a/examples/repomysql/generated/AbstractTableChildRepo.php b/examples/repomysql/generated/AbstractTableChildRepo.php index 74234e9..15b5e96 100644 --- a/examples/repomysql/generated/AbstractTableChildRepo.php +++ b/examples/repomysql/generated/AbstractTableChildRepo.php @@ -1,478 +1,499 @@ + * Generated by PdoOne Version 2.24 Date generated Sun, 06 Feb 2022 16:39:24 -0300. + * DO NOT EDIT THIS CODE. Use instead the Repo Class. + * @copyright (c) Jorge Castro C. MIT License https://github.com/EFTEC/PdoOne + * Class AbstractTableChildRepo + *
* $code=$pdoOne->generateCodeClass('TableChild','repomysql',array(),array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',),array(),'','','TestDb','mysql\repomodel\TableChildModel',array(),array()); *-*/ + */ abstract class AbstractTableChildRepo extends TestDb { -const TABLE = 'TableChild'; -const IDENTITY = 'idtablachildPK'; -const PK = [ - 'idtablachildPK' - ]; -const ME=__CLASS__; -const EXTRACOLS=''; -/** @var string|null $schema you can set the current schema/database used by this class. [Default is null] */ -public static $schema; + const TABLE = 'TableChild'; + const IDENTITY = 'idtablachildPK'; + const PK = [ + 'idtablachildPK' + ]; + const ME = __CLASS__; + const EXTRACOLS = ''; + /** @var string|null $schema you can set the current schema/database used by this class. [Default is null] */ + public static $schema; -/** -* It returns the definitions of the columns
+ /** + * It returns the definitions of the columns
+ * Example:
+ ** self::getDef(); // ['colName'=>[php type,php conversion type,type,size,nullable,extra,sql],'colName2'=>..] * self::getDef('sql'); // ['colName'=>'sql','colname2'=>'sql2'] * self::getDef('identity',true); // it returns the columns that are identities ['col1','col2'] *-* PHP Types: binary, date, datetime, decimal/float,int, string,time, timestamp
-* PHP Conversions: datetime (datetime class), datetime2 (iso),datetime3 (human string) -* , datetime4 (sql no conversion!), timestamp (int), bool, int, float
-* Param Types: PDO::PARAM_LOB, PDO::PARAM_STR, PDO::PARAM_INT
-* -* @param string|null $column =['phptype','conversion','type','size','null','identity','sql'][$i] -* if not null then it only returns the column specified. -* @param string|null $filter If filter is not null, then it uses the column to filter the result. -* -* @return array|array[] -*/ -public static function getDef($column=null,$filter=null) { -$r = [ - 'idtablachildPK' => [ - 'phptype' => 'int', - 'conversion' => 'int', - 'type' => 'int', - 'size' => NULL, - 'null' => FALSE, - 'identity' => TRUE, - 'sql' => 'int not null auto_increment' - ], - 'NameChild' => [ - 'phptype' => 'string', - 'conversion' => NULL, - 'type' => 'varchar', - 'size' => '50', - 'null' => TRUE, - 'identity' => FALSE, - 'sql' => 'varchar(50)' - ], - 'idgrandchildFK' => [ - 'phptype' => 'int', - 'conversion' => 'int', - 'type' => 'int', - 'size' => NULL, - 'null' => TRUE, - 'identity' => FALSE, - 'sql' => 'int' - ] - ]; -if($column!==null) { -if($filter===null) { -foreach($r as $k=>$v) { -$r[$k]=$v[$column]; -} -} else { -$new=[]; -foreach($r as $k=>$v) { -if($v[$column]===$filter) { -$new[]=$k; -} -} -return $new; -} -} -return $r; -} + * PHP Types: binary, date, datetime, decimal/float,int, string,time, timestamp
+ * PHP Conversions: datetime (datetime class), datetime2 (iso),datetime3 (human string) + * , datetime4 (sql no conversion!), timestamp (int), bool, int, float
+ * Param Types: PDO::PARAM_LOB, PDO::PARAM_STR, PDO::PARAM_INT
+ * + * @param string|null $column =['phptype','conversion','type','size','null','identity','sql'][$i] + * if not null then it only returns the column specified. + * @param string|null $filter If filter is not null, then it uses the column to filter the result. + * + * @return array|array[] + */ + public static function getDef($column = null, $filter = null) + { + $r = [ + 'idtablachildPK' => [ + 'phptype' => 'int', + 'conversion' => 'int', + 'type' => 'int', + 'size' => NULL, + 'null' => FALSE, + 'identity' => TRUE, + 'sql' => 'int not null auto_increment' + ], + 'NameChild' => [ + 'phptype' => 'string', + 'conversion' => NULL, + 'type' => 'varchar', + 'size' => '50', + 'null' => TRUE, + 'identity' => FALSE, + 'sql' => 'varchar(50)' + ], + 'idgrandchildFK' => [ + 'phptype' => 'int', + 'conversion' => 'int', + 'type' => 'int', + 'size' => NULL, + 'null' => TRUE, + 'identity' => FALSE, + 'sql' => 'int' + ] + ]; + if ($column !== null) { + if ($filter === null) { + foreach ($r as $k => $v) { + $r[$k] = $v[$column]; + } + } else { + $new = []; + foreach ($r as $k => $v) { + if ($v[$column] === $filter) { + $new[] = $k; + } + } + return $new; + } + } + return $r; + } -/** -* It converts a row returned from the database.
-* If the column is missing then it sets the field as null. -* -* @param array $row [ref] -*/ -public static function convertOutputVal(&$row) { -if($row===false || $row===null) { -return; -} - $row['idtablachildPK']=isset($row['idtablachildPK']) ? (int)$row['idtablachildPK'] : null; - !isset($row['NameChild']) and $row['NameChild']=null; // varchar - $row['idgrandchildFK']=isset($row['idgrandchildFK']) ? (int)$row['idgrandchildFK'] : null; - isset($row['_idgrandchildFK']) - and $row['_idgrandchildFK']['idgrandchildPK']=&$row['idgrandchildFK']; // linked MANYTOONE + /** + * It converts a row returned from the database.
+ * If the column is missing then it sets the field as null. + * + * @param array $row [ref] + */ + public static function convertOutputVal(&$row) + { + if ($row === false || $row === null) { + return; + } + $row['idtablachildPK'] = isset($row['idtablachildPK']) ? (int)$row['idtablachildPK'] : null; + !isset($row['NameChild']) and $row['NameChild'] = null; // varchar + $row['idgrandchildFK'] = isset($row['idgrandchildFK']) ? (int)$row['idgrandchildFK'] : null; + isset($row['_idgrandchildFK']) + and $row['_idgrandchildFK']['idgrandchildPK'] =& $row['idgrandchildFK']; // linked MANYTOONE -} + } -/** -* It converts a row to be inserted or updated into the database.
-* If the column is missing then it is ignored and not converted. -* -* @param array $row [ref] -*/ -public static function convertInputVal(&$row) { - isset($row['idtablachildPK']) and $row['idtablachildPK']=(int)$row['idtablachildPK']; - isset($row['idgrandchildFK']) and $row['idgrandchildFK']=(int)$row['idgrandchildFK']; -} + /** + * It converts a row to be inserted or updated into the database.
+ * If the column is missing then it is ignored and not converted. + * + * @param array $row [ref] + */ + public static function convertInputVal(&$row) + { + isset($row['idtablachildPK']) and $row['idtablachildPK'] = (int)$row['idtablachildPK']; + isset($row['idgrandchildFK']) and $row['idgrandchildFK'] = (int)$row['idgrandchildFK']; + } -/** -* It gets all the name of the columns. -* -* @return string[] -*/ -public static function getDefName() { -return [ - 'idtablachildPK', - 'NameChild', - 'idgrandchildFK' - ]; -} + /** + * It gets all the name of the columns. + * + * @return string[] + */ + public static function getDefName() + { + return [ + 'idtablachildPK', + 'NameChild', + 'idgrandchildFK' + ]; + } -/** -* It returns an associative array (colname=>key type) with all the keys/indexes (if any) -* -* @return string[] -*/ -public static function getDefKey() { -return [ - 'idtablachildPK' => 'PRIMARY KEY', - 'idgrandchildFK' => 'KEY' - ]; -} + /** + * It returns an associative array (colname=>key type) with all the keys/indexes (if any) + * + * @return string[] + */ + public static function getDefKey() + { + return [ + 'idtablachildPK' => 'PRIMARY KEY', + 'idgrandchildFK' => 'KEY' + ]; + } -/** -* It returns a string array with the name of the columns that are skipped when insert -* @return string[] -*/ -public static function getDefNoInsert() { -return [ - 'idtablachildPK' - ]; -} + /** + * It returns a string array with the name of the columns that are skipped when insert + * @return string[] + */ + public static function getDefNoInsert() + { + return [ + 'idtablachildPK' + ]; + } -/** -* It returns a string array with the name of the columns that are skipped when update -* @return string[] -*/ -public static function getDefNoUpdate() { -return [ - 'idtablachildPK' - ]; -} + /** + * It returns a string array with the name of the columns that are skipped when update + * @return string[] + */ + public static function getDefNoUpdate() + { + return [ + 'idtablachildPK' + ]; + } -/** -* It adds a where to the query pipeline. It could be stacked with many where() -* Example:
-*+ /** + * It adds a where to the query pipeline. It could be stacked with many where() + * Example:
+ ** self::where(['col'=>'value'])::toList(); * self::where(['col']=>['value'])::toList(); // s= string/double/date, i=integer, b=bool * self::where(['col=?']=>['value'])::toList(); // s= string/double/date, i=integer, b=bool *-* -* @param array|string $sql =self::factory() -* @param null|array|int $param -* -* @return PdoOneQuery -*/ -public static function where($sql, $param = PdoOne::NULL) -{ -return static::newQuery()->where($sql, $param,false,TableChildRepo::TABLE); -} + * + * @param array|string $sql =self::factory() + * @param null|array|int $param + * + * @return PdoOneQuery + */ + public static function where($sql, $param = PdoOne::NULL) + { + return static::newQuery()->where($sql, $param, false, TableChildRepo::TABLE); + } -public static function getDefFK($structure=false) { -if ($structure) { -return [ - 'idgrandchildFK' => 'FOREIGN KEY REFERENCES`TableGrandChild`(`idgrandchildPK`)' - ]; -} -/* key,refcol,reftable,extra */ -return [ - 'idgrandchildFK' => [ - 'key' => 'FOREIGN KEY', - 'refcol' => 'idgrandchildPK', - 'reftable' => 'TableGrandChild', - 'extra' => '', - 'name' => 'fk_TableChild_idgrandchildFK' - ], - '_idgrandchildFK' => [ - 'key' => 'MANYTOONE', - 'refcol' => 'idgrandchildPK', - 'reftable' => 'TableGrandChild', - 'extra' => '', - 'name' => 'fk_TableChild_idgrandchildFK' - ], - '_TableParent' => [ - 'key' => 'ONETOMANY', - 'col' => 'idtablachildPK', - 'reftable' => 'TableParent', - 'refcol' => '_idchildFK' - ] - ]; -} + public static function getDefFK($structure = false) + { + if ($structure) { + return [ + 'idgrandchildFK' => 'FOREIGN KEY REFERENCES`TableGrandChild`(`idgrandchildPK`)' + ]; + } + /* key,refcol,reftable,extra */ + return [ + 'idgrandchildFK' => [ + 'key' => 'FOREIGN KEY', + 'refcol' => 'idgrandchildPK', + 'reftable' => 'TableGrandChild', + 'extra' => '', + 'name' => 'fk_TableChild_idgrandchildFK' + ], + '_idgrandchildFK' => [ + 'key' => 'MANYTOONE', + 'refcol' => 'idgrandchildPK', + 'reftable' => 'TableGrandChild', + 'extra' => '', + 'name' => 'fk_TableChild_idgrandchildFK' + ], + '_TableParent' => [ + 'key' => 'ONETOMANY', + 'col' => 'idtablachildPK', + 'reftable' => 'TableParent', + 'refcol' => '_idchildFK' + ] + ]; + } -/** -* It returns all the relational fields by type. '*' returns all types.
-* It doesn't return normal columns. -* -* @param string $type=['*','MANYTOONE','ONETOMANY','ONETOONE','MANYTOMANY'][$i] -* -* @return string[] -* @noinspection SlowArrayOperationsInLoopInspection -*/ -public static function getRelations($type='all') { -$r= [ - 'MANYTOONE' => [ - '_idgrandchildFK' - ], - 'ONETOMANY' => [ - '_TableParent' - ] - ]; -if($type==='*') { -$result=[]; -foreach($r as $arr) { -$result = array_merge($result,$arr); -} -return $result; -} -return $r[$type] ?? []; -} + /** + * It returns all the relational fields by type. '*' returns all types.
+ * It doesn't return normal columns. + * + * @param string $type =['*','MANYTOONE','ONETOMANY','ONETOONE','MANYTOMANY'][$i] + * + * @return string[] + * @noinspection SlowArrayOperationsInLoopInspection + */ + public static function getRelations($type = 'all') + { + $r = [ + 'MANYTOONE' => [ + '_idgrandchildFK' + ], + 'ONETOMANY' => [ + '_TableParent' + ] + ]; + if ($type === '*') { + $result = []; + foreach ($r as $arr) { + $result = array_merge($result, $arr); + } + return $result; + } + return $r[$type] ?? []; + } -/** -* @param array|int $filter (optional) if we want to filter the results. -* @param array|null $filterValue (optional) the values of the filter -* @return array|bool|null -* @throws Exception -*/ -public static function toList($filter=PdoOne::NULL,$filterValue=null) { -if(self::$useModel) { -return TableChildModel::fromArrayMultiple( self::_toList($filter, $filterValue)); -} -return self::_toList($filter, $filterValue); -} + /** + * @param array|int $filter (optional) if we want to filter the results. + * @param array|null $filterValue (optional) the values of the filter + * @return array|bool|null + * @throws Exception + */ + public static function toList($filter = PdoOne::NULL, $filterValue = null) + { + if (self::$useModel) { + return TableChildModel::fromArrayMultiple(self::_toList($filter, $filterValue)); + } + return self::_toList($filter, $filterValue); + } -/** -* It sets the recursivity. By default, if we query or modify a value, it operates with the fields of the entity. -* With recursivity, we could use the recursivity of the fields, for example, loading a MANYTOONE relation
-* Example:
-*+ /** + * It sets the recursivity. By default, if we query or modify a value, it operates with the fields of the entity. + * With recursivity, we could use the recursivity of the fields, for example, loading a MANYTOONE relation
+ * Example:
+ ** self::setRecursive([]); // (default) no use recursivity. * self::setRecursive('*'); // recursive every MANYTOONE,ONETOONE,MANYTOONE and ONETOONE relations (first level) * self::setRecursive('MANYTOONE'); // recursive all relations of the type MANYTOONE (first level) * self::setRecursive(['_relation1','_relation2']); // recursive only the relations of the first level * self::setRecursive(['_relation1','_relation1/_subrelation1']); //recursive the relations (first and second level) *-* If array then it uses the values to set the recursivity.
-* If string then the values allowed are '*', 'MANYTOONE','ONETOMANY','MANYTOMANY','ONETOONE' (first level only)
-* -* @param string|array $recursive=self::factory(); -* -* @return PdoOneQuery -*/ -public static function setRecursive($recursive=[]) -{ -if(is_string($recursive)) { -$recursive=TableChildRepo::getRelations($recursive); -} -return parent::_setRecursive($recursive); -} + * If array then it uses the values to set the recursivity.
+ * If string then the values allowed are '*', 'MANYTOONE','ONETOMANY','MANYTOMANY','ONETOONE' (first level only)
+ * + * @param string|array $recursive =self::factory(); + * + * @return PdoOneQuery + */ + public static function setRecursive($recursive = []) + { + if (is_string($recursive)) { + $recursive = TableChildRepo::getRelations($recursive); + } + return parent::_setRecursive($recursive); + } -/** -* It adds an "limit" in a query. It depends on the type of database
-* Example:
-*+ /** + * It adds an "limit" in a query. It depends on the type of database
+ * Example:
+ ** ->select("")->limit("10,20")->toList(); *-* -* @param string $sql Input SQL query -* -* @return PdoOneQuery -* @throws Exception -* @test InstanceOf PdoOne::class,this('1,10') -*/ -public static function limit($sql) -{ -return static::newQuery()->limit($sql); -} + * + * @param string $sql Input SQL query + * + * @return PdoOneQuery + * @throws Exception + * @test InstanceOf PdoOne::class,this('1,10') + */ + public static function limit($sql) + { + return static::newQuery()->limit($sql); + } -/** -* It returns the first row of a query.
-* Example:
-*+ /** + * It returns the first row of a query.
+ * Example:
+ ** Repo::first(); // it returns the first value encountered. * Repo::first(2); // it returns the first value where the primary key is equals to 2 (simple primary key) * Repo::first([2,3]); // it returns the first value where the primary key is equals to 2 (multiple primary keys) * Repo::first(['id'=>2,'id2'=>3]); // it returns the first value where id=2 and id2=3 (multiple primary keys) *-* @param array|mixed|null $pk [optional] Specify the value of the primary key. -* -* @return array|bool It returns false if not file is found. -* @throws Exception -*/ -public static function first($pk = PdoOne::NULL) { -if(self::$useModel) { -return TableChildModel::fromArray(self::_first($pk)); -} -return self::_first($pk); -} + * @param array|mixed|null $pk [optional] Specify the value of the primary key. + * + * @return array|bool It returns false if not file is found. + * @throws Exception + */ + public static function first($pk = PdoOne::NULL) + { + if (self::$useModel) { + return TableChildModel::fromArray(self::_first($pk)); + } + return self::_first($pk); + } -/** -* It returns true if the entity exists, otherwise false.
-* Example:
-*+ /** + * It returns true if the entity exists, otherwise false.
+ * Example:
+ ** $this->exist(['id'=>'a1','name'=>'name']); // using an array * $this->exist('a1'); // using the primary key. The table needs a pks and it only works with the first pk. *-* -* @param array|mixed $entity =self::factory() -* -* @return bool true if the pks exists -* @throws Exception -*/ -public static function exist($entity) { -return self::_exist($entity); -} + * + * @param array|mixed $entity =self::factory() + * + * @return bool true if the pks exists + * @throws Exception + */ + public static function exist($entity) + { + return self::_exist($entity); + } -/** -* It inserts a new entity(row) into the database
-* @param array|object $entity =self::factory() -* @param bool $transactional If true (default) then the operation is transactional -* -* @return array|false=self::factory() -* @throws Exception -*/ -public static function insert(&$entity,$transactional=true) { -return self::_insert($entity,$transactional); -} + /** + * It inserts a new entity(row) into the database
+ * @param array|object $entity =self::factory() + * @param bool $transactional If true (default) then the operation is transactional + * + * @return array|false=self::factory() + * @throws Exception + */ + public static function insert(&$entity, $transactional = true) + { + return self::_insert($entity, $transactional); + } -/** -* It merge a new entity(row) into the database. If the entity exists then it is updated, otherwise the entity is -* inserted
-* @param array|object $entity =self::factory() -* @param bool $transactional If true (default) then the operation is transactional -* -* @return array|false=self::factory() -* @throws Exception -*/ -public static function merge(&$entity,$transactional=true) { -return self::_merge($entity,$transactional); -} + /** + * It merge a new entity(row) into the database. If the entity exists then it is updated, otherwise the entity is + * inserted
+ * @param array|object $entity =self::factory() + * @param bool $transactional If true (default) then the operation is transactional + * + * @return array|false=self::factory() + * @throws Exception + */ + public static function merge(&$entity, $transactional = true) + { + return self::_merge($entity, $transactional); + } -/** -* @param array|object $entity =self::factory() -* @param bool $transactional If true (default) then the operation is transactional -* -* @return array|false=self::factory() -* @throws Exception -*/ -public static function update($entity,$transactional=true) { -return self::_update($entity,$transactional); -} + /** + * @param array|object $entity =self::factory() + * @param bool $transactional If true (default) then the operation is transactional + * + * @return array|false=self::factory() + * @throws Exception + */ + public static function update($entity, $transactional = true) + { + return self::_update($entity, $transactional); + } -/** -* It deletes an entity by the primary key -* -* @param array|object $entity =self::factory() -* @param bool $transactional If true (default) then the operation is transactional -* -* @return false|int -* @throws Exception -*/ -public static function delete($entity,$transactional=true) { -return self::_delete($entity,$transactional); -} + /** + * It deletes an entity by the primary key + * + * @param array|object $entity =self::factory() + * @param bool $transactional If true (default) then the operation is transactional + * + * @return false|int + * @throws Exception + */ + public static function delete($entity, $transactional = true) + { + return self::_delete($entity, $transactional); + } -/** -* It deletes an entity by the primary key. -* -* @param array|mixed $pk =self::factory() -* @param bool $transactional If true (default) then the operation is transactional -* -* @return int|false -* @throws Exception -*/ -public static function deleteById($pk,$transactional=true) { -return self::_deleteById($pk,$transactional); -} + /** + * It deletes an entity by the primary key. + * + * @param array|mixed $pk =self::factory() + * @param bool $transactional If true (default) then the operation is transactional + * + * @return int|false + * @throws Exception + */ + public static function deleteById($pk, $transactional = true) + { + return self::_deleteById($pk, $transactional); + } -/** -* Returns an array with the default values (0 for numbers, empty for string, and array|null if recursive) -* -* @param array|null $values =self::factory() -* @param string $recursivePrefix It is the prefix of the recursivity. -* -* @return array -*/ -public static function factory($values = null, $recursivePrefix = '') { -$recursive=static::getRecursive(); -static::setRecursive(); // reset the recursivity. -$row= [ - 'idtablachildPK'=>0, - '_TableParent'=>(in_array($recursivePrefix.'_TableParent',$recursive,true)) - ? [] - : null, /* ONETOMANY! */ - 'NameChild'=>'', - 'idgrandchildFK'=>0, - '_idgrandchildFK'=>(in_array($recursivePrefix.'_idgrandchildFK',$recursive,true)) - ? TableGrandChildRepo::factory(null,$recursivePrefix.'_idgrandchildFK') - : null, /* MANYTOONE!! */ - ]; - isset($row['_idgrandchildFK']) - and $row['_idgrandchildFK']['idgrandchildPK']=&$row['idgrandchildFK']; // linked MANYTOONE + /** + * Returns an array with the default values (0 for numbers, empty for string, and array|null if recursive) + * + * @param array|null $values =self::factory() + * @param string $recursivePrefix It is the prefix of the recursivity. + * + * @return array + */ + public static function factory($values = null, $recursivePrefix = '') + { + $recursive = static::getRecursive(); + static::setRecursive(); // reset the recursivity. + $row = [ + 'idtablachildPK' => 0, + '_TableParent' => (in_array($recursivePrefix . '_TableParent', $recursive, true)) + ? [] + : null, /* ONETOMANY! */ + 'NameChild' => '', + 'idgrandchildFK' => 0, + '_idgrandchildFK' => (in_array($recursivePrefix . '_idgrandchildFK', $recursive, true)) + ? TableGrandChildRepo::factory(null, $recursivePrefix . '_idgrandchildFK') + : null, /* MANYTOONE!! */ + ]; + isset($row['_idgrandchildFK']) + and $row['_idgrandchildFK']['idgrandchildPK'] =& $row['idgrandchildFK']; // linked MANYTOONE -if ($values !== null) { -$row = array_merge($row, $values); -} -return $row; -} + if ($values !== null) { + $row = array_merge($row, $values); + } + return $row; + } -/** -* It returns an empty array with null values and no recursivity. -* @param array|null $values=self::factoryNull() -* -* @return array -*/ -public static function factoryNull($values=null) { -$row= [ - 'idtablachildPK'=>null, - '_TableParent'=>null, /* ONETOMANY! */ - 'NameChild'=>null, - 'idgrandchildFK'=>null, - '_idgrandchildFK'=>null, /* MANYTOONE!! */ - ]; -if ($values !== null) { -$row = array_merge($row, $values); -} -return $row; -} + /** + * It returns an empty array with null values and no recursivity. + * @param array|null $values =self::factoryNull() + * + * @return array + */ + public static function factoryNull($values = null) + { + $row = [ + 'idtablachildPK' => null, + '_TableParent' => null, /* ONETOMANY! */ + 'NameChild' => null, + 'idgrandchildFK' => null, + '_idgrandchildFK' => null, /* MANYTOONE!! */ + ]; + if ($values !== null) { + $row = array_merge($row, $values); + } + return $row; + } } diff --git a/lib/PdoOne.php b/lib/PdoOne.php index 8b0b09d..4501d5f 100644 --- a/lib/PdoOne.php +++ b/lib/PdoOne.php @@ -1,4 +1,5 @@ - + /** @var CliOne */ + private $cli; /** * PdoOne constructor. It doesn't open the connection to the database. @@ -242,14 +246,12 @@ public function __construct( $this->construct($database, $server, $user, $pwd, $db, $logFile, $charset, $nodeId); if (!class_exists('eftec\MessageContainer')) { throw new RuntimeException('MessageContainer class does not exist'); - } // autowire MessageContainer if the method exists. - $this->messageContainer=MessageContainer::instance(); - if(self::$instance===null) { - self::$instance=$this; + $this->messageContainer = MessageContainer::instance(); + if (self::$instance === null) { + self::$instance = $this; } - } /** @@ -257,12 +259,12 @@ public function __construct( * @param bool $throwIfNull * @return PdoOne|null */ - public static function instance($throwIfNull=true): ?PdoOne + public static function instance($throwIfNull = true): ?PdoOne { - if(self::$instance===null && $throwIfNull) { - throw new RuntimeException('instance not created for PdoOne'); - } - return self::$instance; + if (self::$instance === null && $throwIfNull) { + throw new RuntimeException('instance not created for PdoOne'); + } + return self::$instance; } protected function construct( @@ -292,13 +294,15 @@ protected function construct( case 'test': $this->service = new PdoOne_TestMockup($this); break; + default: + throw new RuntimeException('no value selected'); } $charset = $this->service->construct($charset, []); $this->server = $server; $this->user = $user; $this->pwd = $pwd; $this->db = $db; - $this->lockerId='Pdo::'.$this->db; + $this->lockerId = 'Pdo::' . $this->db; $this->tableDependencyArray = null; $this->tableDependencyArrayCol = null; $this->logFile = $logFile; @@ -364,7 +368,6 @@ public static function unixtime2Sql($dateNum): ?string if ($dateNum === null) { return self::$dateEpoch; } - return date(self::$isoDateTimeMs, $dateNum); } @@ -408,10 +411,8 @@ public static function dateTimeSql2PHP($sqlField, &$hasTime = false) if (self::$dateEpoch === null) { return null; } - return DateTime::createFromFormat(self::$isoDateTimeMs, self::$dateEpoch); } - if (strpos($sqlField, '.')) { // with date with time and microseconds //2018-02-06 05:06:07.123 @@ -420,7 +421,6 @@ public static function dateTimeSql2PHP($sqlField, &$hasTime = false) //$x = DateTime::createFromFormat("Y-m-d H:i:s.u", "2018-02-06 05:06:07.1234"); return DateTime::createFromFormat(self::$isoDateTimeMs, $sqlField); } - if (strpos($sqlField, ':')) { // date with time $hasTime = true; @@ -428,7 +428,6 @@ public static function dateTimeSql2PHP($sqlField, &$hasTime = false) } // only date $hasTime = false; - return DateTime::createFromFormat(self::$isoDate, $sqlField); } @@ -493,7 +492,6 @@ public static function dateConvert($sqlField, $inputFormat, $outputFormat, $forc if ($time) { return $tmpDate->format(self::$dateTimeHumanFormat); } - return $tmpDate->format(self::$dateHumanFormat); case 'sql': if ($ms) { @@ -502,7 +500,6 @@ public static function dateConvert($sqlField, $inputFormat, $outputFormat, $forc if ($time) { return $tmpDate->format(self::$isoDateInputTime); } - return $tmpDate->format(self::$isoDateInput); case 'class': return $tmpDate; @@ -559,7 +556,6 @@ public static function dateConvertInput($inputValue, $inputFormat, &$ms, &$time) $tmpDate = DateTime::createFromFormat(self::$dateTimeHumanFormat, $inputValue); } else { $tmpDate = DateTime::createFromFormat(self::$dateHumanFormat, $inputValue); - if ($tmpDate === false) { return false; } @@ -620,12 +616,10 @@ public static function dateText2Sql($textDate, $hasTime = true): ?string } else { $tmpFormat = self::$dateFormat; } - $tmpDate = DateTime::createFromFormat($tmpFormat, $textDate); if (!$hasTime && $tmpDate) { $tmpDate->setTime(0, 0); } - return self::dateTimePHP2Sql($tmpDate); // it always returns a date with time. Mysql Ignores it. } @@ -647,7 +641,6 @@ public static function dateTimePHP2Sql($date): ?string if ($date->format('u') !== '000000') { return $date->format(self::$isoDateTimeMs); } - return $date->format(self::$isoDateTime); } @@ -710,7 +703,6 @@ public static function dateSqlNow($hasTime = true, $hasMicroseconds = false): st if ($hasTime) { return $tmpDate->format(($hasMicroseconds !== false) ? self::$isoDateTimeMs : self::$isoDateTime); } - return $tmpDate->format(self::$isoDate); } @@ -794,7 +786,6 @@ public static function replaceBetween( $len = $p1 + strlen($endNeedle) - $ini; $offset = $ini + $len; return substr_replace($haystack, $replaceText, $ini, $len); - } $len = $p1 - $ini2; $offset = $ini2 + $len; @@ -833,7 +824,6 @@ public static function tableCase($txt) } if (strpos($txt, '_') !== false || strpos($txt, ' ') !== false) { $txt = strtolower($txt); - $result = ''; $l = strlen($txt); for ($i = 0; $i < $l; $i++) { @@ -849,7 +839,6 @@ public static function tableCase($txt) $result .= $c; } } - return self::singularTable(ucfirst($result)); } // the text is simple. @@ -857,7 +846,8 @@ public static function tableCase($txt) } /** - * It converts a name to singular. This method is used automatically for the generation of the repository classes
+ * It converts a name to singular. This method is used automatically for the generation of the repository + * classes
* Example:
** self::singularTable('categories'); // category @@ -871,13 +861,13 @@ public static function tableCase($txt) public static function singularTable($tableName) { $l = strlen($tableName); - if ($l>=3 && substr($tableName,-3)==='ies') { + if ($l >= 3 && substr($tableName, -3) === 'ies') { // categories => category - $tableName = substr($tableName, 0, $l - 3).'y'; - } else if ($l>=2 && substr($tableName,-2)==='es') { + $tableName = substr($tableName, 0, $l - 3) . 'y'; + } else if ($l >= 2 && substr($tableName, -2) === 'es') { // churches => church (however it fails with prices => pric) $tableName = substr($tableName, 0, $l - 2); - } else if($l>=1 && substr($tableName,-1)==='s') { + } else if ($l >= 1 && substr($tableName, -1) === 's') { // users => user $tableName = substr($tableName, 0, $l - 1); } @@ -955,7 +945,6 @@ public function validateDefTable($table, $defArray, $defKeys, $defFK): array $error[$k] = "fk: $dc , $defFK[$k] are different"; } } - return $error; } @@ -996,12 +985,12 @@ public function getDefTable($table, $specialConversion = null): array $type = $t[0]; $conversion = $specialConversion[$k] ?? null; $extra = (count($t) > 1) ? $t[1] : null; - if ($extra!==null && stripos($extra, 'not null') !== false) { + if ($extra !== null && stripos($extra, 'not null') !== false) { $null = false; } else { $null = true; } - if ($extra!==null && stripos($extra, $this->database_identityName) !== false) { + if ($extra !== null && stripos($extra, $this->database_identityName) !== false) { $identity = true; } else { $identity = false; @@ -1023,7 +1012,6 @@ public function getDefTable($table, $specialConversion = null): array 'sql' => $v ]; } - return $r; } @@ -1130,7 +1118,7 @@ public function dbTypeToPHP($type): array * * @param string $table The name of the table to analize. * @param bool $returnSimple true= returns as a simple associative - * array
example:['id'=>'PRIMARY + * array
Example:['id'=>'PRIMARY * KEY','name'=>'FOREIGN KEY...']
false= * returns as an associative array separated * by parts
@@ -1149,7 +1137,7 @@ public function getDefTableKeys($table, $returnSimple = true, $filter = null): a /** * @param string $table The name of the table to analize. * @param bool $returnSimple true= returns as a simple associative - * array
example:['id'=>'PRIMARY + * array
Example:['id'=>'PRIMARY * KEY','name'=>'FOREIGN KEY...']
false= * returns as an associative array separated * by parts
@@ -1202,16 +1190,143 @@ public function getDefTableExtended($table, $onlyDescription = false) */ public function cliEngine(): void { - $database = self::getParameterCli('database'); - $server = self::getParameterCli('server'); - $user = self::getParameterCli('user'); - $pwd = self::getParameterCli('pwd'); - $db = self::getParameterCli('db'); - $input = self::getParameterCli('input'); - $output = self::getParameterCli('output'); - $namespace = self::getParameterCli('namespace'); + $this->cli = new CliOne(__FILE__); + $this->cli->createParam('database') + ->setRequired(false) + ->setDescription('The type of database', 'Select the type of database', [ + 'Values allowed: ']) + ->setInput(false, 'optionshort', ['mysql', 'sqlsrv', 'oci', 'test']) + ->add(); + $this->cli->createParam('server') + ->setRequired(false) + ->setDefault('127.0.0.1') + ->setDescription('The type of database', 'Select the type of database', [ + 'Example mysql: 127.0.0.1 , 127.0.0.1:3306', + 'Example sqlsrv: (local)\sqlexpress 127.0.0.1\sqlexpress']) + ->setInput(false) + ->add(); + $this->cli->createParam('user') + ->setDescription('The username to access to the database', 'Select the username', ['Example: sa, root']) + ->setRequired(false) + ->setDefault('') + ->setInput(false) + ->add(); + $this->cli->createParam('pwd') + ->setRequired(false) + ->setDescription('The password to access to the database', '', ['Example:12345']) + ->setDefault('') + ->setInput(false, 'password') + ->add(); + $this->cli->createParam('db') + ->setRequired(false) + ->setDescription('The database/schema', 'Select the database/schema', [ + 'Example: sakila,contoso,adventureworks']) + ->setDefault('') + ->setInput(false) + ->add(); + $this->cli->createParam('input') + ->setRequired(false) + ->setDescription('The type of input', '', [ + 'Example: -input "select * from table" = it runs a query', + 'Example: -input "table" = it runs a table (it could generates a query automatically)' + ]) + ->setDefault('') + ->setInput(false) + ->add(); + $this->cli->createParam('output') + ->setRequired(false) + ->setDescription('The type of output', '', [ + 'Values allowed: ', + 'classcode : it returns php code with a CRUDL class', + 'selectcode : it shows a php code with a select', + 'arraycode : it shows a php code with the definition of an array Ex: ["idfield"=0,"name"=>""]', + 'csv : it returns a csv result', + 'json : it returns the value of the queries as json']) + ->setDefault('') + ->setInput(false, 'optionshort', ['classcode', 'selectcode', 'arraycode', 'csv', 'json']) + ->add(); + $this->cli->createParam('namespace') + ->setRequired(false) + ->setDescription('The namespace', '', [ + 'Example: "customers"']) + ->setDefault('') + ->setInput(false) + ->add(); + $scanned_directory = array_diff(scandir('.'), array('..', '.')); + $scanned2=[]; + foreach($scanned_directory as $k) { + if(@pathinfo($k)['extension']==='php') { + $scanned2[$k] = $k; + } + } + $this->cli->createParam('loadconfig') + ->setRequired(false) + ->setDescription('Select the configuration file to load', '', [ + 'Example: "-loadconfig myconfig"']) + ->setDefault('') + ->setInput(true,'string',$scanned2) + ->add(); + + + $this->cli->createParam('saveconfig') + ->setRequired(false) + ->setDescription('save a configuration file', 'Select the configuration file to save', [ + 'Example: "-saveconfig myconfig"']) + ->setDefault('') + ->setInput(true,'string',$scanned2) + ->add(); + $this->cli->createParam('cli') + ->setRequired(false) + ->setAllowEmpty() + ->setDescription('It start the cli', '', [ + 'Example: "-cli"']) + ->setDefault('') + ->setInput(false) + ->add(); $v = self::VERSION; + $this->cli->show(" + _____ _ _____ +| _ | _| | ___ | | ___ ___ +| __|| . || . || | || || -_| +|__| |___||___||_____||_|_||___| $v + +Syntax:php PdoOne.php + +"); + $database = $this->cli->evalParam('database', false, true); + if($database) { + // if the user is inputting some values, then it doesn't ask to load parameters + $this->cli->getParameter('loadconfig')->setInput(false,'string',[]); + } + + $loadconfig = $this->cli->evalParam('loadconfig', false); + if ($loadconfig->value) { + [$ok, $data] = $this->cli->readData($loadconfig->value); + if ($ok === false) { + $this->cli->showCheck('ERROR', 'red', "unable to open file $loadconfig->value"); + } else { + $this->cli->setArrayParam($data); + } + } + $clip = $this->cli->evalParam('cli', false); + if (!$clip->missing) { + $this->runCliGeneration(); + return; + } + + $server = $this->cli->evalParam('server', false, true); + $user = $this->cli->evalParam('user', false, true); + $pwd = $this->cli->evalParam('pwd', false, true); + $db = $this->cli->evalParam('db', false, true); + $input = $this->cli->evalParam('input', false, true); + $output = $this->cli->evalParam('output', false, true); + $namespace = $this->cli->evalParam('namespace', false, true); + + $result = $this->RunCliConnection(); + echo "quatro"; + $this->runCliSaveConfig(); + $this->cli->showLine(); if ($database === '' || $server === '' || $user === '' || $pwd === '' || $input === '' || $output === '') { $databasem = self::messageCli($database === '' ? '*missing*' : $database, $database === '' ? 'e' : 'g', false); $serverm = self::messageCli($server === '' ? '*missing*' : $server, $server === '' ? 'e' : 'g', false); @@ -1219,45 +1334,512 @@ public function cliEngine(): void $pwdm = self::messageCli('***', $pwd === '' ? 'e' : 'g', false); $inputm = self::messageCli($input === '' ? '*missing*' : $input, $input === '' ? 'e' : 'g', false); $outputm = self::messageCli($output === '' ? '*missing*' : $output, $output === '' ? 'e' : 'g', false); + $this->cli->showParamSyntax('*', 0, 1, ['retry']); + return; + } + echo self::messageCli($this->run($database, $server, $user, $pwd, $db, $input, $output, $namespace), 'e'); + } + protected function runCliSaveConfig():void + { + if($this->cli->createParam('dosave','none') + ->setRequired(false) + ->setDefault('false') + ->setInput(true,'optionshort',['yes','no']) + ->setDescription('','Do you want to save?') + ->evalParam(true,true)==='yes') { - echo <<cli->evalParam('saveconfig', false); + if ($saveconfig->value) { + $arr = $this->cli->getArrayParams(['saveconfig', 'loadconfig', 'cli', 'retry']); + $r = $this->cli->saveData($saveconfig->value, $arr); + if ($r === '') { + $this->cli->showCheck('OK', 'green', 'file saved correctly'); + } + } + } + } -Syntax:php PdoOne.php --database [$databasem] - Example: (mysql/sqlsrv/oracle/test) --server [$serverm] - Example mysql: 127.0.0.1 , 127.0.0.1:3306 - Example sqlsrv: (local)\sqlexpress 127.0.0.1\sqlexpress --user The username to access to the database [$userm] - Example: root, su --pwd The password to access to the database [$pwdm] - Example: abc.123 --db The database/schema [$db] - Example: sakila --input The input value.[$inputm] - Example: -input "select * from table" = it runs a query - Example: -input "table" = it runs a table (it could generates a query automatically) --output The result value. [$outputm] - classcode: it returns php code with a CRUDL class - selectcode: it shows a php code with a select - arraycode: it shows a php code with the definition of an array Ex: ['idfield'=0,'name'=>''] - csv: it returns a csv result - json: it returns the value of the queries as json --namespace [optional] the namespace [$namespace] - Example: "customerid" - -eot; + /** + * @return void + * @throws Exception + */ + protected function runCliGeneration(): void + { + [$configOk, $config] = $this->cli->readData('myconfig'); + if (!$configOk) { + $config = [ + 'tablexclass' => '', + 'conversion' => [], + 'extracolumn' => [], + 'removecolumn' => [], + 'db' => $this->cli->getValue('db'), + 'classnamespace' => '', + 'classdirectory' => '', + 'classoverride' => '', + 'columnsTable' => '', + 'classes' => [] + ]; + } - return; + $this->cli->createParam('savegen') + ->setRequired(false) + ->setDescription('save a configuration file', 'Do you want to save the generation', [ + 'Example: "-savegen myconfig"']) + ->setDefault('yes') + ->setInput(true, 'optionshort', ['yes', 'no']) + ->add(); + $this->cli->createParam('namerepo') + ->setDescription('', 'Select the name of the class repository') + ->setInput(true)->add(); + $this->cli->createParam('command') + ->setDescription('', 'Select a command (empty for exit)') + ->setAllowEmpty() + ->setInput(true, 'option', [ + 'select' => 'Select the tables to work', + 'configure' => 'Configure per table', + 'convertxtype' => 'Configure per type of column', + 'end' => 'End this menu and save the project'])->add(); + $this->cli->createParam('tables') + ->setDescription('', '') + ->setInput(true, 'options', [])->add(); + $this->cli->createParam('tablescolumns') + ->setDescription('', '') + ->setAllowEmpty(false) + ->setInput(true, 'options', [])->add(); + $this->cli->createParam('tablescolumnsvalue') + ->setDescription('', '') + ->setRequired(false) + ->setAllowEmpty(true) + ->setInput(true, 'string', [])->add(); + $this->cli->createParam('classselected') + ->setDescription('', 'Select a table to configure') + ->setAllowEmpty() + ->setInput(true, 'option3', [])->add(); + $this->cli->createParam('tablecommand') + ->setDescription('', 'Select the command for the table') + ->setAllowEmpty(true) + ->setInput(true, 'option', [ + 'rename' => 'rename the class from the table', + 'conversion' => 'column conversion', + 'extracolumn' => 'configure extra columns that could be read', + 'remove' => 'remove a column' + ])->add(); + $this->cli->createParam('convertionselected') + ->setDescription('', 'Select a type of data to convert') + ->setAllowEmpty() + ->setInput(true, 'option3', [])->add(); + $this->cli->createParam('convertionnewvalue') + ->setDescription('', 'Select the conversion') + ->setAllowEmpty() + ->setInput(true, 'option', [ + 'encrypt' => 'encrypt and decrypt the value', + 'decrypt' => 'encrypt and decrypt the value', + 'datetime3' => 'convert an human readable date to SQL', + 'datetime4' => 'no conversion, it keeps the format of SQL', + 'datetime2' => 'convert between ISO standard and SQL', + 'datetime' => 'convert between PHP Datetime object and SQL', + 'timestamp' => 'convert between a timestamp number and sql', + 'bool' => 'the value will be converted into a boolean (0,"" or null=false,other=true)', + 'int' => 'the value will be cast into a int', + 'float' => 'the value will be cast into a float', + 'decimal' => 'the value will be cast into a float', + 'null' => 'the value will be null', + 'nothing'=>"it does nothing"])->add(); + $this->cli->createParam('newclassname') + ->setDescription('', 'Select the name of the class') + ->setInput(true, 'string', [])->add(); + $this->cli->createParam('classdirectory') + ->setDescription('', 'Select the relative directory to create the classes') + ->setInput(true)->add(); + $this->cli->createParam('classnamespace') + ->setDescription('', 'Select the namespace of the classes') + ->setInput(true)->add(); + $this->cli->createParam('classoverride') + ->setDescription('', 'Do you want to override previous generated classes?') + ->setInput(true, 'optionshort', ['yes', 'no'])->add(); + $this->cli->getParameter('database')->setInput(true, 'optionshort', ['mysql', 'sqlsrv', 'oci', 'test']); + $this->cli->getParameter('server')->setInput(true); + $this->cli->getParameter('user')->setInput(true); + $this->cli->getParameter('pwd')->setInput(true); + $this->cli->getParameter('db')->setInput(true); + $this->cli->evalParam('database', false); + $this->cli->evalParam('server', false); + $this->cli->evalParam('user', false); + $this->cli->evalParam('pwd', false); + $this->cli->evalParam('db', false); + echo "segunda"; + $pdo = $this->RunCliGenerationTest1(); + if ($pdo === null) { + $this->cli->showCheck('CRITICAL', 'error', 'No connection'); + die(1); } + try { + $tables = $pdo->objectList('table', true); + } catch (Exception $e) { + $this->cli->showCheck('CRITICAL', 'error', 'Unable to read tables'); + die(1); + } + $tablesmarked = $tables; + //$classes=[]; + $tablexclass = []; + $columnsTable = []; + $conversion = []; + $extracolumn=[]; + $removecolumn=[]; + $def2 = []; + $pk = []; + $this->cli->show(' Please wait, reading structure of tables... '); + $this->cli->showWaitCursor(true); + foreach ($tablesmarked as $table) { + /** @noinspection DisconnectedForeachInstructionInspection */ + $this->cli->showWaitCursor(false); + $class = self::tableCase($table) . 'Repo'; + //$classes[] = $class; + $tablexclass[$table] = $class; + $columns = $pdo->columnTable($table); + foreach ($columns as $k => $v) { + $conversion[$v['coltype']] = null; + $columnsTable[$table][$v['colname']] = null; + //var_dump($def2); + } + $pk[$table] = $pdo->getPK($table); + $def2[$table] = $pdo->xxx($table, $pk[$table][0]); + foreach ($def2[$table] as $k => $v) { + if (isset($v['key']) && $v['key'] !== 'FOREIGN KEY') { + $columnsTable[$table][$k] = $v['key']; + } + } + } + $this->cli->showLine(); + ksort($conversion); + if ($configOk !== false) { + $tablexclass = $config['tablexclass']; + $conversion = $config['conversion'] ?? $conversion; + $extracolumn = $config['extracolumn'] ?? $extracolumn; + $removecolumn = $config['removecolumn'] ?? $removecolumn; + //$classes=$config['classes']; + $this->cli->getParameter('db')->value = $config['db']; + $columnsTable = $config['columnsTable']; + $this->cli->getParameter('classnamespace')->setDefault($config['classnamespace']); + $this->cli->getParameter('classdirectory')->setDefault($config['classdirectory']); + $this->cli->getParameter('classoverride')->setDefault($config['classoverride']); + } + $this->cli->upLevel($this->cli->getParameter('db')->value,' (db)'); + while (true) { + $this->cli->setColor(['byellow'])->showBread(); + $com = $this->cli->evalParam('command', true); + + switch ($com->valueKey) { + case 'end': + case $this->cli->emptyValue: + case '': + break 2; + case 'convertxtype': + $this->cli->upLevel('convertxtype'); + while(true) { + $this->cli->setColor(['byellow'])->showBread(); + $this->cli->getParameter('convertionselected') + ->setInput(true, 'option3', $conversion); + $convertionselected = $this->cli->evalParam('convertionselected', true); + if($convertionselected->valueKey===$this->cli->emptyValue) { + break; + } + $this->cli->upLevel($convertionselected->valueKey, ' (type)'); + $this->cli->setColor(['byellow'])->showBread(); + $convertionnewvalue = $this->cli->getParameter('convertionnewvalue') + ->setDefault($convertionselected->value ?? '') + ->evalParam(true); + $conversion[$convertionselected->valueKey] = $convertionnewvalue->valueKey; + $this->cli->downLevel(); + } + $this->cli->downLevel(); + break; + case 'select': + $this->cli->upLevel('select'); + $this->cli->setColor(['byellow'])->showBread(); + $this->cli->getParameter('tables') + ->setDefault($tablesmarked ?? []) + ->setDescription('', 'Select or de-select a table to process') + ->setInput(true, 'multiple2', $tables); + $this->cli->evalParam('tables', true); + $this->cli->downLevel(); + break; + case 'configure': + $this->cli->upLevel('configure'); + while(true) { + $this->cli->setColor(['byellow'])->showBread(); + $tmp = $this->cli->getValue('tables'); + $this->cli->getParameter('classselected') + ->setDescription('', 'Select a table to configure') + ->setInput(true, 'option3', $tablexclass); + $classselected = $this->cli->evalParam('classselected', true); + if ($classselected->value === '') { + $this->cli->downLevel(); + break; // return to command + } + $oldnameclass = $classselected->value; + $ktable = $classselected->valueKey; + $this->cli->upLevel($ktable, '(table)'); + while (true) { // tablecommand + $this->cli->setColor(['byellow'])->showBread(); + $tablecommand = $this->cli->evalParam('tablecommand', true); + switch ($tablecommand->valueKey) { + case $this->cli->emptyValue: + //$this->cli->downLevel(); + $this->cli->downLevel(); + break 2; // while tablecommand + case 'rename': + $this->cli->upLevel('rename'); + $this->cli->setColor(['byellow'])->showBread(); + $this->cli->getParameter('newclassname')->setDefault($classselected->value); + $newclassname = $this->cli->evalParam('newclassname', true); + //$k=array_search($classselected->value,$classes,true); + //$classes[$k]=$newclassname->value; + $tablexclass[$ktable] = $newclassname->value; + $this->cli->downLevel(); + break; + case 'remove': + $this->cli->upLevel('remove'); + while (true) { + $this->cli->setColor(['byellow'])->showBread(); + if (isset($removecolumn[$ktable])) { + $this->cli->showValuesColumn($removecolumn[$ktable], 'option3'); + } + $ecc = $this->cli->createParam('extracolumncommand') + ->setAllowEmpty() + ->setInput(true, 'optionshort', ['add', 'remove']) + ->setDescription('', 'Do you want to add or remove a column from the remove-list') + ->evalParam(true); + switch ($ecc->value) { + case '': + break 2; + case 'add': + $tmp = $this->cli->createParam('extracolumn_name') + //->setAllowEmpty() + ->setInput(true, 'option3', array_keys($columnsTable[$ktable])) + ->setDescription('', 'Select a name of the column to remove') + ->evalParam(true); + $removecolumn[$ktable][] = $tmp->value; + break; + case 'remove': + $tmp = $this->cli->createParam('extracolumn_delete') + ->setAllowEmpty() + ->setInput(true, 'option2', $removecolumn[$ktable]) + ->setDescription('', 'Select a columne to delete') + ->evalParam(true); + if ($tmp->valueKey !== $this->cli->emptyValue) { + unset($removecolumn[$ktable][$tmp->valueKey - 1]); + } + // renumerate + $removecolumn[$ktable] = array_values($removecolumn[$ktable]); + break; + } + } + $this->cli->downLevel(); + break; + case 'extracolumn': + $this->cli->upLevel('extracolumn'); + while (true) { + $this->cli->setColor(['byellow'])->showBread(); + $this->cli->showValuesColumn($extracolumn[$ktable],'option2'); + $ecc = $this->cli->createParam('extracolumncommand') + ->setAllowEmpty() + ->setInput(true, 'optionshort', ['add', 'remove']) + ->setDescription('', 'Select an operation') + ->evalParam(true); + switch ($ecc->value) { + case '': + break 2; + case 'add': + $tmp = $this->cli->createParam('extracolumn_name') + //->setAllowEmpty() + ->setInput(true) + ->setDescription('', 'Select a name for the new column') + ->evalParam(true); + $tmp2 = $this->cli->createParam('extracolumn_sql') + //->setAllowEmpty() + ->setInput(true) + ->setDescription('', 'Select a sql for the new column') + ->evalParam(true); + $extracolumn[$ktable][$tmp->value] = $tmp2->value; + break; + case 'remove': + $tmp = $this->cli->createParam('extracolumn_delete') + ->setAllowEmpty() + ->setInput(true, 'option2', $extracolumn[$ktable]) + ->setDescription('', 'Select a columne to delete') + ->evalParam(true); + if ($tmp->valueKey !== $this->cli->emptyValue) { + unset($extracolumn[$ktable][$tmp->valueKey]); + } + break; + } + } + $this->cli->downLevel(); + break; + case 'conversion': + $this->cli->upLevel('conversion'); + while (true) { + $this->cli->setColor(['byellow'])->showBread(); + $this->cli->getParameter('tablescolumns') + ->setDescription('', 'Select a column (or empty for end)') + ->setAllowEmpty() + ->setInput(true, 'option3', $columnsTable[$ktable]); + $tablecolumn = $this->cli->evalParam('tablescolumns', true); + if ($tablecolumn->value === '') { + // exit + break; + } + $this->cli->upLevel($tablecolumn->valueKey, ' (column)'); + $this->cli->setColor(['byellow'])->showBread(); + if ($tablecolumn->valueKey[0] === '_') { + $this->cli->getParameter('tablescolumnsvalue') + ->setDescription('', 'Select a relation') + ->setAllowEmpty(true) + ->setRequired(false) + ->setDefault($tablecolumn->value) + ->setPattern('[{key}] {value}') + ->setInput(true, 'option', [ + 'PARENT' => 'Same than MANYTONE without the recursivity', + 'MANYTOMANY' => 'Many to many', + 'ONETOMANY' => 'One to many relation', + 'MANYTOONE' => 'Many to one', + 'ONETOONE' => 'One to one' + ]); + } else { + $this->cli->getParameter('tablescolumnsvalue') + ->setDescription('', 'Select a conversion') + ->setDefault($tablecolumn->value) + ->setAllowEmpty() + ->setInput(true, 'option', [ + 'encrypt' => 'encrypt the value', + 'decrypt' => 'decrypt the value', + 'datetime3' => 'datetime3', + 'datetime4' => 'datetime3', + 'datetime2' => 'datetime3', + 'datetime' => 'datetime3', + 'timestamp' => 'datetime3', + 'bool' => 'the value will be converted into a boolean (0=false,other=true)', + 'int' => 'the value will be converted into a int', + 'float' => 'the value will be converted into a float', + 'decimal' => 'the value will be converted into a float', + 'null' => 'pending.', + 'nothing'=>"it does nothing"]); + } + $tablecolumnsvalue = $this->cli->evalParam('tablescolumnsvalue', true); + //var_dump($tablecolumn->valueKey); + //var_dump($tablecolumn->valueKey); + if ($tablecolumnsvalue->valueKey !== $this->cli->emptyValue) { + $columnsTable[$ktable][$tablecolumn->valueKey] = $tablecolumnsvalue->valueKey; + } + $this->cli->downLevel(); + } + $this->cli->downLevel(); + break; + } + } // end while tablecommand + } // end while table - echo self::messageCli($this->run($database, $server, $user, $pwd, $db, $input, $output, $namespace), 'e'); + //var_dump($pdo->columnTable($ktable)); + + break; + } + } + $this->cli->evalParam('classdirectory', true); + $this->cli->evalParam('classnamespace', true); + $this->cli->evalParam('classoverride', true); + try { + $configOk = @mkdir($this->cli->getValue('classdirectory')); + if (!$configOk) { + throw new RuntimeException('failed to create folder, maybe the folder already exists'); + } + $this->cli->showCheck('OK', 'green', 'directory created'); + } catch (Exception $ex) { + $this->cli->show(''); + $this->cli->showMessageBox('unable to create directory ' . $ex->getMessage(),'warning'); + $this->cli->show(' '); + // $this->cli->showCheck('WARNING', 'yellow', 'unable to create directory ' . $ex->getMessage()); + } + $results = $pdo->generateAllClasses($tablexclass, ucfirst($this->cli->getValue('db')), + $this->cli->getValue('classnamespace'), + $this->cli->getValue('classdirectory'), + $this->cli->getValue('classoverride') === 'yes', + $columnsTable, + $extracolumn, + $removecolumn + ); + $sg = $this->cli->evalParam('savegen', true); + if ($sg->value === 'no') { + $this->cli->showLine('Done'); + } + $config = [ + 'tablexclass' => $tablexclass, + 'conversion' => $conversion, + 'extracolumn' => $extracolumn, + 'removecolumn' => $removecolumn, + //'classes' => $classes, + 'db' => $this->cli->getValue('db'), + 'classnamespace' => $this->cli->getValue('classnamespace'), + 'classdirectory' => $this->cli->getValue('classdirectory'), + 'classoverride' => $this->cli->getValue('classoverride'), + 'columnsTable' => $columnsTable + ]; + $this->cli->saveData('myconfig', $config); } + protected function RunCliConnection() : ?PdoOne { + $result= null; + while (true) { + try { + $pdo = new PdoOne($this->cli->getValue('database'), + $this->cli->getValue('server'), + $this->cli->getValue('user'), + $this->cli->getValue('pwd'), + $this->cli->getValue('db')); + $pdo->logLevel = 3; + $pdo->connect(); + $this->cli->showCheck('OK', 'green', 'Connected to the database'); + $result = $pdo; + break; + } catch (Exception $ex) { + $this->cli->showCheck('ERROR', 'red', 'Unable to connect to the database: '.$ex->getMessage()); + } + $rt=$this->cli->createParam('retry') + ->setDescription('', 'Do you want to retry?') + ->setInput(true, 'optionshort', ['yes', 'no'])->evalParam(true); + if ($rt->value === 'no') { + break; + } + $this->cli->evalParam('database', true); + $this->cli->evalParam('server', true); + $this->cli->evalParam('user', true); + $this->cli->evalParam('pwd', true); + $this->cli->evalParam('db', true); + } + return $result; + } + + protected function RunCliGenerationTest1(): ?PdoOne + { + $result = $this->RunCliConnection(); + + if (!$this->cli->getValue('loadconfig')) { + $sg = $this->cli->evalParam('savegen', true); + if ($sg->value === 'yes') { + echo "tres"; + $saveconfig = $this->cli->evalParam('saveconfig', false); + if ($saveconfig->value) { + $arr = $this->cli->getArrayParams(['saveconfig', 'loadconfig', 'cli', 'retry']); + $r = $this->cli->saveData($saveconfig->value, $arr); + if ($r === '') { + $this->cli->showCheck('OK', 'green', 'file saved correctly'); + } + } + } + } + return $result; + } + /** * @param $key @@ -1279,7 +1861,6 @@ protected static function getParameterCli($key, $default = ''): string if (count($argv) >= $p + 1) { return self::removeTrailSlash($argv[$p + 1]); } - return ''; } @@ -1318,7 +1899,6 @@ public function run( if (!$this->isOpen) { $r = "Unable to open database $database $server $user **** $db\n"; $r .= $this->lastError(); - return $r; } if (stripos($input, 'select ') !== false || stripos($input, 'show ') !== false) { @@ -1346,7 +1926,6 @@ public function run( $line = rtrim($line, ',') . "\n"; $r .= $line; } - return $r; case 'json': try { @@ -1357,7 +1936,6 @@ public function run( if (!is_array($result)) { return "No result or result error\n"; } - return json_encode($result); case 'selectcode': return $this->generateCodeSelect($query); @@ -1401,9 +1979,7 @@ public function connect($failIfConnected = true, $alterSession = null): void } $this->conn1->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->conn1->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); - //$this->conn1->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); It is not required. - $this->isOpen = true; } catch (Exception $ex) { $this->isOpen = false; @@ -1484,7 +2060,6 @@ public function throwError($txt, $txtExtra, $extraParam = '', $throwError = true } if ($throwError && $this->throwOnError && $this->genError) { // endtry() invalidates this call (it is never called) - throw new RuntimeException($txt); } $this->endTry(); @@ -1506,7 +2081,7 @@ public function lastError(): string if (!$this->isOpen) { return "It's not connected to the database"; } - return $this->conn1->errorInfo()[2]??''; + return $this->conn1->errorInfo()[2] ?? ''; } /** @@ -1556,7 +2131,6 @@ public function custom_exception_handler($exception, $customMessage = null, $ret } else { $function = @$error['function']; } - $r .= $file . ':' . @$error['line'] . "\t" . $function . '(' . @implode(' , ', $args) . ')' . "\n"; } @@ -1584,51 +2158,58 @@ public function getMessagesContainer(): MessageContainer { return $this->messageContainer; } - public function getMessages($level=null): array + + public function getMessages($level = null): array { return $this->messageContainer->getLocker($this->lockerId)->all($level); } + public function getErrors(): array { return $this->messageContainer->getLocker($this->lockerId)->allError(); } + public function getFirstError(): ?string { return $this->messageContainer->getLocker($this->lockerId)->firstError(); } + public function getLastError(): ?string { return $this->messageContainer->getLocker($this->lockerId)->lastError(); } + public function hasError($includeWarning = false): ?string { return $this->messageContainer->getLocker($this->lockerId)->hasError($includeWarning); } + public function getInfos(): array { return $this->messageContainer->getLocker($this->lockerId)->allInfo(); } + public function getFirstInfo(): ?string { return $this->messageContainer->getLocker($this->lockerId)->firstInfo(); } + public function getLastInfo(): ?string { return $this->messageContainer->getLocker($this->lockerId)->lastInfo(); } - - /** - * Inject an instance of a messagecontainer. It is usually injected automatically when the instance of PdoOne is created. + * Inject an instance of a messagecontainer. It is usually injected automatically when the instance of PdoOne is + * created. * * @param MessageContainer $messageContainer * @return void */ public function setMessages($messageContainer): void { - $this->messageContainer=$messageContainer; + $this->messageContainer = $messageContainer; } public function debugFile($txt, $level = 'INFO'): void @@ -1659,7 +2240,7 @@ public function debugFile($txt, $level = 'INFO'): void */ public function storeInfo($txt): void { - if ($this->logLevel <2 ) { + if ($this->logLevel < 2) { return; } $this->messageContainer->addItem($this->lockerId, $txt, 'info'); @@ -1707,7 +2288,6 @@ private function strposa($haystack, $needles = [], $offset = 0) if (empty($chr)) { return false; } - return min($chr); } @@ -1744,10 +2324,8 @@ public function runRawQuery($rawSql, $params = null, $returnArray = true, $useCa return false; } $writeCommand = self::queryCommand($rawSql, true) !== 'dql'; - /** @var bool|string $uid it stores the unique identifier of the query */ $uid = false; - if ($this->readonly && $writeCommand) { // we aren't checking SQL-DLC queries. Also, "insert into" is stopped but " insert into" not. $this->throwError('Database is in READ ONLY MODE', ''); @@ -1769,7 +2347,6 @@ public function runRawQuery($rawSql, $params = null, $returnArray = true, $useCa return $this->internalCache[$uid]; } } - $this->lastParam = $params; $this->lastQuery = $rawSql; $this->storeInfo($rawSql); @@ -1781,7 +2358,6 @@ public function runRawQuery($rawSql, $params = null, $returnArray = true, $useCa $this->endTry(); return $rows; } - // the "where" has parameters. $stmt = $this->prepare($rawSql); if ($stmt === false) { @@ -1806,7 +2382,7 @@ public function runRawQuery($rawSql, $params = null, $returnArray = true, $useCa foreach ($params as $param) { $this->lastBindParam[$counter] = $param[0]; // note: the second field is & so we could not use $v - $param[3]=$param[3]??0; + $param[3] = $param[3] ?? 0; $stmt->bindParam(...$param); } } else { @@ -1816,7 +2392,7 @@ public function runRawQuery($rawSql, $params = null, $returnArray = true, $useCa //$typeP = $this->stringToPdoParam($param[$i]); $this->lastBindParam[$i] = $iValue; //$stmt->bindParam($counter, $param[$i + 1], $typeP); - $stmt->bindParam($i + 1, $params[$i], $this->getType($params[$i]),0); + $stmt->bindParam($i + 1, $params[$i], $this->getType($params[$i]), 0); } } } @@ -1840,7 +2416,6 @@ public function runRawQuery($rawSql, $params = null, $returnArray = true, $useCa $this->uid = null; } $this->runQuery($stmt); - if ($returnArray && $stmt instanceof PDOStatement) { $rows = ($stmt->columnCount() > 0) ? $stmt->fetchAll(PDO::FETCH_ASSOC) : []; $this->affected_rows = $stmt->rowCount(); @@ -1851,7 +2426,6 @@ public function runRawQuery($rawSql, $params = null, $returnArray = true, $useCa $this->endTry(); return $rows; } - if ($stmt instanceof PDOStatement) { $this->affected_rows = $stmt->rowCount(); } else { @@ -1913,7 +2487,6 @@ private function runRawQueryParamLess($rawSql, $returnArray) $rows = false; $this->throwError('Exception in runRawQueryParamLess :', $rawSql, ['param' => $this->lastParam], true, $ex); } - if ($returnArray && $rows instanceof PDOStatement) { if ($rows->columnCount() > 0) { $result = @$rows->fetchAll(PDO::FETCH_ASSOC); @@ -1921,7 +2494,6 @@ private function runRawQueryParamLess($rawSql, $returnArray) $this->endTry(); return $result; } - $this->affected_rows = $rows->rowCount(); $this->endTry(); return true; @@ -1959,9 +2531,7 @@ public function prepare($sql) $this->throwError('Database is in READ ONLY MODE', ''); } } - $this->storeInfo($sql); - try { $stmt = $this->conn1->prepare($sql); } catch (Exception $ex) { @@ -1969,7 +2539,6 @@ public function prepare($sql) $this->throwError('Failed to prepare', $ex->getMessage() . $this->lastError(), ['param' => $this->lastParam], true, $ex); } if (($stmt === false) && $this->errorText === '') { - $this->throwError('Unable to prepare query', $this->lastQuery, ['param' => $this->lastParam]); } $this->endTry(); @@ -1996,7 +2565,6 @@ private function isAssoc($array): bool if (!is_array($array)) { return false; } - return (array_values($array) !== $array); } @@ -2020,7 +2588,6 @@ public function getType(&$v): int $vt = PDO::PARAM_INT; break; case (is_bool($v)): - $vt = PDO::PARAM_INT; $v = ($v) ? 1 : 0; break; @@ -2031,7 +2598,6 @@ public function getType(&$v): int default: $vt = PDO::PARAM_STR; } - return $vt; } @@ -2084,7 +2650,6 @@ protected static function fixCsv($value) return $value; } $value = str_replace('"', '""', $value); - return '"' . $value . '"'; } @@ -2107,7 +2672,6 @@ public function generateCodeSelect($query): string $this->beginTry(); $q = self::splitQuery($query); $code = '/** @var array $result=array(' . $this->generateCodeArray($query, $query) . ') */' . "\n"; - $code .= '$result=$pdo' . "\n"; foreach ($q as $k => $v) { if ($v !== null) { @@ -2211,7 +2775,6 @@ protected static function splitQuery($query): array } } } - return $result; } @@ -2243,7 +2806,6 @@ public function generateCodeArray( } $query = new PdoOneQuery($this); $r = $query->toMeta($sql); - $ln = ($inline) ? '' : "\n"; if ($recursive) { /** @noinspection PhpUnusedLocalVariableInspection */ @@ -2280,11 +2842,9 @@ public function generateCodeArray( $default = 'null'; } if (!in_array($colName, $norepeat)) { - if (isset($relation[$colName])) { $rc =& $relation[$colName]; $key = $rc['key']; - if ($key === 'PARENT') { $default = 'null'; } @@ -2349,7 +2909,6 @@ public function generateCodeArray( } } } - $used[] = $name; } $result .= ']' . $ln; @@ -2358,7 +2917,6 @@ public function generateCodeArray( } /** @noinspection PhpSameParameterValueInspection */ - /** * It returns an array with all the tables of the schema, also the foreign key and references of each table
* Example: @@ -2455,9 +3013,9 @@ public function objectList($type = 'table', $onlyName = false) // query has an argument if ($onlyName) { $values = $this->runRawQuery($query, [$this->db]); - $final=[]; - foreach($values as $v) { - $final[]=reset($v); + $final = []; + foreach ($values as $v) { + $final[] = reset($v); } return $final; } @@ -2474,7 +3032,6 @@ public function select($sql): PdoOneQuery } // - private function typeDict($row) { return $this->service->typeDict($row, true); @@ -2520,7 +3077,6 @@ public static function varExport($input, $indent = "\t"): ?string $r[] = "$indent " . ($indexed ? '' : self::varExport($key) . ' => ') . self::varExport($value, "$indent "); } - $r = "[\n" . implode(",\n", $r) . "\n" . $indent . ']'; break; case 'boolean': @@ -2593,10 +3149,9 @@ public function generateCodeClass( ) { $this->beginTry(); - $filename=__DIR__ . '/template/template_abstractclassrepo.php'; + $filename = __DIR__ . '/template/template_abstractclassrepo.php'; $r = $this->phpstart . $this->openTemplate($filename); $lastns = explode('\\', $namespace); - if ($modelfullClass) { $arr = explode('\\', $modelfullClass); $modelClass = end($arr); @@ -2605,12 +3160,10 @@ public function generateCodeClass( $modelClass = false; $modelUse = false; } - if ($baseClass === null) { $tmp3 = end($lastns); $baseClass = $tmp3 === false ? '' : $tmp3; } - $fa = func_get_args(); foreach ($fa as $f => $k) { if (is_array($k)) { @@ -2624,13 +3177,11 @@ public function generateCodeClass( } else { $className = $classRelations[$tableName]; } - $extraColArray = ''; foreach ($extraCols as $k => $v) { $extraColArray .= $v . ' as ' . $this->addQuote($k) . ','; } $extraColArray = rtrim($extraColArray, ','); - $r = str_replace(array( '{version}', '{classname}', @@ -2661,14 +3212,12 @@ public function generateCodeClass( $pk = '??'; $pk = $this->service->getPK($tableName, $pk); $pkFirst = (is_array($pk) && count($pk) > 0) ? $pk[0] : null; - try { $relation = $this->getDefTableFK($tableName, false, true); } catch (Exception $e) { $this->endTry(); return 'Error: Unable read fk of table ' . $e->getMessage(); } - // many to many /*foreach ($relation as $rel) { $tableMxM = $rel['reftable']; @@ -2740,7 +3289,6 @@ public function generateCodeClass( if ($pks !== false || count($pks) === 2) { $relation[$k]['key'] = 'MANYTOMANY'; $refcol2 = (self::$prefixBase . $pks[0] === $relation[$k]['refcol']) ? $pks[1] : $pks[0]; - try { $defsFK = $this->service->getDefTableFK($relation[$k]['reftable'], false); } catch (Exception $e) { @@ -2755,7 +3303,7 @@ public function generateCodeClass( return 'Error: Unable read table dependencies' . $e->getMessage(); } $relation[$k]['refcol2'] = self::$prefixBase . $refcol2; - if (count($keys2)>0) { + if (count($keys2) > 0) { $keys2 = array_keys($keys2); $relation[$k]['col2'] = $keys2[0]; } else { @@ -2772,16 +3320,12 @@ public function generateCodeClass( $convertOutput = ''; $convertInput = ''; $getDefTable = $this->getDefTable($tableName, $specialConversion); - foreach ($columnRemove as $v) { unset($getDefTable[$v]); } //die(1); - // we forced the conversion but only if it is not specified explicit - $allColumns = array_merge($getDefTable, $extraCols); // $extraColArray does not has type - foreach ($allColumns as $kcol => $colDef) { $type = $colDef['type'] ?? null; $conversion = null; @@ -2798,7 +3342,6 @@ public function generateCodeClass( $conversion = $this->codeClassConversion[$type]; $getDefTable[$kcol]['conversion'] = $conversion; } - if ($conversion !== null) { if (is_array($conversion)) { list($input, $output) = $conversion; @@ -2806,7 +3349,6 @@ public function generateCodeClass( $input = $conversion; $output = $input; } - switch ($input) { case 'encrypt': $tmp2 = "isset(%s) and %s=self::getPdoOne()->encrypt(%s);"; @@ -2881,6 +3423,8 @@ public function generateCodeClass( $tmp = "%s=isset(%s) ? (float)%s : null;"; break; case null: + case 'nothing': + case 'null': $tmp = "!isset(%s) and %s=null; // no conversion"; break; default: @@ -2890,7 +3434,6 @@ public function generateCodeClass( $tmp = '// type ' . $output . ' not defined'; } } - if ($tmp !== '') { $convertOutput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp) . "\n"; $convertInput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp2) . "\n"; @@ -2900,7 +3443,6 @@ public function generateCodeClass( $convertOutput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp) . "\n"; } } - $linked = ''; foreach ($relation as $k => $v) { $key = $v['key']; @@ -2918,10 +3460,8 @@ public function generateCodeClass( } } //$convertOutput.=$linked; - $convertOutput = rtrim($convertOutput, "\n"); $convertInput = rtrim($convertInput, "\n"); - // discard columns //$identities=$this->getDefTableKeys($tableName,); $identities = $this->getDefIdentities($tableName); @@ -2945,7 +3485,6 @@ public function generateCodeClass( /** @noinspection AdditionOperationOnArraysInspection */ $noUpdate += $pk; // it adds and replaces duplicates, indexes are ignored. } - $relation2 = []; foreach ($relation as $col => $arr) { if ($arr['key'] !== 'FOREIGN KEY' && $arr['key'] !== 'PARENT' && $arr['key'] !== 'NONE') { @@ -2955,7 +3494,6 @@ public function generateCodeClass( // $relation2[]=$col; // } } - try { $r = str_replace(array( '{pk}', @@ -3003,6 +3541,77 @@ public function generateCodeClass( return $r; } + /** + * @param string $tableName + * @param string $pkFirst the first primary key (if any) + * @return array=['key','refcol','reftable','extra','name'][$i] where the key of the array is the name of the column + */ + public function xxx($tableName, $pkFirst): array + { + try { + $relation = $this->getDefTableFK($tableName, false, true); + } catch (Exception $e) { + $this->endTry(); + throw new RuntimeException('Error: Unable read fk of table ' . $e->getMessage()); + } + // many to many + /*foreach ($relation as $rel) { + $tableMxM = $rel['reftable']; + $tableFK = $this->getDefTableFK($tableMxM, false, true); + } + */ + try { + $deps = $this->tableDependency(true); + } catch (Exception $e) { + $this->endTry(); + throw new RuntimeException('Error: Unable read table dependencies ' . $e->getMessage()); + } // ["city"]=> {["city_id"]=> "address"} + $after = @$deps[1][$tableName]; + if ($after === null) { + $after = @$deps[1][strtolower($tableName)]; + } + $before = @$deps[2][$tableName]; + if ($before === null) { + $before = @$deps[2][strtolower($tableName)]; + } + if (is_array($after) && is_array($before)) { + foreach ($before as $key => $rows) { // $value is [relcol,table] + foreach ($rows as $value) { + $relation[self::$prefixBase . $value[1]] = [ + 'key' => 'ONETOMANY', + 'col' => $key, + 'reftable' => $value[1], + 'refcol' => $value[0] //, ltrim( $value[0],self::$prefixBase) + ]; + } + } + } + // converts relations to ONETOONE + foreach ($relation as $k => $rel) { + if ($rel['key'] === 'ONETOMANY') { + $pkref = null; + $pkref = $this->service->getPK($rel['reftable'], $pkref); + if (self::$prefixBase . $pkref[0] === $rel['refcol'] && count($pkref) === 1) { + $relation[$k]['key'] = 'ONETOONE'; + $relation[$k]['refcol'] = ltrim($relation[$k]['refcol'], self::$prefixBase); + } + } + if ($rel['key'] === 'MANYTOONE') { + $pkref = null; + $pkref = $this->service->getPK($rel['reftable'], $pkref); + if ($pkref[0] === $rel['refcol'] && count($pkref) === 1 + && (strcasecmp($k, self::$prefixBase . $pkFirst) === 0) + ) { + // if they are linked by the pks and the pks are only 1. + $relation[$k]['key'] = 'ONETOONE'; + $relation[$k]['col'] = $pkFirst; + $relation[$k]['refcol'] = ltrim($relation[$k]['refcol'], self::$prefixBase); + } + } + } + return $relation; + } + /** * It returns a field, column or table, the quotes defined by the current database type. It doesn't considers points * or space
@@ -3100,7 +3709,6 @@ public function startTransaction(): bool } $this->transactionOpen = true; $this->conn1->beginTransaction(); - return true; } @@ -3182,7 +3790,7 @@ public function rollback($throw = true): bool *int (integer) *float (decimal) *custom function are defined by expression plus %s. Example trim(%s) - *null (no conversion) + *null/nothing (no conversion) * * * @param array $conversion An associative array where the key is the type and the value is the conversion. @@ -3196,13 +3804,9 @@ public function generateCodeClassConversions($conversion = []): void $this->codeClassConversion = $conversion; } // - //- - // //- /** * It builds (generates source code) of the base, repo and repoext classes of the current schema. //
* Example:
@@ -3288,7 +3892,6 @@ public function generateAllClasses( { $internalCache = $this->useInternalCache; $this->setUseInternalCache(); - if (is_array($folders)) { list($folder, $folderModel) = $folders; } else { @@ -3302,7 +3905,6 @@ public function generateAllClasses( $namespaceModel = $namespaces; } $firstKeyRelation = array_keys($relations)[0]; - $firstRelation = $relations[$firstKeyRelation]; // the first value of the relation arrays. if (is_array($firstRelation)) { $useModel = true; @@ -3331,7 +3933,6 @@ public function generateAllClasses( } catch (Exception $exception) { $result = false; } - if ($result === false) { $logs[] = "Unable to save Base Class file '$folder$baseClass.php'"; } @@ -3346,7 +3947,6 @@ public function generateAllClasses( $custom = (isset($columnRelations[$tableName])) ? $columnRelations[$tableName] : []; $extraCols = (isset($extraColumns[$tableName])) ? $extraColumns[$tableName] : []; $columnRem = (isset($columnRemoves[$tableName])) ? $columnRemoves[$tableName] : []; - $classCode1 = $this->generateCodeClass($tableName, $namespace, $custom, $relationsRepo, [], null, null, $baseClass, $modelname, $extraCols, $columnRem); $result = @file_put_contents($folder . "Abstract$className.php", $classCode1); @@ -3363,7 +3963,6 @@ public function generateAllClasses( //$custom = (isset($customRelation[$tableName])) ? $customRelation[$tableName] : []; $classModel1 = $this->generateAbstractModelClass($tableName, $namespaceModel, $custom, $relationsModel, [], null, null, $baseClass, $extraCols, $columnRem); - $result = @file_put_contents($folderModel . 'Abstract' . $relationsModel[$tableName] . '.php', $classModel1); } catch (Exception $e) { @@ -3392,7 +3991,6 @@ public function generateAllClasses( try { $filename = $folder . $className . '.php'; $classCode2 = $this->generateCodeClassRepo($tableName, $namespace, $relationsRepo, $modelname); - if ($force || @!file_exists($filename)) { // if the file exists then, we don't want to replace this class $result = @file_put_contents($filename, $classCode2); @@ -3424,9 +4022,11 @@ public function setUseInternalCache($useInternalCache = true): PdoOne $this->useInternalCache = $useInternalCache; return $this; } - protected function openTemplate($filename) { + + protected function openTemplate($filename) + { $template = @file_get_contents($filename); - if ($template=== false) { + if ($template === false) { throw new RuntimeException("Unable to read template file $filename"); } // we delete and replace the first line. @@ -3435,7 +4035,7 @@ protected function openTemplate($filename) { public function generateBaseClass($baseClassName, $namespace, $classes, $modelUse = false) { - $filename=__DIR__ . '/template/template_base.php'; + $filename = __DIR__ . '/template/template_base.php'; $r = $this->phpstart . $this->openTemplate($filename); /*foreach($classes as $id=>$entity) { foreach($entity as $k=>$class) { @@ -3444,7 +4044,6 @@ public function generateBaseClass($baseClassName, $namespace, $classes, $modelUs } */ $namespace = trim($namespace, '\\'); - return str_replace([ '{type}', '{class}', @@ -3471,7 +4070,6 @@ public function generateBaseClass($baseClassName, $namespace, $classes, $modelUs //- /** * @param string $tableName * @param string $namespace @@ -3502,13 +4100,10 @@ public function generateAbstractModelClass( ) { $this->beginTry(); - - $filename=__DIR__ . '/template/template_abstractmodel.php'; + $filename = __DIR__ . '/template/template_abstractmodel.php'; $r = $this->phpstart . $this->openTemplate($filename); - //$lastns = explode('\\', $namespace); //$baseClass = ($baseClass === null) ? end($lastns) : $baseClass; - $fa = func_get_args(); foreach ($fa as $f => $k) { if (is_array($k)) { @@ -3522,7 +4117,6 @@ public function generateAbstractModelClass( } else { $className = $classRelations[$tableName]; } - $r = str_replace(array( '{version}', '{classname}', @@ -3537,65 +4131,7 @@ public function generateAbstractModelClass( $pk = '??'; $pk = $this->service->getPK($tableName, $pk); $pkFirst = (is_array($pk) && count($pk) > 0) ? $pk[0] : null; - - try { - $relation = $this->getDefTableFK($tableName, false, true); - } catch (Exception $e) { - $this->endTry(); - return 'Error: Unable read fk of table ' . $e->getMessage(); - } - - try { - $deps = $this->tableDependency(true); - } catch (Exception $e) { - $this->endTry(); - return 'Error: Unable read table dependencies ' . $e->getMessage(); - } // ["city"]=> {["city_id"]=> "address"} - $after = @$deps[1][$tableName]; - if ($after === null) { - $after = @$deps[1][strtolower($tableName)]; - } - $before = @$deps[2][$tableName]; - if ($before === null) { - $before = @$deps[2][strtolower($tableName)]; - } - if (is_array($after) && is_array($before)) { - foreach ($before as $key => $rows) { // $value is [relcol,table] - foreach ($rows as $value) { - $relation[self::$prefixBase . $value[1]] = [ - 'key' => 'ONETOMANY', - 'col' => $key, - 'reftable' => $value[1], - 'refcol' => $value[0] - ]; - } - } - } - // converts relations to ONETOONE - foreach ($relation as $k => $rel) { - if ($rel['key'] === 'ONETOMANY') { - $pkref = null; - $pkref = $this->service->getPK($rel['reftable'], $pkref); - if (self::$prefixBase . $pkref[0] === $rel['refcol'] && count($pkref) === 1) { - $relation[$k]['key'] = 'ONETOONE'; - $relation[$k]['col'] = 'xxx1'; - $relation[$k]['refcol'] = ltrim($relation[$k]['refcol'], self::$prefixBase); - } - } - if ($rel['key'] === 'MANYTOONE') { - $pkref = null; - $pkref = $this->service->getPK($rel['reftable'], $pkref); - - if ($pkref[0] === $rel['refcol'] && count($pkref) === 1 - && (strcasecmp($k, self::$prefixBase . $pkFirst) === 0) - ) { - // if they are linked by the pks and the pks are only 1. - $relation[$k]['key'] = 'ONETOONE'; - $relation[$k]['col'] = 'xxx2'; - $relation[$k]['refcol'] = ltrim($relation[$k]['refcol'], self::$prefixBase); - } - } - } + $relation = $this->xxx($tableName, $pkFirst); if ($customRelation) { foreach ($relation as $k => $rel) { if (isset($customRelation[$k])) { @@ -3613,7 +4149,6 @@ public function generateAbstractModelClass( $relation[$k]['key'] = 'MANYTOMANY'; $refcol2 = (self::$prefixBase . $pks[0] === $relation[$k]['refcol']) ? $pks[1] : $pks[0]; - try { $defsFK = $this->service->getDefTableFK($relation[$k]['reftable'], false); } catch (Exception $e) { @@ -3628,7 +4163,7 @@ public function generateAbstractModelClass( return 'Error: Unable read table dependencies' . $e->getMessage(); } $relation[$k]['refcol2'] = self::$prefixBase . $refcol2; - if (count($keys2)>0) { + if (count($keys2) > 0) { $keys2 = array_keys($keys2); $relation[$k]['col2'] = $keys2[0]; } else { @@ -3642,13 +4177,10 @@ public function generateAbstractModelClass( } } //die(1); - $gdf = $this->getDefTable($tableName, $specialConversion); - foreach ($columnRemove as $v) { unset($gdf[$v]); } - $fields = []; $fieldsb = []; foreach ($gdf as $varn => $field) { @@ -3673,7 +4205,6 @@ public function generateAbstractModelClass( } $fieldsArr = implode("\n", $fields); $fieldsbArr = implode("\n", $fieldsb); - $field2s = []; $field2sb = []; foreach ($relation as $varn => $field) { @@ -3716,20 +4247,15 @@ public function generateAbstractModelClass( $field2sb[] = "\t\t\$obj->$varn=isset(\$array['$varn']) ? \$obj->$varn=$class::fromArray(\$array['$varn']) : null; // onetoone"; - $col = $field['col'] ?? $pkFirst; - $rcol = $field['refcol']; - $field2sb[] = "\t\t(\$obj->$varn !== null) and \$obj->$varn->$rcol=&\$obj->$col; // linked onetoone"; break; } } - $fields2Arr = implode("\n", $field2s); $fields2Arrb = implode("\n", $field2sb); - $r = str_replace(['{fields}', '{fieldsrel}', '{fieldsfa}', '{fieldsrelfa}'], [$fieldsArr, $fields2Arr, $fieldsbArr, $fields2Arrb], $r); if (@count($this->codeClassConversion) > 0) { @@ -3741,7 +4267,6 @@ public function generateAbstractModelClass( } } } - // discard columns $identities = $this->getDefIdentities($tableName); if ($defNoInsert !== null) { @@ -3754,7 +4279,6 @@ public function generateAbstractModelClass( } else { $noUpdate = $identities; } - try { $r = str_replace(array( '{pk}', @@ -3819,11 +4343,10 @@ public function generateModelClass( { $this->beginTry(); // - $filename=__DIR__ . '/template/template_classrepo.php'; + $filename = __DIR__ . '/template/template_classrepo.php'; $r = $this->phpstart . $this->openTemplate($filename); //$lastns = explode('\\', $namespace); //$baseClass = ($baseClass === null) ? end($lastns) : $baseClass; - $fa = func_get_args(); foreach ($fa as $f => $k) { if (is_array($k)) { @@ -3837,7 +4360,6 @@ public function generateModelClass( } else { $className = $classRelations[$tableName]; } - $r = str_replace(array( '{version}', '{classname}', @@ -3852,13 +4374,11 @@ public function generateModelClass( $pk = '??'; $pk = $this->service->getPK($tableName, $pk); $pkFirst = (is_array($pk) && count($pk) > 0) ? $pk[0] : null; - try { $relation = $this->getDefTableFK($tableName, false, true); } catch (Exception $e) { return 'Error: Unable read fk of table ' . $e->getMessage(); } - try { $deps = $this->tableDependency(true); } catch (Exception $e) { @@ -3899,7 +4419,6 @@ public function generateModelClass( if ($rel['key'] === 'MANYTOONE') { $pkref = null; $pkref = $this->service->getPK($rel['reftable'], $pkref); - if ($pkref[0] === $rel['refcol'] && count($pkref) === 1 && (strcasecmp($k, self::$prefixBase . $pkFirst) === 0) ) { @@ -3926,7 +4445,6 @@ public function generateModelClass( $relation[$k]['key'] = 'MANYTOMANY'; $refcol2 = (self::$prefixBase . $pks[0] === $relation[$k]['refcol']) ? $pks[1] : $pks[0]; - try { $defsFK = $this->service->getDefTableFK($relation[$k]['reftable'], false); } catch (Exception $e) { @@ -3941,7 +4459,7 @@ public function generateModelClass( return 'Error: Unable read table dependencies' . $e->getMessage(); } $relation[$k]['refcol2'] = self::$prefixBase . $refcol2; - if (count($keys2)>0) { + if (count($keys2) > 0) { $keys2 = array_keys($keys2); $relation[$k]['col2'] = $keys2[0]; } else { @@ -3955,7 +4473,6 @@ public function generateModelClass( } } //die(1); - $gdf = $this->getDefTable($tableName, $specialConversion); $fields = []; $fieldsb = []; @@ -3977,7 +4494,6 @@ public function generateModelClass( } $fieldsArr = implode("\n", $fields); $fieldsbArr = implode("\n", $fieldsb); - $field2s = []; $field2sb = []; foreach ($relation as $varn => $field) { @@ -4019,10 +4535,8 @@ public function generateModelClass( break; } } - $fields2Arr = implode("\n", $field2s); $fields2Arrb = implode("\n", $field2sb); - $r = str_replace(['{fields}', '{fieldsrel}', '{fieldsfa}', '{fieldsrelfa}'], [$fieldsArr, $fields2Arr, $fieldsbArr, $fields2Arrb], $r); if (@count($this->codeClassConversion) > 0) { @@ -4034,7 +4548,6 @@ public function generateModelClass( } } } - // discard columns $identities = $this->getDefIdentities($tableName); if ($defNoInsert !== null) { @@ -4047,7 +4560,6 @@ public function generateModelClass( } else { $noUpdate = $identities; } - try { $r = str_replace(array( '{pk}', @@ -4088,7 +4600,6 @@ public function generateModelClass( // //- public function generateCodeClassRepo( $tableClassName, $namespace = '', @@ -4098,9 +4609,8 @@ public function generateCodeClassRepo( { $this->beginTry(); // - $filename=__DIR__ . '/template/template_codeclassrepo.php'; + $filename = __DIR__ . '/template/template_codeclassrepo.php'; $r = $this->phpstart . $this->openTemplate($filename); - $fa = func_get_args(); foreach ($fa as $f => $k) { if (is_array($k)) { @@ -4109,7 +4619,6 @@ public function generateCodeClassRepo( $fa[$f] = "'$k'"; } } - if ($modelfullClass) { $arr = explode('\\', $modelfullClass); $modelClass = end($arr); @@ -4233,7 +4742,6 @@ public function insert_id($sequenceName = null) if (!$this->isOpen) { return -1; } - $id = $this->conn1->lastInsertId($sequenceName); return $id === false ? false : (int)$id; } @@ -4264,7 +4772,7 @@ public function setCacheService($cacheService): PdoOne * INTEGER * @param string $salt Salt is not used by SIMPLE or * INTEGER
- * @param string $encMethodExample : AES-256-CTR See + * @param string $encMethod
Example: AES-256-CTR See * http://php.net/manual/en/function.openssl-get-cipher-methods.php *
*if SIMPLE then the encryption is @@ -4302,7 +4810,6 @@ public function setEncryption($password, $salt, $encMethod = 'AES-256-CTR'): Pdo * @return int|string|null * @see \eftec\PdoOneEncryption::encrypt */ - public function encrypt($data) { return $this->encryption->encrypt($data); @@ -4337,7 +4844,6 @@ public function render(): void if ($this->logLevel) { ob_clean(); } - /** @noinspection PhpIfWithCommonPartsInspection */ if (!$this->logLevel) { $web = <<<'LOGS' @@ -4569,7 +5075,6 @@ public function render(): void