SitePoint Sponsor

User Tag List

Page 2 of 2 FirstFirst 12
Results 26 to 36 of 36
  1. #26
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    702
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by FrlB View Post
    Anyway, I like your solution to decouple data access from domain objects, I just wonder if you could elaborate a little about this hierarchy:
    PHP Code:
    $this->context-> 
    I gather $this is a controller, but what kind of thing is the context here?
    Thanks!
    The context is a registry that gets injected into the major classes such as controllers, views, models (oops - I meant gateways). I think I got the terminology from Symphony. Plus I tend to misspell registry.

    The context typically contains objects such as
    config
    log
    models - Model Gateway locator
    tables - Table Gateway locator

    By using injection (hope I'm using the term correctly) I simplify testing setup and also allow for the possibility of having multiple contexts when needed.

  2. #27
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ahundiak View Post
    models - Model Gateway locator
    tables - Table Gateway locator
    That's peculiar. What's the division of labour between a "Model Gateway" and a "Table Gateway" in your design?

    Quote Originally Posted by ahundiak View Post
    By using injection (hope I'm using the term correctly) I simplify testing setup and also allow for the possibility of having multiple contexts when needed.
    Injection is when you pass dependencies explicitly. You're using a registry (aka. locator), which pass dependencies implicitly. They both decouple dependencies, making testing easier (among other things).

  3. #28
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    702
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    That's peculiar. What's the division of labour between a "Model Gateway" and a "Table Gateway" in your design?
    In my design, a Table Gateway focuses completely on one and only one table. Row data is passed to it in the form of arrays.
    PHP Code:
    class PersonTable extends BaseTable
    {
        protected 
    $tblName 'person';
        protected 
    $keyName 'person_id';

        protected 
    $mapClassName 'PersonMap';
    }
    $personRow = array('person_id' 27'fname' 'Art');
    $personTable = new PersonTable();
    $personTable->update($personRow); 
    Applications will very seldom use the table objects directly, instead they use the model objects which hide the table details. In the above example, the application would actually deal with PersonItem objects. It's up to the model to decide what table (or tables) to use when persisting it.
    PHP Code:
    // The application
    $person $this->context->models->Person->find(27);
    $person->firstName 'Art';
    $this->context->models->Person->save($person); 
    I found that whenever I started mixing row type table level objects with business type objects then things would get confused. So I put most things that deal only with database tables into their own class and got rid of table row objects completely.
    Last edited by ahundiak; Mar 20, 2007 at 10:50.

  4. #29
    SitePoint Enthusiast echoSwe's Avatar
    Join Date
    Jun 2005
    Location
    Malm, Sweden.
    Posts
    38
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't think Gateway is the correct name for the object with CRUD + search + pickList functionality. I think Shea was spot on with "Repository".

    There are further, from what a google search of "Gateway pattern" shows, a subpattern of "Gateway": "Table Data Gateway".

    From the Patterns of EAA, then:
    Gateway:
    "An object that encapsulates access to an external system or resource."
    http://www.martinfowler.com/eaaCatalog/gateway.html

    Table Data Gateway:
    "An object that acts as a Gateway to a database table. One instance handles all the rows in the table."
    http://www.martinfowler.com/eaaCatal...taGateway.html

    Repository:
    "Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects."
    http://www.martinfowler.com/eaaCatalog/repository.html

    And from the rest of the internet:
    Data Access Object:
    "Code that depends on specific features of data resources ties together business logic with data access logic. This makes it difficult to replace or modify an application's data resources. The Data Access Object (or DAO) pattern:
    * separates a data resource's client interface from its data access mechanisms
    * adapts a specific data resource's access API to a generic client interface "

    http://java.sun.com/blueprints/patterns/DAO.html
    http://www.codefutures.com/data-access-object/

    Factory pattern:
    When the constructors of the single entities aren't enough to create a consistent object, factories may be used. (perhaps all Tickets needs to have an Owner which always has a reference to a user for example). From the description given these don't really need to be used in this example.

    Then finally there is the service pattern which is a common point of connection between many domain/entity/business objects (such as Ticket) and is appropriate when
    • The operation performed by the Service refers to a domain concept which does not naturally belong to an Entity or Value Object
    • The operation performed refers to other objects in the domain.
    • (The operation is stateless.)


    OK, so that's a summary of the different pattern that I personally can see fit to either the question as a whole or subgroups of it.

    Let's call the TicketModel: TicketRepository, instead. Because in an application whose model is modeled after domain driven design, the repository handles finding the collections of the objects (Let's call the Ticket an Entity or Domain object), or single object, by ID for example. A ticket should have an ID, because otherwise, how would anybody know you won? So it's not an immutable object. (i.e. an object created once with values that do not change during the object lifecycle)

    So we have the Ticket class. It doesn't know anything but what it is, i.e. no data access layer information in it.

    Then we have the TicketRepository which contains methods for accessing persisted instances of Ticket. It can also contain methods for caching, authorizing on a granular level or intercepting the data. It's a domain-level object. This can also be a great place to set up distributed transactions or regular database transactions which I greatly recommend if you've not just saving one row in the database!

    Now that we got the TicketRepository, the views differ on what's best to have further down; what actually accesses the database/xml/files/external web services. One view (as in regular english) is that the repository does the accessing, so that it contains references to objects that know how to talk directly to the database. This isn't fully consistent with DDD, but on the other hand, it's good enough for smaller/less complex applications. The other view is that there should be a data access object pattern under the repository which is very similar to what I'm talking about repository as. They differ in that the repository for example may know how to cache object, or authorize requests, which the DAO does not.

    So in the second view, the repository is per definition not concerned with CRUD, but rather uses objects closer to the storage, such as data access objects, to do CRUD and other selective operations. The repository is hence less coupled with the persistance.

    I think the "TicketModel" class that was described above isn't a gateway, because it seems that a gateway is more about providing a unified "interface" (in the pattern sense) to a more irregular system below. In turn a service, such as a web service API might call this Gateway.

    The table data gateway on the other hand may very well be a good point to place CRUD access to a table, but that also assumes that you have one table for each object; and you might have more than one (not very common though).

    ---
    So, if I was doing a small system like yours, I'd have:
    Ticket
    TicketRepository, but no Data Access Objects. TicketRepository has your ->save(in ticket : Ticket), ->loadById(in Id : integer) and as time goes you can add some caching to this as well.
    ---

    Then we have the daos and services which also could play a role. From what I understand, PHP doesn't have the interface which is used to decouple the implementation from its callers, by just declaring the signatures of the methods the implementation should have, forming a contract with the implementation which it has to fullfil in order to compile. (design by contract) This makes it hard to argue greater separation of concerns than a repository handling the database persistence, because you can't as easily switch implementations.

    Web Services don't use interfaces, they use WDSL, which define the methods of the implementation, but not the implementation itself.

    Services lie tier-wise on top of everything stated. They define APIs to the domain model and its logic...

    The $this->context looks very much like the PHP equivalent of an Inversion of Control engine (aka. Dependency Injection). You might try searching for "inversion of control php", or something.

    In my own applications I have (in a JSON-structured text ):
    Views,
    Presenters (instead of controllers because I don't want the views to talk to my model at all),
    Model = { Business layer: { Application services (deal with responsibilities not given to domain object, but not relevant to the GUI-part of the application and hence not the presenters), Domain (entities and their internal logic), (possibly repositories but most often not, because...) },
    Data Access Layer: { GenericNHibernateDao, NHibernate-persistance (O/R-M) framework }},

    where I use inversion of control to inject application services into the presenters, GUI-components (not really presenters) into site-wide presenters, and also to inject daos into repositories.

  5. #30
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    702
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by echoSwe
    I don't think Gateway is the correct name for the object with CRUD + search + pickList functionality. I think Shea was spot on with "Repository".
    I have done a bit more thinking on this and still have not managed to convince myself that Model is not a good term to use.

    Repository does indeed cover the collection query portion.
    Gateway covers the basic CRUD portion.

    And while I didn't bring this up before (flame suit was in the laundry) I also have a Validate method for doing some error checking.

    So what to call a Gateway+Repository+Validator class?

    If we accept that the M in MVC talks about the Domain Model then maybe Model could mean the interface to a portion of the domain model.

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

    > So what to call a Gateway+Repository+Validator class?

    Gateway+Repository+Validator+Kitchen Sink class?

    I may be having a laugh, but the point I am trying to make is that I feel you are all blowing this issue out of proportion, no? The Model [MVC] represents not one class in it's self but in reality it can represent an entire sub system, dependent of course, on complexity of a domain.

    Calling it a Model or appending Model onto the end of the class is wrong in so many ways; It's not only a bad name, in that it tells nothing, it's misleading; It doesn't represent a domain. For example, take a basic shopping cart? I have...

    Code:
    + ./
    + QCommerce
    + --- QCommerce_Basket
    + --- --- QCommerce_Basket_Item
    What you name your assoc. class(es) for News (as a few posts back) is pretty much upto yourself I suppose? Do you append the assoc. pattern name to a class, if you implement a pattern? I find that just as evil as appending Model

    I can't give any descriptive names for you to refer from as my imagination has trouble stretching that far as well (where is Marcus when you need him?), unfortunately.

    > How do you fetch out ALL newsposts?

    Typically, you would encapsulate the SQL (with, or without the logic) within the same class; I keep the logic out of the class in question, going by the name of the Interface, there shouldn't be any logic in there anyways...

    PHP Code:
    interface QStatement_Interface { ... } 
    I place the logic elsewhere, but your class could just as well contain the logic if you feel comfortable with it,

    PHP Code:
    // ...
    public function findById$id ) {
    $sql sprintf$this -> statement -> findByIdStatement(), (int) $id );
    $rs $this -> conn -> fetch$sql );
    // ...
    }

    public function 
    findByUsername$username ) {
    $sql sprintf$this -> statement -> findByUsernameStatement(), (string) $this -> conn -> escape$username ) );
    // ...
    }
    // etc 

  7. #32
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    702
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Dr Livingston View Post
    Umm...
    I have...
    Code:
    + ./
    + QCommerce
    + --- QCommerce_Basket
    + --- --- QCommerce_Basket_Item
    PHP Code:
    $basketModel $this->context->models->Basket;
    $basket $basketModel->find(27);
    $basketItem $basketModel->newItem();
    $basketItem->product 'Born to be wild';
    $basketItem->qty 3;
    $basket->addItem($basketItem);
    $basketModel->save($basket); 
    And your code for adding a new item to an existing basket would look like?

  8. #33
    SitePoint Zealot
    Join Date
    Sep 2005
    Posts
    122
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ahundiak View Post
    Repository does indeed cover the collection query portion.
    Gateway covers the basic CRUD portion.
    The Repository pattern covers CRUD as well as the collection query portion (well technically the R in CRUD is the "collection query portion".
    Perhaps it could be beneficial to refactor out the validation stuff to it's own class to maintain the single responsibility principle.

  9. #34
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    702
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by shea View Post
    The Repository pattern covers CRUD as well as the collection query portion (well technically the R in CRUD is the "collection query portion".
    Perhaps it could be beneficial to refactor out the validation stuff to it's own class to maintain the single responsibility principle.
    Found this on: http://domaindrivendesign.org/books/index.html
    For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type. Set up access through a well-known global interface. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store. Provide methods that select objects based on some criteria and return fully instantiated objects or collections of objects whose attribute values meet the criteria, thereby encapsulating the actual storage and query technology. Provide repositories only for AGGREGATE roots that actually need direct access. Keep the client focused on the model, delegating all object storage and access to the REPOSITORIES.
    So I guess a repository can indeed insert and update objects. Not so sure that being able to validate an object is really a new responsibility. You would expect some error checking to be done when storing an object. Of course the actual validation code would probably be in another class but thats the same concept as having the table gateways be in other classes as well.

    Just wish repository wasn't such a long word to type or that it had a decent abbreviation. Repo just does not seem to cut it.
    PHP Code:
    $basketRepository $this->context->repositories->Basket;
    $basket $basketRepository->find(27);
    $basketItem $basketRepository->newItem(); // Or maybe have a BasketItemRepository
    $basketItem->product 'Born to be wild';
    $basketItem->qty 3;
    $basket->addItem($basketItem);
    $basketRepository->save($basket); 

  10. #35
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    > And your code for adding a new item to an existing basket would look like?

    PHP Code:
    interface QCommerce_Basket_Interface {
            public function 
    addQCommerce_Basket_Item_Interface $item );
            public function 
    flush();
        }

    interface 
    QCommerce_Basket_Item_Interface {
            public function 
    increment();
            public function 
    amountOf();
            public function 
    getId();
        } 
    PHP Code:
    class QCommerce_Basket_Item implements QCommerce_Basket_Item_Interface {
            protected 
    $id;
            const 
    limit 9;
            
            public function 
    __construct$id$amount ) {
                
    $this -> amount $amount;
                
    $this -> id $id;
            }
            
            public function 
    getId() {
                return 
    $this -> id;
            }
            
            public function 
    priceOf() {
                return 
    $this -> price;
            }
            
            public function 
    amountOf() {
                return 
    $this -> amount;
            }
            
            public function 
    update$amount ) {
                if( 
    $this -> withinLimits$amount ) ) {
                    
    $this -> amount $amount;
                }
            }
            
            public function 
    increment() {
                
    $amount $this -> amount; ++$amount;
                if( 
    $this -> withinLimits$amount ) ) {
                    
    $this -> amount++;
                }
            }
            
            protected function 
    withinLimits$amount ) {
                if( 
    $amount <= self::limit ) {
                    return 
    true;
                }
                return 
    false;
            }
        } 
    I persist the basket as is within the SESSION and only export it to the database once checkout have been completed; I see no reason for persisting the basket on the database side of things during the shopping stage at least

  11. #36
    SitePoint Addict
    Join Date
    Apr 2004
    Location
    Melbourne
    Posts
    362
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ahundiak View Post
    Found this on: http://domaindrivendesign.org/books/index.html

    So I guess a repository can indeed insert and update objects. Not so sure that being able to validate an object is really a new responsibility. You would expect some error checking to be done when storing an object. Of course the actual validation code would probably be in another class but thats the same concept as having the table gateways be in other classes as well.
    Remember... use patterns to assist you in solving problems you have in making your code meet quality/requirement goals, not because its a pattern. You don't have to use the explicit meaning of it, more the general gist, if that's helping solve a problem you're having.


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
  •