PHP Data Access Libraries (ORM, ActiveRecord, Persistence)

2016-10-26 15:42:23
I have been looking for in-depths comparison between various libraries that simplify operations with data in PHP. Compare Doctrine vs Agile Data vs Eloquent vs Yii ORM vs Cake ORM vs Fuel ORM. For more information on comparison criteria, see: and
DoctrineAgile DataEloquentYii ORMCake ORMFuel ORMRed Bean PHPx
Site webhttp://www.doctrine-project.org
DescriptionPHP Framework for better Business Logic design and scalable database accessRedBeanPHP is an easy to use ORM for PHP. It's a Zero Config ORM lib that 'automagically' builds your database schema.
Github / Bitbucket / Sourceforge
Dernière version2.5.51.1.x2.
How schema is defined?PHP, XML, YAMLmethod init() in Model class defines fields, relations, conditions, etc.Model class propertiesActive record magic properties.Automatically discovered on the fly.
Code generationOui schema-tool- Planned.Oui Web and console generator
Can be used in Any FrameworkOui composer / packagistOui Through composer/packagistOui Through Capsule- Planned in 2.1.xOui
Automated Cache- PlannedOuiOui
Anti-patterns (purposely included)ORM.SRP in Model. Implements Scopes and Active Record.Eloquent is a God Class; Global functions; DB Conection is global;
DependenciesMedium: ±5 packages.Minimal: 2 packages: DSQL Query Builder (
Simplicité0 aucune note5.0 2 notes0 aucune note5.0 2 notes0 aucune note0 aucune note0 aucune note0 aucune note
Enterprise Compliance5.0 1 note5.0 2 notes3.0 1 note4.5 2 notes0 aucune note0 aucune note0 aucune note0 aucune note
Minimum PHP Version5.45.65.4
Basic Features
PDO SupportOui YesOui MySQL, SQLite, OthersOuiOui
NoSQL Integrate Transparently- Supported, but drivers not provided.Non Eloquent is built on Query Builder.Oui Avialable cross sql and nosql datababase relationsNon Build around plain queries.
How to invoke db-vendor-specific extensions?Oui DBALOui Provides access to persistence-layer actions (Queries)Oui Through Query Builder / RAW queries.Oui SQL - Query Builder.- Can add SQL code chunks.
Array as a persistenceOui CRUD operations supportedOui
RestAPI as a persistence- Planned- To extend BaseActiveRecordNon
JSON string as a persistence- In development- To extend BaseActiveRecordNon
Same model, multiple persistencesOui Same class. Different object.- (no docs)
Persistence Mapping (must support C,R,U,D)
Table Name MappingOui YesOui $model->table = 'my_table'Oui Same as model class name by defaultOui Using static method of active record. mapping no longer supported.
Field Name MappingOui Yes, (Annotations in PHP)Oui PHP: "name" = SQL: "first_name"- Through accessors/3rd party extensionOuiNon mapping no longer supported.
Map Entity to SubQueryNon Must be physical tableOui "Table" can be "Expression" (or another Model)Non Must be physical table.- table = new Expression(..)Non
Map property to expressionNon Must be physical fieldOui $model->addExpression()Non Must be physical table- (couldn't find docs)Non
Map native types (DateTime)Oui $field->type = 'date'Oui Accessors and MutatorsOui Active record behaviorsOui
User-defined types (e.g. "23 USD")Oui Type classOui Through typecastingOui Accessors and MutatorsOui Active record behaviors
Map field of related Entity ('currency' = currency_id->Model Specific record onlyOui Maps into sub-query.- Relationship, but only single record.Oui $model->currency->nameNon
Map field to sub-query on related entity (Client.balance = Client->orders->sum(total))NonOui hasMany()->addField(..aggregate)Non- (couldn't find docs)Non
Entity to join multiple tables (adding new record populates both tables)Oui AssociationsOui $model->join('other_table')NonNon No native support.Non
NoSQL (must be transparent to domain logic)
MongoDB support- PlannedNonOui
Neo4j- PlannedNonNonNon
MemCache- Planned- Through Caching backend, but not as ORM native persistence.Non
Criteria, Scope, Conditions (Model will refuse to work with records that does not match criteria)
Support model-level criteriaOui- Global Scope (querying only)NonNon
Soft-deleteOui Extension- Easy to implement through conditions. See docs.Oui Trait and ScopeOui Events and behaviorsNon
Domain Model CriteriaOui $m->addCondition('gender','M')- Scopes, but not in domain model.Non Only for specific query: User::find()->byEmail('...')->active()->one()Non
Expression-based conditionOui $m->addCondition($m->expr('..'));Oui through Query BuilderNon Only for query: User::find()->andWhere('...')->all()Non
Criteria Compliance (new record must match condition)Oui With reloading and rollbackNonNon
Dynamic criteriaOui $user->addCondition('is_expired', false)Non Only Querying: User::find()->where(['a' => '1', 'b' => true])->all();Non
Query Building (Convert Model into Query object for further SQL tweaking)
Convert Model into Query ObjectOui $q = $model->action('select');Oui Model is a Query object. See: Model::where()Oui \yii\db\ActiveRecord::find()Non
Raw expressionOui new Expression('any sql')Oui DB::raw()Oui new \yii\db\Expression('...')Oui
Nested/Composite Queries/ExpressionsOui Expression can be in any part of queryNonOui Expression can be in any part of queryNon
Reference domain-model field in queryOui through Expressionable interfaceNon No fields. Only properties.Non Field is class property.Non
field, where, order, limitOui Expressions and Parametric valuesOuiOui \yii\db\ActiveQueryNon
options, rollup, partition- Through custom templates, or expressions.- not sure.
UPDATE, DELETE, INSERT query buildingOuiOuiNon
REPLACE, TRUNCATEOui- 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 buildingOui Addon:
User-defined query templateOui Templates for all queriesOui (please link doc)Non
OR deep nested conditionsOui Through Object CompositionOuiNon only raw query
Use Domain logic in multi-record update- Supported, but must map fields/values manually.NonNonNon
Data Fetching (different ways to retrieve data from database)
Get All Data (2x array)OuiOuiOui \yii\db\Query::all()Oui exportAll()
Associative Array (id=>value)Non PlannedOui lists()
Single rowOui loadAnyOuiOui \yii\db\Query::one()
Single Value- Through actionOuiOui \yii\db\Query::scalar()
Single ColumnNon PlannedOuiOui \yii\db\Query::column()
Bypass persistence mappingOui action('select')->getAll()- ?? (e..g prevent date from being transformed into Carbon)
Loading and Saving individual records
Load by IDOui load(id)Oui User::findOne(1)Oui
Load by other fieldOui loadBy('field', $value)Oui User::findOne(['id' => 1])Non
Load if expressionOui loadBy($expression)Oui User::findOne('...')Oui
Load respects Scope (model-level condition)Oui All conditions added as "where" clause- User::find()->where(...)->andWhere(...)->one()Non
Specify fields to loadOui onlyFields()Non Fields load with SELECT *Oui User::find()->select([])->one()Non
Save only sends dirty fieldsOuiOuiOui- (there is Dirty support, so I assuming it is supported)
Guarded / Fillable properties- Conditions and OnlyFields do same thing differently.Oui Prevents "create($_GET)" from messing up important fields.
Object Hierarchy Model
Admin extends User (is_admin=1)Oui Yes, recommended pattern. "User" class adds condition.Non Both have to use "User" model.Non Can be done as wrapper: User::findAdmin(..) or custom CDbCriteriaNon
Model that represent Orders of single User.Oui Yes, recommended pattern.Non Both have to use "Order" model.NonNon
Extend model, add Join (Disjoined SubTypes)Oui Yes. Unlimited number of joins.NonNonNon
Extend model change tableOui Yes. Used to tweak 3rd party models.Non
Relations/References (One model can relate to another model. NOT A TABLE JOIN)
Model can define relation to other ModelOui References are implemented as ObjectsOui RelationsOui RelationsOui
One-to-ManyOui $user->hasMany('Orders', new Order());OuiOui
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-loadingNon Anti-patternOuiOuiOui
One-to-OneOui $order->hasOne('user_id', new User());OuiOui
Many-to-ManyOui $user->addCondition('vip', true)->ref('Orders');Oui relations() method of an entity can define.
Deep Many-to-Many traversal.NonOui $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 traversalOui $user->hasMany('Log', new Log($mongodb));- No docs.Non
Multi-persistence Mapping (some data from SQL, others MongoDB)
Multi-persistence joinNon- Planned.NonNon
UNION existing modelsNon- PlannedNonNon
Multi-persistence UNIONNonNon But you can merge raw dataNonNon
Multi-persistence value linking (current_sensor_value)- Through behaviour- Through 'afterLoad' hook.Non
Behaviours / Hooks
Before/After operationOuiOui
Hooks for C,R,U,D operationsOuiOui
Persistence-specific hooks (to modify Query)Oui- (no docs)
User-defined hooksOuiOui
Mapping strategyRecord 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.
How to set-upAuditLog can be enabled for all models associated with a specific persistence. No further changes are necessary. Works out of the box.
Store old/new field valuesOui Yes in JSON and user-readable string.Oui
Date of creation, modification- No but easy to add through hook.Oui \yii\behaviors\TimestampBehavior
User/IP creation, modification- Easy to add through a hook.Oui \yii\behaviors\BlameableBehavior
Store incremental revisions- Easy to add through a hookOui
Revert action (undo)OuiNonNon
Custom eventsOuiOui
Custom fields, tableOui Remove default fields, use your own table, fields, formats.Oui
Store in CSV- PlannedNon
Access to record-specific historyOui $item->ref('AuditLog');- Through a custom query.
Access Control
Implementation StrategyDefine a special DB-hook. Every time new "Model" is initialized, extra "condition" will be added. This will make sure that you won't forget some important condition when traversing references. You can also restrict access to edit/delete through per-model hooks that can be globally set.
Single-system global access scopeNonOui Define "system_id" for all models that have this field defined - this will create global condition for all models making sure that user can work with records of one system at a time.NonNonNon
Meta-information (allows exploration by UI widgets)
Implementation StrategyAgile Data is designed to work with UI toolkits. Generic widgets can explore model fields and various meta-information about those fields. References are easy to identify and traverse allowing DropDown fields to populate values inside select.Eloquent is designed to work with MVC engines, where view is mandatory and would be defining how model properties fit into your HTML.Widgets must specify data types manually, while dataProvider is used for fetching the data stream.Beans support "meta" data actually contain data type or some user-data.
UI Widget can fetch list of Model FieldsOuiNon Would have to manually specify fields.- \yii\grid\GridView, \yii\widgets\ListView
UI Widget can get Field type, default value, caption, hintOuiNon- (no docs)
field storing reference to another Model can map into DropDownOui Widget can discover references and traverse to fetch list of drop-down options. Model defines "title_field" which is used by default.Non Must manually specify object with lists() method.Non
J'aime 0 2 0 0 0 0 0 0
  • 2016-10-18 22:08:00
    2016-10-26 15:42:23
  • Produits
  • Compare Doctrine vs Agile Data vs Eloquent vs Yii ORM vs Cake ORM vs Fuel ORM vs x vs x
  • Publique
  • Creative Commons License CC-BY-SA 3.0 / GNU FDL
    Gérer les sauvegardes


Laisser un commentaire

Créer des tableaux comparatifs ou listes sur tout !

C'est gratuit et rapide de créer des tableaux originaux

Créer un tableau