{"id":19110197,"url":"https://github.com/locomotivemtl/charcoal-object","last_synced_at":"2026-02-14T13:34:06.316Z","repository":{"id":56060431,"uuid":"79466623","full_name":"locomotivemtl/charcoal-object","owner":"locomotivemtl","description":"Object definition (Content and UserData), behaviors and tools.","archived":false,"fork":false,"pushed_at":"2024-01-30T18:16:07.000Z","size":211,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-10-05T04:28:49.921Z","etag":null,"topics":["charcoal","content","model","object","php","revision","route","userdata"],"latest_commit_sha":null,"homepage":null,"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/locomotivemtl.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":"2017-01-19T15:26:59.000Z","updated_at":"2024-02-06T15:14:02.000Z","dependencies_parsed_at":"2024-11-09T04:25:00.152Z","dependency_job_id":"7770e802-da1c-4141-bdc8-8827ef463e3e","html_url":"https://github.com/locomotivemtl/charcoal-object","commit_stats":{"total_commits":116,"total_committers":10,"mean_commits":11.6,"dds":0.6724137931034483,"last_synced_commit":"dce9936ae1f2a54c897d0e6abd231586169c6ab4"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/locomotivemtl/charcoal-object","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-object","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-object/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-object/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-object/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/locomotivemtl","download_url":"https://codeload.github.com/locomotivemtl/charcoal-object/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-object/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29444751,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T12:43:28.304Z","status":"ssl_error","status_checked_at":"2026-02-14T12:43:14.160Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["charcoal","content","model","object","php","revision","route","userdata"],"created_at":"2024-11-09T04:24:02.472Z","updated_at":"2026-02-14T13:34:06.299Z","avatar_url":"https://github.com/locomotivemtl.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Charcoal Object\n===============\n\nObject definition (Content and UserData), behaviors and tools.\n\n# Table of content\n-   [How to install](#how-to-install)\n    -   [Dependencies](#dependencies)\n-   [The Charcoal Object](#the-charcoal-object)\n    -   [Basic classes](#basic-classes)\n        -   [Content](#content)\n        -   [UserData](#userdata)\n    -   [Object behaviors](#object-behaviors)\n        -   [Archivable](#archivable)\n        -   [Categorizable](#categorizable)\n        -   [Category](#category)\n        -   [Hierarchical](#hierarchical)\n        -   [Publishable](#publishable)\n        -   [Revisionable](#revisionable)\n        -   [Routable](#routable)\n    -   [Helpers](#helpers)\n        -   [ObjectDraft](#objectdraft)\n        -   [ObjectRevision](#objectrevision)\n        -   [ObjectSchedule](#objectschedule)\n-   [Development](#development)\n    -   [Development dependencies](#development-dependencies)\n    -   [Continuous Integration](#continuous-integration)\n    -   [Coding Style](#coding-style)\n    -   [Authors](#authors)\n    -   [Changelog](#changelog)\n\n# How to install\n\nThe preferred (and only supported) way of installing _charcoal-object_ is with **composer**:\n\n```shell\n★ composer require locomotivemtl/charcoal-object\n```\n\n## Dependencies\n\n- PHP 5.6+\n    -   This is the last supported version of PHP.\n    -   `PHP 7` is also supported (meaning _green on travis_…).\n\n# The Charcoal Object\n\nThe `\\Charcoal\\Object` namespace provides a bunch of basic classes, helpers as well as object behaviors (interfaces + traits).\n\n## Basic classes\n\nAll charcoal project object classes should extend one of the 2 base classes, [`\\Charcoal\\Object\\Content`](#content), for data created and managed by administrators or [`\\Charcoal\\Object\\UserData`](#userdata), for data created from clients / users.\n\n### Content\n\nThe **Content** base class should be used for all objects which can be \"managed\". Typically by an administrator, via the `charcoal-admin` module. It adds the \"active\" flag to objects as well as creation and modification informations.\n\n**API**\n\n-   ` setActive($active)`\n-   `active()`\n-   `setPosition($position)`\n-   `position()`\n-   `setCreated($created)`\n-   `created()`\n-   `setCreatedBy($createdBy)`\n-   `createdBy()`\n-   `setLastModified($lastModified)`\n-   `lastModified()`\n-   `setLastModifiedBy($lastModifiedBy)`\n-   `lastModifiedBy()`\n\n\u003e The `Content` class extends `\\Charcoal\\Model\\AbstractModel` from the `charcoal-core` module, which means that it also inherits its API as well as the `DescribableInterface` (`metadata()`, `setMetadata()` and `loadMetadata()`, amongst others) and the `StorableInterface` (`id()`, `key()`, `save()`, `update()`,  `delete()`, `load()`, `loadFrom()`, `loadFromQuery()`, `source()` and `setSource()`, amongst others).\n\u003e\n\u003e The `AbstractModel` class extends `\\Charcoal\\Config\\AbstractEntity` which also defines basic data-access methods (`setData()`, `data()`, `keys()`, `has()`, `get()`, `set()`, plus the `ArrayAccess`, `JsonSerializable` and `Serializable` interfaces).\n\n**Properties (metadata)**\n\n| Property               | Type        | Default     | Description |\n| ---------------------- | ----------- | ----------- | ----------- |\n| **active**             | `boolean`   | `true`      | …           |\n| **position**           | `number`    | `null`      | …           |\n| **created**            | `date-time` | `null` [1]  | …           |\n| **created_by**         | `string`    | `''` [1]    | …           |\n| **last_modified**      | `date-time` | `null` [2]  | …           |\n| **last\\_modified\\_by** | `string`    | `''` [2]    | …           |\n\n\u003csmall\u003e[1] Auto-generated upon `save()`\u003c/small\u003e\u003cbr\u003e\n\u003csmall\u003e[2] Auto-generated upon `update()`\u003c/small\u003e\u003cbr\u003e\n\n\u003e Default metadata is defined in `metadata/charcoal/object/content.json`\n\n### UserData\n\nThe **UserData** class should be used for all objects that are expected to be entered from the project's \"client\" or \"end user\".\n\n**API**\n\n-   `setIp($ip)`\n-   `ip()`\n-   `setTs($ts)`\n-   `ts()`\n-   `setLang($lang)`\n-   `lang()`\n\n\u003e The `Content` class extends `\\Charcoal\\Model\\AbstractModel` from the `charcoal-core` module, which means that it also inherits its API as well as the `DescribableInterface` (`metadata()`, `setMetadata()` and `loadMetadata()`, amongst others) and the `StorableInterface` (`id()`, `key()`, `save()`, `update()`,  `delete()`, `load()`, `loadFrom()`, `loadFromQuery()`, `source()` and `setSource()`, amongst others).\n\u003e\n\u003e The `AbstractModel` class extends `\\Charcoal\\Config\\AbstractEntity` which also defines basic data-access methods (`setData()`, `data()`, `keys()`, `has()`, `get()`, `set()`, plus the `ArrayAccess`, `JsonSerializable` and `Serializable` interfaces).\n\n**Properties (metadata)**\n\n| Property  | Type        | Default     | Description |\n| --------- | ----------- | ----------- | ----------- |\n| **ip**    | `ip`        | `null` [1]  | …           |\n| **ts**    | `date-time` | `null` [1]  | …           |\n| **lang**  | `lang`      | `null` [1]  | …           |\n\n\u003csmall\u003e[1] Auto-generated upon `save()` and `update()`\u003c/small\u003e\u003cbr\u003e\n\n\u003e Default metadata is defined in `metadata/charcoal/object/user-data.json`\n\n## Object behaviors\n\n-   [Archivable](#archivable)\n-   [Categorizable](#categorizable)\n-   [Category](#category)\n-   [Hierarchical](#hierarchical)\n-   [Publishable](#publishable)\n-   [Revisionable](#revisionable)\n-   [Routable](#routable)\n\n### Archivable\n\n_The archivable behavior is not yet documented. It is still under heavy development._\n\n### Categorizable\n\n**API**\n\n-   `setCategory($category)`\n-   `category()`\n-   `setCategoryType($type)`\n-   `categoryType()`\n\n**Properties (metadata)**\n\n| Property        | Type       | Default     | Description |\n| --------------- | ---------- | ----------- | ----------- |\n| **category**    | `object`   | `null`      | The object's category.[1] |\n\n\u003csmall\u003e[1] The category `obj_type` must be explicitely set in implementation's metadata.\u003c/small\u003e\n\n\u003e Default metadata is defined in `metadata/charcoal/object/catgorizable-interface.json`\n\n### Category\n\n**API**\n\n-   `setCategoryItemType($type)`\n-   `categoryItemType()`\n-   `numCategoryItems()`\n-   `hasCategoryItems()`\n-   `categoryItems()`\n\n**Properties (metadata)**\n\n| Property          | Type       | Default     | Description |\n| ----------------- | ---------- | ----------- | ----------- |\n| **category_item** | `string`   | `null`      | …           |\n\n\u003e Default metadata is defined in `metadata/charcoal/object/catgory-interface.json`\n\n### Hierarchical\n\n**API**\n\n-   `hasMaster()`\n-   `isTopLevel()`\n-   `isLastLevel()`\n-   `hierarchyLevel()`\n-   `master()`\n-   `toplevelMaster()`\n-   `hierarchy()`\n-   `invertedHierarchy()`\n-   `isMasterOf($child)`\n-   `recursiveIsMasterOf($child)`\n-   `hasChildren()`\n-   `numChildren()`\n-   `recursiveNumChildren()`\n-   `children()`\n-   `isChildOf($master)`\n-   `recursiveIsChildOf($master)`\n-   `hasSiblings()`\n-   `numSiblings()`\n-   `siblings()`\n-   `isSiblingOf($sibling)`\n\n**Properties (metadata)**\n\n| Property      | Type       | Default     | Description |\n| ------------- | ---------- | ----------- | ----------- |\n| **master**    | `object`   | `null`      | The master object (parent in hierarchy). |\n\n\u003e Default metadata is defined in `metadata/charcoal/object/hierarchical-interface.json`.\n\n### Publishable\n\n-   `setPublishDate($publishDate)`\n-   `publishDate()`\n-   `setExpiryDate($expiryDate)`\n-   `expiryDate()`\n-   `setPublishStatus($status)`\n-   `publishStatus()`\n-   `isPublished()`\n\n**Properties (metadata)**\n\n| Property           | Type         | Default    | Description |\n| ------------------ | ------------ | ---------- | ----------- |\n| **publishDate**   | `date-time`  | `null`     | …           |\n| **expiryDate**    | `date-time`  | `null`     | …           |\n| **publishStatus** | `string` [1] | `'draft'`  | …           |\n\n\u003e Default metadata is defined in `metadata/charcoal/object/publishable-interface.json`.\n\n### Revisionable\n\nRevisionable objects implement `\\Charcoal\\Object\\Revision\\RevisionableInterface`, which can be easily implemented by using `\\Charcoal\\Object\\Revision\\RevisionableTrait`.\n\nRevisionable objects create _revisions_ which logs the changes between an object's versions, as _diffs_.\n\n**API**\n\n-   `setRevisionEnabled(bool$enabled)`\n-   `revisionEnabled()`\n-   `revisionObject()`\n-   `generateRevision()`\n-   `latestRevision()`\n-   `revisionNum(integer $revNum)`\n-   `allRevisions(callable $callback = null)`\n-   `revertToRevision(integer $revNum)`\n\n**Properties (metadata)**\n\n_The revisionable behavior does not implement any properties as all logic \u0026 data is self-contained in the revisions._\n\n### Routable\n\n_The routable behavior is not yet documented. It is still under heavy development._\n\n## Helpers\n\n### ObjectDraft\n\n…\n\n### ObjectRevision\n\nUpon every `update` in _storage_, a revisionable object creates a new *revision* (a `\\Charcoal\\Object\\ObjectRevision` instance) which holds logs the changes (_diff_) between versions of an object:\n\n**Revision properties**\n\n| Property           | Type         | Default    | Description |\n| ------------------ | ------------ | ---------- | ----------- |\n| **target_type**    | `string`     | `null`     | The object type of the target object.\n| **target_id**      | `string`     | `null`     | The object idenfiier of the target object.\n| **rev_num**        | `integer`    | `null`     | Revision number, (auto-generated).\n| **ref_ts**         | `date-time`  |            |\n| **rev_user**       | `string`     | `null`     |\n| **data_prev**      | `structure`  |            |\n| **data_obj**       | `structure`  |            |\n| **data_diff**      | `structure`  |            |\n\n**Revision methods**\n\n-   `createFromObject(RevisionableInterface $obj)`\n-   `createDiff(array $dataPrev, array $dataObj)`\n-   `lastObjectRevision(RevisionableInterface $obj)`\n-   `objectRevisionNum(RevisionableInterface $obj, integer $revNum)`\n\n### ObjetSchedule\n\nIt is possible, (typically from the charcoal admin backend), to create *schedule* (a `\\Charcaol\\Object\\ObjectSchedule` instance) which associate a set of changes to be applied automatically to an object:\n\n**Schedule properties**\n\n| Property           | Type         | Default    | Description |\n| ------------------ | ------------ | ---------- | ----------- |\n| **target_type**    | `string`     | `null`     | The object type of the target object.\n| **target_id**      | `string`     | `null`     | The object idenfiier of the target object.\n| **scheduled_date** | `date-time`  | `null`     |\n| **data_diff**      | `structure`  | `[]`       |\n| **processed**      | `boolean`    | `false`    |\n| **processed_date** |\n\n**Schedule methods (API)**\n\n-   `process([callable $callback, callable $successCallback,callable $failureCallback])`\n\n\u003e Scheduled actions should be run with a timely cron job. The [charcoal-admin](https://github.com/locomotivemtl/charcoal-admin) module contains a script to run schedules automatically:\n\u003e\n\u003e ```shell\n\u003e ★ ./vendor/bin/charcoal admin/object/process-schedules`\n\u003e ```\n\n\n# Development\n\nTo install the development environment:\n\n```shell\n★ composer install --prefer-source\n```\n\nTo run the scripts (phplint, phpcs and phpunit):\n\n```shell\n★ composer test\n```\n\n## API documentation\n\n-   The auto-generated `phpDocumentor` API documentation is available at [https://locomotivemtl.github.io/charcoal-object/docs/master/](https://locomotivemtl.github.io/charcoal-object/docs/master/)\n-   The auto-generated `apigen` API documentation is available at [https://codedoc.pub/locomotivemtl/charcoal-object/master/](https://codedoc.pub/locomotivemtl/charcoal-object/master/index.html)\n\n## Development dependencies\n\n-   `phpunit/phpunit`\n-   `squizlabs/php_codesniffer`\n-   `satooshi/php-coveralls`\n\n## Continuous Integration\n\n| Service | Badge | Description |\n| ------- | ----- | ----------- |\n| [Travis](https://travis-ci.org/locomotivemtl/charcoal-object) | [![Build Status](https://travis-ci.org/locomotivemtl/charcoal-object.svg?branch=master)](https://travis-ci.org/locomotivemtl/charcoal-object) | Runs code sniff check and unit tests. Auto-generates API documentation. |\n| [Scrutinizer](https://scrutinizer-ci.com/g/locomotivemtl/charcoal-object/) | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/locomotivemtl/charcoal-object/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/locomotivemtl/charcoal-object/?branch=master) | Code quality checker. Also validates API documentation quality. |\n| [Coveralls](https://coveralls.io/github/locomotivemtl/charcoal-object) | [![Coverage Status](https://coveralls.io/repos/github/locomotivemtl/charcoal-object/badge.svg?branch=master)](https://coveralls.io/github/locomotivemtl/charcoal-object?branch=master) | Unit Tests code coverage. |\n| [Sensiolabs](https://insight.sensiolabs.com/projects/5ef771c49-8c05-448b-a112-069737b380dc) | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/ef771c49-8c05-448b-a112-069737b380dc/mini.png)](https://insight.sensiolabs.com/projects/ef771c49-8c05-448b-a112-069737b380dc) | Another code quality checker, focused on PHP. |\n\n## Coding Style\n\nThe charcoal-object module follows the Charcoal coding-style:\n\n-   [_PSR-1_](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)\n-   [_PSR-2_](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)\n-   [_PSR-4_](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md), autoloading is therefore provided by _Composer_.\n-   [_phpDocumentor_](http://phpdoc.org/) comments.\n-   Read the [phpcs.xml](phpcs.xml) file for all the details on code style.\n\n\u003e Coding style validation / enforcement can be performed with `composer phpcs`. An auto-fixer is also available with `composer phpcbf`.\n\n# Authors\n\n-   Mathieu Ducharme, mat@locomotive.ca\n-   Chauncey McAskill\n-   Locomotive Inc.\n\n# License\n\nCharcoal is licensed under the MIT license. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocomotivemtl%2Fcharcoal-object","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flocomotivemtl%2Fcharcoal-object","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocomotivemtl%2Fcharcoal-object/lists"}