{"id":16347729,"url":"https://github.com/oscarotero/simple-crud","last_synced_at":"2025-04-04T17:10:19.872Z","repository":{"id":6116439,"uuid":"7344350","full_name":"oscarotero/simple-crud","owner":"oscarotero","description":"PHP library to provide magic CRUD in MySQL/Sqlite databases with zero configuration","archived":false,"fork":false,"pushed_at":"2022-09-07T08:06:50.000Z","size":791,"stargazers_count":241,"open_issues_count":5,"forks_count":59,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-28T16:11:36.710Z","etag":null,"topics":["crud","database","mysql","orm","sqlite"],"latest_commit_sha":null,"homepage":"","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/oscarotero.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-27T18:43:21.000Z","updated_at":"2025-02-04T04:28:43.000Z","dependencies_parsed_at":"2022-08-06T19:15:16.877Z","dependency_job_id":null,"html_url":"https://github.com/oscarotero/simple-crud","commit_stats":null,"previous_names":[],"tags_count":92,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarotero%2Fsimple-crud","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarotero%2Fsimple-crud/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarotero%2Fsimple-crud/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarotero%2Fsimple-crud/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oscarotero","download_url":"https://codeload.github.com/oscarotero/simple-crud/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247217222,"owners_count":20903009,"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":["crud","database","mysql","orm","sqlite"],"created_at":"2024-10-11T00:45:24.834Z","updated_at":"2025-04-04T17:10:19.852Z","avatar_url":"https://github.com/oscarotero.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SimpleCrud\n\n[![Build Status](https://travis-ci.org/oscarotero/simple-crud.png?branch=master)](https://travis-ci.org/oscarotero/simple-crud)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/oscarotero/simple-crud/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/oscarotero/simple-crud/?branch=master)\n\nPHP library to (Create, Read, Update, Delete) in Mysql/Sqlite databases with zero configuration and some magic.\n\n## Naming conventions:\n\nThis library relies in some conventions to avoid configuration.\n\n* Table names SHOULD be in [singular](http://stackoverflow.com/a/5841297) and **camelCase**\n* Fields names SHOULD be in **singular** and **camelCase**\n* The primary key of all tables MUST be `id`.\n* Foreign keys MUST be `[tableName]_id`. For example, `post` table uses `post_id` as foreign key.\n* Associative tables MUST use an underscore joining the two tables in alphabetic order. For example, the relationship between `post` and `tag` is `post_tag` but `post` and `category` is `category_post`.\n\n## Installation\n\nThis package is installable and autoloadable via Composer as [simple-crud/simple-crud](https://packagist.org/packages/simple-crud/simple-crud).\n\n```\n$ composer require simple-crud/simple-crud\n```\n\n## Classes\n\nSimpleCrud has the following classes:\n\n* **Database:** Manage the database connection. Uses internally [Atlas.PDO](https://github.com/atlasphp/Atlas.PDO)\n* **Query:** Creates the database queries. SimpleCrud is tested with MySQL and SQLite but due uses [Atlas.Query](https://github.com/atlasphp/Atlas.Query) internally, in theory Postgres and Microsoft SQL should be supported too.\n* **Table:** Manages a database table\n* **Field:** Manages a database field. Used to format and validate values\n* **Row:** To store and modify a row\n* **RowCollection:** Is a collection of rows\n\n## Usage example\n\nLet's say we have the following database scheme:\n\n```sql\nCREATE TABLE \"post\" (\n    `id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\n    `title` TEXT,\n    `category_id` INTEGER,\n    `type`  TEXT,\n\n    FOREIGN KEY(`category_id`) REFERENCES category(id)\n);\n\nCREATE TABLE `category` (\n    `id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\n    `name`  TEXT\n);\n\nCREATE TABLE `tag` (\n    `id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\n    `name`  TEXT\n);\n\nCREATE TABLE `post_tag` (\n    `id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\n    `tag_id`   INTEGER NOT NULL,\n    `post_id`  INTEGER NOT NULL,\n\n    FOREIGN KEY(`tag_id`) REFERENCES tag(id),\n    FOREIGN KEY(`post_id`) REFERENCES post(id)\n);\n```\n\nTo start, create an instance of `SimpleCrud\\Database` passing the `PDO` connection.\n\n```php\nuse SimpleCrud\\Database;\n\n$pdo = new PDO($dsn, $username, $password);\n\n$db = new Database($pdo);\n\n//To get any table, use magic properties, they will be instantiated on demand:\n$post = $db-\u003epost;\n```\n\nSimpleCrud load the database scheme and detects automatically all relationships between the tables using the naming conventions described above. For example the table \"post\" has a field called \"category_id\", so SimpleCrud knows that each post has one category.\n\n**Note:** In production environment, you may want to cache the scheme in order to avoid execute these queries and improve the performance. You can do it in this way:\n\n```php\nuse SimpleCrud\\Scheme\\Cache;\nuse SimpleCrud\\Scheme\\Mysql;\n\nif ($cache-\u003ehas('db_scheme')) {\n    $array = $cache-\u003eget('db_scheme');\n    $scheme = new Cache($array);\n} else {\n    $scheme = new Mysql($pdo);\n    $cache-\u003esave('db_scheme', $scheme-\u003etoArray());\n}\n\n$db = new Database($pdo, $scheme);\n```\n\n## Using the library\n\n### Basic CRUD:\n\nYou can interact directly with the tables to insert/update/delete/select data:\n\nUse `ArrayAccess` interface to access to the data using the `id`:\n\n```php\n//Get the post id = 3;\n$post = $db-\u003epost[3];\n\n//Check if a row exists\nif (isset($db-\u003epost[3])) {\n    echo 'exists';\n}\n\n//Delete a post\nunset($db-\u003epost[3]);\n\n//Update a post\n$db-\u003epost[3] = [\n    'title' =\u003e 'Hello world'\n];\n\n//Insert a new post\n$db-\u003epost[] = [\n    'title' =\u003e 'Hello world 2'\n];\n\n//Tables implements the Countable interface\n$totalPost = count($db-\u003epost);\n```\n\n### Select by other fields\n\nIf you want to select a row by other key than `id`, just use the method `get`:\n\n```php\n$post = $db-\u003epost-\u003eget(['slug' =\u003e 'post-slug']);\n```\n\n### Select or create\n\nSometimes, you want to get a row or create it if it does not exist. You can do it easily with `getOrCreate` method:\n\n```php\n$post = $db-\u003epost-\u003egetOrCreate(['slug' =\u003e 'post-slug']);\n```\n\n### Rows\n\nA `Row` object represents a database row and is used to read and modify its data:\n\n```php\n//get a row by id\n$post = $db-\u003epost[34];\n\n//Get/modify fields values\necho $post-\u003etitle;\n\n$post-\u003etitle = 'New title';\n\n//Update the row into database\n$post-\u003esave();\n\n//Remove the row in the database\n$post-\u003edelete();\n\n//Create a new row\n$newPost = $db-\u003epost-\u003ecreate(['title' =\u003e 'The title']);\n\n//Insert the row in the database\n$newPost-\u003esave();\n```\n\n### Queries\n\nA `Query` object represents a database query. SimpleCrud uses magic methods to create queries. For example `$db-\u003epost-\u003eselect()` returns a new instance of a `Select` query in the tabe `post`. Other examples: `$db-\u003ecomment-\u003eupdate()`, `$db-\u003ecategory-\u003edelete()`, etc... Each query has modifiers like `orderBy()`, `limit()`:\n\n```php\n//Create an UPDATE query with the table post\n$updateQuery = $db-\u003epost-\u003eupdate(['title' =\u003e 'New title']);\n\n//Add conditions, limit, etc\n$updateQuery\n    -\u003ewhere('id = ', 23)\n    -\u003elimit(1);\n\n//get the query as string\necho $updateQuery; //UPDATE `post` ...\n\n//execute the query and returns a PDOStatement with the result\n$PDOStatement = $updateQuery();\n```\n\nThe method `get()` executes the query and returns the processed result of the query. For example, with `insert()` returns the id of the new row:\n\n```php\n//insert a new post\n$id = $db-\u003epost\n    -\u003einsert([\n        'title' =\u003e 'My first post',\n        'text' =\u003e 'This is the text of the post'\n    ])\n    -\u003eget();\n\n//Delete a post\n$db-\u003epost\n    -\u003edelete()\n    -\u003ewhere('id = ', 23)\n    -\u003eget();\n\n//Count all posts\n$total = $db-\u003epost\n    -\u003eselectAggregate('COUNT')\n    -\u003eget();\n//note: this is the same like count($db-\u003epost)\n\n//Sum the ids of all posts\n$total = $db-\u003epost\n    -\u003eselectAggregate('SUM', 'id')\n    -\u003eget();\n```\n\n`select()-\u003eget()` returns an instance of `RowCollection` with the result:\n\n```php\n$posts = $db-\u003epost\n    -\u003eselect()\n    -\u003ewhere('id \u003e ', 10)\n    -\u003eorderBy('id ASC')\n    -\u003elimit(100)\n    -\u003eget();\n\nforeach ($posts as $post) {\n    echo $post-\u003etitle;\n}\n```\n\nIf you only need the first row, use the modifier `one()`:\n\n```php\n$post = $db-\u003epost\n    -\u003eselect()\n    -\u003eone()\n    -\u003ewhere('id = ', 23)\n    -\u003eget();\n\necho $post-\u003etitle;\n```\n\n`select()` has some interesting modifiers like `relatedWith()` to add automatically the `WHERE` clauses needed to select data related with other row or rowCollection:\n\n```php\n//Get the post id = 23\n$post = $db-\u003epost[23];\n\n//Select the category related with this post\n$category = $db-\u003ecategory\n    -\u003eselect()\n    -\u003erelatedWith($post)\n    -\u003eone()\n    -\u003eget();\n```\n\n### Query API:\n\nQueries use [Atlas.Query](http://atlasphp.io/cassini/query/) library to build the final queries, so you can see the documentation for all available options.\n\n#### Select / SelectAggregate\n\nFunction | Description\n---------|------------\n`one` | Select 1 result.\n`relatedWith(Row / RowCollection / Table $relation)` | To select rows related with other rows or tables (relation added in `WHERE`).\n`joinRelation(Table $table)` | To add a related table as `LEFT JOIN`.\n`getPageInfo()` | Returns the info of the pagination.\n`from` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`columns` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`join` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`catJoin` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`groupBy` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`having` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`orHaving` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`orderBy` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`catHaving` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`where` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`whereSprintf` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`catWhere` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`orWhere` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`orWhereSprintf` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`whereEquals` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`limit` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`offset` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`distinct` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`forUpdate` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`setFlag` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n`bindValue` | [Atlas.Query Select()](http://atlasphp.io/cassini/query/select.html)\n\n#### Update\n\nFunction | Description\n---------|------------\n`relatedWith(Row / RowCollection / Table $relation)` | To update rows related with other rows or tables (relation added in `WHERE`).\n`set` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n`setFlag` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n`where` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n`orWhere` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n`catWhere` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n`orderBy` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n`limit` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n`offset` | [Atlas.Query Update()](http://atlasphp.io/cassini/query/update.html)\n\n#### Insert\n\nFunction | Description\n---------|------------\n`orIgnore()` | To ignore silently the insertion on duplicated keys, instead throw an exception.\n`set` | [Atlas.Query Insert()](http://atlasphp.io/cassini/query/insert.html)\n`setFlag` | [Atlas.Query Insert()](http://atlasphp.io/cassini/query/insert.html)\n\n#### Delete\n\nFunction | Description\n---------|------------\n`relatedWith(Row / RowCollection / Table $relation)` | To delete rows related with other rows or tables (relation added in `WHERE`).\n`setFlag` | [Atlas.Query Delete()](http://atlasphp.io/cassini/query/delete.html)\n`where` | [Atlas.Query Delete()](http://atlasphp.io/cassini/query/delete.html)\n`orWhere` | [Atlas.Query Delete()](http://atlasphp.io/cassini/query/delete.html)\n`catWhere` | [Atlas.Query Delete()](http://atlasphp.io/cassini/query/delete.html)\n`orderBy` | [Atlas.Query Delete()](http://atlasphp.io/cassini/query/delete.html)\n`limit` | [Atlas.Query Delete()](http://atlasphp.io/cassini/query/delete.html)\n`offset` | [Atlas.Query Delete()](http://atlasphp.io/cassini/query/delete.html)\n\n### Lazy loads\n\nBoth `Row` and `RowCollection` can load automatically other related rows. Just use a property named as related table. For example:\n\n```php\n//Get the category id=34\n$category = $db-\u003ecategory[34];\n\n//Load the posts of this category\n$posts = $category-\u003epost;\n\n//This is equivalent to:\n$posts = $db-\u003epost\n    -\u003eselect()\n    -\u003erelatedWith($category)\n    -\u003eget();\n\n//But the result is cached so the database query is executed only the first time\n$posts = $category-\u003epost;\n```\n\nThis allows make things like this:\n\n```php\n$titles = $db-\u003epost[34]-\u003etag-\u003epost-\u003etitle;\n\n//Get the post id=34\n//Get the tags of the post\n//Then the posts related with these tags\n//And finally, the titles of all these posts\n```\n\nUse magic methods to get a `Select` query returning related rows:\n\n```php\n$category = $db-\u003ecategory[34];\n\n//Magic property: Returns all posts of this category:\n$posts = $category-\u003epost;\n\n//Magic method: Returns the query instead the result\n$posts = $category-\u003epost()\n    -\u003ewhere('pubdate \u003e ', date('Y-m-d'))\n    -\u003elimit(10)\n    -\u003eget();\n```\n\n### Solving the n+1 problem\n\nThe [n+1 problem](http://stackoverflow.com/questions/97197/what-is-the-n1-selects-issue) can be solved in the following way:\n\n```php\n//Get some posts\n$posts = $db-\u003epost\n    -\u003eselect()\n    -\u003eget();\n\n//preload all categories\n$posts-\u003ecategory;\n\n//now you can iterate with the posts\nforeach ($posts as $post) {\n    echo $post-\u003ecategory;\n}\n```\n\nYou can perform the select by yourself to include modifiers:\n\n```php\n//Get some posts\n$posts = $db-\u003epost\n    -\u003eselect()\n    -\u003eget();\n\n//Select the categories but ordered alphabetically descendent\n$categories = $posts-\u003ecategory()\n    -\u003eorderBy('name DESC')\n    -\u003eget();\n\n//Save the result in the cache and link the categories with each post\n$posts-\u003elink($categories);\n\n//now you can iterate with the posts\nforeach ($posts as $post) {\n    echo $post-\u003ecategory;\n}\n```\n\nFor many-to-many relations, you need to do one more step:\n\n```php\n//Get some posts\n$posts = $db-\u003epost\n    -\u003eselect()\n    -\u003eget();\n\n//Select the post_tag relations\n$tagRelations = $posts-\u003epost_tag()-\u003eget();\n\n//And now the tags of these relations\n$tags = $tagRelations-\u003etag()\n    -\u003eorderBy('name DESC')\n    -\u003eget();\n\n//Link the tags with posts using the relations\n$posts-\u003elink($tags, $tagRelations);\n\n//now you can iterate with the posts\nforeach ($posts as $post) {\n    echo $post-\u003etag;\n}\n```\n\n\n### Relate and unrelate data\n\nTo save related rows in the database, you need to do this:\n\n```php\n//Get a comment\n$comment = $db-\u003ecomment[5];\n\n//Get a post\n$post = $db-\u003epost[34];\n\n//Relate\n$post-\u003erelate($comment);\n\n//Unrelate\n$post-\u003eunrelate($comment);\n\n//Unrelate all comments of the post\n$post-\u003eunrelateAll($db-\u003ecomment);\n```\n\n### Pagination\n\nThe `select` query has a special modifier to paginate the results:\n\n```php\n$query = $db-\u003epost-\u003eselect()\n    -\u003epage(1)\n    -\u003eperPage(50);\n\n$posts = $query-\u003eget();\n\n//To get the page info:\n$pagination = $query-\u003egetPageInfo();\n\necho $pagination['totalRows']; //125\necho $pagination['totalPages']; //3\necho $pagination['currentPage']; //1\necho $pagination['previousPage']; //NULL\necho $pagination['nextPage']; //2\n```\n\n### Events\n\nSimpleCrud uses [PSR-14 Event Dispatcher](https://www.php-fig.org/psr/psr-14/) to dispatch events. The events are attached to tables allowing to validate data, modify queries, etc.\n\n```php\nuse SimpleCrud\\Events\\BeforeSaveRow;\nuse SimpleCrud\\Events\\CreateSelectQuery;\n\n//Get the event dispatcher\n$dispatcher = $db-\u003epost-\u003egetEventDispatcher();\n\n//Assign the BeforeSaveRow event listener\n$dispatcher-\u003elisten(BeforeSaveRow::class, function (BeforeSaveRow $event) {\n    $row = $event-\u003egetRow();\n\n    if (!$row-\u003ecreatedAt) {\n        $row-\u003ecreatedAt = new Datetime();\n    }\n});\n\n//Assign a CreateSelectQuery\n$dispatcher-\u003elisten(CreateSelectQuery::class, function (CreateSelectQuery $event) {\n    $query = $event-\u003egetQuery();\n\n    //Add automatically a where clause in all selects\n    $query-\u003ewhere('active = true');\n});\n\n//Create a new post\n$post = $db-\u003epost-\u003ecreate(['title' =\u003e 'Hello world']);\n\n//Save the post, so BeforeSaveRow event is triggered\n$post-\u003esave();\n\n$post-\u003ecreatedAt; //This field was filled and saved\n\n//Select a post, so CreateSelectQuery is triggered and only active posts are selected\n$posts = $db-\u003epost-\u003eselect()-\u003eget();\n```\n\nYou can provide your own event dispatcher:\n\n```php\n$myDispatcher = new Psr14EventDispatcher();\n\n$db-\u003epost-\u003esetEventDispatcher($myDispatcher);\n```\n\nThe available Events are:\n\n* `SimpleCrud\\Events\\BeforeSaveRow`: Executed before save a row using `$row-\u003esave()`.\n* `SimpleCrud\\Events\\BeforeCreateRow`: Executed before create a new row with `$table-\u003ecreate()`.\n* `SimpleCrud\\Events\\CreateDeleteQuery`: Executed on create a DELETE query with `$table-\u003edelete()`.\n* `SimpleCrud\\Events\\CreateInsertQuery`: Executed on create a INSERT query with `$table-\u003einsert()`.\n* `SimpleCrud\\Events\\CreateSelectQuery`: Executed on create a SELECT query with `$table-\u003eselect()`.\n* `SimpleCrud\\Events\\CreateUpdateQuery`: Executed on create a UPDATE query with `$table-\u003eupdate()`.\n\n### Fields\n\nThe purpose of the `SimpleCrud\\Fields` classes is to convert the data from/to the database for its usage. For example, in Mysql the format used to store datetime values is \"Y-m-d H:i:s\", so the class `SimpleCrud\\Fields\\Datetime` converts any string or `Datetime` instance to this format, and when you select this value, you get a Datetime instance. The available fields are:\n\n* Boolean: To manage boolean values\n* Date: To manage date values. Converts the database values to a `Datetime`\n* Datetime: To manage datetime values. Converts the database values to a `Datetime`\n* Decimal: Converts values to float numbers or NULL\n* Field: It's the default field and doesn't transform the value\n* Integer: Converts values to integers or NULL\n* Json: To store json structures.\n* Serializable: To store arrays or any other serializable data structure.\n* Set: Manages multiple values. For example: ['red', 'blue', 'green'] will be stored as \"red,blue,green\" in database.\n* Point: Manages geometry points [more info](https://dev.mysql.com/doc/refman/5.7/en/gis-class-point.html)\n* Other advanced fields can be found here: https://github.com/oscarotero/simple-crud-extra-fields\n\nThe Field classes are asigned automatically according with the field type in the database. There are also \"special names\" that have specific types asigned:\n\n* Integer format will be asigned to any field named `id` or ending by `_id`.\n* Datetime format will be asigned to any field named `pubdate` or ending by `At` (for example: `createdAt`, `updatedAt` etc).\n* Boolean format will be asigned to any field named `active` or starting by `is` or `has` (for example: `isActived`, `hasContent`, etc)\n\nExample:\n\n```php\n$post = $db-\u003epost-\u003ecreate([\n    'title' =\u003e 'My post',\n    'text' =\u003e 'My post text',\n    'createdAt' =\u003e new Datetime('now'),\n    'isActive' =\u003e true\n]);\n\n$post-\u003esave();\n\n//Use magic properties to get the Field instance\n$titleField = $db-\u003epost-\u003etitle;\n```\n\n### Configuration\n\nYou may want to store some database configuration, for example the default language or base path where the assets are stored. To do that, there are the `getConfig` and `setConfig` methods:\n\n```php\n$db-\u003esetConfig('name', 'value');\n\necho $db-\u003egetConfig('name'); //value\n```\n\n### Localizable fields\n\nIf you need to save values in multiple languages, just have to create a field for each language using the language as suffix. For example, to save the title in english (en) and galician (gl), just create the fields `title_en` and `title_gl`.\n\nThen, you have to configure the current language using the `SimpleCrud::ATTR_LOCALE` attribute:\n\n```php\n//Set the current language as \"en\"\n$db-\u003esetConfig(SimpleCrud::CONFIG_LOCALE, 'en');\n\n//Select a post\n$post = $db-\u003epost[23];\n\n//Get the title in the current language\necho $post-\u003etitle; //Returns the value of title_en\n\n//You can access to any languages using the full name:\necho $post-\u003etitle_en;\necho $post-\u003etitle_gl;\n\n//And assign a diferent value to the current language\n$post-\u003etitle = 'New title in english';\n```\n\n## Debugging\n\n`SimpleCrud` use internally [Atlas.PDO](http://atlasphp.io/cassini/pdo/) to manage the connection and perform the queries in the database. You can see the documentation for more details.\n\n```php\n$db-\u003egetConnection()-\u003elogQueries(true);\n\n//-- Run queries --//\n\n$queries = $db-\u003egetConnection()-\u003egetQueries();\n```\n\n## Customization\n\nYou can use your own custom classes for tables, rows and row collections:\n\n### Custom Tables\n\nUse `setTableClasses` to assign custom classes to table:\n\n```php\n$db = new SimpleCrud\\Database($pdo);\n\n$db-\u003esetTableClasses([\n    'post' =\u003e CustomPost::class,\n    'comment' =\u003e CustomComment::class,\n]);\n\n$db-\u003epost; //Returns an instance of CustomPost\n```\n\n### FieldFactory\n\nTo create field instances, SimpleCrud use the `SimpleCrud\\Field\\FieldFactory` factory class that you can customize or even replace with your own factory:\n\n```php\nuse SimpleCrud\\Fields\\FieldFactory;\nuse SimpleCrud\\Fields\\Boolean;\n\n$db = new SimpleCrud\\Database($pdo);\n\n//Create a factory for your custom field\n$factory = new FieldFactory(\n    Year::class,          //Your custom field class name\n    ['integer'],          //All fields of type integer will use this class\n    ['year', '/$year/'],  //All fields named \"year\" or matching this regex will use this class\n    ['min' =\u003e 2000],      //Default config\n);\n\n$db-\u003esetFieldFactory($factory);\n\n//Modify a existing field\n$db-\u003egetFieldFactory(Boolean::class)-\u003eaddNames('enabled');\n\n//Use it:\n$db-\u003epost-\u003efields['year']; //returns an instance of Year\n$db-\u003epost-\u003efields['enabled']; //returns an instance of SimpleCrud\\Fields\\Boolean\n```\n\n## Creating your Rows and RowCollections\n\nTo define the Rows and RowCollections classes used in a specific table, first create a custom table and use `ROW_CLASS` and `ROWCOLLECTION_CLASS` protected constants to set the class.\n\n```php\nnamespace MyModels;\n\nuse SimpleCrud\\Table;\n\nclass Post extends Table\n{\n    protected const ROW_CLASS = PostRow::class;\n    protected const ROWCOLLECTION_CLASS = PostRowCollection::class;\n\n    protected function init()\n    {\n        //Insert code to be executed after the instantion\n    }\n\n    public function selectLatest()\n    {\n        return $this-\u003eselect()\n            -\u003eorderBy('createdAt DESC')\n            -\u003elimit(10);\n    }\n}\n```\n\nNow configure the database to use this class for the table `post`:\n\n```php\n$db = new SimpleCrud\\Database($pdo);\n$db-\u003esetTableClasses([\n    'post' =\u003e MyModels\\Post::class,\n]);\n\n\n$latests = $db-\u003epost-\u003eselectLatest()-\u003eget(); //Returns an instance of MyModels\\PostRowCollection\n\nforeach ($latests as $post) {\n    //Instances of MyModels\\PostRow\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foscarotero%2Fsimple-crud","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foscarotero%2Fsimple-crud","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foscarotero%2Fsimple-crud/lists"}