Cool Objects Sleep on the Couch

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    4 Favorites & 1 Group

    Cool Objects Sleep on the Couch - Presentation Transcript

    1. Cool Objects Sleep on the Couch Sebastian Bergmann October 20th 2009
    2. Sebastian Bergmann  Co-Founder and Principal Consultant with thePHP.cc  Creator of PHPUnit  Involved in the PHP project since 2000
    3. How can we map data between objects and a database?
    4. The Problem class User { protected $name; protected $address; } class Address { protected $city; protected $zip; protected $state; protected $country; }
    5. The Problem Relational databases store scalar values that are organized in tuples and relations.  An object is not a scalar value  An object graph has to be broken down into single objects, then into scalar values
    6. The Problem class User { Table: users protected $name; +------+---------+ protected $address; | name | address | } +------+---------+ class Address { Table: addresses protected $city; +------+-----+-------+---------+ protected $zip; | city | zip | state | country | protected $state; +------+-----+-------+---------+ protected $country; }
    7. The Problem class User { Table: users protected $name; +------+---------+ protected $addresses = array(); | name | ??????? | } +------+---------+ class Address { Table: addresses protected $city; +------+-----+-------+---------+ protected $zip; | city | zip | state | country | protected $state; +------+-----+-------+---------+ protected $country; }
    8. Not a sustainable solution: Hand­Coded SQL in the Domain Class class User { protected $name; public function __construct($name) { $this->setName($name); } public function setName($name) { $this->name = $name; if (/* new user */) { DB::getInstance()->query('INSERT INTO users …'); } else { DB::getInstance()->query('UPDATE users SET …'); } } }
    9. Not a sustainable solution: Hand­Coded SQL in the Domain Class Domain logic and persistence layer are tangled  No locality of change  No separation of concerns  Domain logic cannot be used – tested, for instance – without the persistence layer
    10. How can we map the model to the database
    11. How can we map the model to the database without writing unmaintainable spaghetti code?
    12. Separation of Concerns Model and persistence are separate concerns.
    13. Separation of Concerns Model and persistence should be decoupled.
    14. Separation of Concerns Design Patterns help decouple model and persistence.
    15. Data Source Architectural Patterns Active Record
    16. Data Source Architectural Patterns Active Record An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. This slide contains material by Martin Fowler
    17. Data Source Architectural Patterns Active Record Active Record may be used to implement an Object-Relational Mapper (ORM), but it should never be used as one. This slide contains material by Kore Nordmann
    18. Object­Relational Mapping (ORM)
    19. Object­Relational Mapping (ORM) Programming technique for converting data between incompatible type systems in relational databases and object- oriented programming languages [that] creates a ”virtual object database”. This slide contains material by Martin Fowler
    20. Object­Relational Behavioral Patterns Unit of Work
    21. Object­Relational Behavioral Patterns Unit of Work Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems. This slide contains material by Martin Fowler
    22. Object­Relational Behavioral Patterns Identity Map
    23. Object­Relational Behavioral Patterns Identity Map Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them. This slide contains material by Martin Fowler
    24. Object­Relational Behavioral Patterns Lazy Load
    25. Object­Relational Behavioral Patterns Lazy Load An object that does not contain all of the data you need but knows how to get it. This slide contains material by Martin Fowler
    26. ORM Solutions for PHP  Doctrine  Propel
    27. ORM Solutions for PHP Propel <database name="example" defaultIdMethod="native"> <table name="user"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/> <column name="name" type="varchar" size="255" required="true" /> <column name="address" type="integer" required="true"/> <foreign-key foreignTable="address"> <reference local="address" foreign="id"/> </foreign-key> </table> <table name="address"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/> <column name="city" type="varchar" size="128" required="true"/> <column name="zip" type="varchar" size="128" required="true"/> <column name="state" type="varchar" size="128" required="true"/> <column name="country" type="varchar" size="128" required="true"/> </table> </database>
    28. ORM Solutions for PHP Propel sb@thinkpad example % propel-gen . . . . sb@thinkpad example % tree build build |-- classes | `-- example | |-- Address.php | |-- AddressPeer.php | |-- User.php | |-- UserPeer.php | |-- map | | |-- AddressMapBuilder.php | | `-- UserMapBuilder.php | `-- om | |-- BaseAddress.php | |-- BaseAddressPeer.php | |-- BaseUser.php | `-- BaseUserPeer.php |-- conf | |-- example-classmap.php | `-- example-conf.php `-- sql |-- schema.sql `-- sqldb.map 6 directories, 14 files
    29. ORM Solutions for PHP Propel sb@thinkpad example % phploc --count-tests build phploc 1.3.0 by Sebastian Bergmann. Directories: 3 Files: 12 Lines of Code (LOC): 3469 Cyclomatic Complexity / Lines of Code: 0.19 Executable Lines of Code (ELOC): 1234 Comment Lines of Code (CLOC): 1743 Non-Comment Lines of Code (NCLOC): 1726 Interfaces: 0 Classes: 10 Abstract Classes: 4 Concrete Classes: 6 Lines of Code / Number of Classes: 329 Methods: 123 Non-Static Methods: 69 Static Methods: 54 Lines of Code / Number of Methods: 26 Cyclomatic Complexity / Number of Methods: 2.92 Functions: 0 Constants: 20 Global constants: 0 Class constants: 20 Tests: Classes: 0 Methods: 0
    30. Object­Relational Mapping (ORM) ”The Vietnam of Computer Science”
    31. Object­Relational Mapping (ORM) Law of Diminishing Returns Early successes yield a commitment to use ORM in places where success becomes more elusive, and over time, isn't a success at all due to the overhead of time and energy required to support it through all possible use-cases. This slide contains material by Ted Neward
    32. Here's an idea: Lets redefine what ORM stands for! ct O bje tory po si Re ing pp Ma
    33. Map PHP object graphs to a schema­free database using the Object_Freezer library.
    34. Object_Freezer Freezing an object class SomeClass { private $foo = 'bar'; } require_once 'Object/Freezer.php'; $freezer = new Object_Freezer; $frozenObject = $freezer->freeze(new SomeClass);
    35. Object_Freezer A frozen object array( 'root' => '087998e3-5305-4837-bd50-79564e720777', 'objects' => array( '087998e3-5305-4837-bd50-79564e720777' => array( 'className' => 'SomeClass', 'isDirty' => TRUE, 'state' => array( 'foo' => 'bar', '__php_object_freezer_hash' => 'a8e3be85ce27a1e44ec5bb83407b53f25bbf9a95', ) ) ) )
    36. Object_Freezer Thawing a frozen object $object = $freezer->thaw( array( 'root' => '087998e3-5305-4837-bd50-79564e720777', 'objects' => array( '087998e3-5305-4837-bd50-79564e720777' => array( 'className' => 'SomeClass', 'isDirty' => TRUE, 'state' => array( 'foo' => 'bar', '__php_object_freezer_hash' => 'a8e3be85ce27a1e44ec5bb83407b53f25bbf9a95', ) ) ) ) );
    37. Object_Freezer Internals: Reading non­public object state $reflector = new ReflectionObject($object); $state = array(); foreach ($reflector->getProperties() as $attribute) { $attribute->setAccessible(TRUE); $state[$attribute->getName()] = $attribute->getValue($object); }
    38. Object_Freezer Internals: Reading non­public object state $reflector = new ReflectionObject($object); $state = array(); foreach ($reflector->getProperties() as $attribute) { $attribute->setAccessible(TRUE); $state[$attribute->getName()] = $attribute->getValue($object); } New in PHP 5.3
    39. Object_Freezer Internals: Creating an object without invoking __construct() $object = unserialize( sprintf( 'O:%d:"%s":0:{}', strlen($className), $className ) );
    40. Object_Freezer Internals: Setting non­public object state $object = unserialize( sprintf( 'O:%d:"%s":0:{}', strlen($className), $className ) ); $reflector = new ReflectionObject($object); foreach ($state as $name => $value) { $attribute = $reflector->getProperty($name); $attribute->setAccessible(TRUE); $attribute->setValue($object, $value); }
    41. Object_Freezer_Storage  Abstract base class for object storage implementations  Unit of Work  Identity Map  Lazy Load  Available implementations  Apache CouchDB
    42. Apache CouchDB  Distributed  Fault-Tolerant  Schema-Free  Document-Oriented  RESTful JSON API
    43. Apache CouchDB RESTful JSON API sb@thinkpad ~ % curl -X GET http://127.0.0.1:5984/ {"couchdb":"Welcome","version":"0.9.0"} sb@thinkpad ~ % curl -X GET http://127.0.0.1:5984/_all_dbs [] sb@thinkpad ~ % curl -X PUT http://127.0.0.1:5984/test {"ok":true} sb@thinkpad ~ % curl -X GET http://127.0.0.1:5984/_all_dbs ["test"] sb@thinkpad ~ % curl -X DELETE http://127.0.0.1:5984/test {"ok":true}
    44. Object_Freezer_Storage_CouchDB Storing an object class SomeClass { private $foo = 'bar'; } require_once 'Object/Freezer/Storage/CouchDB.php'; $storage = new Object_Freezer_Storage_CouchDB( 'test', new Object_Freezer, TRUE, 'localhost', 5984 ); $id = $storage->store(new SomeClass);
    45. Object_Freezer_Storage_CouchDB Fetching an object var_dump($storage->fetch($id)); object(SomeClass)#5 (3) { ["foo":"SomeClass":private]=> string(3) "bar" ["__php_object_freezer_uuid"]=> string(36) "29ea0bf5-e3f8-4694-8278-7a58a40f9d1a" ["__php_object_freezer_hash"]=> string(40) "b4eb9c1b85b392b06e778ded6fe3136859d7e7e3" }
    46. Object_Freezer_Storage_CouchDB Internals: PHP Code protected function doStore(array $frozenObject) { $payload = array('docs' => array()); foreach ($frozenObject['objects'] as $_id => $_object) { if ($_object['isDirty'] !== FALSE) { $payload['docs'][] = array( '_id' => $_id, 'class' => $_object['className'], 'state' => $_object['state'] ); } } if (!empty($payload['docs'])) { $this->send( 'POST', '/' . $this->database . '/_bulk_docs', json_encode($payload) ); } }
    47. Object_Freezer_Storage_CouchDB Internals: JSON Message POST /test/_bulk_docs { "docs": [ { "_id": "8314aba0-fe30-494f-b836-edc9e7366366", "class": "SomeClass", "state": { "__php_object_freezer_hash": "9bb7d790...", "foo": "bar" } } ] }
    48. Object_Freezer_Storage_CouchDB Internals: PHP Code protected function doFetch($id, array &$objects = array()) { $isRoot = empty($objects); if (!isset($objects[$id])) { $response = $this->send('GET', '/' . $this->database . '/' . $id); if (strpos($response['headers'], 'HTTP/1.0 200 OK') === 0) { $object = json_decode($response['body'], TRUE); } else { throw new RuntimeException(/* ... */); } $objects[$id] = array( 'className' => $object['class'], 'isDirty' => FALSE, 'state' => $object['state'] ); if (!$this->lazyLoad) { $this->fetchArray($object['state'], $objects); } } if ($isRoot) { return array('root' => $id, 'objects' => $objects); } }
    49. Object_Freezer_Storage_CouchDB Internals: JSON Message GET /test/8314aba0-fe30-494f-b836-edc9e7366366 { "_id": "8314aba0-fe30-494f-b836-edc9e7366366", "_rev": "2289472561", "class": "SomeClass", "state": { "__php_object_freezer_hash": "9bb7d790...", "foo": "bar" } }
    50. Object_Freezer sb@thinkpad php-object-freezer % phploc --count-tests . phploc 1.3.0 by Sebastian Bergmann. Directories: 10 Files: 30 Lines of Code (LOC): 4032 Cyclomatic Complexity / Lines of Code: 0.06 Executable Lines of Code (ELOC): 1218 Comment Lines of Code (CLOC): 2007 Non-Comment Lines of Code (NCLOC): 2025 Interfaces: 2 Classes: 19 Abstract: 1 (5.26%) Concrete: 18 (94.74%) Lines of Code / Number of Classes: 153 Methods: 51 Scope: Non-Static: 48 (94.12%) Static: 3 (5.88%) Visibility: Public: 35 (68.63%) Non-Public: 16 (31.37%) Lines of Code / Number of Methods: 57 Cyclomatic Complexity / Number of Methods: 2.41 Functions: 0 Constants: 1 Global constants: 0 Class constants: 1 Tests: Classes: 9 Methods: 76
    51. The End Thank you for your interest! These slides will be posted on http://slideshare.net/sebastian_bergmann
    52. License   This presentation material is published under the Attribution-Share Alike 3.0 Unported license.   You are free: ✔ to Share – to copy, distribute and transmit the work. ✔ to Remix – to adapt the work.   Under the following conditions: ● Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). ● Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.   For any reuse or distribution, you must make clear to others the license terms of this work.   Any of the above conditions can be waived if you get permission from the copyright holder.   Nothing in this license impairs or restricts the author's moral rights.

    + Sebastian BergmannSebastian Bergmann, 1 month ago

    custom

    1113 views, 4 favs, 0 embeds more stats

    The PHP Object Freezer provides the low-level funct more

    More info about this document

    CC Attribution-ShareAlike LicenseCC Attribution-ShareAlike License

    Go to text version

    • Total Views 1113
      • 1113 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 4
    • Downloads 83
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories

    Groups / Events