9.8 KiB
name, description
| name | description |
|---|---|
| oro-dba | OroCommerce database administration reference covering PostgreSQL configuration, Doctrine ORM mapping, migrations, entity extensions, schema management, indexing, performance optimization, and data management. Use when working with database schema, writing migrations, optimizing queries, configuring PostgreSQL, or troubleshooting database issues in OroCommerce. |
OroCommerce DBA
Database administration and schema reference for OroCommerce. Docs: https://doc.oroinc.com/backend/entities/
Database Requirements
- PostgreSQL >= 16.1 (only supported RDBMS)
uuid-osspextension required:CREATE EXTENSION "uuid-ossp";- Doctrine ORM with Oro Doctrine Extensions for PG-specific functions
Doctrine ORM in Oro
Oro uses standard Doctrine ORM with PHP 8 attributes:
#[ORM\Entity]
#[ORM\Table(name: 'acme_example')]
#[ORM\Index(columns: ['status'], name: 'idx_acme_example_status')]
#[ORM\UniqueConstraint(columns: ['external_id'], name: 'uniq_acme_ext_id')]
class Example { }
Oro-specific: #[Config] attribute adds entity config metadata (ACL, ownership,
audit, extend support). This is processed by EntityConfigBundle.
Migration System
Oro uses its own migration system (not Doctrine Migrations).
Migration Interface
use Oro\Bundle\MigrationBundle\Migration\Migration;
class AddStatusColumn implements Migration
{
public function up(Schema $schema, QueryBag $queries): void
{
$table = $schema->getTable('acme_example');
$table->addColumn('status', 'string', ['length' => 32, 'default' => 'new']);
$table->addIndex(['status'], 'idx_acme_example_status');
}
}
Installation Interface (Initial Schema)
use Oro\Bundle\MigrationBundle\Migration\Installation;
class AcmeExampleInstaller implements Installation
{
public function getMigrationVersion(): string { return 'v1_0'; }
public function up(Schema $schema, QueryBag $queries): void
{
$table = $schema->createTable('acme_example');
$table->addColumn('id', 'integer', ['autoincrement' => true]);
// ... all columns
$table->setPrimaryKey(['id']);
}
}
Data Migrations
Use QueryBag for INSERT/UPDATE/DELETE:
public function up(Schema $schema, QueryBag $queries): void
{
$queries->addQuery("INSERT INTO oro_enum_value ...");
$queries->addPreQuery("UPDATE ..."); // runs before schema changes
$queries->addPostQuery("UPDATE ..."); // runs after schema changes
}
Migration Commands
php bin/console oro:migration:load # run pending migrations
php bin/console oro:migration:dump # generate diff migration
php bin/console oro:entity-extend:update-schema # update extended entity schema
php bin/console oro:entity-extend:update-schema --dry-run
Migration File Location
Migrations/Schema/
v1_0/CreateExampleTable.php
v1_1/AddStatusColumn.php
v1_2/AddForeignKeys.php
Version directories must sort lexicographically (v1_0 < v1_1 < v1_10).
Multiple migration files per version directory are allowed and common:
Migrations/Schema/
v1_13/
AddNewFields.php
RemoveObsoleteFields.php
UpdateFieldLabels.php
Extending Oro Base Entities
Custom entities can extend Oro base entity classes (e.g., Transport for shipping/payment integrations):
#[ORM\Entity]
class FreightShippingSettings extends Transport
{
#[ORM\ManyToMany(targetEntity: LocalizedFallbackValue::class, cascade: ['ALL'], orphanRemoval: true)]
#[ORM\JoinTable(name: 'acme_freight_transport_label')]
#[ORM\JoinColumn(name: 'transport_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
#[ORM\InverseJoinColumn(name: 'localized_value_id', referencedColumnName: 'id', onDelete: 'CASCADE', unique: true)]
private Collection $labels;
}
Doctrine Mapping Configuration
For app-level entities outside bundles, configure in config/doctrine.yml:
doctrine:
orm:
mappings:
App:
is_bundle: false
type: attribute
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
Bundle entities are auto-discovered -- no explicit mapping needed.
Entity Extension Schema
Extended fields use oro_options in column definitions:
$table->addColumn('custom_field', 'string', [
'oro_options' => [
'extend' => [
'is_extend' => true,
'owner' => ExtendScope::OWNER_CUSTOM, // or OWNER_SYSTEM
'nullable' => true,
],
'entity' => ['label' => 'Custom Field'],
'datagrid' => ['is_visible' => DatagridScope::IS_VISIBLE_TRUE],
]
]);
Adding Enum Fields via ExtendExtension
For select/multiselect fields on Oro core entities, use addEnumField:
use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtension;
use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtensionAwareInterface;
class AddFrequencyEnum implements Migration, ExtendExtensionAwareInterface
{
protected ExtendExtension $extendExtension;
public function setExtendExtension(ExtendExtension $extendExtension): void
{
$this->extendExtension = $extendExtension;
}
public function up(Schema $schema, QueryBag $queries): void
{
$this->extendExtension->addEnumField(
$schema,
$schema->getTable('oro_product'),
'frequency', // field name
'acme_product_frequency', // enum code (must be unique)
false, // is_multiple (false = select, true = multiselect)
false, // is_public
[
'extend' => ['owner' => ExtendScope::OWNER_CUSTOM],
'entity' => ['label' => 'Frequency']
]
);
}
}
Populate enum values via data migration:
use Oro\Bundle\EntityExtendBundle\Migration\Fixture\AbstractEnumFixture;
class LoadFrequencyEnumValues extends AbstractEnumFixture
{
protected function getData(): array
{
return [
'50hz' => false, // value => is_default
'60hz' => true,
'variable' => false,
];
}
protected function getEnumCode(): string
{
return 'acme_product_frequency';
}
}
Datagrid Visibility in oro_options
| Value | Effect |
|---|---|
DatagridScope::IS_VISIBLE_TRUE |
Shown by default |
DatagridScope::IS_VISIBLE_HIDDEN |
Available but hidden by default |
DatagridScope::IS_VISIBLE_FALSE |
Not available in datagrid |
Extended entity schema is managed separately:
- Proxy classes generated in cache
oro:entity-extend:update-schemaapplies extend changesoro:entity-extend:cache:clearrebuilds proxies
Table Naming Conventions
| Scope | Pattern | Example |
|---|---|---|
| Custom entities | acme_{bundle}_{entity} |
acme_cpn_customer_part_number |
| Oro core | oro_{entity} |
oro_order |
| Extend fields | auto-generated columns on existing table | custom_field on oro_order |
| Enum tables | oro_enum_{code} |
oro_enum_order_status |
Indexing Guidance
When to Add Indexes
- Columns used in WHERE clauses
- Foreign key columns
- Columns used in ORDER BY
- Columns used in datagrid filters/sorters
Oro Datagrid Query Patterns
Datagrids generate ORM queries. The data_name in sorters and filters
maps directly to query aliases. Ensure underlying columns are indexed.
Composite Indexes
$table->addIndex(['organization_id', 'status'], 'idx_org_status');
Key Oro Tables
| Table | Purpose |
|---|---|
oro_user |
Admin/back-office users |
oro_customer |
Commerce customers (organizations) |
oro_customer_user |
Commerce storefront users |
oro_order |
Orders |
oro_product |
Products |
oro_category |
Product categories |
oro_shopping_list |
Shopping lists |
oro_checkout |
Checkout sessions |
oro_price_list |
Price lists |
oro_workflow_item |
Workflow state |
oro_message_queue |
DBAL message queue |
oro_entity_config |
Entity configuration metadata |
oro_migration |
Migration version tracking |
Performance Considerations
PostgreSQL Tuning
shared_buffers: 25% of RAMeffective_cache_size: 75% of RAMwork_mem: 4-16MB (depends on concurrent queries)maintenance_work_mem: 256MB-1GB for migrations/vacuumrandom_page_cost: 1.1 for SSD- Enable
pg_stat_statementsfor query monitoring
Oro-Specific Performance
- Extend entity cache warmup is CPU-intensive; run during deployment
- Migration load can be slow on large schemas; use maintenance windows
- DBAL MQ polls every 1s by default; tune
polling_intervalor use RabbitMQ - Elasticsearch offloads search from PostgreSQL (EE)
- Redis caching reduces DB query load
Doctrine Query Hints
Oro uses Doctrine query hints for:
HINT_PRECISE_ORDER_BY-- deterministic ordering- Custom walker hints for ACL filtering
- Translation hints for localized queries
Backup and Recovery
Standard PostgreSQL tools apply:
pg_dump -Fc dbname > backup.dump # custom format backup
pg_restore -d dbname backup.dump # restore
pg_dump --schema-only dbname > schema.sql # schema only
Always back up before oro:migration:load or oro:entity-extend:update-schema.
Data Fixtures
Seed data in Migrations/Data/ORM/, demo data in Migrations/Data/Demo/ORM/.
Fixtures implement FixtureInterface. Use OrderedFixtureInterface for ordering.
Load: php bin/console oro:migration:data:load (--fixtures-type=demo for demo).
Preview: --dry-run. Scope: --bundles=BundleName.
Data Audit Tables
When dataaudit is enabled, changes tracked in oro_audit and oro_audit_field.
Each entry stores: entity class, entity ID, action, user, timestamp, version.
Segment filters can query audit data for historical analysis.