{"id":15002502,"url":"https://github.com/eftec/pdoone","last_synced_at":"2025-04-12T21:23:11.385Z","repository":{"id":37546308,"uuid":"187865991","full_name":"EFTEC/PdoOne","owner":"EFTEC","description":"It is a simple library for PHP that simplify the use of the PDO extension.","archived":false,"fork":false,"pushed_at":"2025-02-21T11:12:35.000Z","size":2818,"stargazers_count":108,"open_issues_count":0,"forks_count":17,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-04T01:06:21.842Z","etag":null,"topics":["mysql-php","pdo-php","pdo-wrapper","php","php-library","query-builder","sql-server"],"latest_commit_sha":null,"homepage":"https://www.eftec.cl","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EFTEC.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-21T15:31:41.000Z","updated_at":"2025-02-21T11:12:18.000Z","dependencies_parsed_at":"2025-01-15T02:06:05.414Z","dependency_job_id":"6a01a7c9-6465-4750-8fe0-bc2b312835b0","html_url":"https://github.com/EFTEC/PdoOne","commit_stats":{"total_commits":240,"total_committers":3,"mean_commits":80.0,"dds":0.3208333333333333,"last_synced_commit":"858d85b151545a3a4659393a5d1b0815c22ace96"},"previous_names":[],"tags_count":166,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOne","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOne/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOne/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOne/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EFTEC","download_url":"https://codeload.github.com/EFTEC/PdoOne/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248632858,"owners_count":21136766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mysql-php","pdo-php","pdo-wrapper","php","php-library","query-builder","sql-server"],"created_at":"2024-09-24T18:50:49.547Z","updated_at":"2025-04-12T21:23:11.342Z","avatar_url":"https://github.com/EFTEC.png","language":"PHP","readme":"# Database Access Object wrapper for PHP and PDO in a single class\n\nPdoOne. It's a simple wrapper for PHP's PDO library compatible with SQL Server (2008 R2 or higher), MySQL (5.7 or\nhigher) and Oracle (12.1 or higher).\n\nThis library tries to **work as fast as possible**. Most of the operations are simple string/array managements and work\nin the bare metal of the PDO library, but it also allows to create an ORM using the extension [eftec/PdoOneORM](https://github.com/EFTEC/PdoOneORM).\n\n[![Packagist](https://img.shields.io/packagist/v/eftec/PdoOne.svg)](https://packagist.org/packages/eftec/PdoOne)\n[![Total Downloads](https://poser.pugx.org/eftec/PdoOne/downloads)](https://packagist.org/packages/eftec/PdoOne)\n[![Maintenance](https://img.shields.io/maintenance/yes/2025.svg)]()\n[![composer](https://img.shields.io/badge/composer-%3E1.6-blue.svg)]()\n[![php](https://img.shields.io/badge/php-7.4-green.svg)]()\n[![php](https://img.shields.io/badge/php-8.4-green.svg)]()\n[![CocoaPods](https://img.shields.io/badge/docs-70%25-yellow.svg)]()\n\nTurn this\n\n```php\n$stmt = $pdo-\u003eprepare(\"SELECT * FROM myTable WHERE name = ?\");\n$stmt-\u003ebindParam(1,$_POST['name'],PDO::PARAM_STR);\n$stmt-\u003eexecute();\n$result = $stmt-\u003eget_result();\n$products=[];\nwhile($row = $result-\u003efetch_assoc()) {\n  $product[]=$row; \n}\n$stmt-\u003eclose();\n```\n\ninto this\n\n```php\n$products=$pdoOne\n    -\u003eselect(\"*\")\n    -\u003efrom(\"myTable\")\n    -\u003ewhere(\"name = ?\",[$_POST['name']]) \n    -\u003etoList();\n```\n\nor using the ORM (using [eftec/PdoOneORM](https://github.com/EFTEC/PdoOneORM) library)\n\n```php\nProductRepo // this class was generated with echo $pdoOne()-\u003egenerateCodeClass(['Product']); or using the cli.\n    ::where(\"name = ?\",[$_POST['name']])\n    ::toList();\n```\n\n# Table of contents\n\n\u003c!-- TOC --\u003e\n* [Database Access Object wrapper for PHP and PDO in a single class](#database-access-object-wrapper-for-php-and-pdo-in-a-single-class)\n* [Table of contents](#table-of-contents)\n  * [Examples](#examples)\n  * [Installation](#installation)\n    * [Install (using composer)](#install-using-composer)\n    * [Install (manually)](#install-manually)\n  * [How to create a Connection?](#how-to-create-a-connection)\n    * [OCI](#oci)\n  * [How to run a SQL command?](#how-to-run-a-sql-command)\n    * [1. Running a raw query](#1-running-a-raw-query)\n    * [2. Running a native PDO statement](#2-running-a-native-pdo-statement)\n    * [3. Running using the query builder](#3-running-using-the-query-builder)\n    * [4. Running using an ORM](#4-running-using-an-orm)\n    * [5. Run a query with a different mode](#5-run-a-query-with-a-different-mode)\n  * [How to work with Date values?](#how-to-work-with-date-values)\n  * [How to run a transaction?](#how-to-run-a-transaction)\n  * [Custom Queries](#custom-queries)\n    * [tableExist($tableName)](#tableexisttablename)\n    * [statValue($tableName,$columnName)](#statvaluetablenamecolumnname)\n    * [columnTable($tablename)](#columntabletablename)\n    * [foreignKeyTable($tableName)](#foreignkeytabletablename)\n    * [createTable($tableName,$definition,$primaryKey=null,$extra='',$extraOutside='')](#createtabletablenamedefinitionprimarykeynullextraextraoutside)\n    * [tableSorted($maxLoop = 5, $returnProblems = false, $debugTrace = false)](#tablesortedmaxloop--5-returnproblems--false-debugtrace--false)\n    * [validateDefTable($pdoInstance,$tablename,$defTable,$defTableKey)](#validatedeftablepdoinstancetablenamedeftabledeftablekey)\n    * [foreignKeyTable](#foreignkeytable)\n  * [Query Builder (DQL)](#query-builder-dql)\n    * [select($columns)](#selectcolumns)\n    * [count($sql,$arg='*')](#countsqlarg)\n    * [min($sql,$arg='*')](#minsqlarg)\n    * [max($sql,$arg='*')](#maxsqlarg)\n    * [sum($sql,$arg='*')](#sumsqlarg)\n    * [avg($sql,$arg='*')](#avgsqlarg)\n    * [distinct($distinct='distinct')](#distinctdistinctdistinct)\n    * [from($tables)](#fromtables)\n    * [where($where,[$arrayParameters=array()])](#wherewherearrayparametersarray)\n      * [Where() without parameters.](#where-without-parameters)\n      * [Where() with parameters defined by an indexed array.](#where-with-parameters-defined-by-an-indexed-array)\n      * [Where() using an associative array](#where-using-an-associative-array)\n      * [Where() using an associative array and named arguments](#where-using-an-associative-array-and-named-arguments)\n      * [Examples of where()](#examples-of-where)\n    * [order($order)](#orderorder)\n    * [group($group)](#groupgroup)\n    * [having($having,[$arrayParameters])](#havinghavingarrayparameters)\n    * [End of the chain](#end-of-the-chain)\n      * [runGen($returnArray=true)](#rungenreturnarraytrue)\n      * [toList($pdoMode)](#tolistpdomode)\n* [toPdoStatement($pdoMode)](#topdostatementpdomode)\n* [fetchLoop($callable,$pdoMode)](#fetchloopcallablepdomode)\n      * [toMeta()](#tometa)\n      * [toListSimple()](#tolistsimple)\n      * [toListKeyValue()](#tolistkeyvalue)\n      * [toResult()](#toresult)\n      * [firstScalar($colName=null)](#firstscalarcolnamenull)\n      * [first()](#first)\n      * [last()](#last)\n      * [sqlGen()](#sqlgen)\n  * [Query Builder (DML)](#query-builder-dml)\n    * [insert($table,$schema,[$values])](#inserttableschemavalues)\n    * [insertObject($table,[$declarativeArray],$excludeColumn=[])](#insertobjecttabledeclarativearrayexcludecolumn)\n    * [update($$table,$schema,$values,[$schemaWhere],[$valuesWhere])](#updatetableschemavaluesschemawherevalueswhere)\n    * [delete([$table],[$schemaWhere],[$valuesWhere])](#deletetableschemawherevalueswhere)\n  * [Cache](#cache)\n    * [How to configure it?](#how-to-configure-it)\n    * [Example using apcu](#example-using-apcu)\n  * [Sequence](#sequence)\n    * [Creating a sequence](#creating-a-sequence)\n    * [Creating a sequence without a table.](#creating-a-sequence-without-a-table)\n    * [Using the sequence](#using-the-sequence)\n  * [Fields](#fields)\n  * [Encryption](#encryption)\n  * [How to debug and trace errors in the database?](#how-to-debug-and-trace-errors-in-the-database)\n    * [Setting the log level](#setting-the-log-level)\n    * [Throwing errors](#throwing-errors)\n    * [Getting the last Query](#getting-the-last-query)\n    * [Generating a log file](#generating-a-log-file)\n  * [CLI](#cli)\n    * [Run as cli](#run-as-cli)\n    * [Run as CLI interative](#run-as-cli-interative)\n      * [Examples](#examples-1)\n    * [Run CLI to generate repository classes.](#run-cli-to-generate-repository-classes)\n    * [cli-classcode](#cli-classcode)\n    * [cli-selectcode](#cli-selectcode)\n    * [cli-arraycode](#cli-arraycode)\n    * [cli-json](#cli-json)\n    * [cli-csv](#cli-csv)\n    * [UI](#ui)\n    * [How to run the UI?](#how-to-run-the-ui)\n    * [DDL  Database Design Language](#ddl--database-design-language)\n    * [Nested Operators](#nested-operators)\n    * [DQL Database Query Language](#dql-database-query-language)\n    * [DML Database Model Language](#dml-database-model-language)\n    * [Validate the model](#validate-the-model)\n    * [Recursive](#recursive)\n      * [recursive()](#recursive-1)\n      * [getRecursive()](#getrecursive)\n      * [hasRecursive()](#hasrecursive)\n  * [Benchmark (mysql, estimated)](#benchmark-mysql-estimated)\n  * [migration from 3 to 4](#migration-from-3-to-4)\n  * [Error FAQs](#error-faqs)\n    * [Uncaught Error: Undefined constant eftec\\_BasePdoOneRepo::COMPILEDVERSION](#uncaught-error-undefined-constant-eftec_basepdoonerepocompiledversion)\n  * [Changelist](#changelist)\n\u003c!-- TOC --\u003e\n\n## Examples\n\n| [ExampleTicketPHP](https://github.com/jorgecc/ExampleTicketPHP)                                                                                                                                                                                                        | [Example cupcakes](https://github.com/EFTEC/example.cupcakes)                                                                     | [Example Search](https://github.com/EFTEC/example-search)                                                                              | [Example Different Method](https://github.com/escuelainformatica/example-pdoone)                          |\n|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|\n| \u003cimg src=\"https://camo.githubusercontent.com/3c938f71f46a90eb85bb104f0f396fcba62b8f4a/68747470733a2f2f74686570726163746963616c6465762e73332e616d617a6f6e6177732e636f6d2f692f3436696b7061376661717677726533797537706a2e6a7067\" alt=\"example php bladeone\" width=\"200\"/\u003e | \u003cimg src=\"https://github.com/EFTEC/example.cupcakes/raw/master/docs/result.jpg\" alt=\"example php bladeone cupcakes\" width=\"200\"/\u003e | \u003cimg src=\"https://github.com/EFTEC/example-search/raw/master/img/search_bootstrap.jpg\" alt=\"example php bladeone search\" width=\"200\"/\u003e | \u003cimg src='https://github.com/escuelainformatica/example-pdoone/raw/master/docs/database.jpg' width=200 /\u003e |\n\nMore examples:\n\n[Example Mysql PHP and PDO using PDOOne](https://www.southprojects.com/Programming/mysql-php-pdo)\n\n## Installation\n\nThis library requires PHP 7.1 and higher, and it requires the extension PDO and the extension PDO-MYSQL (Mysql),\nPDO-SQLSRV (sql server) or PDO-OCI (Oracle)\n\n### Install (using composer)\n\nEdit  **composer.json** the next requirement, then update composer.\n\n```json\n  {\n      \"require\": {\n        \"eftec/PdoOne\": \"^4.0.1\"\n      }\n  }\n```\n\nor install it via cli using\n\n\u003e composer require eftec/PdoOne\n\n### Install (manually)\n\nJust download the folder lib from the library and put in your folder project. Then you must include all the files\nincluded on it.\n\n## How to create a Connection?\n\nCreate an instance of the class PdoOne as follows. Then, you can open the connection using the method connect() or\nopen()\n\n```php\nuse eftec\\PdoOne;\n// mysql\n$dao=new PdoOne(\"mysql\",\"127.0.0.1\",\"root\",\"abc.123\",\"sakila\",\"\");\n$conn-\u003elogLevel=3; // it is for debug purpose and it works to find problems.\n$dao-\u003econnect();\n\n// sql server 10.0.0.1\\instance or (local)\\instance or machinename\\instance or machine (default instance)\n$dao=new PdoOne(\"sqlsrv\",\"(local)\\sqlexpress\",\"sa\",\"abc.123\",\"sakila\",\"\");\n$conn-\u003elogLevel=3; // it is for debug purpose and it works to find problems.\n$dao-\u003econnect();\n\n// test (mockup)\n$dao=new PdoOne(\"test\",\"anyy\",\"any\",\"any\",\"any\",\"\");\n$dao-\u003econnect();\n\n// oci (oracle) ez-connect. Remember that you must have installed Oracle Instant client and added to the path.\n\n$cs='(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = instancia1)))';\n$dao=new PdoOne(\"oci\",$cs,\"sa\",\"abc.123\"); // oracle uses the user as the schema\n$conn-\u003elogLevel=3; // it is for debug purpose and it works to find problems.\n$dao-\u003econnect();\n\n// oci (oracle) tsnnames (the environment variables TNS_ADMIN and PATH must be correctly configured), also tnsnames.ora must exists.\n$cs='instancia1';\n$dao=new PdoOne(\"oci\",$cs,\"sa\",\"abc.123\"); // oracle uses the user as the schema\n$conn-\u003elogLevel=3; // it is for debug purpose and it works to find problems.\n$dao-\u003econnect();\n\n```\n\nwhere\n\n\u003e $dao=new PdoOne(\"mysql\",\"127.0.0.1\",\"root\",\"abc.123\",\"sakila\",\"\");\n\n* \"**mysql**\" is the MySQL database. It also allows sqlsrv (for sql server) or \"oci\"\n* **127.0.0.1** is the server where is the database.\n* **root** is the user\n* **abc.123** is the password of the user root.\n* **sakila** is the database used.\n* \"\" (optional) it could be a log file, such as c:\\temp\\log.txt\n\n### OCI\n\nOracle is tricky to install. In Windows, from the Oracle home's bin folder, you must copy all the dll\nto the PHP folder and Apache Folder.\n\n## How to run a SQL command?\n\n### 1. Running a raw query\n\nWith the method **RunRawQuery()**, we could execute a command directly to PDO with or without parameters. And it could\nreturn a **PdoStatement** or an **array**. It is useful when we want speed.\n\n\u003e **RunRawQuery($rawSql,$param,$returnArray,$fetchMode,$fetchArgument)**\n\u003e\n\u003e string **$rawSql** The query to execute\n\u003e array|null **$param** [type1,value1,type2,value2] or [name1=\u003evalue,name2=value2]\n\u003e bool **$returnArray** if true (default) then it returns an array. If false then it returns a **PDOStatement**\n\u003e int  **$fetchMode**     Indicates the mode to fetch. Example: PDO::FETCH_ASSOC\n\u003e null **$fetchArgument** The argument of the fetchMode.\n```php\n$sql='select * from table where id=1';\n$pdoStatement=$pdoOne-\u003erunRawQuery($sql,[],false);  // [] are the parameters\n```\n\nBut we could change it to returns an array\n\n```php\n$sql='select * from table where id=1';\n$values=$pdoOne-\u003erunRawQuery($sql);  // [] are the parameters\n```\n\nWe could also pass parameters.\n\n```php\n$values=$con-\u003erunRawQuery('select * from table where id=?',[20]); // with parameter\n$values=$con-\u003erunRawQuery('select * from table where id=:name',['name'=\u003e20]); // with named parameter\n$values=$con-\u003erunRawQuery('select * from table',[]); // without parameter.\n\n```\n\n\u003e Note, this library uses prepared statements, so it is free of SQL injection (if you use parameters)\n\n```php\n$name=\"O'hara\";\n$values=$con-\u003erunRawQuery(\"select * from table where name=:name\",['name'=\u003e $name]); // it works.✅\n$values=$con-\u003erunRawQuery(\"select * from table where name=?\",[$name]); // it works ok.✅\n$values=$con-\u003erunRawQuery(\"select * from table where name='$name'\"); // it will crash.❌\n```\n\n### 2. Running a native PDO statement\n\nWith the method **runQuery()** we could execute a prepared statement in PDO. It is useful when we want to pass arguments\nto it.   **runQuery()** requires a PDO **PreparedStatement**.\n\n\u003e This method is not recommended unless you are already working with PDO statements, and you don't want to adapt all\n\u003e your code.\n\n```php\n$sql=\"insert into `product`(name) values(?)\";\n$stmt=$pdoOne-\u003eprepare($sql);\n$productName=\"Cocacola\";\n$stmt-\u003ebind_param(\"s\",$productName); // s stand for a string. Also i =integer, d = double and b=blob\n$rows=$pdoOne-\u003erunQuery($stmt);\n$allRows=$rows-\u003efetch_all(PDO::FETCH_ASSOC);\n```\n\n### 3. Running using the query builder\n\nYou can use the query builder to build your command. You could check the chapter\nabout [Query Builder (DQL)](#query-builder-dql) for more information.\n\n```php\n// query builder\n$pdoOne-\u003eset(['name'=\u003e'cocacola'])\n    -\u003efrom('product')\n    -\u003einsert();\n\n```\n\n### 4. Running using an ORM\n\nThe library eftec\\PdoOneORM allows to create an **[orm]**(#orm) of your tables. If you are generated an ORM, then you can use the\nnext code\n\n```php\nProductRepo::toList(['category'=\u003e'drink']);\n```\n\nWhere **ProductRepo** is a service class generated by using the ORM.\n\n### 5. Run a query with a different mode\nBy default, PdoOne executes the queries in the mode PDO::FETCH_ASSOC\nYou can change by running the queries as:\n\n```php\n$pdo-\u003esetFechMode(PDO::FETCH_CLASS,'stdClass')-\u003erunRawQuery($query);\n// or you can run as\n$pdo-\u003erunRawQuery($query,null,true,false,null,PDO::FETCH_CLASS,'stdClass')\n```\n\n\n\n## How to work with Date values?\n\nPdoOne allows 5 types of dates.\n\n* **SQL Format** It is the format how the date is stored into the database. It depends on the type of the database.\n  For example MySQL could use the format Y-m-d.\n\n* **Human Format**  It is the format how the end user looks our date.\n\n* **ISO Date Format**. It is the format how the value could be transported and serialized.\n\n* **Timestamp**: It counts the number of seconds after 1-1-1970\n\n* **Class / PHP Class**: It is an **DateTime** object.\n\n## How to run a transaction?\n\nThere are 3 methods to runs a transaction:\n\n| Method             | Description                                                                           |\n|--------------------|---------------------------------------------------------------------------------------|\n| startTransaction() | It starts a transaction. Depending on the type database, it could be stacked  or not. |\n| commit()           | Commit (and closes) a transaction                                                     |\n| rollback()         | Rollback (and closes) a transaction                                                   |\n\nExample:\n\n```php\ntry {\n    $sql=\"insert into `product`(name) values(?)\";\n    $pdoOne-\u003estartTransaction();\n    $result=$pdoOne-\u003erunRawQuery($sql,['Fanta'=\u003e$productName],false);\n    $pdoOne-\u003ecommit(); // transaction ok\n} catch (Exception $e) {\n    $pdoOne-\u003erollback(false); // error, transaction cancelled, the false means that it doesn't throw an exception if we want rollback.\n}\n```\n\n## Custom Queries\n\n### tableExist($tableName)\n\nReturns true if the table exists (current database/schema)\n\n### statValue($tableName,$columnName)\n\nReturns the statistics (as an array) of a column of a table.\n\n```php\n$stats=$pdoOne-\u003estatValue('actor','actor_id');\n```\n\n| min | max | avg      | sum   | count |\n|-----|-----|----------|-------|-------|\n| 1   | 205 | 103.0000 | 21115 | 205   |\n\n### columnTable($tablename)\n\nReturns all columns of a table\n\n```php\n$result=$pdoOne-\u003ecolumnTable('actor');\n```\n\n| colname     | coltype   | colsize | colpres | colscale | iskey | isidentity |\n|-------------|-----------|---------|---------|----------|-------|------------|\n| actor_id    | smallint  |         | 5       | 0        | 1     | 1          |\n| first_name  | varchar   | 45      |         |          | 0     | 0          |\n| last_name   | varchar   | 45      |         |          | 0     | 0          |\n| last_update | timestamp |         |         |          | 0     | 0          |\n\n### foreignKeyTable($tableName)\n\nReturns all foreign keys of a table (source table)\n\n### createTable($tableName,$definition,$primaryKey=null,$extra='',$extraOutside='')\n\nCreates a table using a definition and primary key.\n\n* **$definition** The definition is an associative array with the name of the column as key and the definition as value.\n* **primaryKey** It could be a string or associative array.\n    * if it is a string then it is the name of the primary key, example \"user_id\";\n    * if it is an associative array, then it could be used to define primary key, unique, key and foreign keys:\n        * 'key_name'=\u003e'PRIMARY KEY'\n        * 'key_name'=\u003e'KEY'\n        * 'key_name'=\u003e'UNIQUE KEY'\n        * 'key_name'=\u003e'FOREIGN KEY REFERENCES TABLEREF(COLREF) ...'\n* **$extra** It defines an extra definition inside the definition of the table.\n* **extraOutside** It defines an extra definition after the definition of the table.\n\n\u003e Note: You could generate a code to create a table using an existing table by executing cli (output classcode)   \n\u003e php pdoone.php -database mysql -server 127.0.0.1 -user root -pwd abc.123 -db sakila -input film -output classcode\n\nExample: (mysql)\n\n```php\n$pdo-\u003ecreateTable('film',                                                                                                \n    [                                                                                                                    \n        \"film_id\" =\u003e \"smallint unsigned not null auto_increment\",                                                        \n        \"title\" =\u003e \"varchar(255) not null\",                                                                              \n        \"description\" =\u003e \"text\",                                                                                         \n        \"release_year\" =\u003e \"year\",                                                                                        \n        \"language_id\" =\u003e \"tinyint unsigned not null\",                                                                    \n        \"original_language_id\" =\u003e \"tinyint unsigned\",                                                                    \n        \"rental_duration\" =\u003e \"tinyint unsigned not null default '3'\",                                                    \n        \"rental_rate\" =\u003e \"decimal(4,2) not null default '4.99'\",                                                         \n        \"length\" =\u003e \"smallint unsigned\",                                                                                 \n        \"replacement_cost\" =\u003e \"decimal(5,2) not null default '19.99'\",                                                   \n        \"rating\" =\u003e \"enum('G','PG','PG-13','R','NC-17') default 'G'\",                                                    \n        \"special_features\" =\u003e \"set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes')\",                     \n        \"last_update\" =\u003e \"timestamp not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP\"                      \n    ],[                                                                                                                  \n        \"film_id\" =\u003e \"PRIMARY KEY\",                                                                                      \n        \"title\" =\u003e \"KEY\",                                                                                                \n        \"language_id\" =\u003e \"FOREIGN KEY REFERENCES`language`(`language_id`) ON UPDATE CASCADE\",                            \n        \"original_language_id\" =\u003e \"FOREIGN KEY REFERENCES`language`(`language_id`) ON UPDATE CASCADE\"                    \n    ]);                                                                                                                  \n```\n\n```php\n$pdo-\u003ecreateTable('film',                                                                                                \n    [                                                                                                                    \n        \"film_id\" =\u003e \"smallint unsigned not null auto_increment\",                                                        \n        \"title\" =\u003e \"varchar(255) not null\",                                                                              \n        \"description\" =\u003e \"text\",                                                                                         \n        \"release_year\" =\u003e \"year\",                                                                                        \n        \"language_id\" =\u003e \"tinyint unsigned not null\",                                                                    \n        \"original_language_id\" =\u003e \"tinyint unsigned\",                                                                    \n        \"rental_duration\" =\u003e \"tinyint unsigned not null default '3'\",                                                    \n        \"rental_rate\" =\u003e \"decimal(4,2) not null default '4.99'\",                                                         \n        \"length\" =\u003e \"smallint unsigned\",                                                                                 \n        \"replacement_cost\" =\u003e \"decimal(5,2) not null default '19.99'\",                                                   \n        \"rating\" =\u003e \"enum('G','PG','PG-13','R','NC-17') default 'G'\",                                                    \n        \"special_features\" =\u003e \"set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes')\",                     \n        \"last_update\" =\u003e \"timestamp not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP\"                      \n    ],'film_id');                                                                                                                  \n```\n\nExample (sqlsrv)\n\n```php\n$pdo-\u003ecreateTable('film',\n   [\n       \"film_id\" =\u003e \"int NOT NULL IDENTITY(1,1)\",\n       \"title\" =\u003e \"varchar(255) NOT NULL\",\n       \"description\" =\u003e \"text(2147483647) DEFAULT (NULL)\",\n       \"release_year\" =\u003e \"varchar(4)\",\n       \"language_id\" =\u003e \"tinyint NOT NULL\",\n       \"original_language_id\" =\u003e \"tinyint DEFAULT (NULL)\",\n       \"rental_duration\" =\u003e \"tinyint NOT NULL DEFAULT ((3))\",\n       \"rental_rate\" =\u003e \"decimal(4,2) NOT NULL DEFAULT ((4.99))\",\n       \"length\" =\u003e \"smallint DEFAULT (NULL)\",\n       \"replacement_cost\" =\u003e \"decimal(5,2) NOT NULL DEFAULT ((19.99))\",\n       \"rating\" =\u003e \"varchar(10) DEFAULT ('G')\",\n       \"special_features\" =\u003e \"varchar(255) DEFAULT (NULL)\",\n       \"last_update\" =\u003e \"datetime NOT NULL DEFAULT (getdate())\"\n   ],[\n       \"language_id\" =\u003e \"FOREIGN KEY REFERENCES language(language_id)\",\n       \"original_language_id\" =\u003e \"FOREIGN KEY REFERENCES language(language_id)\",\n       \"film_id\" =\u003e \"PRIMARY KEY\"\n   ]);\n```\n\n### tableSorted($maxLoop = 5, $returnProblems = false, $debugTrace = false)\n\nIt returns a list of tables ordered by dependency (from no dependent to more dependent)\n\n**Note**: This operation is not foolproof because the tables could have circular references.\n\n```php\n$dao = new PdoOne('sqlsrv', \"(local)\\sqlexpress\", \"sa\", \"abc.123\", \"sakila\");\n$dao-\u003eopen();\necho \"\u003cpre\u003e\";\nvar_dump($dao-\u003etableSorted(3, false, true)); // it returns the tables sortered\nvar_dump($dao-\u003etableSorted(3, true, true)); // it returns all the tables that can't be sortered\necho \"\u003c/pre\u003e\";\n```\n\n### validateDefTable($pdoInstance,$tablename,$defTable,$defTableKey)\n\nIt validates a table if the table matches the definition asigned by values.\n\n```\n$def=[\n       \"film_id\" =\u003e \"int NOT NULL IDENTITY(1,1)\",\n       \"title\" =\u003e \"varchar(255) NOT NULL\",\n       \"description\" =\u003e \"text(2147483647) DEFAULT (NULL)\",\n       \"release_year\" =\u003e \"varchar(4)\",\n       \"language_id\" =\u003e \"tinyint NOT NULL\",\n       \"original_language_id\" =\u003e \"tinyint DEFAULT (NULL)\",\n       \"rental_duration\" =\u003e \"tinyint NOT NULL DEFAULT ((3))\",\n       \"rental_rate\" =\u003e \"decimal(4,2) NOT NULL DEFAULT ((4.99))\",\n       \"length\" =\u003e \"smallint DEFAULT (NULL)\",\n       \"replacement_cost\" =\u003e \"decimal(5,2) NOT NULL DEFAULT ((19.99))\",\n       \"rating\" =\u003e \"varchar(10) DEFAULT ('G')\",\n       \"special_features\" =\u003e \"varchar(255) DEFAULT (NULL)\",\n       \"last_update\" =\u003e \"datetime NOT NULL DEFAULT (getdate())\"\n   ];\n$keys=[\n       \"language_id\" =\u003e \"FOREIGN KEY REFERENCES language(language_id)\",\n       \"original_language_id\" =\u003e \"FOREIGN KEY REFERENCES language(language_id)\",\n       \"film_id\" =\u003e \"PRIMARY KEY\"\n   ]; \n   \nvar_dump(PdoOne::validateDefTable(self::getPdoOne(),self::TABLE,$def,$keys));\n```\n\n### foreignKeyTable\n\nIt returns all the foreign keys of a table.\n\n```php\n\n$result=$pdoOne-\u003eforeignKeyTable('actor');\n```\n\n| collocal    | tablerem | colrem      |\n|-------------|----------|-------------|\n| customer_id | customer | customer_id |\n| rental_id   | rental   | rental_id   |\n| staff_id    | staff    | staff_id    |\n\n## Query Builder (DQL)\n\nYou could also build a procedural query.\n\nExample:\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom(\"producttype\")\n    -\u003ewhere('name=?', [ 'Cocacola'])\n    -\u003ewhere('idproducttype=?', [ 1])\n    -\u003etoList();   \n```\n\n### select($columns)\n\nIndicates the columns to return. The argument is a SQL command, so it allows any operation that the database support,\nincluding functions, constants, operators, alias and such.\n\n```php\n$results = $pdoOne-\u003eselect(\"col1,col2\"); //...\n```\n\n\u003e Generates the query: **select col1,col2** ....\n\n```php\n$results = $pdoOne-\u003eselect(\"select * from table\"); //-\u003e...\n```\n\n\u003e Generates the query: **select * from table** ....\n\n### count($sql,$arg='*')\n\nGenerates a query that returns a count of values.\nIt is a macro of the method select()\n\n```php\n$result = $pdoOne-\u003ecount('from table where condition=1'); // select count(*) from table where c..\n$result = $pdoOne-\u003ecount()-\u003efrom('table')-\u003ewhere('condition=?',[1]); // select count(*) from table where c..\n$result = $pdoOne-\u003ecount('from table','col1'); // select count(col1) from table\n$result = $pdoOne-\u003ecount()-\u003efrom('table'); // select count(*) from table\n```\n\n### min($sql,$arg='*')\n\nGenerates a query that returns the minimum value of a column.\nIf $arg is empty then it uses $sql for the name of the column\nIt is a macro of the method select()\n\n```php\n$result = $pdoOne-\u003emin('from table where condition=1','col'); // select min(col) from table where c..\n$result = $pdoOne-\u003emin('from table','col1'); // select min(col1) from table\n$result = $pdoOne-\u003emin('','col1')-\u003efrom('table'); // select min(col1) from table\n$result = $pdoOne-\u003emin('col1')-\u003efrom('table'); // select min(col1) from table\n```\n\n### max($sql,$arg='*')\n\nGenerates a query that returns the maximum value of a column.\nIf $arg is empty then it uses $sql for the name of the column\nIt is a macro of the method select()\n\n```php\n$result = $pdoOne-\u003emax('from table where condition=1','col'); // select max(col) from table where c..\n$result = $pdoOne-\u003emax('from table','col1'); // select max(col1) from table\n```\n\n### sum($sql,$arg='*')\n\nGenerates a query that returns the sum value of a column.\nIf $arg is empty then it uses $sql for the name of the column\nIt is a macro of the method select()\n\n```php\n$result = $pdoOne-\u003esum('from table where condition=1','col'); // select sum(col) from table where c..\n$result = $pdoOne-\u003esum('from table','col1'); // select sum(col1) from table\n```\n\n### avg($sql,$arg='*')\n\nGenerates a query that returns the average value of a column.\nIf $arg is empty then it uses $sql for the name of the column\nIt is a macro of the method select()\n\n```php\n$result = $pdoOne-\u003eavg('from table where condition=1','col'); // select avg(col) from table where c..\n$result = $pdoOne-\u003eavg('from table','col1'); // select avg(col1) from table\n```\n\n### distinct($distinct='distinct')\n\nGenerates a select command.\n\n```php\n$results = $pdoOne-\u003eselect(\"col1,col2\")-\u003edistinct(); //...\n```\n\n\u003e Generates the query: select **distinct** col1,col2 ....\n\n\u003e Note: -\u003edistinct('unique') returns select **unique** ..\n\n### from($tables)\n\nGenerates a \"from\" sql command.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table'); //...\n```\n\n\u003e Generates the query: select * **from table**\n\n**$tables** could be a single table or a sql construction. For examp, the next command is valid:\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table t1 inner join t2 on t1.c1=t2.c2'); //...\n```\n\n### where($where,[$arrayParameters=array()])\n\nGenerates a where command.\n\n* $where is an array or a string. If it's a string, then it's evaluated by using the parameters. if any\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003ewhere('p1=1'); //...\n```\n\nThe where could be expressed in different ways.\n\n#### Where() without parameters.\n\nIt is possible to write the where without parameters as follows:\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table')-\u003ewhere(\"p1=1 and p2\u003e2.5 or p3 like '%aa%'\");\n```\n\n#### Where() with parameters defined by an indexed array.\n\n```php\n$aa='aa';\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table')-\u003ewhere(\"p1=? and p2\u003e? or p3 like ?\",[1\n                                                                                    ,2.5\n                                                                                    ,\"%$aa%\"]);\n```\n\nIt also works\n\n```php\n// (if there is only a single argument without a type)\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table')-\u003ewhere(\"p1=?\",[1]);  // = where(\"p1=?\",[1]);\n// (if we don't define to where to put the value)\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table')-\u003ewhere(\"p1\",[1]); // = where(\"p1=?\",[1]);\n```\n\n#### Where() using an associative array\n\nIt is a shorthand definition of a query using an associative array, where the key is the name of the column and the\nvalue is the value to compare\n\nIt only works with **equality** (=) and the logic operator **'and'**  (the type is defined automatically)\n\n```php\n// select * from table where p1='1' and p2='2.5' and p3='aa'\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table')-\u003ewhere(['p1'=\u003e1\n                                                       ,'p2'=\u003e2.5\n                                                       ,'p3'=\u003e'aa']);  \n```\n\nAlso, it is possible to specify the type of parameter.\n\n```php\n// select * from table where p1=1 and p2='2.5' and p3='aa'\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom('table')-\u003ewhere(['p1'=\u003e[1]\n                                                       ,'p2'=\u003e[2.5]\n                                                       ,'p3'=\u003e['aa']]);  \n```\n\n#### Where() using an associative array and named arguments\n\nYou could also use an associative array as argument and named parameters in the query\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom(\"table\")\n    -\u003ewhere('condition=:p1 and condition2=:p2',['p1'=\u003e'Coca-Cola','p2'=\u003e1])\n    -\u003etoList();\n```\n\n\u003e Generates the query: select * from table **where condition=?(Coca-Cola) and condition2=?(1)**\n\n#### Examples of where()\n\n\u003e Generates the query: select * **from table** where p1=1\n\n\u003e Note: ArrayParameters is an array as follows: **type,value.**     \n\u003e Where type is i=integer, d=double, s=string or b=blob. In case of doubt, use \"s\" (see table bellow)   \n\u003e Example of arrayParameters:   \n\u003e [1 ,'hello' ,20.3 ,'world']\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003ewhere('p1=?',[1]); //...\n```\n\n\u003e Generates the query: select * from table **where p1=?(1)**\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003ewhere('p1=? and p2=?',[1,'hello']); //...\n```\n\n\u003e Generates the query: select * from table **where p1=?(1) and p2=?('hello')**\n\n\u003e Note. where could be nested.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003ewhere('p1=?',[1])\n-\u003ewhere('p2=?',['hello']); //...\n```\n\n\u003e Generates the query: select * from table **where p1=?(1) and p2=?('hello')**\n\nYou could also use:\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")-\u003efrom(\"table\")\n    -\u003ewhere(['p1'=\u003e'Coca-Cola','p2'=\u003e1])\n    -\u003etoList();\n```\n\n\u003e Generates the query: select * from table **where p1=?(Coca-Cola) and p2=?(1)**\n\n### order($order)\n\nGenerates an order command.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003eorder('p1 desc'); //...\n```\n\n\u003e Generates the query: select * from table **order by p1 desc**\n\n### group($group)\n\nGenerates a group command.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003egroup('p1'); //...\n```\n\n\u003e Generates the query: select * from table **group by p1**\n\n### having($having,[$arrayParameters])\n\nGenerates a having command.\n\n\u003e Note: it uses the same parameters as **where()**\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003egroup('p1')\n-\u003ehaving('p1\u003e?',array(1)); //...\n```\n\n\u003e Generates the query: select * from table group by p1 having p1\u003e?(1)\n\n\u003e Note: Having could be nested having()-\u003ehaving()  \n\u003e Note: Having could be without parameters having('col\u003e10')\n\n### End of the chain\n\n#### runGen($returnArray=true)\n\nRun the query generate.\n\n\u003e Note if returnArray is true then it returns an associative array.\n\u003e if returnArray is false then it returns a mysqli_result  \n\u003e Note: It resets the current parameters (such as current select, from, where, etc.)\n\n#### toList($pdoMode)\n\nIt's a macro of **runGen()**. It returns an associative array or false if the operation fails.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003etoList(); \n```\n\n# toPdoStatement($pdoMode)\n\nIt returns a PdoStatement from the current query\n\u003e Note: if you want to loop the statement, then you can use fetchLoop()\n\n**Example**:\n```php\n$stmt = $pdoOne-\u003eselect(\"*\")\n  -\u003efrom('table')\n  -\u003etoPdoStatement(); \nwhile ($row = $stmt-\u003efetch()) {\n  // do something\n}\n```\n\n# fetchLoop($callable,$pdoMode)\nIt fetches a query for every row.  \nThis method could be used when we don't want to read all the information at once,\nso you can read and process each line separately  \n**Example**:  \n```php\n$this-\u003eselect('select id,name from table')\n      -\u003efetchLoop(static function($row) {return($row);},\\PDO::FETCH_ASSOC)\n```\n\n\n#### toMeta()\n\nIt returns a **metacode** (definitions) of each column of a query.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003etoMeta(); \n```\n\nor\n\n```php\n$results = $pdoOne-\u003etoMeta('select * from table'); \n```\n\nresult:\n\n```\narray(3) {\n  [0]=\u003e\n  array(7) {\n    [\"native_type\"]=\u003e\n    string(4) \"LONG\"\n    [\"pdo_type\"]=\u003e\n    int(2)\n    [\"flags\"]=\u003e\n    array(2) {\n      [0]=\u003e\n      string(8) \"not_null\"\n      [1]=\u003e\n      string(11) \"primary_key\"\n    }\n    [\"table\"]=\u003e\n    string(11) \"producttype\"\n    [\"name\"]=\u003e\n    string(13) \"idproducttype\"\n    [\"len\"]=\u003e\n    int(11)\n    [\"precision\"]=\u003e\n    int(0)\n  }\n  [1]=\u003e\n  array(7) {\n    [\"native_type\"]=\u003e\n    string(10) \"VAR_STRING\"\n    [\"pdo_type\"]=\u003e\n    int(2)\n    [\"flags\"]=\u003e\n    array(0) {\n    }\n    [\"table\"]=\u003e\n    string(11) \"producttype\"\n    [\"name\"]=\u003e\n    string(4) \"name\"\n    [\"len\"]=\u003e\n    int(135)\n    [\"precision\"]=\u003e\n    int(0)\n  }\n}\n```\n\n#### toListSimple()\n\nIt's a macro of runGen. It returns an indexed array from the first column\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003etoListSimple(); // ['1','2','3','4']\n```\n\n#### toListKeyValue()\n\nIt returns an associative array where the first value is the key and the second is the value.  \nIf the second value does not exist then it uses the index as value (first value).\n\n```php\n$results = $pdoOne-\u003eselect(\"cod,name\")\n-\u003efrom('table')\n-\u003etoListKeyValue(); // ['cod1'=\u003e'name1','cod2'=\u003e'name2']\n```\n\n#### toResult()\n\nIt's a macro of runGen. It returns a mysqli_result or null.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003etoResult(); //\n```\n\n#### firstScalar($colName=null)\n\nIt returns the first scalar (one value) of a query.\nIf $colName is null then it uses the first column.\n\n```php\n$count=$this-\u003ecount('from product_category')-\u003efirstScalar();\n```\n\n#### first()\n\nIt's a macro of runGen. It returns the first row if any, if not then it returns false, as an associative array.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003efirst(); \n```\n\n#### last()\n\nIt's a macro of runGen. It returns the last row (if any, if not, it returns false) as an associative array.\n\n```php\n$results = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003elast(); \n```\n\n\u003e Sometimes is more efficient to run order() and first() because last() reads all values.\n\n#### sqlGen()\n\nIt returns the sql command and string.\n\n```php\n$sql = $pdoOne-\u003eselect(\"*\")\n-\u003efrom('table')\n-\u003esqlGen();\necho $sql; // returns select * from table\n$results=$pdoOne-\u003etoList(); // executes the query\n```\n\n\u003e Note: it doesn't reset the query.\n\n## Query Builder (DML)\n\nThere are four ways to execute each command.\n\nLet's say that we want to add an **integer** in the column **col1** with the value **20**\n\n__Schema and values using a list of values__: Where the first value is the column, the second is the type of value (\ni=integer,d=double,s=string,b=blob) and second array contains the values.\n\n```php\n$pdoOne-\u003einsert(\"table\"\n    ,['col1']\n    ,[20]);\n```\n\n__Schema and values in the same list__: Where the first value is the column, the second is the type of value (\ni=integer,d=double,s=string,b=blob) and the third is the value.\n\n```php\n$pdoOne-\u003einsert(\"table\"\n    ,['col1',20]);\n```\n\n__Schema and values using two associative arrays__:\n\n```php\n$pdoOne-\u003einsert(\"table\"\n    ,['col1']\n    ,['col1'=\u003e20]);\n```\n\n__Schema and values using a single associative array__: The type is calculated automatically.\n\n```php\n$pdoOne-\u003einsert(\"table\"\n    ,['col1'=\u003e20]);\n```\n\n### insert($table,$schema,[$values])\n\nGenerates an insert command.\n\n```php\n$pdoOne-\u003einsert(\"producttype\"\n    ,['idproducttype','name','type']\n    ,[1,'cocacola',1]);\n```\n\nUsing nested chain (single array)\n\n```php\n    $pdoOne-\u003efrom(\"producttype\")\n        -\u003eset(['idproducttype',0 ,'name','Pepsi' ,'type',1])\n        -\u003einsert();\n```\n\nUsing nested chain multiple set\n\n```php\n    $pdoOne-\u003efrom(\"producttype\")\n        -\u003eset(\"idproducttype=?\",[101])\n        -\u003eset('name=?',['Pepsi'])\n        -\u003eset('type=?',[1])\n        -\u003einsert();\n```\n\nor (the type is defined, in the possible, automatically by MySql)\n\n```php\n    $pdoOne-\u003efrom(\"producttype\")\n        -\u003eset(\"idproducttype=?\",[101])\n        -\u003eset('name=?','Pepsi')\n        -\u003eset('type=?',1)\n        -\u003einsert();\n```\n\n### insertObject($table,[$declarativeArray],$excludeColumn=[])\n\n```php\n    $pdoOne-\u003einsertObject('table',['Id'=\u003e1,'Name'=\u003e'CocaCola']);\n```\n\nUsing nested chain declarative set\n\n```php\n    $pdoOne-\u003efrom(\"producttype\")\n        -\u003eset('(idproducttype,name,type) values (?,?,?)',[100,'Pepsi',1])\n        -\u003einsert();\n```\n\n\u003e Generates the query: **insert into productype(idproducttype,name,type) values(?,?,?)** ....\n\n### update($$table,$schema,$values,[$schemaWhere],[$valuesWhere])\n\nGenerates an insert command.\n\n```php\n$pdoOne-\u003eupdate(\"producttype\"\n    ,['name','type'] //set\n    ,[6,'Captain-Crunch',2] //set\n    ,['idproducttype'] // where\n    ,[6]); // where\n```\n\n```php\n$pdoOne-\u003eupdate(\"producttype\"\n    ,['name'=\u003e'Captain-Crunch','type'=\u003e2] // set\n    ,['idproducttype'=\u003e6]); // where\n```\n\n```php\n$pdoOne-\u003efrom(\"producttype\")\n    -\u003eset(\"name=?\",['Captain-Crunch']) //set\n    -\u003eset(\"type=?\",[6]) //set\n    -\u003ewhere('idproducttype=?',[6]) // where\n    -\u003eupdate(); // update\n```\n\nor\n\n```php\n$pdoOne-\u003efrom(\"producttype\")\n    -\u003eset(\"name=?\",'Captain-Crunch') //set\n    -\u003eset(\"type=?\",6) //set\n    -\u003ewhere('idproducttype=?',[6]) // where\n    -\u003eupdate(); // update\n```\n\n\u003e Generates the query: **update producttype set `name`=?,`type`=? where `idproducttype`=?** ....\n\n### delete([$table],[$schemaWhere],[$valuesWhere])\n\nGenerates a delete command.\n\n```php\n$pdoOne-\u003edelete(\"producttype\"\n    ,['idproducttype'] // where\n    ,[7]); // where\n```\n\n```php\n$pdoOne-\u003edelete(\"producttype\"\n    ,['idproducttype'=\u003e7]); // where\n```\n\n\u003e Generates the query: **delete from producttype where `idproducttype`=?** ....\n\nYou could also delete via a DQL builder chain.\n\n```php\n$pdoOne-\u003efrom(\"producttype\")\n    -\u003ewhere('idproducttype=?',[7]) // where\n    -\u003edelete(); \n```\n\n```php\n$pdoOne-\u003efrom(\"producttype\")\n    -\u003ewhere(['idproducttype'=\u003e7]) // where\n    -\u003edelete(); \n```\n\n\u003e Generates the query: **delete from producttype where `idproducttype`=?** ....\n\n## Cache\n\nIt is possible to optionally cache the result of the queries. The duration of the query is also defined in the query.\nIf the result of the query is not cached, then it is calculated normally (executing the query in the database). For\nidentify a query as unique, the system generates a unique id (uid) based in sha256 created with the query,\nparameters, methods and the type of operation.\n\nThe library does not do any cache operation directly, instead it allows to cache the results using an external library.\n\n* Cache works with the next methods.\n    * toList()\n    * toListSimple()\n    * first()\n    * firstScalar()\n    * last()\n\n### How to configure it?\n\n1. We need to define a class that implements the interface **\\eftec\\IPdoOneCache**\n\n```php\nclass CacheService implements \\eftec\\IPdoOneCache {\n    public $cacheData=[];\n    public $cacheCounter=0; // for debug\n    public  function getCache($uid,$family='') {\n        if(isset($this-\u003ecacheData[$uid])) {\n            $this-\u003ecacheCounter++;\n            echo \"using cache\\n\";\n            return $this-\u003ecacheData[$uid];\n        }\n        return false;\n    }\n    public function setCache($uid,$family='',$data=null,$ttl=null) {\n        \n        $this-\u003ecacheData[$uid]=$data;\n    }\n    public function invalidateCache($uid = '', $family = '') {\n        unset($this-\u003ecacheData[$uid]);\n    }\n}\n$cache=new CacheService();\n```\n\n(2) Sets the cache service\n\n```php\n    $pdoOne=new PdoOne(\"mysql\",\"127.0.0.1\",\"travis\",\"\",\"travisdb\");\n    $cache=new CacheService();\n    $$pdoOne-\u003esetCacheService($cache);\n```\n\n(3) Use the cache as follows, we must add the method **useCache()** in any part of the query.\n\n```php\n    $pdoOne-\u003eselect('select * from table')\n        -\u003euseCache()-\u003etoList(); // cache that never expires\n    $pdoOne-\u003eselect('select * from table')\n        -\u003euseCache(1000)-\u003etoList(); // cache that lasts 1000ms.\n```\n\n### Example using apcu\n\n```php\nclass CacheService implements \\eftec\\IPdoOneCache {\n    public  function getCache($uid,$family='') {\n        return apcu_fetch($uid);\n    }\n    public function setCache($uid,$family='',$data=null,$ttl=null) {\n        apcu_store($uid,$data,$ttl);\n    }\n    public function invalidateCache($uid = '', $family = '') {\n        // invalidate cache\n        apcu_delete($uid);\n    }\n}\n$cache=new CacheService();\n```\n\n## Sequence\n\nSequence is an alternative to AUTO_NUMERIC (identity) field. It has two methods to create a sequence: **snowflake** and\n**sequence**. It is an alternative to create a GUID mainly because it returns a number (a GUID usually is a string that\nit is more expensive to index and to store)\n\nThe goal of the sequence is to create a unique number that it is never repeated.\n\n* **sequence**: It uses the functionality of the database to create and use a sequence. MySql doesn't have sequences but\n  they are emulated. The main problem of the sequence is it returns a consecutive number, example: 1,2,3,4... This\n  number is predictable. For example, if you are the user number **20**, then you can guess another user = **19, 21**,\n  etc.\n* **snowflakes**: It uses a table to generate a unique ID. The sequence used is based on Twitter's Snowflake, and it is\n  generated based on\n  time (with microseconds), **nodeId** and a unique sequence. This generates a LONG (int 64) value that it's unique.\n  Example: **10765432100123456789**. This number is partially predictable .\n\n### Creating a sequence\n\n* **$dao-\u003enodeId** set the node value (default is 1). If we want unique values amongst different clusters, then we could\n  set the value of the node as unique. The limit is up to 1024 nodes.\n* **$dao-\u003etableSequence** it sets the table (and function), the default value is snowflake.\n\n```php\n$dao-\u003enodeId=1; // optional\n$dao-\u003etableSequence='snowflake'; // optional\n$dao-\u003ecreateSequence(); // it creates a table (and it could create a store procedure) called snowflake and a function called next_snowflake(). You could create it only once.\n```\n\n### Creating a sequence without a table.\n\nIt is possible to create a new sequence without any table. It is fast, but it could have problems of collisions.\n\n\u003e It ensures a collision free number only if we don't do more **than one operation per 0.0001 second** However, it also\n\u003e adds a pseudo random number (0-4095 based in time) so the chances of collision is **1/4095** (per two operations done\n\u003e every 0.0001 second). It is based on Twitter's Snowflake number. i.e.. **you are safe of collisions if you are doing\nless than 1 million of operations per second** (technically: 45 millions).\n\n* **$pdo-\u003egetSequencePHP([unpredictable=false])** Returns a sequence without using a table.\n  This sequence is more efficient than $dao-\u003egetSequence, but it uses a random value to deals\n  with collisions.\n\n* If upredictable is true then it returns an unpredictable number (it flips some digits)\n\n```php\n$pdo-\u003egetSequencePHP() // string(19) \"3639032938181434317\" \n```\n\n```php\n$dao-\u003egetSequencePHP(true) // string(19) \"1739032938181434311\" \n```\n\n### Using the sequence\n\n* **$dao-\u003egetSequence([unpredictable=false])** returns the last sequence. If the sequence fails to generate, then it\n  returns -1.\n  The function could fail if the function is called more than 4096 times every 1/1000th second.\n\n```php\n$pdo-\u003egetSequence() // string(19) \"3639032938181434317\" \n$pdo-\u003egetSequencePHP() // string(19) \"3639032938181434317\" \n```\n\n```php\n$pdo-\u003egetSequence(true) // returns a sequence by flipping some values.\n$pdo-\u003egetSequencePHP(true) // string(19) \"1739032938181434311\" \n```\n\n## Fields\n\n| Field                 | Description                                                                                                    | Example                            |\n|-----------------------|----------------------------------------------------------------------------------------------------------------|------------------------------------|\n| $prefixBase           | If we need to add a prefix to every table                                                                      | $this-\u003eprefixBase='example_';      |\n| $internalCacheCounter | The counter of hits of the internal cache.                                                                     | $this-\u003einternalCacheCounter=;      |\n| $nodeId               | Used by sequence (snowflake). nodeId It is the identifier of the node. It  must be between 0..1023             | $this-\u003enodeId=3;                   |\n| $tableSequence        | The name of the table sequence (snowflake)                                                                     | $this-\u003etableSequence=\"tableseq1\";  |\n| $masks0               | If we want to generate an unpredictable number (used by sequence)                                              | $this-\u003emasks0=[0,1,2,3,4];         |\n| $masks1               | If we want to generate an unpredictable number (used by sequence)                                              | $this-\u003emasks1=[4,3,2,1,0];         |\n| $databaseType         | The current type of database. It is set via el constructor                                                     | echo $this-\u003edatabaseType;          |\n| $server               | The current server machine                                                                                     | echo $this-\u003eserver;                |\n| $user                 | The current user                                                                                               | echo $this-\u003euser;                  |\n| $pwd                  | The current password                                                                                           | echo $this-\u003epwd;                   |\n| $db                   | The current database or schema (oracle ignores this value)                                                     | echo $this-\u003edb;                    |\n| $charset              | To set the default charset. It must be set via constructor                                                     | echo $this-\u003echarset;               |\n| $isOpen               | It is true if the database is connected otherwise,it's false                                                   | if($this-\u003eisOpen) { …};            |\n| $throwOnError         | If true (default), then it throws an error if happens an  error. If false, then the execution continues        | $this-\u003ethrowOnError=false;         |\n| $conn1                | The instance of PDO. You can set it or use it directly.                                                        | $this-\u003econn1-\u003epdoStatement(..);    |\n| $transactionOpen      | True if the transaction is open                                                                                | if($this-\u003etransactionOpen) { …};   |\n| $readonly             | if the database is in READ ONLY mode or not. If true then we  must avoid to write in the database              | $this-\u003ereadonly=true;              |\n| $logFile              | full filename of the log file. If it's empty then it doesn't  store a log file. The log file is limited to 1mb | $this-\u003elogFile=\"/folder/file.log\"; |\n| $errorText            | It stores the last error. runGet and beginTry resets it                                                        | echo $this-\u003eerrorText;             |\n| $isThrow              | todo                                                                                                           | $this-\u003eisThrow=;                   |\n| $logLevel             | It indicates the current level of log. 0 = no log (for production), 3= full log                                | $this-\u003elogLevel=3;                 |\n| $lastQuery            | Last query executed                                                                                            | echo $this-\u003elastQuery;             |\n| $lastParam            | The last parameters. It is an associative array                                                                | echo $this-\u003elastParam;             |\n\n## Encryption\n\nThis library permits encryption/decryption of the information.\n\nTo set the encryption you could use the next command:\n\n```php\n$this-\u003esetEncryption(12345678, '', 'INTEGER'); // the type of encryption is integer and it only works with integers. It doesn't use a salt value\n$this-\u003esetEncryption('password', 'some-salt', 'AES-256-CTR'); // the password, the salt and the type of encryption (aes-256-ctr), you can use other methods\n$this-\u003esetEncryption('passwrd', '', 'SIMPLE'); // the type of encryption is simple and it only works with primitive values. It doesn't use a salt.\n```\n\nThen you can encrypt and decrypt a value using\n\n```php\n$encrypted=$this-\u003eencrypt($original); // encrypt $original\n$original=$this-\u003edecrypt($encrypted); // decrypt $encrypted\n```\n\nExample:\n\n```php\n$this-\u003esetEncryption('12345', 'salt-1234'); // it will use AES-256-CTR, the password and the salt must be secret.\n// create user\n$this-\u003eset(['username' =\u003e 1, 'password' =\u003e $this-\u003eencrypt($password)])\n     -\u003efrom('user')\n     -\u003einsert();\n// validate user\n$user=$this-\u003eselect(['username','password'])\n    -\u003efrom('user')\n    -\u003ewhere(['username','password'],[1,$this-\u003eencrypt($password)])\n             -\u003efirst();\n// $user= if false or null then the user does not exist or the password is incorrect.\n```\n\n## How to debug and trace errors in the database?\n\n### Setting the log level\n\nYou can set the log level to 3. The log level works when the operation fails, the higher the log level, then it shows\nmost information.\n\n```php\n$pdoOne-\u003elogLevel=3; // the highest for debug.\n```\n\n* 0=no debug for production (all message of error are generic)\u003cbr\u003e\n* 1=it shows an error message\u003cbr\u003e\n* 2=it shows the error messages and the last query\n* 3=it shows the error message, the last query and the last parameters (if any). It could be unsafe (it could show\n  passwords)\n\n### Throwing errors\n\nBy default, PdoOne throws PHP errors, but we could avoid it by setting the field $throwOnError to false.\n\n```php\n$pdoOne-\u003ethrowOnError=false; // it could be used in production.\n```\n\n### Getting the last Query\n\n```php\nvar_dump($pdoOne-\u003elastQuery); // it shows the last query\nvar_dump($pdoOne-\u003elastParam); // and it shows the last parameters.\n```\n\n### Generating a log file\n\nIf empty then it will not generate a log file (using the php log file)\n\n```php\n$pdoOne-\u003elogFile=true; \n```\n\n## CLI\n\n**PdoOne** has some features available only in CLI.\n\n![](examples/cli.jpg)\n\n### Run as cli\n\nExecute the next line (in the lib folder)\n\n\u003e php pdoonecli.php \u003carg\u003e\n\n(or pointing to the right folder)\n\n\u003e php /var/web/vendor/eftec/lib/pdoonecli \u003carg\u003e\n\n### Run as CLI interative\n\nYou could use the flag \"-i\" to enter in interactive mode.\n\nYou could use the TAB key to autocomplete values (if any).\n\n![](examples/cli2.jpg)\n\nNote: You could also save and load the configuration.\n\n#### Examples\n\nConnect to mysql and generate a csv from the table \"actor\"\n\n```shell\n## via arguments\nphp pdoonecli --databasetype mysql --server 127.0.0.1 -u root -p abc.123 --database sakila -in actor -out csv\n## via user input (interactive)\nphp pdoonecli -i -in actor -out csv\n```\n\nSave the configuration in a file\n\n```shell\nphp pdoonecli --databasetype mysql --server 127.0.0.1 -u root -p abc.123 --database sakila --saveconfig myconfig\n```\n\nLoad the configuration from a file\n\n```shell\nphp pdoonecli --loadconfig myconfig -in actor -out csv\n```\n\n### Run CLI to generate repository classes.\n\nYou could use the flag \"-cli\" to generate the repository classes\n\n![](examples/cli3.jpg)\n\nThe CLI is interactive, and it allows to load and save the configuration.\n\n### cli-classcode\n\nThe functionality will generate a ready-to-use repository class.\n\nLet's say the next example\n\n\u003e mysql:  \n\u003e php pdoone.php --database mysql --server 127.0.0.1:3306 --user root -p abc.123 -db sakila --input \"Actor\" --output\n\u003e classcode  \n\u003e sqlsrv:  \n\u003e php pdoone.php --database sqlsrv --server PCJC\\SQLEXPRESS --user sa -p abc.123 -db sakila --input \"Actor\" --output\n\u003e classcode\n\nIt will connect to the database mysql, ip: 127.0.0.1 and database sakila, and it will read the \"actor\" table.\n\nIt will return the next result\n\n```php\n/**\n * Generated by PdoOne Version 1.28\n * Class ActorRepo\n */\nclass ActorRepo\n{\n    const TABLE = 'Actor';\n    const PK = 'actor_id';\n    /** @var PdoOne */\n    public static $pdoOne = null;\n\n    /**\n     * It creates a new table\u003cbr\u003e\n     * If the table exists then the operation is ignored (and it returns false)\n     *\n     * @param array $definition\n     * @param null  $extra\n     *\n     * @return array|bool|PDOStatement\n     * @throws Exception\n     */\n    public static function createTable($definition, $extra = null) {\n        if (!self::getPdoOne()-\u003etableExist(self::TABLE)) {\n            return self::getPdoOne()-\u003ecreateTable(self::TABLE, $definition, self::PK, $extra);\n        }\n        return false; // table already exist\n    }\n    // .....\n}\n\n```\n\nThis functionality will generate a new Repository class with the most common operations: insert,\nlist, update, delete, get, count, create table, drop table and truncate table\n\nWhy we need to generate a class? (instead of inherit one)  This Crud class is only a starting point. The developer\ncould modify the code, add new methods, modify previous method and so on.\n\nFor to use the class, we could write the next code:\n\n```php\n// 1) option 1, inject an instance of $pdo\nActorRepo::setPdoOne($pdoOne); // it inject the current connect to the database\n\n// 2) option 2.\n// If the global variable $pdoOne exists, then it is injected. (unless it is defined by using setPdoOne()\n$pdoOne=new PdoOne(\"mysql\",\"127.0.0.1\",\"root\",\"abc.123\",\"sakila\",\"\");\n$pdoOne-\u003econnect();\n\n// 3) option 3\n// If the global function pdoOne() exists, then it is used for obtain the instance.\nfunction pdoOne() {\n    global $pdo;\n    if ($pdo===null) {\n        $pdo=new PdoOne('mysql','127.0.0.1','root','abc.123','sakila');\n    }\n    return $pdo;\n}\n\n\n$actorActorRepo::get(2); // it will read the actor with the pk=2 and it will return as an array.\n$actors=$actorArray=ActorRepo::select(); // it returns all the rows.\n\n```\n\nAlternatively, you could generate the php file automatically as follows:\n\n\u003e php pdoone.php -database mysql -server 127.0.0.1:3306 -user root -pwd abc.123 -db sakila\n\u003e -input \"Actor\" -output classcode \u003eActorRepo.php\n\nNote: the code lacks of php-tags, namespace and use but everything else is here.\n\n### cli-selectcode\n\nIt will take a query and will return a php code with the query formatted.\n\nExample:\n\n\u003e php pdoone.php -database mysql -server 127.0.0.1:3306 -user root -pwd abc.123 -db sakila\n\u003e -input \"select * from actor\" -output selectcode\n\nIt will generate the next code:\n\n```php\n /** @var array $result=array([\"actor_id\"=\u003e0,\"first_name\"=\u003e'',\"last_name\"=\u003e'',\"last_update\"=\u003e'']) */\n $result=$pdo\n         -\u003eselect(\"*\")\n         -\u003efrom(\"actor\")\n         -\u003etoList();\n```\n\n### cli-arraycode\n\nIt will generate an associative array (with default values) based in the query or table selected.\n\n\u003e php pdoone.php -database mysql -server 127.0.0.1:3306 -user root -pwd abc.123 -db sakila\n\u003e -input \"select * from actor\" -output arraycode\n\nIt will return:\n\n```php\n// [\"actor_id\"=\u003e0,\"first_name\"=\u003e'',\"last_name\"=\u003e'',\"last_update\"=\u003e'']\n```\n\n### cli-json\n\nIt will return the result of the query as a json\n\n\u003e php pdoone.php -database mysql -server 127.0.0.1:3306 -user root -pwd abc.123 -db sakila\n\u003e -input \"select * from actor\" -output json\n\nIt will return:\n\n```json\n[{\"actor_id\":\"1\",\"first_name\":\"PENELOPE\",\"last_name\":\"GUINESS\",\"last_update\":\"2006-02-15 01:34:33\"}\n,{\"actor_id\":\"2\",\"first_name\":\"NICK\",\"last_name\":\"WAHLBERG\",\"last_update\":\"2006-02-15 01:34:33\"}\n,{\"actor_id\":\"3\",\"first_name\":\"ED\",\"last_name\":\"CHASE\",\"last_update\":\"2006-02-15 01:34:33\"}\n,{\"actor_id\":\"4\",\"first_name\":\"JENNIFER\",\"last_name\":\"DAVIS\",\"last_update\"}]\n```\n\n### cli-csv\n\nIt will return the result of the query as a json\n\n\u003e php pdoone.php -database mysql -server 127.0.0.1:3306 -user root -pwd abc.123 -db sakila\n\u003e -input \"select * from actor\" -output csv\n\nIt will return:\n\n```csv\nactor_id,first_name,last_name,last_update\n1,\"PENELOPE\",\"GUINESS\",\"2006-02-15 01:34:33\"\n2,\"NICK\",\"WAHLBERG\",\"2006-02-15 01:34:33\"\n3,\"ED\",\"CHASE\",\"2006-02-15 01:34:33\"\n4,\"JENNIFER\",\"DAVIS\",\"2006-02-15 01:34:33\"\n```\n\n### UI\n\nAlternatively to the CLI, the library has an interface visual. It does all the operation of the CLI.\n\n![](examples/ui.jpg)\n\n### How to run the UI?\n\nSimply call the method render()\n\n```php\n\u003c?php\n\nuse eftec\\PdoOne;\nuse mapache_commons\\Collection;\n\ninclude \"../vendor/autoload.php\";\n\n$dao=new PdoOne(\"test\",\"127.0.0.1\",\"dummy\",\"dummy\",\"dummy\"); // we need any connection.\n$dao-\u003elogLevel=3;\n\n$dao-\u003erender();\n```\n\n\u003e There is an example in the folder examples/testui.php\n\n### DDL  Database Design Language\n\nThe next commands usually are executed alone (not in a chain of methods)\n\n| Method              | Description                                                        | Example                               |\n|---------------------|--------------------------------------------------------------------|---------------------------------------|\n| createTable()       | Creates the table and indexes using the definition inside the Repo | TablaParentRepo::createTable();       |\n| createForeignKeys() | Create all foreign keys of the table                               | TablaParentRepo::createForeignKeys(); |\n| dropTable()         | Drop the table                                                     | TablaParentRepo::dropTable();         |\n| truncate()          | Truncate the table                                                 | TablaParentRepo::truncate();          |\n| validTable()        | Validate if the table hasn't changed                               | $ok=TablaParentRepo::validTable();    |\n\n```php\nTablaParentRepo::createTable();\nTablaParentRepo::createForeignKeys();\nTablaParentRepo::dropTable();\nTablaParentRepo::truncate();\n// We don't have a method to alter a table.\n$ok=TablaParentRepo::validTable(); // it returns true if the table matches with the definition stored into the clas\n```\n\n### Nested Operators\n\nThe nested operators are methods that should be in between of our chain of methods.\n\n\u003e ClassRepo::op()::where()::finalop() is ✅\n\u003e\n\u003e ClassRepo::op()::op()::where() will leave the chain open ❌\n\nFor example:\n\n```php\n// select * \n//        from table \n//        inner join table2 on t1=t2 \n//        where col=:arg\n//        and col2=:arg2\n//    group by col\n//        having col3=:arg3\n//    order by col\n//    limit 20,30\n$results=$pdo-\u003eselect('*')\n    -\u003efrom('table')\n    -\u003einnerjoin('table2 on t1=t2')\n    -\u003ewhere('col=:arg and col2:=arg2',[20,30]) \n    // it also works with -\u003ewhere('col=:arg',20)-\u003ewhere('col2'=\u003e30)\n    // it also works with -\u003ewhere('col=?',20)-\u003ewhere('col2=?'=\u003e30)\n    -\u003egroup('col')\n    -\u003ehaving('col3=:arg3',400)\n    -\u003eorder('col')\n    -\u003elimit('20,30')\n    -\u003etoList(); // end of the chain\n\n```\n\n| Method      | Description                           | Example                      |\n|-------------|---------------------------------------|------------------------------|\n| where()     | It adds a where to the chain          | TablaParentRepo::where()     |\n| order()     | It adds a order by to the chain       | TablaParentRepo::order()     |\n| group()     | it adds a group by to the chain       | TablaParentRepo::group()     |\n| limit()     | It limits the results                 | TablaParentRepo::limit()     |\n| page()      | Its similar to limit but it uses page | TablaParentRepo::page()      |\n| innerjoin() | It adds a inner join to the query     | TablaParentRepo::innerjoin() |\n| left()      | It adds a left join to the query      | TablaParentRepo::left()      |\n| right()     | It adds a right join to the query     | TablaParentRepo::right()     |\n\n### DQL Database Query Language\n\nWe have different methods to generate a DQL (query) command in our database.\n\n\u003e If the operation fails, they return a FALSE, and they could trigger an exception.\n\u003e\n\u003e The next methods should be at the end of the chain. Examples:\n\u003e\n\u003e ClassRepo::op()::op()::toList() is ✅\n\u003e\n\u003e ClassRepo::op()::toList()::op() will trigger an exception ❌\n\n| Command  | Description                           | Example                                                                                                                                                                                                                         |\n|----------|---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| toList() | Returns an array of elements          | $data=TableNameRepo::toList(); // select * from tablerepo\u003cbr /\u003e$data=TableNameRepo::where('a1=?',[$value])::toList(); // select * from tablerepo where a1=$value                                                                |\n| first()  | Returns a simple row                  | $data=TableNameRepo::first($pk); // select * from tablerepo where pk=$pk  (it always returns 1 or zero values)\u003cbr /\u003e$data=TableNameRepo::where('a1=?',[$value])::first(); // it returns the first value (or false if not found) |\n| exist()  | Returns true if a primary key exists  | $data=TableNameRepo::exist($pk); // returns true if the object exists.                                                                                                                                                          |\n| count()  | Returns the number of rows in a query | $data=TableNameRepo::count($conditions); \u003cbr /\u003e$data=TableNameRepo::where('a1=?',[$value])::count();                                                                                                                            |\n\n### DML Database Model Language\n\nThe next methods allow inserting,update or delete values in the database.\n\n| Method     | Description                                                                | Example                                  |\n|------------|----------------------------------------------------------------------------|------------------------------------------|\n| insert     | It inserts a value into the database. It could return an identity          | $identity=TablaParentRepo::insert($obj); |\n| update     | It updates a value into the database.                                      | TablaParentRepo::update($obj);           |\n| delete     | It deletes a value from the database.                                      | TablaParentRepo::delete($obj);           |\n| deletebyId | It deletes a value (using the primary key as condition) from the database. | TablaParentRepo::deleteById($pk);        |\n\n```php\n// where obj is an associative array or an object, where the keys are the name of the columns (case sensitive)\n$identity=TablaParentRepo::insert($obj); \nTablaParentRepo::update($obj);\nTablaParentRepo::delete($obj);\nTablaParentRepo::deleteById(id);\n```\n\n### Validate the model\n\nIt is possible to validate the model. The model is validated using the information of the database, using the type of\nthe column, the length, if the value allows null and if it is identity (auto numeric).\n\n```php\n$obj=['IdUser'=\u003e1,'Name'='John Doe']; \nUserRepo::validateModel($obj,false,['_messages']); // returns true if $obj is a valid User.\n```\n\n### Recursive\n\nA recursive array is an array of strings with values that it could be read or obtained or compared. For example, to join\na table conditionally.\nPdoOne does not use it directly but _BasePdoOneRepo uses it (_BasePdoOneRepo is a class used when we generate a\nrepository service class automatically).\n\nExample\n\n```php\n$this-\u003eselect('*')-\u003efrom('table')-\u003erecursive(['table1','table1.table2']);\n// some operations that involves recursive\nif($this-\u003ehasRecursive('table1')) {\n    $this-\u003einnerJoin('table1 on table.c=table1.c');\n}\nif($this-\u003ehasRecursive('table1.table2')) {\n    $this-\u003einnerJoin('table1 on table1.c=table2.c');\n}\n$r=$this-\u003etoList(); // recursive is resetted.\n```\n\n#### recursive()\n\nIt sets a recursive array.\n\n\u003e This value is resets each time a chain methods ends.\n\n#### getRecursive()\n\nIt gets the recursive array.\n\n#### hasRecursive()\n\nIt returns true if recursive has some needle.\n\nIf $this-\u003erecursive is ['*'] then it always returns true.\n\n```php\n$this-\u003eselect('*')-\u003efrom('table')-\u003erecursive(['*']);\n$this-\u003ehasRecursive('anything'); // it always returns true.\n```\n\n## Benchmark (mysql, estimated)\n\n| Library                 | Insert | findPk | hydrate | with | time   |\n|-------------------------|--------|--------|---------|------|--------|\n| PDO                     | 671    | 60     | 278     | 887  | 3,74   |\n| **PdoOne**              | 774    | 63     | 292     | 903  | 4,73   |\n| LessQL                  | 1413   | 133    | 539     | 825  | 5,984  |\n| YiiM                    | 2260   | 127    | 446     | 1516 | 8,415  |\n| YiiMWithCache           | 1925   | 122    | 421     | 1547 | 7,854  |\n| Yii2M                   | 4344   | 208    | 632     | 1165 | 11,968 |\n| Yii2MArrayHydrate       | 4114   | 213    | 531     | 1073 | 11,22  |\n| Yii2MScalarHydrate      | 4150   | 198    | 421     | 516  | 9,537  |\n| Propel20                | 2507   | 123    | 1373    | 1960 | 11,781 |\n| Propel20WithCache       | 1519   | 68     | 1045    | 1454 | 8,228  |\n| Propel20FormatOnDemand  | 1501   | 72     | 994     | 1423 | 8,228  |\n| DoctrineM               | 2119   | 250    | 1592    | 1258 | 18,139 |\n| DoctrineMWithCache      | 2084   | 243    | 1634    | 1155 | 17,952 |\n| DoctrineMArrayHydrate   | 2137   | 240    | 1230    | 877  | 16,83  |\n| DoctrineMScalarHydrate  | 2084   | 392    | 1542    | 939  | 18,887 |\n| DoctrineMWithoutProxies | 2119   | 252    | 1432    | 1960 | 19,822 |\n| Eloquent                | 3691   | 228    | 708     | 1413 | 12,155 |\n\nPdoOne adds a bit of ovehead over PDO, however it is simple a wrapper to pdo.\n\n## migration from 3 to 4\n\n* If you are not using ORM features, then you don't need to do any change.\n* If you are using ORM features then:\n  * Add the new library [eftec/PdoOneORM](https://github.com/EFTEC/PdoOneORM)\n  * Use $pdo=new PdoOneORM(); instead of $pdo=new PdoOne();\n  * The filename configuration of the CLI must be rebuilt again.\n\n## Error FAQs\n\n### Uncaught Error: Undefined constant eftec\\_BasePdoOneRepo::COMPILEDVERSION\n\nIt means that you are updated PdoOne, and you are using one class generated by the ORM. This class must be re-generated.\n\n## Changelist\n\nIn a nutshell:\n\n\u003e Every major version means that it could break old code. I.e. 1.0 -\u003e 2.0\n\u003e\n\u003e Every minor version means that it adds a new functionality i.e. 1.5 -\u003e 1.6 (new methods)\n\u003e\n\u003e Every decimal version means that it patches/fixes/refactoring a previous functionality i.e. 1.5.0 -\u003e 1.5.1 (fix)\n\n* 4.13.2 2025-02-20\n  * Later fix in the constructor.\n* 4.13 2025-02-20\n  * Added prefix and postfix to the referential columns. \n* 4.12 2024-12-30 \n  * Compatibility with PHP 8.4\n  * Some preliminary work with Sqlite and PostgreSQL\n* 4.11 2024-10-08 (not yet released)\n  * sqlGen() now allows empty \"from\".\n    * Note: on \"oci\" (Oracle), it uses \"from dual\"\n* 4.10 2024-09-06\n  * **[upd]** constructor now allows to use of an array \n* * 4.9.2 2024-08-20\n  * **[fix]** added more fixed to where(), now considering \"is not null\" where field\u003c\u003e:value (and :value is null) \n* 4.9.1 2024-08-20\n  * **[fix]** fixed a bug in where(), where the value is null.\n    * 4.9: $this-\u003e...-\u003ewhere('col',null); // select * from table where col=null (invalid query)\n    * 4.9.1: $this-\u003e...-\u003ewhere('col',null); // select * from table where col is null (valid)\n* 4.9 2024-08-02\n  * **[upd]** camelize update to consider \"-\" and \"\\_\" and not only \"\\_\"\n  * **[upd]** update dependencies.\n* 4.8 2024-07-06\n  * **[upd]** added fetchMode for runRawQuery()\n  * **[new]** added setFetchMode()\n  * **[new]** PdoOneQuery added runRawQuery() which is a wrapper of PdoOne::runRawQuery()\n* 4.7.1 2024-06-07\n  * **[fix]** Fixed a phpdoc in PdoOneQuery::where() \n* 4.7 2024-06-07\n  * **[upd]** Update phpdoc using markdown without \"php\" because PHPStorm is not compatible with it.\n* 4.6.2 2024-03-02\n  * **[fix]** PdoOne::$cacheService is now mixed.\n* 4.6.1 2024-03-02\n  * **[fix]** PdoOne::$instance is null by default (instead of undefined)  \n  * **[upd]** updated CliOne dependency.\n* 4.6 2024-03-02\n  * Updating dependency to PHP 7.4. The extended support of PHP 7.2 ended 3 years ago.\n  * Added more type hinting in the code.\n* 4.4 2023-12-12\n  * updated PodOneQuery to be compatible with PdoOneORM \n  * update phpdoc to be compatible with Visual Studio Code.\n* 4.3.3 2023-09-05\n  * change the PHPDOC comments, now it uses markdown instead of \"pre\" tag.\n* 4.3.2 2023-09-05\n  * A small fix with the error messages, now on level 1 it shows the cause of the error. \n* 4.3.1 2023-09-02\n  * [PdoOneCli] Update to 2.5\n    * Fixed a problem when the cli ends.\n    * The class is able to return an instance of it.\n* 4.3 2023-07-01\n  * [PdoOneQuery] Update to 4.1\n    * _toList() added argument $returnArray\n    * toPdoStatement() new method\n    * fetchLoop() new method.\n* 4.2 2023-04-07\n  * [PdoOne] the constructor allows to set the key-value table.\n  * [PdoOne] new methods getTableKV() getDefaultTableKV(),existKVTable()\n  * [PdoOneCli] Update to 2.3.1.  Now you can enter more values. Also, load and save works in PHP format (it is more flexible4)\n* 4.1.2 2023-03-21\n  * str_start_with() is not defined in PHP older than PHP 8.0, so I replaced. \n* 4.1.1 2023-03-21\n  * [PdoOneCli] Update to 2.3.1. \n  * [composer.json] Update dependency to eftec/clione 1.26 or higher.\n* 4.1 2023-03-20\n  * [PdoOneCli] Updated to 2.3. Now menu is generated by library CliOne. \n* 4.0.1 2023-03-11\n  * [PdoOneCli] Fix a small bug with option save. It failed to ask the filename. \n* 4.00 2023-11-03\n  * [PdoOne] 4.0 Now ORM features are separated in a different library called [eftec/PdoOneORM](https://github.com/EFTEC/PdoOneORM).\n    * If you want to use ORM, then install the library [eftec/PdoOneORM](https://github.com/EFTEC/PdoOneORM) and use it instead.  \n    * See [migration from 3 to 4](#migration-from-3-to-4) for further information.\n  * [PdoOne] new method factoryFromArray()\n  * [PdoOne] Removed all old GUI features that are not available anymore.\n  * [CLI] The cli was rebuilt. Only a few features are present. Now, it allows to save the configuration, load and save\nit as a PHP file.\n  * [_BasePdoOne] Now it is separated in eftec/pdoonerepo\n\n* 3.16 2023-12-02\n    * [PdoOneQuery] 3.11\n        * exists(),insert(),update(),delete(),deleteById() fixed a bug that caused a recursivity\n        * insertObjects() avoids to add a numeric index. Now it adds the correct index\n    * [PdoOne] 3.16\n        * dateConvertInput() does not crash if the date is incorrect, and it tries to determine the current time.\n        * runRawQuery() returns false if the inmediate query fails\n        * Added the method generateCodeArrayRecursive() used to generate code.\n        * rollback() allows to show the cause why it failed\n        * The templates (used to generate the code) now validates some input and output values.\n    * [BasePdoOneRepo] 6.7\n        * validateModel() now works with date. If the date is incorrect then it returns false. It also cleans the last\n          error.\n          if the cause is correct.\n        * recursive insert or update now validates if the record exists using the right class.\n        * called to rollback() now stores the cause of why it failed.\n* 3.15 2023-02-03\n    * [PdoOneQuery] 3.10 Fixed a problem with insert(),update(),delete(), it will not reset the stack correctly.\n    * [_BasePdoOneRepo] reset() method is now public.\n* 3.14 2023-01-30\n    * [PdoOneQuery] 3.9 Fixed a problem with first() where the primary key is not numeric.\n    * [Pdo] /[PdoOneQuery] New method now() to obtain the date and time of the database.\n    * [_BasePdoOneRepo] 12 Updated to binary version 12. You must rebuild the ORM files.\n* 3.13 2023-01-26\n    * [PdoOneQuery] Fixed a problem with single() value.\n    * [PdoOne] Fixed if MessageContainer is not loaded (now, it is ignored and not used)\n* 3.12.2 2022-09-03\n    * [_BasePdoOneRepo] Added some missing argument hinting\n    * [_BasePdoOneRepo] Fixed a problem with Insert()\n    * [PdoOne] fixed some problem when some indexes are missing\n    * [PdoOneEncryption] Added some missing argument hinting\n* 3.12.1 2022-08-26\n    * [PdoOneQuery] fixed a problem with page() in an ORM.\n* 3.12 2022-08-14\n    * [PdoOne] Added field $prefixTable to prefix every table in the database.\n        * It works with select,insert,update,delete,from,count and many others operations.\n* 3.11.1 2022-07-30\n    * [CLI] update CLI to 1.6.1 Added the column \"key\" to \"tablefull\".\n* 3.11 2022-07-30\n    * [CLI] update CLI to 1.6. Added \"relation2\" and \"tablefull\" to definitions.\n* 3.10 2022-07-30\n    * [CLI] update CLI to 1.5.\n* 3.9 2022-07-23\n    * [ORM] \\[CLI] Now, you can savely edit some part of the code generated under the comment blocks marked as \"EDIT\".\n* 3.8.1 2022-07-23\n    * [ORM] fixed another problem with where() when the filter use a named parameter.\n    * [CLI] Exit option exists instantly. And create does not exit.\n* 3.8 2022-07-22\n    * [ORM] fixed a problem when where is used and more than two column (different tables) use the same name of column.\n* 3.7 2022-07-16\n    * [ORM] fixed a problem with first\n    * [ORM] fixed a problem with insert and conversion of columns\n    * _BasePdoOne update to binary version 11. It will require regeneration of repository classes.\n* 3.6 2022-07-07\n    * [CLI] update CLI to 1.1\n* 3.5 2022-07-06\n    * [ORM] fixed recursive when \"query\", \"insert\",\"update\" and \"delete\". Now recursive work with aliases.\n    * _BasePdoOne update to binary version BINARYVERSION. It will require regeneration of repository classes.\n* 3.3 2022-06-27\n    * [CLI] updated CLI to 1.0\n* 3.2 2022-06-27\n    * [CLI] updated CLI to 0.14\n* 3.1.6 2022-06-24\n    * [CLI] solved a problem with the conversion per type of column\n    * [_BasePdoOneRepo] Fixed a problem with the conversion of the end results.\n* 3.1.5 2022-06-23\n    * [PdoOneQuery] Solved a bug when the cache is invalidated when insert(),update(), etc.\n* 3.1.4 2022-06-21\n    * [CACHE] fixed a problem with the cache and type hinting.\n* 3.1.3 2022-06-18\n    * [ORM] fixed a bug with the template of the abstract file and limit()\n* 3.1.2 2022-06-18\n    * [ORM] fixed a bug with the template of the abstract file and limit()\n* 3.1.1 2022-06-17\n    * fixed a bug with limit() and page()\n* 3.1 2022-06-11\n    * fixed a problem with mysql in Linux in the method getdeftablefk()\n* 3.0 2022-06-1\n    * _BasePdoOneRepo rebuild from scratch.\n    * [ORM] the use of dependencies are changed.\n* 2.32 2022-03-20\n    * createTable() allows to specify the definition of the columns universally using a pseudo php syntax.\n* 2.31 2022-03-04\n    * PdoOneCli updated to version 0.10\n* 2.30 2022-02-28\n    * Update PdoOneCli to version 0.9\n        * The CLI is almost functional with the new engine however it requires some cleanups.\n* 2.29 2022-02-20\n\n    * Added as a binary file (vendor/bin/pdoonecli)\n\n* 2.27 2022-02-19\n\n    * **[core]** lots of cleanups.\n    * **[_BasePdoOneRepo]** update to binary version 8.  **You must rebuild the repository classes to rebuild the base\n      class.**\n\n* 2.26 2022-02-19\n    * **[core]** ****[new]**** added more type hiting for the arguments for safety and stability of the tool.\n    * **[cli]** now the CLI is located a different file called pdoonecli Also the CLI has more features than before,\n      including the generation of the OOP classes.\n\n* 2.25 2022-02-01\n    * **[core]** ****[new]**** Key-Value functionalities:setKvDefaultTable(),kv(),createTableKV(),dropTableKV(),getKV()\n      ,setKV(),garbageCollectorKV(),delKV(),flushKV(),existKV()\n    * **[core]** ****[new]**** createIndex()\n\n* 2.24.1 2022-02-06\n\n    * **[core]** ****[fix]**** Now, most generation of classes are defined in templates instead of the code. It will keep\n      the code clean while it will also save a few bits of memories (old: 6446 lines, current: 5963 lines).\n\n* 2.24 2022-02-06\n\n    * **[repo]** Now the library allows multiple connections using different repository class bases.\n    * **[_BasePdoOne]** Updated to version 7. **You must rebuild the repository classes to rebuild the base class.**\n    * **[core]** ****[new]**** Now **MessageContainer** is injected automatically\n    * **[core]** ****[new]**** You can obtain an instance of PdoOne using the static method PdoOne::instance()\n    * **[core]** ****[fix]**** Method lastError() always returns a string (empty if not error) instead of a NULL.\n    * **[core]** **[change]** \u003cu\u003eMethod getMessages() rename to getMessageContainer()\u003c/u\u003e\n    * **[core]** ****[new]**** Method getMessages() returns all the messages.\n    * **[core]** ****[new]**** Method getErrors(),getFirstError(),getLastError(),hasError() return error messages.\n    * **[core]** ****[new]**** Method getInfos(),getFirstInfo(),getLastInfo() return info messages.\n\n* 2.23 2022-02-04\n\n    * **[PdoOneQuery]** **[PdoOne]** ****[fix]**** Fixed compatibility with PHP 8.1. PHP 8.1 deprecates a lot of\n      functionalities.\n    * ****[new]**** update dependency to php\u003e=7.2.5 to stay in sync with Composer. If you have trouble, then you can use an\n      old version of the library\n\n* 2.22.2 2022-02-01\n    * **[PdoOneQuery]** ****[fix]**** when the argument of a method is empty or zero. Now, it throws an exception.\n\n* 2.22.1 2022-01-03\n    * **[core]** **[edit]** generateAllClasses() now returns errors and warnings.\n\n* 2.22 2022-01-30\n    * **[core]** **[edit]** A new static value called $pageSize\n    * **[PdoOneQuery]** **[edit]** the method page() allows to specify the size of the page.\n    * **[_BasePdoOne]** **[edit]** the method page() allows to specify the size of the page.\n\n* 2.21 2022-01-28\n    * **[core]** ****[fix]**** method singularTable() is now more exact to convert plural names to singular.\n    *               However, it is far from perfect.\n    * **[_BasePdoOne]** [fixed] now several methods store the last error.\n\n* 2.20 2022-01-04\n    * ****[new]**** update dependency to php\u003e=7.1.3. PHP 5.6 was discontinued 3 years ago.\n\n* 2.19\n    * ****[new]**** **[core]** callProcedure() could return a value other than true or false (SQL server only)\n    * ****[new]**** **[sqlsrv]** implemented callProcedure() and createProcedure()\n\n* 2.18\n    * ****[new]**** [oci] added oci (oracle) as a new driver.\n    * ****[fix]**** **[core]** dbTypeToPHP() and datesql2Text()\n    * ****[new]**** **[core]** clearError(),removeDoubleQuotes() and a new argument for connect()\n\n* 2.16\n    * ****[fix]**** **[sqlsrv]** fixed the format of the date-time of sql.\n    * ****[fix]**** **[sqlsrv]** columnTable() returns distinct values.\n\n* 2.15 2021-07-24\n\n* 2.14.3 2021-06-15\n    * ****[fix]**** **[orm]** setCache()::first() and setCache()::count() didn't work correctly. fixed.\n    * Query now supports factoryNull()\n\n* 2.14.2 2021-06-13\n    * ****[fix]**** **[orm]** useCache() and setRelation() do not chain correctly, fixed.\n    * ****[fix]**** **[orm]** useCache() doubled the cache. fixed.\n\n* 2.14.1 2021-06-09\n    * ****[fix]**** custom_exception_handler when the error returned does not have an argument, or the argument is not an\n      array.\n\n* 2.14 2021-06-04\n\n*\n    * **_BasePdoOneRepo** now works more closely with the class **PdoOneQuery**, so each query is a different instance.\n\n    * ****[fix]**** **PdoOne** dateConvertInput() does not crash when the value is not a date.\n\n    * ****[fix]**** **PdoOne** throwError() does not stack errors but still triggers the last error (if any).\n\n    * [changes] ❗ **PdoOne** aggregate functions (sum,min,max,avg) now returns a value instead of generating a query.\n\n        * ```php\n      $result=$pdo-\u003esum('xxx')-\u003efirstScalar(); // before\n      $result=$pdo-\u003esum('xxx'); // now\n      ```\n\n\n* ****[fix]**** **PdoOne**  generateCodeArray() used for the generation of classes, returns the correct name when it is set.\n\n* [changes] **_BasePdoOneRepo**: reset(),getQuery(),dropTable(),useCache(),limit(),newQuery(),order(),innerjoin(),left()\n  ,right()\n\n* [changes] **PdoOneQuery**: Multiples changes.\n\n\n* 2.13.1 2021-05-22\n\n    * ****[fix]**** **[orm]** the method where() and limit() generated a new query every time, so the command\n      ClaseRepo::recursive()::where() failed generated two queries instead of one.\n\n* 2.13 2021-04-17\n    * [debug] More changes to how it shows error messages.\n    * /_BasePdoOneRepo updated to version 5.0 (binary 5).\n\n* 2.12 2021-04-17\n    * [debug] Change how it shows the errors. Now it uses a custom error handle\n      (it could be disabled with setting $this-\u003ecustomError=false)\n\n* 2.11.1 2021-04-17\n    * ****[fix]**** Mysql extension now knows the type int24 (plus other types of variables).\n    * ****[fix]**** Regresion, some removed { } caused a bug when they are followed by []\n    * [code]\n\n* 2.11 2021-04-17\n\n    * [code] Lots of cleanups. Removed unneeding { }. Merged common code in branches.\n\n* 2.10.3 2021-04-14\n    * ****[fix]**** BasePdoOne fixed method getRecursive(), it generated a new query, and now it reuses a query (if any).\n    * It also returns the query\n\n* 2.10.2 2021-04-06\n\n    * Fixed\n\n* 2.10.1 2021-04-05\n\n    * Fixed the generation of the ORM in the use of where(), limit() and dependencies()\n\n* 2.10 2021-04-04\n\n    * Some CLI cleanups.\n\n* 2.9.4 2021-03-22\n    * **ORM:** **_BasePdoOneRepo** is updated to BINARYVERSION=4. If you are using the ORM, then you should rebuild all\n      ORM classes.\n    * **CORE:** Query chains creates a new instance of **PdoOneQuery** instead of an instance of **PdoOne**, so it is\n      possible to define\n      multiples chains without interfering each others.\n    * **ORM:** Fixed a problem with the base class. Now the Base class contains the constant COMPILEDVERSION\n    * **ORM**: Fixed a problem with the model and the method toArray()\n\n* 2.9.3 2021-02-22\n\n    * fix a bug with **useCache()** when we use with where()\n\n* 2.9.2 2021-02-18\n\n    * fixed a bug with createSequence()\n\n* 2.9.1 2021-02-16\n\n    * Fixed debugFile() when the file is unable to open.\n\n* 2.9 2021-02-16\n    * BasePdoOneRepo::getPdoOne() validates if the static class uses the right version. It is only done once\n      (when it creates the instance of pdoOne), so it must not affect the performance.\n    * **You should re-generate all ORM classes generated (if you are generated one)**\n\n* **2.8** 2021-02-13\n\n    * Updated _BasePdoOneRepo to 4.13. **You should re-generate all ORM classes generated (if you are generated one)**\n\n* 2.7.1 2021-01-21\n\n    * Oracle is still a WIP (OCI)\n\n* **2.7** 2021-01-10\n    * Many changes, compatibility with PHP 8.0\n    * Fixed a bug with cache where it keeps the cache of previous runs.\n    * Note: $PdoOne-\u003euseCache considers = false (no cache) and everything else as use cache. Nulls are not allowed.\n    * Note: Previous generated code must be rebuilt it again.\n\n* **2.6.3** 2020-10-16\n    * Internal, Changed beginTry() and endTry(). Now, if an operation that uses beginTry() and endTry() fails,\n      then the error is throw in endTry().\n\n* **2.6.2** 2020-10-09\n\n    * The default argument of _first (code generated) is PdoOne::NULL instead of null because null is a valid value\n\n* 2.6.1 2020-09-24\n    * update \\_BasePdoOneRepo to 4.12.1\n    * Preliminary support to Oracle OCI (only raw operations)\n    * \\_BasePdoOneRepo() insert now allows using nulls\n    * \\_BasePdoOneRepo() first() the \"where\" uses the name of the table.\n\n* 2.6 2020-09-17\n    * the methods insert(),update(),delete() and insertObject() flushes the cache if it is called with useCache()\n      , example: $this-\u003eusecache('','customers')-\u003einsert(); // delete the group cache customers.\n\n* 2.5 2020-09-13\n    * update \\_BasePdoOneRepo to 4.12\n    * new method setCache()\n    * updated method useCache(). Now it allows '*' to use the same tables assigned by from() and joins()\n\n* 2.4.1 2020-09-13\n\n    * The code generated now the method first() returns false if it doesn't found any value, instead of an empty array.\n\n* 2.4 2020-09-06\n    * update \\_BasePdoOneRepo to 4.11\n    * The code generated now store the column of the identity SELF::IDENTITY;\n    * \\_BasePdoOneRepo now converts objects to array recursively (array)$obj only converts the first level.\n\n* 2.3 2020-09-06\n    * new method getDefTableExtended() that returns extended information about the table (motor,description,collation\n      and schema)\n    * method truncate() has a new argument $forced. Now, it is possible to force truncate (for example, when the table\n      has FK)\n    * new method resetIdentity() that reset the identity/autonumeric of a table (if any)\n    * Updated \\_BasePdoOneRepo\n    * The code generated now allows setting values using the factory()\n    * The code generated now reset the recursivity when we use the method factory()\n\n* 2.2.6 2020-09-03\n    * Updated \\_BasePdoOneRepo\n    * Method validateDefTable() works with table\n\n* 2.2.5 2020-08-30\n\n    * Fixed a bug with the method dateConvert(). The conversion from date -\u003e any other format misses the time.\n\n* 2.2.3 2020-08-23\n\n    * \\_BasePdoOneRepo update to 4.8.2. Solved a fix returning a ONETOMANY field.\n\n* 2.2.2 2020-08-17\n\n    * \\_BasePdoOneRepo update to 4.8.2. It solved a problem with insert,update,delete and merge when the input is an\n      object.\n\n* 2.2.1 2020-08-16\n    * Fixed a bug when the system is unable to convert the date. Now, it returns false.\n    * BasePdoOneRepo update to 4.8.1, if the transaction is open, then it doesn't nest a new transaction.\n\n* 2.2 2020-08-14\n    * New method setUseInternalCache() and flushInternalCache() where we could set an internal cache. The internal cache\n      stores\n      results, and they are keep into memory. For example\n\n```php\n$this-\u003esetUseInternalCache(true);\n$rows=$this-\u003eselect('*')-\u003efrom('table')-\u003ewhere(['i'=\u003e1])-\u003etoList(); // read from the database\n// ...\n$rows2=$this-\u003eselect('*')-\u003efrom('table')-\u003ewhere(['i'=\u003e1])-\u003etoList(); // read from memory\n// ...\n$rows3=$this-\u003eselect('*')-\u003efrom('table')-\u003ewhere(['i'=\u003e2])-\u003etoList(); // read from the database because the query is in \n                                                                     // memory but the parameters are different \n\necho $this-\u003einternalCacheCounter; \n\n```\n\n* The internal cache is tested with runRawQuery (if returns an array), toList(), meta() and first()\n\n* 2.0.1 2020-08-12\n    * Fixed a bug with the generated code with linked relation manytoone and onetonone.\n* 2.0 2020-08-11\n    * **Core**: The arguments are rebuild from scratch. Now, arguments are more natural, and we don't need to specify\n      the type. It also allows many other different kind of combinations.\n    * Before: **$this-\u003erunRawQuery($sql,['i',20,'s','hello]);**\n    * Now: **$this-\u003erunRawQuery($sql,[20,'hello']);**\n    * Also, (named): **$this-\u003erunRawQuery($sql,['col1'=\u003e20,'col2'=\u003e'hello']);**\n    * Since it is a core change, then former code that uses the version 1.x could not be compatible without changing all\n      references to methods that use arguments specifying the types.\n        * runRawQuery()\n        * set()\n        * select()\n        * where()\n        * insert()\n        * update()\n        * delete()\n        * toMeta()\n        *\n* 1.55.1 2020-08-05\n    * In the generation of the code, changed is_array() by isset()\n* 1.55 2020-8-05\n    * Updated generation of code. Now, the relations manytoony and onetoone returns linked values. Linked values\n      are values that are linked (one of them is a pointer to the other value).\n    * Fixed: the relation onetoone, the field refcol now uses the right column.\n* 1.54 2020-8-02\n    * connect does not set attribute directly. Mysql and sql server sets different arguments.\n    * generateCodeClass has an additional argument and it generares an extra field.\n    * generateAllClasses has an additional field (allows adds new fields)\n    * generateAbstractCodeclass has an additional field (allows adds new fields)\n    * BasePdoOneRepo updated to 4.8. Now it uses new functionalities.\n        * It allows custom input and output conversions.\n        * Input and output conversions code is generated at compile time instead to evaluates at runtime.\n        * It allows toList() and first() to returns extra columns. Those columns are also added to the model-class\n* 1.53 2020-7-27\n    * Method connect() sets PDO::ATTR_EMULATE_PREPARES to false\n* 1.52 2020-7-19\n    * Updated method generateCodeArray()\n    * Updated method generateCodeClass()\n    * Updated method generateCodeClassRepo()\n    * Updated method generateModelClass()\n    * new method generateAbstractModelClass()\n* 1.51 2020-7-18\n    * class BasePdoOneRepo updated to 4.7. Now it supports arrays and objects\n    * Updated method generateCodeArray()\n    * Updated method generateCodeClass()\n    * Updated method generateCodeClassRepo()\n    * new method generateModelClass() It generates model from tables\n* 1.50 2020-7-04\n    * Updated method generateCodeArray()\n    * Updated method generateCodeClass()\n    * Updated method generateCodeClassRepo()\n* 1.49 2020-6-19\n    * New method generateAllClasses()\n* 1.48 2020-6-15\n    * dateTextNow() now returns a human-readable format\n    * New method dateNow() that returns a date in a normal format.\n    * BasePdoOne::count() now works with setRecursive()\n* 1.47 2020-6-14\n    * The flow -\u003ewhere()-\u003eupdate() now works when \"where()\" uses named arguments.\n    * Fixed a bug with the next query -\u003ewhere('a1=:Argument',[])\n    * Added the method PdoOneEncryption::hash() and added the method PdoOne::hash() to wrap the first method.\n    * Added the field PdoOneEncryption:$hashType And PdoOne uses as the default hash algorythm.\n    * The method RunRawQuery() now accept named arguments.\n* 1.46 2020-6-13\n    * _BasePdoOneRepo updated to 4.6\n    * Now generation of code has a Base class, so it is possible to name each independiently of the table.\n* 1.45.1 2020-6-11\n    * Method generateCodeClass now creates ONETOMANY relation if the case of the table does not match.\n* 1.45 2020-6-7\n    * Added method generateCodeClassRepo()\n    * Modified method generateCodeClass()\n* 1.44.2 2020-6-3\n    * Solved a problem with BasePdoOneRepo\n* 1.44.1 2020-6-2\n    * Solved a small bug on BasePdoOneRepo\n* 1.44 2020-5-31\n    * Updated BasePdoOneRepo to 4.4. Now it catches errors or returns false.\n* 1.43 2020-5-31\n    * Updated BasePdoOneRepo to 4.3. Now it works with conversions. It doesn't convert fields from **where**\n      , but it converts results, insert and update.\n    * BasePdoOneRepo 4.3 also restricts the columns to insert and update.\n    * BasePdoOneRepo 4.3 also uses a long definition of columns.\n* 1.42 2020-5-29\n    * Updated BasePdoOneRepo to 4.2. Now it works with cache\n    * New method buildUniqueID()\n* 1.41.2 2020-5-29\n    * Updated BasePdoOneRepo to 4.1.1 In the method _first(), if argument is null then it doesn't query the value.\n* 1.41.1 2020-5-28\n    * Added more phpdoc for generateCodeClass()\n* 1.41 2020-5-28\n    * Updated BasePdoOneRepo to 4.0.1. It allows to specify a prefix in classes.\n    * generateCodeClass() allows to specificy a prefix different from 'Repo'.\n* 1.40.1 2020-5-27\n    * Updated BasePdoOneRepo to 4.0.1 It allows long namespaces. It also adds an alias to the first table.\n* 1.40 2020-05-21\n    * Updated BasePdoOneRepo 4.0\n* 1.39 2020-05-12\n    * Updated _BasePdoOneRepo to version 4.0\n    * Solved a problem with getDefTableFK (mysql and sqlsrv)\n    * new field (database_identityName)\n    * Solved a problem with getPK (sqlsrv)\n* 1.38 2020-05-10\n    * updated _BasePdoOneRepo to version 4.0\n* 1.37 2020-05-03\n    * added method setNoReset()\n* 1.36 2020-05-03\n    * added method hasRecursive()\n* 1.35.1 2020-04-30\n    * autoload.php delete (it's a trash file)\n* 1.35 2020-04-28\n    * _BasePdoOneRepo 2.3 added relation ONETOMANY\n    * generateCodeClass() supports for _BasePdoOneRepo 2.3\n* 1.34.2 2020-04-27\n    * Updated other components.\n    * left(), right() and innerjoin() don't replace where() anymore\n\n\n* 1.34.1 2020-04-27\n    * _BasePdoOneRepo 2.2.1 fixed.\n\n* 1.34 2020-04-27\n    * _BasePdoOneRepo 2.2 now it allows load relation many by one.\n    * sniffer is removed. Using Php Inspections ​(EA Extended)​\n* 1.33 2020-04-15\n    * _BasePdoOneRepo version 2.1\n    * new method hasWhere()\n    * generateCodeArray() has a new argument (recursive)\n    * toList(), first(), firstScalar(), toMeta(), toListSimple() and all related method throws error\n      more close to the method.\n    * Travis has been removed (tests are done locally in my machine. Why? It's because travis is not fully compatible\n      with sqlsrv)\n* 1.32.1 BasePdoOneRepo added version 2.0\n* 1.32 2020-04-12\n    * The class generated now extends _BasePdoOneRepo\n        * It implements the default commands: insert,select,update,delete,create table,truncate.\n    * Security: user/password is deleted from memory after connection.\n    * Mysql:createSequence() functions are now marked as \"MODIFIES SQL DATA\" and \"NOT DETERMINISTIC\"\n    * Added more test, including test for SQLSRV.\n* 1.31.1 2020-04-11\n    * CLI: Primary key is not required anymore.\n    * new method createFK();\n    * Foreign keys are not created separately of other keys.\n    * new method camelize()\n    * new method isQuery()\n    * new method filterKey()\n    * new method getDefTableFK()\n* 1.31 2020-04-11\n    * new method tableSorted()\n* 1.30 2020-04-10\n    * Class separated in 3 new service class\n    * lib/ext/PdoOne_Mysql.php = Service class for Mysql (mysql)\n    * lib/ext/PdoOne_Sqlsrv.php = Service class for Sql Server (sqlsrv)\n    * lib/ext/PdoOne_TestMockup.php = Service class for mockup test (test)\n    * lib/ext/PdoOne_IExt.php = Interface for all services.\n    * the /examples folder is not delivered by default. It allows to reduce the number of size. Use composer\n      --prefer-source to get the examples\n* 1.29 2020-04-10\n    * createTable() now allows more features\n    * new method validateDefTable()\n    * a new UI render()\n* 1.28.1 2020-04-06\n    * cli now supports sqlsrv\n* 1.28 2020-04-06\n    * method toMeta() now allows arguments.\n    * **The library now has a cli interface and a generation of code**\n    * new method isCli()\n    * new method cliEngine()\n    * new method getParameterCli() protected\n    * new method removeTrailSlash() protected\n    * new method fixCsv() protected\n    * new method generateCodeSelect() protected\n    * new method generateCodeArray() protected\n    * new method generateCodeClass() protected\n* 1.24 2020-03-26\n    * builderReset() is now public\n* 1.23.1 2020-03-10\n    * Fixed a problem with the cache\n* 1.23 2020-03-10\n    * method toMeta()\n* 1.22 2020-02-08\n    * method invalidateCache()\n    * changed the interface IPdoOneCache\n* 1.21 2020-02-07\n    * method setCacheService() and getCacheService()\n    * method useCache()\n* 1.20 2020-jan-25\n    * Many cleanups.\n    * update() and delete() now allows to set the query.\n    * new method addDelimiter() to add delimiters to the query (i.e. 'table' for mysql and [table] for sql server)\n* 1.19 2020-jan-15\n    * getSequence() now has a new argument (name of the sequence, optional)\n    * createSequence() has a new argument (type of sequence) and it allows to create a sequential sequence.\n    * objectexist() now is public, and it allows to works with functions\n    * Bug fixed: objectExist() now works correctly (used by tableExist())\n    * new DDL methods drop(), dropTable() and truncate()\n* 1.16 2020-jan-14\n    * new method toListKeyValue()\n* 1.15 2019-dec-29\n    * Fix small bug if the argument of isAssoc() is not an array.\n* 1.14 2019-dec-26\n    * method where() works with associative array\n* 1.13 2019-dec-26\n    * new method count()\n    * new method sum()\n    * new method min()\n    * new method max()\n    * new method avg()\n    * method select now allows null definition.\n    * obtainSqlFields() discontinued\n* 1.12 2019-oct-20 Added argument (optional) -\u003etoList($pdomodel) Added method -\u003etoListSimple()\n* 1.11 2019-oct-01 1.11 It is still compatible with php 5.6.Added to composer.json\n* 1.10 2019-oct-01 1.10 Added method dateConvert(). Added trace to the throw.\n* 1.9 2019-aug-10 1.8 republished\n* 1.8 2019-aug-10 Added a date format. Methods dateSql2Text() and dateText2Sql()\n* 1.7 2019-jun-23 Added some benchmark. It also solves a problem with the tags. Now: table.field=? is converted\n  to `table`.`field`=?\n* 1.6 2019-jun-22 affected_rows() returns a correct value.\n* 1.5 2019-may-31 some cleanups. columnTable() returns if the column is nullable or not.\n* 1.4 2019-may-30 insertobject()\n* 1.3 2019-may-23 New changes\n* 1.2 2019-may-22 New fixed.\n* 1.1 2019-may-21 Some maintenance\n* 1.0 2019-may-21 First version \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feftec%2Fpdoone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feftec%2Fpdoone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feftec%2Fpdoone/lists"}