Skip to content

Configuration file reference

Propulsion has two entirely separate configuration surfaces, loaded by different code at different times:

  1. Build-time properties — the flat propulsion.* key space controlling how bin/propulsion generates code (builders, platform, paths, object-model options). Read by Propulsion\Generator\Config\GeneratorConfig.
  2. Runtime configuration — the datasource/connection array your generated Object Model classes use to actually connect to the database at request time. Read by Propulsion::init() (Propulsion\Propulsion) into a Propulsion\Config\PropulsionConfiguration.

There’s also a narrower, easy-to-conflate third thing: build-time database connections — the DSN(s) the generator itself connects with, only needed for build-time tasks that talk to a live database (schema:reverse, sql:exec, sql:diff against a live schema). This page covers all three.

This page replaces Propel 1’s propel.ext/YAML configuration file and runtime-conf.xml reference — Propulsion’s actual configuration format is different from both, as detailed below.

Properties come from three layers, merged in order (later layers win):

  1. generator/default.php — the base set Propulsion ships with. A plain PHP file returning a flat ['propulsion.foo' => 'value', ...] array. This is the authoritative list of every property and its default; read it directly if this page and the code ever disagree.
  2. One or more override files, passed with --config (repeatable — later files win) on the console commands. Two formats are accepted, dispatched by extension:
    • build.php (recommended) — a plain PHP file returning the same flat ['propulsion.foo' => ...] shape.
    • build.properties (legacy) — an Ant/Phing-style text file, one key = value pair per line, #/; comments. Still fully supported for existing Propel 1 projects; see GeneratorConfig::parsePropertiesFile().
  3. Ad-hoc CLI overrides--database and --target-platform on model:build set propulsion.database/propulsion.targetPlatform directly, applied after the config files.
Terminal window
bin/propulsion model:build schema.xml --config=build.php --database=pgsql
bin/propulsion model:build schema.xml --config=build.properties --config=build.local.properties

${propulsion.some.key} placeholders are resolved against the fully-merged flat array (up to 10 passes, innermost-first), regardless of which format produced them — so propulsion.platform.class => ${propulsion.platform.${propulsion.database}.class} in default.php resolves once propulsion.database is set.

The following tables list every propulsion.* key from generator/default.php, grouped the same way the file is. Property names below drop the propulsion. prefix and use dots for readability — write them with the full propulsion. prefix in your own build.php/build.properties.

PropertyDefaultDescription
version1.6.2-devPropulsion’s own version string.
home.Propulsion’s install root, used to resolve templatePath and the XSD/XSL resource paths below.
databasepgsqlTarget database adapter: pgsql, mysql, sqlite, oracle, mssql, sqlsrv. PostgreSQL is the default (Propel 1 defaulted to mysql).
targetPackage“ (empty)Default package for generated classes when a schema doesn’t set its own.
targetPlatform“ (empty)Codegen dialect selector, effectively vestigial. The legacy PHP5 builders were removed from the codebase entirely (archived under archaeology/php5-builders/), so there is no alternate builder set left to select — every builder.*.class key below is unconditionally the modern builder. --target-platform and the platform-suffixed builder.*.<platform>.class override mechanism still work in general, and .php84.class entries are kept as a redundant alias for anyone still passing targetPlatform=php84 explicitly.
runOnlyOnSchemaChangefalseSkip regeneration when the schema file’s mtime hasn’t changed.
packageObjectModelfalseWhether to join schemas sharing a database name into a single schema.
useDateTimeClasstrueWhether temporal getters return DateTime objects.
dateTimeClassDateTimeWhich DateTime-compatible class to instantiate for temporal columns.
schema.validatetrueValidate schema.xml against the bundled XSD before building.
schema.transformfalseRun the schema through the XSL transform file before building.
schema.autoPackagefalseCopy a table’s schema attribute to its package attribute.
schema.autoNamespacefalseCopy a table’s schema attribute to its namespace attribute.
schema.autoPrefixfalseUse a table’s schema attribute as a phpName prefix.
useLeftJoinsInDoJoinMethodstrueWhether generated doSelectJoin*()-style methods default to LEFT JOIN.
PropertyDefaultDescription
database.url“ (empty)Single build-time database DSN (fallback path — see Build-time database connections).
database.buildUrl${propulsion.database.url}DSN used specifically for build tasks.
database.createUrl${propulsion.database.buildUrl}DSN used when creating the database.
database.driver“ (empty)Overrides the PDO driver segment if it differs from database.
database.schema“ (empty)Default SQL schema/namespace for RDBMS that support it.
database.encoding“ (empty)Character encoding for DDL generation.
database.manualCreationfalseSkip automatic database creation.
database.user / database.password“ (empty)Fallback build-time credentials, used together with database.url when no buildtime-conf is configured.
PropertyDefaultDescription
samePhpNamefalseWhether reverse-engineered columns get a phpName identical to the column name.
addVendorInfofalseWhether reverse engineering emits <vendor> elements.
addValidatorsnoneValidator rules to emit when reverse-engineering.
PropertyDefaultDescription
addGenericAccessorstrueGenerate getByName()/getByPosition()/toArray().
addGenericMutatorstrueGenerate setByName()/setByPosition()/fromArray().
addSaveMethodtrueGenerate save().
addTimeStampfalseAdd a generation timestamp to the phpDoc header of generated classes.
addValidateMethodtrueGenerate validate()/getValidationFailures().
addIncludesfalseEmit require/include statements in generated code instead of relying on autoloading.
addHookstrueGenerate pre/post lifecycle hook call sites on save()/delete().
basePrefixBasePrefix for the abstract Base* classes.
saveExceptionPropulsionExceptionException class thrown by generated save()/delete() on failure.
emulateForeignKeyConstraintsfalseEmit application-level FK constraint checks instead of relying on the database.
disableIdentifierQuotingfalseDisable identifier quoting in generated DDL/SQL — can be necessary on PostgreSQL for certain identifier casing.
defaultTimeStampFormatY-m-d H:i:sDefault format string for TIMESTAMP columns’ getByName()-style access.
defaultTimeFormat%XDefault format string for TIME columns.
defaultDateFormat%xDefault format string for DATE columns.
namespace.omOMSub-namespace segment for generated OM classes (only used by certain packaging modes).
namespace.mapMapSub-namespace segment for generated *TableMap classes.
namespace.autoPackagetrueUse a table’s namespace attribute to derive its output subdirectory.
PropertyDefaultDescription
conf.dir${propulsion.project.dir}Directory searched for runtime/buildtime config files.
schema.dir${propulsion.project.dir}Directory searched for schema.xml files.
templatePath${propulsion.home}/templatesCode-generation template root.
output.dir${propulsion.project.dir}/buildRoot output directory (legacy Phing-style layout; the console’s --output-dir option is the modern equivalent for model:build).
php.dir${propulsion.output.dir}/classesGenerated PHP class output directory (legacy path — superseded by --output-dir).
phpconf.dir${propulsion.output.dir}/confGenerated runtime-config output directory.
sql.dir${propulsion.output.dir}/sqlGenerated DDL/SQL output directory.
migration.dir${propulsion.output.dir}/migrationsGenerated migration class output directory.
graph.dir${propulsion.output.dir}/graphgraph:build output directory.
dbd2propel.dir${propulsion.project.dir}/dbdDBDesigner4 import source directory.
PropertyDefaultDescription
runtime.conf.fileruntime-conf.xmlLegacy default filename some tooling still probes for — not what Propulsion::init() expects; pass your PHP runtime config file’s path explicitly (see Runtime configuration).
runtime.phpconf.file${propulsion.project}-conf.phpLegacy compiled runtime-config filename pattern.
runtime.phpconf-classmap.fileclassmap-${propulsion.runtime.phpconf.file}Legacy classmap companion file.
default.schema.basenameschemaBase filename schemas are matched against (*schema.xml).
schema.xsd.file${propulsion.home}/resources/xsd/database.xsdSchema-validation XSD path.
schema.xsl.file${propulsion.home}/resources/xsl/database.xslSchema-transform XSL path.
dbd2propel.xsl.file${propulsion.home}/resources/xsl/dbd2propel.xslDBDesigner4 import XSL path.
PropertyDefaultDescription
schema.sql.includes / schema.sql.excludes*schema.xml / “File matching for the SQL-build task.
schema.doc.includes / schema.doc.excludes*schema.xml / “File matching for documentation generation.
schema.create-db.includes / schema.create-db.excludes*schema.xml / “File matching for database creation.
schema.init-sql.includes / schema.init-sql.excludes*schema.xml / id-table-schema.xmlFile matching for initial-data SQL.
schema.om.includes / schema.om.excludes*schema.xml / id-table-schema.xmlFile matching for Object Model generation.
schema.datadtd.includes / schema.datadtd.excludes*schema.xml / id-table-schema.xmlFile matching for data-DTD generation.
dbd2propel.includes*.xmlFile matching for DBDesigner4 import.
datasql.mapper.from / datasql.mapper.to*.xml / *.sqlData-XML-to-SQL filename mapping.
datadump.mapper.from / datadump.mapper.to*schema.xml / *data.xmlSchema-to-data-dump filename mapping.
datadtd.mapper.from / datadtd.mapper.to*.xml / *.dtdData-to-DTD filename mapping.
sql.mapper.from / sql.mapper.to*.xml / *.sqlSchema-to-SQL filename mapping.
PropertyDefaultDescription
migration.editor“ (empty)Editor command invoked when opening a generated migration for review.
migration.tablepropulsion_migrationAppend-only ledger table Propulsion uses to record migration run attempts — see Migrations: How it works.
migration.caseInsensitivetrueWhether migration filename comparison ignores case.

Every builder.*.class key names the concrete class for a stage of code generation. All of them point at the modern PHP 8.4+ builders unconditionally — the PHP5-era builder classes (PHP5PeerBuilder, PHP5ObjectBuilder, PHP5TableMapBuilder, PHP5QueryBuilder, the PHP5 node/nestedset family) have been removed from the codebase entirely (archived under archaeology/php5-builders/). targetPlatform is effectively vestigial as a result — there’s no alternate builder set left to select via php5, though GeneratorConfig::getBuilderClassname() still honors a builder.*.php5.class-style override if you supply your own.

PropertyDefault
builder.peer.classPropulsion\Generator\Builder\OM\PeerBuilder
builder.object.classPropulsion\Generator\Builder\OM\ObjectBuilder
builder.objectstub.classPropulsion\Generator\Builder\OM\ExtensionObjectBuilder
builder.peerstub.classPropulsion\Generator\Builder\OM\ExtensionPeerBuilder
builder.objectmultiextend.classPropulsion\Generator\Builder\OM\MultiExtendObjectBuilder
builder.tablemap.classPropulsion\Generator\Builder\OM\TableMapBuilder
builder.query.classPropulsion\Generator\Builder\OM\QueryBuilder
builder.querystub.classPropulsion\Generator\Builder\OM\ExtensionQueryBuilder
builder.interface.classPropulsion\Generator\Builder\OM\InterfaceBuilder
builder.node.class / builder.nodepeer.classPropulsion\Generator\Builder\OM\NodeBuilder / NodePeerBuilder
builder.nodestub.class / builder.nodepeerstub.classPropulsion\Generator\Builder\OM\ExtensionNodeBuilder / ExtensionNodePeerBuilder

| builder.queryinheritance.class / builder.queryinheritancestub.class | Propulsion\Generator\Builder\OM\QueryInheritanceBuilder / ExtensionQueryInheritanceBuilder | | builder.pluralizer.class | Propulsion\Generator\Builder\Util\DefaultEnglishPluralizer | | builder.datasql.mysql.class | Propulsion\Generator\Builder\SQL\MySQL\MysqlDataSQLBuilder | | builder.datasql.pgsql.class | Propulsion\Generator\Builder\SQL\PgSQL\PgsqlDataSQLBuilder | | builder.datasql.sqlite.class | Propulsion\Generator\Builder\SQL\Sqlite\SqliteDataSQLBuilder | | builder.datasql.mssql.class | Propulsion\Generator\Builder\SQL\MSSQL\MssqlDataSQLBuilder | | builder.datasql.sqlsrv.class | Propulsion\Generator\Builder\SQL\Sqlsrv\SqlsrvDataSQLBuilder | | builder.datasql.oracle.class | Propulsion\Generator\Builder\SQL\Oracle\OracleDataSQLBuilder | | builder.datasql.class | ${propulsion.builder.datasql.${propulsion.database}.class} |

builder.*.php84.class variants of the OM builders above also exist, as an explicit alias for anyone who still passes --target-platform=php84 — they resolve to the exact same classes.

The four node/nodepeer keys drive treeMode="MaterializedPath" only. The nested_set behavior has no builder key of its own — it’s a behavior, so it modifies the ordinary object, peer and query builders rather than replacing them, and there’s nothing here to point elsewhere.

PropertyDefault
platform.mysql.classPropulsion\Generator\Platform\MysqlPlatform
platform.pgsql.classPropulsion\Generator\Platform\PgsqlPlatform
platform.sqlite.classPropulsion\Generator\Platform\SqlitePlatform
platform.oracle.classPropulsion\Generator\Platform\OraclePlatform
platform.mssql.classPropulsion\Generator\Platform\MssqlPlatform
platform.sqlsrv.classPropulsion\Generator\Platform\SqlsrvPlatform
platform.class${propulsion.platform.${propulsion.database}.class}

Reverse-engineering (schema parser) classes

Section titled “Reverse-engineering (schema parser) classes”
PropertyDefault
reverse.parser.mysql.classPropulsion\Generator\Reverse\MySQL\MysqlSchemaParser
reverse.parser.pgsql.classPropulsion\Generator\Reverse\PgSQL\PgsqlSchemaParser — requires PostgreSQL 15+ (uses pg_get_expr(adbin, adrelid), not the pre-12 pg_attrdef.adsrc text column).
reverse.parser.sqlite.classPropulsion\Generator\Reverse\SQLite\SqliteSchemaParser
reverse.parser.mssql.classPropulsion\Generator\Reverse\MSSQL\MssqlSchemaParser
reverse.parser.sqlsrv.classPropulsion\Generator\Reverse\Sqlsrv\SqlsrvSchemaParser
reverse.parser.oracle.classPropulsion\Generator\Reverse\Oracle\OracleSchemaParser
reverse.parser.class${propulsion.reverse.parser.${propulsion.database}.class}
PropertyDefaultDescription
mysql.tableTypeInnoDBDefault storage engine for generated CREATE TABLE statements. InnoDB has been MySQL’s own default since 5.5, and native delete triggers need its foreign-key support. Set it to MyISAM for the pre-2.0 behaviour.
mysql.tableEngineKeywordENGINEKeyword used to specify the engine (TYPE on MySQL < 5, not relevant to any currently supported MySQL version).
PropertyDefaultDescription
oracle.autoincrementSequencePattern${table}_SEQSequence naming pattern for autoincrement columns.
PropertyDefault
behavior.timestampable.classPropulsion\Generator\Behavior\TimestampableBehavior
behavior.alternative_coding_standards.classPropulsion\Generator\Behavior\AlternativeCodingStandardsBehavior
behavior.soft_delete.classPropulsion\Generator\Behavior\SoftDeleteBehavior
behavior.auto_add_pk.classPropulsion\Generator\Behavior\AutoAddPkBehavior
behavior.nested_set.classPropulsion\Generator\Behavior\NestedSet\NestedSetBehavior
behavior.sortable.classPropulsion\Generator\Behavior\Sortable\SortableBehavior
behavior.sluggable.classPropulsion\Generator\Behavior\Sluggable\SluggableBehavior
behavior.aggregate_column.classPropulsion\Generator\Behavior\AggregateColumn\AggregateColumnBehavior
behavior.versionable.classPropulsion\Generator\Behavior\Versionable\VersionableBehavior
behavior.optimistic_lock.classPropulsion\Generator\Behavior\OptimisticLock\OptimisticLockBehavior
behavior.i18n.classPropulsion\Generator\Behavior\I18n\I18nBehavior
behavior.delegate.classPropulsion\Generator\Behavior\DelegateBehavior
behavior.archivable.classPropulsion\Generator\Behavior\Archivable\ArchivableBehavior
PropertyDefault
om.BaseObjectPropulsion\OM\BaseObject
om.PersistentPropulsion\OM\Persistent
  • All propulsion.builder.*.php5.class default entries — the PHP5 builder classes they used to point at (PHP5PeerBuilder, PHP5ObjectBuilder, PHP5TableMapBuilder, PHP5QueryBuilder, PHP5NodeBuilder, PHP5NestedSetBuilder, and their extension/stub counterparts) are gone from the codebase. targetPlatform=php5 no longer has anything to fall back to; only supply builder.*.php5.class yourself if you’ve written a replacement.
  • propulsion.builder.nestedset.class and propulsion.builder.nestedsetpeer.class, along with the NestedSetBuilder/NestedSetPeerBuilder classes themselves. They served treeMode="NestedSet", removed in 3.0 in favour of the nested_set behavior. A configuration still setting either key has nothing to point at.
  • Propel 1’s default database (mysql) — see propulsion.database above; PostgreSQL is now the default.

What changed defaults relative to Propel 1

Section titled “What changed defaults relative to Propel 1”

Only propulsion.database (mysqlpgsql) changes default value versus Propel 1’s own default.properties. Every other Propel 1 default carries over unchanged, modulo the class renames.

Separate from the generator’s own build properties, some build-time tasks need a live database connection — reverse-engineering an existing schema (schema:reverse), diffing against a live database (sql:diff), or executing generated SQL (sql:exec). GeneratorConfig::getBuildConnections() resolves this, checked in order:

  1. propulsion.buildtimeConfigArray build property — a plain PHP array already in the target shape (see below). The recommended path for new configs.
  2. propulsion.buildtimeConfFile build property naming a .php file, which is required and expected to return the same shape as buildtimeConfigArray. It’s tried at a projectDir-relative path, the given path directly, and a couple of legacy build/propel/-style fallback locations. This is what --buildtime-conf on the migration and sql:diff commands sets.
  3. If neither of the above resolves a connection for the requested datasource name, falls back to the single connection assembled from propulsion.database.adapter/propulsion.database.url/.user/.password (see Database settings; database.adapter isn’t itself a documented default property).

The plain-PHP array shape:

buildtime-conf.php
<?php
return [
'default' => 'bookstore',
'datasources' => [
'bookstore' => [
'adapter' => 'pgsql',
'dsn' => 'pgsql:host=localhost;dbname=bookstore',
'user' => 'me',
'password' => 'secret',
],
],
];

This is the configuration your generated Object Model classes use to open a real database connection when your application runs — the Propulsion equivalent of what Propel 1 called runtime-conf.xml. It has nothing to do with the build-time properties or build-time connections above; it’s loaded separately, by your application, not by bin/propulsion.

Propel 1’s runtime-conf.xml is gone. Propulsion::init($path) (Propulsion\Propulsion::init()) calls Propulsion::configure($path), which does exactly one thing: include($path) and expects the file to return an array. That array is wrapped in a Propulsion\Config\PropulsionConfiguration (an ArrayAccess container supporting dotted-key lookups like $config->getParameter('datasources.bookstore.connection.dsn')) and stored for the rest of the process.

runtime-conf.php
<?php
return [
'datasources' => [
'default' => 'bookstore',
'bookstore' => [
'adapter' => 'pgsql',
'connection' => [
// optional; defaults to the adapter's own connection class
'classname' => 'Propulsion\Adapter\Pgsql\PgsqlPropulsionPDO',
'dsn' => 'pgsql:host=localhost;dbname=bookstore',
'user' => 'app',
'password' => 'secret',
'options' => [], // PDO constructor options
'attributes' => [], // set via PDO::setAttribute() after connecting
'settings' => [
'charset' => 'utf8',
'queries' => [], // SQL run once, immediately after connecting
],
],
// optional: read-replica connections for this datasource
'slaves' => [
'connection' => [
['dsn' => 'pgsql:host=replica-1;dbname=bookstore'],
['dsn' => 'pgsql:host=replica-2;dbname=bookstore'],
],
],
],
],
];
<?php
Propulsion::init(__DIR__ . '/runtime-conf.php');
$con = Propulsion::getConnection('bookstore'); // master, by default
$reader = Propulsion::getConnection('bookstore', Propulsion::CONNECTION_READ); // a slave, if configured
Key pathDescription
datasources.defaultName of the datasource Propulsion::getConnection() uses when called with no argument.
datasources.<name>.adapterDatabase adapter identifier (pgsql, mysql, sqlite, oracle, mssql, sqlsrv) — used to select the right DBAdapter subclass, independent from the PDO driver in dsn (e.g. an ODBC DSN targeting SQL Server would still set adapter: sqlsrv).
datasources.<name>.connection.classnameThe connection class to instantiate. Defaults to the adapter’s own (DBAdapter::getDefaultPdoClass()) — PgsqlPropulsionPDO for pgsql, MysqlPropulsionPDO for mysql, and so on, each extending the matching \Pdo\* class. A custom class must implement Propulsion\Connection\PropulsionPDO, which is an interface as of 2.0; the simplest way is to extend the driver-specific class you’re replacing, or to use PropulsionPDOTrait for the nested-transaction, logging, and statement-caching behaviour stock PDO doesn’t have. Naming the interface itself — or Propel 1’s PropelPDO, which a converted configuration carries — means “use Propulsion’s own PDO” and is substituted with the adapter’s default class rather than rejected.
datasources.<name>.connection.dsnThe PDO DSN. Same format PHP’s PDO drivers always expected — see the PHP manual for PostgreSQL, MySQL, SQLite, Oracle, SQL Server.
datasources.<name>.connection.user / .passwordCredentials, for adapters that don’t embed them in the DSN.
datasources.<name>.connection.optionsPDO constructor options array — passed to new PDO($dsn, $user, $password, $options). Keys may be integer constants or bare names: ATTR_PERSISTENT resolves against PropulsionPDO first (where PROPEL_ATTR_CACHE_PREPARES lives) and then PDO, so the spelling Propel 1’s convert-conf emitted keeps working. An unresolvable name throws, naming both prefixes it tried.
datasources.<name>.connection.attributesOptions applied via PDO::setAttribute() after the connection is created — same key space as options, different timing.
datasources.<name>.connection.settings.charsetCharacter set applied to the connection where the RDBMS supports it.
datasources.<name>.connection.settings.queriesArray of SQL statements executed once, immediately after connecting.
datasources.<name>.slaves.connectionEither a single connection array, or a list of them — one is picked at random per getConnection(..., Propulsion::CONNECTION_READ) call when there’s more than one.
cache.queryOptional. Configures the global (cross-process) query result cache — enabled, driver, ttl, namespace, plus admission, stampede, and per-driver option blocks. Fully documented in Query cache configuration.
connection.liveness / connection.retryOptional. The execution-strategy settings — pre-checkout liveness pings and transaction retry. Both off by default; see the connection section below.
telemetryOptional. Turns on OpenTelemetry span export for every statement — enabled, service_name, record_statement_text, plus exporter and sampler blocks. Off by default; see the telemetry section below.

Read a value at runtime with Propulsion::getConfiguration() or, for a single dotted key, PropulsionConfiguration::getParameter('datasources.bookstore.connection.dsn').

One of three optional top-level keys besides datasources (the others being connection and telemetry). It’s optional, and an absent cache key means the query result cache stays request-scoped, exactly as it is without any configuration:

return [
'datasources' => [ /* ... */ ],
'cache' => [
'query' => [
'enabled' => true,
'driver' => 'apcu',
'ttl' => 300,
],
],
];

Unlike datasources, this section is strictly validated: an unknown key or a wrong value type throws a PropulsionException at parse time rather than being silently ignored, so a 'tll' => 300 typo fails at boot instead of quietly running on defaults. See Query cache configuration for every key, the shipped drivers, and how to register your own PSR-16 pool.

Optional, and absent means both features are off — which is the default because each spends something real: a round trip per idle checkout, or running the caller’s closure more than once.

return [
'datasources' => [ /* ... */ ],
'connection' => [
'liveness' => [
'enabled' => true,
'idle_threshold' => 5.0,
],
'retry' => [
'enabled' => true,
'max_attempts' => 3,
],
],
];
KeyDefaultEffect
connection.liveness.enabledfalsePing a pooled connection before handing it out, replacing it if the ping fails.
connection.liveness.idle_threshold5.0Seconds a connection must have sat unused before a checkout is worth a SELECT 1. 0.0 pings every checkout; a negative value is rejected.
connection.retry.enabledfalseRetry a Propulsion::transaction() whose failure the adapter classifies as transient.
connection.retry.max_attempts3Total attempts, not retries.
connection.retry.base_delay50Milliseconds before the first retry.
connection.retry.max_delay1000Millisecond ceiling on the computed delay.
connection.retry.multiplier2.0Per-attempt backoff growth factor.
connection.retry.jitter1.01.0 is full jitter, 0.0 none.

Like cache, this section is strictly validated: an unknown key or a wrong value type throws a PropulsionException at parse time rather than being silently ignored. What each setting buys, what is and isn’t retried, and the requirement that a retried closure be safe to run twice are all on Connection resilience.

Optional, and absent means off — under which Propulsion never references an open-telemetry/* class at all, so those packages don’t need to be installed. Turning it on gives every statement an exported OpenTelemetry span, with no application code:

return [
'datasources' => [ /* ... */ ],
'telemetry' => [
'enabled' => true,
'service_name' => 'bookstore-api',
'exporter' => [
'endpoint' => 'http://otel-collector:4318/v1/traces',
'protocol' => 'http/protobuf',
'headers' => ['authorization' => 'Bearer ' . getenv('OTLP_TOKEN')],
'timeout' => 10,
],
'sampler' => ['ratio' => 0.05],
'record_statement_text' => true,
],
];
KeyDefaultEffect
telemetry.enabledfalseMaster gate.
telemetry.service_name'propulsion'The service.name resource attribute.
telemetry.exporter.endpointOTLP/HTTP traces endpoint, path included. Required when enabled is true, and validated as a URL.
telemetry.exporter.protocol'http/protobuf'http/protobuf or http/json; anything else is rejected.
telemetry.exporter.headers[]Extra HTTP headers on every export request. A map of string to string.
telemetry.exporter.timeout10Export request timeout in seconds; at least 1.
telemetry.sampler.ratio1.0TraceIdRatioBased fraction, 0.01.0 inclusive.
telemetry.record_statement_texttrueWhether db.query.text is attached to spans.

Like cache and connection, this section is strictly validated: an unknown key or a wrong value type throws a PropulsionException at parse time, so an 'enpoint' => ... typo fails at boot rather than leaving the feature looking on while shipping nothing. The packages to install, sampling, the PII trade-off on record_statement_text, worker-mode flushing and how to supply your own tracer provider are all on OpenTelemetry tracing.

Propel 1 (runtime-conf.xml)Propulsion (runtime array)
<datasources default="bookstore">'datasources' => ['default' => 'bookstore', ...]
<datasource id="bookstore"><adapter>mysql</adapter>'datasources' => ['bookstore' => ['adapter' => 'pgsql', ...]]
<connection><dsn>...</dsn><user>...</user><password>...</password></connection>'connection' => ['dsn' => ..., 'user' => ..., 'password' => ...]
<connection><classname>Propel\Runtime\Connection\ConnectionWrapper</classname></connection>'connection' => ['classname' => 'Propulsion\Connection\PropulsionPDO']
<connection><options>...</options></connection>'connection' => ['options' => [...]]
<connection><attributes>...</attributes></connection>'connection' => ['attributes' => [...]]
<connection><settings><charset>utf8</charset><queries>...</queries></settings></connection>'connection' => ['settings' => ['charset' => 'utf8', 'queries' => [...]]]
<slaves><connection>...</connection>...</slaves>'slaves' => ['connection' => [...]]
Propel::init('/path/to/runtime-conf.php') (compiled from XML)Propulsion::init('/path/to/runtime-conf.php') (hand-written PHP array, no compile step)

Since the runtime file is plain PHP, there’s no separate “compile the XML into PHP” build step the way Propel 1’s propel-gen produced a *-conf.php alongside runtime-conf.xml — you write the array directly, or generate it yourself from whatever source you like (environment variables, a secrets manager, etc.).

Propel 1’s runtime config carried Zend/sfLogger-flavored <log>/<logger> sections. Propulsion doesn’t read logging configuration from the runtime array at all — it logs through PSR-3 instead, and you register your own logger programmatically:

<?php
Propulsion::init(__DIR__ . '/runtime-conf.php');
Propulsion::setLogger($myPsr3Logger); // e.g. a Monolog\Logger instance

Without a registered logger, Propulsion::log() is a no-op — there’s no implicit error_log() fallback. See Logging for the full setup, including per-connection overrides.

If you’re using Propulsion through Quiote’s database adapter rather than standalone, you don’t call Propulsion::init() yourself — point the propulsion database’s config parameter at this same file, and PropulsionDatabase calls it for you:

Config/databases.php
return [
'databases' => [
'main' => [
'class' => 'propulsion',
'parameters' => [
'config' => __DIR__ . '/runtime-conf.php',
'datasource' => 'bookstore',
],
],
],
];

That databases config is Quiote’s, not Propulsion’s, so it can equally be written as Config/databases.yaml or Config/databases.xml — see Databases. Only the config parameter’s target, the Propulsion runtime file above, is PHP by nature.

See Databases: Propulsion for the full parameter list.