Architecture
This document explains the architecture and design principles behind Derafu ETL.
ETL Pattern
The Extract-Transform-Load (ETL) pattern is a data integration process used to collect data from various sources, transform it to fit operational needs, and load it into a target database for analysis and storage.
The Three Phases
- Extract: Gathering data from source systems.
- Transform: Converting the extracted data to satisfy operational requirements.
- Load: Writing the transformed data to the target system.
Derafu ETL Implementation
Derafu ETL implements this pattern with a clean, object-oriented approach centered around the Pipeline concept.
Core Components
Extract Phase
DataSource: Encapsulates the data source (spreadsheet, database).DataExtractor: Handles extraction logic.SchemaSource: Extracts schema information from the source.
Transform Phase
DataRules: Defines transformation rules.DataTransformer: Applies transformations to extracted data.
Load Phase
DataTarget: Represents the destination system.DataLoader: Manages loading data into the target.SchemaTarget: Applies schema to the target system.
Pipeline Orchestration
The Pipeline class orchestrates the entire ETL process, providing a fluent interface:
$pipeline
->extract($source) // Configure extraction.
->transform($rules) // Configure transformation.
->load($target) // Configure loading.
->execute() // Run the pipeline.
;
When execute() is called, the pipeline:
- Validates the configuration.
- Extracts data from the source.
- Transforms the data according to rules.
- Synchronizes the target schema with the source.
- Loads the transformed data into the target.
- Returns a result object with statistics.
Dependency Injection
Import the package configuration to use the shared ETL and Spreadsheet services:
imports:
- { resource: '../vendor/derafu/etl/resources/config/etl-services.yaml' }
Inject Derafu\ETL\Pipeline\Contract\PipelineInterface into the consuming
service. The YAML also registers DatabaseManagerInterface,
DataExtractorInterface, DataTransformerInterface and DataLoaderInterface
under their respective contracts. Extractor and loader use the same database
manager, which passes Spreadsheet’s shared factory, caster, loader and dumper
to the runtime database adapters. Spreadsheet configuration and caster overrides
therefore apply to those operations too.
Each request for PipelineInterface creates a separate pipeline, because its
source, target and rules belong to one configured transfer. A service holding a
pipeline keeps that instance; request another pipeline when independent
configuration is needed.
The YAML registers Derafu\ETL\Command\PipelineCommand with the configured
pipeline. The consuming application registers the command with its console.
Database connections, schemas, data sources, targets and transformation rules
remain runtime values.
Opening an ETL spreadsheet file preserves business-cell values. The shared
caster decodes the __schema metadata there; dump loading and spreadsheet
exports use their existing Spreadsheet loader and dumper casting boundaries.
Atomic Loads
The built-in database adapters group schema synchronization and the loading of all tables into one operation. A failure while loading a later table also discards earlier changes, within the backend limitations described below. Extraction and transformation run before this operation; external side effects performed by custom rules are outside its scope.
- SQLite and PostgreSQL: ordinary table schema changes and row loads share one database transaction. If the caller already opened a transaction, the pipeline uses nested transactions/savepoints and does not commit the caller’s transaction.
- Spreadsheets: changes are prepared in a separate document. Success makes
that document the database’s current connection; failure preserves the original
document. References previously obtained through
spreadsheet()still point to the original document. File persistence throughsave()is a separate operation and is not included in this guarantee. - MySQL: row rollback requires transactional tables, such as InnoDB. When
schema synchronization requires structural changes, full atomicity cannot be
guaranteed because DDL causes implicit commits. The pipeline remains usable
but cannot restore the previous schema and all data after an error. This also
affects transactions opened by the caller. With
syncdisabled, or when the schema already matches, the pipeline wraps row loading in one transaction.
The MySQL limitation follows the server’s implicit commit behavior; a transaction around schema changes does not make those changes reversible.
Custom database adapters opt in by implementing
TransactionalDatabaseInterface. Its transactional() method receives the
complete synchronization/load operation and, when synchronization is enabled,
the source database. Existing adapters that implement only DatabaseInterface
continue to work, but the pipeline does not provide an atomicity guarantee for
them. Custom loaders and targets must perform writes through the database they
expose; unrelated connections or external side effects are outside its scope.
Key Abstractions
Database
The Database abstraction provides a unified interface for different database types:
SpreadsheetDatabase: Treats spreadsheets as databases using Derafu Spreadsheet.DoctrineDatabase: Works with any database supported by Doctrine DBAL.
Schema
The Schema system represents database structure:
- Tables, columns, indexes, foreign keys.
- Import/export to various formats (Spreadsheet, Doctrine, Markdown, D2, etc.).
- The model is independent from Doctrine DBAL: see Schema Model, including the
IndexTypeof an index.
Extension Points
Derafu ETL is designed for extensibility:
- New Data Sources: Implement
DataSourceInterface. - Custom Transformations: Extend
DataRules. - New Data Targets: Implement
DataTargetInterface. - Schema Visualization: Implement
SchemaTargetInterface.
Design Principles
- Separation of Concerns: Each component has a clear responsibility.
- Fluent Interface: Expressive, chainable API.
- Flexibility: Support for various formats and systems.
- Extensibility: Easy to extend with custom components.