diff --git a/README.md b/README.md
index 70a0001..0ac5e82 100644
--- a/README.md
+++ b/README.md
@@ -1953,8 +1953,18 @@ In a nutshell:
* Every minor version means that it adds a new functionality i.e. 1.5 -> 1.6 (new methods)
* Every decimal version means that it patches/fixes/refactoring a previous functionality i.e. 1.5.0 -> 1.5.1 (fix)
+
+
+
+
+* 2.9.4 2021-03-22
+ * **ORM:** **_BasePdoOneRepo** is updated to BINARYVERSION=4. If you are using the ORM, then you should rebuild all ORM classes.
+ * **CORE:** Query chains creates a new instance of **PdoOneQuery** instead of a instance of **PdoOne**, so it is possible to define
+ multiples chains without interfering each others.
+ * **ORM:** Fixed a problem with the base class. Now the Base class contains the constant COMPILEDVERSION
+ * **ORM**: Fixed a problem with the model and the method toArray()
* 2.9.3 2021-02-22
- * fix a bug with useCache() when we use with where()
+ * fix a bug with **useCache()** when we use with where()
* 2.9.2 2021-02-18
* fixed a bug with createSequence()
* 2.9.1 2021-02-16
@@ -2032,7 +2042,6 @@ echo $this->internalCacheCounter;
```
* The internal cache is tested with runRawQuery (if returns an array), toList(), meta() and first()
-
* 2.0.1 2020-08-12
* Fixed a bug with the generated code with linked relation manytoone and onetonone.
* 2.0 2020-08-11
diff --git a/composer.json b/composer.json
index dc31d31..f67c45e 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,6 @@
{
"name": "eftec/pdoone",
"description": "Procedural PDO Data access class in a single Class",
- "version": "2.9.3",
"type": "library",
"keywords": [
"dao",
diff --git a/examples/repomysql/generated/AbstractTableCategoryRepo.php b/examples/repomysql/generated/AbstractTableCategoryRepo.php
deleted file mode 100644
index 61b393d..0000000
--- a/examples/repomysql/generated/AbstractTableCategoryRepo.php
+++ /dev/null
@@ -1,403 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass('TableCategory','repomysql',array(),array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',),array(),'','','TestDb','mysql\repomodel\TableCategoryModel',array(),array());
- *
- */
-abstract class AbstractTableCategoryRepo extends TestDb
-{
- const TABLE = 'TableCategory';
- const COMPILEDVERSION=3;
- const IDENTITY = NULL;
- const PK = [
- 'IdTableCategoryPK'
- ];
- const ME=__CLASS__;
- const EXTRACOLS='';
-
- /**
- * 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 = [
- 'IdTableCategoryPK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => FALSE,
- 'identity' => FALSE,
- 'sql' => 'int not null'
- ],
- 'Name' => [
- 'phptype' => 'string',
- 'conversion' => NULL,
- 'type' => 'varchar',
- 'size' => '200',
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'varchar(200)'
- ]
- ];
- 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['IdTableCategoryPK']=isset($row['IdTableCategoryPK']) ? (int)$row['IdTableCategoryPK'] : null;
- !isset($row['Name']) and $row['Name']=null; // varchar
-
- }
-
- /**
- * 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['IdTableCategoryPK']) and $row['IdTableCategoryPK']=(int)$row['IdTableCategoryPK'];
- }
-
-
- /**
- * It gets all the name of the columns.
- *
- * @return string[]
- */
- public static function getDefName() {
- return [
- 'IdTableCategoryPK',
- 'Name'
- ];
- }
-
- /**
- * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
- *
- * @return string[]
- */
- public static function getDefKey() {
- return [
- 'IdTableCategoryPK' => 'PRIMARY KEY'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when insert
- * @return string[]
- */
- public static function getDefNoInsert() {
- return [
-
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when update
- * @return string[]
- */
- public static function getDefNoUpdate() {
- return [
- 'IdTableCategoryPK'
- ];
- }
-
- /**
- * It adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
- *
- * @return TableCategoryRepo
- */
- public static function where($sql, $param = PdoOne::NULL)
- {
- self::getPdoOne()->where($sql, $param,false,TableCategoryRepo::TABLE);
- return TableCategoryRepo::class;
- }
-
- public static function getDefFK($structure=false) {
- if ($structure) {
- return [
-
- ];
- }
- /* key,refcol,reftable,extra */
- return [
- '_TableParentxCategory' => [
- 'key' => 'ONETOMANY',
- 'col' => 'IdTableCategoryPK',
- 'reftable' => 'TableParentxCategory',
- 'refcol' => '_idcategoryPKFK'
- ]
- ];
- }
-
- /**
- * 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= [
- 'ONETOMANY' => [
- '_TableParentxCategory'
- ]
- ];
- if($type==='*') {
- $result=[];
- foreach($r as $arr) {
- $result = array_merge($result,$arr);
- }
- return $result;
- }
- return isset($r[$type]) ? $r[$type] : [];
-
- }
-
- public static function toList($filter=PdoOne::NULL,$filterValue=null) {
- if(self::$useModel) {
- return TableCategoryModel::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:
- *
- * 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 TableCategoryRepo
- */
- public static function setRecursive($recursive=[])
- {
- if(is_string($recursive)) {
- $recursive=TableCategoryRepo::getRelations($recursive);
- }
- return parent::_setRecursive($recursive);
- }
-
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return TableCategoryRepo::class;
- }
-
- /**
- * It returns the first row of a query.
- * @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 TableCategoryModel::fromArray(self::_first($pk));
- }
- return self::_first($pk);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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 mixed
- * @throws Exception
- */
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
- }
-
- /**
- * It deletes an entity by the primary key.
- *
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
- *
- * @return mixed
- * @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= [
- 'IdTableCategoryPK'=>0,
- '_TableParentxCategory'=>(in_array($recursivePrefix.'_TableParentxCategory',$recursive,true))
- ? []
- : null, /* ONETOMANY! */
- 'Name'=>''
- ];
-
- 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= [
- 'IdTableCategoryPK'=>null,
- '_TableParentxCategory'=>null, /* ONETOMANY! */
- 'Name'=>null
- ];
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
- }
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/AbstractTableChildRepo.php b/examples/repomysql/generated/AbstractTableChildRepo.php
deleted file mode 100644
index 540b3f2..0000000
--- a/examples/repomysql/generated/AbstractTableChildRepo.php
+++ /dev/null
@@ -1,443 +0,0 @@
-
- * $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 COMPILEDVERSION=3;
- const IDENTITY = 'idtablachildPK';
- const PK = [
- 'idtablachildPK'
- ];
- const ME=__CLASS__;
- const EXTRACOLS='';
-
- /**
- * 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;
- }
-
- /**
- * 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 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 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 adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
- *
- * @return TableChildRepo
- */
- public static function where($sql, $param = PdoOne::NULL)
- {
- self::getPdoOne()->where($sql, $param,false,TableChildRepo::TABLE);
- return TableChildRepo::class;
- }
-
- 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' => 'tablachild_fk1'
- ],
- '_idgrandchildFK' => [
- 'key' => 'MANYTOONE',
- 'refcol' => 'idgrandchildPK',
- 'reftable' => 'TableGrandChild',
- 'extra' => '',
- 'name' => 'tablachild_fk1'
- ],
- '_TableParent' => [
- 'key' => 'ONETOMANY',
- 'col' => 'idtablachildPK',
- 'reftable' => 'TableParent',
- 'refcol' => '_idchild2FK'
- ]
- ];
- }
-
- /**
- * 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 isset($r[$type]) ? $r[$type] : [];
-
- }
-
- 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:
- *
- * 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 TableChildRepo
- */
- public static function setRecursive($recursive=[])
- {
- if(is_string($recursive)) {
- $recursive=TableChildRepo::getRelations($recursive);
- }
- return parent::_setRecursive($recursive);
- }
-
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return TableChildRepo::class;
- }
-
- /**
- * It returns the first row of a query.
- * @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:
- *
- * $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);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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 mixed
- * @throws Exception
- */
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
- }
-
- /**
- * It deletes an entity by the primary key.
- *
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
- *
- * @return mixed
- * @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
-
- 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;
- }
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/AbstractTableGrandChildRepo.php b/examples/repomysql/generated/AbstractTableGrandChildRepo.php
deleted file mode 100644
index 69a2cd6..0000000
--- a/examples/repomysql/generated/AbstractTableGrandChildRepo.php
+++ /dev/null
@@ -1,414 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass('TableGrandChild','repomysql',array(),array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',),array(),'','','TestDb','mysql\repomodel\TableGrandChildModel',array(),array());
- *
- */
-abstract class AbstractTableGrandChildRepo extends TestDb
-{
- const TABLE = 'TableGrandChild';
- const COMPILEDVERSION=3;
- const IDENTITY = 'idgrandchildPK';
- const PK = [
- 'idgrandchildPK'
- ];
- const ME=__CLASS__;
- const EXTRACOLS='';
-
- /**
- * 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 = [
- 'idgrandchildPK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => FALSE,
- 'identity' => TRUE,
- 'sql' => 'int not null auto_increment'
- ],
- 'NameGrandChild' => [
- 'phptype' => 'string',
- 'conversion' => NULL,
- 'type' => 'varchar',
- 'size' => '50',
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'varchar(50)'
- ]
- ];
- 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['idgrandchildPK']=isset($row['idgrandchildPK']) ? (int)$row['idgrandchildPK'] : null;
- !isset($row['NameGrandChild']) and $row['NameGrandChild']=null; // varchar
-
- }
-
- /**
- * 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['idgrandchildPK']) and $row['idgrandchildPK']=(int)$row['idgrandchildPK'];
- }
-
-
- /**
- * It gets all the name of the columns.
- *
- * @return string[]
- */
- public static function getDefName() {
- return [
- 'idgrandchildPK',
- 'NameGrandChild'
- ];
- }
-
- /**
- * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
- *
- * @return string[]
- */
- public static function getDefKey() {
- return [
- 'idgrandchildPK' => 'PRIMARY KEY'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when insert
- * @return string[]
- */
- public static function getDefNoInsert() {
- return [
- 'idgrandchildPK'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when update
- * @return string[]
- */
- public static function getDefNoUpdate() {
- return [
- 'idgrandchildPK'
- ];
- }
-
- /**
- * It adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
- *
- * @return TableGrandChildRepo
- */
- public static function where($sql, $param = PdoOne::NULL)
- {
- self::getPdoOne()->where($sql, $param,false,TableGrandChildRepo::TABLE);
- return TableGrandChildRepo::class;
- }
-
- public static function getDefFK($structure=false) {
- if ($structure) {
- return [
-
- ];
- }
- /* key,refcol,reftable,extra */
- return [
- '_TableChild' => [
- 'key' => 'ONETOMANY',
- 'col' => 'idgrandchildPK',
- 'reftable' => 'TableChild',
- 'refcol' => '_idgrandchildFK'
- ],
- '_TableGrandChildTag' => [
- 'key' => 'ONETOMANY',
- 'col' => 'idgrandchildPK',
- 'reftable' => 'TableGrandChildTag',
- 'refcol' => '_IdgrandchildFK'
- ]
- ];
- }
-
- /**
- * 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= [
- 'ONETOMANY' => [
- '_TableChild',
- '_TableGrandChildTag'
- ]
- ];
- if($type==='*') {
- $result=[];
- foreach($r as $arr) {
- $result = array_merge($result,$arr);
- }
- return $result;
- }
- return isset($r[$type]) ? $r[$type] : [];
-
- }
-
- public static function toList($filter=PdoOne::NULL,$filterValue=null) {
- if(self::$useModel) {
- return TableGrandChildModel::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:
- *
- * 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 TableGrandChildRepo
- */
- public static function setRecursive($recursive=[])
- {
- if(is_string($recursive)) {
- $recursive=TableGrandChildRepo::getRelations($recursive);
- }
- return parent::_setRecursive($recursive);
- }
-
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return TableGrandChildRepo::class;
- }
-
- /**
- * It returns the first row of a query.
- * @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 TableGrandChildModel::fromArray(self::_first($pk));
- }
- return self::_first($pk);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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 mixed
- * @throws Exception
- */
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
- }
-
- /**
- * It deletes an entity by the primary key.
- *
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
- *
- * @return mixed
- * @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= [
- 'idgrandchildPK'=>0,
- '_TableChild'=>(in_array($recursivePrefix.'_TableChild',$recursive,true))
- ? []
- : null, /* ONETOMANY! */
- '_TableGrandChildTag'=>(in_array($recursivePrefix.'_TableGrandChildTag',$recursive,true))
- ? []
- : null, /* ONETOMANY! */
- 'NameGrandChild'=>''
- ];
-
- 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= [
- 'idgrandchildPK'=>null,
- '_TableChild'=>null, /* ONETOMANY! */
- '_TableGrandChildTag'=>null, /* ONETOMANY! */
- 'NameGrandChild'=>null
- ];
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
- }
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/AbstractTableGrandChildTagRepo.php b/examples/repomysql/generated/AbstractTableGrandChildTagRepo.php
deleted file mode 100644
index dcfb48b..0000000
--- a/examples/repomysql/generated/AbstractTableGrandChildTagRepo.php
+++ /dev/null
@@ -1,430 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass('TableGrandChildTag','repomysql',array(),array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',),array(),'','','TestDb','mysql\repomodel\TableGrandChildTagModel',array(),array());
- *
- */
-abstract class AbstractTableGrandChildTagRepo extends TestDb
-{
- const TABLE = 'TableGrandChildTag';
- const COMPILEDVERSION=3;
- const IDENTITY = 'IdTablaGrandChildTagPK';
- const PK = [
- 'IdTablaGrandChildTagPK'
- ];
- const ME=__CLASS__;
- const EXTRACOLS='';
-
- /**
- * 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 = [
- 'IdTablaGrandChildTagPK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => FALSE,
- 'identity' => TRUE,
- 'sql' => 'int not null auto_increment'
- ],
- 'Name' => [
- '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['IdTablaGrandChildTagPK']=isset($row['IdTablaGrandChildTagPK']) ? (int)$row['IdTablaGrandChildTagPK'] : null;
- !isset($row['Name']) and $row['Name']=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['IdTablaGrandChildTagPK']) and $row['IdTablaGrandChildTagPK']=(int)$row['IdTablaGrandChildTagPK'];
- isset($row['IdgrandchildFK']) and $row['IdgrandchildFK']=(int)$row['IdgrandchildFK'];
- }
-
-
- /**
- * It gets all the name of the columns.
- *
- * @return string[]
- */
- public static function getDefName() {
- return [
- 'IdTablaGrandChildTagPK',
- 'Name',
- 'IdgrandchildFK'
- ];
- }
-
- /**
- * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
- *
- * @return string[]
- */
- public static function getDefKey() {
- return [
- 'IdTablaGrandChildTagPK' => '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 [
- 'IdTablaGrandChildTagPK'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when update
- * @return string[]
- */
- public static function getDefNoUpdate() {
- return [
- 'IdTablaGrandChildTagPK'
- ];
- }
-
- /**
- * It adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
- *
- * @return TableGrandChildTagRepo
- */
- public static function where($sql, $param = PdoOne::NULL)
- {
- self::getPdoOne()->where($sql, $param,false,TableGrandChildTagRepo::TABLE);
- return TableGrandChildTagRepo::class;
- }
-
- 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_tablagrandchildcat_tablagrandchild'
- ],
- '_IdgrandchildFK' => [
- 'key' => 'MANYTOONE',
- 'refcol' => 'idgrandchildPK',
- 'reftable' => 'TableGrandChild',
- 'extra' => '',
- 'name' => 'FK_tablagrandchildcat_tablagrandchild'
- ]
- ];
- }
-
- /**
- * 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'
- ]
- ];
- if($type==='*') {
- $result=[];
- foreach($r as $arr) {
- $result = array_merge($result,$arr);
- }
- return $result;
- }
- return isset($r[$type]) ? $r[$type] : [];
-
- }
-
- public static function toList($filter=PdoOne::NULL,$filterValue=null) {
- if(self::$useModel) {
- return TableGrandChildTagModel::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:
- *
- * 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 TableGrandChildTagRepo
- */
- public static function setRecursive($recursive=[])
- {
- if(is_string($recursive)) {
- $recursive=TableGrandChildTagRepo::getRelations($recursive);
- }
- return parent::_setRecursive($recursive);
- }
-
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return TableGrandChildTagRepo::class;
- }
-
- /**
- * It returns the first row of a query.
- * @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 TableGrandChildTagModel::fromArray(self::_first($pk));
- }
- return self::_first($pk);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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 mixed
- * @throws Exception
- */
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
- }
-
- /**
- * It deletes an entity by the primary key.
- *
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
- *
- * @return mixed
- * @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= [
- 'IdTablaGrandChildTagPK'=>0,
- 'Name'=>'',
- '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;
- }
-
- /**
- * 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= [
- 'IdTablaGrandChildTagPK'=>null,
- 'Name'=>null,
- 'IdgrandchildFK'=>null,
- '_IdgrandchildFK'=>null, /* MANYTOONE!! */
- ];
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
- }
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/AbstractTableParentExtRepo.php b/examples/repomysql/generated/AbstractTableParentExtRepo.php
deleted file mode 100644
index e3e3025..0000000
--- a/examples/repomysql/generated/AbstractTableParentExtRepo.php
+++ /dev/null
@@ -1,406 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass('TableParentExt','repomysql',array('_idtablaparentExtPK'=>'PARENT',),array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',),array(),'','','TestDb','mysql\repomodel\TableParentExtModel',array(),array());
- *
- */
-abstract class AbstractTableParentExtRepo extends TestDb
-{
- const TABLE = 'TableParentExt';
- const COMPILEDVERSION=3;
- const IDENTITY = 'idtablaparentExtPK';
- const PK = [
- 'idtablaparentExtPK'
- ];
- const ME=__CLASS__;
- const EXTRACOLS='';
-
- /**
- * 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 = [
- 'idtablaparentExtPK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => FALSE,
- 'identity' => TRUE,
- 'sql' => 'int not null auto_increment'
- ],
- 'fieldExt' => [
- 'phptype' => 'string',
- 'conversion' => NULL,
- 'type' => 'varchar',
- 'size' => '50',
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'varchar(50)'
- ]
- ];
- 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['idtablaparentExtPK']=isset($row['idtablaparentExtPK']) ? (int)$row['idtablaparentExtPK'] : null;
- !isset($row['fieldExt']) and $row['fieldExt']=null; // varchar
-
- }
-
- /**
- * 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['idtablaparentExtPK']) and $row['idtablaparentExtPK']=(int)$row['idtablaparentExtPK'];
- }
-
-
- /**
- * It gets all the name of the columns.
- *
- * @return string[]
- */
- public static function getDefName() {
- return [
- 'idtablaparentExtPK',
- 'fieldExt'
- ];
- }
-
- /**
- * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
- *
- * @return string[]
- */
- public static function getDefKey() {
- return [
- 'idtablaparentExtPK' => 'PRIMARY KEY'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when insert
- * @return string[]
- */
- public static function getDefNoInsert() {
- return [
- 'idtablaparentExtPK'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when update
- * @return string[]
- */
- public static function getDefNoUpdate() {
- return [
- 'idtablaparentExtPK'
- ];
- }
-
- /**
- * It adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
- *
- * @return TableParentExtRepo
- */
- public static function where($sql, $param = PdoOne::NULL)
- {
- self::getPdoOne()->where($sql, $param,false,TableParentExtRepo::TABLE);
- return TableParentExtRepo::class;
- }
-
- public static function getDefFK($structure=false) {
- if ($structure) {
- return [
- 'idtablaparentExtPK' => 'FOREIGN KEY REFERENCES`TableParent`(`idtablaparentPK`)'
- ];
- }
- /* key,refcol,reftable,extra */
- return [
- 'idtablaparentExtPK' => [
- 'key' => 'FOREIGN KEY',
- 'refcol' => 'idtablaparentPK',
- 'reftable' => 'TableParent',
- 'extra' => '',
- 'name' => 'FK_tablaparent_ext_tablaparent'
- ],
- '_idtablaparentExtPK' => [
- 'key' => 'PARENT',
- 'refcol' => 'idtablaparentPK',
- 'reftable' => 'TableParent',
- 'extra' => '',
- 'name' => 'FK_tablaparent_ext_tablaparent',
- 'col' => 'idtablaparentExtPK'
- ]
- ];
- }
-
- /**
- * 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= [
-
- ];
- if($type==='*') {
- $result=[];
- foreach($r as $arr) {
- $result = array_merge($result,$arr);
- }
- return $result;
- }
- return isset($r[$type]) ? $r[$type] : [];
-
- }
-
- public static function toList($filter=PdoOne::NULL,$filterValue=null) {
- if(self::$useModel) {
- return TableParentExtModel::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:
- *
- * 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 TableParentExtRepo
- */
- public static function setRecursive($recursive=[])
- {
- if(is_string($recursive)) {
- $recursive=TableParentExtRepo::getRelations($recursive);
- }
- return parent::_setRecursive($recursive);
- }
-
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return TableParentExtRepo::class;
- }
-
- /**
- * It returns the first row of a query.
- * @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 TableParentExtModel::fromArray(self::_first($pk));
- }
- return self::_first($pk);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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 mixed
- * @throws Exception
- */
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
- }
-
- /**
- * It deletes an entity by the primary key.
- *
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
- *
- * @return mixed
- * @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= [
- 'idtablaparentExtPK'=>0,
- 'fieldExt'=>''
- ];
-
- 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= [
- 'idtablaparentExtPK'=>null,
- 'fieldExt'=>null
- ];
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
- }
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/AbstractTableParentRepo.php b/examples/repomysql/generated/AbstractTableParentRepo.php
deleted file mode 100644
index 931fe33..0000000
--- a/examples/repomysql/generated/AbstractTableParentRepo.php
+++ /dev/null
@@ -1,532 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass('TableParent','repomysql',array('_idchild2FK'=>'PARENT','_TableParentxCategory'=>'MANYTOMANY','fieldKey'=>array(0=>'encrypt',1=>NULL,),'extracol'=>'datetime3',),array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',),array(),'','','TestDb','mysql\repomodel\TableParentModel',array('extracol'=>'CURRENT_TIMESTAMP','extracol2'=>'20',),array(0=>'idchild2FK',));
- *
- */
-abstract class AbstractTableParentRepo extends TestDb
-{
- const TABLE = 'TableParent';
- const COMPILEDVERSION=3;
- const IDENTITY = 'idtablaparentPK';
- const PK = [
- 'idtablaparentPK'
- ];
- const ME=__CLASS__;
- const EXTRACOLS='CURRENT_TIMESTAMP as `extracol`,20 as `extracol2`';
-
- /**
- * 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 = [
- 'idtablaparentPK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => FALSE,
- 'identity' => TRUE,
- 'sql' => 'int not null auto_increment'
- ],
- 'fieldVarchar' => [
- 'phptype' => 'string',
- 'conversion' => NULL,
- 'type' => 'varchar',
- 'size' => '50',
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'varchar(50)'
- ],
- 'idchildFK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'int unsigned'
- ],
- 'fieldInt' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'int'
- ],
- 'fielDecimal' => [
- 'phptype' => 'float',
- 'conversion' => 'decimal',
- 'type' => 'decimal',
- 'size' => '9,2',
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'decimal(9,2)'
- ],
- 'fieldDateTime' => [
- 'phptype' => 'datetime',
- 'conversion' => 'datetime',
- 'type' => 'datetime',
- 'size' => NULL,
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'datetime'
- ],
- 'fieldUnique' => [
- 'phptype' => 'string',
- 'conversion' => NULL,
- 'type' => 'varchar',
- 'size' => '20',
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'varchar(20)'
- ],
- 'fieldKey' => [
- 'phptype' => 'string',
- 'conversion' => [
- 'encrypt',
- NULL
- ],
- 'type' => 'varchar',
- 'size' => '100',
- 'null' => TRUE,
- 'identity' => FALSE,
- 'sql' => 'varchar(100)'
- ]
- ];
- 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['idtablaparentPK']=isset($row['idtablaparentPK']) ? (int)$row['idtablaparentPK'] : null;
- !isset($row['fieldVarchar']) and $row['fieldVarchar']=null; // varchar
- $row['idchildFK']=isset($row['idchildFK']) ? (int)$row['idchildFK'] : null;
- $row['fieldInt']=isset($row['fieldInt']) ? (int)$row['fieldInt'] : null;
- $row['fielDecimal']=isset($row['fielDecimal']) ? (float)$row['fielDecimal'] : null;
- $row['fieldDateTime']=isset($row['fieldDateTime']) ? PdoOne::dateConvert($row['fieldDateTime'], 'sql', 'class') : null;
- !isset($row['fieldUnique']) and $row['fieldUnique']=null; // varchar
- !isset($row['fieldKey']) and $row['fieldKey']=null; // no conversion
- $row['extracol']=isset($row['extracol']) ? PdoOne::dateConvert($row['extracol'], 'sql', 'human') : null;
- !isset($row['extracol2']) and $row['extracol2']=null; //
- isset($row['_TableParentExt'])
- and $row['_TableParentExt']['idtablaparentExtPK']=&$row['idtablaparentPK']; // linked ONETOONE
-
- }
-
- /**
- * 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['idtablaparentPK']) and $row['idtablaparentPK']=(int)$row['idtablaparentPK'];
- isset($row['idchildFK']) and $row['idchildFK']=(int)$row['idchildFK'];
- isset($row['fieldInt']) and $row['fieldInt']=(int)$row['fieldInt'];
- isset($row['fielDecimal']) and $row['fielDecimal']=(float)$row['fielDecimal'];
- isset($row['fieldDateTime']) and $row['fieldDateTime']=PdoOne::dateConvert($row['fieldDateTime'], 'class', 'sql');
- isset($row['fieldKey']) and $row['fieldKey']=self::getPdoOne()->encrypt($row['fieldKey']);
- isset($row['extracol']) and $row['extracol']=PdoOne::dateConvert($row['extracol'], 'human', 'sql');
- }
-
-
- /**
- * It gets all the name of the columns.
- *
- * @return string[]
- */
- public static function getDefName() {
- return [
- 'idtablaparentPK',
- 'fieldVarchar',
- 'idchildFK',
- 'fieldInt',
- 'fielDecimal',
- 'fieldDateTime',
- 'fieldUnique',
- 'fieldKey'
- ];
- }
-
- /**
- * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
- *
- * @return string[]
- */
- public static function getDefKey() {
- return [
- 'idtablaparentPK' => 'PRIMARY KEY',
- 'fieldUnique' => 'UNIQUE KEY',
- 'idchildFK' => 'KEY',
- 'fieldKey' => 'KEY',
- 'idchild2FK' => 'KEY'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when insert
- * @return string[]
- */
- public static function getDefNoInsert() {
- return [
- 'idtablaparentPK'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when update
- * @return string[]
- */
- public static function getDefNoUpdate() {
- return [
- 'idtablaparentPK'
- ];
- }
-
- /**
- * It adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
- *
- * @return TableParentRepo
- */
- public static function where($sql, $param = PdoOne::NULL)
- {
- self::getPdoOne()->where($sql, $param,false,TableParentRepo::TABLE);
- return TableParentRepo::class;
- }
-
- public static function getDefFK($structure=false) {
- if ($structure) {
- return [
- 'idchild2FK' => 'FOREIGN KEY REFERENCES`TableChild`(`idtablachildPK`)'
- ];
- }
- /* key,refcol,reftable,extra */
- return [
- 'idchild2FK' => [
- 'key' => 'FOREIGN KEY',
- 'refcol' => 'idtablachildPK',
- 'reftable' => 'TableChild',
- 'extra' => '',
- 'name' => 'TableParent_fk2'
- ],
- '_idchild2FK' => [
- 'key' => 'PARENT',
- 'refcol' => 'idtablachildPK',
- 'reftable' => 'TableChild',
- 'extra' => '',
- 'name' => 'TableParent_fk2'
- ],
- '_TableParentExt' => [
- 'key' => 'ONETOONE',
- 'col' => 'idtablaparentPK',
- 'reftable' => 'TableParentExt',
- 'refcol' => 'idtablaparentExtPK'
- ],
- '_TableParentxCategory' => [
- 'key' => 'MANYTOMANY',
- 'col' => 'idtablaparentPK',
- 'reftable' => 'TableParentxCategory',
- 'refcol' => '_idtablaparentPKFK',
- 'refcol2' => '_idcategoryPKFK',
- 'col2' => 'IdTableCategoryPK',
- 'table2' => 'TableCategory'
- ]
- ];
- }
-
- /**
- * 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= [
- 'ONETOONE' => [
- '_TableParentExt'
- ],
- 'MANYTOMANY' => [
- '_TableParentxCategory'
- ]
- ];
- if($type==='*') {
- $result=[];
- foreach($r as $arr) {
- $result = array_merge($result,$arr);
- }
- return $result;
- }
- return isset($r[$type]) ? $r[$type] : [];
-
- }
-
- public static function toList($filter=PdoOne::NULL,$filterValue=null) {
- if(self::$useModel) {
- return TableParentModel::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:
- *
- * 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 TableParentRepo
- */
- public static function setRecursive($recursive=[])
- {
- if(is_string($recursive)) {
- $recursive=TableParentRepo::getRelations($recursive);
- }
- return parent::_setRecursive($recursive);
- }
-
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return TableParentRepo::class;
- }
-
- /**
- * It returns the first row of a query.
- * @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 TableParentModel::fromArray(self::_first($pk));
- }
- return self::_first($pk);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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 mixed
- * @throws Exception
- */
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
- }
-
- /**
- * It deletes an entity by the primary key.
- *
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
- *
- * @return mixed
- * @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= [
- 'idtablaparentPK'=>0,
- '_TableParentExt'=>(in_array($recursivePrefix.'_TableParentExt',$recursive,true))
- ? TableParentExt::factory(null,$recursivePrefix.'_TableParentExt')
- : null, /* ONETOONE! */
- '_TableParentxCategory'=>(in_array($recursivePrefix.'_TableParentxCategory',$recursive,true))
- ? []
- : null, /* MANYTOMANY! */
- 'fieldVarchar'=>'',
- 'idchildFK'=>0,
- 'idchild2FK'=>0,
- 'fieldInt'=>0,
- 'fielDecimal'=>0.0,
- 'fieldDateTime'=>'',
- 'fieldUnique'=>'',
- 'fieldKey'=>''
- ];
- isset($row['_TableParentExt'])
- and $row['_TableParentExt']['idtablaparentExtPK']=&$row['idtablaparentPK']; // linked ONETOONE
-
- 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= [
- 'idtablaparentPK'=>null,
- '_TableParentExt'=>null, /* ONETOONE! */
- '_TableParentxCategory'=>null, /* MANYTOMANY! */
- 'fieldVarchar'=>null,
- 'idchildFK'=>null,
- 'idchild2FK'=>null,
- 'fieldInt'=>null,
- 'fielDecimal'=>null,
- 'fieldDateTime'=>null,
- 'fieldUnique'=>null,
- 'fieldKey'=>null
- ];
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
- }
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/AbstractTableParentxCategoryRepo.php b/examples/repomysql/generated/AbstractTableParentxCategoryRepo.php
deleted file mode 100644
index 69a266f..0000000
--- a/examples/repomysql/generated/AbstractTableParentxCategoryRepo.php
+++ /dev/null
@@ -1,446 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass('TableParentxCategory','repomysql',array(),array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',),array(),'','','TestDb','mysql\repomodel\TableParentxCategoryModel',array(),array());
- *
- */
-abstract class AbstractTableParentxCategoryRepo extends TestDb
-{
- const TABLE = 'TableParentxCategory';
- const COMPILEDVERSION=3;
- const IDENTITY = 'idtablaparentPKFK';
- const PK = [
- 'idtablaparentPKFK',
- 'idcategoryPKFK'
- ];
- const ME=__CLASS__;
- const EXTRACOLS='';
-
- /**
- * 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 = [
- 'idtablaparentPKFK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => FALSE,
- 'identity' => TRUE,
- 'sql' => 'int not null auto_increment'
- ],
- 'idcategoryPKFK' => [
- 'phptype' => 'int',
- 'conversion' => 'int',
- 'type' => 'int',
- 'size' => NULL,
- 'null' => FALSE,
- 'identity' => FALSE,
- 'sql' => 'int not null'
- ]
- ];
- 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['idtablaparentPKFK']=isset($row['idtablaparentPKFK']) ? (int)$row['idtablaparentPKFK'] : null;
- $row['idcategoryPKFK']=isset($row['idcategoryPKFK']) ? (int)$row['idcategoryPKFK'] : null;
- isset($row['_idcategoryPKFK'])
- and $row['_idcategoryPKFK']['IdTableCategoryPK']=&$row['idcategoryPKFK']; // linked MANYTOONE
- isset($row['_idtablaparentPKFK'])
- and $row['_idtablaparentPKFK']['idtablaparentPK']=&$row['idtablaparentPKFK']; // linked ONETOONE
-
- }
-
- /**
- * 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['idtablaparentPKFK']) and $row['idtablaparentPKFK']=(int)$row['idtablaparentPKFK'];
- isset($row['idcategoryPKFK']) and $row['idcategoryPKFK']=(int)$row['idcategoryPKFK'];
- }
-
-
- /**
- * It gets all the name of the columns.
- *
- * @return string[]
- */
- public static function getDefName() {
- return [
- 'idtablaparentPKFK',
- 'idcategoryPKFK'
- ];
- }
-
- /**
- * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
- *
- * @return string[]
- */
- public static function getDefKey() {
- return [
- 'idtablaparentPKFK' => 'PRIMARY KEY',
- 'idcategoryPKFK' => 'PRIMARY KEY'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when insert
- * @return string[]
- */
- public static function getDefNoInsert() {
- return [
- 'idtablaparentPKFK'
- ];
- }
-
- /**
- * It returns a string array with the name of the columns that are skipped when update
- * @return string[]
- */
- public static function getDefNoUpdate() {
- return [
- 'idtablaparentPKFK',
- 'idcategoryPKFK'
- ];
- }
-
- /**
- * It adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
- *
- * @return TableParentxCategoryRepo
- */
- public static function where($sql, $param = PdoOne::NULL)
- {
- self::getPdoOne()->where($sql, $param,false,TableParentxCategoryRepo::TABLE);
- return TableParentxCategoryRepo::class;
- }
-
- public static function getDefFK($structure=false) {
- if ($structure) {
- return [
- 'idcategoryPKFK' => 'FOREIGN KEY REFERENCES`TableCategory`(`IdTableCategoryPK`)',
- 'idtablaparentPKFK' => 'FOREIGN KEY REFERENCES`TableParent`(`idtablaparentPK`)'
- ];
- }
- /* key,refcol,reftable,extra */
- return [
- 'idcategoryPKFK' => [
- 'key' => 'FOREIGN KEY',
- 'refcol' => 'IdTableCategoryPK',
- 'reftable' => 'TableCategory',
- 'extra' => '',
- 'name' => 'tablaparentxcategory_fk2'
- ],
- '_idcategoryPKFK' => [
- 'key' => 'MANYTOONE',
- 'refcol' => 'IdTableCategoryPK',
- 'reftable' => 'TableCategory',
- 'extra' => '',
- 'name' => 'tablaparentxcategory_fk2'
- ],
- 'idtablaparentPKFK' => [
- 'key' => 'FOREIGN KEY',
- 'refcol' => 'idtablaparentPK',
- 'reftable' => 'TableParent',
- 'extra' => '',
- 'name' => 'FK_tablaparentxcategory_tablaparent'
- ],
- '_idtablaparentPKFK' => [
- 'key' => 'ONETOONE',
- 'refcol' => 'idtablaparentPK',
- 'reftable' => 'TableParent',
- 'extra' => '',
- 'name' => 'FK_tablaparentxcategory_tablaparent',
- 'col' => 'idtablaparentPKFK'
- ]
- ];
- }
-
- /**
- * 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' => [
- '_idcategoryPKFK'
- ],
- 'ONETOONE' => [
- '_idtablaparentPKFK'
- ]
- ];
- if($type==='*') {
- $result=[];
- foreach($r as $arr) {
- $result = array_merge($result,$arr);
- }
- return $result;
- }
- return isset($r[$type]) ? $r[$type] : [];
-
- }
-
- public static function toList($filter=PdoOne::NULL,$filterValue=null) {
- if(self::$useModel) {
- return TableParentxCategoryModel::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:
- *
- * 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 TableParentxCategoryRepo
- */
- public static function setRecursive($recursive=[])
- {
- if(is_string($recursive)) {
- $recursive=TableParentxCategoryRepo::getRelations($recursive);
- }
- return parent::_setRecursive($recursive);
- }
-
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return TableParentxCategoryRepo::class;
- }
-
- /**
- * It returns the first row of a query.
- * @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 TableParentxCategoryModel::fromArray(self::_first($pk));
- }
- return self::_first($pk);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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 mixed
- * @throws Exception
- */
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
- }
-
- /**
- * It deletes an entity by the primary key.
- *
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
- *
- * @return mixed
- * @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= [
- 'idtablaparentPKFK'=>0,
- '_idtablaparentPKFK'=>(in_array($recursivePrefix.'_idtablaparentPKFK',$recursive,true))
- ? TableParentRepo::factory(null,$recursivePrefix.'_idtablaparentPKFK')
- : null, /* ONETOONE!! */
- 'idcategoryPKFK'=>0,
- '_idcategoryPKFK'=>(in_array($recursivePrefix.'_idcategoryPKFK',$recursive,true))
- ? TableCategoryRepo::factory(null,$recursivePrefix.'_idcategoryPKFK')
- : null, /* MANYTOONE!! */
- ];
- isset($row['_idcategoryPKFK'])
- and $row['_idcategoryPKFK']['IdTableCategoryPK']=&$row['idcategoryPKFK']; // linked MANYTOONE
- isset($row['_idtablaparentPKFK'])
- and $row['_idtablaparentPKFK']['idtablaparentPK']=&$row['idtablaparentPKFK']; // linked ONETOONE
-
- 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= [
- 'idtablaparentPKFK'=>null,
- '_idtablaparentPKFK'=>null, /* ONETOONE!! */
- 'idcategoryPKFK'=>null,
- '_idcategoryPKFK'=>null, /* MANYTOONE!! */
- ];
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
- }
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TableCategoryRepo.php b/examples/repomysql/generated/TableCategoryRepo.php
deleted file mode 100644
index 4507bda..0000000
--- a/examples/repomysql/generated/TableCategoryRepo.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * $code=$pdoOne->generateCodeClassRepo(''TableCategory'',''repomysql'','array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',)',''mysql\repomodel\TableCategoryModel'');
- *
- */
-class TableCategoryRepo extends AbstractTableCategoryRepo
-{
- const ME=__CLASS__;
- const MODEL= TableCategoryModel::class;
-
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TableChildRepo.php b/examples/repomysql/generated/TableChildRepo.php
deleted file mode 100644
index 1a21c50..0000000
--- a/examples/repomysql/generated/TableChildRepo.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * $code=$pdoOne->generateCodeClassRepo(''TableChild'',''repomysql'','array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',)',''mysql\repomodel\TableChildModel'');
- *
- */
-class TableChildRepo extends AbstractTableChildRepo
-{
- const ME=__CLASS__;
- const MODEL= TableChildModel::class;
-
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TableGrandChildRepo.php b/examples/repomysql/generated/TableGrandChildRepo.php
deleted file mode 100644
index a830b20..0000000
--- a/examples/repomysql/generated/TableGrandChildRepo.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * $code=$pdoOne->generateCodeClassRepo(''TableGrandChild'',''repomysql'','array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',)',''mysql\repomodel\TableGrandChildModel'');
- *
- */
-class TableGrandChildRepo extends AbstractTableGrandChildRepo
-{
- const ME=__CLASS__;
- const MODEL= TableGrandChildModel::class;
-
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TableGrandChildTagRepo.php b/examples/repomysql/generated/TableGrandChildTagRepo.php
deleted file mode 100644
index 2516329..0000000
--- a/examples/repomysql/generated/TableGrandChildTagRepo.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * $code=$pdoOne->generateCodeClassRepo(''TableGrandChildTag'',''repomysql'','array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',)',''mysql\repomodel\TableGrandChildTagModel'');
- *
- */
-class TableGrandChildTagRepo extends AbstractTableGrandChildTagRepo
-{
- const ME=__CLASS__;
- const MODEL= TableGrandChildTagModel::class;
-
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TableParentExtRepo.php b/examples/repomysql/generated/TableParentExtRepo.php
deleted file mode 100644
index 3013e3b..0000000
--- a/examples/repomysql/generated/TableParentExtRepo.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * $code=$pdoOne->generateCodeClassRepo(''TableParentExt'',''repomysql'','array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',)',''mysql\repomodel\TableParentExtModel'');
- *
- */
-class TableParentExtRepo extends AbstractTableParentExtRepo
-{
- const ME=__CLASS__;
- const MODEL= TableParentExtModel::class;
-
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TableParentRepo.php b/examples/repomysql/generated/TableParentRepo.php
deleted file mode 100644
index a688bf1..0000000
--- a/examples/repomysql/generated/TableParentRepo.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * $code=$pdoOne->generateCodeClassRepo(''TableParent'',''repomysql'','array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',)',''mysql\repomodel\TableParentModel'');
- *
- */
-class TableParentRepo extends AbstractTableParentRepo
-{
- const ME=__CLASS__;
- const MODEL= TableParentModel::class;
-
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TableParentxCategoryRepo.php b/examples/repomysql/generated/TableParentxCategoryRepo.php
deleted file mode 100644
index 29828cf..0000000
--- a/examples/repomysql/generated/TableParentxCategoryRepo.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * $code=$pdoOne->generateCodeClassRepo(''TableParentxCategory'',''repomysql'','array('TableParent'=>'TableParentRepo','TableChild'=>'TableChildRepo','TableGrandChild'=>'TableGrandChildRepo','TableGrandChildTag'=>'TableGrandChildTagRepo','TableParentxCategory'=>'TableParentxCategoryRepo','TableCategory'=>'TableCategoryRepo','TableParentExt'=>'TableParentExtRepo',)',''mysql\repomodel\TableParentxCategoryModel'');
- *
- */
-class TableParentxCategoryRepo extends AbstractTableParentxCategoryRepo
-{
- const ME=__CLASS__;
- const MODEL= TableParentxCategoryModel::class;
-
-
-}
\ No newline at end of file
diff --git a/examples/repomysql/generated/TestDb.php b/examples/repomysql/generated/TestDb.php
deleted file mode 100644
index a5c5016..0000000
--- a/examples/repomysql/generated/TestDb.php
+++ /dev/null
@@ -1,54 +0,0 @@
- 'TableParentRepo',
- 'TableChild' => 'TableChildRepo',
- 'TableGrandChild' => 'TableGrandChildRepo',
- 'TableGrandChildTag' => 'TableGrandChildTagRepo',
- 'TableParentxCategory' => 'TableParentxCategoryRepo',
- 'TableCategory' => 'TableCategoryRepo',
- 'TableParentExt' => 'TableParentExtRepo'
- ];
- /**
- * With the name of the table, we get the class
- * @param string $tableName
- *
- * @return string[]
- */
- protected function tabletoClass($tableName) {
- return static::RELATIONS[$tableName];
- }
-}
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/AbstractTableCategoryModel.php b/examples/repomysql/generatedmodel/AbstractTableCategoryModel.php
deleted file mode 100644
index 0435ad4..0000000
--- a/examples/repomysql/generatedmodel/AbstractTableCategoryModel.php
+++ /dev/null
@@ -1,95 +0,0 @@
-
- * $code=$pdoOne->generateAbstractModelClass({args});
- *
- */
-abstract class AbstractTableCategoryModel
-{
- /** @var int $IdTableCategoryPK */
- public $IdTableCategoryPK;
- /** @var string $Name */
- public $Name;
-
- /** @var TableParentxCategoryModel[] $_TableParentxCategory onetomany */
- public $_TableParentxCategory;
-
-
- /**
- * AbstractTableCategoryModel constructor.
- *
- * @param array|null $array
- */
- public function __construct($array=null)
- {
- if($array===null) {
- return;
- }
- foreach($array as $k=>$v) {
- $this->{$k}=$v;
- }
- }
-
- //
- public static function fromArray($array) {
- if($array===null) {
- return null;
- }
- $obj=new TableCategoryModel();
- $obj->IdTableCategoryPK=isset($array['IdTableCategoryPK']) ? $array['IdTableCategoryPK'] : null;
- $obj->Name=isset($array['Name']) ? $array['Name'] : null;
- $obj->_TableParentxCategory=isset($array['_TableParentxCategory']) ?
- $obj->_TableParentxCategory=TableParentxCategoryModel::fromArrayMultiple($array['_TableParentxCategory'])
- : null; // onetomany
-
- return $obj;
- }
-
- /**
- * It converts the current object in an array
- *
- * @return mixed
- */
- public function toArray() {
- return static::objectToArray($this);
- }
-
- /**
- * It converts an array of arrays into an array of objects.
- *
- * @param array|null $array
- *
- * @return array|null
- */
- public static function fromArrayMultiple($array) {
- if($array===null) {
- return null;
- }
- $objs=[];
- foreach($array as $v) {
- $objs[]=self::fromArray($v);
- }
- return $objs;
- }
- //
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/AbstractTableChildModel.php b/examples/repomysql/generatedmodel/AbstractTableChildModel.php
deleted file mode 100644
index f938f27..0000000
--- a/examples/repomysql/generatedmodel/AbstractTableChildModel.php
+++ /dev/null
@@ -1,105 +0,0 @@
-
- * $code=$pdoOne->generateAbstractModelClass({args});
- *
- */
-abstract class AbstractTableChildModel
-{
- /** @var int $idtablachildPK */
- public $idtablachildPK;
- /** @var string $NameChild */
- public $NameChild;
- /** @var int $idgrandchildFK */
- public $idgrandchildFK;
-
- /** @var TableGrandChildModel $_idgrandchildFK manytoone */
- public $_idgrandchildFK;
- /** @var TableParentModel[] $_TableParent onetomany */
- public $_TableParent;
-
-
- /**
- * AbstractTableChildModel constructor.
- *
- * @param array|null $array
- */
- public function __construct($array=null)
- {
- if($array===null) {
- return;
- }
- foreach($array as $k=>$v) {
- $this->{$k}=$v;
- }
- }
-
- //
- public static function fromArray($array) {
- if($array===null) {
- return null;
- }
- $obj=new TableChildModel();
- $obj->idtablachildPK=isset($array['idtablachildPK']) ? $array['idtablachildPK'] : null;
- $obj->NameChild=isset($array['NameChild']) ? $array['NameChild'] : null;
- $obj->idgrandchildFK=isset($array['idgrandchildFK']) ? $array['idgrandchildFK'] : null;
- $obj->_idgrandchildFK=isset($array['_idgrandchildFK']) ?
- $obj->_idgrandchildFK=TableGrandChildModel::fromArray($array['_idgrandchildFK'])
- : null; // manytoone
- ($obj->_idgrandchildFK !== null)
- and $obj->_idgrandchildFK->idgrandchildPK=&$obj->idgrandchildFK; // linked manytoone
- $obj->_TableParent=isset($array['_TableParent']) ?
- $obj->_TableParent=TableParentModel::fromArrayMultiple($array['_TableParent'])
- : null; // onetomany
-
- return $obj;
- }
-
- /**
- * It converts the current object in an array
- *
- * @return mixed
- */
- public function toArray() {
- return static::objectToArray($this);
- }
-
- /**
- * It converts an array of arrays into an array of objects.
- *
- * @param array|null $array
- *
- * @return array|null
- */
- public static function fromArrayMultiple($array) {
- if($array===null) {
- return null;
- }
- $objs=[];
- foreach($array as $v) {
- $objs[]=self::fromArray($v);
- }
- return $objs;
- }
- //
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/AbstractTableGrandChildModel.php b/examples/repomysql/generatedmodel/AbstractTableGrandChildModel.php
deleted file mode 100644
index 03223c6..0000000
--- a/examples/repomysql/generatedmodel/AbstractTableGrandChildModel.php
+++ /dev/null
@@ -1,100 +0,0 @@
-
- * $code=$pdoOne->generateAbstractModelClass({args});
- *
- */
-abstract class AbstractTableGrandChildModel
-{
- /** @var int $idgrandchildPK */
- public $idgrandchildPK;
- /** @var string $NameGrandChild */
- public $NameGrandChild;
-
- /** @var TableChildModel[] $_TableChild onetomany */
- public $_TableChild;
- /** @var TableGrandChildTagModel[] $_TableGrandChildTag onetomany */
- public $_TableGrandChildTag;
-
-
- /**
- * AbstractTableGrandChildModel constructor.
- *
- * @param array|null $array
- */
- public function __construct($array=null)
- {
- if($array===null) {
- return;
- }
- foreach($array as $k=>$v) {
- $this->{$k}=$v;
- }
- }
-
- //
- public static function fromArray($array) {
- if($array===null) {
- return null;
- }
- $obj=new TableGrandChildModel();
- $obj->idgrandchildPK=isset($array['idgrandchildPK']) ? $array['idgrandchildPK'] : null;
- $obj->NameGrandChild=isset($array['NameGrandChild']) ? $array['NameGrandChild'] : null;
- $obj->_TableChild=isset($array['_TableChild']) ?
- $obj->_TableChild=TableChildModel::fromArrayMultiple($array['_TableChild'])
- : null; // onetomany
- $obj->_TableGrandChildTag=isset($array['_TableGrandChildTag']) ?
- $obj->_TableGrandChildTag=TableGrandChildTagModel::fromArrayMultiple($array['_TableGrandChildTag'])
- : null; // onetomany
-
- return $obj;
- }
-
- /**
- * It converts the current object in an array
- *
- * @return mixed
- */
- public function toArray() {
- return static::objectToArray($this);
- }
-
- /**
- * It converts an array of arrays into an array of objects.
- *
- * @param array|null $array
- *
- * @return array|null
- */
- public static function fromArrayMultiple($array) {
- if($array===null) {
- return null;
- }
- $objs=[];
- foreach($array as $v) {
- $objs[]=self::fromArray($v);
- }
- return $objs;
- }
- //
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/AbstractTableGrandChildTagModel.php b/examples/repomysql/generatedmodel/AbstractTableGrandChildTagModel.php
deleted file mode 100644
index 532e10e..0000000
--- a/examples/repomysql/generatedmodel/AbstractTableGrandChildTagModel.php
+++ /dev/null
@@ -1,100 +0,0 @@
-
- * $code=$pdoOne->generateAbstractModelClass({args});
- *
- */
-abstract class AbstractTableGrandChildTagModel
-{
- /** @var int $IdTablaGrandChildTagPK */
- public $IdTablaGrandChildTagPK;
- /** @var string $Name */
- public $Name;
- /** @var int $IdgrandchildFK */
- public $IdgrandchildFK;
-
- /** @var TableGrandChildModel $_IdgrandchildFK manytoone */
- public $_IdgrandchildFK;
-
-
- /**
- * AbstractTableGrandChildTagModel constructor.
- *
- * @param array|null $array
- */
- public function __construct($array=null)
- {
- if($array===null) {
- return;
- }
- foreach($array as $k=>$v) {
- $this->{$k}=$v;
- }
- }
-
- //
- public static function fromArray($array) {
- if($array===null) {
- return null;
- }
- $obj=new TableGrandChildTagModel();
- $obj->IdTablaGrandChildTagPK=isset($array['IdTablaGrandChildTagPK']) ? $array['IdTablaGrandChildTagPK'] : null;
- $obj->Name=isset($array['Name']) ? $array['Name'] : null;
- $obj->IdgrandchildFK=isset($array['IdgrandchildFK']) ? $array['IdgrandchildFK'] : null;
- $obj->_IdgrandchildFK=isset($array['_IdgrandchildFK']) ?
- $obj->_IdgrandchildFK=TableGrandChildModel::fromArray($array['_IdgrandchildFK'])
- : null; // manytoone
- ($obj->_IdgrandchildFK !== null)
- and $obj->_IdgrandchildFK->idgrandchildPK=&$obj->IdgrandchildFK; // linked manytoone
-
- return $obj;
- }
-
- /**
- * It converts the current object in an array
- *
- * @return mixed
- */
- public function toArray() {
- return static::objectToArray($this);
- }
-
- /**
- * It converts an array of arrays into an array of objects.
- *
- * @param array|null $array
- *
- * @return array|null
- */
- public static function fromArrayMultiple($array) {
- if($array===null) {
- return null;
- }
- $objs=[];
- foreach($array as $v) {
- $objs[]=self::fromArray($v);
- }
- return $objs;
- }
- //
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/AbstractTableParentExtModel.php b/examples/repomysql/generatedmodel/AbstractTableParentExtModel.php
deleted file mode 100644
index f40964c..0000000
--- a/examples/repomysql/generatedmodel/AbstractTableParentExtModel.php
+++ /dev/null
@@ -1,92 +0,0 @@
-
- * $code=$pdoOne->generateAbstractModelClass({args});
- *
- */
-abstract class AbstractTableParentExtModel
-{
- /** @var int $idtablaparentExtPK */
- public $idtablaparentExtPK;
- /** @var string $fieldExt */
- public $fieldExt;
-
-
-
-
- /**
- * AbstractTableParentExtModel constructor.
- *
- * @param array|null $array
- */
- public function __construct($array=null)
- {
- if($array===null) {
- return;
- }
- foreach($array as $k=>$v) {
- $this->{$k}=$v;
- }
- }
-
- //
- public static function fromArray($array) {
- if($array===null) {
- return null;
- }
- $obj=new TableParentExtModel();
- $obj->idtablaparentExtPK=isset($array['idtablaparentExtPK']) ? $array['idtablaparentExtPK'] : null;
- $obj->fieldExt=isset($array['fieldExt']) ? $array['fieldExt'] : null;
-
-
- return $obj;
- }
-
- /**
- * It converts the current object in an array
- *
- * @return mixed
- */
- public function toArray() {
- return static::objectToArray($this);
- }
-
- /**
- * It converts an array of arrays into an array of objects.
- *
- * @param array|null $array
- *
- * @return array|null
- */
- public static function fromArrayMultiple($array) {
- if($array===null) {
- return null;
- }
- $objs=[];
- foreach($array as $v) {
- $objs[]=self::fromArray($v);
- }
- return $objs;
- }
- //
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/AbstractTableParentModel.php b/examples/repomysql/generatedmodel/AbstractTableParentModel.php
deleted file mode 100644
index 8fb18f7..0000000
--- a/examples/repomysql/generatedmodel/AbstractTableParentModel.php
+++ /dev/null
@@ -1,126 +0,0 @@
-
- * $code=$pdoOne->generateAbstractModelClass({args});
- *
- */
-abstract class AbstractTableParentModel
-{
- /** @var int $idtablaparentPK */
- public $idtablaparentPK;
- /** @var string $fieldVarchar */
- public $fieldVarchar;
- /** @var int $idchildFK */
- public $idchildFK;
- /** @var int $fieldInt */
- public $fieldInt;
- /** @var float $fielDecimal */
- public $fielDecimal;
- /** @var datetime $fieldDateTime */
- public $fieldDateTime;
- /** @var string $fieldUnique */
- public $fieldUnique;
- /** @var string $fieldKey */
- public $fieldKey;
- /** @var mixed $extracol extra column: CURRENT_TIMESTAMP */
- public $extracol;
- /** @var mixed $extracol2 extra column: 20 */
- public $extracol2;
-
- /** @var TableParentExtModel $_TableParentExt onetoone */
- public $_TableParentExt;
- /** @var TableParentxCategoryModel[] $_TableParentxCategory manytomany */
- public $_TableParentxCategory;
-
-
- /**
- * AbstractTableParentModel constructor.
- *
- * @param array|null $array
- */
- public function __construct($array=null)
- {
- if($array===null) {
- return;
- }
- foreach($array as $k=>$v) {
- $this->{$k}=$v;
- }
- }
-
- //
- public static function fromArray($array) {
- if($array===null) {
- return null;
- }
- $obj=new TableParentModel();
- $obj->idtablaparentPK=isset($array['idtablaparentPK']) ? $array['idtablaparentPK'] : null;
- $obj->fieldVarchar=isset($array['fieldVarchar']) ? $array['fieldVarchar'] : null;
- $obj->idchildFK=isset($array['idchildFK']) ? $array['idchildFK'] : null;
- $obj->fieldInt=isset($array['fieldInt']) ? $array['fieldInt'] : null;
- $obj->fielDecimal=isset($array['fielDecimal']) ? $array['fielDecimal'] : null;
- $obj->fieldDateTime=isset($array['fieldDateTime']) ? $array['fieldDateTime'] : null;
- $obj->fieldUnique=isset($array['fieldUnique']) ? $array['fieldUnique'] : null;
- $obj->fieldKey=isset($array['fieldKey']) ? $array['fieldKey'] : null;
- $obj->extracol=isset($array['extracol']) ? $array['extracol'] : null;
- $obj->extracol2=isset($array['extracol2']) ? $array['extracol2'] : null;
- $obj->_TableParentExt=isset($array['_TableParentExt']) ?
- $obj->_TableParentExt=TableParentExtModel::fromArray($array['_TableParentExt'])
- : null; // onetoone
- ($obj->_TableParentExt !== null)
- and $obj->_TableParentExt->idtablaparentExtPK=&$obj->xxx1; // linked onetoone
- $obj->_TableParentxCategory=isset($array['_TableParentxCategory']) ?
- $obj->_TableParentxCategory=TableParentxCategoryModel::fromArrayMultiple($array['_TableParentxCategory'])
- : null; // manytomany
-
- return $obj;
- }
-
- /**
- * It converts the current object in an array
- *
- * @return mixed
- */
- public function toArray() {
- return static::objectToArray($this);
- }
-
- /**
- * It converts an array of arrays into an array of objects.
- *
- * @param array|null $array
- *
- * @return array|null
- */
- public static function fromArrayMultiple($array) {
- if($array===null) {
- return null;
- }
- $objs=[];
- foreach($array as $v) {
- $objs[]=self::fromArray($v);
- }
- return $objs;
- }
- //
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/AbstractTableParentxCategoryModel.php b/examples/repomysql/generatedmodel/AbstractTableParentxCategoryModel.php
deleted file mode 100644
index c21caa3..0000000
--- a/examples/repomysql/generatedmodel/AbstractTableParentxCategoryModel.php
+++ /dev/null
@@ -1,104 +0,0 @@
-
- * $code=$pdoOne->generateAbstractModelClass({args});
- *
- */
-abstract class AbstractTableParentxCategoryModel
-{
- /** @var int $idtablaparentPKFK */
- public $idtablaparentPKFK;
- /** @var int $idcategoryPKFK */
- public $idcategoryPKFK;
-
- /** @var TableCategoryModel $_idcategoryPKFK manytoone */
- public $_idcategoryPKFK;
- /** @var TableParentModel $_idtablaparentPKFK onetoone */
- public $_idtablaparentPKFK;
-
-
- /**
- * AbstractTableParentxCategoryModel constructor.
- *
- * @param array|null $array
- */
- public function __construct($array=null)
- {
- if($array===null) {
- return;
- }
- foreach($array as $k=>$v) {
- $this->{$k}=$v;
- }
- }
-
- //
- public static function fromArray($array) {
- if($array===null) {
- return null;
- }
- $obj=new TableParentxCategoryModel();
- $obj->idtablaparentPKFK=isset($array['idtablaparentPKFK']) ? $array['idtablaparentPKFK'] : null;
- $obj->idcategoryPKFK=isset($array['idcategoryPKFK']) ? $array['idcategoryPKFK'] : null;
- $obj->_idcategoryPKFK=isset($array['_idcategoryPKFK']) ?
- $obj->_idcategoryPKFK=TableCategoryModel::fromArray($array['_idcategoryPKFK'])
- : null; // manytoone
- ($obj->_idcategoryPKFK !== null)
- and $obj->_idcategoryPKFK->IdTableCategoryPK=&$obj->idcategoryPKFK; // linked manytoone
- $obj->_idtablaparentPKFK=isset($array['_idtablaparentPKFK']) ?
- $obj->_idtablaparentPKFK=TableParentModel::fromArray($array['_idtablaparentPKFK'])
- : null; // onetoone
- ($obj->_idtablaparentPKFK !== null)
- and $obj->_idtablaparentPKFK->idtablaparentPK=&$obj->xxx2; // linked onetoone
-
- return $obj;
- }
-
- /**
- * It converts the current object in an array
- *
- * @return mixed
- */
- public function toArray() {
- return static::objectToArray($this);
- }
-
- /**
- * It converts an array of arrays into an array of objects.
- *
- * @param array|null $array
- *
- * @return array|null
- */
- public static function fromArrayMultiple($array) {
- if($array===null) {
- return null;
- }
- $objs=[];
- foreach($array as $v) {
- $objs[]=self::fromArray($v);
- }
- return $objs;
- }
- //
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/TableCategoryModel.php b/examples/repomysql/generatedmodel/TableCategoryModel.php
deleted file mode 100644
index 419625e..0000000
--- a/examples/repomysql/generatedmodel/TableCategoryModel.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- */
-class TableCategoryModel extends AbstractTableCategoryModel
-{
-
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/TableChildModel.php b/examples/repomysql/generatedmodel/TableChildModel.php
deleted file mode 100644
index fbb7bce..0000000
--- a/examples/repomysql/generatedmodel/TableChildModel.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- */
-class TableChildModel extends AbstractTableChildModel
-{
-
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/TableGrandChildModel.php b/examples/repomysql/generatedmodel/TableGrandChildModel.php
deleted file mode 100644
index 680942a..0000000
--- a/examples/repomysql/generatedmodel/TableGrandChildModel.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- */
-class TableGrandChildModel extends AbstractTableGrandChildModel
-{
-
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/TableGrandChildTagModel.php b/examples/repomysql/generatedmodel/TableGrandChildTagModel.php
deleted file mode 100644
index 8d0b31b..0000000
--- a/examples/repomysql/generatedmodel/TableGrandChildTagModel.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- */
-class TableGrandChildTagModel extends AbstractTableGrandChildTagModel
-{
-
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/TableParentExtModel.php b/examples/repomysql/generatedmodel/TableParentExtModel.php
deleted file mode 100644
index 3fd7f2d..0000000
--- a/examples/repomysql/generatedmodel/TableParentExtModel.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- */
-class TableParentExtModel extends AbstractTableParentExtModel
-{
-
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/TableParentModel.php b/examples/repomysql/generatedmodel/TableParentModel.php
deleted file mode 100644
index 7f2e16f..0000000
--- a/examples/repomysql/generatedmodel/TableParentModel.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- */
-class TableParentModel extends AbstractTableParentModel
-{
-
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/generatedmodel/TableParentxCategoryModel.php b/examples/repomysql/generatedmodel/TableParentxCategoryModel.php
deleted file mode 100644
index 0ad9524..0000000
--- a/examples/repomysql/generatedmodel/TableParentxCategoryModel.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- */
-class TableParentxCategoryModel extends AbstractTableParentxCategoryModel
-{
-
-
-} // end class
\ No newline at end of file
diff --git a/examples/repomysql/test_select.php b/examples/repomysql/test_select.php
index 48b6c3e..f83a1c0 100644
--- a/examples/repomysql/test_select.php
+++ b/examples/repomysql/test_select.php
@@ -21,6 +21,8 @@
])::testRecursive();
+
+
//new dBug(TableParentRepo::base()->runRawQuery('select * from tableparent',[],true));
TableChildRepo::$useModel = false;
$child = TableParentRepo::setRecursive([
diff --git a/examples/repomysql/test_select2.php b/examples/repomysql/test_select2.php
index 00faac1..cdd5e32 100644
--- a/examples/repomysql/test_select2.php
+++ b/examples/repomysql/test_select2.php
@@ -12,6 +12,20 @@
new dBug(TableParentRepo::base()->runRawQuery('select * from tableparent',[],true));
+$random='';
+for($i=0;$i<10;$i++) {
+ $random.=chr(mt_rand(64,90));
+}
+
+$m=new TableParentModel();
+$m->fieldUnique=$random;
+$m->fieldKey="key1";
+$m->fieldVarchar='varchar';
+$m->fieldDateTime=new DateTime();
+
+
+//TableParentRepo::insert($m);
+
$parent= (TableParentRepo::setRecursive(
[
@@ -23,7 +37,7 @@
,'_TableParentExt'
]))::first(1);
new dBug($parent);
-die(1);
+
diff --git a/lib/PdoOne.php b/lib/PdoOne.php
index e621e7c..004cd4a 100644
--- a/lib/PdoOne.php
+++ b/lib/PdoOne.php
@@ -1,4 +1,5 @@
-
-
- //
/**
* @var array
* @see \eftec\PdoOne::generateCodeClassConversions
* @see \eftec\PdoOne::generateCodeClass
*/
- private $codeClassConversion = [];
- private $lastBindParam = [];
+ public $codeClassConversion = [];
+ public $genError = true;
/** @var int */
- private $affected_rows = 0;
- private $select = '';
+ public $affected_rows = 0;
+
+ /** @var PdoOne_IExt */
+ public $service;
+ /** @var string|array [optional] It is the family or group of the cache */
+ public $cacheFamily = '';
+ /** @var IPdoOneCache The service of cache [optional] */
+ public $cacheService;
/**
* @var null|int $ttl If 0 then the cache never expires.
* If false then we don't use cache.
@@ -172,53 +182,10 @@ class PdoOne
* cache
* (in seconds)
*/
- private $useCache = false;
- /** @var bool if true then builderReset will not reset (unless it is force), if false then it will reset */
- private $noReset = false;
+ public $useCache = false;
/** @var null|array it stores the values obtained by $this->tableDependency() */
- private $tableDependencyArrayCol;
- private $tableDependencyArray;
- /** @var null|string the unique id generate by sha256or $hashtype and based in the query, arguments, type
- * and methods
- */
- private $uid;
- /** @var string|array [optional] It is the family or group of the cache */
- private $cacheFamily = '';
- /** @var IPdoOneCache The service of cache [optional] */
- private $cacheService;
- /** @var array */
- private $where = [];
-
- /** @var array parameters for the set. [paramvar,value,type,size] */
- private $setParamAssoc = [];
-
-
- /** @var array parameters for the where. [paramvar,value,type,size] */
- private $whereParamAssoc = [];
- /** @var array parameters for the having. [paramvar,value,type,size] */
- private $havingParamAssoc = [];
-
- private $whereCounter = 1;
-
- /** @var array */
- //private $whereParamValue = [];
-
- /** @var array */
- private $set = [];
-
- private $group = '';
-
- private $recursive = [];
-
- private $genError = true;
-
- /** @var array */
- private $having = [];
-
- private $distinct = '';
-
- /** @var PdoOne_IExt */
- private $service;
+ public $tableDependencyArrayCol;
+ public $tableDependencyArray;
//
@@ -646,101 +613,6 @@ public function getDefTableExtended($table, $onlyDescription = false)
return $this->service->getDefTableExtended($table, $onlyDescription);
}
- /**
- * It adds an "order by" in a query.
- * Example:
- *
- * iso depends on the database.
- * Example: Y-m-d H:i:s
- * human is based in d/m/Y H:i:s but it could be changed (self::dateHumanFormat)
- * sql depends on the database
- * class is a DateTime() object
- *
- * @param string $sqlField The date to convert
- * @param string $inputFormat =['iso','human','sql','class','timestamp'][$i]
- * @param string $outputFormat =['iso','human','sql','class','timestamp'][$i]
- * @param null|string $force =[null,'time','ms','none'][$i] It forces if the result gets time or
- * microseconds
- * null = no force the result (it is calculated automatically)
- * time = returns with a precision of seconds
- * ms = returns with a precision of microseconds
- * none = it never returns any time
- *
- * @return bool|DateTime
- */
- public static function dateConvert($sqlField, $inputFormat, $outputFormat, $force = null)
+ public static function varExport($input, $indent = "\t")
{
- /** @var boolean $ms if true then the value has microseconds */
- $ms = false;
- /** @var boolean $time if true then the value has time */
- $time = false;
- $tmpDate=self::dateConvertInput($sqlField,$inputFormat,$ms,$time);
- if (!$tmpDate) {
- return false;
- }
- if ($force !== null) {
- if ($force === 'ms') {
- $ms = true;
- } elseif ($force === 'time') {
- $time = true;
- $ms = false;
- } elseif ($force === 'none') {
- $time = false;
- $ms = false;
- }
- }
- switch ($outputFormat) {
- case 'iso':
- if ($ms) {
- return $tmpDate->format(self::$dateTimeMicroFormat);
- }
- if ($time) {
- return $tmpDate->format(self::$dateTimeFormat);
- }
- return $tmpDate->format(self::$dateFormat);
- case 'human':
- if ($ms) {
- return $tmpDate->format(self::$dateTimeMicroHumanFormat);
- }
- if ($time) {
- return $tmpDate->format(self::$dateTimeHumanFormat);
- }
-
- return $tmpDate->format(self::$dateHumanFormat);
- case 'sql':
- if ($ms) {
- return $tmpDate->format(self::$isoDateInputTimeMs);
- }
- if ($time) {
- return $tmpDate->format(self::$isoDateInputTime);
+ switch (gettype($input)) {
+ case 'string':
+ $r = "'" . addcslashes($input, "\\\$\'\r\n\t\v\f") . "'";
+ break;
+ case 'array':
+ $indexed = array_keys($input) === range(0, count($input) - 1);
+ $r = [];
+ foreach ($input as $key => $value) {
+ $r[] = "$indent " . ($indexed ? '' : self::varExport($key) . ' => ') . self::varExport($value,
+ "$indent ");
}
- return $tmpDate->format(self::$isoDateInput);
- case 'class':
- return $tmpDate;
- case 'timestamp':
- return $tmpDate->getTimestamp();
+ $r = "[\n" . implode(",\n", $r) . "\n" . $indent . ']';
+ break;
+ case 'boolean':
+ $r = $input ? 'TRUE' : 'FALSE';
+ break;
+ default:
+ $r = var_export($input, true);
+ break;
}
- return false;
+ return $r;
}
/**
- * It converts a date and time value (expressed in different means) into a DateTime object or false if the operation
- * fails.
+ * It generates a class
* Example:
*
- * $r=PdoOne::dateConvertInput('01/12/2020','human',$ms,$time); // it depends on the fields self::$date*HumanFormat
- * $r=PdoOne::dateConvertInput('2020-12-01','iso',$ms,$time); // it depends on the fields self::$date*Format
- * $r=PdoOne::dateConvertInput('2020-12-01','sql',$ms,$time); // it depends on the database
- * $r=PdoOne::dateConvertInput(50000,'timestamp',$ms,$time); // a timestamp
- * $r=PdoOne::dateConvertInput(new DateTime(),'class',$ms,$time); // a DateTime object (it keeps the same one)
+ * $class = $this->generateCodeClass('tablename', 'namespace\namespace2'
+ * ,['_idchild2FK'=>'PARENT' // relation
+ * ,'_tablaparentxcategory'=>'MANYTOMANY' // relation
+ * ,'col'=>'datetime3' // conversion
+ * ,'col2'=>'conversion(%s)' // custom conversion (identified by %s)
+ * ,'col3'=>] // custom conversion (identified by %s)
+ * ,'Repo');
+ * $class = $this->generateCodeClass(['ClassName'=>'tablename'], 'namespace\namespace2'
+ * ,['/idchild2FK'=>'PARENT','/tablaparentxcategory'=>'MANYTOMANY']
+ * ,'Repo');
*
*
- * @param mixed $inputValue the input value.
- * @param string $inputFormat=['iso','human','sql','class','timestamp'][$i] The input format
- * @param boolean $ms [ref] It returns if it includes microseconds
- * @param boolean $time [ref] It returns if it includes time
- * @return DateTime|false false if the operation fails
+ * @param string|array $tableName The name of the table and the class.
+ * If the value is an array, then the key is the name of the table and
+ * the value is the name of the class
+ * @param string $namespace The Namespace of the generated class
+ * @param array|null $columnRelations An associative array to specific custom relations, such as PARENT
+ * The key is the name of the columns and the value is the type of
+ * relation
+ * @param null|string[] $classRelations The postfix of the class. Usually it is Repo or Dao.
+ *
+ * @param array $specialConversion An associative array to specify a custom conversion
+ * The key is the name of the columns and the value is the type of
+ * relation
+ * @param string[]|null $defNoInsert An array with the name of the columns to not to insert. The identity
+ * is added automatically to this list
+ * @param string[]|null $defNoUpdate An array with the name of the columns to not to update. The identity
+ * is added automatically to this list
+ * @param string|null $baseClass The name of the base class. If no name then it uses the last namespace
+ * @param string $modelfullClass (default:'') The full class of the model (with the namespace). If
+ * empty, then it doesn't use a model
+ * @param array $extraCols An associative array with extra columns where they key is the name of
+ * the column and the value is the value to return (it is evaluated in
+ * the query). It is used by toList() and first(), it's also added to
+ * the model.
+ *
+ * @param array $columnRemove
+ *
+ * @return string|string[]
+ * @throws Exception
*/
- public static function dateConvertInput($inputValue, $inputFormat, &$ms, &$time) {
- switch ($inputFormat) {
- case 'iso':
- if (strpos($inputValue, '.') !== false) {
- $ms = true;
- $tmpDate = DateTime::createFromFormat(self::$dateTimeMicroFormat, $inputValue);
- } elseif (strpos($inputValue, ':') !== false) {
- $time = true;
- $tmpDate = DateTime::createFromFormat(self::$dateTimeFormat, $inputValue);
- } else {
- $tmpDate = DateTime::createFromFormat(self::$dateFormat, $inputValue);
- if ($tmpDate === false) {
- return false;
- }
- $tmpDate->setTime(0, 0);
- }
- break;
- case 'human':
- if (strpos($inputValue, '.') !== false) {
- $ms = true;
- $tmpDate = DateTime::createFromFormat(self::$dateTimeMicroHumanFormat, $inputValue);
- } elseif (strpos($inputValue, ':') !== false) {
- $time = true;
- $tmpDate = DateTime::createFromFormat(self::$dateTimeHumanFormat, $inputValue);
- } else {
- $tmpDate = DateTime::createFromFormat(self::$dateHumanFormat, $inputValue);
+ public function generateCodeClass(
+ $tableName,
+ $namespace = '',
+ $columnRelations = null,
+ $classRelations = null,
+ $specialConversion = [],
+ $defNoInsert = null,
+ $defNoUpdate = null,
+ $baseClass = null,
+ $modelfullClass = '',
+ $extraCols = [],
+ $columnRemove = []
+ )
+ {
+ $r = <<<'eot'
+setTime(0, 0);
- }
- break;
- case 'sql':
- if (strpos($inputValue, '.') !== false) {
- $ms = true;
- $tmpDate = DateTime::createFromFormat(self::$isoDateTimeMs, $inputValue);
- } elseif (strpos($inputValue, ':') !== false) {
- $time = true;
- $tmpDate = DateTime::createFromFormat(self::$isoDateTime, $inputValue);
- } else {
- $tmpDate = DateTime::createFromFormat(self::$isoDate, $inputValue);
- $tmpDate->setTime(0, 0);
- }
- break;
- case 'class':
- /** @var DateTime $tmpDate */
- $tmpDate = $inputValue;
- $time = $tmpDate->format('Gis') !== '000000';
- break;
- case 'timestamp':
- $tmpDate = new DateTime();
- $tmpDate->setTimestamp($inputValue);
- $time = $tmpDate->format('Gis') !== '000000';
- $ms = fmod($inputValue, 1) !== 0.0;
- break;
- default:
- $tmpDate = false;
- trigger_error('PdoOne: dateConvert type not defined');
- }
- return $tmpDate;
- }
+/**
+ * Generated by PdoOne Version {version}.
+ * DO NOT EDIT THIS CODE. Use instead the Repo Class.
+ * @copyright (c) Jorge Castro C. MIT License https://github.com/EFTEC/PdoOne
+ * Class Abstract{classname}
+ *
+ * $code=$pdoOne->generateCodeClass({args});
+ *
+ */
+abstract class Abstract{classname} extends {baseclass}
+{
+ const TABLE = '{table}';
+ const IDENTITY = {identity};
+ const PK = {pk};
+ const ME=__CLASS__;
+ const EXTRACOLS='{extracol}';
/**
- * Convert date, from text -> mysql (using a format pre-established)
+ * 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 $textDate Input date
- * @param bool $hasTime If true then it works with date and time
- * (instead of date)
+ * @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 string
+ * @return array|array[]
*/
- public static function dateText2Sql($textDate, $hasTime = true)
- {
- if (($hasTime)) {
- $tmpFormat = strpos($textDate, '.') === false ? self::$dateTimeFormat : self::$dateTimeMicroFormat;
- } else {
- $tmpFormat = self::$dateFormat;
+ public static function getDef($column=null,$filter=null) {
+ $r = {def};
+ 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;
+ }
}
-
- $tmpDate = DateTime::createFromFormat($tmpFormat, $textDate);
- if (!$hasTime && $tmpDate) {
- $tmpDate->setTime(0, 0);
+ 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;
}
+{convertoutput}
+{linked}
+ }
- return self::dateTimePHP2Sql($tmpDate); // it always returns a date with time. Mysql Ignores it.
+ /**
+ * 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) {
+{convertinput}
}
+
/**
- * Conver date from php -> mysql
- * It always returns a time (00:00:00 if time is empty). it could returns
- * microseconds 2010-01-01 00:00:00.00000
- *
- * @param DateTime $date
+ * It gets all the name of the columns.
*
- * @return string
+ * @return string[]
*/
- public static function dateTimePHP2Sql($date)
- {
- // 31/01/2016 20:20:00 --> 2016-01-31 00:00
- if ($date == null) {
- return self::$dateEpoch;
- }
- if ($date->format('u') !== '000000') {
- return $date->format(self::$isoDateTimeMs);
- }
-
- return $date->format(self::$isoDateTime);
+ public static function getDefName() {
+ return {defname};
}
/**
- * Returns the current date(and time) in Text (human) format. Usually, it is d/m/Y H:i:s
- *
- * @param bool $hasTime
- * @param bool $hasMicroseconds
+ * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
*
- * @return string
- * @throws Exception
- * @see PdoOne::$dateTimeFormat
+ * @return string[]
*/
- public static function dateTextNow(
- $hasTime = true,
- $hasMicroseconds = false
- )
- {
- $tmpDate = new DateTime();
- if ($hasTime) {
- return $tmpDate->format(($hasMicroseconds !== false) ? self::$dateTimeMicroHumanFormat
- : self::$dateTimeHumanFormat);
- }
- return $tmpDate->format(self::$dateHumanFormat);
+ public static function getDefKey() {
+ return {defkey};
}
/**
- * Returns the current (PHP server) date and time in the regular format. (Y-m-d\TH:i:s\Z in long format)
- *
- * @param bool $hasTime
- * @param bool $hasMicroseconds
+ * It returns a string array with the name of the columns that are skipped when insert
+ * @return string[]
+ */
+ public static function getDefNoInsert() {
+ return {defnoinsert};
+ }
+
+ /**
+ * It returns a string array with the name of the columns that are skipped when update
+ * @return string[]
+ */
+ public static function getDefNoUpdate() {
+ return {defnoupdate};
+ }
+
+ /**
+ * It adds a where to the query pipeline. It could be stacked with many where()
+ * Example:
+ *
+ *
+ * @param array|string $sql =self::factory()
+ * @param null|array|int $param
*
- * @return string
- * @throws Exception
- * @see PdoOne::$dateTimeFormat
+ * @return {classname}
*/
- public static function dateNow(
- $hasTime = true,
- $hasMicroseconds = false
- )
+ public static function where($sql, $param = PdoOne::NULL)
{
- $tmpDate = new DateTime();
- if ($hasTime) {
- return $tmpDate->format(($hasMicroseconds !== false) ? self::$dateTimeMicroFormat : self::$dateTimeFormat);
+ self::getPdoOne()->where($sql, $param,false,{classname}::TABLE);
+ return {classname}::class;
+ }
+
+ public static function getDefFK($structure=false) {
+ if ($structure) {
+ return {deffk};
}
- return $tmpDate->format(self::$dateFormat);
+ /* key,refcol,reftable,extra */
+ return {deffktype};
}
/**
- * Returns the current date(and time) in SQL/ISO format. It depends on the type of database.
+ * 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]
*
- * @param bool $hasTime
- * @param bool $hasMicroseconds
+ * @return string[]
+ * @noinspection SlowArrayOperationsInLoopInspection
+ */
+ public static function getRelations($type='all') {
+ $r= {deffktype2};
+ if($type==='*') {
+ $result=[];
+ foreach($r as $arr) {
+ $result = array_merge($result,$arr);
+ }
+ return $result;
+ }
+ return isset($r[$type]) ? $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 {classmodellist}
+ }
+ 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:
+ *
+ * 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)
*
- * @return string
+ * @param string|array $recursive=self::factory();
+ *
+ * @return {classname}
*/
- public static function dateSqlNow($hasTime = true, $hasMicroseconds = false)
+ public static function setRecursive($recursive=[])
{
- $tmpDate = new DateTime();
- if ($hasTime) {
- var_dump(($hasMicroseconds !== false) ? self::$isoDateTimeMs : self::$isoDateTime);
- return $tmpDate->format(($hasMicroseconds !== false) ? self::$isoDateTimeMs : self::$isoDateTime);
+ if(is_string($recursive)) {
+ $recursive={classname}::getRelations($recursive);
}
-
- return $tmpDate->format(self::$isoDate);
+ return parent::_setRecursive($recursive);
}
- public static function isCli()
+ public static function limit($sql)
{
- return !http_response_code();
+ self::getPdoOne()->limit($sql);
+ return {classname}::class;
}
- //
-
/**
- * @param mixed $v Variable
+ * It returns the first row of a query.
+ * @param array|mixed|null $pk [optional] Specify the value of the primary key.
*
- * @return int=[PDO::PARAM_STR,PDO::PARAM_INT,PDO::PARAM_BOOL][$i]
- * @test equals PDO::PARAM_STR,(20.3)
- * @test equals PDO::PARAM_STR,('hello')
+ * @return array|bool It returns false if not file is found.
+ * @throws Exception
*/
- private function getType(&$v)
- {
- switch (1) {
- case (is_float($v)):
- case ($v === null):
- $vt = PDO::PARAM_STR;
- break;
- case (is_numeric($v)):
- $vt = PDO::PARAM_INT;
- break;
- case (is_bool($v)):
-
- $vt = PDO::PARAM_INT;
- $v = ($v) ? 1 : 0;
- break;
- case (is_object($v) && $v instanceof DateTime):
- $vt = PDO::PARAM_STR;
- $v = self::dateTimePHP2Sql($v);
- break;
- default:
- $vt = PDO::PARAM_STR;
- }
-
- return $vt;
+ public static function first($pk = PdoOne::NULL) {
+ if(self::$useModel) {
+ return {classmodelfirst}
+ }
+ return self::_first($pk);
}
/**
- * Run a prepared statement.
- * Example:
- * $con->runQuery($con->prepare('select * from table'));
- *
- * @param PDOStatement $stmt PDOStatement
- * @param array|null $namedArgument (optional)
+ * 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 bool $throwError (default true) if false, then it won't throw an error but it will store the error
+ * @param array|mixed $entity =self::factory()
*
- * @return bool returns true if the operation is correct, otherwise false
+ * @return bool true if the pks exists
* @throws Exception
- * @test equals true,$this->pdoOne->runQuery($this->pdoOne->prepare('select
- * 1 from dual'))
- * @test equals
- * [1=>1],$this->pdoOne->select('1')->from('dual')->first(),'it
- * must runs'
*/
- public function runQuery($stmt, $namedArgument = null, $throwError = true)
- {
- if (!$this->isOpen) {
- $this->throwError("It's not connected to the database", '', $throwError);
- return null;
- }
- try {
- //$namedArgument = ($namedArgument === null)
- // ? array_merge($this->setParamAssoc,$this->whereParamAssoc,$this->havingParamAssoc) : $namedArgument;
- $r = $stmt->execute($namedArgument);
- } catch (Exception $ex) {
- $this->throwError($this->databaseType . ':Failed to run query', $this->lastQuery,
- ['param' => $this->lastParam, 'error_last' => json_encode(error_get_last())], $throwError, $ex);
- return false;
- }
- if ($r === false) {
- $this->throwError('Exception query ', $this->lastQuery, ['param' => $this->lastParam], $throwError);
- return false;
- }
-
- return true;
+ public static function exist($entity) {
+ return self::_exist($entity);
}
- protected static function fixCsv($value)
- {
- if (is_numeric($value)) {
- return $value;
- }
- $value = str_replace('"', '""', $value);
-
- return '"' . $value . '"';
+ /**
+ * 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);
}
/**
- * @param string $query
+ * @param array|object $entity =self::factory()
+ * @param bool $transactional If true (default) then the operation is transactional
*
- * @return string
+ * @return array|false=self::factory()
* @throws Exception
*/
- public function generateCodeSelect($query)
- {
- $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) {
- $k2 = str_replace(' by', '', $k); // order by -> order
- foreach ($v as $vitem) {
- $code .= "\t->{$k2}(\"{$vitem}\")\n";
- }
- }
- }
- $code .= "\t->toList();\n";
-
- return $code;
- }
-
- protected static function splitQuery($query)
- {
- $result = [];
- $parts = [
- 'select',
- 'from',
- 'inner join',
- 'inner join',
- 'inner join',
- 'inner join',
- 'inner join',
- 'inner join',
- 'left join',
- 'left join',
- 'left join',
- 'left join',
- 'left join',
- 'left join',
- 'right join',
- 'right join',
- 'right join',
- 'right join',
- 'right join',
- 'right join',
- 'where',
- 'group by',
- 'having',
- 'order by',
- 'limit',
- '*END*',
- ];
- $partsRealIndex = [
- 'select',
- 'from',
- 'innerjoin',
- 'innerjoin',
- 'innerjoin',
- 'innerjoin',
- 'innerjoin',
- 'innerjoin',
- 'left',
- 'left',
- 'left',
- 'left',
- 'left',
- 'left',
- 'right',
- 'right',
- 'right',
- 'right',
- 'right',
- 'right',
- 'where',
- 'group',
- 'having',
- 'order',
- 'limit',
- '*END*',
- ];
- $query = str_replace(array("\r\n", "\n", "\t", ' ', ' '), ' ',
- $query); // remove 3 or 2 space and put instead 1 space
- $query = ' ' . trim($query, " \t\n\r\0\x0B;") . '*END*'; // we also trim the last ; (if any)
- $pfin = 0;
- foreach ($parts as $kp => $part) {
- $ri = $partsRealIndex[$kp];
- if ($part !== '*END*') {
- //$result[$ri] = null;
- $pini = stripos($query, $part, $pfin);
- if ($pini !== false) {
- $pini += strlen($part);
- $found = false;
- $cp = count($parts);
- for ($i = $kp + 1; $i < $cp; $i++) {
- $pfin = stripos($query, $parts[$i], $pini);
- if ($pfin !== false) {
- $found = $pfin;
- break;
- }
- }
- if ($found !== false) {
- $pfin = $found;
- if (!isset($result[$ri])) {
- $result[$ri] = [];
- }
- $result[$ri][] = trim(substr($query, $pini, $pfin - $pini));
- }
- }
- }
- }
-
- return $result;
- }
+ public static function update($entity,$transactional=true) {
+ return self::_update($entity,$transactional);
+ }
/**
- * @param string $table
- * @param null|string $sql
- * @param bool $defaultNull
- * @param bool $inline
- * @param bool $recursive
- * @param null|array $classRelations [optional] The relation table=>classname
- * @param array $relation [optional] An optional custom relation of columns
+ * It deletes an entity by the primary key
*
- * @return string
+ * @param array|object $entity =self::factory()
+ * @param bool $transactional If true (default) then the operation is transactional
+ *
+ * @return mixed
* @throws Exception
*/
- public function generateCodeArray(
- $table,
- $sql = null,
- $defaultNull = false,
- $inline = true,
- $recursive = false,
- $classRelations = null,
- $relation = []
- )
- {
- if ($sql === null) {
- $sql = 'select * from ' . $this->addDelimiter($table);
- }
- $r = $this->toMeta($sql);
-
- $ln = ($inline) ? '' : "\n";
- if ($recursive) {
- /** @noinspection PhpUnusedLocalVariableInspection */
- list($tables, $after, $before) = $this->tableDependency(true);
- } else {
- $tables = null;
- $after = null;
- $before = null;
- }
- $result = '[' . $ln;
- $used = [];
- $norepeat = [];
- foreach ($r as $row) {
- $name = $row['name'];
- if (!in_array($name, $used, true)) {
- if ($defaultNull) {
- $default = 'null';
- } else {
- $default = $this->typeDict($row);
- }
- $result .= "'" . $name . "'=>" . $default . ',' . $ln;
- if ($recursive) {
- if (isset($before[$table][$name])) {
- foreach ($before[$table][$name] as $k => $v3) {
- if ($v3[1]
- && $v3[0][0] !== self::$prefixBase
- ) { // before is defined as [colremote,tableremote]
- $colName = self::$prefixBase . $v3[1];
- if (!$defaultNull) {
- $default = '(in_array($recursivePrefix.\'' . $colName . '\',$recursive,true))
- ? []
- : null';
- } else {
- $default = 'null';
- }
- if (!in_array($colName, $norepeat)) {
- if (isset($relation[$colName])) {
- $key = $relation[$colName]['key'];
-
- if ($key === 'PARENT') {
- $default = 'null';
- }
- if ($key === 'ONETOONE' && !$defaultNull) {
- if ($classRelations === null
- || !isset($classRelations[$relation[$colName]['reftable']])
- ) {
- $className = self::camelize($relation[$colName]['reftable']) . 'Repo';
- } else {
- $className = $relation[$colName]['reftable'];
- }
- $default = '(in_array($recursivePrefix.\'' . $colName . '\',$recursive,true))
- ? ' . $className . '::factory(null,$recursivePrefix.\'' . $colName . '\')
- : null';
- }
- $result .= "'" . $colName . "'=>" . $default . ', /* ' . $key . '! */' . $ln;
- $norepeat[] = $colName;
- } else {
- $result .= "'" . $colName . "'=>" . $default . ', /* onetomany */' . $ln;
- $norepeat[] = $colName;
- }
- }
- }
- }
- }
- if (@$after[$table][$name]) {
- if (!$defaultNull) {
- if ($classRelations === null || !isset($classRelations[$after[$table][$name]])) {
- $className = self::camelize($after[$table][$name]) . 'Repo';
- } else {
- $className = $classRelations[$after[$table][$name]];
- }
- $default = '(in_array($recursivePrefix.\'' . self::$prefixBase . $name . '\',$recursive,true))
- ? ' . $className . '::factory(null,$recursivePrefix.\'' . self::$prefixBase . $name . '\')
- : null';
- }
- if (!in_array($name, $norepeat)) {
- $namep = self::$prefixBase . $name;
- if (isset($relation[$namep])) {
- /*array(5) {
- ["key"]=>
- string(11) "FOREIGN KEY"
- ["refcol"]=>
- string(14) "idtablachildPK"
- ["reftable"]=>
- string(10) "TableChild"
- ["extra"]=>
- string(0) ""
- ["name"]=>
- string(26) "FK_TableParent_TableChild1"
- }*/
- $key = $relation[$namep]['key'];
- if ($key !== 'PARENT') {
- // $default = 'null';
- $result .= "'" . $namep . "'=>" . $default . ', /* ' . $key . '!! */' . $ln;
- $norepeat[] = $name;
- }
- } else {
- $result .= "'" . $namep . "'=>" . $default . ', /* manytoone */' . $ln;
- $norepeat[] = $name;
- }
- }
- }
- }
- }
-
- $used[] = $name;
- }
- $result .= ']' . $ln;
- $result = str_replace(",$ln]", "$ln]", $result);
- return $result;
+ public static function delete($entity,$transactional=true) {
+ return self::_delete($entity,$transactional);
}
/**
- * It returns an array with the metadata of each columns (i.e. name, type,
- * size, etc.) or false if error.
- *
- * @param null|string $sql If null then it uses the generation of query
- * (if any). if string then get the
- * statement of the query
+ * It deletes an entity by the primary key.
*
- * @param array $args
+ * @param array $pk =self::factory()
+ * @param bool $transactional If true (default) then the operation is transactional
*
- * @return array|bool
+ * @return mixed
* @throws Exception
*/
- public function toMeta($sql = null, $args = [])
- {
- $uid = false;
- if ($sql === null) {
- $this->beginTry();
- /** @var PDOStatement $stmt */
- $stmt = $this->runGen(false, PDO::FETCH_ASSOC, 'tometa', $this->genError);
- if ($this->endtry() === false) {
- return false;
- }
+ 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= {array};
+{linked}
+ 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= {array_null};
+ if ($values !== null) {
+ $row = array_merge($row, $values);
+ }
+ return $row;
+ }
+
+}
+eot;
+ $lastns = explode('\\', $namespace);
+
+ if ($modelfullClass) {
+ $arr = explode('\\', $modelfullClass);
+ $modelClass = end($arr);
+ $modelUse = true;
} else {
- if ($this->useInternalCache) {
- $uid = hash($this->encryption->hashType, 'meta:' . $sql . serialize($args));
- if (isset($this->internalCache[$uid])) {
- // we have an internal cache, so we will return it.
- $this->internalCacheCounter++;
- return $this->internalCache[$uid];
- }
- }
- /** @var PDOStatement $stmt */
- $stmt = $this->runRawQuery($sql, $args, false);
+ $modelClass = false;
+ $modelUse = false;
}
- if ($stmt === null || $stmt instanceof PDOStatement === false) {
- $stmt = null;
- return false;
- }
- $numCol = $stmt->columnCount();
- $rows = [];
- for ($i = 0; $i < $numCol; $i++) {
- $rows[] = $stmt->getColumnMeta($i);
+ $baseClass = ($baseClass === null) ? end($lastns) : $baseClass;
+
+ $fa = func_get_args();
+ foreach ($fa as $f => $k) {
+ if (is_array($k)) {
+ $fa[$f] = str_replace([' ', "\r\n", "\n"], ['', '', ''], var_export($k, true));
+ } else {
+ $fa[$f] = "'$k'";
+ }
}
- $stmt = null;
- if ($uid !== false) {
- $this->internalCache[$uid] = $rows;
+ if ($classRelations === null || !isset($classRelations[$tableName])) {
+ $className = self::camelize($tableName);
+ } else {
+ $className = $classRelations[$tableName];
}
- return $rows;
- }
- /**
- * Begin a try block. It marks the erroText as empty and it store the value of genError
- */
- private function beginTry()
- {
- $this->errorText = '';
- $this->isThrow = $this->genError; // this value is deleted when it trigger an error
- $this->throwOnErrorB = $this->throwOnError;
- $this->throwOnError = false;
- }
+ $extraColArray = '';
+ foreach ($extraCols as $k => $v) {
+ $extraColArray .= $v . ' as ' . $this->addQuote($k) . ',';
+ }
+ $extraColArray = rtrim($extraColArray, ',');
- /**
- * Run builder query and returns a PDOStatement.
- *
- * @param bool $returnArray true=return an array. False returns a
- * PDOStatement
- * @param int $extraMode PDO::FETCH_ASSOC,PDO::FETCH_BOTH,PDO::FETCH_NUM,etc.
- * By default it returns
- * $extraMode=PDO::FETCH_ASSOC
- *
- * @param string $extraIdCache [optional] if 'rungen' then cache is
- * stored. If false the cache could be
- * stored
- *
- * @param bool $throwError
- *
- * @return bool|PDOStatement|array
- * @throws Exception
- */
- public function runGen(
- $returnArray = true,
- $extraMode = PDO::FETCH_ASSOC,
- $extraIdCache = 'rungen',
- $throwError = true
- )
- {
- $this->errorText = '';
- $allparam = '';
- $uid = false;
- $sql = $this->sqlGen();
- $isSelect = self::queryCommand($sql, true) === 'dql';
+ $r = str_replace(array(
+ '{version}',
+ '{classname}',
+ '{exception}',
+ '{baseclass}',
+ '{args}',
+ '{table}',
+ '{namespace}',
+ '{modelnamespace}',
+ '{classmodellist}',
+ '{classmodelfirst}',
+ '{extracol}'
+ ), array(
+ self::VERSION . ' Date generated ' . date('r'), //{version}
+ $className, // {classname}
+ ($namespace) ? 'use Exception;' : '',
+ $baseClass, // {baseclass}
+ implode(",", $fa),
+ $tableName, // {table}
+ ($namespace) ? "namespace $namespace;" : '', //{namespace}
+ $modelUse ? "use $modelfullClass;" : '', // {modelnamespace}
+ $modelUse ? "$modelClass::fromArrayMultiple( self::_toList(\$filter, \$filterValue));"
+ : 'false; // no model set', // {classmodellist}
+ $modelUse ? "$modelClass::fromArray(self::_first(\$pk));" : 'false; // no model set' // {classmodelfirst}
+ ,
+ $extraColArray // {extracol}
+ ), $r);
+ $pk = '??';
+ $pk = $this->service->getPK($tableName, $pk);
+ $pkFirst = (is_array($pk) && count($pk) > 0) ? $pk[0] : null;
try {
- $allparam = array_merge($this->setParamAssoc, $this->whereParamAssoc, $this->havingParamAssoc);
-
- if ($isSelect && $this->useInternalCache && $returnArray) {
- $uid = hash($this->encryption->hashType, $sql . $extraMode . serialize($allparam));
- if (isset($this->internalCache[$uid])) {
- // we have an internal cache, so we will return it.
- $this->internalCacheCounter++;
- $this->builderReset();
- return $this->internalCache[$uid];
- }
- }
+ $relation = $this->getDefTableFK($tableName, false, true);
+ } catch (Exception $e) {
+ return 'Error: Unable read fk of table ' . $e->getMessage();
+ }
- /** @var PDOStatement $stmt */
- $stmt = $this->prepare($sql);
+ // 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->throwError('Error in prepare runGen', $extraIdCache, ['values' => $allparam], $throwError, $e);
- $this->builderReset();
- return false;
+ return 'Error: Unable read table dependencies ' . $e->getMessage();
+ } // ["city"]=> {["city_id"]=> "address"}
+ $after = @$deps[1][$tableName];
+ if ($after === null) {
+ $after = @$deps[1][strtolower($tableName)];
}
- if ($stmt === null || $stmt === false) {
- $this->builderReset();
- return false;
+ $before = @$deps[2][$tableName];
+ if ($before === null) {
+ $before = @$deps[2][strtolower($tableName)];
}
- $reval = true;
- if ($allparam) {
- try {
- foreach ($allparam as $k => $v) {
- $reval = $reval && $stmt->bindParam($v[0], $allparam[$k][1], $v[2]);
+ 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)
+ ];
}
- } catch(Exception $ex) {
- if(is_object($allparam[$k][1])) {
- $this->throwError("Error in bind. Parameter error."
- , "Parameter {$v[0]} ($k) is an object of the class ".get_class($allparam[$k][1])
- , ['values' => $allparam], $throwError);
- $this->builderReset();
- return false;
+ }
+ }
+ // 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);
}
- $this->throwError("Error in bind. Parameter error.", "Parameter {$v[0]} ($k)"
- , ['values' => $allparam], $throwError);
- $this->builderReset();
- return false;
}
- if (!$reval) {
- $this->throwError('Error in bind', $extraIdCache, ['values' => $allparam], $throwError);
- $this->builderReset();
- return false;
+ 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);
+ }
}
}
- $useCache = $this->useCache; // because builderReset cleans this value
- if ($useCache !== false && $returnArray) {
- $this->uid
- = hash($this->encryption->hashType,
- $this->lastQuery . $extraMode . serialize($allparam) . $extraIdCache);
- $result = $this->cacheService->getCache($this->uid, $this->cacheFamily);
- if ($result !== false) {
- // it's found in the cache.
- $this->builderReset();
- if ($uid !== false) {
- $this->internalCache[$uid] = $result;
+ if ($columnRelations) {
+ foreach ($relation as $k => $rel) {
+ if (isset($columnRelations[$k])) {
+ // parent.
+ if ($columnRelations[$k] === 'PARENT') {
+ $relation[$k]['key'] = 'PARENT';
+ } elseif ($columnRelations[$k] === 'MANYTOMANY') {
+ // the table must has 2 primary keys.
+ $pks = null;
+ $pks = $this->service->getPK($relation[$k]['reftable'], $pks);
+ /** @noinspection PhpParamsInspection */
+ 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) {
+ return 'Error: Unable read table dependencies ' . $e->getMessage();
+ }
+ try {
+ $keys2 = $this->service->getDefTableKeys($defsFK[$refcol2]['reftable'], true,
+ 'PRIMARY KEY');
+ } catch (Exception $e) {
+ return 'Error: Unable read table dependencies' . $e->getMessage();
+ }
+ $relation[$k]['refcol2'] = self::$prefixBase . $refcol2;
+ if (is_array($keys2)) {
+ $keys2 = array_keys($keys2);
+ $relation[$k]['col2'] = $keys2[0];
+ } else {
+ $relation[$k]['col2'] = null;
+ }
+ $relation[$k]['table2'] = $defsFK[$refcol2]['reftable'];
+ }
+ }
+ // manytomany
}
- return $result;
}
- } elseif ($extraIdCache === 'rungen') {
- $this->uid = null;
}
- $this->runQuery($stmt, null, false);
- if ($returnArray && $stmt instanceof PDOStatement) {
- $result = ($stmt->columnCount() > 0) ? $stmt->fetchAll($extraMode) : [];
- $this->affected_rows = $stmt->rowCount();
- $stmt = null; // close
- if ($extraIdCache === 'rungen' && $this->uid) {
- // we store the information of the cache.
- $this->setCache($this->uid, $this->cacheFamily, $result, $useCache);
- }
- $this->builderReset();
- if ($uid !== false) {
- $this->internalCache[$uid] = $result;
- }
- return $result;
+ //die(1);
+ $convertOutput = '';
+ $convertInput = '';
+ $getDefTable = $this->getDefTable($tableName, $specialConversion);
+
+ foreach ($columnRemove as $v) {
+ unset($getDefTable[$v]);
}
+ //die(1);
- $this->builderReset();
- return $stmt;
- }
+ // we forced the conversion but only if it is not specified explicit
- /**
- * Generates the sql (script). It doesn't run or execute the query.
- *
- * @param bool $resetStack if true then it reset all the values of the
- * stack, including parameters.
- *
- * @return string
- */
- public function sqlGen($resetStack = false)
- {
- if (stripos($this->select, 'select ') === 0) {
- // is it a full query? $this->select=select * ..." instead of $this->select=*
- $words = preg_split('#\s+#', strtolower($this->select));
- } else {
- $words = [];
- }
- if (!in_array('select', $words)) {
- $sql = 'select ' . $this->distinct . $this->select;
- } else {
- $sql = $this->select; // the query already constains "select", so we don't want "select select * from".
- }
- if (!in_array('from', $words)) {
- $sql .= ' from ' . $this->from;
- } else {
- $sql .= $this->from;
- }
- $where = $this->constructWhere();
- $having = $this->constructHaving();
+ $allColumns = array_merge($getDefTable, $extraCols); // $extraColArray does not has type
+
+ foreach ($allColumns as $kcol => $colDef) {
+ $type = isset($colDef['type']) ? $colDef['type'] : null;
+ $conversion = null;
+ if (isset($columnRelations[$kcol])) {
+ $conversion = $columnRelations[$kcol];
+ if ($type !== null) {
+ $getDefTable[$kcol]['conversion'] = $conversion;
+ } else {
+ $type = 'new column';
+ }
+ } elseif ($type !== null && isset($this->codeClassConversion[$type])
+ && $getDefTable[$kcol]['conversion'] === null
+ ) {
+ $conversion = $this->codeClassConversion[$type];
+ $getDefTable[$kcol]['conversion'] = $conversion;
+ }
+
+ if ($conversion !== null) {
+ if (is_array($conversion)) {
+ list($input, $output) = $conversion;
+ } else {
+ $input = $conversion;
+ $output = $input;
+ }
- $sql .= $where . $this->group . $having . $this->order . $this->limit;
+ switch ($input) {
+ case 'encrypt':
+ $tmp2 = "isset(%s) and %s=self::getPdoOne()->encrypt(%s);";
+ break;
+ case 'decrypt':
+ $tmp2 = "isset(%s) and %s=self::getPdoOne()->decrypt(%s);";
+ break;
+ case 'datetime3':
+ $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'human', 'sql');";
+ break;
+ case 'datetime4':
+ $tmp2='';
+ //$tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'sql', 'sql');";
+ break;
+ case 'datetime2':
+ $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'iso', 'sql');";
+ break;
+ case 'datetime':
+ $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'class', 'sql');";
+ break;
+ case 'timestamp':
+ $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'timestamp', 'sql')";
+ break;
+ case 'bool':
+ $tmp2 = "isset(%s) and %s=(%s) ? 1 : 0;";
+ break;
+ case 'int':
+ $tmp2 = "isset(%s) and %s=(int)%s;";
+ break;
+ case 'float':
+ case 'decimal':
+ $tmp2 = "isset(%s) and %s=(float)%s;";
+ break;
+ default:
+ if (strpos($input, '%s') !== false) {
+ $tmp2 = "%s=isset(%s) ? " . $input . " : null;";
+ } else {
+ $tmp2 = '// type ' . $input . ' not defined';
+ }
+ }
+ switch ($output) {
+ case 'encrypt':
+ $tmp = "%s=isset(%s) ? self::getPdoOne()->encrypt(%s) : null;";
+ break;
+ case 'decrypt':
+ $tmp = "%s=isset(%s) ? self::getPdoOne()->decrypt(%s) : null;";
+ break;
+ case 'datetime3':
+ $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'human') : null;";
+ break;
+ case 'datetime4':
+ // sql->sql no conversion
+ $tmp = '';
+ break;
+ case 'datetime2':
+ $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'iso') : null;";
+ break;
+ case 'datetime':
+ $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'class') : null;";
+ break;
+ case 'timestamp':
+ $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'timestamp') : null;";
+ break;
+ case 'bool':
+ $tmp = "%s=isset(%s) ? (%s) ? true : false : null;";
+ break;
+ case 'int':
+ $tmp = "%s=isset(%s) ? (int)%s : null;";
+ break;
+ case 'float':
+ case 'decimal':
+ $tmp = "%s=isset(%s) ? (float)%s : null;";
+ break;
+ case null:
+ $tmp = "!isset(%s) and %s=null; // no conversion";
+ break;
+ default:
+ if (strpos($output, '%s') !== false) {
+ $tmp = "%s=isset(%s) ? " . $output . " : null;";
+ } else {
+ $tmp = '// type ' . $output . ' not defined';
+ }
+ }
- if ($resetStack) {
- $this->builderReset();
+ if ($tmp !== '') {
+ $convertOutput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp) . "\n";
+ $convertInput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp2) . "\n";
+ }
+ } else {
+ $tmp = "!isset(%s) and %s=null; // $type";
+ $convertOutput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp) . "\n";
+ }
}
- return $sql;
- }
+ $linked = '';
+ foreach ($relation as $k => $v) {
+ $key = $v['key'];
+ if ($key === 'MANYTOONE') {
+ //$col = ltrim($v['refcol'], '_');
+ $col = ltrim($k, '_');
+ $linked .= str_replace(['{_col}', '{refcol}', '{col}'], [$k, $v['refcol'], $col], "\t\tisset(\$row['{_col}'])
+ and \$row['{_col}']['{refcol}']=&\$row['{col}']; // linked MANYTOONE\n");
+ }
+ if ($key === 'ONETOONE') {
+ //$col = ltrim($v['refcol'], '_');
+ //$col = ltrim($k, '_');
+ $linked .= str_replace(['{_col}', '{refcol}', '{col}'], [$k, $v['refcol'], $v['col']], "\t\tisset(\$row['{_col}'])
+ and \$row['{_col}']['{refcol}']=&\$row['{col}']; // linked ONETOONE\n");
+ }
+ }
+ //$convertOutput.=$linked;
- /**
- * @return string
- */
- private function constructWhere()
- {
- return count($this->where) ? ' where ' . implode(' and ', $this->where) : '';
- }
+ $convertOutput = rtrim($convertOutput, "\n");
+ $convertInput = rtrim($convertInput, "\n");
- //
+ // discard columns
+ //$identities=$this->getDefTableKeys($tableName,);
+ $identities = $this->getDefIdentities($tableName);
+ if (count($identities) > 0) {
+ $identity = $identities[0];
+ } else {
+ $identity = null;
+ }
+ if ($defNoInsert !== null) {
+ $noInsert = array_merge($identities, $defNoInsert);
+ } else {
+ $noInsert = $identities;
+ }
+ if ($defNoUpdate !== null) {
+ $noUpdate = array_merge($identities, $defNoUpdate);
+ } else {
+ $noUpdate = array_merge($identities);
+ }
+ if ($pk) {
+ // we never update the primary key.
+ /** @noinspection AdditionOperationOnArraysInspection */
+ $noUpdate += $pk; // it adds and replaces duplicates, indexes are ignored.
+ }
- /**
- * Returns a list of objects from the current schema/db
- *
- * @param string $type =['table','function'][$i] The type of the
- * object
- * @param bool $onlyName If true then it only returns the name of the
- * objects.
- *
- * @return bool|array
- * @throws Exception
- */
- public function objectList($type = 'table', $onlyName = false)
- {
- $query = $this->service->objectList($type, $onlyName);
- if ($onlyName) {
- return $this->select($query)->toListSimple();
+ $relation2 = [];
+ foreach ($relation as $col => $arr) {
+ if ($arr['key'] !== 'FOREIGN KEY' && $arr['key'] !== 'PARENT' && $arr['key'] !== 'NONE') {
+ @$relation2[$arr['key']][] = $col;
+ }
+ //if($arr['key']==='MANYTOONE') {
+ // $relation2[]=$col;
+ // }
}
- return $this->runRawQuery($query, []);
+ try {
+ $r = str_replace(array(
+ '{pk}',
+ '{identity}',
+ '{def}',
+ '{convertoutput}',
+ '{convertinput}',
+ '{defname}',
+ '{defkey}',
+ '{defnoinsert}',
+ '{defnoupdate}',
+ '{deffk}',
+ '{deffktype}',
+ '{deffktype2}',
+ '{array}',
+ '{array_null}',
+ '{linked}'
+ ), array(
+ self::varExport($pk),
+ self::varExport($identity), // {identity}
+ //str_replace(["\n\t\t ", "\n\t\t ],"], ['', '],'], self::varExport($gdf, "\t\t")), // {def}
+ self::varExport($getDefTable, "\t\t"), // {def}
+ $convertOutput, // {convertoutput}
+ $convertInput, // {convertinput}
+ self::varExport(array_keys($getDefTable), "\t\t"), // {defname}
+ self::varExport($this->getDefTableKeys($tableName), "\t\t"), // {defkey}
+ self::varExport($noInsert, "\t\t"), // {defnoinsert}
+ self::varExport($noUpdate, "\t\t"), // {defnoupdate}
+ self::varExport($this->getDefTableFK($tableName), "\t\t\t"), //{deffk}
+ self::varExport($relation, "\t\t"), //{deffktype}
+ self::varExport($relation2, "\t\t"), //{deffktype2}
+ str_replace("\n", "\n\t\t",
+ rtrim($this->generateCodeArray($tableName, null, false, false, true, $classRelations, $relation),
+ "\n")),
+ str_replace("\n", "\n\t\t",
+ rtrim($this->generateCodeArray($tableName, null, true, false, true, $classRelations, $relation),
+ "\n")),
+ $linked // {linked}
+ ), $r);
+ } catch (Exception $e) {
+ return "Unable read definition of tables " . $e->getMessage();
+ }
+
+ return $r;
}
/**
- * It returns an array of simple columns (not declarative). It uses the
- * first column
- * Example:
+ * It returns an array with all the tables of the schema, also the foreign key and references of each table
+ * Example:
*
- *
- * @param int $pdoMode (optional) By default is PDO::FETCH_ASSOC
+ * Injects a Message Container.
*
- * @return array|bool
- * @throws Exception
+ * @return MessageList|null
+ * @test equals null,this(),'this is not a message container'
*/
- public function toList($pdoMode = PDO::FETCH_ASSOC)
+ public function getMessages()
{
- $useCache = $this->useCache; // because builderReset cleans this value
- $this->beginTry();
- $rows = $this->runGen(true, $pdoMode, 'tolist', false);
- if ($this->endtry() === false) {
- return false;
- }
- if ($this->uid && $useCache !== false) {
- // we store the information of the cache.
- $this->setCache($this->uid, $this->cacheFamily, $rows, $useCache);
+ if (function_exists('messages')) {
+ return messages();
}
- return $rows;
- }
- /**
- * It returns a PDOStatement.
- * Note: The result is not cached.
- *
- * @return PDOStatement
- * @throws Exception
- */
- public function toResult()
- {
- return $this->runGen(false);
+ return null;
}
- /**
- * It returns the first row. If there is not row then it returns false.
- * This method is an end of the chain method, so it clears the method stack
- * Example:
- *
- *
- * @param string|array $tableName The name of the table and the class.
- * If the value is an array, then the key is the name of the table and
- * the value is the name of the class
- * @param string $namespace The Namespace of the generated class
- * @param array|null $columnRelations An associative array to specific custom relations, such as PARENT
- * The key is the name of the columns and the value is the type of
- * relation
- * @param null|string[] $classRelations The postfix of the class. Usually it is Repo or Dao.
- *
- * @param array $specialConversion An associative array to specify a custom conversion
- * The key is the name of the columns and the value is the type of
- * relation
- * @param string[]|null $defNoInsert An array with the name of the columns to not to insert. The identity
- * is added automatically to this list
- * @param string[]|null $defNoUpdate An array with the name of the columns to not to update. The identity
- * is added automatically to this list
- * @param string|null $baseClass The name of the base class. If no name then it uses the last namespace
- * @param string $modelfullClass (default:'') The full class of the model (with the namespace). If
- * empty, then it doesn't use a model
- * @param array $extraCols An associative array with extra columns where they key is the name of
- * the column and the value is the value to return (it is evaluated in
- * the query). It is used by toList() and first(), it's also added to
- * the model.
- *
- * @param array $columnRemove
- *
- * @return string|string[]
- * @throws Exception
- */
- public function generateCodeClass(
- $tableName,
- $namespace = '',
- $columnRelations = null,
- $classRelations = null,
- $specialConversion = [],
- $defNoInsert = null,
- $defNoUpdate = null,
- $baseClass = null,
- $modelfullClass = '',
- $extraCols = [],
- $columnRemove = []
- )
- {
- $r = <<<'eot'
-
- * $code=$pdoOne->generateCodeClass({args});
- *
- * 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 = {def};
- if($column!==null) {
- if($filter===null) {
- foreach($r as $k=>$v) {
- $r[$k]=$v[$column];
+ // the "where" has parameters.
+ $stmt = $this->prepare($rawSql);
+ if ($stmt === false) {
+ $this->throwError("Unable to prepare statement", $rawSql);
+ return false;
+ }
+ $counter = 0;
+ if ($this->isAssoc($param)) {
+ $this->lastBindParam = $param;
+ // [':name'=>value,':name2'=>value2];
+ foreach ($param as $k => $v) {
+ // note: the second field is & so we could not use $v
+ $stmt->bindParam($k, $param[$k], $this->getType($v));
+ }
+ } else {
+ // parameters numeric
+ $this->lastBindParam = [];
+ $f = reset($param);
+ if (is_array($f)) {
+ // arrays of arrays.
+ // [[name1,value1,type1,l1],[name2,value2,type2,l1]]
+ foreach ($param as $k => $v) {
+ $this->lastBindParam[$counter] = $v[0];
+ // note: the second field is & so we could not use $v
+ $stmt->bindParam($v[0], $param[$k][1], $v[2], $v[3]);
}
} else {
- $new=[];
- foreach($r as $k=>$v) {
- if($v[$column]===$filter) {
- $new[]=$k;
- }
+ // [value1,value2]
+ foreach ($param as $i => $iValue) {
+ //$counter++;
+ //$typeP = $this->stringToPdoParam($param[$i]);
+ $this->lastBindParam[$i] = $param[$i];
+ //$stmt->bindParam($counter, $param[$i + 1], $typeP);
+ $stmt->bindParam($i + 1, $param[$i], $this->getType($param[$i]));
}
- 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;
+
+ if ($this->useCache !== false && $returnArray) {
+ $this->uid = hash($this->encryption->hashType, $this->lastQuery . serialize($this->lastBindParam));
+ $result = $this->cacheService->getCache($this->uid, $this->cacheFamily);
+ if ($result !== false) {
+ // it's found in the cache.
+ if (is_array($result)) {
+ $this->affected_rows = count($result);
+ } else {
+ $this->affected_rows = 0;
+ }
+ if ($uid !== false) {
+ $this->internalCache[$uid] = $result;
+ }
+ return $result;
+ }
+ } else {
+ $this->uid = null;
}
-{convertoutput}
-{linked}
- }
+ $this->runQuery($stmt);
- /**
- * 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) {
-{convertinput}
- }
+ if ($returnArray && $stmt instanceof PDOStatement) {
+ $rows = ($stmt->columnCount() > 0) ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
+ $this->affected_rows = $stmt->rowCount();
+ $stmt = null;
+ if ($uid !== false) {
+ $this->internalCache[$uid] = $rows;
+ }
+ return $rows;
+ }
+
+ if ($stmt instanceof PDOStatement) {
+ $this->affected_rows = $stmt->rowCount();
+ } else {
+ $this->affected_rows = 0;
+ }
+ return $stmt;
+ }
/**
- * It gets all the name of the columns.
+ * It returns the command (in lower case) or the type of command of a query
+ * Example:
+ *
+ * $this->queryCommand("select * from table") // returns "select"
+ * $this->queryCommand("select * from table",true) // returns "dql"
+ *
+ *
+ * @param string $sql
+ * @param false $returnType if true then it returns DML (insert/updat/delete/etc) or DQL (select/show/display)
+ *
+ * @return string
*
- * @return string[]
*/
- public static function getDefName() {
- return {defname};
+ public static function queryCommand($sql, $returnType = false)
+ {
+ if (!$sql) {
+ return $returnType ? 'dml' : 'dql';
+ }
+ $command = strtolower((explode(' ', trim($sql)))[0]);
+ if ($returnType) {
+ if ($command === 'select' || $command === 'show' || $command === 'display') {
+ return 'dql';
+ }
+ return 'dml';
+ }
+ return $command;
}
+ //
+
/**
- * It returns an associative array (colname=>key type) with all the keys/indexes (if any)
+ * It starts a transaction. If fails then it returns false, otherwise true.
*
- * @return string[]
+ * @return bool
+ * @test equals true,this()
+ * @posttest execution $this->pdoOne->commit();
+ * @example examples/testdb.php 92,4
*/
- public static function getDefKey() {
- return {defkey};
+ public function startTransaction()
+ {
+ if ($this->transactionOpen || !$this->isOpen) {
+ return false;
+ }
+ $this->transactionOpen = true;
+ $this->conn1->beginTransaction();
+
+ return true;
}
/**
- * It returns a string array with the name of the columns that are skipped when insert
- * @return string[]
+ * Commit and close a transaction.
+ *
+ * @param bool $throw if true and it fails then it throws an error.
+ *
+ * @return bool
+ * @throws Exception
+ * @test equals false,(false),'transaction is not open'
*/
- public static function getDefNoInsert() {
- return {defnoinsert};
+ public function commit($throw = true)
+ {
+ if (!$this->transactionOpen && $throw) {
+ $this->throwError('Transaction not open to commit()', '');
+
+ return false;
+ }
+ if (!$this->isOpen) {
+ $this->throwError("It's not connected to the database", '');
+
+ return false;
+ }
+ $this->transactionOpen = false;
+
+ return @$this->conn1->commit();
}
/**
- * It returns a string array with the name of the columns that are skipped when update
- * @return string[]
+ * Rollback and close a transaction
+ *
+ * @param bool $throw [optional] if true and it fails then it throws an error.
+ *
+ * @return bool
+ * @throws Exception
+ * @test equals false,(false),'transaction is not open'
*/
- public static function getDefNoUpdate() {
- return {defnoupdate};
+ public function rollback($throw = true)
+ {
+ if (!$this->transactionOpen && $throw) {
+ $this->throwError('Transaction not open to rollback()', '');
+ }
+ if (!$this->isOpen) {
+ $this->throwError("It's not connected to the database", '');
+
+ return false;
+ }
+ $this->transactionOpen = false;
+
+ return @$this->conn1->rollback();
}
+ //
+
/**
- * It adds a where to the query pipeline. It could be stacked with many where()
- * Example:
- *
- *
- * @param array|string $sql =self::factory()
- * @param null|array|int $param
+ * Internal Use: It runs a raw query
*
- * @return {classname}
+ * @param string $rawSql
+ * @param bool $returnArray
+ *
+ * @return array|bool|false|PDOStatement
+ * @throws Exception
+ * @see \eftec\PdoOne::runRawQuery
*/
- public static function where($sql, $param = PdoOne::NULL)
+ private function runRawQueryParamLess($rawSql, $returnArray)
{
- self::getPdoOne()->where($sql, $param,false,{classname}::TABLE);
- return {classname}::class;
- }
+ // the "where" chain doesn't have parameters.
+ try {
+ $rows = $this->conn1->query($rawSql);
+ if ($rows === false) {
+ throw new RuntimeException('Unable to run raw runRawQueryParamLess', 9001);
+ }
+ } catch (Exception $ex) {
+ $rows = false;
+ $this->throwError('Exception in runRawQueryParamLess :', $rawSql, ['param' => $this->lastParam], true, $ex);
+ }
- public static function getDefFK($structure=false) {
- if ($structure) {
- return {deffk};
+ if ($returnArray && $rows instanceof PDOStatement) {
+ if ($rows->columnCount() > 0) {
+ $result = @$rows->fetchAll(PDO::FETCH_ASSOC);
+ $this->affected_rows = $rows->rowCount();
+
+ return $result;
+ }
+
+ $this->affected_rows = $rows->rowCount();
+
+ return true;
}
- /* key,refcol,reftable,extra */
- return {deffktype};
+
+ $this->affected_rows = $rows->rowCount();
+
+ return $rows;
}
/**
- * 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]
+ * Prepare a query. It returns a mysqli statement.
*
- * @return string[]
- * @noinspection SlowArrayOperationsInLoopInspection
- */
- public static function getRelations($type='all') {
- $r= {deffktype2};
- if($type==='*') {
- $result=[];
- foreach($r as $arr) {
- $result = array_merge($result,$arr);
+ * @param string $statement A SQL statement.
+ *
+ * @return PDOStatement returns the statement if correct otherwise null
+ * @throws Exception
+ */
+ public function prepare($statement)
+ {
+ if (!$this->isOpen) {
+ $this->throwError("It's not connected to the database", '');
+
+ return null;
+ }
+ $this->lastQuery = $statement;
+ if ($this->readonly) {
+ if (stripos($statement, 'insert ') === 0 || stripos($statement, 'update ') === 0
+ || stripos($statement, 'delete ') === 0
+ ) {
+ // we aren't checking SQL-DCL queries.
+ $this->throwError('Database is in READ ONLY MODE', '');
}
- return $result;
}
- return isset($r[$type]) ? $r[$type] : [];
-
- }
-
- public static function toList($filter=PdoOne::NULL,$filterValue=null) {
- if(self::$useModel) {
- return {classmodellist}
+ if ($this->logLevel >= 2) {
+ $this->storeInfo($statement);
}
- return self::_toList($filter, $filterValue);
+
+ try {
+ $stmt = $this->conn1->prepare($statement);
+ } catch (Exception $ex) {
+ $stmt = false;
+ if ($this->errorText === '') {
+ $this->throwError('Failed to prepare', $ex->getMessage(), ['param' => $this->lastParam]);
+ }
+ }
+ if (($stmt === false) && $this->errorText === '') {
+ $this->throwError('Unable to prepare query', $this->lastQuery, ['param' => $this->lastParam]);
+ }
+
+ return $stmt;
}
-
+
/**
- * 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
+ * It returns true if the array is an associative array. False
+ * otherwise.
* 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)
+ * isAssoc(['a1'=>1,'a2'=>2]); // true
+ * isAssoc(['a1','a2']); // false
+ * isAssoc('aaa'); isAssoc(null); // false
*
- * @param string|array $recursive=self::factory();
+ * @param mixed $array
*
- * @return {classname}
+ * @return bool
*/
- public static function setRecursive($recursive=[])
+ private function isAssoc($array)
{
- if(is_string($recursive)) {
- $recursive={classname}::getRelations($recursive);
+ if ($array === null) {
+ return false;
+ }
+ if (!is_array($array)) {
+ return false;
}
- return parent::_setRecursive($recursive);
- }
- public static function limit($sql)
- {
- self::getPdoOne()->limit($sql);
- return {classname}::class;
+ return (array_values($array) !== $array);
}
+
+
+ //
+
/**
- * It returns the first row of a query.
- * @param array|mixed|null $pk [optional] Specify the value of the primary key.
+ * Convert date from unix timestamp -> ISO (database format).
+ *
Example: ::unixtime2Sql(1558656785); // returns 2019-05-24 00:13:05
*
- * @return array|bool It returns false if not file is found.
- * @throws Exception
+ * @param integer $dateNum
+ *
+ * @return string
*/
- public static function first($pk = PdoOne::NULL) {
- if(self::$useModel) {
- return {classmodelfirst}
- }
- return self::_first($pk);
+ public static function unixtime2Sql($dateNum)
+ {
+ // 31/01/2016 20:20:00 --> 2016-01-31 00:00
+ if ($dateNum === null) {
+ return self::$dateEpoch;
+ }
+
+ return date(self::$isoDateTimeMs, $dateNum);
}
/**
- * 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.
- *
+ * Convert date, from mysql date -> text (using a format pre-established)
*
- * @param array|mixed $entity =self::factory()
+ * @param string $sqlField
+ * @param bool $hasTime if true then the date contains time.
*
- * @return bool true if the pks exists
- * @throws Exception
+ * @return string Returns a text with the date formatted (human readable)
*/
- public static function exist($entity) {
- return self::_exist($entity);
+ public static function dateSql2Text($sqlField, $hasTime = false)
+ {
+ $tmpDate = self::dateTimeSql2PHP($sqlField, $hasTime);
+ if ($tmpDate === null) {
+ return null;
+ }
+ if ($hasTime) {
+ return $tmpDate->format((strpos($sqlField, '.') !== false) ? self::$dateTimeMicroHumanFormat
+ : self::$dateTimeHumanFormat);
+ }
+
+ return $tmpDate->format(self::$dateHumanFormat);
}
/**
- * 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
+ * Convert date, from mysql -> php
*
- * @return array|false=self::factory()
- * @throws Exception
+ * @param string $sqlField
+ * @param bool $hasTime
+ *
+ * @return bool|DateTime|null
*/
- public static function insert(&$entity,$transactional=true) {
- return self::_insert($entity,$transactional);
+ public static function dateTimeSql2PHP($sqlField, &$hasTime = false)
+ {
+ // 3 2016-01-31 00:00:00 -> 01/01/2016 00:00:00
+ // mysql always returns the date/datetime/timestmamp in ansi format.
+ if ($sqlField === '' || $sqlField === null) {
+ 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
+ // Y-m-d H:i:s.v
+ $hasTime = true;
+ //$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;
+ return DateTime::createFromFormat(self::$isoDateTime, $sqlField);
+ }
+ // only date
+ $hasTime = false;
+
+ return DateTime::createFromFormat(self::$isoDate, $sqlField);
}
-
+
/**
- * 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
+ * It converts a date (as string) into another format.
+ * Example:
+ *
+ * iso depends on the database.
+ * Example: Y-m-d H:i:s
+ * human is based in d/m/Y H:i:s but it could be changed (self::dateHumanFormat)
+ * sql depends on the database
+ * class is a DateTime() object
*
- * @return array|false=self::factory()
- * @throws Exception
+ * @param string $sqlField The date to convert
+ * @param string $inputFormat =['iso','human','sql','class','timestamp'][$i]
+ * @param string $outputFormat =['iso','human','sql','class','timestamp'][$i]
+ * @param null|string $force =[null,'time','ms','none'][$i] It forces if the result gets time or
+ * microseconds
+ * null = no force the result (it is calculated automatically)
+ * time = returns with a precision of seconds
+ * ms = returns with a precision of microseconds
+ * none = it never returns any time
+ *
+ * @return bool|DateTime
*/
- public static function merge(&$entity,$transactional=true) {
- return self::_merge($entity,$transactional);
+ public static function dateConvert($sqlField, $inputFormat, $outputFormat, $force = null)
+ {
+ /** @var boolean $ms if true then the value has microseconds */
+ $ms = false;
+ /** @var boolean $time if true then the value has time */
+ $time = false;
+ $tmpDate=self::dateConvertInput($sqlField,$inputFormat,$ms,$time);
+ if (!$tmpDate) {
+ return false;
+ }
+ if ($force !== null) {
+ if ($force === 'ms') {
+ $ms = true;
+ } elseif ($force === 'time') {
+ $time = true;
+ $ms = false;
+ } elseif ($force === 'none') {
+ $time = false;
+ $ms = false;
+ }
+ }
+ switch ($outputFormat) {
+ case 'iso':
+ if ($ms) {
+ return $tmpDate->format(self::$dateTimeMicroFormat);
+ }
+ if ($time) {
+ return $tmpDate->format(self::$dateTimeFormat);
+ }
+ return $tmpDate->format(self::$dateFormat);
+ case 'human':
+ if ($ms) {
+ return $tmpDate->format(self::$dateTimeMicroHumanFormat);
+ }
+ if ($time) {
+ return $tmpDate->format(self::$dateTimeHumanFormat);
+ }
+
+ return $tmpDate->format(self::$dateHumanFormat);
+ case 'sql':
+ if ($ms) {
+ return $tmpDate->format(self::$isoDateInputTimeMs);
+ }
+ if ($time) {
+ return $tmpDate->format(self::$isoDateInputTime);
+ }
+
+ return $tmpDate->format(self::$isoDateInput);
+ case 'class':
+ return $tmpDate;
+ case 'timestamp':
+ return $tmpDate->getTimestamp();
+ }
+ return false;
}
/**
- * @param array|object $entity =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
+ * It converts a date and time value (expressed in different means) into a DateTime object or false if the operation
+ * fails.
+ * Example:
+ *
+ * $r=PdoOne::dateConvertInput('01/12/2020','human',$ms,$time); // it depends on the fields self::$date*HumanFormat
+ * $r=PdoOne::dateConvertInput('2020-12-01','iso',$ms,$time); // it depends on the fields self::$date*Format
+ * $r=PdoOne::dateConvertInput('2020-12-01','sql',$ms,$time); // it depends on the database
+ * $r=PdoOne::dateConvertInput(50000,'timestamp',$ms,$time); // a timestamp
+ * $r=PdoOne::dateConvertInput(new DateTime(),'class',$ms,$time); // a DateTime object (it keeps the same one)
+ *
*
- * @return array|false=self::factory()
- * @throws Exception
+ * @param mixed $inputValue the input value.
+ * @param string $inputFormat =['iso','human','sql','class','timestamp'][$i] The input format
+ * @param boolean $ms [ref] It returns if it includes microseconds
+ * @param boolean $time [ref] It returns if it includes time
+ * @return DateTime|false false if the operation fails
+ * @noinspection PhpUnhandledExceptionInspection
+ * @noinspection PhpDocMissingThrowsInspection
*/
- public static function update($entity,$transactional=true) {
- return self::_update($entity,$transactional);
+ public static function dateConvertInput($inputValue, $inputFormat, &$ms, &$time) {
+ switch ($inputFormat) {
+ case 'iso':
+ if (strpos($inputValue, '.') !== false) {
+ $ms = true;
+ $tmpDate = DateTime::createFromFormat(self::$dateTimeMicroFormat, $inputValue);
+ } elseif (strpos($inputValue, ':') !== false) {
+ $time = true;
+ $tmpDate = DateTime::createFromFormat(self::$dateTimeFormat, $inputValue);
+ } else {
+ $tmpDate = DateTime::createFromFormat(self::$dateFormat, $inputValue);
+ if ($tmpDate === false) {
+ return false;
+ }
+ $tmpDate->setTime(0, 0);
+ }
+ break;
+ case 'human':
+ if (strpos($inputValue, '.') !== false) {
+ $ms = true;
+ $tmpDate = DateTime::createFromFormat(self::$dateTimeMicroHumanFormat, $inputValue);
+ } elseif (strpos($inputValue, ':') !== false) {
+ $time = true;
+ $tmpDate = DateTime::createFromFormat(self::$dateTimeHumanFormat, $inputValue);
+ } else {
+ $tmpDate = DateTime::createFromFormat(self::$dateHumanFormat, $inputValue);
+
+ if ($tmpDate === false) {
+ return false;
+ }
+ $tmpDate->setTime(0, 0);
+ }
+ break;
+ case 'sql':
+ if (strpos($inputValue, '.') !== false) {
+ $ms = true;
+ $tmpDate = DateTime::createFromFormat(self::$isoDateTimeMs, $inputValue);
+ } elseif (strpos($inputValue, ':') !== false) {
+ $time = true;
+ $tmpDate = DateTime::createFromFormat(self::$isoDateTime, $inputValue);
+ } else {
+ $tmpDate = DateTime::createFromFormat(self::$isoDate, $inputValue);
+ $tmpDate->setTime(0, 0);
+ }
+ break;
+ case 'class':
+ if(is_array($inputValue)) {
+ // sometimes we have a DateTime class but it is converted into an array. We fixed this problem.
+ $inputValue=new DateTime($inputValue['date']);
+ }
+ /** @var DateTime $tmpDate */
+ $tmpDate = $inputValue;
+ $time = $tmpDate->format('Gis') !== '000000';
+ break;
+ case 'timestamp':
+ $tmpDate = new DateTime();
+ $tmpDate->setTimestamp($inputValue);
+ $time = $tmpDate->format('Gis') !== '000000';
+ $ms = fmod($inputValue, 1) !== 0.0;
+ break;
+ default:
+ $tmpDate = false;
+ trigger_error('PdoOne: dateConvert type not defined');
+ }
+ return $tmpDate;
}
/**
- * It deletes an entity by the primary key
+ * Convert date, from text -> mysql (using a format pre-established)
*
- * @param array|object $entity =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
+ * @param string $textDate Input date
+ * @param bool $hasTime If true then it works with date and time
+ * (instead of date)
*
- * @return mixed
- * @throws Exception
+ * @return string
*/
- public static function delete($entity,$transactional=true) {
- return self::_delete($entity,$transactional);
+ public static function dateText2Sql($textDate, $hasTime = true)
+ {
+ if (($hasTime)) {
+ $tmpFormat = strpos($textDate, '.') === false ? self::$dateTimeFormat : self::$dateTimeMicroFormat;
+ } 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.
}
/**
- * It deletes an entity by the primary key.
+ * Conver date from php -> mysql
+ * It always returns a time (00:00:00 if time is empty). it could returns
+ * microseconds 2010-01-01 00:00:00.00000
*
- * @param array $pk =self::factory()
- * @param bool $transactional If true (default) then the operation is transactional
+ * @param DateTime $date
*
- * @return mixed
- * @throws Exception
+ * @return string
*/
- public static function deleteById($pk,$transactional=true) {
- return self::_deleteById($pk,$transactional);
+ public static function dateTimePHP2Sql($date)
+ {
+ // 31/01/2016 20:20:00 --> 2016-01-31 00:00
+ if ($date == null) {
+ return self::$dateEpoch;
+ }
+ if ($date->format('u') !== '000000') {
+ return $date->format(self::$isoDateTimeMs);
+ }
+
+ return $date->format(self::$isoDateTime);
}
-
+
/**
- * Returns an array with the default values (0 for numbers, empty for string, and array|null if recursive)
+ * Returns the current date(and time) in Text (human) format. Usually, it is d/m/Y H:i:s
*
- * @param array|null $values =self::factory()
- * @param string $recursivePrefix It is the prefix of the recursivity.
+ * @param bool $hasTime
+ * @param bool $hasMicroseconds
*
- * @return array
+ * @return string
+ * @throws Exception
+ * @see PdoOne::$dateTimeFormat
*/
- public static function factory($values = null, $recursivePrefix = '') {
- $recursive=static::getRecursive();
- static::setRecursive(); // reset the recursivity.
- $row= {array};
-{linked}
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
+ public static function dateTextNow(
+ $hasTime = true,
+ $hasMicroseconds = false
+ )
+ {
+ $tmpDate = new DateTime();
+ if ($hasTime) {
+ return $tmpDate->format(($hasMicroseconds !== false) ? self::$dateTimeMicroHumanFormat
+ : self::$dateTimeHumanFormat);
+ }
+ return $tmpDate->format(self::$dateHumanFormat);
}
-
+
/**
- * It returns an empty array with null values and no recursivity.
- * @param array|null $values=self::factoryNull()
- *
- * @return array
+ * Returns the current (PHP server) date and time in the regular format. (Y-m-d\TH:i:s\Z in long format)
+ *
+ * @param bool $hasTime
+ * @param bool $hasMicroseconds
+ *
+ * @return string
+ * @throws Exception
+ * @see PdoOne::$dateTimeFormat
*/
- public static function factoryNull($values=null) {
- $row= {array_null};
- if ($values !== null) {
- $row = array_merge($row, $values);
- }
- return $row;
+ public static function dateNow(
+ $hasTime = true,
+ $hasMicroseconds = false
+ )
+ {
+ $tmpDate = new DateTime();
+ if ($hasTime) {
+ return $tmpDate->format(($hasMicroseconds !== false) ? self::$dateTimeMicroFormat : self::$dateTimeFormat);
+ }
+ return $tmpDate->format(self::$dateFormat);
}
-}
-eot;
- $lastns = explode('\\', $namespace);
-
- if ($modelfullClass) {
- $arr = explode('\\', $modelfullClass);
- $modelClass = end($arr);
- $modelUse = true;
- } else {
- $modelClass = false;
- $modelUse = false;
+ /**
+ * Returns the current date(and time) in SQL/ISO format. It depends on the type of database.
+ *
+ * @param bool $hasTime
+ * @param bool $hasMicroseconds
+ *
+ * @return string
+ */
+ public static function dateSqlNow($hasTime = true, $hasMicroseconds = false)
+ {
+ $tmpDate = new DateTime();
+ if ($hasTime) {
+ return $tmpDate->format(($hasMicroseconds !== false) ? self::$isoDateTimeMs : self::$isoDateTime);
}
- $baseClass = ($baseClass === null) ? end($lastns) : $baseClass;
+ return $tmpDate->format(self::$isoDate);
+ }
- $fa = func_get_args();
- foreach ($fa as $f => $k) {
- if (is_array($k)) {
- $fa[$f] = str_replace([' ', "\r\n", "\n"], ['', '', ''], var_export($k, true));
- } else {
- $fa[$f] = "'$k'";
- }
- }
- if ($classRelations === null || !isset($classRelations[$tableName])) {
- $className = self::camelize($tableName);
- } else {
- $className = $classRelations[$tableName];
- }
+ public static function isCli()
+ {
+ return !http_response_code();
+ }
- $extraColArray = '';
- foreach ($extraCols as $k => $v) {
- $extraColArray .= $v . ' as ' . $this->addQuote($k) . ',';
- }
- $extraColArray = rtrim($extraColArray, ',');
+ //
- $r = str_replace(array(
- '{version}',
- '{classname}',
- '{exception}',
- '{baseclass}',
- '{args}',
- '{table}',
- '{compiled}',
- '{namespace}',
- '{modelnamespace}',
- '{classmodellist}',
- '{classmodelfirst}',
- '{extracol}'
- ), array(
- self::VERSION . ' Date generated ' . date('r'), //{version}
- $className, // {classname}
- ($namespace) ? 'use Exception;' : '',
- $baseClass, // {baseclass}
- implode(",", $fa),
- $tableName, // {table}
- _BasePdoOneRepo::BINARYVERSION, // {compiled}
- ($namespace) ? "namespace $namespace;" : '', //{namespace}
- $modelUse ? "use $modelfullClass;" : '', // {modelnamespace}
- $modelUse ? "$modelClass::fromArrayMultiple( self::_toList(\$filter, \$filterValue));"
- : 'false; // no model set', // {classmodellist}
- $modelUse ? "$modelClass::fromArray(self::_first(\$pk));" : 'false; // no model set' // {classmodelfirst}
- ,
- $extraColArray // {extracol}
- ), $r);
- $pk = '??';
- $pk = $this->service->getPK($tableName, $pk);
- $pkFirst = (is_array($pk) && count($pk) > 0) ? $pk[0] : null;
+ /**
+ * @param mixed $v Variable
+ *
+ * @return int=[PDO::PARAM_STR,PDO::PARAM_INT,PDO::PARAM_BOOL][$i]
+ * @test equals PDO::PARAM_STR,(20.3)
+ * @test equals PDO::PARAM_STR,('hello')
+ */
+ public function getType(&$v)
+ {
+ switch (1) {
+ case (is_float($v)):
+ case ($v === null):
+ $vt = PDO::PARAM_STR;
+ break;
+ case (is_numeric($v)):
+ $vt = PDO::PARAM_INT;
+ break;
+ case (is_bool($v)):
- try {
- $relation = $this->getDefTableFK($tableName, false, true);
- } catch (Exception $e) {
- return 'Error: Unable read fk of table ' . $e->getMessage();
+ $vt = PDO::PARAM_INT;
+ $v = ($v) ? 1 : 0;
+ break;
+ case (is_object($v) && $v instanceof DateTime):
+ $vt = PDO::PARAM_STR;
+ $v = self::dateTimePHP2Sql($v);
+ break;
+ default:
+ $vt = PDO::PARAM_STR;
}
- // many to many
- /*foreach ($relation as $rel) {
- $tableMxM = $rel['reftable'];
- $tableFK = $this->getDefTableFK($tableMxM, false, true);
+ return $vt;
+ }
+
+ /**
+ * Run a prepared statement.
+ * Example:
+ * $con->runQuery($con->prepare('select * from table'));
+ *
+ * @param PDOStatement $stmt PDOStatement
+ * @param array|null $namedArgument (optional)
+ *
+ * @param bool $throwError (default true) if false, then it won't throw an error but it will store the error
+ *
+ * @return bool returns true if the operation is correct, otherwise false
+ * @throws Exception
+ * @test equals true,$this->pdoOne->runQuery($this->pdoOne->prepare('select
+ * 1 from dual'))
+ * @test equals
+ * [1=>1],$this->pdoOne->select('1')->from('dual')->first(),'it
+ * must runs'
+ */
+ public function runQuery($stmt, $namedArgument = null, $throwError = true)
+ {
+ if (!$this->isOpen) {
+ $this->throwError("It's not connected to the database", '', $throwError);
+ return null;
}
- */
try {
- $deps = $this->tableDependency(true);
- } catch (Exception $e) {
- 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)];
+ //$namedArgument = ($namedArgument === null)
+ // ? array_merge($this->setParamAssoc,$this->whereParamAssoc,$this->havingParamAssoc) : $namedArgument;
+ $r = $stmt->execute($namedArgument);
+ } catch (Exception $ex) {
+ $this->throwError($this->databaseType . ':Failed to run query', $this->lastQuery,
+ ['param' => $this->lastParam, 'error_last' => json_encode(error_get_last())], $throwError, $ex);
+ return false;
}
- 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)
- ];
- }
- }
+ if ($r === false) {
+ $this->throwError('Exception query ', $this->lastQuery, ['param' => $this->lastParam], $throwError);
+ return false;
}
- // 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);
- }
- }
- }
- if ($columnRelations) {
- foreach ($relation as $k => $rel) {
- if (isset($columnRelations[$k])) {
- // parent.
- if ($columnRelations[$k] === 'PARENT') {
- $relation[$k]['key'] = 'PARENT';
- } elseif ($columnRelations[$k] === 'MANYTOMANY') {
- // the table must has 2 primary keys.
- $pks = null;
- $pks = $this->service->getPK($relation[$k]['reftable'], $pks);
- /** @noinspection PhpParamsInspection */
- 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) {
- return 'Error: Unable read table dependencies ' . $e->getMessage();
- }
- try {
- $keys2 = $this->service->getDefTableKeys($defsFK[$refcol2]['reftable'], true,
- 'PRIMARY KEY');
- } catch (Exception $e) {
- return 'Error: Unable read table dependencies' . $e->getMessage();
- }
- $relation[$k]['refcol2'] = self::$prefixBase . $refcol2;
- if (is_array($keys2)) {
- $keys2 = array_keys($keys2);
- $relation[$k]['col2'] = $keys2[0];
- } else {
- $relation[$k]['col2'] = null;
- }
- $relation[$k]['table2'] = $defsFK[$refcol2]['reftable'];
- }
- }
- // manytomany
- }
- }
- }
- //die(1);
- $convertOutput = '';
- $convertInput = '';
- $getDefTable = $this->getDefTable($tableName, $specialConversion);
+ return true;
+ }
- foreach ($columnRemove as $v) {
- unset($getDefTable[$v]);
+ protected static function fixCsv($value)
+ {
+ if (is_numeric($value)) {
+ return $value;
}
- //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 = isset($colDef['type']) ? $colDef['type'] : null;
- $conversion = null;
- if (isset($columnRelations[$kcol])) {
- $conversion = $columnRelations[$kcol];
- if ($type !== null) {
- $getDefTable[$kcol]['conversion'] = $conversion;
- } else {
- $type = 'new column';
- }
- } elseif ($type !== null && isset($this->codeClassConversion[$type])
- && $getDefTable[$kcol]['conversion'] === null
- ) {
- $conversion = $this->codeClassConversion[$type];
- $getDefTable[$kcol]['conversion'] = $conversion;
- }
+ $value = str_replace('"', '""', $value);
- if ($conversion !== null) {
- if (is_array($conversion)) {
- list($input, $output) = $conversion;
- } else {
- $input = $conversion;
- $output = $input;
- }
+ return '"' . $value . '"';
+ }
- switch ($input) {
- case 'encrypt':
- $tmp2 = "isset(%s) and %s=self::getPdoOne()->encrypt(%s);";
- break;
- case 'decrypt':
- $tmp2 = "isset(%s) and %s=self::getPdoOne()->decrypt(%s);";
- break;
- case 'datetime3':
- $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'human', 'sql');";
- break;
- case 'datetime4':
- $tmp2='';
- //$tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'sql', 'sql');";
- break;
- case 'datetime2':
- $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'iso', 'sql');";
- break;
- case 'datetime':
- $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'class', 'sql');";
- break;
- case 'timestamp':
- $tmp2 = "isset(%s) and %s=PdoOne::dateConvert(%s, 'timestamp', 'sql')";
- break;
- case 'bool':
- $tmp2 = "isset(%s) and %s=(%s) ? 1 : 0;";
- break;
- case 'int':
- $tmp2 = "isset(%s) and %s=(int)%s;";
- break;
- case 'float':
- case 'decimal':
- $tmp2 = "isset(%s) and %s=(float)%s;";
- break;
- default:
- if (strpos($input, '%s') !== false) {
- $tmp2 = "%s=isset(%s) ? " . $input . " : null;";
- } else {
- $tmp2 = '// type ' . $input . ' not defined';
- }
- }
- switch ($output) {
- case 'encrypt':
- $tmp = "%s=isset(%s) ? self::getPdoOne()->encrypt(%s) : null;";
- break;
- case 'decrypt':
- $tmp = "%s=isset(%s) ? self::getPdoOne()->decrypt(%s) : null;";
- break;
- case 'datetime3':
- $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'human') : null;";
- break;
- case 'datetime4':
- // sql->sql no conversion
- $tmp = '';
- break;
- case 'datetime2':
- $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'iso') : null;";
- break;
- case 'datetime':
- $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'class') : null;";
- break;
- case 'timestamp':
- $tmp = "%s=isset(%s) ? PdoOne::dateConvert(%s, 'sql', 'timestamp') : null;";
- break;
- case 'bool':
- $tmp = "%s=isset(%s) ? (%s) ? true : false : null;";
- break;
- case 'int':
- $tmp = "%s=isset(%s) ? (int)%s : null;";
- break;
- case 'float':
- case 'decimal':
- $tmp = "%s=isset(%s) ? (float)%s : null;";
- break;
- case null:
- $tmp = "!isset(%s) and %s=null; // no conversion";
- break;
- default:
- if (strpos($output, '%s') !== false) {
- $tmp = "%s=isset(%s) ? " . $output . " : null;";
- } else {
- $tmp = '// type ' . $output . ' not defined';
- }
- }
+ /**
+ * @param string $query
+ *
+ * @return string
+ * @throws Exception
+ */
+ public function generateCodeSelect($query)
+ {
+ $q = self::splitQuery($query);
+ $code = '/** @var array $result=array(' . $this->generateCodeArray($query, $query) . ') */' . "\n";
- if ($tmp !== '') {
- $convertOutput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp) . "\n";
- $convertInput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp2) . "\n";
+ $code .= '$result=$pdo' . "\n";
+ foreach ($q as $k => $v) {
+ if ($v !== null) {
+ $k2 = str_replace(' by', '', $k); // order by -> order
+ foreach ($v as $vitem) {
+ $code .= "\t->{$k2}(\"{$vitem}\")\n";
}
- } else {
- $tmp = "!isset(%s) and %s=null; // $type";
- $convertOutput .= "\t\t" . str_replace('%s', "\$row['$kcol']", $tmp) . "\n";
- }
- }
-
- $linked = '';
- foreach ($relation as $k => $v) {
- $key = $v['key'];
- if ($key === 'MANYTOONE') {
- //$col = ltrim($v['refcol'], '_');
- $col = ltrim($k, '_');
- $linked .= str_replace(['{_col}', '{refcol}', '{col}'], [$k, $v['refcol'], $col], "\t\tisset(\$row['{_col}'])
- and \$row['{_col}']['{refcol}']=&\$row['{col}']; // linked MANYTOONE\n");
}
- if ($key === 'ONETOONE') {
- //$col = ltrim($v['refcol'], '_');
- //$col = ltrim($k, '_');
- $linked .= str_replace(['{_col}', '{refcol}', '{col}'], [$k, $v['refcol'], $v['col']], "\t\tisset(\$row['{_col}'])
- and \$row['{_col}']['{refcol}']=&\$row['{col}']; // linked ONETOONE\n");
- }
- }
- //$convertOutput.=$linked;
-
- $convertOutput = rtrim($convertOutput, "\n");
- $convertInput = rtrim($convertInput, "\n");
-
- // discard columns
- //$identities=$this->getDefTableKeys($tableName,);
- $identities = $this->getDefIdentities($tableName);
- if (count($identities) > 0) {
- $identity = $identities[0];
- } else {
- $identity = null;
- }
- if ($defNoInsert !== null) {
- $noInsert = array_merge($identities, $defNoInsert);
- } else {
- $noInsert = $identities;
- }
- if ($defNoUpdate !== null) {
- $noUpdate = array_merge($identities, $defNoUpdate);
- } else {
- $noUpdate = array_merge($identities);
- }
- if ($pk) {
- // we never update the primary key.
- /** @noinspection AdditionOperationOnArraysInspection */
- $noUpdate += $pk; // it adds and replaces duplicates, indexes are ignored.
}
+ $code .= "\t->toList();\n";
- $relation2 = [];
- foreach ($relation as $col => $arr) {
- if ($arr['key'] !== 'FOREIGN KEY' && $arr['key'] !== 'PARENT' && $arr['key'] !== 'NONE') {
- @$relation2[$arr['key']][] = $col;
- }
- //if($arr['key']==='MANYTOONE') {
- // $relation2[]=$col;
- // }
- }
-
- try {
- $r = str_replace(array(
- '{pk}',
- '{identity}',
- '{def}',
- '{convertoutput}',
- '{convertinput}',
- '{defname}',
- '{defkey}',
- '{defnoinsert}',
- '{defnoupdate}',
- '{deffk}',
- '{deffktype}',
- '{deffktype2}',
- '{array}',
- '{array_null}',
- '{linked}'
- ), array(
- self::varExport($pk),
- self::varExport($identity), // {identity}
- //str_replace(["\n\t\t ", "\n\t\t ],"], ['', '],'], self::varExport($gdf, "\t\t")), // {def}
- self::varExport($getDefTable, "\t\t"), // {def}
- $convertOutput, // {convertoutput}
- $convertInput, // {convertinput}
- self::varExport(array_keys($getDefTable), "\t\t"), // {defname}
- self::varExport($this->getDefTableKeys($tableName), "\t\t"), // {defkey}
- self::varExport($noInsert, "\t\t"), // {defnoinsert}
- self::varExport($noUpdate, "\t\t"), // {defnoupdate}
- self::varExport($this->getDefTableFK($tableName), "\t\t\t"), //{deffk}
- self::varExport($relation, "\t\t"), //{deffktype}
- self::varExport($relation2, "\t\t"), //{deffktype2}
- str_replace("\n", "\n\t\t",
- rtrim($this->generateCodeArray($tableName, null, false, false, true, $classRelations, $relation),
- "\n")),
- str_replace("\n", "\n\t\t",
- rtrim($this->generateCodeArray($tableName, null, true, false, true, $classRelations, $relation),
- "\n")),
- $linked // {linked}
- ), $r);
- } catch (Exception $e) {
- return "Unable read definition of tables " . $e->getMessage();
- }
-
- return $r;
+ return $code;
}
-
/**
- * It returns a field, column or table, the quotes defined by the current database type. It doesn't considers points
- * or space
+ * It sets conversions depending of the type of data. This method is used together with generateCodeClassAll().
+ * This value persists across calls
+ * For example, if we always want to convert tinyint into boolean, then we could use this function
+ * , instead of specify per each column.
+ * Example:
*
- * $this->pdoOne->select('*')->from('missintable')->setNoReset(true)->toList();
- * // we do something with the stack
- * $this->pdoOne->builderReset(true); // reset the stack manually
- *
- *
- * @param bool $noReset
- *
- * @return $this
- */
- public function setNoReset($noReset = true)
- {
- $this->noReset = $noReset;
- return $this;
- }
-
- /**
- * It returns an uniqued uid ('sha256' or the value defined in PdoOneEncryption::$hashType) based in all the
- * parameters of the query (select,from,where,parameters,group,recursive,having,limit,distinct,order,etc.) and
- * optionally in an extra value
- *
- * @param mixed|null $extra [optional] If we want to add an extra value to the UID generated
- * @param string $prefix A prefix added to the UNID generated.
- *
- * @return string
- * @see \eftec\PdoOneEncryption::$hashType
- */
- public function buildUniqueID($extra = null, $prefix = '')
- {
- // set and setparam are not counted
- $all = [
- $this->select,
- $this->from,
- $this->where,
- $this->whereParamAssoc,
- $this->havingParamAssoc,
- // $this->setParamAssoc,
- //$this->whereParamValue,
- $this->group,
- $this->recursive,
- $this->having,
- $this->limit,
- $this->distinct,
- $this->order,
- $extra
- ];
- return $prefix . hash($this->encryption->hashType, json_encode($all));
- }
-
- /**
- * It sets conversions depending of the type of data. This method is used together with generateCodeClassAll().
- * This value persists across calls
- * For example, if we always want to convert tinyint into boolean, then we could use this function
- * , instead of specify per each column.
- * Example:
- *
- * $this->generateCodeClassConversions(
- * ['datetime'=>'datetime2'
- * ,'tinyint'=>'bool' // converts tinyint as boolean
- * ,'int'=['int',null] // converts input int as integer, and doesn't convert output int
- * ]);
- * echo $this->generateCodeClassAll('table');
- * $this->generateCodeClassConversions(); // reset.
- *
- * PHP Conversions:
- *
- *
encrypt (encrypt value. Encryption must be set)
- *
decrypt (decrypt a value if can. Encryption must be set)
- *
datetime4 (sql string, no conversion). input (2020-12-30) --> db (2020-12-30) ---> output (30/12/2010)
-
-
-
-TEM1;
-
- $database = @$_POST['database'];
- $server = @$_POST['server'];
- $user = @$_POST['user'];
- $pwd = @$_POST['pwd'];
- $db = @$_POST['db'];
- $input = @$_POST['input'];
- $output = @$_POST['output'];
- $namespace = @$_POST['namespace'];
- $button = @$_POST['button'];
- $log = '';
- if ($button) {
- try {
- $log = $this->run($database, $server, $user, $pwd, $db, $input, $output, $namespace);
- } catch (Exception $e) {
- $log = $e->getMessage();
- }
- }
-
- $web = str_replace('{{version}}', $this::VERSION, $web);
- $valid = ['mysql', 'sqlsrv', 'oci'];
+ }
- $web = str_replace(array('{{database}}', '{{server}}', '{{user}}', '{{pwd}}', '{{db}}', '{{input}}'),
- array($this->runUtilCombo($valid, $database), $server, $user, $pwd, $db, $input), $web);
- $valid = [
- 'classcode',
- 'selectcode',
- 'createcode',
- 'arraycode',
- 'csv',
- 'json',
- ];
- $web = str_replace(array('{{output}}', '{{namespace}}', '{{log}}'),
- array($this->runUtilCombo($valid, $output), $namespace, $log), $web);
+ $used[] = $name;
+ }
+ $result .= ']' . $ln;
+ $result = str_replace(",$ln]", "$ln]", $result);
+ return $result;
+ }
- $ms = 1;
- $web = str_replace('{{ms}}', $ms, $web);
- echo $web;
+ /**
+ * It returns a simple array with all the columns that has identities/sequence.
+ *
+ * @param string $table
+ *
+ * @return array
+ * @throws Exception
+ */
+ public function getDefIdentities($table)
+ {
+ $r = $this->service->getDefTable($table);
+ $identities = [];
+ foreach ($r as $k => $v) {
+ if (stripos($v, $this->database_identityName) !== false) {
+ $identities[] = $k;
+ }
}
+ return $identities;
}
+
- public function bootstrapcss()
+
+ /**
+ * Begin a try block. It marks the erroText as empty and it store the value of genError
+ */
+ public function beginTry()
{
- return <<
-html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],.input-group-sm input[type=time],input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],.input-group-lg input[type=time],input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.in{opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;opacity:0;line-break:auto}.tooltip.in{opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
-
-BOOTS;
+ $this->errorText = '';
+ $this->isThrow = $this->genError; // this value is deleted when it trigger an error
+ $this->throwOnErrorB = $this->throwOnError;
+ $this->throwOnError = false;
}
+ //
+
+ //
+
+
+ //
+ //
- private function runUtilCombo($array, $select)
- {
- $r = '';
- foreach ($array as $item) {
- /** @noinspection TypeUnsafeComparisonInspection */
- $r .= "";
- }
- return $r;
- }
/**
- * It changes default database, schema or user.
+ * It sets the cache service (optional).
*
- * @param $dbName
+ * @param IPdoOneCache $cacheService Instance of an object that implements IPdoOneCache
*
- * @test void this('travisdb')
+ * @return $this
*/
- public function db($dbName)
+ public function setCacheService($cacheService)
{
- if (!$this->isOpen) {
- return;
- }
- $this->db = $dbName;
- $this->tableDependencyArray = null;
- $this->tableDependencyArrayCol = null;
- $this->conn1->exec('use ' . $dbName);
+ $this->cacheService = $cacheService;
+ return $this;
}
/**
- * returns if the database is in read-only mode or not.
+ * It stores a cache. This method is used internally by PdoOne.
*
- * @return bool
- * @test equals false,this(),'the database is read only'
+ * @param string $uid The unique id. It is generate by sha256 based in the query, parameters, type of query
+ * and method.
+ * @param string|string[] $family [optional] It is the family or group of the cache. It could be used to invalidate
+ * the whole group. For example, to invalidate all the cache related with a table.
+ * @param mixed|null $data The data to store
+ * @param null|bool|int $ttl If null then the cache never expires.
+ * If false then we don't use cache.
+ * If int then it is the duration of the cache (in seconds)
+ *
+ * @return void.
*/
- public function readonly()
+ public function setCache($uid, $family = '', $data = null, $ttl = null)
{
- return $this->readonly;
+ if ($family === '*') {
+ $family = $this->tables;
+ }
+ $this->cacheService->setCache($uid, $family, $data, $ttl);
}
/**
- * Alias of PdoOne::connect()
+ * Invalidate a single cache or a list of cache based in a single uid or in
+ * a family/group of cache.
*
- * @param bool $failIfConnected
+ * @param string|string[] $uid The unique id. It is generate by sha256 (or by $hashtype)
+ * based in the query, parameters, type
+ * of query and method.
+ * @param string|string[] $family [optional] It is the family or group
+ * of
+ * the cache. It could be used to
+ * invalidate the whole group. For
+ * example, to invalidate all the cache
+ * related with a table.
*
- * @throws Exception
- * @test exception this(false)
- * @see PdoOne::connect()
+ * @return $this
+ * @see \eftec\PdoOneEncryption::$hashType
*/
- public function open($failIfConnected = true)
+ public function invalidateCache($uid = '', $family = '')
{
- $this->connect($failIfConnected);
+ if ($this->cacheService !== null) {
+ if ($family === '*') {
+ $family = $this->tables;
+ }
+ $this->cacheService->invalidateCache($uid, $family);
+ }
+ return $this;
}
+
+ //
+ //
+
/**
- * It closes the connection
+ * Returns the number of affected rows.
*
- * @test void this()
+ * @param PDOStatement|null|bool $stmt
+ *
+ * @return mixed
*/
- public function close()
+ public function affected_rows($stmt = null)
{
- $this->isOpen = false;
- if ($this->conn1 === null) {
- return;
- } // its already close
-
- @$this->conn1 = null;
- }
-
- public function getPK($table,$pkDefault=null) {
- return $this->service->getPK($table,$pkDefault);
+ if ($stmt instanceof PDOStatement && !$this->isOpen) {
+ return $stmt->rowCount();
+ }
+ return $this->affected_rows; // returns previous calculated information
}
/**
- * It returns the next sequence.
- * It gets a collision free number if we don't do more than one operation
- * every 0.0001 seconds.
- * But, if we do 2 or more operations per seconds then, it adds a sequence
- * number from
- * 0 to 4095
- * So, the limit of this function is 4096 operations per 0.0001 second.
- *
- * @see \eftec\PdoOne::getSequencePHP It's the same but it uses less
- * resources but lacks of a sequence.
+ * Returns the last inserted identity.
*
- * @param bool $asFloat
- * @param bool $unpredictable
- * @param string $sequenceName (optional) the name of the sequence. If
- * not then it uses $this->tableSequence
+ * @param null|string $sequenceName [optional] the name of the sequence
*
- * @return string . Example string(19) "3639032938181434317"
- * @throws Exception
+ * @return mixed a number or 0 if it is not found
*/
- public function getSequence(
- $asFloat = false,
- $unpredictable = false,
- $sequenceName = ''
- )
+ public function insert_id($sequenceName = null)
{
- $sql = $this->service->getSequence($sequenceName);
- $r = $this->runRawQuery($sql);
- if ($unpredictable) {
- if (PHP_INT_SIZE === 4) {
- return $this->encryption->encryptSimple($r[0]['id']);
- }
-
-// $r is always a 32 bit number so it will fail in PHP 32bits
- return $this->encryption->encryptInteger($r[0]['id']);
- }
- if ($asFloat) {
- return (float)$r[0]['id'];
+ if (!$this->isOpen) {
+ return -1;
}
- return $r[0]['id'];
+ return $this->conn1->lastInsertId($sequenceName);
}
/**
- *
This function returns an unique sequence
- * It ensures a collision free number only if we don't do more than one
- * operation per 0.0001 second However,it also adds a pseudo random number
- * (0-4095) so the chances of collision is 1/4095 (per two operations done
- * every 0.0001 second). It is based on Twitter's Snowflake number
- *
- * @param bool $unpredictable
- *
- * @return float
- * @see \eftec\PdoOne::getSequence
+ * @return IPdoOneCache
*/
- public function getSequencePHP($unpredictable = false)
+ public function getCacheService()
{
- $ms = microtime(true);
- //$ms=1000;
- $timestamp = (double)round($ms * 1000);
- $rand = (fmod($ms, 1) * 1000000) % 4096; // 4096= 2^12 It is the millionth of seconds
- $calc = (($timestamp - 1459440000000) << 22) + ($this->nodeId << 12) + $rand;
- usleep(1);
-
- if ($unpredictable) {
- if (PHP_INT_SIZE === 4) {
- return '' . $this->encryption->encryptSimple($calc);
- }
+ return $this->cacheService;
+ }
-// $r is always a 32 bit number so it will fail in PHP 32bits
- return '' . $this->encryption->encryptInteger($calc);
- }
- return '' . $calc;
- }
+ //
+ //
/**
- * It uses \eftec\PdoOne::$masks0 and \eftec\PdoOne::$masks1 to flip
- * the number, so they are not as predictable.
- * This function doesn't add entrophy. However, the generation of Snowflakes
- * id
- * (getSequence/getSequencePHP) generates its own entrophy. Also,
- * both masks0[] and masks1[] adds an extra secrecy.
- *
- * @param $number
+ * @param string|int $password
Use a integer if the method is
+ * INTEGER
+ * @param string $salt
Salt is not used by SIMPLE or
+ * INTEGER
+ * @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
+ * simplified (generates a short
+ * result)
+ *
if INTEGER then the encryption is
+ * even simple (generates an integer)
*
- * @return mixed
+ * @throws Exception
+ * @test void this('123','somesalt','AES-128-CTR')
*/
- public function getUnpredictable($number)
+ public function setEncryption($password, $salt, $encMethod)
{
- $string = '' . $number;
- $maskSize = count($this->masks0);
-
- for ($i = 0; $i < $maskSize; $i++) {
- $init = $this->masks0[$i];
- $end = $this->masks1[$i];
- $tmp = $string[$end];
- $string = substr_replace($string, $string[$init], $end, 1);
- $string = substr_replace($string, $tmp, $init, 1);
+ if (!extension_loaded('openssl')) {
+ $this->encryption->encEnabled = false;
+ $this->throwError('OpenSSL not loaded, encryption disabled', '');
+ } else {
+ $this->encryption->encEnabled = true;
+ $this->encryption->setEncryption($password, $salt, $encMethod);
}
-
- return $string;
}
/**
- * it is the inverse of \eftec\PdoOne::getUnpredictable
+ * Wrapper of PdoOneEncryption->encrypt
*
- * @param $number
+ * @param $data
*
- * @return mixed
- * @see \eftec\PdoOne::$masks0
- * @see \eftec\PdoOne::$masks1
+ * @return bool|string
+ * @see \eftec\PdoOneEncryption::encrypt
*/
- public function getUnpredictableInv($number)
+
+ public function encrypt($data)
{
- $maskSize = count($this->masks0);
- for ($i = $maskSize - 1; $i >= 0; $i--) {
- $init = $this->masks1[$i];
- $end = $this->masks0[$i];
- $tmp = $number[$end];
- $number = substr_replace($number, $number[$init], $end, 1);
- $number = substr_replace($number, $tmp, $init, 1);
- }
+ return $this->encryption->encrypt($data);
+ }
- return $number;
+ public function hash($data)
+ {
+ return $this->encryption->hash($data);
}
/**
- * Returns true if the table exists. It uses the default schema ($this->db)
+ * Wrapper of PdoOneEncryption->decrypt
*
- * @param string $tableName The name of the table (without schema).
+ * @param $data
*
- * @return bool true if the table exist
- * @throws Exception
+ * @return bool|string
+ * @see \eftec\PdoOneEncryption::decrypt
*/
- public function tableExist($tableName)
+ public function decrypt($data)
{
- return $this->objectExist($tableName);
+ return $this->encryption->decrypt($data);
}
- /**
- * returns true if the object exists
- * Currently only works with table
- *
- * @param string $objectName
- * @param string $type =['table','function','sequence'][$i] The type of the object
- *
- * @return bool
- * @throws Exception
- */
- public function objectExist($objectName, $type = 'table')
+ public function render()
{
- $query = $this->service->objectExist($type);
+ if ($this->logLevel) {
+ ob_clean();
+ }
+
+ if (!$this->logLevel) {
+ $web = <<<'LOGS'
+
+
+
+
+
+ PdoOne Login Screen
+
+
+LOGS;
+ $web .= $this->bootstrapcss();
+ $web .= <<<'LOGS'
+
+
+
+
+
- * ->count('')->from('table')->firstScalar() // select count(*) from
- * table
- * ->count('from table')->firstScalar() // select count(*) from table
- * ->count('from table where condition=1')->firstScalar() // select count(*)
- * from table where condition=1
- * ->count('from table','col')->firstScalar() // select count(col) from
- * table
- *
+ * Alias of PdoOne::connect()
*
- * @param string|null $sql [optional]
- * @param string $arg [optional]
+ * @param bool $failIfConnected
*
- * @return PdoOne
+ * @throws Exception
+ * @test exception this(false)
+ * @see PdoOne::connect()
*/
- public function count($sql = '', $arg = '*')
+ public function open($failIfConnected = true)
{
- return $this->_aggFn('count', $sql, $arg);
+ $this->connect($failIfConnected);
}
- private function _aggFn($method, $sql = '', $arg = '')
+ /**
+ * It closes the connection
+ *
+ * @test void this()
+ */
+ public function close()
{
- if ($arg === '') {
- $arg = $sql; // if the argument is empty then it uses sql as argument
- $sql = ''; // and it lefts sql as empty
- }
- if ($arg === '*' || $this->databaseType !== 'sqlsrv') {
- return $this->select("select $method($arg) $sql");
- }
+ $this->isOpen = false;
+ if ($this->conn1 === null) {
+ return;
+ } // its already close
+
+ @$this->conn1 = null;
+ }
- return $this->select("select $method(cast($arg as decimal)) $sql");
+ public function getPK($table,$pkDefault=null) {
+ return $this->service->getPK($table,$pkDefault);
}
/**
- * It generates a query for "sum". It is a macro of select()
- * Example:
- * ->sum('from table','col')->firstScalar() // select sum(col) from
- * table
- * ->sum('col')->from('table')->firstScalar() // select sum(col) from
- * table
- * ->sum('','col')->from('table')->firstScalar() // select sum(col) from
- * table
+ * It returns the next sequence.
+ * It gets a collision free number if we don't do more than one operation
+ * every 0.0001 seconds.
+ * But, if we do 2 or more operations per seconds then, it adds a sequence
+ * number from
+ * 0 to 4095
+ * So, the limit of this function is 4096 operations per 0.0001 second.
*
- * @param string $sql [optional] it could be the name of column or part
- * of the query ("from table..")
- * @param string $arg [optiona] it could be the name of the column
+ * @see \eftec\PdoOne::getSequencePHP It's the same but it uses less
+ * resources but lacks of a sequence.
*
- * @return PdoOne
+ * @param bool $asFloat
+ * @param bool $unpredictable
+ * @param string $sequenceName (optional) the name of the sequence. If
+ * not then it uses $this->tableSequence
+ *
+ * @return string . Example string(19) "3639032938181434317"
+ * @throws Exception
*/
- public function sum($sql = '', $arg = '')
+ public function getSequence(
+ $asFloat = false,
+ $unpredictable = false,
+ $sequenceName = ''
+ )
{
- return $this->_aggFn('sum', $sql, $arg);
+ $sql = $this->service->getSequence($sequenceName);
+ $r = $this->runRawQuery($sql);
+ if ($unpredictable) {
+ if (PHP_INT_SIZE === 4) {
+ return $this->encryption->encryptSimple($r[0]['id']);
+ }
+
+// $r is always a 32 bit number so it will fail in PHP 32bits
+ return $this->encryption->encryptInteger($r[0]['id']);
+ }
+ if ($asFloat) {
+ return (float)$r[0]['id'];
+ }
+
+ return $r[0]['id'];
}
/**
- * It generates a query for "min". It is a macro of select()
- * Example:
- * ->min('from table','col')->firstScalar() // select min(col) from
- * table
- * ->min('col')->from('table')->firstScalar() // select min(col) from
- * table
- * ->min('','col')->from('table')->firstScalar() // select min(col) from
- * table
+ *
This function returns an unique sequence
+ * It ensures a collision free number only if we don't do more than one
+ * operation per 0.0001 second However,it also adds a pseudo random number
+ * (0-4095) so the chances of collision is 1/4095 (per two operations done
+ * every 0.0001 second). It is based on Twitter's Snowflake number
*
- * @param string $sql
- * @param string $arg
+ * @param bool $unpredictable
*
- * @return PdoOne
+ * @return float
+ * @see \eftec\PdoOne::getSequence
*/
- public function min($sql = '', $arg = '')
+ public function getSequencePHP($unpredictable = false)
{
- return $this->_aggFn('min', $sql, $arg);
+ $ms = microtime(true);
+ //$ms=1000;
+ $timestamp = (double)round($ms * 1000);
+ $rand = (fmod($ms, 1) * 1000000) % 4096; // 4096= 2^12 It is the millionth of seconds
+ $calc = (($timestamp - 1459440000000) << 22) + ($this->nodeId << 12) + $rand;
+ usleep(1);
+
+ if ($unpredictable) {
+ if (PHP_INT_SIZE === 4) {
+ return '' . $this->encryption->encryptSimple($calc);
+ }
+
+// $r is always a 32 bit number so it will fail in PHP 32bits
+ return '' . $this->encryption->encryptInteger($calc);
+ }
+
+ return '' . $calc;
}
/**
- * It generates a query for "max". It is a macro of select()
- * Example:
- * ->max('from table','col')->firstScalar() // select max(col) from
- * table
- * ->max('col')->from('table')->firstScalar() // select max(col) from
- * table
- * ->max('','col')->from('table')->firstScalar() // select max(col) from
- * table
+ * It uses \eftec\PdoOne::$masks0 and \eftec\PdoOne::$masks1 to flip
+ * the number, so they are not as predictable.
+ * This function doesn't add entrophy. However, the generation of Snowflakes
+ * id
+ * (getSequence/getSequencePHP) generates its own entrophy. Also,
+ * both masks0[] and masks1[] adds an extra secrecy.
*
- * @param string $sql
- * @param string $arg
+ * @param $number
*
- * @return PdoOne
+ * @return mixed
*/
- public function max($sql = '', $arg = '')
+ public function getUnpredictable($number)
{
- return $this->_aggFn('max', $sql, $arg);
+ $string = '' . $number;
+ $maskSize = count($this->masks0);
+
+ for ($i = 0; $i < $maskSize; $i++) {
+ $init = $this->masks0[$i];
+ $end = $this->masks1[$i];
+ $tmp = $string[$end];
+ $string = substr_replace($string, $string[$init], $end, 1);
+ $string = substr_replace($string, $tmp, $init, 1);
+ }
+
+ return $string;
}
/**
- * It generates a query for "avg". It is a macro of select()
- * Example:
- * ->avg('from table','col')->firstScalar() // select avg(col) from
- * table
- * ->avg('col')->from('table')->firstScalar() // select avg(col) from
- * table
- * ->avg('','col')->from('table')->firstScalar() // select avg(col) from
- * table
+ * it is the inverse of \eftec\PdoOne::getUnpredictable
*
- * @param string $sql
- * @param string $arg
+ * @param $number
*
- * @return PdoOne
+ * @return mixed
+ * @see \eftec\PdoOne::$masks0
+ * @see \eftec\PdoOne::$masks1
*/
- public function avg($sql = '', $arg = '')
+ public function getUnpredictableInv($number)
{
- return $this->_aggFn('avg', $sql, $arg);
+ $maskSize = count($this->masks0);
+ for ($i = $maskSize - 1; $i >= 0; $i--) {
+ $init = $this->masks1[$i];
+ $end = $this->masks0[$i];
+ $tmp = $number[$end];
+ $number = substr_replace($number, $number[$init], $end, 1);
+ $number = substr_replace($number, $tmp, $init, 1);
+ }
+
+ return $number;
}
/**
- * Adds a left join to the pipeline. It is possible to chain more than one
- * join
- * Example:
- *
- * left('table on t1.c1=t2.c2')
- * left('table on table.c1=t2.c2').left('table2 on
- * table1.c1=table2.c2')
- *
+ * Returns true if the table exists. It uses the default schema ($this->db)
*
- * @param string $sql Input SQL query
+ * @param string $tableName The name of the table (without schema).
*
- * @return PdoOne
- * @test InstanceOf PdoOne::class,this('table2 on table1.t1=table2.t2')
+ * @return bool true if the table exist
+ * @throws Exception
*/
- public function left($sql)
+ public function tableExist($tableName)
{
- if ($sql === null) {
- return $this;
- }
- $this->from .= ($sql) ? " left join $sql" : '';
- $this->tables[] = explode(' ', $sql)[0];
- return $this;
+ return $this->objectExist($tableName);
}
/**
- * Adds a right join to the pipeline. It is possible to chain more than one
- * join
- * Example:
- * right('table on t1.c1=t2.c2')
- * right('table on table.c1=t2.c2').right('table2 on
- * table1.c1=table2.c2')
+ * returns true if the object exists
+ * Currently only works with table
*
- * @param string $sql Input SQL query
+ * @param string $objectName
+ * @param string $type =['table','function','sequence'][$i] The type of the object
*
- * @return PdoOne
- * @test InstanceOf PdoOne::class,this('table2 on table1.t1=table2.t2')
+ * @return bool
+ * @throws Exception
*/
- public function right($sql)
+ public function objectExist($objectName, $type = 'table')
{
- if ($sql === null) {
- return $this;
+ $query = $this->service->objectExist($type);
+
+ if($this->databaseType==='oci') {
+ $arr = $this->runRawQuery($query, [$objectName,$this->db]);
+ } else {
+ $arr = $this->runRawQuery($query, [$objectName]);
}
- $this->from .= ($sql) ? " right join $sql" : '';
- $this->tables[] = explode(' ', $sql)[0];
- return $this;
+
+ return is_array($arr) && count($arr) > 0;
}
/**
- * It sets a value into the query (insert or update)
- * Example:
- * ->from("table")->set('field1=?',20),set('field2=?','hello')->insert()
- * ->from("table")->set("type=?",[6])->where("i=1")->update()
- * set("type=?",6) // automatic
- *
- * @param string|array $sqlOrArray
- * @param array|mixed $param
+ * It returns a list of tables ordered by dependency (from no dependent to
+ * more dependent)
+ * Note:: This operation is not foolproof because the tables could
+ * have circular reference.
*
+ * @param int $maxLoop The number of tests. If the sort is
+ * correct, then it ends as fast as it can.
+ * @param bool $returnProblems [false] if true then it returns all the
+ * tables with problem
+ * @param bool $debugTrace [false] if true then it shows the
+ * operations done.
*
- * @return PdoOne
- * @test InstanceOf
- * PdoOne::class,this('field1=?,field2=?',[20,'hello'])
+ * @return array List of table.
+ * @throws Exception
*/
- public function set($sqlOrArray, $param = self::NULL)
+ public function tableSorted($maxLoop = 5, $returnProblems = false, $debugTrace = false)
{
- if ($sqlOrArray === null) {
- return $this;
+ list($tables, $after, $before) = $this->tableDependency();
+ $tableSorted = [];
+ // initial load
+ foreach ($tables as $k => $table) {
+ $tableSorted[] = $table;
+ }
+ $problems = [];
+ for ($i = 0; $i < $maxLoop; $i++) {
+ if ($this->reSort($tables, $tableSorted, $after, $before, $problems, $debugTrace)) {
+ break;
+ }
}
- if (count($this->where)) {
- $this->throwError('method set() must be before where()', 'set');
- return $this;
+ if ($returnProblems) {
+ return $problems;
}
- $this->constructParam2($sqlOrArray, $param, 'set');
- return $this;
+ return $tableSorted;
}
/**
- * Example:
- *
- * where( ['field'=>20] ) // associative array (named)
- * where( ['field=?'=>20] ) // associative array (numeric)
- * where( ['field=:name'=>20] ) // associative array (named)
- * where( ['field=:name and field2=:name'=>20] ) // IT DOESN'T WORK
- * where( ['field'=>[20]] ) // associative array with type defined
- * where( ['field',20] ) // indexed array automatic type
- * where (['field',[20]] ) // indexed array type defined
- * where('field=20') // literal value
- * where('field=?',[20]) // automatic type
- * where('field',[20]) // automatic type (it's the same than
- * where('field=?',[20]) where('field=?', [20] ) // type(i,d,s,b)
- * defined where('field=?,field2=?', [20,'hello'] )
- * where('field=:field,field2=:field2',
- * ['field'=>'hello','field2'=>'world'] ) // associative array as value
- *
+ * Resort the tableSorted list based in dependencies.
*
- * @param array|string $where
- * @param string|array|int $params
- * @param string $type
- * @param bool $return
- * @param null|string $tablePrefix
+ * @param array $tables An associative array with the name of the
+ * tables
+ * @param array $tableSorted (ref) An associative array with the name
+ * of the tables
+ * @param array $after $after[city]=[country,..]
+ * @param array $before $before[city]=[address]
+ * @param array $tableProblems (ref) an associative array whtn the name
+ * of the tables with problem.
+ * @param bool $debugTrace If true then it shows a debug per
+ * operation.
*
- * @return array|null
+ * @return bool true if the sort is finished and there is nothing wrong.
*/
- public function constructParam2(
- $where,
- $params = PdoOne::NULL,
- $type = 'where',
- $return = false,
- $tablePrefix = null
+ protected function reSort(
+ $tables,
+ &$tableSorted,
+ $after,
+ $before,
+ &$tableProblems,
+ $debugTrace = false
)
{
- $queryEnd = [];
- $named = [];
- $pars = [];
-
- if ($params === self::NULL || $params === null) {
- if (is_array($where)) {
- $numeric = isset($where[0]);
- if ($numeric) {
- // numeric
- $c = count($where) - 1;
- for ($i = 0; $i < $c; $i += 2) {
- $v = $where[$i + 1];
- // constructParam2(['field',20]])
- $param = [$this->whereCounter, $v, $this->getType($v), null];
- $queryEnd[] = $where[$i];
- $named[] = '?';
- $this->whereCounter++;
- $pars[] = $param;
- }
- } else {
- // named
- foreach ($where as $k => $v) {
- if (strpos($k, '?') === false) {
- if (strpos($k, ':') !== false) {
- // "aaa=:aaa"
-
- $parts = explode(':', $k, 2);
- $paramName = ':' . str_replace('.', '_', $parts[1]);
- $named[] = $paramName;
- } else {
- // "aaa"
-
- $paramName = ':' . str_replace('.', '_', $k);
- $named[] = $paramName;
- }
- } else {
- // "aa=?"
- $paramName = $this->whereCounter;
- $this->whereCounter++;
- $named[] = '?';
- }
- // constructParam2(['field'=>20])
- $param = [$paramName, $v, $this->getType($v), null];
- $pars[] = $param;
- if ($tablePrefix !== null && strpos($k, '.') === false) {
- $queryEnd[] = $tablePrefix . '.' . $k;
- } else {
- $queryEnd[] = $k;
- }
+ shuffle($tables);
+ $tableProblems = [];
+ $nothingWrong = true;
+ foreach ($tables as $k => $table) {
+ $pos = array_search($table, $tableSorted);
+ // search for after in the wrong position
+ $wrong = false;
+ $pairProblem = '';
+ for ($i = 0; $i < $pos; $i++) {
+ if (in_array($tableSorted[$i], $before[$table])) {
+ $wrong = true;
+ $nothingWrong = false;
+ $pairProblem = $tableSorted[$i];
+ if ($debugTrace) {
+ echo "reSort: [wrong position] $table ($pos) is after " . $tableSorted[$i] . " ($i) ";
}
+ break;
}
- } else {
- // constructParam2('query=xxx')
- $named[] = '';
- $queryEnd[] = $where;
}
- } else {
- // where and params are not empty
- if (!is_array($params)) {
- $params = [$params];
- }
- if (!is_array($where)) {
- $queryEnd[] = $where;
- $numeric = isset($params[0]);
- if ($numeric) {
- foreach ($params as $k => $v) {
- // constructParam2('name=? and type>?', ['Coca-Cola',12345]);
- $named[] = '?';
- $pars[] = [
- $this->whereCounter,
- $v,
- $this->getType($v),
- null
- ];
- $this->whereCounter++;
- }
- } else {
- foreach ($params as $k => $v) {
- $named[] = $k;
- // constructParam2('name=:name and type<:type', ['name'=>'Coca-Cola','type'=>987]);;
- $pars[] = [$k, $v, $this->getType($v), null];
- //$paramEnd[]=$param;
+ if ($wrong) {
+ // the value is already in the list, we start removing it
+ $cts = count($tableSorted);
+ for ($i = $pos + 1; $i < $cts; $i++) {
+ $tableSorted[$i - 1] = $tableSorted[$i];
+ }
+ unset($tableSorted[count($tableSorted) - 1]); // we removed the last element.
+ // We found the initial position to add.
+ $pInitial = 0;
+ foreach ($tableSorted as $k2 => $v2) {
+ if (in_array($v2, $after[$table])) {
+ $pInitial = $k2 + 1;
}
}
- if (count($named) === 0) {
- $named[] = '?'; // at least one argument.
+ // we found the last position
+ $pEnd = count($tableSorted);
+ foreach ($tableSorted as $k2 => $v2) {
+ if (in_array($v2, $before[$table])) {
+ $pEnd = $k2 - 1;
+ }
}
- } else {
- // constructParam2([],..);
- $numeric = isset($where[0]);
-
- if ($numeric) {
- foreach ($where as $k => $v) {
- //$named[] = '?';
- $queryEnd[] = $v;
+ if ($pEnd < $pInitial) {
+ $tableProblems[] = $table;
+ $tableProblems[] = $pairProblem;
+ if ($debugTrace) {
+ echo "reSort: $table There is a circular reference (From $pInitial to $pEnd) ";
}
- } else {
- trigger_error('parameteres not correctly defined');
- /*foreach ($where as $k => $v) {
- $named[] = '?';
- $queryEnd[] = $k;
- }*/
}
- $numeric = isset($params[0]);
- if ($numeric) {
- foreach ($params as $k => $v) {
- //$paramEnd[]=$param;
- // constructParam2(['name','type'], ['Coca-Cola',123]);
- $named[] = '?';
- $pars[] = [$this->whereCounter, $v, $this->getType($v), null];
- $this->whereCounter++;
- //$paramEnd[]=$param;
+ if (isset($tableSorted[$pInitial])) {
+ if ($debugTrace) {
+ echo "reSort: moving $table to $pInitial ";
}
- } else {
- foreach ($params as $k => $v) {
- $named[] = $k;
- // constructParam2(['name=:name','type<:type'], ['name'=>'Coca-Cola','type'=>987]);;
- $pars[] = [$k, $v, $this->getType($v), null];
- //$paramEnd[]=$param;
+ // the space is used, so we stack the values
+ for ($i = count($tableSorted) - 1; $i >= $pInitial; $i--) {
+ $tableSorted[$i + 1] = $tableSorted[$i];
}
+ $tableSorted[$pInitial] = $table;
+ } else {
+ $tableSorted[$pInitial] = $table;
}
}
}
- //echo " where:";
- $i = -1;
+ return $nothingWrong;
+ }
- foreach ($queryEnd as $k => $v) {
- $i++;
+ /**
+ * It returns the statistics (minimum,maximum,average,sum and count) of a
+ * column of a table
+ *
+ * @param string $tableName Name of the table
+ * @param string $columnName The column name to analyze.
+ *
+ * @return array|bool Returns an array of the type
+ * ['min','max','avg','sum','count']
+ * @throws Exception
+ */
+ public function statValue($tableName, $columnName)
+ {
+ $query = "select min($columnName) min
+ ,max($columnName) max
+ ,avg($columnName) avg
+ ,sum($columnName) sum
+ ,count($columnName) count
+ from $tableName";
- if ($named[$i] !== '' && strpos($v, '?') === false && strpos($v, $named[$i]) === false) {
- $v .= '=' . $named[$i];
- $queryEnd[$k] = $v;
- }
- switch ($type) {
- case 'where':
- $this->where[] = $v;
- break;
- case 'having':
- $this->having[] = $v;
- break;
- case 'set':
- $this->set[] = $v;
- break;
- }
- }
+ return $this->runRawQuery($query);
+ }
- switch ($type) {
- case 'where':
- $this->whereParamAssoc = array_merge($this->whereParamAssoc, $pars);
- break;
- case 'having':
- $this->havingParamAssoc = array_merge($this->havingParamAssoc, $pars);
- break;
- case 'set':
- $this->setParamAssoc = array_merge($this->setParamAssoc, $pars);
- break;
- }
+ /**
+ * Returns the columns of a table
+ *
+ * @param string $tableName The name of the table.
+ *
+ * @return array|bool=['colname','coltype','colsize','colpres','colscale','iskey','isidentity','isnullable']
+ * @throws Exception
+ */
+ public function columnTable($tableName)
+ {
+ $query = $this->service->columnTable($tableName);
- if ($return) {
- return [$queryEnd, $pars];
- }
- return null;
+ return $this->runRawQuery($query);
}
/**
- * It groups by a condition.
- * Example:
- * ->select('col1,count(*)')->from('table')->group('col1')->toList();
+ * Returns all the foreign keys (and relation) of a table
*
- * @param string $sql Input SQL query
+ * @param string $tableName The name of the table.
*
- * @return PdoOne
- * @test InstanceOf PdoOne::class,this('fieldgroup')
+ * @return array|bool
+ * @throws Exception
*/
- public function group($sql)
+ public function foreignKeyTable($tableName)
{
- if ($sql === null) {
- return $this;
- }
- $this->group = ($sql) ? ' group by ' . $sql : '';
+ $query = $this->service->foreignKeyTable($tableName);
- return $this;
+ return $this->runRawQuery($query);
}
/**
- * It sets a recursive array.
- * example::
- *
- * $this->recursive(['field1','field2']);
- *
+ * Returns true if the sql starts with "select " or with "show ".
*
- * @param array|mixed $rec
+ * @param string $sql The query
*
- * @return $this
+ * @return bool
*/
- public function recursive($rec)
+ public function isQuery($sql)
{
- if (is_array($rec)) {
- $this->recursive = $rec;
- } else {
- $this->recursive = [$rec];
+ $sql = trim($sql);
+
+ return (stripos($sql, 'select ') === 0 || stripos($sql, 'show ') === 0);
+ }
+
+ /** @noinspection TypeUnsafeComparisonInspection */
+ public function filterKey($condition, $columns, $returnSimple)
+ {
+ if ($condition === null) {
+ // no filter.
+ return $columns;
}
- return $this;
+ $result = [];
+ foreach ($columns as $key => $col) {
+ if ($returnSimple) {
+ if ($col == $condition) {
+ $result[$key] = $col;
+ }
+ } elseif ($col['key'] == $condition) {
+ $result[$key] = $col;
+ }
+ }
+
+ return $result;
}
+
+ //
+ //
/**
- * It gets the recursive array.
+ * Generates and execute an insert command.
+ * Example:
+ *
+ * insert('table',['col1',10,'col2','hello world']); // simple array: name1,value1,name2,value2..
+ * insert('table',null,['col1'=>10,'col2'=>'hello world']); // definition is obtained from the values
+ * insert('table',['col1'=>10,'col2'=>'hello world']); // definition is obtained from the values
+ * insert('table',['col1','col2'],[10,'hello world']); // definition (binary) and value
+ * insert('table',['col1','col2'],['col1'=>10,'col2'=>'hello world']); // definition declarative array)
+ * ->set(['col1',10,'col2','hello world'])
+ * ->from('table')
+ * ->insert();
+ *
*
- * @return array
+ * @param null|string $tableName
+ * @param string[]|null $tableDef
+ * @param string[]|int|null $values
+ *
+ * @return mixed Returns the identity (if any) or false if the operation fails.
+ * @throws Exception
*/
- public function getRecursive()
- {
- return $this->recursive;
+ public function insert(
+ $tableName = null,
+ $tableDef = null,
+ $values = PdoOne::NULL
+ ) {
+ $query=new PdoOneQuery($this);
+ return $query->insert($tableName,$tableDef,$values);
}
-
/**
- * It returns true if recursive has some needle.
- * If $this->recursive is '*' then it always returns true.
+ * It returns an array with the metadata of each columns (i.e. name, type,
+ * size, etc.) or false if error.
+ *
+ * @param null|string $sql If null then it uses the generation of query
+ * (if any). if string then get the
+ * statement of the query
*
- * @param string $needle
- * @param null|array $recursiveArray If null then it uses the recursive array specified by $this->>recursive();
+ * @param array $args
*
- * @return bool
+ * @return array|bool
+ * @throws Exception
*/
- public function hasRecursive($needle, $recursiveArray = null)
+ public function toMeta($sql = null, $args = [])
{
- if (count($this->recursive) === 1 && $this->recursive[0] === '*') {
- return true;
- }
- if ($recursiveArray) {
- return in_array($needle, $recursiveArray, true);
- }
- return in_array($needle, $this->recursive, true);
+ $query=new PdoOneQuery($this);
+ return $query->toMeta($sql,$args);
}
-
/**
* If false then it wont generate an error.
* If true (default), then on error, it behave normally
@@ -6479,252 +5455,141 @@ public function hasRecursive($needle, $recursiveArray = null)
*
* @param bool $error
*
- * @return PdoOne
+ * @return PdoOneQuery
* @see \eftec\PdoOne::$errorText
*/
public function genError($error = false)
{
- $this->genError = $error;
- return $this;
+ $query=new PdoOneQuery($this);
+ return $query->genError($error);
}
-
- //
-
- //
-
/**
- * Executes the query, and returns the first column of the first row in the
- * result set returned by the query. Additional columns or rows are ignored.
- * If value is not found then it returns null.
- * * This method is an end of the chain method, so it clears the method stack
- * Example:
- *
+ *
+ * @param string $sql Input SQL query
+ *
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('table t1')
+ */
+ public function from($sql)
+ {
+ $query=new PdoOneQuery($this);
+ return $query->from($sql);
}
-
/**
* It allows to insert a declarative array. It uses "s" (string) as
* filetype.
@@ -6741,28 +5606,9 @@ private function constructInsert()
*/
public function insertObject($tableName, &$object, $excludeColumn = [])
{
- $objectCopy = (array)$object;
- foreach ($excludeColumn as $ex) {
- unset($objectCopy[$ex]);
- }
-
- $id = $this->insert($tableName, $objectCopy);
- /** id could be 0,false or null (when it is not generated */
- if ($id) {
- $pks = $this->service->getDefTableKeys($tableName, true, 'PRIMARY KEY');
- if ($pks > 0) {
- // we update the object because it returned an identity.
- $k = array_keys($pks)[0]; // first primary key
- if (is_array($object)) {
- $object[$k] = $id;
- } else {
- $object->$k = $id;
- }
- }
- }
- return $id;
+ $query=new PdoOneQuery($this);
+ return $query->insertObject($tableName, $object, $excludeColumn);
}
-
/**
* Delete a row(s) if they exists.
* Example:
@@ -6783,45 +5629,12 @@ public function insertObject($tableName, &$object, $excludeColumn = [])
public function delete(
$tableName = null,
$tableDefWhere = null,
- $valueWhere = self::NULL
+ $valueWhere = PdoOne::NULL
)
{
- if ($tableName === null) {
- $tableName = $this->from;
- } else {
- $this->tables[] = $tableName;
- }
- if ($this->useCache === true) {
- $this->invalidateCache('', $this->cacheFamily);
- }
- // using builder. from()->set()->where()->update()
- $errorCause = '';
- if (!$tableName) {
- $errorCause = "you can't execute an empty delete() without a from()";
- }
- if ($errorCause) {
- $this->throwError('Delete:' . $errorCause, '');
- return false;
- }
-
- if ($tableDefWhere !== null) {
- $this->constructParam2($tableDefWhere, $valueWhere);
- }
-
- $sql = 'delete from ' . $this->addDelimiter($tableName);
- $sql .= $this->constructWhere();
- $param = $this->whereParamAssoc;
-
- $this->beginTry();
- $stmt = $this->runRawQuery($sql, $param, false);
- $this->builderReset(true);
- if ($this->endtry() === false) {
- return false;
- }
-
- return $this->affected_rows($stmt);
+ $query=new PdoOneQuery($this);
+ return $query->delete($tableName, $tableDefWhere, $valueWhere);
}
-
/**
* Generate and run an update in the database.
* Example:
@@ -6842,276 +5655,231 @@ public function delete(
* @param string[]|null $tableDefWhere
* @param string[]|int|null $valueWhere
*
- * @return mixed
- * @throws Exception
- */
- public function update(
- $tableName = null,
- $tableDef = null,
- $values = self::NULL,
- $tableDefWhere = null,
- $valueWhere = self::NULL
- )
- {
- if ($tableName === null) {
- // using builder. from()->set()->where()->update()
- $tableName = $this->from;
- } else {
- $this->tables[] = $tableName;
- }
- if ($this->useCache === true) {
- $this->invalidateCache('', $this->cacheFamily);
- }
-
- if ($tableDef !== null) {
- $this->constructParam2($tableDef, $values, 'set');
- }
-
- if ($tableDefWhere !== null) {
- $this->constructParam2($tableDefWhere, $valueWhere);
- }
-
- $errorCause = '';
-
- if (!$tableName) {
- $errorCause = "you can't execute an empty update() without a from()";
- }
- if (count($this->set) === 0) {
- $errorCause = "you can't execute an empty update() without a set()";
- }
- if ($errorCause) {
- $this->throwError('Update:' . $errorCause, 'update');
- return false;
- }
-
- $sql = 'update ' . $this->addDelimiter($tableName);
- $sql .= $this->constructSet();
- $sql .= $this->constructWhere();
- $param = array_merge($this->setParamAssoc, $this->whereParamAssoc); // the order matters.
-
- // $this->builderReset();
- $this->beginTry();
- $stmt = $this->runRawQuery($sql, $param, false);
- $this->builderReset(true);
- if ($this->endtry() === false) {
- return false;
- }
- return $this->affected_rows($stmt);
+ * @return mixed
+ * @throws Exception
+ */
+ public function update(
+ $tableName = null,
+ $tableDef = null,
+ $values = PdoOne::NULL,
+ $tableDefWhere = null,
+ $valueWhere = PdoOne::NULL
+ )
+ {
+ $query=new PdoOneQuery($this);
+ return $query->update($tableName, $tableDef, $values,$tableDefWhere,$valueWhere);
}
-
-
- //
- //
-
/**
- * It sets to use cache for the current pipelines. It is disabled at the end of the pipeline
- * It only works if we set the cacheservice
- * Example
- *
- * $this->setCacheService($instanceCache);
- * $this->useCache()->select()..; // The cache never expires
- * $this->useCache(60)->select()..; // The cache lasts 60 seconds.
- * $this->useCache(60,'customers')
- * ->select()..; // cache associated with customers
- * // it could be invalidated by invalidateCache()
- * $this->useCache(60,['customers','invoices'])
- * ->select()..; // cache associated with customers
- * // it could be invalidated by invalidateCache()
- * $this->useCache(60,'*')->select('col')
- * ->from('table')->toList(); // '*' uses all the table assigned.
- *
+ * Adds a right join to the pipeline. It is possible to chain more than one
+ * join
+ * Example:
+ * right('table on t1.c1=t2.c2')
+ * right('table on table.c1=t2.c2').right('table2 on
+ * table1.c1=table2.c2')
*
- * @param null|bool|int $ttl null then the cache never expires.
- * false then we don't use cache.
- * int then it is the duration of the cache (in seconds)
- * @param string|array $family [optional] It is the family or group of the cache. It could be used to
- * identify a group of cache to invalidate the whole group (for example
- * ,invalidate all cache from a specific table).
- * * If "*" then it uses the tables assigned by from() and join()
+ * @param string $sql Input SQL query
*
- * @return $this
- * @see \eftec\PdoOne::invalidateCache
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('table2 on table1.t1=table2.t2')
*/
- public function useCache($ttl = 0, $family = '')
+ public function right($sql)
{
- if ($this->cacheService === null) {
- $ttl = false;
- }
- $this->cacheFamily = $family;
- $this->useCache = $ttl;
-
- return $this;
+ $query=new PdoOneQuery($this);
+ return $query->right($sql);
}
-
/**
- * It sets the cache service (optional).
+ * Adds a left join to the pipeline. It is possible to chain more than one
+ * join
+ * Example:
+ *
+ * left('table on t1.c1=t2.c2')
+ * left('table on table.c1=t2.c2').left('table2 on
+ * table1.c1=table2.c2')
+ *
*
- * @param IPdoOneCache $cacheService Instance of an object that implements IPdoOneCache
+ * @param string $sql Input SQL query
*
- * @return $this
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('table2 on table1.t1=table2.t2')
*/
- public function setCacheService($cacheService)
+ public function left($sql)
{
- $this->cacheService = $cacheService;
-
- return $this;
+ $query=new PdoOneQuery($this);
+ return $query->left($sql);
}
-
/**
- * It stores a cache. This method is used internally by PdoOne.
+ * Example:
+ * where( ['field'=>20] ) // associative array with automatic type
+ * where( ['field'=>[20]] ) // associative array with type defined
+ * where( ['field',20] ) // array automatic type
+ * where (['field',[20]] ) // array type defined
+ * where('field=20') // literal value
+ * where('field=?',[20]) // automatic type
+ * where('field',[20]) // automatic type (it's the same than
+ * where('field=?',[20]) where('field=?', [20] ) // type(i,d,s,b)
+ * defined where('field=?,field2=?', [20,'hello'] )
+ * where('field=:field,field2=:field2',
+ * ['field'=>'hello','field2'=>'world'] ) // associative array as value
*
- * @param string $uid The unique id. It is generate by sha256 based in the query, parameters, type of query
- * and method.
- * @param string|string[] $family [optional] It is the family or group of the cache. It could be used to invalidate
- * the whole group. For example, to invalidate all the cache related with a table.
- * @param mixed|null $data The data to store
- * @param null|bool|int $ttl If null then the cache never expires.
- * If false then we don't use cache.
- * If int then it is the duration of the cache (in seconds)
+ * @param string|array $sql Input SQL query or associative/indexed
+ * array
+ * @param array|mixed $param Associative or indexed array with the
+ * conditions.
+ * @param bool $isHaving if true then it is a HAVING sql commando
+ * instead of a WHERE.
*
- * @return void.
+ * @param null|string $tablePrefix
+ *
+ * @return PdoOneQuery
+ * @see http://php.net/manual/en/mysqli-stmt.bind-param.php for types
+ * @test InstanceOf
+ * PdoOne::class,this('field1=?,field2=?',[20,'hello'])
*/
- public function setCache($uid, $family = '', $data = null, $ttl = null)
+ public function where($sql, $param = PdoOne::NULL, $isHaving = false, $tablePrefix = null)
{
- if ($family === '*') {
- $family = $this->tables;
- }
- $this->cacheService->setCache($uid, $family, $data, $ttl);
+ $query=new PdoOneQuery($this);
+ return $query->where($sql, $param, $isHaving, $tablePrefix);
}
-
/**
- * Invalidate a single cache or a list of cache based in a single uid or in
- * a family/group of cache.
+ * It adds a having to the query builder.
+ * Example:
+ * select('*')->from('table')->group('col')->having('field=2')
+ * having( ['field'=>20] ) // associative array with automatic type
+ * having( ['field'=>[20]] ) // associative array with type defined
+ * having( ['field',20] ) // array automatic type
+ * having(['field',[20]] ) // array type defined
+ * having('field=20') // literal value
+ * having('field=?',[20]) // automatic type
+ * having('field',[20]) // automatic type (it's the same than
+ * where('field=?',[20]) having('field=?', [20] ) // type(i,d,s,b)
+ * defined having('field=?,field2=?', [20,'hello'] )
*
- * @param string|string[] $uid The unique id. It is generate by sha256 (or by $hashtype)
- * based in the query, parameters, type
- * of query and method.
- * @param string|string[] $family [optional] It is the family or group
- * of
- * the cache. It could be used to
- * invalidate the whole group. For
- * example, to invalidate all the cache
- * related with a table.
+ * @param string|array $sql
+ * @param array|mixed $param
*
- * @return $this
- * @see \eftec\PdoOneEncryption::$hashType
+ * @return PdoOneQuery
+ * @see http://php.net/manual/en/mysqli-stmt.bind-param.php for types
+ * @test InstanceOf
+ * PdoOne::class,this('field1=?,field2=?',[20,'hello'])
*/
- public function invalidateCache($uid = '', $family = '')
+ public function having($sql, $param = PdoOne::NULL)
{
- if ($this->cacheService !== null) {
- if ($family === '*') {
- $family = $this->tables;
- }
- $this->cacheService->invalidateCache($uid, $family);
- }
- return $this;
+ $query=new PdoOneQuery($this);
+ return $query->having($sql, $param);
}
-
-
- //
- //
-
/**
- * Returns the number of affected rows.
+ * It generates an inner join
+ * Example:
+ *
+ * join('tablejoin on t1.field=t2.field')
+ * join('tablejoin','t1.field=t2.field')
+ *
*
- * @param PDOStatement|null|bool $stmt
+ * @param string $sql Example "tablejoin on table1.field=tablejoin.field"
+ * @param string $condition
*
- * @return mixed
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('tablejoin on t1.field=t2.field')
*/
- public function affected_rows($stmt = null)
+ public function join($sql, $condition = '')
{
- if ($stmt instanceof PDOStatement && !$this->isOpen) {
- return $stmt->rowCount();
- }
- return $this->affected_rows; // returns previous calculated information
+ $query=new PdoOneQuery($this);
+ return $query->join($sql, $condition);
}
-
/**
- * Returns the last inserted identity.
+ * It groups by a condition.
+ * Example:
+ * ->select('col1,count(*)')->from('table')->group('col1')->toList();
*
- * @param null|string $sequenceName [optional] the name of the sequence
+ * @param string $sql Input SQL query
*
- * @return mixed a number or 0 if it is not found
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('fieldgroup')
*/
- public function insert_id($sequenceName = null)
+ public function group($sql)
{
- if (!$this->isOpen) {
- return -1;
- }
-
- return $this->conn1->lastInsertId($sequenceName);
+ $query=new PdoOneQuery($this);
+ return $query->group($sql);
}
-
/**
- * @return IPdoOneCache
+ * It adds an "order by" in a query.
+ * Example:
+ *
+ *
+ * @return array|null
+ * @throws Exception
+ * @see \eftec\PdoOne::first
+ */
+ public function last()
+ {
+ $useCache = $this->parent->useCache; // because builderReset cleans this value
+
+ if ($useCache !== false) {
+ $sql = $this->sqlGen();
+ $this->uid = hash($this->parent->encryption->hashType,
+ $sql . PDO::FETCH_ASSOC . serialize($this->whereParamAssoc) . serialize($this->havingParamAssoc)
+ . 'last');
+ $rows = $this->parent->cacheService->getCache($this->uid, $this->parent->cacheFamily);
+ if ($rows !== false) {
+ $this->builderReset();
+
+ return $rows;
+ }
+ }
+ $this->parent->beginTry();
+ /** @var PDOStatement $statement */
+ $statement = $this->runGen(false, PDO::FETCH_ASSOC, 'last', false);
+ if ($this->endtry() === false) {
+ return null;
+ }
+ $row = null;
+ if ($statement === false) {
+ $row = null;
+ } elseif (!$statement->columnCount()) {
+ $row = null;
+ } else {
+ while ($dummy = $statement->fetch(PDO::FETCH_ASSOC)) {
+ $row = $dummy;
+ }
+ @$statement->closeCursor();
+ $statement = null;
+ }
+
+ if ($this->uid && $useCache !== false) {
+ // we store the information of the cache.
+ $this->parent->setCache($this->uid, $this->parent->cacheFamily, $row, $useCache);
+ }
+
+ return $row;
+ }
+
+
+ /**
+ * It returns an array of simple columns (not declarative). It uses the
+ * first column
+ * Example:
+ *
+ * select('select id from table')->toListSimple() // ['1','2','3','4']
+ *
+ *
+ * @return array|bool
+ * @throws Exception
+ */
+ public function toListSimple()
+ {
+ $useCache = $this->parent->useCache; // because builderReset cleans this value
+ $this->parent->beginTry();
+ $rows = $this->runGen(true, PDO::FETCH_COLUMN, 'tolistsimple', false);
+ if ($this->endtry() === false) {
+ return false;
+ }
+ if ($this->uid && $useCache !== false) {
+ // we store the information of the cache.
+ $this->parent->setCache($this->uid, $this->parent->cacheFamily, $rows, $useCache);
+ }
+
+ return $rows;
+ }
+
+ /**
+ * It adds a select to the query builder.
+ * Example:
+ *
+ * ->select("\*")->from('table') = "select * from table"
+ * ->select(['col1','col2'])->from('table') = "select col1,col2 from
+ * table"
+ * ->select('col1,col2')->from('table') = "select col1,col2 from
+ * table"
+ * ->select('select *')->from('table') = "select * from table"
+ * ->select('select * from table') = "select * from table"
+ * ->select('select * from table where id=1') = "select * from table
+ * where id=1"
+ *
+ *
+ * @param string|array $sql
+ *
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('select 1 from DUAL')
+ */
+ public function select($sql)
+ {
+ if (is_array($sql)) {
+ $this->select .= implode(', ', $sql);
+ } elseif ($this->select === '') {
+ $this->select = $sql;
+ } else {
+ $this->select .= ', ' . $sql;
+ }
+
+ return $this;
+ }
+
+ /**
+ * It adds a having to the query builder.
+ * Example:
+ * select('*')->from('table')->group('col')->having('field=2')
+ * having( ['field'=>20] ) // associative array with automatic type
+ * having( ['field'=>[20]] ) // associative array with type defined
+ * having( ['field',20] ) // array automatic type
+ * having(['field',[20]] ) // array type defined
+ * having('field=20') // literal value
+ * having('field=?',[20]) // automatic type
+ * having('field',[20]) // automatic type (it's the same than
+ * where('field=?',[20]) having('field=?', [20] ) // type(i,d,s,b)
+ * defined having('field=?,field2=?', [20,'hello'] )
+ *
+ * @param string|array $sql
+ * @param array|mixed $param
+ *
+ * @return PdoOneQuery
+ * @see http://php.net/manual/en/mysqli-stmt.bind-param.php for types
+ * @test InstanceOf
+ * PdoOne::class,this('field1=?,field2=?',[20,'hello'])
+ */
+ public function having($sql, $param = PdoOne::NULL)
+ {
+ if ($sql === null) {
+ return $this;
+ }
+
+ return $this->where($sql, $param, true);
+ }
+
+ /**
+ * Example:
+ * where( ['field'=>20] ) // associative array with automatic type
+ * where( ['field'=>[20]] ) // associative array with type defined
+ * where( ['field',20] ) // array automatic type
+ * where (['field',[20]] ) // array type defined
+ * where('field=20') // literal value
+ * where('field=?',[20]) // automatic type
+ * where('field',[20]) // automatic type (it's the same than
+ * where('field=?',[20]) where('field=?', [20] ) // type(i,d,s,b)
+ * defined where('field=?,field2=?', [20,'hello'] )
+ * where('field=:field,field2=:field2',
+ * ['field'=>'hello','field2'=>'world'] ) // associative array as value
+ *
+ * @param string|array $sql Input SQL query or associative/indexed
+ * array
+ * @param array|mixed $param Associative or indexed array with the
+ * conditions.
+ * @param bool $isHaving if true then it is a HAVING sql commando
+ * instead of a WHERE.
+ *
+ * @param null|string $tablePrefix
+ *
+ * @return PdoOneQuery
+ * @see http://php.net/manual/en/mysqli-stmt.bind-param.php for types
+ * @test InstanceOf
+ * PdoOne::class,this('field1=?,field2=?',[20,'hello'])
+ */
+ public function where($sql, $param = PdoOne::NULL, $isHaving = false, $tablePrefix = null)
+ {
+ if ($sql === null) {
+ return $this;
+ }
+ $this->constructParam2($sql, $param, $isHaving ? 'having' : 'where', false, $tablePrefix);
+ return $this;
+ }
+
+ /**
+ * Returns true if the current query has a "having" or "where"
+ *
+ * @param bool $having true it return the number of where
+ * false it returns the number of having
+ *
+ * @return bool
+ */
+ public function hasWhere($having = false)
+ {
+ if ($having) {
+ return count($this->having) > 0;
+ }
+
+ return count($this->where) > 0;
+ }
+
+ /**
+ * 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 function limit($sql)
+ {
+ if ($sql === null) {
+ return $this;
+ }
+ $this->limit=$this->parent->service->limit($sql);
+
+ return $this;
+ }
+
+ /**
+ * Adds a distinct to the query. The value is ignored if the select() is
+ * written complete.
+ *
+ * ->select("*")->distinct() // works
+ * ->select("select *")->distinct() // distinct is ignored.
+ *
+ *
+ * @param string $sql Input SQL query
+ *
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this()
+ */
+ public function distinct($sql = 'distinct')
+ {
+ if ($sql === null) {
+ return $this;
+ }
+ $this->distinct = ($sql) ? $sql . ' ' : '';
+
+ return $this;
+ }
+
+ /**
+ * It returns an associative array where the first value is the key and the
+ * second is the value If the second value does not exist then it uses
+ * the index as value (first value)
+ * Example:
+ *
+ *
+ * @param string|null $extraValueSeparator (optional) It allows to read a
+ * third value and returns it
+ * concatenated with the value.
+ * Example '|'
+ *
+ * @return array|bool|null
+ * @throws Exception
+ */
+ public function toListKeyValue($extraValueSeparator = null)
+ {
+ $list = $this->toList(PDO::FETCH_NUM);
+ if (!is_array($list)) {
+ return null;
+ }
+ $result = [];
+ foreach ($list as $item) {
+ if ($extraValueSeparator === null) {
+ $result[$item[0]] = isset($item[1]) ? $item[1] : $item[0];
+ } else {
+ $result[$item[0]] = (isset($item[1]) ? $item[1] : $item[0]) . $extraValueSeparator . @$item[2];
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * It returns an declarative array of rows.
+ * If not data is found, then it returns an empty array
+ * This method is an end of the chain method, so it clears the method stack
+ * Example:
+ *
+ *
+ * @param int $pdoMode (optional) By default is PDO::FETCH_ASSOC
+ *
+ * @return array|bool
+ * @throws Exception
+ */
+ public function toList($pdoMode = PDO::FETCH_ASSOC)
+ {
+ $useCache = $this->parent->useCache; // because builderReset cleans this value
+ $this->parent->beginTry();
+ $rows = $this->runGen(true, $pdoMode, 'tolist', false);
+ if ($this->endtry() === false) {
+ return false;
+ }
+ if ($this->uid && $useCache !== false) {
+ // we store the information of the cache.
+ $this->parent->setCache($this->uid, $this->parent->cacheFamily, $rows, $useCache);
+ }
+ return $rows;
+ }
+
+ /**
+ * It returns a PDOStatement.
+ * Note: The result is not cached.
+ *
+ * @return PDOStatement
+ * @throws Exception
+ */
+ public function toResult()
+ {
+ return $this->runGen(false);
+ }
+
+ /**
+ * It returns the first row. If there is not row then it returns false.
+ * This method is an end of the chain method, so it clears the method stack
+ * Example:
+ *
+ *
+ * @return array|null|false
+ * @throws Exception
+ */
+ public function first()
+ {
+ $useCache = $this->parent->useCache; // because builderReset cleans this value
+ $uid = false;
+ if ($useCache !== false) {
+ $sql = $this->sqlGen();
+ $this->uid = hash($this->parent->encryption->hashType,
+ $sql . PDO::FETCH_ASSOC . serialize($this->whereParamAssoc) . serialize($this->havingParamAssoc)
+ . 'firstscalar');
+ $rows = $this->parent->cacheService->getCache($this->uid, $this->parent->cacheFamily);
+ if ($rows !== false) {
+ $this->builderReset();
+
+ return $rows;
+ }
+ }
+ if ($this->parent->useInternalCache) {
+ $sql = (!isset($sql)) ? $this->sqlGen() : $sql;
+ $allparam = array_merge($this->setParamAssoc, $this->whereParamAssoc, $this->havingParamAssoc);
+ $uid = hash($this->parent->encryption->hashType, 'first' . $sql . serialize($allparam));
+ if (isset($this->parent->internalCache[$uid])) {
+ // we have an internal cache, so we will return it.
+ $this->parent->internalCacheCounter++;
+ $this->builderReset();
+ return $this->parent->internalCache[$uid];
+ }
+ }
+ $this->parent->beginTry();
+ /** @var PDOStatement $statement */
+ $statement = $this->runGen(false, PDO::FETCH_ASSOC, 'first', false);
+ if ($this->endtry() === false) {
+ return null;
+ }
+ $row = null;
+ if ($statement === false) {
+ $row = null;
+ } elseif (!$statement->columnCount()) {
+ $row = null;
+ } else {
+ $row = $statement->fetch(PDO::FETCH_ASSOC);
+ @$statement->closeCursor();
+ $statement = null;
+ }
+
+ if ($this->uid && $useCache !== false) {
+ // we store the information of the cache.
+ $this->parent->setCache($this->uid, $this->parent->cacheFamily, $row, $useCache);
+ }
+ if ($uid !== false) {
+ $this->parent->internalCache[$uid] = $row;
+ }
+
+ return $row;
+ }
+
+ //
+
+ //
+
+ /**
+ * @return string
+ */
+ private function constructHaving()
+ {
+ return count($this->having) ? ' having ' . implode(' and ', $this->having) : '';
+ }
+
+ /**
+ * It ends a try block and throws the error (if any)
+ *
+ * @return bool
+ * @throws Exception
+ */
+ private function endTry()
+ {
+ $this->parent->throwOnError = $this->parent->throwOnErrorB;
+ if ($this->parent->errorText) {
+ $this->throwErrorChain('endtry:' . $this->parent->errorText, '', '', $this->parent->isThrow);
+ return false;
+ }
+ return true;
+ }
+
+
+
+ /**
+ * If true, then on error, the code thrown an error. >
+ * If false, then on error, the the code returns false and logs the errors ($this->parent->errorText).
+ *
+ * @param bool $value
+ *
+ * @return $this
+ */
+ public function setThrowOnError($value = false)
+ {
+ $this->parent->throwOnError = $value;
+ return $this;
+ }
+
+
+
+ /**
+ * If true then the stack/query builder will not reset the stack (but on error) when it is finished
+ * Example:
+ *
+ * $this->parent->pdoOne->select('*')->from('missintable')->setNoReset(true)->toList();
+ * // we do something with the stack
+ * $this->parent->pdoOne->builderReset(true); // reset the stack manually
+ *
+ *
+ * @param bool $noReset
+ *
+ * @return $this
+ */
+ public function setNoReset($noReset = true)
+ {
+ $this->noReset = $noReset;
+ return $this;
+ }
+
+ /**
+ * It returns an uniqued uid ('sha256' or the value defined in PdoOneEncryption::$hashType) based in all the
+ * parameters of the query (select,from,where,parameters,group,recursive,having,limit,distinct,order,etc.) and
+ * optionally in an extra value
+ *
+ * @param mixed|null $extra [optional] If we want to add an extra value to the UID generated
+ * @param string $prefix A prefix added to the UNID generated.
+ *
+ * @return string
+ * @see \eftec\PdoOneEncryption::$hashType
+ */
+ public function buildUniqueID($extra = null, $prefix = '')
+ {
+ // set and setparam are not counted
+ $all = [
+ $this->select,
+ $this->from,
+ $this->where,
+ $this->whereParamAssoc,
+ $this->havingParamAssoc,
+ // $this->setParamAssoc,
+ //$this->whereParamValue,
+ $this->group,
+ $this->recursive,
+ $this->having,
+ $this->limit,
+ $this->distinct,
+ $this->order,
+ $extra
+ ];
+ return $prefix . hash($this->parent->encryption->hashType, json_encode($all));
+ }
+
+ /**
+ * Write a log line for debug, clean the command chain then throw an error
+ * (if throwOnError==true)
+ *
+ * @param string $txt The message to show.
+ * @param string $txtExtra It's only used if $logLevel>=2. It
+ * shows an extra message
+ * @param string|array $extraParam It's only used if $logLevel>=3 It
+ * shows parameters (if any)
+ *
+ * @param bool $throwError if true then it throw error (is enabled). Otherwise it store the error.
+ *
+ * @param null|RuntimeException $exception
+ *
+ * @see \eftec\PdoOne::$logLevel
+ */
+ public function throwErrorChain($txt, $txtExtra, $extraParam = '', $throwError = true, $exception = null)
+ {
+ if ($this->parent->logLevel === 0) {
+ $txt = 'Error on database';
+ }
+ if ($this->parent->logLevel >= 2) {
+ $txt .= "\n extra:[{$txtExtra}]";
+ }
+ if ($this->parent->logLevel >= 2) {
+ $txt .= "\n last query:[{$this->parent->lastQuery}]";
+ }
+ if ($this->parent->logLevel >= 3) {
+ $txt .= "\n database:" . $this->parent->server . ' - ' . $this->parent->db;
+ if (is_array($extraParam)) {
+ foreach ($extraParam as $k => $v) {
+ if (is_array($v) || is_object($v)) {
+ $v = json_encode($v);
+ }
+ $txt .= "\n $k:$v";
+ }
+ } else {
+ $txt .= "\n Params :[" . $extraParam . "]\n ";
+ }
+ if ($exception !== null) {
+ $txt .= "\n message :[" . str_replace("\n", "\n ", $exception->getMessage()) . "]";
+ $txt .= "\n trace :[" . str_replace("\n", "\n ", $exception->getTraceAsString()) . "]";
+ $txt .= "\n code :[" . str_replace("\n", "\n ", $exception->getCode()) . "]\n ";
+ }
+ }
+ if ($this->parent->getMessages() === null) {
+ $this->parent->debugFile($txt, 'ERROR');
+ } else {
+ $this->parent->getMessages()->addItem($this->parent->db, $txt);
+ $this->parent->debugFile($txt, 'ERROR');
+ }
+ $this->parent->errorText = $txt;
+
+ if ($throwError && $this->parent->throwOnError && $this->parent->genError) {
+ throw new RuntimeException($txt);
+ }
+ $this->builderReset(true); // it resets the chain if any.
+ }
+
+
+ /**
+ * It generates a query for "count". It is a macro of select()
+ * Example:
+ *
+ * ->count('')->from('table')->firstScalar() // select count(*) from
+ * table
+ * ->count('from table')->firstScalar() // select count(*) from table
+ * ->count('from table where condition=1')->firstScalar() // select count(*)
+ * from table where condition=1
+ * ->count('from table','col')->firstScalar() // select count(col) from
+ * table
+ *
+ *
+ * @param string|null $sql [optional]
+ * @param string $arg [optional]
+ *
+ * @return PdoOneQuery
+ */
+ public function count($sql = '', $arg = '*')
+ {
+ return $this->_aggFn('count', $sql, $arg);
+ }
+
+ public function _aggFn($method, $sql = '', $arg = '')
+ {
+ if ($arg === '') {
+ $arg = $sql; // if the argument is empty then it uses sql as argument
+ $sql = ''; // and it lefts sql as empty
+ }
+ if ($arg === '*' || $this->parent->databaseType !== 'sqlsrv') {
+ return $this->select("select $method($arg) $sql");
+ }
+
+ return $this->select("select $method(cast($arg as decimal)) $sql");
+ }
+
+ /**
+ * It generates a query for "sum". It is a macro of select()
+ * Example:
+ * ->sum('from table','col')->firstScalar() // select sum(col) from
+ * table
+ * ->sum('col')->from('table')->firstScalar() // select sum(col) from
+ * table
+ * ->sum('','col')->from('table')->firstScalar() // select sum(col) from
+ * table
+ *
+ * @param string $sql [optional] it could be the name of column or part
+ * of the query ("from table..")
+ * @param string $arg [optiona] it could be the name of the column
+ *
+ * @return PdoOneQuery
+ */
+ public function sum($sql = '', $arg = '')
+ {
+ return $this->_aggFn('sum', $sql, $arg);
+ }
+
+ /**
+ * It generates a query for "min". It is a macro of select()
+ * Example:
+ * ->min('from table','col')->firstScalar() // select min(col) from
+ * table
+ * ->min('col')->from('table')->firstScalar() // select min(col) from
+ * table
+ * ->min('','col')->from('table')->firstScalar() // select min(col) from
+ * table
+ *
+ * @param string $sql
+ * @param string $arg
+ *
+ * @return PdoOneQuery
+ */
+ public function min($sql = '', $arg = '')
+ {
+ return $this->_aggFn('min', $sql, $arg);
+ }
+
+ /**
+ * It generates a query for "max". It is a macro of select()
+ * Example:
+ * ->max('from table','col')->firstScalar() // select max(col) from
+ * table
+ * ->max('col')->from('table')->firstScalar() // select max(col) from
+ * table
+ * ->max('','col')->from('table')->firstScalar() // select max(col) from
+ * table
+ *
+ * @param string $sql
+ * @param string $arg
+ *
+ * @return PdoOneQuery
+ */
+ public function max($sql = '', $arg = '')
+ {
+ return $this->_aggFn('max', $sql, $arg);
+ }
+
+ /**
+ * It generates a query for "avg". It is a macro of select()
+ * Example:
+ * ->avg('from table','col')->firstScalar() // select avg(col) from
+ * table
+ * ->avg('col')->from('table')->firstScalar() // select avg(col) from
+ * table
+ * ->avg('','col')->from('table')->firstScalar() // select avg(col) from
+ * table
+ *
+ * @param string $sql
+ * @param string $arg
+ *
+ * @return PdoOneQuery
+ */
+ public function avg($sql = '', $arg = '')
+ {
+ return $this->_aggFn('avg', $sql, $arg);
+ }
+
+ /**
+ * Adds a left join to the pipeline. It is possible to chain more than one
+ * join
+ * Example:
+ *
+ * left('table on t1.c1=t2.c2')
+ * left('table on table.c1=t2.c2').left('table2 on
+ * table1.c1=table2.c2')
+ *
+ *
+ * @param string $sql Input SQL query
+ *
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('table2 on table1.t1=table2.t2')
+ */
+ public function left($sql)
+ {
+ if ($sql === null) {
+ return $this;
+ }
+ $this->from .= ($sql) ? " left join $sql" : '';
+ $this->parent->tables[] = explode(' ', $sql)[0];
+ return $this;
+ }
+
+ /**
+ * Adds a right join to the pipeline. It is possible to chain more than one
+ * join
+ * Example:
+ * right('table on t1.c1=t2.c2')
+ * right('table on table.c1=t2.c2').right('table2 on
+ * table1.c1=table2.c2')
+ *
+ * @param string $sql Input SQL query
+ *
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('table2 on table1.t1=table2.t2')
+ */
+ public function right($sql)
+ {
+ if ($sql === null) {
+ return $this;
+ }
+ $this->from .= ($sql) ? " right join $sql" : '';
+ $this->parent->tables[] = explode(' ', $sql)[0];
+ return $this;
+ }
+
+ /**
+ * It sets a value into the query (insert or update)
+ * Example:
+ * ->from("table")->set('field1=?',20),set('field2=?','hello')->insert()
+ * ->from("table")->set("type=?",[6])->where("i=1")->update()
+ * set("type=?",6) // automatic
+ *
+ * @param string|array $sqlOrArray
+ * @param array|mixed $param
+ *
+ *
+ * @return PdoOneQuery
+ * @test InstanceOf
+ * PdoOne::class,this('field1=?,field2=?',[20,'hello'])
+ */
+ public function set($sqlOrArray, $param = PdoOne::NULL)
+ {
+ if ($sqlOrArray === null) {
+ return $this;
+ }
+ if (count($this->where)) {
+ $this->throwErrorChain('method set() must be before where()', 'set');
+ return $this;
+ }
+
+ $this->constructParam2($sqlOrArray, $param, 'set');
+ return $this;
+ }
+
+ /**
+ * Example:
+ *
+ * where( ['field'=>20] ) // associative array (named)
+ * where( ['field=?'=>20] ) // associative array (numeric)
+ * where( ['field=:name'=>20] ) // associative array (named)
+ * where( ['field=:name and field2=:name'=>20] ) // IT DOESN'T WORK
+ * where( ['field'=>[20]] ) // associative array with type defined
+ * where( ['field',20] ) // indexed array automatic type
+ * where (['field',[20]] ) // indexed array type defined
+ * where('field=20') // literal value
+ * where('field=?',[20]) // automatic type
+ * where('field',[20]) // automatic type (it's the same than
+ * where('field=?',[20]) where('field=?', [20] ) // type(i,d,s,b)
+ * defined where('field=?,field2=?', [20,'hello'] )
+ * where('field=:field,field2=:field2',
+ * ['field'=>'hello','field2'=>'world'] ) // associative array as value
+ *
+ *
+ * @param string $sql Input SQL query
+ *
+ * @return PdoOneQuery
+ * @test InstanceOf PdoOne::class,this('table t1')
+ */
+ public function from($sql)
+ {
+ if ($sql === null) {
+ return $this;
+ }
+ $this->from = ($sql) ? $sql . $this->from : $this->from;
+ $this->parent->tables[] = explode(' ', $sql)[0];
+
+ return $this;
+ }
+ /**
+ * It sets to use cache for the current pipelines. It is disabled at the end of the pipeline
+ * It only works if we set the cacheservice
+ * Example
+ *
+ * $this->setCacheService($instanceCache);
+ * $this->useCache()->select()..; // The cache never expires
+ * $this->useCache(60)->select()..; // The cache lasts 60 seconds.
+ * $this->useCache(60,'customers')
+ * ->select()..; // cache associated with customers
+ * // it could be invalidated by invalidateCache()
+ * $this->useCache(60,['customers','invoices'])
+ * ->select()..; // cache associated with customers
+ * // it could be invalidated by invalidateCache()
+ * $this->useCache(60,'*')->select('col')
+ * ->from('table')->toList(); // '*' uses all the table assigned.
+ *
+ *
+ * @param null|bool|int $ttl null then the cache never expires.
+ * false then we don't use cache.
+ * int then it is the duration of the cache (in seconds)
+ * @param string|array $family [optional] It is the family or group of the cache. It could be used to
+ * identify a group of cache to invalidate the whole group (for example
+ * ,invalidate all cache from a specific table).
+ * * If "*" then it uses the tables assigned by from() and join()
+ *
+ * @return $this
+ * @see \eftec\PdoOne::invalidateCache
+ */
+ public function useCache($ttl = 0, $family = '')
+ {
+ if ($this->parent->cacheService === null) {
+ $ttl = false;
+ }
+ $this->parent->cacheFamily = $family;
+ $this->parent->useCache = $ttl;
+
+ return $this;
+ }
+
+
+}
\ No newline at end of file
diff --git a/lib/_BasePdoOneRepo.php b/lib/_BasePdoOneRepo.php
index 8f7a0dc..9ed4a60 100644
--- a/lib/_BasePdoOneRepo.php
+++ b/lib/_BasePdoOneRepo.php
@@ -9,8 +9,6 @@
* @noinspection DisconnectedForeachInstructionInspection
* @noinspection PhpUnused
* @noinspection NullPointerExceptionInspection
- * @noinspection PhpUndefinedMethodInspection
- * @noinspection PhpUndefinedClassConstantInspection
*/
namespace eftec;
@@ -23,7 +21,7 @@
/**
* Class _BasePdoOneRepo
*
- * @version 4.14 2021-02-16
+ * @version 4.15 2021-03-22
* @package eftec
* @author Jorge Castro Castillo
* @copyright (c) Jorge Castro C. MIT License https://github.com/EFTEC/PdoOne
@@ -31,9 +29,11 @@
abstract class _BasePdoOneRepo
{
// it is used for compatibility.
- const BINARYVERSION=3;
+ const BINARYVERSION = 4;
/** @var PdoOne */
public static $pdoOne;
+ /** @var PdoOneQuery */
+ public static $pdoOneQuery;
/** @var array $gQuery =[['columns'=>[],'joins'=>[],'where'=>[]] */
public static $gQuery = [];
public static $gQueryCounter = 0;
@@ -111,8 +111,8 @@ protected static function getPdoOne()
if (self::$pdoOne !== null) {
return self::$pdoOne;
}
- if(self::BINARYVERSION!==static::COMPILEDVERSION) {
- throw new RuntimeException(self::class.' requires a new version');
+ if (self::BINARYVERSION !== static::COMPILEDVERSION) {
+ throw new RuntimeException(self::class . ' requires a new version');
}
if (function_exists('PdoOne')) {
return PdoOne();
@@ -123,6 +123,16 @@ protected static function getPdoOne()
return null;
}
+ /**
+ * @return PdoOneQuery
+ */
+ protected static function getQuery() {
+ if(self::$pdoOneQuery===null) {
+ return new PdoOneQuery(self::getPdoOne());
+ }
+ return self::$pdoOneQuery;
+ }
+
/**
* It sets the field self::$pdoOne
*
@@ -147,7 +157,7 @@ protected static function reset($forcedPdoOne = false)
self::$gQuery = [];
self::$falseOnError = false;
self::$lastException = '';
- self::getPdoOne()->builderReset($forcedPdoOne);
+ self::getQuery()->builderReset($forcedPdoOne);
}
/**
@@ -184,11 +194,12 @@ public static function testRecursive($initClass = null, $recursiveInit = '')
$local = static::NS . $initClass;
}
//$recursive=$local::getPdoOne()->getRecursive();
+ /** @noinspection PhpUndefinedMethodInspection */
$relations = $local::getDefFK();
foreach ($relations as $nameCol => $r) {
$key = $r['key'];
$recursiveComplete = ltrim($recursiveInit . '/' . $nameCol, '/');
- if (self::getPdoOne()->hasRecursive($recursiveComplete)) {
+ if (self::getQuery()->hasRecursive($recursiveComplete)) {
$used = '';
} else {
$used = '// ';
@@ -196,22 +207,22 @@ public static function testRecursive($initClass = null, $recursiveInit = '')
switch ($key) {
case 'PARENT':
$class = static::RELATIONS[$r['reftable']];
- echo "// \$relation['".$recursiveComplete. "']; //".$local . '->' . $class . " ($key) ";
+ echo "// \$relation['" . $recursiveComplete . "']; //" . $local . '->' . $class . " ($key) ";
break;
case 'MANYTOONE':
case 'ONETOONE':
case 'ONETOMANY':
$class = static::RELATIONS[$r['reftable']];
- echo $used."\$relation['".$recursiveComplete. "']; //".$local . '->' . $class . " ($key) ";
- if($used==='') {
- self::testRecursive($class,$recursiveComplete);
+ echo $used . "\$relation['" . $recursiveComplete . "']; //" . $local . '->' . $class . " ($key) ";
+ if ($used === '') {
+ self::testRecursive($class, $recursiveComplete);
}
break;
case 'MANYTOMANY':
$class = static::RELATIONS[$r['table2']];
- echo $used."\$relation['".$recursiveComplete. "']; //".$local . '->' . $class . " ($key) ";
- if($used!=='') {
- self::testRecursive($class,$recursiveComplete);
+ echo $used . "\$relation['" . $recursiveComplete . "']; //" . $local . '->' . $class . " ($key) ";
+ if ($used !== '') {
+ self::testRecursive($class, $recursiveComplete);
}
break;
}
@@ -265,10 +276,10 @@ public static function createForeignKeys()
public static function query($sql, $param = null)
{
try {
- $pdoOne = self::getPdoOne();
- if (self::$useCache && $pdoOne->getCacheService() !== null) {
+ $pdoOne = self::getQuery();
+ if (self::$useCache && $pdoOne->parent->getCacheService() !== null) {
self::$uid = $pdoOne->buildUniqueID([$sql, $param], 'query');
- $getCache = $pdoOne->getCacheService()->getCache(self::$uid, static::TABLE);
+ $getCache = $pdoOne->parent->getCacheService()->getCache(self::$uid, static::TABLE);
if ($getCache !== false) {
self::reset();
return $getCache;
@@ -281,7 +292,7 @@ public static function query($sql, $param = null)
}
$rowc = self::getPdoOne()->runRawQuery($sql, $param);
if ($rowc !== false && $usingCache) {
- $pdoOne->getCacheService()->setCache(self::$uid, $recursiveClass, $rowc, self::$useCache);
+ $pdoOne->parent->getCacheService()->setCache(self::$uid, $recursiveClass, $rowc, self::$useCache);
self::reset();
}
} catch (Exception $exception) {
@@ -329,6 +340,8 @@ public static function getRecursiveClass(&$final = null, $prefix = '')
if (!in_array($className, $final, true)) {
$final[] = $className;
}
+
+ /** @noinspection PhpUndefinedMethodInspection */
$class::getRecursiveClass($final, $keyr);
if ($keyRels[$keyr]['key'] === 'MANYTOMANY') {
$className
@@ -337,6 +350,7 @@ public static function getRecursiveClass(&$final = null, $prefix = '')
if (!in_array($className, $final, true)) {
$final[] = $className;
}
+ /** @noinspection PhpUndefinedMethodInspection */
$class::getRecursiveClass($final, $keyr);
}
}
@@ -517,7 +531,7 @@ public static function getPostfix()
*/
public static function useCache($ttl = null, $family = '')
{
- self::getPdoOne()->useCache($ttl, $family);
+ self::getQuery()->useCache($ttl, $family);
self::$useCache = $ttl;
return static::ME;
}
@@ -570,7 +584,7 @@ public static function order($order)
*/
public static function innerjoin($sql, $condition = '')
{
- self::getPdoOne()->innerjoin($sql, $condition);
+ self::getQuery()->innerjoin($sql, $condition);
return static::ME;
}
@@ -617,10 +631,10 @@ public static function group($sql)
*/
public static function count($where = null)
{
- $pdoOne = self::getPdoOne();
- if (self::$useCache && $pdoOne->getCacheService() !== null) {
+ $pdoOne = self::getQuery();
+ if (self::$useCache && $pdoOne->parent->getCacheService() !== null) {
self::$uid = $pdoOne->buildUniqueID([$where], static::TABLE . '::count');
- $getCache = $pdoOne->getCacheService()->getCache(self::$uid, static::TABLE);
+ $getCache = $pdoOne->parent->getCacheService()->getCache(self::$uid, static::TABLE);
if ($getCache !== false) {
self::reset();
return $getCache;
@@ -640,7 +654,7 @@ public static function count($where = null)
$from = (isset(self::$gQuery[0]['joins'])) ? self::$gQuery[0]['joins'] : [];
$rowc = self::getPdoOne()->count()->from($from)->where($where)->firstScalar();
if ($rowc !== false && $usingCache) {
- $pdoOne->getCacheService()->setCache(self::$uid, $recursiveClass, (int)$rowc, self::$useCache);
+ $pdoOne->parent->getCacheService()->setCache(self::$uid, $recursiveClass, (int)$rowc, self::$useCache);
self::reset();
}
return $rowc;
@@ -679,7 +693,7 @@ protected static function generationRecursive(
// $nameColClean = trim($nameCol, PdoOne::$prefixBase);
$recursiveComplete = ltrim($recursiveInit . '/' . $nameCol, '/');
//echo "check recursive: $recursiveComplete ";
- if (self::getPdoOne()->hasRecursive($recursiveComplete)) {
+ if (self::getQuery()->hasRecursive($recursiveComplete)) {
//echo "OK $type ";
// type='PARENT' is n
switch ($type) {
@@ -694,6 +708,7 @@ protected static function generationRecursive(
$refCol = ltrim($keyRel['refcol'], PdoOne::$prefixBase);
$newQuery['joins'] .= " left join {$keyRel['reftable']} as $tableRelAlias "
. "on {$pt}{$col}=$tableRelAlias.$refCol \n"; // $recursiveInit$nameCol\n"; // adds a query to the current query
+ /** @noinspection PhpUndefinedMethodInspection */
$class::generationRecursive($newQuery, $tableRelAlias . '.', $colRelAlias . '.',
$recursiveComplete, false); // $recursiveInit . $nameCol
break;
@@ -708,6 +723,7 @@ protected static function generationRecursive(
$newQuery['joins'] .= " left join {$keyRel['reftable']} as $tableRelAlias "
. "on {$pt}{$col}=$tableRelAlias.$refCol \n"; // $recursiveInit$nameCol\n"; // adds a query to the current query
+ /** @noinspection PhpUndefinedMethodInspection */
$class::generationRecursive($newQuery, $tableRelAlias . '.', $colRelAlias . '.',
$recursiveComplete, false); // $recursiveInit . $nameCol
break;
@@ -727,6 +743,7 @@ protected static function generationRecursive(
//self::$gQuery[]=$other;
$class = $ns
. static::RELATIONS[$keyRel['reftable']]; // $ns . PdoOne::camelize($keyRel['reftable']) . $postfix;
+ /** @noinspection PhpUndefinedMethodInspection */
$class::generationRecursive($other, '', '', $pColumn . $recursiveComplete,
false); //$recursiveInit . $nameCol
self::$gQuery[] = $other;
@@ -750,6 +767,7 @@ protected static function generationRecursive(
$other['data'] = $keyRel;
$class = $ns
. static::RELATIONS[$keyRel['reftable']]; // $ns . PdoOne::camelize($keyRel['reftable']) . $postfix;
+ /** @noinspection PhpUndefinedMethodInspection */
$class::generationRecursive($other, '', '', $pColumn . $recursiveComplete,
false); //$recursiveInit . $nameCol
// we reduce a level
@@ -788,6 +806,109 @@ protected static function generationRecursive(
}
}
+ /**
+ * This method validates a model before it is inserted/updated into the database.
+ *
+ * @param object|array $model It could be one model or multiple models.
+ * @param boolean $multiple if true then it validates multiples models at once.
+ * @param array $recursive =self::factory()
+ * @return bool if true then the model is valid, otherwise its false.
+ */
+ public static function validateModel($model, $multiple = false, $recursive = [])
+ {
+ if ($multiple) {
+ if ($model === null || count($model) === 0) {
+ return true;
+ }
+ $array = $model;
+ } else {
+ $array[0] = $model;
+ }
+ $defs = static::getDef();
+ $fks = static::getDefFK();
+ foreach ($array as $mod) {
+ if (is_object($mod)) {
+ $mod = (array)$mod;
+ }
+ foreach ($defs as $col => $def) {
+ $curCol = array_key_exists($col, $mod) ? $mod[$col] : null;
+
+ // if null (or missing) and it is allowed = true
+ // if null (or missing) and not null and it is not identity = false (identities are generated)
+ if (($curCol === null) && !($def['null'] === false && $def['identity'] === false)) {
+ return false;
+ }
+ switch ($def['phptype']) {
+ case 'binary':
+ case 'string':
+ if (!is_string($curCol)) {
+ // not a string
+ return false;
+ }
+ break;
+ case 'float':
+ if (!is_float($curCol)) {
+ return false;
+ }
+ break;
+ case 'timestamp':
+ case 'int':
+ if (!is_int($curCol)) {
+ return false;
+ }
+ break;
+ case 'time':
+ case 'datetime':
+ case 'date':
+ $bool = false;
+ $time = false;
+ $r = false;
+ if ($def['conversion'] === 'datetime2') {
+ $r = PdoOne::dateConvertInput($curCol, 'iso', $bool, $time);
+ } elseif ($def['conversion'] === 'datetime3') {
+ $r = PdoOne::dateConvertInput($curCol, 'human', $bool, $time);
+ } elseif ($def['conversion'] === 'datetime') {
+ $r = PdoOne::dateConvertInput($curCol, 'class', $bool, $time);
+ } elseif ($def['conversion'] === 'datetime4') {
+ $r = PdoOne::dateConvertInput($curCol, 'sql', $bool, $time);
+ }
+ if ($r === false) {
+ return false;
+ }
+ }
+ }
+ if (count($recursive) > 0) {
+ $ns = self::getNamespace();
+ foreach ($fks as $key => $fk) {
+ if (array_key_exists($key, $mod) && self::getQuery()->hasRecursive($key, $recursive)) {
+ $curFK = $fk['key'];
+ $class = $ns . static::RELATIONS[$fk['reftable']];
+ switch ($curFK) {
+ case 'ONETOMANY':
+ case 'MANYTOMANY':
+ /** @noinspection PhpUndefinedMethodInspection */
+ $r = $class::validateModel($mod[$key], true, $recursive);
+ break;
+ case 'MANYTOONE':
+ case 'ONETOONE':
+ /** @noinspection PhpUndefinedMethodInspection */
+ $r = $class::validateModel($mod[$key], false, $recursive);
+ break;
+ default:
+ $r = true;
+ }
+ if ($r === false) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+
+ return true;
+ }
+
protected static function _merge($entity, $transaction = true)
{
if (static::_exist($entity)) {
@@ -831,6 +952,18 @@ protected static function _exist($entity)
}
}
+ protected static function objectToArray($obj)
+ {
+ if (is_object($obj) || is_array($obj)) {
+ $ret = (array)$obj;
+ foreach ($ret as &$item) {
+ $item = self::objectToArray($item);
+ }
+ return $ret;
+ }
+ return $obj;
+ }
+
/**
* Update an registry
*
@@ -847,21 +980,21 @@ protected static function _update($entity, $transaction = true)
if (is_object($entity)) {
$entity = static::objectToArray($entity);
}
- $pdoOne = self::getPdoOne();
+ $pdoOne = self::getQuery();
//$defTable = static::getDef('conversion');
(static::ME)::convertInputVal($entity);
self::invalidateCache();
// only the fields that are defined are inserted
$entityCopy = self::intersectArraysNotNull($entity, static::getDefName());
$entityCopy = self::diffArrays($entityCopy, array_merge(static::getDefKey(), static::getDefNoUpdate())); // columns discarded
- if ($pdoOne->transactionOpen === true) {
+ if ($pdoOne->parent->transactionOpen === true) {
// we disable transaction to avoid nested transactions.
// mysql does not allows nested transactions
// sql server allows nested transaction but afaik, it only counts the outer one.
$transaction = false;
}
if ($transaction) {
- $pdoOne->startTransaction();
+ $pdoOne->parent->startTransaction();
}
$recursiveBack = $pdoOne->getRecursive();
$r = $pdoOne->from(static::TABLE)->set($entityCopy)->where(static::intersectArrays($entity, static::PK))
@@ -889,6 +1022,7 @@ protected static function _update($entity, $transaction = true)
//self::_setRecursive([$def['refcol2']]);
self::_setRecursive([]);
+ /** @noinspection PhpUndefinedMethodInspection */
$oldRows = ($classRef::where($refcol, $entity[$col1]))::_toList();
$oldRowsKeys = [];
foreach ($oldRows as $v) {
@@ -900,12 +1034,15 @@ protected static function _update($entity, $transaction = true)
foreach ($newRows as $item) {
if (in_array($item[$refpk], $insertKeys, false)) {
$item[$refcol] = $fatherPK;
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::insert($item, false);
} elseif (!in_array($item[$refpk], $deleteKeys, false)) {
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::update($item, false);
}
}
foreach ($deleteKeys as $key2) {
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::deleteById($key2, false);
}
}
@@ -929,6 +1066,7 @@ protected static function _update($entity, $transaction = true)
}
//self::_setRecursive([$def['refcol2']]);
self::_setRecursive([]);
+ /** @noinspection PhpUndefinedMethodInspection */
$oldRows = ($classRef::where($refcol, $entity[$col1]))::_toList();
$oldRowsKeys = [];
foreach ($oldRows as $v) {
@@ -940,14 +1078,18 @@ protected static function _update($entity, $transaction = true)
foreach ($newRows as $item) {
if (in_array($item[$col2], $insertKeys, false)) {
$pk2 = $item[$def['col2']];
+ /** @noinspection PhpUndefinedMethodInspection */
if ($class2::exist($item) === false
&& self::getPdoOne()->hasRecursive($key, $recursiveBack)
) {
+ /** @noinspection PhpUndefinedMethodInspection */
$pk2 = $class2::insert($item, false);
} else {
+ /** @noinspection PhpUndefinedMethodInspection */
$class2::update($item, false);
}
$relationalObjInsert = [$refcol => $entity[$def['col']], $refcol2 => $pk2];
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::insert($relationalObjInsert, false);
}
}
@@ -955,10 +1097,12 @@ protected static function _update($entity, $transaction = true)
foreach ($newRows as $item) {
if (in_array($item[$col2], $deleteKeys)) {
$pk2 = $item[$def['col2']];
- if (self::getPdoOne()->hasRecursive($key, $recursiveBack)) {
+ if ($pdoOne->hasRecursive($key, $recursiveBack)) {
+ /** @noinspection PhpUndefinedMethodInspection */
$class2::deleteById($item, $pk2);
}
$relationalObjDelete = [$refcol => $entity[$def['col']], $refcol2 => $pk2];
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::deleteById($relationalObjDelete, false);
}
}
@@ -982,7 +1126,6 @@ protected static function _update($entity, $transaction = true)
}
}
-
/**
* It invalidates a family/group of cache
* Example
@@ -1139,7 +1282,7 @@ protected static function _insert(&$entity, $transaction = true)
{
$returnObject = false;
try {
- $pdoOne = self::getPdoOne();
+ $pdoOne = self::getQuery();
//$defTable = static::getDef('conversion');
//self::_convertInputValue($entity, $defTable);
@@ -1159,14 +1302,14 @@ protected static function _insert(&$entity, $transaction = true)
' and case of the fields', $entity);
return false;
}
- if ($pdoOne->transactionOpen === true) {
+ if ($pdoOne->parent->transactionOpen === true) {
// we disable transaction to avoid nested transactions.
// mysql does not allows nested transactions
// sql server allows nested transaction but afaik, it only counts the outer one.
$transaction = false;
}
if ($transaction) {
- $pdoOne->startTransaction();
+ $pdoOne->parent->startTransaction();
}
$insert = $pdoOne->insertObject(static::TABLE, $entityCopy);
$pks = static::IDENTITY;
@@ -1193,6 +1336,7 @@ protected static function _insert(&$entity, $transaction = true)
$refCol = ltrim($def['refcol'], PdoOne::$prefixBase);
$item[$refCol]
= $entityCopy[$def['col']]; // if the pk (of the original object) is identity.
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::insert($item, false);
}
}
@@ -1201,8 +1345,10 @@ protected static function _insert(&$entity, $transaction = true)
. static::RELATIONS[$def['table2']]; // $ns . PdoOne::camelize($def['table2']) . $postfix;
foreach ($entity[$key] as $item) {
$pk2 = $item[$def['col2']];
+ /** @noinspection PhpUndefinedMethodInspection */
if ($pdoOne->hasRecursive($key, $recursiveBack) && $class2::exist($item) === false) {
// we only update it if it has a recursive
+ /** @noinspection PhpUndefinedMethodInspection */
$pk2 = $class2::insert($item, false);
}
$classRel = $ns
@@ -1210,6 +1356,7 @@ protected static function _insert(&$entity, $transaction = true)
$refCol = ltrim($def['refcol'], PdoOne::$prefixBase);
$refCol2 = ltrim($def['refcol2'], PdoOne::$prefixBase);
$relationalObj = [$refCol => $entityCopy[$def['col']], $refCol2 => $pk2];
+ /** @noinspection PhpUndefinedMethodInspection */
$classRel::insert($relationalObj, false);
}
}
@@ -1242,19 +1389,6 @@ protected static function _insert(&$entity, $transaction = true)
}
}
-
- protected static function objectToArray($obj)
- {
- if (is_object($obj) || is_array($obj)) {
- $ret = (array)$obj;
- foreach ($ret as &$item) {
- $item = self::objectToArray($item);
- }
- return $ret;
- }
- return $obj;
- }
-
/**
* @param mixed $filter
* @param mixed $filterValue
@@ -1287,11 +1421,10 @@ protected static function generationStart($type, $filter = PdoOne::NULL, $filter
try {
static::$gQuery = [];
static::$gQueryCounter = 0;
- /** @var PdoOne $pdoOne instance of PdoOne */
- $pdoOne = self::getPdoOne();
- if (self::$useCache && $pdoOne->getCacheService() !== null) {
+ $pdoOne = self::getQuery();
+ if (self::$useCache && $pdoOne->parent->getCacheService() !== null) {
self::$uid = $pdoOne->buildUniqueID([$filter, $filterValue], static::TABLE . '::' . $type);
- $getCache = $pdoOne->getCacheService()->getCache(self::$uid, static::TABLE);
+ $getCache = $pdoOne->parent->getCacheService()->getCache(self::$uid, static::TABLE);
if ($getCache !== false) {
self::reset();
return $getCache;
@@ -1358,7 +1491,7 @@ protected static function generationStart($type, $filter = PdoOne::NULL, $filter
self::convertSQLValueInit($rowc, true);
}
if ($rowc !== false && $usingCache) {
- $pdoOne->getCacheService()->setCache(self::$uid, $recursiveClass, $rowc, self::$useCache);
+ $pdoOne->parent->getCacheService()->setCache(self::$uid, $recursiveClass, $rowc, self::$useCache);
}
self::reset();
return $rowc;
@@ -1442,14 +1575,17 @@ protected static function convertSQLValueInit(&$rows, $list = false)
// PARENT not because parent is a fk but is used for a one way relation.
case 'MANYTOONE':
$class = $ns . static::RELATIONS[$v['reftable']];
+ /** @noinspection PhpUndefinedMethodInspection */
$class::convertSQLValueInit($row[$k], false);
break;
case 'ONETOMANY':
$class = $ns . static::RELATIONS[$v['reftable']];
+ /** @noinspection PhpUndefinedMethodInspection */
$class::convertSQLValueInit($row[$k], true);
break;
case 'MANYTOMANY':
$class = $ns . static::RELATIONS[$v['table2']];
+ /** @noinspection PhpUndefinedMethodInspection */
$class::convertSQLValueInit($row[$k], true);
break;
}
@@ -1461,107 +1597,6 @@ protected static function convertSQLValueInit(&$rows, $list = false)
}
}
- /**
- * This method validates a model before it is inserted/updated into the database.
- *
- * @param object|array $model It could be one model or multiple models.
- * @param boolean $multiple if true then it validates multiples models at once.
- * @param array $recursive =self::factory()
- * @return bool if true then the model is valid, otherwise its false.
- */
- public static function validateModel($model, $multiple = false, $recursive = [])
- {
- if ($multiple) {
- if ($model === null || count($model) === 0) {
- return true;
- }
- $array = $model;
- } else {
- $array[0] = $model;
- }
- $defs = static::getDef();
- $fks = static::getDefFK();
- foreach ($array as $mod) {
- if (is_object($mod)) {
- $mod = (array)$mod;
- }
- foreach ($defs as $col => $def) {
- $curCol = array_key_exists($col, $mod) ? $mod[$col] : null;
-
- // if null (or missing) and it is allowed = true
- // if null (or missing) and not null and it is not identity = false (identities are generated)
- if (($curCol === null) && !($def['null'] === false && $def['identity'] === false)) {
- return false;
- }
- switch ($def['phptype']) {
- case 'binary':
- case 'string':
- if (!is_string($curCol)) {
- // not a string
- return false;
- }
- break;
- case 'float':
- if (!is_float($curCol)) {
- return false;
- }
- break;
- case 'timestamp':
- case 'int':
- if (!is_int($curCol)) {
- return false;
- }
- break;
- case 'time':
- case 'datetime':
- case 'date':
- $bool = false;
- $time = false;
- $r = false;
- if ($def['conversion'] === 'datetime2') {
- $r = PdoOne::dateConvertInput($curCol, 'iso', $bool, $time);
- } elseif ($def['conversion'] === 'datetime3') {
- $r = PdoOne::dateConvertInput($curCol, 'human', $bool, $time);
- } elseif ($def['conversion'] === 'datetime') {
- $r = PdoOne::dateConvertInput($curCol, 'class', $bool, $time);
- } elseif ($def['conversion'] === 'datetime4') {
- $r = PdoOne::dateConvertInput($curCol, 'sql', $bool, $time);
- }
- if ($r === false) {
- return false;
- }
- }
- }
- if (count($recursive) > 0) {
- $ns = self::getNamespace();
- foreach ($fks as $key => $fk) {
- if (array_key_exists($key, $mod) && self::getPdoOne()->hasRecursive($key, $recursive)) {
- $curFK = $fk['key'];
- $class = $ns . static::RELATIONS[$fk['reftable']];
- switch ($curFK) {
- case 'ONETOMANY':
- case 'MANYTOMANY':
- $r = $class::validateModel($mod[$key], true, $recursive);
- break;
- case 'MANYTOONE':
- case 'ONETOONE':
- $r = $class::validateModel($mod[$key], false, $recursive);
- break;
- default:
- $r=true;
- }
- if ($r === false) {
- return false;
- }
- }
- }
- }
- }
-
-
- return true;
- }
-
/**
* It deletes a registry
*
@@ -1602,15 +1637,15 @@ protected static function _delete($entity, $transaction = true, $columns = null)
}
$entityCopy = self::intersectArraysNotNull($entity, $columns);
self::invalidateCache();
- $pdoOne = self::getPdoOne();
- if ($pdoOne->transactionOpen === true) {
+ $pdoOne = self::getQuery();
+ if ($pdoOne->parent->transactionOpen === true) {
// we disable transaction to avoid nested transactions.
// mysql does not allows nested transactions
// sql server allows nested transaction but afaik, it only counts the outer one.
$transaction = false;
}
if ($transaction) {
- $pdoOne->startTransaction();
+ $pdoOne->parent->startTransaction();
}
$defs = static::getDefFK();
$ns = self::getNamespace();
@@ -1628,6 +1663,7 @@ protected static function _delete($entity, $transaction = true, $columns = null)
//$refcol = ltrim($def['refcol'], PdoOne::$prefixBase); // it is how they are joined
//$refpk = $classRef::PK[0];
foreach ($newRows as $item) {
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::deleteById($item, false);
}
}
@@ -1649,11 +1685,13 @@ protected static function _delete($entity, $transaction = true, $columns = null)
$cols2[] = $item[$col2];
}
$relationalObjDelete = [$refcol => $entity[$col1]];
+ /** @noinspection PhpUndefinedMethodInspection */
$classRef::delete($relationalObjDelete, false);
- if (self::getPdoOne()->hasRecursive($key, $recursiveBackup)) {
+ if (self::getQuery()->hasRecursive($key, $recursiveBackup)) {
foreach ($cols2 as $c2) {
// $k = $v[$refcol2];
$object2Delete = [$col2 => $c2];
+ /** @noinspection PhpUndefinedMethodInspection */
$class2::delete($object2Delete, false);
}
}
@@ -1726,7 +1764,7 @@ protected static function _first($pk = PdoOne::NULL)
*
* @return self
*/
- public function having($sql, $param = self::NULL)
+ public function having($sql, $param = PdoOne::NULL)
{
self::getPdoOne()->having($sql, $param);
return static::ME;
diff --git a/lib/ext/PdoOne_IExt.php b/lib/ext/PdoOne_IExt.php
index d475453..9ca716d 100644
--- a/lib/ext/PdoOne_IExt.php
+++ b/lib/ext/PdoOne_IExt.php
@@ -206,6 +206,7 @@ public function createFK($tableName,$foreignKey);
*
*
* @param $sql
+ * @return string
*
* @throws Exception
*/
diff --git a/lib/ext/PdoOne_Mysql.php b/lib/ext/PdoOne_Mysql.php
index 1f88632..dd0ba3e 100644
--- a/lib/ext/PdoOne_Mysql.php
+++ b/lib/ext/PdoOne_Mysql.php
@@ -1,4 +1,4 @@
-parent->limit = ($sql) ? ' limit ' . $sql : '';
+ return ($sql) ? ' limit ' . $sql : '';
}
diff --git a/lib/ext/PdoOne_Oci.php b/lib/ext/PdoOne_Oci.php
index cadd325..43b2241 100644
--- a/lib/ext/PdoOne_Oci.php
+++ b/lib/ext/PdoOne_Oci.php
@@ -1,4 +1,7 @@
-'',"ColumnName"=>'',"is_unique"=>0,"is_primary_key"=>0,"TYPE"=>0]) */
- $pks=$this->getPK($table,null);
+ $pks=$this->getPK($table);
$result =
$this->parent->select('SELECT ALL_indexes.INDEX_NAME "IndexName",all_ind_columns.COLUMN_NAME "ColumnName",
(CASE WHEN UNIQUENESS = \'UNIQUE\' THEN 1 ELSE 0 END) "is_unique",0 "is_primary_key",0 "TYPE"')
@@ -434,10 +437,9 @@ public function foreignKeyTable($tableName)
public function createSequence($tableSequence = null, $method = 'snowflake')
{
- $sql = "CREATE SEQUENCE {$tableSequence}
+ return "CREATE SEQUENCE {$tableSequence}
START WITH 1
INCREMENT BY 1";
- return $sql;
}
public function getSequence($sequenceName) {
$sequenceName = ($sequenceName == '') ? $this->parent->tableSequence : $sequenceName;
@@ -526,15 +528,15 @@ public function createFK($tableName, $foreignKey)
public function limit($sql)
{
//throw new RuntimeException("no yet implemented");
- if (!$this->parent->order) {
- $this->parent->throwError('limit without a sort', '');
- }
+ //if (!$this->parent->order) {
+ // $this->parent->throwError('limit without a sort', '');
+ //}
if (strpos($sql, ',')) {
$arr = explode(',', $sql);
- $this->parent->limit = " OFFSET {$arr[0]} ROWS FETCH NEXT {$arr[1]} ROWS ONLY";
- } else {
- $this->parent->limit = " OFFSET 0 ROWS FETCH NEXT $sql ROWS ONLY";
+ return " OFFSET {$arr[0]} ROWS FETCH NEXT {$arr[1]} ROWS ONLY";
}
+
+ return " OFFSET 0 ROWS FETCH NEXT $sql ROWS ONLY";
}
public function getPK($query, $pk=null)
diff --git a/lib/ext/PdoOne_Sqlsrv.php b/lib/ext/PdoOne_Sqlsrv.php
index bbc0865..aae6827 100644
--- a/lib/ext/PdoOne_Sqlsrv.php
+++ b/lib/ext/PdoOne_Sqlsrv.php
@@ -1,4 +1,7 @@
-parent->order) {
- $this->parent->throwError('limit without a sort', '');
- }
+ //if (!$this->parent->order) {
+ // $this->parent->throwError('limit without a sort', '');
+ //}
if (strpos($sql, ',')) {
$arr = explode(',', $sql);
- $this->parent->limit = " OFFSET {$arr[0]} ROWS FETCH NEXT {$arr[1]} ROWS ONLY";
- } else {
- $this->parent->limit = " OFFSET 0 ROWS FETCH NEXT $sql ROWS ONLY";
+ return " OFFSET {$arr[0]} ROWS FETCH NEXT {$arr[1]} ROWS ONLY";
}
+
+ return " OFFSET 0 ROWS FETCH NEXT $sql ROWS ONLY";
}
public function getPK($query, $pk=null)
diff --git a/lib/ext/PdoOne_TestMockup.php b/lib/ext/PdoOne_TestMockup.php
index 3244a09..e849957 100644
--- a/lib/ext/PdoOne_TestMockup.php
+++ b/lib/ext/PdoOne_TestMockup.php
@@ -1,4 +1,5 @@
-parent->order) {
- $this->parent->throwError('limit without a sort', '');
- }
+ //if (!$this->parent->order) {
+ // $this->parent->throwError('limit without a sort', '');
+ //}
if (strpos($sql, ',')) {
$arr = explode(',', $sql);
- $this->parent->limit = " OFFSET {$arr[0]} ROWS FETCH NEXT {$arr[1]} ROWS ONLY";
- } else {
- $this->parent->limit = " OFFSET 0 ROWS FETCH NEXT $sql ROWS ONLY";
+ return " OFFSET {$arr[0]} ROWS FETCH NEXT {$arr[1]} ROWS ONLY";
}
+
+ return " OFFSET 0 ROWS FETCH NEXT $sql ROWS ONLY";
}
public function getPK($query, $pk=null)
diff --git a/tests/PdoOne_mysql_Test.php b/tests/PdoOne_mysql_Test.php
index 2a04edb..522da03 100644
--- a/tests/PdoOne_mysql_Test.php
+++ b/tests/PdoOne_mysql_Test.php
@@ -1,4 +1,7 @@
-cacheData[$uid])) {
$this->cacheCounter++;
return $this->cacheData[$uid];
@@ -56,7 +60,7 @@ public function setCache($uid, $family = '', $data = null, $ttl = null)
if (!isset($this->cacheDataFamily[$fam])) {
$this->cacheDataFamily[$fam] = [];
}
-
+
$this->cacheDataFamily[$fam][] = $uid;
$this->cacheData[$uid] = $data;
//var_dump($fam);
@@ -84,11 +88,11 @@ public function invalidateCache($uid = '', $family = '')
$family = [$family];
}
foreach ($family as $fam) {
- foreach($this->cacheDataFamily[$fam] as $id) {
+ foreach ($this->cacheDataFamily[$fam] as $id) {
unset($this->cacheData[$id]);
echo "deleting cache $id\n";
}
- $this->cacheDataFamily[$fam]=[];
+ $this->cacheDataFamily[$fam] = [];
}
}
//unset($this->cacheData[$uid]);
@@ -151,7 +155,7 @@ public function test_connect()
$this->pdoOne->connect();
}
- function test_chainresetErrorList()
+ public function test_chainresetErrorList()
{
$this->pdoOne->logLevel = 3;
$rows = $this->pdoOne->genError(false)->select('select 123 field1 from dual222')->toList();
@@ -180,7 +184,7 @@ function test_chainresetErrorList()
self::assertNotEmpty($this->pdoOne->errorText); // there is an error.
}
- function test_chainresetErrorListSimple()
+ public function test_chainresetErrorListSimple()
{
$this->pdoOne->logLevel = 3;
$rows = $this->pdoOne->genError(false)->select('select 123 field1 from dual222')->toListSimple();
@@ -209,7 +213,7 @@ function test_chainresetErrorListSimple()
self::assertNotEmpty($this->pdoOne->errorText); // there is an error.
}
- function test_genCode()
+ public function test_genCode()
{
if (!$this->pdoOne->tableExist('table1')) {
$this->pdoOne->createTable('table1', ['id' => 'int']);
@@ -221,7 +225,7 @@ function test_genCode()
self::assertContains('$pdo->createTable(\'table1', $this->pdoOne->generateCodeCreate('table1'));
}
- function test_debug()
+ public function test_debug()
{
$file = __DIR__ . '/file.txt';
$this->pdoOne->logFile = $file;
@@ -231,7 +235,7 @@ function test_debug()
$this->pdoOne->logFile = '';
}
- function test_chainresetErrorMeta()
+ public function test_chainresetErrorMeta()
{
$this->pdoOne->logLevel = 3;
$rows = $this->pdoOne->genError(false)->select('select 123 field1 from dual222')->toMeta();
@@ -260,7 +264,7 @@ function test_chainresetErrorMeta()
self::assertNotEmpty($this->pdoOne->errorText); // there is an error.
}
- function test_chainresetErrorFirst()
+ public function test_chainresetErrorFirst()
{
$this->pdoOne->logLevel = 3;
$rows = $this->pdoOne->genError(false)->select('select 123 field1 from dual222')->first();
@@ -293,7 +297,7 @@ function test_chainresetErrorFirst()
//$this->assertEquals([['field1'=>123]],$rows);
}
- function test_chainresetErrorLast()
+ public function test_chainresetErrorLast()
{
$this->pdoOne->logLevel = 3;
$rows = $this->pdoOne->genError(false)->select('select 123 field1 from dual222')->last();
@@ -302,6 +306,7 @@ function test_chainresetErrorLast()
$rows = $this->pdoOne->genError(true)->select('select 123 field1 from dual222')->last();
$rows = 'XXX';
} catch (Exception $exception) {
+ var_dump("this message must be visible");
$rows = false;
}
self::assertEquals(false, $rows);
@@ -324,7 +329,7 @@ function test_chainresetErrorLast()
}
- function test_createtable()
+ public function test_createtable()
{
if ($this->pdoOne->tableExist('table5')) {
$this->pdoOne->dropTable('table5');
@@ -334,23 +339,23 @@ function test_createtable()
self::assertEquals(true, $r);
self::assertEquals(array(
- 'id' => [
- 'phptype' => 'int',
+ 'id' => [
+ 'phptype' => 'int',
'conversion' => null,
- 'type' => 'int',
- 'size' => null,
- 'null' => false,
- 'identity' => false,
- 'sql' => 'int not null'
+ 'type' => 'int',
+ 'size' => null,
+ 'null' => false,
+ 'identity' => false,
+ 'sql' => 'int not null'
],
'name' => [
- 'phptype' => 'string',
+ 'phptype' => 'string',
'conversion' => null,
- 'type' => 'varchar',
- 'size' => '50',
- 'null' => true,
- 'identity' => false,
- 'sql' => 'varchar(50)'
+ 'type' => 'varchar',
+ 'size' => '50',
+ 'null' => true,
+ 'identity' => false,
+ 'sql' => 'varchar(50)'
]
), $this->pdoOne->getDefTable('table5'));
@@ -359,16 +364,16 @@ function test_createtable()
}
- function test_chainreset()
+ public function test_chainreset()
{
$this->pdoOne->logLevel = 3;
$rows = $this->pdoOne->select('select 123 field1 from dual');
- $this->pdoOne->builderReset();
+ // $this->pdoOne->builderReset();
$rows = $this->pdoOne->select('select 123 field1 from dual')->toList();
self::assertEquals([['field1' => 123]], $rows);
}
- function test_cache()
+ public function test_cache()
{
$this->pdoOne->getCacheService()->cacheCounter = 0;
@@ -381,8 +386,6 @@ function test_cache()
self::assertEquals([['field1' => 123]], $rows);
-
-
self::assertEquals(1, $this->pdoOne->getCacheService()->cacheCounter); // 1= cache used 1 time
$this->pdoOne->invalidateCache();
$rows = $this->pdoOne->select('select 123 field1 from dual')->useCache()
@@ -392,7 +395,7 @@ function test_cache()
$this->pdoOne->getCacheService()->cacheCounter = 0;
}
- function test_cache_expire()
+ public function test_cache_expire()
{
$this->pdoOne->getCacheService()->cacheCounter = 0;
$this->pdoOne->invalidateCache();
@@ -400,10 +403,10 @@ function test_cache_expire()
sleep(2); // enough time to expire the cache.
$rows = $this->pdoOne->select('select 123 field1 from dual')->useCache(1, 'dual')->toList(); // +1 cache
self::assertEquals(1, $this->pdoOne->getCacheService()->cacheCounter); // 1= cache used 1 time
-
+
}
- function test_cache_family()
+ public function test_cache_family()
{
$this->pdoOne->getCacheService()->cacheCounter = 0;
$this->pdoOne->invalidateCache();
@@ -415,7 +418,7 @@ function test_cache_family()
self::assertEquals(2, $this->pdoOne->getCacheService()->cacheCounter); // 1= cache used 1 time
}
- function test_cache_multiple_family()
+ public function test_cache_multiple_family()
{
$this->pdoOne->getCacheService()->cacheCounter = 0;
$this->pdoOne->invalidateCache();
@@ -433,7 +436,7 @@ function test_cache_multiple_family()
}
- function test_cache_noCache()
+ public function test_cache_noCache()
{
$this->pdoOne->setCacheService(null);
@@ -575,16 +578,166 @@ public function test_open()
self::assertEquals(8, $this->pdoOne->getCacheService()->cacheCounter); // 3= cache used 1 time
- self::assertEquals([['id_category'=>3]],
- $this->pdoOne->select('id_category')->from('product_category')->where('id_category',3)->useCache()->toList());
- self::assertEquals([['id_category'=>4]],
- $this->pdoOne->select('id_category')->from('product_category')->where('id_category',4)->useCache()->toList());
- self::assertEquals(['id_category'=>123],
+ self::assertEquals([['id_category' => 3]],
+ $this->pdoOne->select('id_category')->from('product_category')->where('id_category', 3)->useCache()->toList());
+ self::assertEquals([['id_category' => 4]],
+ $this->pdoOne->select('id_category')->from('product_category')->where('id_category', 4)->useCache()->toList());
+ self::assertEquals(['id_category' => 123],
$this->pdoOne->select('id_category')->from('product_category')->order('id_category desc')->useCache()->first());
- self::assertEquals(['id_category'=>2],
+ self::assertEquals(['id_category' => 2],
$this->pdoOne->select('id_category')->from('product_category')->order('id_category')->useCache()->first());
}
+ public function test_select()
+ {
+ //$this->expectException(\Exception::class);
+ //$this->pdoOne->open(true);
+ try {
+ $r = $this->pdoOne->runRawQuery('drop table product_category');
+ self::assertEquals(true, $r, 'Drop failed');
+ } catch (Exception $e) {
+ $r = false;
+ // drops silently
+ }
+
+
+ $sqlT2 = 'CREATE TABLE `product_category` (
+ `id_category` INT NOT NULL,
+ `catname` VARCHAR(45) NULL,
+ PRIMARY KEY (`id_category`));';
+
+ try {
+ $r = $this->pdoOne->runRawQuery($sqlT2);
+ } catch (Exception $e) {
+ echo $e->getMessage() . ' ';
+ }
+ self::assertEquals(true, $r, 'failed to create table');
+ $this->pdoOne->getCacheService()->cacheCounter = 0;
+
+ self::assertGreaterThan(1, count($this->pdoOne->objectList('table')));
+ // we add some values
+ $this->pdoOne->set(['id_category' => 123, 'catname' => 'cheap'])->from('product_category')->insert();
+ $this->pdoOne->insert('product_category', ['id_category', 'catname'],
+ ['id_category' => 2, 'catname' => 'cheap']);
+
+ $this->pdoOne->insert('product_category', ['id_category' => 3, 'catname' => 'cheap']);
+
+ $this->pdoOne->insert('product_category', ['id_category' => 4, 'catname' => 'cheap4']);
+ $this->pdoOne->insert('product_category', ['id_category', '5', 'catname', 'cheap']);
+ $query1=$this->pdoOne->select('*')->from('product_category')->where('1=1')->order('id_category');
+ $r = $query1->toList();
+ $query2=$this->pdoOne->select('*')->from('product_category')->where('catname=?',['cheap'])->order('id_category');
+ $r2 = $query2->toList();
+
+ //var_dump(var_export($r));
+ self::assertEquals([
+ 0 =>
+ [
+ 'id_category' => 2,
+ 'catname' => 'cheap',
+ ],
+ 1 =>
+ [
+ 'id_category' => 3,
+ 'catname' => 'cheap',
+ ],
+ 2 =>
+ [
+ 'id_category' => 4,
+ 'catname' => 'cheap4',
+ ],
+ 3 =>
+ [
+ 'id_category' => 5,
+ 'catname' => 'cheap',
+ ],
+ 4 =>
+ [
+ 'id_category' => 123,
+ 'catname' => 'cheap',
+ ],
+ ], $r);
+ self::assertEquals([
+ 0 =>
+ [
+ 'id_category' => 2,
+ 'catname' => 'cheap',
+ ],
+ 1 =>
+ [
+ 'id_category' => 3,
+ 'catname' => 'cheap',
+ ],
+ 2 =>
+ [
+ 'id_category' => 5,
+ 'catname' => 'cheap',
+ ],
+ 3 =>
+ [
+ 'id_category' => 123,
+ 'catname' => 'cheap',
+ ],
+ ], $r2);
+
+ $query1=$this->pdoOne->select('*')->from('product_category')->where('1=1')->order('id_category')->useCache(10);
+ $r = $query1->toList();
+ $query2=$this->pdoOne->select('*')->from('product_category')->where('catname=?',['cheap'])->order('id_category')->useCache(10);
+ $r2 = $query2->toList();
+
+ //var_dump(var_export($r));
+ self::assertEquals([
+ 0 =>
+ [
+ 'id_category' => 2,
+ 'catname' => 'cheap',
+ ],
+ 1 =>
+ [
+ 'id_category' => 3,
+ 'catname' => 'cheap',
+ ],
+ 2 =>
+ [
+ 'id_category' => 4,
+ 'catname' => 'cheap4',
+ ],
+ 3 =>
+ [
+ 'id_category' => 5,
+ 'catname' => 'cheap',
+ ],
+ 4 =>
+ [
+ 'id_category' => 123,
+ 'catname' => 'cheap',
+ ],
+ ], $r);
+ self::assertEquals([
+ 0 =>
+ [
+ 'id_category' => 2,
+ 'catname' => 'cheap',
+ ],
+ 1 =>
+ [
+ 'id_category' => 3,
+ 'catname' => 'cheap',
+ ],
+ 2 =>
+ [
+ 'id_category' => 5,
+ 'catname' => 'cheap',
+ ],
+ 3 =>
+ [
+ 'id_category' => 123,
+ 'catname' => 'cheap',
+ ],
+ ], $r2);
+ }
+
+
public function test_quota()
{
self::assertEquals('`hello` world', $this->pdoOne->addDelimiter('hello world'));
@@ -657,6 +810,9 @@ public function test_emptyargs()
public function test_time()
{
+ PdoOne::$dateTimeFormat = 'Y-m-d\TH:i:s\Z';
+ PdoOne::$dateTimeMicroFormat = 'Y-m-d\TH:i:s.u\Z';
+ PdoOne::$dateFormat = 'Y-m-d';
self::assertEquals('2019-02-06 05:06:07', PdoOne::dateText2Sql('2019-02-06T05:06:07Z', true));
self::assertEquals('2019-02-06 00:00:00', PdoOne::dateText2Sql('2019-02-06', false));
@@ -735,9 +891,9 @@ public function test_rollback()
}
- public function test_select()
+ public function test_selectDual()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->select('select 1 from DUAL'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->select('select 1 from DUAL'));
}
public function test_sqlGen()
@@ -757,6 +913,7 @@ public function test_sqlGen()
self::assertEquals('select 1, 2 from DUAL where field=:field',
$this->pdoOne->select(['1', '2'])->from('DUAL')->where('field=:field', [':field' => 20])->sqlGen(true));
+ /** @noinspection SqlAggregates */
self::assertEquals('select 1, 2 from DUAL where field=? group by 2 having field2=? order by 1',
$this->pdoOne->select(['1', '2'])->from('DUAL')->where('field=?', [20])->order('1')->group('2')
->having('field2=?', [4])->sqlGen(true));
@@ -764,58 +921,58 @@ public function test_sqlGen()
public function test_join()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->join('tablejoin on t1.field=t2.field'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->join('tablejoin on t1.field=t2.field'));
}
public function test_from()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->from('table t1'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->from('table t1'));
}
public function test_left()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->left('table2 on table1.t1=table2.t2'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->left('table2 on table1.t1=table2.t2'));
}
public function test_right()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->right('table2 on table1.t1=table2.t2'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->right('table2 on table1.t1=table2.t2'));
}
public function test_where()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->where('field1=?,field2=?', [20, 'hello']));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->where('field1=?,field2=?', [20, 'hello']));
}
public function test_set()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->set('field1=?,field2=?', [20, 'hello']));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->set('field1=?,field2=?', [20, 'hello']));
}
public function test_group()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->group('fieldgroup'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->group('fieldgroup'));
}
public function test_having()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->having('field1=?,field2=?', [20, 'hello']));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->having('field1=?,field2=?', [20, 'hello']));
}
public function test_order()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->order('name desc'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->order('name desc'));
}
public function test_limit()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->limit('1,10'));
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->limit('1,10'));
}
public function test_distinct()
{
- self::assertInstanceOf(PdoOne::class, $this->pdoOne->distinct());
+ self::assertInstanceOf(PdoOneQuery::class, $this->pdoOne->distinct());
}