Add BMAD commands, skills, and module files from piSetup
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
---
|
||||
name: oro-dba
|
||||
description: 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-ossp` extension 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:
|
||||
|
||||
```php
|
||||
#[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
|
||||
|
||||
```php
|
||||
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)
|
||||
|
||||
```php
|
||||
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:
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```bash
|
||||
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):
|
||||
|
||||
```php
|
||||
#[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`:
|
||||
|
||||
```yaml
|
||||
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:
|
||||
|
||||
```php
|
||||
$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`:
|
||||
|
||||
```php
|
||||
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:
|
||||
|
||||
```php
|
||||
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-schema` applies extend changes
|
||||
- `oro:entity-extend:cache:clear` rebuilds 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
|
||||
```php
|
||||
$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 RAM
|
||||
- `effective_cache_size`: 75% of RAM
|
||||
- `work_mem`: 4-16MB (depends on concurrent queries)
|
||||
- `maintenance_work_mem`: 256MB-1GB for migrations/vacuum
|
||||
- `random_page_cost`: 1.1 for SSD
|
||||
- Enable `pg_stat_statements` for 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_interval` or 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:
|
||||
```bash
|
||||
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.
|
||||
Reference in New Issue
Block a user