{"id":13660370,"url":"https://github.com/conceptsandtraining/lib-ente","last_synced_at":"2026-01-13T23:43:00.694Z","repository":{"id":56957158,"uuid":"82300707","full_name":"conceptsandtraining/lib-ente","owner":"conceptsandtraining","description":"An entity component framework for PHP.","archived":false,"fork":false,"pushed_at":"2019-07-04T14:45:52.000Z","size":220,"stargazers_count":2,"open_issues_count":1,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-06-01T08:49:04.948Z","etag":null,"topics":["entity-component","lib"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/conceptsandtraining.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}},"created_at":"2017-02-17T13:37:53.000Z","updated_at":"2024-02-02T20:42:57.000Z","dependencies_parsed_at":"2022-08-21T04:40:22.283Z","dependency_job_id":null,"html_url":"https://github.com/conceptsandtraining/lib-ente","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/conceptsandtraining/lib-ente","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conceptsandtraining%2Flib-ente","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conceptsandtraining%2Flib-ente/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conceptsandtraining%2Flib-ente/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conceptsandtraining%2Flib-ente/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/conceptsandtraining","download_url":"https://codeload.github.com/conceptsandtraining/lib-ente/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conceptsandtraining%2Flib-ente/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28405149,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["entity-component","lib"],"created_at":"2024-08-02T05:01:20.739Z","updated_at":"2026-01-13T23:43:00.680Z","avatar_url":"https://github.com/conceptsandtraining.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.com/conceptsandtraining/lib-ente.svg?token=4shwrT94iPQfpaEX1GWY\u0026branch=master)](https://travis-ci.com/conceptsandtraining/lib-ente)\n# ente.php\n\n*An entity component framework for ILIAS.*\n\n**Contact:** [Richard Klees](https://github.com/klees)\n\n\n## Model\n\n[Entity component model or system is an architectural pattern](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system)\ndeveloped for and mostly used in games. Still, the problems solved with that\npattern are discovered in other situations, i.e. the development of interconnected\nfunctionality in [ILIAS](https://github.com/ILIAS-eLearning/ILIAS).\n\nThe general problem that is solved could be described as such: One has a system\nwith some (or often a lot of) entities in it. An entity can be understood as an\nobject that has an identity and exhibits some continuity over time and space.\nWithin the system, there are a lot of subsystems that act upon these entities.\n\n\u003e **Example:**\n\u003e In a real time strategy game, entities would be units of the armies in the game\n\u003e as well as objects in the landscape and maybe other things. Systems acting\n\u003e upon these objects would be e.g. a physics system, a path finding system, a\n\u003e sound system, ...\n\n\u003e **Example:**\n\u003e In ILIAS an entity could basically be identified with all descendants of `ilObject`\n\u003e although there are possibly more things that could be called entities, e.g.\n\u003e questions in the test. Systems acting upon these entities would then e.g. be the\n\u003e RBAC system, the Learning Progress System, the Tree/Repository, ...\n\nImplementing that kind of system with inheritance could lead to some problems that\ncould also be observed in ILIAS:\n\n* The classes that are used to build entities aqcuire a lot of code to be able to\n  serve all systems that are interested in them.\n* It is difficult to share functionality between the different classes of entities.\n* It is cumbersome to define classes of entities where the objects might or might\n  not take part in that system, depending on whatever.\n* For languages that are not memory managed (e.g. C) that strategy for implementation\n  might also be bad for caching in CPU caches.\n\nEntity component model solves these problems by employing the principle to \"favour\ncomposition over inheritance\". The entities on their own are understood to just\nsupply the required identity and continuity, i.e. each entity is basically an id.\nComponents that serve the needs of different subsystems can then be attached to\nthe entity to make them take part in that system.\n\n\u003e **Example:**\n\u003e A entity in the RTS game could be extended with a \"physics\" component that\n\u003e knows a location and other physical metrics of the entity to make it appear\n\u003e on the playground.\n\n\u003e **Example:**\n\u003e The implementation of the learning progress in ILIAS actually follows that\n\u003e model. Instead of providing some interface that all `ilObjects` with learning\n\u003e progress need to implement, one needs to build a separate object that takes\n\u003e care of the learning progress of the original `ilObject`.\n\nThis pattern for solving the described problem has some virtues over the naive\ninheritance based approach:\n\n* Instead of one huge class that contains code for all kind of subsystems the\n  entity is split up into distinct classes that each serve only some subset\n  of all systems.\n* There is an obvious way to share functionality between entities: just use\n  the same components or implementation for the component.\n* If an entity should not be processed by a subsystem just don't add the\n  according component to the entity. This could easily be changed at runtime\n  and requires no code change.\n* C-programmes and the like could take care about memory locality more easily.\n  A similar benefit regarding the database could apply in the PHP scenario.\n\nThere are definetly also disadvantages in using the entity component model. For\nthe sake of the argument they are not written down here. Finding them is left as\nan exercise to the reader.\n\n\n## Implementation\n\nThis implementation is meant to work in the context of ILIAS, where Plugins should\nbe able to define components for `ilObjects`. This library therefore knows four\nkinds of objects, where the according interfaces could be found in the base directory\nof the lib:\n\n* `Entity` provides the basic means to identify an object. That is, an entity\n  needs to be able to provide some comparable id, where objects with the same id\n  are indeed the very same object. This is the thingy known from the pattern.\n* A `Component` is the thingy from the pattern that provides information and\n  implementations for a certain subsystem. Since the library doesn't know about\n  these subsystems, the basic interface just provides a method to get to know\n  the entity the component belongs to. This will be one main extension point\n  for this library.\n* This library should be able to work in the context of `ilObjects`, plugins and\n  the ILIAS tree. The plugins this framework will be used for are mainly there\n  to enhance the ILIAS Course with different functionality. Plugins then need\n  to be able to extend the course in different directions, thus a notion of\n  sources for components of an entity is required. A `Provider` thus can provide\n  different types of components for a fixed entity. \n* All this stuff needs to be tied together, that is what the `Repository` does.\n  It is the source to query for `Providers` and `Components`.\n\nA simple implementation (without ILIAS) can be found in `src/Simple`. It defines\ntwo Components `AttachInt` and `AttachString` that both have one `*Memory`\nimplementation.\n\nAn ILIAS based implementation can be found in `src/ILIAS`. It contains two more\nnoteworthy objects, that act as a plumbing between the simple model presented\nabove and the factual ILIAS world.\n\n* The `UnboundProvider` accounts for the fact, that ILIAS repository objects can\n  actually have different locations in the tree. An object providing components\n  could thus provide for different branches of the tree. To still allow for some\n  common machinery to store and load providers, repository objects need a way to\n  talk about their possibilities to provide components without actually knowing\n  which entity they are bound to.\n* The `ProviderDB` is that common machinery to store and load providers. Objects\n  providing components must create `UnboundProviders` via that object. The ILIAS\n  implementation of the model then uses the tree to turn the `UnboundProviders`\n  to real providers for the objects in the tree.\n\nThe usage of both facilities is showcased in two examples.\n\n\n## Example\n\nThe `example` folder contains two plugins, one that provides a component, one that\nuses handles the provided component. Note that both plugins do not know each other.\nTheir common denominator is this library and the `AttachString` component they both\nuse. Both plugins try to showcase this framework only and are no good showcases for\ngeneral plugin development!\n\nThe `AttachString` component is a very dumb component that allows to attach a string\nto an entity. We most probably won't use such a simple component in a real world\nproblem.\n\nTo check out what the plugins are doing, copy both of them to the directory for\nRepositoryPlugins in an ilias installation, `composer install` them and activate\nthem within ILIAS. You should be provided with two new types of repo objects: \n`Component Handler Example` and `Component Provider Example`. Create a course and\nan object for each plugin within the course.\n\nFirst open the Provider-object. You should get a simple form where you can add\nmultiple strings the object will provide via the `AttachString` component. Do that\nnow (and don't forget to save the form). Then open the Handler-object. You should\nsee a simple listing of all strings you added to the provider. You can also\nadd some more providers to the course. The handler will collect the strings\nfrom all providers. You could of course also add some more handlers, but they\nwon't differ from your first one.\n\nNow have a look at how the provider object is implemented. One thing the plugin\nneeds to implement is an instance of `UnboundProvider`. This can be found in\n`example/ComponentProviderExample/classes/UnboundProvider.php`. This class needs\nto tell which components it intents to provide via `componentTypes` and needs to\npresent a way how instance of these components can be created via `buildComponentsOf`.\n\nThe `UnboundProvider` has an `owner`-ilObject, which is used to get the provided\nstrings from the ILIAS-database. The component interface `AttachString` is used\nfor the declaration in `componentTypes`, but `buildComponentOf` uses the in-memory\nimplementation `AttachStringMemory` to create the actual components. \n\nThe provider object needs to define when an `UnboundProvider` is actually created\nand the object starts to provide components for some other object. This is done\non creation of the object in `example/ComponentProviderExample/classes/class.ilObjComponentProviderExample.php`. The trait `ilProviderObjectHelper` helps to easily implement that\ncreation. The object needs to provide a DIC via `getDIC` and then may `createUnboundProvider`\nwhenever it needs to. To do that, it needs to tell for which objects on its path\nit wants to provide components for (`crs` in the example), what the name of the\n`UnboundProvider` is and where the according implementation can be found. The object\nalso needs to take care that the UnboundProviders it created gets destroyed afterwards,\nwhich is done via `deleteUnboundProviders` on object deletion.\n\nThe handler object is even simple. In `example/ComponentHandlerExample/classes/class.ilObjComponentHandlerExample.php`\nyou can see the according implementation for the handler. It uses the `ilHandlerObjectHelper`\ntrait and also needs to provide a DIC via `getDIC`. It also needs to provide the\n`ref_id` of an object it intends to handle components for. We just use the parent\nin the example. It then can use `getComponentsOfType` to get all components provided\nfor its object and do further processing on them.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconceptsandtraining%2Flib-ente","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconceptsandtraining%2Flib-ente","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconceptsandtraining%2Flib-ente/lists"}