550 likes | 759 Views
Zend Framework and Doctrine Putting the M in Zend. A Few Notes…. On the presentation: For the so inclined, the “model object” referred to is equivalent to the DDD domain object (I think). On Me: Isaac Foster ( isaac.z.foster@gmail.com ) Zend Framework Certified
E N D
A Few Notes… • On the presentation: • For the so inclined, the “model object” referred to is equivalent to the DDD domain object (I think). • On Me: • Isaac Foster (isaac.z.foster@gmail.com) • Zend Framework Certified • Currently working for Tabula Digita.
Your Honor, I Intend to Prove… • That Doctrine’s value added over Zend_Dbis the framework it provides for business logic. • Other features make it a complete, powerful tool.
First TLA: MVC • Model – Behavior and data of the application. • View– Display information. • Controller– Takes inputs from the user, invokes the model and chooses the view.
The M in MVC • Model objects hold business data and logic. • Model != DB: • True, data that a model acts on is often persisted in a db. • Db code in the model layer, not necessarily model object. • Model object should focus on what makes it special. your models -->
Separate Business and Persistence Logic • DBAL (Database Abstraction Layer) • One API to rule them all. • ORM (Object Relational Mapper) • Put the object in, get the object out. • ↑Consistency, ↑Reliability, ↑Reuse, ↑Ease… • It’s a Good Thing Snoop shares his thoughts on the active record pattern.
Frameworks and Libraries Help us Achieve These (and other) Goals and one of those frameworks is…
Zend Framework • MVC Framework + Components • Great View and Controller framework: • IOC lets you focus on the ACTION, not the request, response, router, dispatcher … • Components • Zend_Acl for authorization. • Zend_Auth for authentication • Zend_Session for session management … what about M?
The M in Z-E-N-D? • Zend_Db wraps db driver for DBAL. • Zend_Db_Table wraps a table, gives some structure to a model, ORM-ish. • Zend_DB_Table_Row wraps row, active record features.
The M in Z-E-N-D? • Provides: • Protection from SQL Injection • Query Construction API • Transactions • Profiler • Cache
So What’s the Problem? Definitely Zend_Db, not Zend_Model • Not much from a business logic perspective: • Little help you stay DRY with business logic. • Not much in the way of model life-cycle hooks (preSave, postSave, preDelete, etc). • Still thinking about db’s, tables, and table references, not models and relationships.
Doctrine is…DBAL + ORM + Active Record + Model Framework • Provides framework for business logic… • Plugins hook into events, core code untouched. • Reuse code and structure with behaviors. • Configure validation and rules. • Doctrine model IOC ≈ ZF controllers IOC • Think more about models, not tables.
Doctrine • Will create your database tables. • Migration tools. • Performance tools and configurations. • Utilities • Command line interface • Pagination
A Problem To Solve… • Need to keep track of Users • Auto incremented id. • Email property must be valid email address. • Password must be hashed. • Want to send a confirmation email to new users after they register.
A Harder Problem… • Exercise 1st Amendment right to blog • Need to update blog post, track previous versions. • Want to attach images to a post. • Store them on Amazon S3 • Update author’s numPosts field after blogging. • Don’t feel like creating tables manually.
Guideposts • Doctrine_Connection ≈ Zend_Db • Doctrine_Table ≈ Zend_Db_Table_Abstract • Doctrine_Record ≈ Zend_Db_Table_Row_Abstract
Doctrine Core Classes • Doctrine_Manager • Manages connections, knows available drivers. • Handles application wide options. • Doctrine_Core • Manages autoloading. • Methods to create tables, export database, etc.
Connections • Connect to a database: • MySql, MsSql, Oracle, Postgre, DB2, Sqlite.
Bootstrapping • Connections and autoloading in bootstrap. • Doctrine autoloader for models. • Zend Autoloader for Doctrine library files.
Defining Models: Goal • Model creation should be like Lego building. • Configure when possible, code if necessary. • Let framework do the easy stuff. • Leverage framework for harder stuff.
Defining Models • Each model has a Doctrine_Table. • Structure and meta-info stored there. • setTableDefinition and setUp create the table: • hasColumn → add properties • hasOne → add one-to-one relationships • hasMany → add one-to-many and many-to-many • Model can be defined in code or YAML config.
A More Detailed Problem… • Need a Blog model with: • Unique integer key. • Title (non null, less than 150 chars) • Text (non null). • Flag for whether it is published (default false). • Foreign key for relating to the author. • DETAILS, REQUIREMENTS, RULES!! WHAT TO DO!!
Doctrine_Record::hasColumn() • Adds properties to your model. • Blog has a title property, content property, etc. • hasColumn($name, $type [,$length, $options]) • name – “propertyName” or “columnName as propertyName” • type - int, string, boolean, float, many more. • length – max length • options – options
Property Options • default – sets default value. • primary – if the primary key. • autoincrement – if autoincrementing id. • notnull – enforce the value not be null. • email – enforce the value be a valid email. • Other validator indicators
More Details… • Blog also needs: • An Author. • Images attached to it for upload and display. • WHAT TO DO!!
Doctrine_Record ::hasOne() • Defines one-to-one associations between your model and another. • hasOne($associationClass [, $options]) • associationClass –either “associationClass” or “associationClass as associationName” • options – the association options
Doctrine_Record::hasMany() • Add one-to-many, many-to-many associations. • A Blog has Comments (1-to-many). • A User can be in many Groups and a Group can have many Users (many-to-many). • hasMany($associationClass [, $options]) • name – “associationClass” or “associationClass as associationName” • options – association options
More Problem Specs… • When… • The blog is created: • An email should be sent to all editors informing them they need to proof read it. • The blog is published: • An email should be sent to the mailing list informing them of the new post. • A Facebook story should be published doing the same. • A Tweet should be sent with the fist 140 characters. • The blog is saved (inserted or updated). • All image objects associated with it must be uploaded to Amazon S3
Note That… • Stuff happens when other stuff happens. • On X, do Y. • Not Blog’s responsibility to email, Facebook, Tweet, or upload to S3. • Probably shouldn’t be hardcoded into Blog class. • COMPLEXITY!! AND YOU WANT ARCHITECTURAL PURITY!!! LAAAAMMMEE!!!
Plugins (Listeners) • As Zendfront controller pluginshook into preDispatch, postDispatch, etc, events… • …so Doctrine record pluginshook into: • pre/post Insert/Update/Save/Delete, others. • Also plugins for connections. Hook into: • pre/post connect/transactionBeing/fetch/exec, others.
Plugins (Listeners) • IOC: add logic to a model or connection without touching the core code. • Log and profile all SQL queries (connection hooks). • Send an email to a user when they sign up (model hooks). • Register as many as you need. • Similar to JS DOM events.
Doctrine_Record::addListener() • Add a plugin to run when something happens. • addListener($listener, $listenerName = null) • listener the plugin to add. • listenerName name of the plugin, useful for removing later.
More Problem Specs… • The Blog must… • Keep track of when it was created and last updated. • Timestamps should be set automatically, not explicitly by consumer code. • Keep track of previous versions. • Provide revert and get versions methods. • Versioning happens automatically, not in consumer code. • Be flaggable. • Provide a flag method. • Automatically increment the Blog’s flag count.
Notice That… • These behaviors are generic: • Probably want them elsewhere, but in different combinations, with different configurations. • Implementation not special to Blog. • Define base classes for each and extend… • …But no multiple inheritance in PHP. • I’VE HAD ALL I CAN STANDS, AND I CAN’T STANDS NO MORE!
Mix-in With Templates • Avoid single inheritance issues. • Don’t choose between extending Flaggable, Taggable, Locateable, Versionable, just mix-in all of them! • Stay DRY. • Inversion of (model definition) control. • Add properties, relationships, plugins,… and methods! • Encapsulate generic behavior in one place. • Add as many as you want.
Defining Models: BehaviorsStep One: Find a Template… • In “path/to/Doctrine/Template” • Community contributed at http://trac.doctrine-project.org/browser/extensions?rev=7461
Defining Models: BehaviorsStep Two: Tell Your Model to “actAs” the Template
Doctrine_Record::actAs() • Adds a template to your model. • actAs($template[, $options]) • $template – template name or instance. • $options – configuration options
Defining Models: Summary • Model creation should be like Lego building. • Snap on properties and relationships. • Snap in listeners that get called at hook points. • Snap on behavior with templates.
Querying Models • Query your model with: • Doctrine_Table finder methods • Doctrine_Table::find() – by primary key • Doctrine_Table::findAll() • Doctrine_Table::findBy() – by specified key • Others • Doctrine Query Language • SQL like syntax • Translation to native SQL handled by Doctrine • Similar to various Zend_Db statement classes