chameleon-system/chameleon-base
Core foundation package for the Chameleon System PHP CMS, providing shared base classes, bootstrap and configuration helpers, service utilities, and common components used by Chameleon modules and extensions. It streamlines setup and extension development for Chameleon-based applications.
chameleon-system/chameleon-base is the technical foundation of the Chameleon CMS — the container bootstrapping, the table/record abstraction, the module system, and the shared services that every other Chameleon package builds on. You almost never install it "bare"; you install it as the base of a project and let the other chameleon-system/* packages (core, backend, standard modules) layer on top.
Minimal steps:
composer.json and require constraints first — this is the single biggest decision point.composer require chameleon-system/chameleon-base in a project skeleton, or clone an existing Chameleon project and treat this as a vendor dependency you read, not edit./cms (backend). If the login page renders, the container, DB connection, and autoloading are all healthy — that's your smoke test.Where to look first, in order: composer.json (dependency shape and PHP floor), the bundle/service wiring under src/, the auto-generated record classes (they tell you the naming conventions faster than any doc), and the backend module registry.
The record layer is the API. Chameleon generates a class per database table (TdbCms* / Tdb<Customer>*) at runtime/build time, all extending the base record class. Day-to-day work looks like:
$page = TdbCmsPage::GetNewInstance();
$page->LoadFromField('id', $pageId);
$list = TdbCmsPage::GetList();
$list->AddWhereToQuery("`cms_page`.`active` = '1'");
$list->SetOrderBy('name');
foreach ($list as $record) { /* ... */ }
Use the generated classes and record lists rather than hand-written SQL — they carry field metadata, localization handling, and caching. Drop to raw SQL only for reporting/aggregation where the record overhead is genuinely wasteful, and then still use the DBAL connection from the container rather than a global handle.
Backend CRUD goes through the table editor manager, not the record. For anything that must behave like a native backend edit (field types, permissions, workflow, history), drive TCMSTableEditorManager rather than saving records directly:
$editor = new TCMSTableEditorManager($db, $tableId);
$editor->SetId($recordId);
$editor->SaveField('name', $value);
Direct Save() on a record bypasses validation and the audit trail — fine for imports, dangerous for user-facing writes.
Modules are the unit of backend functionality. A backend module is a PHP class (implementing the module contract) plus a DB row describing it: name, icon, permission, and the class to instantiate. The pattern is: register the module → implement Execute() → return a rendered view. Keep module classes thin; push logic into a service.
Views are plain .view.php templates rendered by the framework's view object ($oView in template scope). Business logic belongs in the module or a service; templates should only read prepared data. Use the framework's escaping helpers — the frontend layer does not auto-escape.
Wire new code through the service container. Register services in a project bundle's services.yml and inject them; avoid TGlobal::Get()-style lookups in new code. This is the one area where you can write modern code on an old foundation, and it pays off in testability.
Extend by overriding, not patching. Chameleon supports replacing core services/classes via the container and via class-extension points. For a customized table or module, subclass the generated record or the module and point the config at your subclass. Never edit generated classes or vendor files — they are regenerated.
Schema changes belong in the project's migration/update mechanism, not ad-hoc ALTER TABLE. Chameleon tracks the data model and regenerates classes from it; an out-of-band column will exist in MySQL but not in the ORM until you resync and clear caches. Treat "edit field in backend → regenerate → clear cache" as one atomic step.
each(), create_function, dynamic properties, curly-brace string offsets, Symfony 3/4 deprecations). Budget for either pinning an old PHP runtime (with the security implications that carries) or a real upgrade effort before you commit.cms_ prefix, table-to-class mapping, and localization field suffixes are conventions the framework relies on. Renaming a table outside the tooling breaks class generation.AddWhereToQuery or an order-by applied to the wrong list instance.How can I help you explore Laravel packages today?