componenta / cycle
Cycle ORM integration for Componenta
Requires
- php: ^8.4
- componenta/caster: ^1.0
- componenta/config: ^3.0.0
- componenta/di: ^5.0.3
- componenta/identity: ^1.0
- componenta/paginator: ^1.0
- cycle/annotated: ^4.4
- cycle/database: ^2.15
- cycle/migrations: ^4.2
- cycle/orm: ^2.12
- cycle/schema-builder: ^2.11
- nesbot/carbon: ^3.0
- psr/container: ^2.0
Requires (Dev)
- phpunit/phpunit: ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Runtime integration between Componenta framework libraries and Cycle ORM/DBAL. The package provides repository base classes, data fetcher helpers, query filter contracts, typecasts, config provider factories, and database-oriented read models.
Discovery and console integration live in componenta/cycle-app.
Installation
composer require componenta/cycle
Install componenta/cycle-app only when an application needs entity discovery, schema-related console commands, or framework cache integration.
Related Packages
| Package | Why it matters here |
|---|---|
cycle/orm and cycle/database |
Provide the ORM/DBAL layer; this package adds Componenta integration around them. |
componenta/di |
Registers repositories, factories, and typecast services. |
componenta/cqrs |
Commonly uses repositories in command handlers and data fetchers in query handlers. |
componenta/paginator |
Represents paginated read-side results. |
componenta/cycle-app |
Discovers entities, builds ORM configuration, and wires console commands. |
Repository Layer
Repository extends Cycle ORM repositories and gives application repositories a common framework base without forcing domain code to depend on the application runtime.
Use repositories for aggregate persistence and identity-based lookups. Keep business transitions in aggregates and handlers; repositories should not become policy or workflow services.
Data Fetchers
DataFetcher is a read-side helper for list/detail projections built on Cycle DBAL. It provides:
- table name derivation with override support
- column selection through query interfaces
- pagination and optional total counts
- sort filters
- field mapping from
snake_casetocamelCase - per-field casters
- mapper methods named as
map{FieldName} - batch relation helpers for belongs-to, has-many, and many-to-many reads
Fetcher methods transform database rows into arrays or projection objects. Relation loading is batched after rows are collected, so fetchers can avoid N+1 queries.
Query Contracts
Read query objects can opt into behavior by implementing small contracts:
| Contract | Enables |
|---|---|
PaginableInterface |
Limit/offset pagination. |
RequiresTotalCountInterface |
Exposes the exact total count in the paginator. |
SortableInterface |
Ordered reads. |
SelectableInterface |
Explicit selected columns. |
SearchableInterface |
Full-text-like filtering through a fetcher-defined search filter. |
DateRangeInterface |
Date interval filtering. |
ListQueryInterface |
Common marker for list query objects. |
RequiresTotalCountInterface controls whether the paginator exposes the total. Without it, totalCount is null and hasNextPage still reports whether another page exists.
Fetcher Extension Points
Application fetchers usually extend DataFetcher and customize it with protected properties and methods:
| API | Purpose |
|---|---|
$excluded |
Fields removed from the transformed result. |
$autoMapToCamelCase |
Enables automatic snake_case to camelCase result keys. |
$fieldMapping |
Explicit database-field to result-field map. |
$casters |
Field-to-caster map resolved through CasterProviderInterface. |
map{FieldName}() |
Per-field mapper method called after caster conversion. |
loadRelations() |
Optional relation-loading hook for batched belongs-to, has-many, and many-to-many reads. |
Standard filters include PaginationFilter, OrderFilter, SearchFilter, DateRangeFilter, DateTimeFilter, ComparisonFilter, BetweenFilter, InFilter, NotInFilter, NullFilter, NotNullFilter, BooleanFilter, and SoftDeleteFilter.
Typecasts And Factories
The package includes framework typecasts and factory services used to configure Cycle ORM integration. These are runtime pieces and can be wired manually or through the Componenta DI config provider.
Built-in typecasts are UuidTypecast, EnumTypecast, and CarbonTypecast.
ConfigProvider registers Cycle DBAL/ORM factories for database configuration, database manager, ORM, schema, entity manager, migrations, and the default core factory. The main config keys live in ConfigKey.
Performance Notes
DataFetcher caches mapper-method names per instance and reads the current relation selection from the query. Requested totals use an aggregate over the unpaginated selection. Without a total, a limited query checks for one result after the page: ordinary selections use EXISTS, while DISTINCT, grouping and set operations retain their result cardinality in a limited count query. MySQL and SQL Server describe the output width before derived-table counts, assigning unique column aliases for stars and duplicate names. The page query selects only the requested rows. Page fields pass through unchanged to row transformation. The fetcher closes its statements before loading relations, including when reading or transforming a row fails.
The default database configuration uses the native SQL compiler. Query compilation caching is disabled because the upstream cache can change parameter binding for compound queries.
Pagination tests use SQLite in memory by default. To run the same public-contract tests on another supported database, set CYCLE_TEST_DB_DRIVER, CYCLE_TEST_DB_NAME and the required CYCLE_TEST_DB_HOST, CYCLE_TEST_DB_PORT, CYCLE_TEST_DB_USER, CYCLE_TEST_DB_PASSWORD or CYCLE_TEST_DB_SCHEMA variables, then run tests/DataFetcherPaginationTest.php. These tests select literal rows and do not create or modify tables.
tests/DataFetcherCursorTest.php uses the same MySQL connection variables to verify unbuffered reads, query caching, relation loading and recovery after row-conversion exceptions. It is skipped when a MySQL test connection has not been configured.
Boundaries
componenta/cycle contains runtime database behavior. Filesystem scanning, attribute discovery, schema console commands, and compile integration belong to componenta/cycle-app.