Upgrading To Core 4.0
This guide covers the breaking changes in Core 4.0.0 and the checks required when adopting it in an application. PHP 8.5 and Phalcon 5.22 remain the runtime baseline.
Only Core 4.x is maintained. All earlier versions, including zemit-cms/core, are end of life and receive no support, bug fixes, security fixes, or backports. Older tags remain available for reproducible installs during migration; see the security policy.
Core 4.0 focuses on reusable Phalcon extensions and common application features. Application schemas belong to the applications that use them. This change retires the old spreadsheet/catalog application and CMS runtime while keeping the existing provider, model-mapping, controller, and module extension patterns.
What Stays
- Bootstrap, configuration, providers, MVC/CLI/WebSocket modules, and helpers.
- REST controllers, query/filter/save rules, response transformers, model behaviors, eager loading, nested relationship writes, and scaffolding.
- Identity, login/registration/reset hooks, sessions, impersonation, permissions, roles/groups/types, email/templates, files, audit, and settings.
- Locale, translation adapters, validation helpers, and ordinary database models.
- Generic database maintenance commands and the existing REST compatibility aliases. Migrate callers of deprecated routes separately with response tests.
The remaining prepared models (Backup, Job/JobScheduler, Profile, FileRelation, and feature/association models) stay in this first scope. Some are referenced by retained services or model relationships; absence of an application import alone is insufficient evidence for removing them.
Core remains one package. No new repository abstraction or optional legacy package is introduced by this change.
See Retained Feature Contracts for model replacement, required services/tables, and workflows owned by the application.
Removed Model Inventory
All names in this table are under PhalconKit\Models\. For each name, the concrete class, Abstracts\{Name}Abstract, Abstracts\Interfaces\{Name}AbstractInterface, and Interfaces\{Name}Interface are removed together.
| Retired area | Model families |
|---|---|
| Dynamic catalog | Workspace, WorkspaceLang, Table, Column, Record, Data, Validator |
| CMS | Site, SiteLang, Page, Post, PostCategory, Category, Menu, Meta |
| Database-backed language/translation records | Lang, Translate |
| Site-owned flags | Flag |
Flag belongs to the retired Site model graph. The separate Feature model and feature permissions remain. Models\Validator was a catalog table model; PhalconKit\Filter\Validation and its validators remain.
An application's App\Models\Record, Data, Table, or Workspace is not removed. Inspect its parent, implemented interfaces, relations, and configuration before deciding whether it depends on a retired Core contract. Ordinary models can continue extending PhalconKit\Mvc\Model or PhalconKit\Models\AbstractModel through application-owned generated abstracts.
Removed Runtime Surface
| Surface | Exact removal | Application action |
|---|---|---|
API controllers in PhalconKit\Modules\Api\Controllers | CategoryController, ColumnController, DataController, FlagController, LangController, MenuController, MetaController, PageController, PostController, RecordController, TableController, TranslateController, WorkspaceController, plus the placeholder FieldController, TranslateFieldController, TranslateTableController | Remove obsolete routes/permissions, or implement an app-owned resource using the generic API controller. |
| Model implementation | PhalconKit\Mvc\Model\Dynamic | Use app-owned models with stable class/source metadata. There is no drop-in dynamic-source replacement. |
| Record transformer | PhalconKit\Modules\Api\Transformers\RecordTransformer | Use an application transformer for the application's record model. The generic transformer infrastructure remains. |
| Database provider | PhalconKit\Provider\DatabaseDynamic\ServiceProvider, service dbd, database.drivers.dynamic, PROVIDER_DATABASE_DYNAMIC, and DATABASE_DYNAMIC_* defaults | Remove unused configuration. If a second database is needed, register an application provider explicitly. Primary db and read-only dbr remain. |
Permission presets in PhalconKit\Bootstrap\Permissions | ColumnConfig, DynamicConfig, RecordConfig, TableConfig, WorkspaceConfig | Remove these imports and ACL entries; define policies for app-owned resources. TemplateConfig remains. |
| Catalog fixture generator | PhalconKit\Modules\Cli\Tasks\FakerTask and bin/database-faker.sh | Remove task/permission references and scheduled invocations. Use application fixtures or explicit deployment seed rows. The generic Faker provider remains. |
Enums in PhalconKit\Models\Enums | ColumnType, WorkspaceStatus, SiteStatus, ValidatorType, TranslateTableTable | Own any still-needed domain enums in the application. |
| Typed registry helpers | getFlag(), getLang(), getTranslate(), getWorkspace(), getWorkspaceLang(), getPage(), getPost(), getTable(), and their get{Name}Class() counterparts | Remove obsolete calls. models mappings and generic getInstance()/getClassMap() continue to support application-owned classes. |
| Default model mappings | Entries and MODEL_* defaults for those eight typed registry families | Remove overrides targeting the retired classes. Retained model mappings keep their current contracts. |
The dependency review includes retained models' relationship targets, through models, service/config references, and application inheritance. Tests initialize all retained Core models and resolve their relationship classes without opening a database. This verifies the runtime class graph, not the availability of any application's database tables.
Explicit Database Maintenance
database drop, truncate, fix-engine, insert, optimize, analyze, and reset remain available. Core no longer supplies table lists, role/language seeds, or a development account. With no instructions, these commands perform no database queries. main still runs engine changes, optimization, and analysis; reset still truncates before inserting.
Put instructions in the application configuration, using its own table and model names. For example:
'deployment' => [
'drop' => [],
'truncate' => [],
'engine' => ['app_lookup' => 'InnoDB'],
'optimize' => ['app_lookup'],
'analyze' => ['app_lookup'],
'insert' => [
\App\Models\Lookup::class => [
['key' => 'active', 'label' => 'Active'],
],
],
],
Each configured key replaces the matching task property in full. Omitted keys preserve an application subclass's defaults, including properties assigned before parent::initialize(). An explicit empty array disables that operation. The six arrays may also be set directly on an application DatabaseTask. Bootstrap\Deployment remains available as a config container with empty defaults.
These are trusted maintainer instructions, not request input. drop and truncate destroy data, engine names must be trusted, and inserts are ordinary model saves with their validation/events. Seeds use the concrete class key exactly as supplied; Core-to-app model mappings are not applied here. The task grants the CLI role access to the configured seed models. Repeated inserts are not automatically idempotent, and reset is not an atomic database transaction.
Review existing seed records before copying them. Supply account credentials explicitly through the application's account-creation flow; do not recreate the old default development account or assume that seed insertion generates a secure password.
Existing Data And Migration History
No removal in this branch runs a migration, drops a table, or deletes data. Keep application-owned migration history and existing schemas intact while upgrading PHP code. Deleting unused database tables is a separate application migration with its own data review and rollback plan.
The package now ships resources/migrations/4.0.0/ for fresh databases, with only the 29 retained Core tables. The old packaged 1.0.0/ directory is removed; historical tags still contain it. Do not remove or rename migrations already owned/applied by an application.
The baseline uses InnoDB, connection-local foreign keys, Unicode text defaults, case-sensitive credential/token comparisons, larger OAuth token storage, and 64-character audit/file relation identifiers. It refuses existing tables/history and never drops retired tables. Review these changes against actual application data and introduce separate, explicit upgrade migrations where appropriate.
See Database Migrations for the fresh installation and reusable SQL helper. Retained models still require their tables; the baseline contains no accounts, roles, or other seed records.
Application Upgrade Checks
- Keep the application's existing lockfile and a suitable tagged-version constraint while preparing an isolated upgrade checkout.
dev-masternow follows ongoing development; use^4.0for the supported stable line. The old0.4.x,1.0.x, and temporary4.xbranches have been retired. Applications using branch constraints must select an appropriate tagged release or opt into testingdev-masterdeliberately. - Search imports, parent classes, interfaces, DI registrations, model mappings, permission config, routes, CLI schedules, and seed code for the exact retired namespaces above. Remove unused imports and permission-only references too.
- Preserve app-owned schemas and adapt any actual Core-domain dependencies. Applications that still need the retired runtime must own the equivalent feature before upgrading. Remaining on 3.x means using an unsupported release without security fixes or backports. No compatibility shim is provided.
- Supply explicit database-maintenance instructions. Verify app overrides, seed models, and empty defaults with disposable data.
- Test authentication and reset delivery, authorization, model substitution, REST response shapes, nested saves, eager loading, audit/files, and any CLI or WebSocket tasks the application uses. Class-loading smoke tests do not prove those flows work.
Release Validation And Application Adoption
Core 4.0 validation includes the lowest/highest dependency CI matrix, native MySQL baseline and transaction tests, public Composer installs, regenerated API reference, and isolated application acceptance suites. Consumer fixtures cover model substitution and persistence, tenant/permission rules, API compatibility, identity/reset/session behavior, notifications, and application migrations.
These fixtures use disposable schemas and synthetic data. They do not certify an application's production data conversion, browser/mobile SSO, or external provider delivery. Verify those workflows in the application's rollout process, with its own migration review and recovery plan. The fresh Core baseline must never run over an existing application schema.
Model substitution follows the boundaries in Retained Feature Contracts: configured resolvers do not rewrite direct class references or generated relationships. Preserve application overrides and public REST aliases until their callers have been migrated and tested.
Only Core 4.x is maintained. master is the sole long-lived branch; signed tags identify releases. See the release process for distribution checks and the security policy for the support boundary.