PHP Data Access Libraries (ORM, ActiveRecord, Persistence)

2017-12-21 16:47:00
For description on the comparison criteria, please read full article here:
DoctrineAgile DataEloquentYii ORMCake ORMFuel ORMRed Bean PHPTingSpiral ORM..
DescriptionData Access Framework for high-latency databases (Cloud SQL/NoSQL).RedBeanPHP is an easy to use ORM for PHP. It's a Zero Config ORM lib that 'automagically' builds your database schema.Simple: no magic inside : it’s basically SQL queriesORM engine with automatic database scaffolding, strict schemas, code discovery, modular database partitions and various relation loaders.
Github / Bitbucket / Sourceforge
LicenseMITMITBSD-3New BSD / GPLApache 2MIT
Latest version2.5.51.2.x2.
How schema is defined?PHP, XML, YAMLin PHP. Method init() in Model class defines fields, relations, conditions, etc.Model class propertiesActive record magic properties.Automatically discovered on the fly.PHPPHP Const array. Column class.
Code generationYes schema-toolYes Web and console generator
Can be used in Any FrameworkYes composer / packagistYes Through composer/packagistYes Through Capsule- Planned in 2.1.xYesYes composer / packagist
Automated CacheYes Frameworks focuses on optimizing queries rather then caching. Still possible with cross-persistence saving.YesYes
Anti-patterns (purposely included)Model close-coupled with Persistence and Field classes.Eloquent is a God Class; Global functions; DB Conection is global;
DependenciesMedium: ±5 packages.Minimal: 2 packages: DSQL Query Builder ( 3, pimple, doctrine/cache, aura/sqlquery
Simplicity0 no rating5.0 2 ratings0 no rating5.0 2 ratings0 no rating0 no rating0 no rating5.0 1 rating0 no rating0 no rating
Enterprise Compliance5.0 1 rating5.0 2 ratings3.0 1 rating4.5 2 ratings0 no rating0 no rating0 no rating5.0 1 rating0 no rating0 no rating
Minimum PHP Version5.
Basic Features
PDO SupportYes YesYes YesYesYes- But made a custom driver to support it is easyYes
Transparent support for NoSQL- Through 3rd party drivers.No Eloquent is built on Query Builder. Perhaps moloquent? Also - Through Caching backend, but not as ORM native persistence.Yes Avialable cross sql and nosql datababase relations ( Build around plain queries.NoNo No, through ODM (
How to invoke db-vendor-specific extensions?Yes DBALYes For SQL - save/load/delete operations are expressed in DSQL Queries that can be manipulated: Through Query Builder / RAW queries.Yes SQL - Query Builder.- Can add SQL code chunks.Yes Ting use native query, you can use everyting of your SGBDYes Query models:
Array as a persistenceYes CRUD operations supportedYes
RestAPI as a persistence- Through 3rd party extension.- To extend BaseActiveRecordNoNo
JSON string as a persistenceYes Supported with few extra lines of code.- To extend BaseActiveRecordNoNo
Same model, multiple persistencesYes Same class. Different object.- (no docs)
Basic Single-record operations (C,R,U,D)
Table Name MappingYes YesYes YesYes Same as model class name by defaultYes Using static method of active record. mapping no longer supported.Yes Yes
Field Name MappingYes Yes, (Annotations in PHP)Yes Yes (Field::actual property)- Through accessors/3rd party extensionYesNo mapping no longer supported.Yes Yes
Map Entity to SubQueryNo Must be physical tableYes Yes. Extension exist for UNION-models. Must be physical table.- table = new Expression(..)NoNo This concept is no-sense for Ting
Map property to expressionNo Must be physical fieldYes $model->addExpression()No Must be physical table- (couldn't find docs)NoNo This concept is no-sense for Ting
Map native types (DateTime)Yes $field->type = 'date'Yes Accessors and MutatorsYes Active record behaviorsYesYes Yes- No support for DateTime.
User-defined types (e.g. "23 USD")Yes Type classYes Yes. Independent from Model. by extending Field class.Yes Accessors and MutatorsYes Active record behaviorsYes Yes, with custom serializer
Map field of related Entity ('currency' = currency_id->Model Specific record onlyYes Transparently maps into sub-select.- Relationship, but only single record.Yes $model->currency->nameNoYes Yes
Map field to sub-query on related entity (Client.balance = Client->orders->sum(total))NoYes Yes. hasMany()->addField(..aggregate)No- (couldn't find docs)No- This concept is no-sense for Ting
Entity to join multiple tables (adding new record populates both tables)Yes AssociationsYes $model->join('other_table')NoNo No native support.NoYes Yes
Criteria, Scope, Conditions (Model will refuse to work with records that does not match criteria)
Support model-level criteriaYes Yes. Applied on loading / saving / update.- Global Scope (querying only)NoNo
Soft-deleteYes ExtensionYes Through criteria. Example given in the docs.Yes Trait and ScopeYes Events and behaviorsNo
Domain Model CriteriaYes $m->addCondition('gender','M'); where 'gender' can be arbitrary expression, sub-select, field from association(join) or mapped no another physical field.- Scopes, but not in domain model.No Only for specific query: User::find()->byEmail('...')->active()->one()No
Expression-based conditionYes $m->addCondition($m->expr('..'));Yes through Query BuilderNo Only for query: User::find()->andWhere('...')->all()No
Criteria Compliance (new record must match condition)Yes Transaction rollback and exception. Automated-rloading.NoNo
Dynamic criteriaYes $user->addCondition('is_expired', false)No Only Querying: User::find()->where(['a' => '1', 'b' => true])->all();No
Query Building (Convert Model into Query object for further SQL tweaking)
Convert Model into Query ObjectYes $q = $model->action('select');Yes Model is a Query object. See: Model::where()Yes \yii\db\ActiveRecord::find()NoYes RecordSelector
Raw expressionYes new Expression('any sql')Yes DB::raw()Yes new \yii\db\Expression('...')YesYes
Nested/Composite Queries/ExpressionsYes Expression can be in any part of queryNoYes Expression can be in any part of queryNo
Reference domain-model field in queryYes through Expressionable interfaceNo No fields. Only properties.No Field is class property.NoNo
field, where, order, limitYes Expressions and Parametric valuesYesYes \yii\db\ActiveQueryNoYes
options, rollup, partition- Through custom templates, or expressions.- not sure.
UPDATE, DELETE, INSERT query buildingYesYesNoYes
REPLACE, TRUNCATEYes- Throught raw sql in \yii\db\Command- wipe(),
SHOW, DESCRIBE, CALL- Supported through Expressions or Custom query template- Throught raw sql in \yii\db\Command- Automatic schema alter / discovery.
ALTER, CREATE query buildingYes Addon:
User-defined query templateYes Templates for all queriesYes (please link doc)No
full support for OR conditionsYes Through Object Composition and Expressions- Partial-No only raw query
Use Domain logic in multi-record update- Supported, but must map fields/values manually.NoNoNo
Data Fetching (different ways to retrieve data from database)
Get All Data (2x array)YesYesYes \yii\db\Query::all()Yes exportAll()Yes
Associative Array (id=>value)No PlannedYes lists()
Select only required fieldsYes
Typecasting (e.g. DateTime)YesYes
Import (multiple records)YesYes
Respect domain model mapping (and criteria)Yes
Single rowYes loadAnyYesYes \yii\db\Query::one()Yes
Single ValueYes Through actionYesYes \yii\db\Query::scalar()Yes
Single Column- may need to map resulting arrayYesYes \yii\db\Query::column()YesYes
Bypass persistence mappingYes action('select')->getAll()Yes ?? (e..g prevent date from being transformed into Carbon)
Loading and Saving individual records
Load by IDYes load(id)Yes User::findOne(1)YesYes get(id)Yes findByPK
Load by other fieldYes loadBy('field', $value)Yes User::findOne(['id' => 1])NoYes getBy(['propertyName' => 'value']);
Read-only ModelsYes YesNo
Model without primary keyYes Yes, but only in Read-only ModeNoYes
Specify fields to loadYes onlyFields()No Fields load with SELECT *Yes User::find()->select([])->one()NoYes
Save only sends dirty fieldsYesYesYes- (there is Dirty support, so I assuming it is supported)YesYes
Guarded / Fillable propertiesYes Conditions and OnlyFields do same thing but more reliably.Yes Prevents "create($_GET)" from messing up important fields.
Object Hierarchy Model
Admin extends User, adds criteria (is_admin=1)Yes Yes, recommended pattern. "User" class adds condition.NoNo Can be done as wrapper: User::findAdmin(..) or custom CDbCriteriaNo
Admin extends User, adds accessible fieldsYes Yes, recommended pattern.NoNoNo
Extend model, add Join (Disjoined SubTypes)Yes Yes. Unlimited number of joins.NoNoNo
Extend model change tableYes Yes. Used to tweak 3rd party models.No
Relations/References (One model can relate to another model. NOT A TABLE JOIN)
Model can define relation to other ModelYes References are implemented as ObjectsYes RelationsYes RelationsYes
One-to-ManyYes $user->hasMany('Orders', new Order());YesYes
One-to-many traversal strategyReturns destination model instance with dynamically applied criteria (parent_id=123). No queries are executed. Inserting record into this model will ensure association with parent model.Returns array of objects that may either be pre-loaded with record data or only contain IDs (lazy-loaded).Uses classical eager/lazy loading approach. with() can help pre-fetch the data for related entities.pre-fetch and store objects in an array.
Lazy/Eager-loadingNo Anti-patternYesYesYes
One-to-OneYes $order->hasOne('user_id', new User());YesYes
Many-to-ManyYes $user->addCondition('vip', true)->ref('Orders');Yes relations() method of an entity can define.
Deep Many-to-Many traversal.NoYes $user->ref('Orders')->ref('Payments')->action('count'); No intermediate queries.- only with "to-one" references: $book->author->address->street; Executes multiple queries.- only with to-one references. Executes multiple queries.
Cross-Persistence traversalYes $user->hasMany('Log', new Log($mongodb));- No docs.No
Cross-persistence joins, aggregation, reporting
Multi-persistence joinNoNoNoNo
UNION existing modelsNoYes Yes, in add-on Can join UNION result with more tables.NoNo
Domain-model AggregationYes Group by multiple fields. Apply aggregation functions. Preserve types.No
Model to Model joinNo Planned.No
Multi-persistence UNIONNoNoNoNo
Behaviours / Hooks
Before/After operationYesYes
Override standard C,R,U,D operationsYesYes
Persistence-specific hooks (to modify Query)Yes- (no docs)
User-defined hooksYesYes
Global AuditingYes
Store old/new field valuesYes Yes in JSON and user-readable string.Yes
Revert action (undo) and replay (redo)YesNoNo
Reactive actionsYes Each action will be automatically linked with sub-actions which may be invoked through Hooks.
Store log in any persistenceYesNo
Override, Add fields to audit logRecord dirty fields before persisting. Type-cast into JSON string and store in a single field of AuditLog Model. This model can be persisted anywhere, table, file, etc.
Custom eventsYesYes
Access to record-specific historyYes $item->ref('AuditLog');- Through a custom query.
Date of creation, modification- No but easy to add through hook.Yes \yii\behaviors\TimestampBehaviorYes TimestampTrait
User/IP creation, modification- Easy to add through a hook.Yes \yii\behaviors\BlameableBehavior
Store incremental revisions- Easy to add through a hookYes
Field meta-information providedType, caption, possible values, mapped field, join table spec, encryption, serialization, UI-specific settings, validation rules.
UI extensionsNoYes CRUD, Form, Table, Grid, Entity-manager. (see
API extensionsYes RestFULL API, automated CRUD operations + RPC
Like 0 2 0 0 0 0 0 0 0 0
  • 2016-10-18 22:08:00
    2017-12-21 16:47:00
  • Products
  • Compare Doctrine vs Agile Data vs Eloquent vs Yii ORM vs Cake ORM vs Fuel ORM vs x vs x
  • Public
  • Creative Commons License CC-BY-SA 3.0 / GNU FDL
    Manage backups


Leave a comment

Build comparison tables or lists about everything !

It's free and fast to publish data into original tables

Create a table