SitePoint Sponsor

User Tag List

Results 1 to 9 of 9
  1. #1
    SitePoint Zealot
    Join Date
    Jul 2003
    Location
    Palo Alto
    Posts
    179
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Unit of work example, anyone?

    I need to implement the "Unit of work" pattern described in Martin Fowler's "Patterns of Enterprise Application Architecture," but I'm hoping I don't have to start from scratch. Does anyone have, or know where I might find, a PHP example?

  2. #2
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

  3. #3
    SitePoint Zealot
    Join Date
    Jul 2003
    Location
    Palo Alto
    Posts
    179
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, but no. That's a tutorial on unit testing, but what I'm after is an example implementation in PHP (i.e., code) of a design pattern known as a "Unit of Work." I'll quote from Martin Fowler here:
    A Unit of Work (184) keeps track of all objects read from the database, together with all objects modified in any way.

  4. #4
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry

    Do not have Martin Fowlers book so I had no reference.

    [Shame there isn't an on-line version to download though - free of course ]

  5. #5
    SitePoint Zealot
    Join Date
    Jul 2003
    Location
    Palo Alto
    Posts
    179
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Not available for download as far as I know, but it is available through the O'Reilly Safari service (which I use and recommend), and the patterns themselves are also available on Fowler's site at http://www.martinfowler.com/eaaCatalog/

  6. #6
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi.

    I am doing something similar, but called it Transaction. The persistent objects in our library have a commit() method that returns true on success or false on failure. False means that the write was unsuccessful and the database could be in a mess.

    The transaction class is very simple...
    PHP Code:
    class Transaction {
        function 
    Transaction() { ... }
        function 
    attach(&$persistent) { ... }
        function 
    commit() { ... }
        function 
    getError() { ... }

    All it does on commit() is open a database transaction, run through any attached objects running their commits and if any return false a rollback query is issued. Otherwise a commit query is issued. That's really all there is to it. The persistent objects only have to worry about trying to save themselves and not about cleaning up.

    This is simpler than the Fowler version, but for short lived web processes it looks like being enough. Our previous version, with the persistent classes handling transactions, was an embarassing mess .

    yours, Marcus.
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  7. #7
    SitePoint Zealot
    Join Date
    Jul 2003
    Location
    Palo Alto
    Posts
    179
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So the peristent objects need to call Transaction::attach($this) at some point, and then (later) Transaction::commit()? Also, how does the Transaction class distingush between persistent and non-persistent attributes in an attached object? I use a DataMapper -- only a simple one -- and I'm leaning towards using that since it already contains a map from the database to the objects, and reversing the map's direction would be fairly simple.

  8. #8
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You might want to look at some of the CORBA Transaction Service and Java Transaction service documentation. They implement transactions with two-phase commit, but you can probably get some good ideas from them.

    I implemented a simple CORBA transaction manager in Delphi years ago as part of a persistence architecture. I'll try to remember this correctly...

    Each object involved in a transaction implements a Resource interface:

    prepare()
    commit()
    rollback()
    etc...

    And the transaction implements an interface:

    register($resource)
    rollback()
    commit()
    etc... (although the OTS interfaces are much more complicated)

    When the transaction is committed, All of the registered resources are first sent a prepare message, then if all resources report themselves as successfully prepared, then a commit message is sent.

    There is also a concept of a current transaction (each thread had a current transaction). This lets the objects involved in a transaction automatically register themselves with the current transaction. I forget the exact syntax of this, though it was something like this:

    Context.BeginTransaction();
    Object1.methodThatUpdatesObject();
    Object2.methodThatUpdatesObject();
    Context.EndTransaction();

    (I am somewhat disturbed at how much I have forgotten. That was one thing I probably should have kept a private copy of the source code for. It implemented many of the object-relational patterns described in PEAA (four years before the book came out I wish I had it then). Alas, I kept no code. )

    If I am not mistaken, the middleware company's petstore benchmark application requires a transaction with two-phase commit. Something that a PHP implementation would have to tackle.

  9. #9
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by brainpipe
    So the peristent objects need to call Transaction::attach($this) at some point, and then (later) Transaction::commit()?
    It is even cruder than that. The client code just attaches any objects it wants isolated. The transaction can be started anytime, I forgot the start() method above. If it hasn't been started, then it is started at the beginning of the commit method. I also missed out (because we were working it all out when you posted) that there is a confirmCommit() method so that they can do some internal book keeping. Otherwise a second update and commit would needlessly resend the previous data.

    Quote Originally Posted by brainpipe
    Also, how does the Transaction class distinguish between persistent and non-persistent attributes in an attached object?
    It doesn't. All of that is in the (generated) persistent classes. Also in there is their volatility (whether they need to read themselves back from the database) and any extra actions they need to perform if they are a new inserted object.

    Quote Originally Posted by brainpipe
    I use a DataMapper -- only a simple one -- and I'm leaning towards using that since it already contains a map from the database to the objects, and reversing the map's direction would be fairly simple.
    What does it look like, I'm curious? See also the Scott Ambler material somewhere at http://www.agiledata.org/. I cannot find it right now, but there is a 30 page PDF describing how to roll a full on persistence layer. Not everything comes from Martin Fowler .

    yours, Marcus.
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •