Skip to content

Configuration

The core and CI4 adapter share ORM options, but obtain connections and cache pools differently.

Concern Standalone core CodeIgniter adapter
Configuration object Daycry\Doctrine\Configuration Config\Doctrine extending the adapter config
Connection Explicit connection DBAL parameters Config\Database group
Mapping directories entities defaults to [] Defaults to APPPATH . 'Models/Entity'
Caches Inject CachePools; defaults are independent ArrayAdapters Creates pools from Config\Cache
Query logger Inject a PSR-3 logger Resolves CI4's logger service
Named managers Explicit ManagerRegistry factories Framework services keyed by database group

Configure the standalone core

use Daycry\Doctrine\Configuration;
use Daycry\Doctrine\Doctrine;

$config = new Configuration();
$config->connection = ['driver' => 'pdo_sqlite', 'memory' => true];
$config->entities = [__DIR__ . '/src/Entity']; // directory must exist
$doctrine = new Doctrine($config);

Connection keys use DBAL's names: for example driver, host, dbname, user and password. The core does not read config(), service(), CI4 constants or environment variables. Resolve application settings before constructing it.

Configure the CI4 adapter

Run php spark doctrine:publish once, then edit app/Config/Doctrine.php. Republishing prompts before replacing existing files.

<?php

namespace Config;

class Doctrine extends \Daycry\Doctrine\CodeIgniter4\Config\Doctrine
{
    public array $entities = [APPPATH . 'Models/Entity'];
    public bool $secondLevelCache = true;
    public bool $secondLevelCacheStatistics = true;
}

Declare only application overrides. Property initializers in subclasses are respected, and the inherited BaseConfig constructor handles CI4 configuration. See CI4 usage for group selection.

Entity mapping and lazy objects

Option Default Meaning
entities Core: []; adapter: application entity directory Existing directories containing entity mappings
metadataConfigurationMethod 'attribute' Use 'attribute' or 'xml' mappings
isXsdValidationEnabled false Validate XML mappings against the schema

PHP 8.5 native lazy objects are always enabled. Generated-proxy options proxyFactory, proxies, proxiesNamespace and setAutoGenerateProxyClasses have been removed. No proxy files are generated during deployment.

Query, result and metadata caches

Option Default Scope
queryCache / resultsCache / metadataCache true Enable the corresponding pool on the ORM configuration
queryCacheNamespace / resultsCacheNamespace / metadataCacheNamespace doctrine_queries / doctrine_results / doctrine_metadata Used by the CI4 adapter when constructing pools

The core uses the namespaces and lifetimes of the injected PSR-6 pools. Set those on the adapters themselves; changing a namespace option does not rename an injected pool. Defaults are independent, process-local ArrayAdapters. See standalone caching.

The CI4 adapter creates pools using Config\Cache:

  • Query and metadata pools inherit the framework TTL.
  • Result pools have a zero default lifetime.
  • The file backend uses PhpFilesAdapter for query/metadata and FilesystemAdapter for results/SLC.
  • Non-default groups append their exact hex-encoded group name to namespaces. The default group keeps the base namespace.

In the core, give different managers distinct persistent pool namespaces. ManagerRegistry does not add namespace suffixes.

Second-Level Cache

Option Default Meaning
secondLevelCache false Enable SLC using the injected or adapter-created pool
secondLevelCacheStatistics false Collect region hits, misses and puts
secondLevelCacheTtl null Core: zero lifetime; adapter: inherit framework TTL. Set 0 for no expiration or a positive number of seconds
secondLevelCacheLockPath null Core: explicit path required for READ_WRITE regions. Adapter: supplies a group-specific directory under WRITEPATH

The core accepts the SLC pool as CachePools::$secondLevel. Processes sharing READ_WRITE regions must share the lock directory. See SLC configuration for mappings, lifetimes and invalidation.

Custom DQL functions and types

Option Meaning
customStringFunctions / customNumericFunctions / customDatetimeFunctions / customJsonFunctions Named DQL function classes
customTypeMappings Native database type to Doctrine type mappings; defaults to enum/set mapped to string
customTypes Custom DBAL type names mapped to Type subclasses

DQL functions are prefilled from DoctrineExtensions and scienta/doctrine-json-functions using MySQL implementations. Override the arrays for database-specific functions on other platforms. Basic ORM use does not require calling these functions.

Custom types are registered idempotently. Platform type mappings are applied at construction and after reOpen().

Extension points

These options default to empty arrays or null:

Option Meaning
sqlFilters Filter names mapped to SQLFilter subclasses
enabledFilters Registered filters enabled on each new EntityManager
eventListeners Event names mapped to lists of listener objects or class names
eventSubscribers EventSubscriber objects or class names
dbalMiddlewares DBAL middleware objects or class names
defaultRepositoryClass Repository class for entities without an explicit repository

Classes supplied without instances must support construction without arguments. The CI4 adapter also adds toolbar instrumentation when CI_DEBUG is enabled. Filter parameters must be supplied by the application after enabling a filter.

Query logging

Option Default Meaning
queryLogging false Enable the PSR-3 query logger middleware
slowQueryThreshold 0.0 Minimum duration in seconds; zero logs every successful query
queryLogLevel 'info' PSR-3 record level

In standalone code, pass a PSR-3 logger explicitly:

$config->queryLogging = true;
$config->slowQueryThreshold = 0.5;
$config->queryLogLevel = 'warning';
$doctrine = new \Daycry\Doctrine\Doctrine($config, logger: $logger);

$logger is supplied by the application. Enabling logging without one raises InvalidArgumentException. The CI4 adapter uses its logger service automatically. Records contain SQL, bound parameters and duration_ms. Logging is independent of the debug toolbar.

Reopening

reOpen() creates a replacement EntityManager over the existing DBAL connection and ORM configuration. It rebuilds configured events, registers types/mappings and enables configured filters using the original constructor settings. The connection's middleware chain and cache pools remain in place.

Reapply runtime filter parameters and load entities through the replacement manager. Closing an in-memory SQLite connection discards its database; use reOpen() for the documented server-connection recovery case. See usage.