Architecting Your Models
-
Upload
matthew-weier-ophinney -
Category
Technology
-
view
33.612 -
download
0
Transcript of Architecting Your Models
Architecting Your Models
Matthew Weier O'PhinneyProject LeadZend Framework
Goals
Learn to recognize why old habits may be bad
Learn several design patterns that can help you write testable, maintainable code
Learn some techniques for altering existing behavior without rewriting existing code
What We've Learned and What We Do
Oooh! Let's create the schema!
Write code that uses the DB
Plain Old Mysql (POM)
ActiveRecord
Table/Row Data Gateway
And then
We start lamenting about performance.
We end up refactoring for every new feature (e.g. caching, logging).
We need to go to a Service Oriented Architecture, and effectively refactor twice.
STOP
THE
MADNESS!
Step One
Models are just classes.
Create classes.
Models have metadata and behavior;
create properties and methods.
class Person implements PersonInterface{ // Metadata protected $_email; protected $_password; protected $_username;
// Cheat: use overloading to
// provide setters/getters public function __get($name) { } public
function __set($name, $value) { }
// Behaviors public function authenticate() { } public function logout() { } public function ban() { }}
Step Two
Now start thinking
about data persistence.
Identify what data you need to persist
Identify how you'll persist the data
Write code for persisting data
(Data Access Layer)
CREATE TABLE person( username VARCHAR PRIMARY KEY, password VARCHAR, email VARCHAR,);
class PersonTable
extends Zend_Db_Table_Abstract{ protected $_name = 'person';
protected $_primary = 'username';}
Step Three
Map your model
to your data.
Common approaches
Transaction Script (can even use POM)
Table Module (often with ActiveRecord or Table Data Gateway)
Data Mapper / ORM
class PersonMapper
implements PersonMapperInterface{ public function
save(PersonInterface $person) { $data = array( 'username' =>
$person->username, 'password' => $person->password,
'email' => $person->email, );
$this->getTable()->save($data); }
public function fetch($username); public function getTable(); public function setTable($table);}
Some notes:
Data !== Relational Database.
Data could come from a document database, filesystem, cache, or web service.
Choose an ORM that allows you to generate your schema from your entities; allows you to easily model first, and persistence comes for free.
Step Four
Move business and
application logic to
a Service Layer.
Applications
are like onions;
they have layers.
Photo 2008, Mike Chaput-Branson
The Service Layer
provides application logic
on top of your models
Service Layer
in perspective
Data Access Objects and Data store(s)
Data Mappers
Domain Models
Service Layer
Benefits to a Service Layer
Allows easy consumption of the application
via your MVC layer
Allows easy re-use of your application
via services
Write CLI scripts that consume the
Service Layer
What kind of application logic?
Validation and filtering
Authentication and Authorization
Transactions and interactions between model entities
class PersonService{ public function create(array $data) {
$person = new Person(); if (!$data = $this->getValidator()
->isValid($data)
) { throw new InvalidArgumentException(); } $person->username =
$data['username']; $person->password = $data['password'];
$person->email = $data['email'];
$this->getMapper()->save($person); return $person; }}
Decorating for
fun and profit
Decorators allow you
to add or alter functionality
of an existing class.
Typical decorators
Implement the same interface(s) of the class being decorated
Often use overloading to proxy to the decorated class
Override specific behavior(s) you wish to modify or enhance
Add new behaviors that use existing behaviors in the decorated class
Refactor to add caching?
No!
Decorate!
class CachingPersonMapper
implements PersonMapperInterface{ public function
__construct(
PersonMapperInterface $mapper) { $this->_mapper = $mapper; }
public function fetch($username) { $cache =
$this->getCache(); if (!$person = $cache->load($username)) {
$person = $this->_mapper
->fetch($username); $cache->save($person, $username); }
return $person; }}
Refactor to provide alternate
return formats? (e.g., JSON, XML, etc.)
No!
Decorate!
class JsonPerson implements PersonInterface{ public function
__construct(
PersonInterface $person
) { $this->_person = $person; }
public function __toString() { $data = array( 'username' => $this->_person->username, 'email' => $this->_person->email, ); return json_encode($data); }}
Nicely Formed
Objects
Rebuilding and refactoring is costly and painful
Good OOP and encapsulation CAN make your life easier
Testing is easier than debugging
Choose a good ORM to expedite development. (Doctrine, Object Freezer, Zend_Entity, etc.)
Think beyond
the DB!
Thank you!
Feedback: http://joind.in/918
Twitter: @weierophinney
Blog: http://weierophinney.net/matthew/
Click to edit the title text format
Click to edit the outline text formatSecond Outline LevelThird Outline LevelFourth Outline LevelFifth Outline LevelSixth Outline LevelSeventh Outline LevelEighth Outline LevelNinth Outline Level
All rights reserved. Zend Technologies, Inc.
Click to edit the title text format
Click to edit the outline text formatSecond Outline LevelThird Outline LevelFourth Outline LevelFifth Outline LevelSixth Outline LevelSeventh Outline LevelEighth Outline LevelNinth Outline Level
All rights reserved. Zend Technologies, Inc.
Click to edit the title text format
Click to edit the outline text formatSecond Outline LevelThird Outline LevelFourth Outline LevelFifth Outline LevelSixth Outline LevelSeventh Outline LevelEighth Outline LevelNinth Outline Level
All rights reserved. Zend Technologies, Inc.