{"id":16019491,"url":"https://github.com/eftec/pdooneorm","last_synced_at":"2026-02-11T08:08:48.084Z","repository":{"id":142263254,"uuid":"612238106","full_name":"EFTEC/PdoOneORM","owner":"EFTEC","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-21T02:58:44.000Z","size":732,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-13T23:26:48.773Z","etag":null,"topics":["mysql","oracle","orm","php","sqlserver"],"latest_commit_sha":null,"homepage":"https://www.escuelainformatica.cl","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","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":"2023-03-10T13:53:34.000Z","updated_at":"2025-02-21T02:58:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"651792d3-0730-4a27-b02c-dd08b0a1a703","html_url":"https://github.com/EFTEC/PdoOneORM","commit_stats":{"total_commits":13,"total_committers":2,"mean_commits":6.5,"dds":0.07692307692307687,"last_synced_commit":"4e4bbd9dcb21614414b2e64adc474aa34277c6b7"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOneORM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOneORM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOneORM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EFTEC%2FPdoOneORM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EFTEC","download_url":"https://codeload.github.com/EFTEC/PdoOneORM/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250339464,"owners_count":21414363,"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","oracle","orm","php","sqlserver"],"created_at":"2024-10-08T17:04:34.747Z","updated_at":"2026-02-11T08:08:48.010Z","avatar_url":"https://github.com/EFTEC.png","language":"PHP","readme":"# Database Access Object wrapper for PHP and PDO in a single class\n\nPdoOneORM. It's a simple ORM wrapper for PHP's PDO library compatible with SQL Server (2008 R2 or higher),\nMySQL (5.7 or higher) and Oracle (12.1 or higher).\n\nThis library tries to **work as fast as possible and simply as possible**. The complete library, including dependencies\nis less than 100 files (and less than 30 are code).\n\nThis library works differently to Eloquent. While Eloquent is code-first, this library is database first.\n\n| PdoOneORM                                                    | Eloquent and others code-first ORM                           |\n| ------------------------------------------------------------ | ------------------------------------------------------------ |\n| Database first. You create the database and it will generate the code | Code First. You create the code and it will generate the database |\n| This library is aware of the schema of the database, for example every column of every table. | This library is not aware of the schema of the database      |\n| Relations are created using foreign keys or manually.        | Relation could create foreign keys.                          |\n|                                                              |                                                              |\n\nWhy?\n\n\n\n[![Packagist](https://img.shields.io/packagist/v/eftec/PdoOneORM.svg)](https://packagist.org/packages/eftec/PdoOneORM)\n[![Total Downloads](https://poser.pugx.org/eftec/PdoOneORM/downloads)](https://packagist.org/packages/eftec/PdoOneORM)\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.1-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 using the ORM.\n\n```php\nProductRepo // this class was generated with echo $pdoOne()-\u003egenerateCodeClass(['Product']); or using the cli.\n    ::where(\"name = ?\",[$_POST['name']])\n    -\u003etoList();\n```\n\n# Table of contents\n\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  * [CLI configuration.](#cli-configuration)\n    * [Connect CLI](#connect-cli)\n    * [Save](#save)\n    * [Create ORM](#create-orm)\n    * [Scan](#scan)\n    * [(optional) detail and type](#optional-detail-and-type)\n    * [Save](#save-1)\n    * [Create](#create)\n  * [Using the code generated](#using-the-code-generated)\n  * [ORM](#orm)\n      * [What is an ORM?](#what-is-an-orm)\n    * [Building and installing the ORM manually](#building-and-installing-the-orm-manually)\n      * [Creating the repository class](#creating-the-repository-class)\n      * [Creating multiples repositories classes](#creating-multiples-repositories-classes)\n      * [Creating all repositories classes](#creating-all-repositories-classes)\n    * [Using the Repository class.](#using-the-repository-class)\n      * [Using multiples connections](#using-multiples-connections)\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  * [Error FAQs](#error-faqs)\n    * [Uncaught Error: Undefined constant eftec\\_BasePdoOneRepo::COMPILEDVERSION](#uncaught-error-undefined-constant-eftec_basepdoonerepocompiledversion)\n  * [Changelist](#changelist)\n  * [License](#license)\n  \u003c!-- TOC --\u003e\n\n## Examples\n\nThere are some examples in the **\"examples\"** folder. If you want to run the examples, then you must change the configuration of the database.\n\nOther example here:\n\n* [getting started](examples/sakilatest.php)\n\n## Installation\n\nThis library requires PHP 7.4 and higher, and it requires the extension PDO and the extension PDO-MYSQL (Mysql), PDO-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/PdoOneORM\": \"^1.0\"\n      }\n  }\n```\nor install it via cli using\n\n\u003e composer require eftec/PdoOneORM\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 included on it.\n\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 open()\n\n```php\nuse eftec\\PdoOneORM;\n// mysql\n$dao=new PdoOneORM(\"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 PdoOneORM(\"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 PdoOneORM(\"test\",\"anyy\",\"any\",\"any\",\"any\",\"\");\n$dao-\u003econnect();\n\n// oci (oracle) ez-connect. Remember that you must have installed Oracle Instant client and add it to the path.\n\n$cs='(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = instancia1)))';\n$dao=new PdoOneORM(\"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 PdoOneORM(\"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 PdoOneORM(\"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\" (oracle)\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\n* Windows installation. Add the Oracle Instant client to the path and try to run from it.\n  * If it fails, the copy the oracle bin folder (instant client) into the apache folder. \n\n## CLI configuration.\nThe command line interface is important to generate the code needed. You can also generate code using PHP code but using the CLI is more straightforward.\nIn the command line, runs the next command:\n\n```bash\n.\\vendor\\bin\\pdoonecli.bat  # windows\n./vendor/bin/pdoonecli  # linux bash\n```\nAnd it will show the next screen\n\n![img1.png](docs/img1.png)\n\n\u003e Note: you can use the arrow keys and the TAB key for autocomplete values.\n\n### Connect CLI\nSelection the option connect, then configure and configure your database. In the next example we will configure a MySql database (schema sakila).\n\n\u003e You can't configure a database if your PHP installation is not using the correct drivers (including the PDO Drivers)\n\n![img1.png](docs/img2.png)\n\nIf the connect was done successfully (it shows **ok**), then you can continue.\n\n### Save\n\nOnce configured, you can save your configuration (**save**).\n![img3.png](docs/img3.png)\n\nLater, if you want to reconfigure, you can load your configuration file using the option **load**.\n\nThe configuration file is stored in a PHP file with extension .config.php\n\nExample:\n\n```php\n\u003c?php // eftec/CliOne(1.33) PHP configuration file (date gen: 2024-09-06 08:45). DO NOT EDIT THIS FILE \n/**\n * It is a configuration file\n */\n$config=[\n    'databaseType' =\u003e 'mysql',\n    'server' =\u003e '127.0.0.1',\n    'user' =\u003e 'root',\n    'pwd' =\u003e 'abc.123',\n    'database' =\u003e 'sakila',\n    'logFile' =\u003e false,\n    'charset' =\u003e NULL,\n    'nodeId' =\u003e 1,\n    'tableKV' =\u003e '',\n];\n```\n\nYou can use this file freely in your code, of you could simply copy and paste in your final code.\n\n### Create ORM\n\nOnce the database is configured, return to the main menu. \n\nIn the menu connect, **press enter** to return to the main menu. then enter **repo** to go to the repository menu.\n\n![img4.png](docs/img4.png)\n\nIt is the ORM menu:\n\n![img5.png](docs/img5.png)\n\nFirst, we must configure the folder and the **namespace** where the files will be generated.\n\nThe folder and namespace must work with your **composer.json** configuration (autoload). If you edit your **composer.json** file, then you must reopen the CLI.\n\nExample of composer.json\n\n![img6.png](docs/img6.png)\n\n* Go to the **folder** option\n\n* Enter the folder that you want to store your PHP files. In this example, the folder will be examples/repo\n* Then indicates a postfix for the class. \n  * If the table is named Customer, and the postfix is Repo, then the files will be called:\n  * CustomerRepo.php\n  * AbstractCustomerRepo.php\n\n* Then indicate the namespace corresponding to your composer.json (autoload) and your new folder.\n  * If autoload is set the namespace to to **eftec\\examples** =\u003e folder **examples/**\n  * then the folder **examples/repo** =\u003e namespace **eftec\\examples\\repo**\n\n\n\n\n\n![img7.png](docs/img7.png)\n\n### Scan\n\nOnce the folder is set, you must scan the schema. If you do changes to the schema, then you must re-scan it again.\n\n![img8.png](docs/img8.png)\n\n### (optional) detail and type\n\nOptionally you can change the detail of every table, for example how the classes are called, what column are used and to determine the type for every column.\n\n### Save\n\nSave the configuration, so you can load it later.\n\n### Create\n\nAnd finally, you can create the PHP files.\n\n![img9.png](docs/img9.png)\n\nIt will generate 3 kind of files.\n\n* Abstract classes (marked with red). The **abstract class** is a class used by the repo class. It contains all the information of the schema.  This class must not be edited manually and you can't use it directly.\n* Repo classes (marked with green). The **repo class** is the repository class and it is the class that you can use finally. You could edit this file.\n* Schema class (marked with yellow). The **schema class** is the class that contains information of all the schema. You mustn't edit this file or use it directly.\n\n![img10.png](docs/img10.png)\n\n### Reload the configuration\n\nYou can easily reload the previous configuration by running in the shell\n\n\u003e pdooneorm --fileconnect c1 --filerepo p1\n\nwhere c1 is the first configuration file (without extension), and p1 is the second configuration file.\n\n\n\n![img11.png](docs/img11.png)\n\n## Using the code generated\n\nOnce the code is generated, you could use the repo classes.\n\n1) You must connect to the database once so the repo classes could work correctly.\n2) Then you can use the repo classes.\n\n```php\nuse eftec\\examples\\repo\\ActorRepo;\nuse eftec\\PdoOne;\n\ninclude __DIR__.\"/../vendor/autoload.php\";\n\n// this configuration is obtained when you save the configuration file.\n$config=[\n    'databaseType' =\u003e 'mysql',\n    'server' =\u003e '127.0.0.1',\n    'user' =\u003e 'root',\n    'pwd' =\u003e 'abc.123',\n    'database' =\u003e 'sakila', \n    'logFile' =\u003e false,\n    'charset' =\u003e NULL,\n    'nodeId' =\u003e 1,\n    'tableKV' =\u003e '',\n];\n// we must connect once so the Repo class could identify the connection\n$pdo=PdoOne::factoryFromArray($config);\n$pdo-\u003econnect() or die(\"not connected\");\n// and we could use the repo class\nvar_dump(ActorRepo::toList());\n\n```\n\n\n\n## ORM\n\nThis library allows creating and use it as an ORM. To use it as an ORM, you must create the classes.\n\n#### What is an ORM?\n\nAn ORM transforms queries to the database in objects serializables.\n\nLet's say the next example\n\n```php\n$result=$pdoOne-\u003erunRawQuery('select IdCustomer,Name from Customers where IdCustomer=?',1); \n```\n\nYou can also run using the Query Builder\n\n```php\n$result=$pdoOne-\u003eselect('IdCustomer,Name')-\u003efrom('Customers')-\u003ewhere('IdCustomer=?',1)-\u003etoList();\n```\n\nWhat if you use the same table over and over.  You can generate a new class called **CustomerRepo** and calls the code as\n\n```php\n$result=CustomerRepo::where('IdCustomer=?',1)::toList();\n```\n\nWhile it is simple, but it also hides part of the implementation.  It could hurt the performance a bit, but it adds more simplicity and consistency.\n\n\n\n### Building and installing the ORM manually\n\nThere are several ways to generate a Repository code, it is possible to generate a code using the CLI, the GUI or using the next code:\n\n```php\n$pdo=new PdoOneORM('mysql','127.0.0.1','root','abc.123','sakila');\n$pdo-\u003econnect();\n$table=$pdo-\u003egenerateCodeClass('Tablename','repo'); // where Tablename is the name of the table to analyze. it must exsits.\necho $clase;\n```\n\nThe code generated looks like this one\n\n```php\nclass TableNameRepo extends _BasePdoOneRepo\n{\n// ....\n}\n```\n\n#### Creating the repository class\n\n\u003e This method is not recommended. Uses the method to create multiple classes.\n\nThere are several ways to create a class, you could use the UI, the CLI or directly via code.\n\nIt is an example to create our repository class\n\n```php\n$class = $pdoOne-\u003egenerateCodeClass('Customer'); // The table Customer must exists in the database\nfile_put_contents('CustomerRepo.php',$clase); // and we write the code into a file.\n```\n\nIt will build our Repository class.\n\n```php\n\u003c?php\nuse eftec\\PdoOneORM;\nuse eftec\\_BasePdoOneRepo;\n\nclass CustomerRepo extends _BasePdoOneRepo\n{\n    //....\n}\n```\n\n```php\n$class = $pdoOne-\u003egenerateCodeClass('Customer','namespace\\anothernamespace'); \n```\n\nIt will generate the next class\n\n```php\n\u003c?php\nnamespace namespace\\anothernamespace;    \nuse eftec\\PdoOneORM;\nuse eftec\\_BasePdoOneRepo;\n\nclass CustomerRepo extends _BasePdoOneRepo\n{\n    //....\n}\n```\n\n#### Creating multiples repositories classes\n\nIn this example, we have two classes, messages and users\n\n```php\n// converts all datetime columns into a ISO date.\n$pdoOne-\u003egenerateCodeClassConversions(['datetime'=\u003e'datetime2']);\n\n$errors=$pdoOneORM-\u003egenerateAllClasses(\n    ['messages'=\u003e'MessageRepo','users'=\u003e'UserRepo'] // the tables and their name of classes\n    ,'BaseClass' // a base class.\n    ,'namespace1\\repo' // the namespaces that we will use\n    ,'/folder/repo' // the folders where we store our classes\n    ,false // [optional] if true the we also replace the Repo classes\n    ,[] // [optional] Here we could add a custom relation of conversion per column.\n    ,[] // [optional] Extra columns. We could add extra columns to our repo.\n    ,[] // [optional] Columns to exclude.    \n);\nvar_dump($errors); // it shows any error or an empty array if success.\n```\n\nIt will generate the next classes:\n\n```\n📁 folder\n   📁repo\n       📃AbstractMessageRepo.php   [namespace1\\repo\\AbstractMessageRepo] NOT EDIT OR REFERENCE THIS FILE\n       📃MessageRepo.php         [namespace1\\repo\\MessageRepo] EDITABLE\n       📃AbstractUserRepo.php     [namespace1\\repo\\AbstractUserRepo] NOT EDIT OR REFERENCE THIS FILE\n       📃UserRepo.php               [namespace1\\repo\\UserRepo]  EDITABLE\n       📃BaseClass.php              [namespace1\\repo\\BaseClass] NOT EDIT OR REFERENCE THIS FILE      \n```\n\n* Abstract Classes are classes with all the definitions of the tables, indexes and such. They contain the whole definition of a class.\n  * This class should be rebuilded if the table changes. How? You must run the method **generateAllClasses**() again.\n* Repo Classes are classes that works as a placeholder of the Abstract class. These classes are safe for edit, so we could add our own methods and logic.\n  * Note: if you run **generateAllClasses**() again, then those classes are not touched unless we force it (argument **$forced**) or we delete those files.\n* Base Class is a unique class (per schema) where it contains the definition of all the tables and the relations between them.\n  * This class should be rebuilt if the table changes. How? You must run the method **generateAllClasses**() again.\n\n#### Creating all repositories classes\n\nWe could automate even further\n\n```php\n$allTablesTmp=$pdoOne-\u003eobjectList('table',true); // we get all the tables from the current schema.\n$allTables=[];\nforeach($allTablesTmp as $table) {\n    $allTables[$table]=ucfirst($table).'Repo';\n}\n$errors=$pdoOne-\u003egenerateAllClasses(\n   $allTables // tables=\u003erepo class\n    ,'MiniChat' // a base class.\n    ,'eftec\\minichat\\repo' // the namespaces that we will use\n    ,'/folder/repo' // the folders where we store our classes\n);\necho \"Errors (empty if it is ok:)\";\nvar_dump($errors);\n```\n\n\n\n### Using the Repository class.\n\nFor started, the library must know to know where to connect, so you must set an instance of the PdoOne and there are 3 ways to instance it.\n\nThe repository class is smart, and it does the next operation:\n\n\u003e If the Repository base doesn't have a connection, then it will try to use the latest connection available.\n\n\nThe easiest way is to create an instance of PdoOne();\n\n```php\n$pdo=new PdoOneORM('mysql','127.0.0.1','root','abc.123','sakila');\n$pdo-\u003econnect();\n$listing=TableNameRepo::toList(); // it will inject automatically into the Repository base class, instance of PdoOneORM.\n```\n\nYou could also do it by creating a root function called **pdoOneORM()**\n\n```php\nfunction pdoOneORM() {\n   $pdo=new PdoOneORM('mysql','127.0.0.1','root','abc.123','sakila');\n   $pdo-\u003econnect();\n}\n```\n\nOr creating a global variable called **$pdoOne**\n\n```php\n$pdoOne=new PdoOneORM('mysql','127.0.0.1','root','abc.123','sakila');\n$pdoOne-\u003econnect();\n```\n\nOr injecting the instance into the class using the static method **Class::setPdoOne()**\n\n```php\n$pdo=new PdoOneORM('mysql','127.0.0.1','root','abc.123','sakila');\n$pdo-\u003econnect();\nTableNameRepo::setPdoOne($pdo); // TableNameRepo is our class generated. You must inject it once per all schema.\n```\n\n#### Using multiples connections\n\nNote: If you are using multiples connections, then you must use the method **RepoClass::setPdoOne()** and it injects the connection inside the Repository Base. \n\nEvery repository base could hold only one connection at the same time\n\nExample:\n\n* BaseAlpha (Base class)\n  * Table1AlphaRepo (Repository class)\n  * Table2AlphaRepo (Repository class)\n* BaseBeta (Base class)\n  * Table1BetaRepo (Repository class)\n  * Table2BetaRepo (Repository class)\n\n```php\n$con1=new PdoOneORM('mysql','127.0.0.1','root','abc.123','basealpha');\n$con1-\u003econnect();\n$con2=new PdoOneORM('mysql','127.0.0.1','root','abc.123','basebeta');\n$con2-\u003econnect();\n// every base with its own connection:\nTable1AlphaRepo::setPdoOne($pdo); // ✅ Table1AlphaRepo and Table2AlphaRepo will use basealpha\nTable1BetaRepo::setPdoOne($pdo); // ✅ Table1BetaRepo and Table2BetaRepo will use basebeta\n// however, it will not work as expected\n// every base with its own connection:\nTable1AlphaRepo::setPdoOne($pdo); // ✅ Table1AlphaRepo and Table2AlphaRepo will use basealpha\nTable2AlphaRepo::setPdoOne($pdo); // ❌ And now, Table1AlphaRepo and Table2AlphaRepo will use basebeta\n```\n\nWhat if you want to use the same base for different connections? You can't. However, you could copy the files and create two different bases and repositories (or you could generate a code to create a new base and repository classes), then you can use multiples connections.\n\n\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\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\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\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\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 the 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 a table conditionally.\nPdoOne does not use it directly but _BasePdoOneRepo uses it (_BasePdoOneRepo is a class used when we generate a repository 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\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\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\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* 2.26 2025-02-20\n  * Added prefix and postfix for the relational columns.\n  * [_BasePdoOneRepo] updated to binary 16, so you should rebuild the repositories classes.\n* 2.5 2024-12-30\n  * Compatible with PHP 8.4 \n* 2.4 2024-09-06\n  * updated documentation and in the use of the CLI.\n* 2.3 2024-08-02\n  * [fixed] fixed a bug when the database is called with a minus symbol.\n  * [updated] Updated dependencies\n* 2.2 2024-06-07\n  * Update phpdoc using markdown without \"php\" because PHPStorm is not compatible with it. \n* 2.1 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* 2.0 2023-12-13\n  * Repo classes: Constant fields are now regular fields. \n  * Why? Constants are a bit slow, but it also lacks of flexibility.\n  * Example: (prev) CustomerRepo::TABLE, (now) CustomerREPO::$TABLE\n  * Repositories classes must be regenerated.`\n* 1.3.1 2023-11-13\n  * Update some templates\n  * It shows the table source when update() fails\n* 1.3 2023-09-02\n  * [PdoOneORMCli] 1.9 fixed a bug not scanning.\n  * Update composer.json dependency.\n* 1.2.2 2023-08-11\n  * [PdoOneORMCli] 1.8.2 fixed a bug not scanning.\n  * Update dependencies to eftec/pdoone 4.3\n* 1.2.1 2023-05-21\n  * [PdoOneORMCli] 1.8.1 fixed a small bug in \"configure per type\" \n* 1.2 2023-04-7\n  * [PdoOneORM] update for compatibility with PdoOne 4.2 and higher\n  * [composer.json] PHPUnit reduced to 8.5 (PHP 7.2 compatible)\n  * [PdoOneORMCli] 1.8 now configuration files are stored as PHP file instead of a json. Why? It is more flexible.\n* 1.1 2023-03-21\n  * [PdoOneORMCli] 1.7 CLI menu updated using the new functionality of the menu from CliOne 1.26.1 \n* 1.0 2023-03-11\n  * First version. This version is split from library PdoOne. \n\n\n## License\n\nCopyright Jorge Castro Castillo 2023. Dual license, commercial and LGPL-3.0\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feftec%2Fpdooneorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feftec%2Fpdooneorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feftec%2Fpdooneorm/lists"}