{"id":16517811,"url":"https://github.com/rancoud/model","last_synced_at":"2026-04-02T16:36:03.708Z","repository":{"id":37579860,"uuid":"144625566","full_name":"rancoud/Model","owner":"rancoud","description":"Model Package","archived":false,"fork":false,"pushed_at":"2025-03-14T11:42:05.000Z","size":427,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-17T05:02:48.335Z","etag":null,"topics":["composer","coverage","database","model","models","packagist","pdo","php","php74","php8","php80","php81","phpunit","phpunit9","sql"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/rancoud/model","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/rancoud.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-13T19:38:19.000Z","updated_at":"2025-03-14T11:42:07.000Z","dependencies_parsed_at":"2023-11-14T19:25:29.931Z","dependency_job_id":"f0e4f8ee-da57-46ad-a802-4895a2dfb52b","html_url":"https://github.com/rancoud/Model","commit_stats":{"total_commits":114,"total_committers":3,"mean_commits":38.0,"dds":"0.29824561403508776","last_synced_commit":"86c78c3cc3765514c34264931d06d4d64d81bbde"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FModel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FModel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FModel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FModel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rancoud","download_url":"https://codeload.github.com/rancoud/Model/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244765502,"owners_count":20506824,"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":["composer","coverage","database","model","models","packagist","pdo","php","php74","php8","php80","php81","phpunit","phpunit9","sql"],"created_at":"2024-10-11T16:33:46.815Z","updated_at":"2026-04-02T16:36:03.673Z","avatar_url":"https://github.com/rancoud.png","language":"PHP","readme":"# Model Package\n\n![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/rancoud/model)\n[![Packagist Version](https://img.shields.io/packagist/v/rancoud/model)](https://packagist.org/packages/rancoud/model)\n[![Packagist Downloads](https://img.shields.io/packagist/dt/rancoud/model)](https://packagist.org/packages/rancoud/model)\n[![Composer dependencies](https://img.shields.io/badge/dependencies-1-brightgreen)](https://github.com/rancoud/model/blob/master/composer.json)\n[![Test workflow](https://img.shields.io/github/actions/workflow/status/rancoud/model/test.yml?branch=master)](https://github.com/rancoud/model/actions/workflows/test.yml)\n[![Codecov](https://img.shields.io/codecov/c/github/rancoud/model?logo=codecov)](https://codecov.io/gh/rancoud/model)\n\nAbstract Model for better data manipulation between code and database.  \n\n## Dependencies\nDatabase package: [https://github.com/rancoud/Database](https://github.com/rancoud/Database)\n\n## Installation\n```php\ncomposer require rancoud/model\n```\n\n## How to use it?\nExtends Rancoud\\Model\\Model to your class.  \nYou have to implement two abstract methods setFields and setTable.  \n* setFields is for setting the fields in table  \n* setTable is for setting the table in database  \n```php\nclass User extends Model\n{\n    protected function setFields(): void\n    {\n        $this-\u003efields = [\n            'id'       =\u003e new Field('int', ['not_null', 'unsigned', 'pk']),\n            'nickname' =\u003e new Field('varchar', ['max:255', 'not_null'])\n        ];\n    }\n\n    protected function setTable(): void\n    {\n        $this-\u003etable = 'user';\n    }\n}\n```\n\n### What is Field?\nField represent a field in the table.  \nIt have 3 arguments:  \n1. field type\n2. rules\n3. default value\n\n#### Field type\nIt support those field type\n* int\n* float\n* char\n* varchar\n* text\n* date\n* datetime\n* time\n* timestamp\n* year\n* enum:x,y,z (x,y,z represent each possible value)\n\n#### Rules\n* pk : primary key\n* fk : foreign key\n* unsigned : only positive value\n* email : check if it is valid email\n* not_null : can't be null\n* max:x : max size (x is size)\n* min:x : min size (x is size)\n* range:x,y : min size + max size (x is min size, y is max size)\n\n#### Custom rule\n```php\nclass MyRule extends CustomRule\n{\n    public function applyRule($value)\n    {\n        if ($value === 'azerty') {\n            throw new FieldException('invalid azerty value');\n        }\n\n        return $value;\n    }\n}\n```\n\n#### Default\nWhen value is not setted it can be set with those argument\n\n### Helpers\nIt have methods for pagination, create, read, update and delete.  \n\n```php\n// $database is an instance of Rancoud\\Database\\Database\n$user = new User($database);\n\n$newId = $user-\u003ecreate(['nickname' =\u003e 'rancoud']);\n\n$row = $user-\u003eone($newId);\n// you will have an array representing data in database with correct types\n// here : ['id' =\u003e 1, 'nickname' =\u003e 'rancoud'];\n$rows = $user-\u003eall();\n// here it's all rows in table : [ ['id' =\u003e 1, 'nickname' =\u003e 'rancoud'] ] \n\n$user-\u003eupdate(['nickname' =\u003e 'rancoud2'], $newId);\n\n$user-\u003edelete($newId);\n```\n\nModel::all() accept an array with some keys that triggers specific actions  \n\n```php\n// $database is an instance of Rancoud\\Database\\Database\n$user = new User($database);\n\n// 50 rows using LIMIT 50 OFFSET 50\n$rows = $user-\u003eall(['page' =\u003e 1]);\n// 10 rows using LIMIT 10 OFFSET 10\n$rows = $user-\u003eall(['count' =\u003e 10, 'page' =\u003e 1]);\n\n// count rows in table\n$count = $user-\u003eall(['rows_count' =\u003e 1]);\n\n// return all rows with no limit \n$count = $user-\u003eall(['no_limit' =\u003e 1]);\n\n// change order by\n$count = $user-\u003eall(['order' =\u003e 'nickname']);\n// change order by and order\n$count = $user-\u003eall(['order' =\u003e 'nickname|desc']);\n// multiple change order by and order\n$count = $user-\u003eall(['order' =\u003e 'nickname|desc,id|asc']);\n```\n\nYou can change values output in Model::all() with override functions:  \n* getSqlAllSelectAndFillSqlParams(params: array)  \n* getSqlAllJoinAndFillSqlParams(params: array)  \n* getSqlAllWhereAndFillSqlParams(params: array)  \n\n## Callbacks\nYou can add callback before and after create, update and delete.  \n```php\n$model-\u003eaddBeforeCreate('a', function($sql, $params){\n    // for modifying sql and params use this return otherwise don't\n    return [$sql, $params];\n});\n\n$model-\u003eaddAfterCreate('a', function($newId, $params){\n    // for modifying params use this return otherwise don't\n    return $params;\n});\n\n$model-\u003eaddBeforeUpdate('a', function($sql, $params){\n    // for modifying sql and params use this return otherwise don't\n    return [$sql, $params];\n});\n\n$model-\u003eaddAfterUpdate('a', function($params){\n    // for modifying params use this return otherwise don't\n    return $params;\n});\n\n$model-\u003eaddBeforeDelete('a', function($sql, $params){\n    // for modifying sql and params use this return otherwise don't\n    return [$sql, $params];\n});\n\n$model-\u003eaddAfterDelete('a', function($params){\n    // for modifying params use this return otherwise don't\n    return $params;\n});\n```\n\nYou can use JsonOutput trait for adding json format for the model.  \n\n## Field Constructor\n### Settings\n#### Mandatory\n| Parameter | Type   | Description                                                                                                           |\n|-----------|--------|-----------------------------------------------------------------------------------------------------------------------|\n| type      | string | type of field, values used : int \\| float \\| char \\| varchar \\| text \\| date \\| datetime \\| time \\| timestamp \\| year |\n\n#### Optionnals\n| Parameter | Type  | Default value | Description                                                                                                                           |\n|-----------|-------|---------------|---------------------------------------------------------------------------------------------------------------------------------------|\n| rules     | array | []            | rules for checking values, values used : pk \\| fk \\| unsigned \\| email \\| not_null \\| max \\| min \\| range \\| Rancoud\\Model\\CustomRule |\n| default   | mixed | false         | default value when none given                                                                                                         |\n\n## Field Methods\n* isPrimaryKey(): bool  \n* isForeignKey(): bool  \n* isNotNull(): bool  \n* getDefault(): mixed  \n* formatValue(value: mixed): ?mixed  \n\n## Model Constructor\n### Settings\n#### Mandatory\n| Parameter | Type                       | Description       |\n|-----------|----------------------------|-------------------|\n| $database | \\Rancoud\\Database\\Database | Database Instance |\n\n## Model Methods\n### General Commands\n* all(params: array, [validFields: array = []]): array|bool|int  \n* one(id: mixed, [...ids: mixed = []]): array  \n* create(args: array): bool|int  \n* update(args: array, id: mixed, [...ids: mixed = []]): void  \n* delete(id: mixed, [...ids: mixed = []]): void  \n* getLastInsertId(): ?int  \n\n### Database error\n* getDatabaseErrors(): ?array  \n* getDatabaseLastError(): ?array  \n\n### Callbacks\n#### Add\n* addBeforeCreate(name: string, callback: mixed): void  \n* addAfterCreate(name: string, callback: mixed): void  \n* addBeforeUpdate(name: string, callback: mixed): void  \n* addAfterUpdate(name: string, callback: mixed): void  \n* addBeforeDelete(name: string, callback: mixed): void  \n* addAfterDelete(name: string, callback: mixed): void  \n\n#### Remove\n* removeBeforeCreate(name: string): void  \n* removeAfterCreate(name: string): void  \n* removeBeforeUpdate(name: string): void  \n* removeAfterUpdate(name: string): void  \n* removeBeforeDelete(name: string): void  \n* removeAfterDelete(name: string): void  \n\n## Static Helper Methods\n* getCountPerPage(args: array): int  \n* getLimitOffsetCount(args: array): array  \n* getOrderByOrderField(args: array, [validFields: array = []]): array  \n* getPageNumberForHuman(args: array): int  \n* getPageNumberForSql(args: array): int  \n* hasInvalidPrimaryKey(value: int): bool  \n* hasLimit(args: array): bool  \n* implodeOrder(orders: array): string  \n* isRowsCount(args: array): bool  \n* isValidFieldForOrderBy(field: string, [validFields: array = []]): bool  \n\n## How to Dev\n`docker compose build \u0026\u0026 docker compose run lib composer ci` for launching tests\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Francoud%2Fmodel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Francoud%2Fmodel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Francoud%2Fmodel/lists"}