SitePoint Sponsor

User Tag List

Page 1 of 11 12345 ... LastLast
Results 1 to 25 of 274
  1. #1
    SitePoint Addict JNKlein's Avatar
    Join Date
    Sep 2004
    Location
    New York, NY
    Posts
    258
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Data Access Layer - Is there a real seperation?

    This conversation started in the comments of HarryF's Blog, and I thought it would be worthwhile to move here to continue the conversation, since thats what this forum is for.

    This started as a response to Tony Marston's very interesting Development Infrastructure for PHP, which I highly recommend as reading even if you walk away disagreeing with his methodology.

    To bring you up to speed:

    Quote Originally Posted by JNKlein
    I read (everything on) your site, Tony, and found it very enlightening - thank you.

    A problem I continually have, when reading various literature on the subject or perusing sitepoint's forums or various informative web sites, is with the seperation between the Business Logic and Data Access Logic.

    Don't get me wrong - I get it; its a very worthwhile ideal to be able to switch the way you store your data and maintain the same business logic, or use your data in a new way by simply creating new components in the business logic without having to change the data access Logic.

    But the two seem inexorably tied together in a practical and realistic sense. After all, what is your business logic without data to work with, and at that, should your business logic really be able to handle ANY data you pass to it? Is that healthy?

    Let me use the example of the User class, something I'm sure we're all familiar with. Suppose one of the properties of a "user" is "username". You whip up your User class, then you whip up a UserMapper class, which has a method insert(User). The internals of this method inevitably make specific reference to the properties of a User object AND inevitably make specific reference to your method of storing the data (even with a DAO you need to specifically state where you are putting the info... "INSERT ... WHERE username = etc).

    So now, instead of releasing your data access from the tied-down clutches of your business logic, you've tied it down to both the business logic AND the extremely specific data storage mechanism.

    Perhaps what I am trying to understand is whether or not people are really serious when they talk about seperation of logic. When you add a new property to your theoretical user, you're going to have to add it in the User class, then add a place to put it in the data storage mechanism, and lastly, you've got to change the functions that map your class to your data storage.

    Perhaps I'm missing the point here - so please, set my disillusioned mind to rest by clarifying what I'm getting wrong here.

    I do see the benefits in being able to use the User class in any number of ways and always being able to instantiate a UserMapper to insert(User), but what is the difference from having this code internal to the User class in a practical sense (as opposed to the "because OOP is right" reasoning).

    Posted by: JNKlein Nov 4th, 2004 @ 1:58 PM MST
    Quote Originally Posted by Tony Marston
    In reply to the previous post from JNKlein here are my (arrogant?) views on the subject of separating business logic from data access logic:

    The primary purpose of having a separate object in the data access layer (sometimes known as a Data Access Object or DAO) is that is should be possible to switch the entire application from one data source to another simply by changing this one component. Thus if I want to switch my application from MySQL to PostgreSQL (or whatever) I simply change my DAO.

    In order to make this work in practice my own implementation is as follows:

    (a) Each business entity (eg: customer, product, invoice) has its own class. This identifies the structure of the associated database table plus all the business rules required by that entity. Each of these is actually a subclass of a generic table class which contains sharable code that can be applied to any database table.

    (b) When the business object gets instructions to update the database it does so via an insertRecord(), updateRecord(), or deleteRecord() method which contains the entire $_POST array. This is validated according to whatever rules have been defined within that particular subclass. If there are no errors it will talk to the relavant DAO in order to perform the database update.

    (c) The DAO also has the insertRecord(), updateRecord() and deleteRecord() methods, but as well as the validated contents of the $_POST array it is also given a second array which contains all the table structure details. Using these two arrays it is easy to construct the relevant SQL query string before calling the relevant database API.

    In this way my business object contains business rules, but no calls to database APIs, and my DAO contains calls to database APIs but no business rules. This is clear separation of logic.

    Switching from one DBMS to another is simple to achieve in my infrastructure. In my generic table superclass I have a variable called $dbms_engine which is set to 'mysql' or 'postgresql' or whatever. This will then apply to all database tables unless overridden in any individual subclass. When the business object wants to talk to the data access object it first needs to instantiate an object from a class which is defined within a separate include() file. The name of this file is in the format 'dml.<engine>.class.inc' where <engine> is replaced by the contents of variable $dbms_engine. I have a separate version of this include() file for every DBMS that I use. All I need to do before accessing a new DBMS is to create a new version of the 'dml.<engine>.class.inc' file and I'm up and running.

    Another advantage of this mechanism is that it would even be possible to talk to different database tables through different DBMS engines within the same transaction. Hows that for flexibility?

    In case you want to see these (arrogant?) theories put into practice I have created a sample application which is described in http://www.tonymarston.net/php-mysql...plication.html. This contains links where you can run the application online as well as download all the source code and run it on your own machine. You can then examine the source code and tell me what I am doing wrong.

    BTW, in your example you mentioned have a User class and a UserMapper class. Why two? I can put everything I need into a single class, which is what encapsulation is supposed to be about.

    Posted by: Tony Marston from tonymarston.net Nov 5th, 2004 @ 4:29 AM MST
    Quote Originally Posted by Cochambre
    I 've considered the logic layers separation in a Web Application many times. And the only thing that keeps me from efectively using it is that it's main function (independence of user interfase, business rules and data storage/retrieval) only helps when migrating or extending to other script-language/data engine/platform. But this only happens very very few times in an Application Lifetime. In the other hand, this versatility has the invonvenience of not taking advantage of each platform/engine/language optimization benefits (which usually are not compatible between them), and this lowers the application performance, affecting the consecuences directly to the users. So the question here is Versatility vs Performance. I believe that we must not punish the users by using this "development shurtcuts". This, of course, is considering that you care about your application performance. (i'm sorry if I misspelled some words. I'm from Argentina)

    Posted by: Cochambre Nov 5th, 2004 @ 2:18 PM MST
    Quote Originally Posted by Tony Marston
    Oochambre said: <quote> The separation of presentaion, business and data access logic only helps when migrating or extending to another script-language/data engine/platform. But this only happens very very few times in an Application Lifetime. </quote>

    Your view of the benefits of the 3 tier architecture are very narrow as in reality they are not restricted to changes in the scripting language, database engine or platform.

    As my article is about building web applications with PHP, and PHP can run on many platforms, any argument about not being optimized for a particular platform is rather empty.

    Being able to change from one database engine to another by changing just one component is not just a fancy expensive option that is rarely used. Take the case of MySQL, for example. For versions up to 4.0 you must use the mysql_* functions, but for 4.1 and above you must use the mysqli_* functions. How complicated would that be if you had hundreds of scripts to change instead of just one? You must also consider the case where a supplier creates an application which is then run on customers own machines with the database of their choice. If it is coded so that it only runs with MySQL but they actually want PostreSQL or Oracle or whatever then how difficult would it be to cater for the customer's needs?

    Having presentation logic separated from business logic has other advantages besides a switch to a totally different user interface device (for example, from client/server to the web). In the first place the creation of efficient, artistic and user-friendly web pages requires more than a passing knowledge of (X)HTML and CSS (and perhaps javascript) which a lot of PHP coders are without. The people with these skills may have little or no abilities with PHP, so by having separate layers you can have a different set of experts to deal with each layer. Another more common requirement is to have the ability to change the style of a web application with relative ease. By ensuring that all output is strict XHTML with all style specified in an external CSS stylesheet it is possible to change the entire 'look' of an application by changing a single CSS file.

    In my infrastructure all my XHTML output is produced from a small set of generic XSL stylesheets, which means that should I need to make changes to my 350+ screens that cannot be done by altering the CSS file then all I have to do is change my generic XSL stylesheets, which are currently about 10 in number. You may think that such changes are rare, but what about when the time comes to convert your existing web application from HTML forms to XFORMS, the latest W3C standard? I can do that by changing 10 XSL stylesheets. Can you?

    Posted by: Tony Marston from tonymarston.net Nov 6th, 2004 @ 5:24 AM MST
    Now, to continue ...

    To respond to Tony's question about why I seperated the User and UserMapper class; if you have a User class that performs some business logic that doesn't interact with the database - suppose a hypothetical printUserName() method that just spits out the current $user->username, wouldn't you want a seperate class that mapped a user to the database, either inserting or deleting or what-have-you? Then, if you needed to add more functionality on the business logic end, you would only change the User class (not the UserMapper class) to have another method, suppose printUserEmail(). This way, you can extend or refactor your User business logic (maintaining the same interface), without changing anything about the data access.

    This is how I interpret the "seperation of data access and business logic".

    Maybe I'm not doing a good job of explaining my logic here - George Schlossangle says it well in his "Advanced PHP" chapter on this very subject (which, again, I recommend). Maybe someone else can clarify?

    Regardless, my question to Tony is this - if you have your business logic and data access logic in the same class, can they be seperate? In reference to the business logic, Tony said "Each business entity (eg: customer, product, invoice) has its own class. This identifies the structure of the associated database table..." - I think this is the part I'm having trouble understanding, because where is the seperation of logic if the business entity knows both the business logic and must know the structure of the associated data storage mechanism.

    And now, a seperate question - what is the point of a DAO (chose your favorite - ADODB or PEAR DB) that probably won't make it any easier to change what database you're using, since there is inevitably still hardcoded some query that doesn't work the same in mySQL, msSQL, PostreSQL, and Oracle, let alone just two of the above. Just because you execute($query) doesn't mean $query will actually work.

  2. #2
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Off Topic:

    I believe that we must not punish the users by using this "development shurtcuts".


    No offence though I wouldn't consider them to be shortcuts? Fair enough about the point you made about adding functionality to the core of an application where it may not be needed, though you do not really know this for certain 3 years down the line.

    This is more of a design issue than a development issue in my view, but it's always possible that once an application has been in use for a while, it'll grow and evolve, requireing for example, a better database server.

    You need to account for this possibility, even if it (presently) sounds remote.

    Back on topic then, I agree that a degree of seperation is a basic requirement for todays applications. I'm still looking at the url in question, very interesting it is so will have more to say once I've digested it all

  3. #3
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think this is the part I'm having trouble understanding, because where is the seperation of logic if the business entity knows both the business logic and must know the structure of the associated data storage mechanism.
    Yer, can see where your going with this But in my thinking, would the actual database table (columns in this case) actual change as well? Just because your moving to a new(er) database server?

    I think in my view the seperation for the most part is in removing the data source from the business logic.

    On this same subject I'm looking into the same thing with Reflection, so I do not need to have the database table column names within a class, if I am thinking right anyways.

  4. #4
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by JNKlein
    To respond to Tony's question about why I seperated the User and UserMapper class; if you have a User class that performs some business logic that doesn't interact with the database - suppose a hypothetical printUserName() method that just spits out the current $user->username, wouldn't you want a seperate class that mapped a user to the database, either inserting or deleting or what-have-you? Then, if you needed to add more functionality on the business logic end, you would only change the User class (not the UserMapper class) to have another method, suppose printUserEmail(). This way, you can extend or refactor your User business logic (maintaining the same interface), without changing anything about the data access.
    Surely if you have information or processing for a user contained in more than one class you are breaking encapsulation? There is no rule that says you must have one class which maps an object to a database and one which does not. I have all the information (properties and methods) for a USER in a single USER class. Within this class I may have a method such as insertUser() which adds a user's data to the database, and I may have another method sendEmail() which sends the user an email. Just because the second method does not communicate with the database does not mean that I cannot include it with a method which does.

    To follow the rules of encapsulation all the methods which deal with an object must be defined within a single class. It does not matter if one method talks to a database, one method sends an email, one method dials a telephone number and yet another method changes the television channel. The internals of each method are supposed to be irrelevant.


    Quote Originally Posted by JNKlein
    if you have your business logic and data access logic in the same class, can they be seperate?
    Each database table class contains both business rules in the form of custom code and a description of the table's physical structure as described in $fieldspec array. By containing all this information within a single class I am adhering to one of the fundamental principles of OOP which is encapsulation.

    Although this information is defined within a business object it is not used to access the persistent data store (i.e. database) until it is passed to my Data Access Object (DML class). This uses the information given to it - the table structure and some data - to construct the relevant query and then pass it to the specified database engine via the relevant API.

    There is nothing in the rules of OOP that says I cannot define information in one object, then pass it to another for processing. It is where this information is actually processed which is important. My $fieldspec array actually contains information which is used in three different places:
    1. Some information is passed to a validation object to perform primary validation.
    2. Some information is passed to the XSL transformation to help build the HTML control for each field.
    3. Some information is passed to the DAO to communicate with the database.


    If I were to define this information in three separate places surely this would break encapsulation?

    Remember that my data access object contains no information about any database table whatsoever, so this information has to be passed to it from an external source. This does not make the external source part of the data access object, now does it? Similarly the XSL stylesheet, which is used to construct the XHTML output, is useless without an XML file containing the data. This data originates from the business layer, but that does not make the business layer part of the XSL stylesheet, now does it?

    If you are prepared to treat the term logic as where information is processed rather than where information originates you will see that my usage of the term 'separation of logic' is entirely justified whereas yours is questionable.


    Quote Originally Posted by JNKlein
    What is the point of a DAO (chose your favorite - ADODB or PEAR DB) that probably won't make it any easier to change what database you're using, since there is inevitably still hardcoded some query that doesn't work the same in mySQL, msSQL, PostreSQL, and Oracle, let alone just two of the above. Just because you execute($query) doesn't mean $query will actually work.
    It depends on how you have designed your DAO to work. In my case my business object does not construct an SQL query then pass it to the DAO for processing. It passes the components of the query to the DAO, and it is up to the DAO to construct the actual query string. I have a separate DAO class for each database engine, so each class is able to construct the query according to the requirements of that particular database engine.

  5. #5
    SitePoint Member
    Join Date
    Jul 2004
    Location
    Norway
    Posts
    13
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Version0-00e
    Yer, can see where your going with this But in my thinking, would the actual database table (columns in this case) actual change as well? Just because your moving to a new(er) database server?
    Yes, the schema for the database could also change. It is not sure that you are moving from a relational database to another relational database, but maybe you are moving to an object relational dbms or object-orientet dbms or an XML database or som other type of dbms.
    The limits of my language are the limits of my world.
    (Wittgenstein)

  6. #6
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Using your example of a data mapper between the domain model (User class) and the data model (database)... If you push the specific mapping code into a data mapper class you only have to make changes in one place. If there is a bi-directional dependency between the domain object and the data access object you have to make changes in two places. The business objects care about business logic and data not how to get the data. The data access objects care about how to get the data not what to do with it. It isn't just a logical separation of business logic and data access logic, it is a separation of concerns.

    JT

  7. #7
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    In my case my business object does not construct an SQL query then pass it to the DAO for processing. It passes the components of the query to the DAO, and it is up to the DAO to construct the actual query string. I have a separate DAO class for each database engine, so each class is able to construct the query according to the requirements of that particular database engine.
    I like this idea - a lot

    The business objects care about business logic and data not how to get the data. The data access objects care about how to get the data not what to do with it. It isn't just a logical separation of business logic and data access logic, it is a separation of concerns.
    Excellent description, are you willing to post some examples? If your saying the DAO is only concerned about getting the data (from business logic) is the db API responsible for what to do with the data such as an insert?

  8. #8
    SitePoint Zealot
    Join Date
    Jul 2003
    Location
    Los Angeles
    Posts
    199
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by JNKlein
    And now, a seperate question - what is the point of a DAO (chose your favorite - ADODB or PEAR DB) that probably won't make it any easier to change what database you're using, since there is inevitably still hardcoded some query that doesn't work the same in mySQL, msSQL, PostreSQL, and Oracle, let alone just two of the above. Just because you execute($query) doesn't mean $query will actually work.
    No matter how much you encapsulate logic there is no magical bullet to solve everything. ADODB, PEAR, Creole, etc cannot handle 100% of every situation between all databases but they sure as hell can get pretty close. Take a simple hard-coded query in mysqli
    PHP Code:

    <?php
    $mysqli 
    = new mysqli('localhost''user''password''dbname');

    if( 
    $result $mysqli->query('SELECT * from user LIMIT 5, 0') )
    {
        while( 
    $row $result->fetch_assoc() ){
            
    print_r($row);
        }
    }
    ?>
    If you switched to a database abstraction layer and tried to use that statement in Postgres it will choke since there is no comma separator after LIMIT and you must use the OFFSET keyword. Any decent database abstraction layer can easily take care of this however. Using Creole for example.
    PHP Code:
    <?php
    $stmt 
    $con->createStatement();
    $stmt->setLimit(5);
    $stmt->setOffset(0);
    $result $stmt->executeQuery('SELECT * FROM user');

    foreach( 
    $result as $user)
    {
        
    // process here
    }
    ?>
    Which will pass 'SELECT * FROM user LIMIT 5 OFFSET 0' to the postgres driver.

    However there are certain situations where it's not so easy and it requires the programmer to do a switch on the database type and handle a special case but overall a good abstraction layer makes your application that much more portable.

    You can apply the same thing to one level higher with an ORM where you define your database tables in XML and run a generator to create classes to help you access your database tables. It can save you a lot of time but can't cover every single situation. Propel for instance which I really love requires manual intervention for returning data from functions like COUNT, MAX, etc when you mix it with results from entities:
    Code:
    SELECT 'c.cat_id, c.cat_title, COUNT(photo_id) as cnt
                    FROM 
                        gallery_category AS c
                    LEFT JOIN 
                        gallery_photos as p
                    ON
                        p.cat_id = c.cat_id
                    GROUP BY
                        c.cat_id, c.cat_title'
    results of functions like count don't fit anywhere inside an entity so you have to handle it by hand and end up circumventing entity objects like this:
    PHP Code:
    <?php
    /*
    * Fetch the categories with the count of the number of photos 
    * that belong to each of them.
    *
    * @return array
    * @throws PropelException
    */
    class GalleryCategoryPeer extends BaseGalleryCategoryPeer
    {
        function 
    findCategories($limit$offset)
        {
            
    $con Propel::getConnection();

            
    $sql 'SELECT c.cat_id, c.cat_title, count(photo_id) as cnt
                    FROM 
                        gallery_category AS c
                    LEFT JOIN 
                        gallery_photos as p
                    ON
                        p.cat_id = c.cat_id
                    GROUP BY
                        c.cat_id, c.cat_title'
    ;

            
    $stmt $con->createStatement();
            
    $stmt->setLimit($limit);
            
    $stmt->setOffset($offset);

            
    // Hand code the query to return just the cat_id, cat_title, cnt
            
    $rs $stmt->executeQuery($sqlResultSet::FETCHMODE_ASSOC);
            while( 
    $rs->next() )
            {
                
    $row $rs->getRow();
                
    $categories[] = $row;
            }
            return 
    $categories;
        }
    }
    ?>
    Hopefully they will be able to handle that smoother in a future version of Propel but in the meantime I can live with it for all the other conveniences it offers me.

    And as for the issue of DataMappers, again it's ONE possible design pattern but not the magical one. There are many ways to skin a cat including ActiveRecords and the RDG+TDG approach that Propel takes. For some things I use hand coded DataMappers for others I use raw SQL(eww yea gross but it's fast as hell to code) and for a project I'm working on now I use Propel.

    There isn't one answer to fit everybody's needs.

  9. #9
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Tony Marston
    In my case my business object does not construct an SQL query then pass it to the DAO for processing. It passes the components of the query to the DAO, and it is up to the DAO to construct the actual query string. I have a separate DAO class for each database engine, so each class is able to construct the query according to the requirements of that particular database engine.
    Quote Originally Posted by Version0-00e
    I like this idea - a lot. Are you willing to post some examples?
    Take a look at A Sample PHP Application which contains links to my sample application which you can run online. You can also download the source code so you can discover how it works.

  10. #10
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Version0-00e
    Excellent description, are you willing to post some examples? If your saying the DAO is only concerned about getting the data (from business logic) is the db API responsible for what to do with the data such as an insert?
    A data mapper is where you would put code that maps between the data model and the domain model. A data mapper could access the database through a low-level data access pattern (e.g. Table Data or Row Data Gateway) or use SQL directly. The data mapper hides the code required to map into your domain model. The data mapper knows about the domain model and the data model, but domain model and the data model do not know that the mapper exists.

    Code:
    Domain Model <-- Data Mapper --> Data Model
    For example, you could ask the mapper for a Person object with and ID of "1". Then you could change the name of the person and give it back to the mapper to update the database. The mapper is responsible for making sure that the update happens. All you care about is getting and using the Person object with its state and behavior. Which again takes us back to the idea of "separation of concerns".

    PHP Code:
    <?php
    // Find the person with an ID of "1"
    $mapper =& new PersonMapper($db);
    $person $mapper->findById(1);

    // Do something with the person here
    $person->setName("John");

    // Tell the mapper to update the data model (the data model does not have to be a database...)
    $mapper->update($person);
    ?>
    JT
    Last edited by seratonin; Nov 10, 2004 at 21:36.

  11. #11
    SitePoint Zealot
    Join Date
    Jul 2003
    Location
    Los Angeles
    Posts
    199
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I made a post about using a datamapper pattern here http://www.sitepoint.com/forums/showthread.php?t=208510 It's a simple example with code gutted out that I think is pretty clear.

    Just keep an open mind about these things. DataMappers are one possible solution and may not appeal to everyone.

  12. #12
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Tony Marston
    Surely if you have information or processing for a user contained in more than one class you are breaking encapsulation? There is no rule that says you must have one class which maps an object to a database and one which does not. I have all the information (properties and methods) for a USER in a single USER class. Within this class I may have a method such as insertUser() which adds a user's data to the database, and I may have another method sendEmail() which sends the user an email. Just because the second method does not communicate with the database does not mean that I cannot include it with a method which does.

    To follow the rules of encapsulation all the methods which deal with an object must be defined within a single class. It does not matter if one method talks to a database, one method sends an email, one method dials a telephone number and yet another method changes the television channel. The internals of each method are supposed to be irrelevant.
    Yeh, I agree with this. However, if you want to get a list of users whose first name is 'John', do you use this below? Because logically does it make sense for a user to return a list/resultset of users?

    PHP Code:
    $result_iterator User::GetByFirstName('John'); 
    But yeh, I think encapsulation should be highest priority

  13. #13
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lazy yogi
    However, if you want to get a list of users whose first name is 'John', do you use this below?
    In my infrastructure I would use the following:
    PHP Code:
    $object = new User;
    $where "first_name='John'";
    $data $object->getdata($where); 
    Notice here that the $where string could be anything, so the getData() method is completely general purpose.

  14. #14
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lazy_yogi
    However, if you want to get a list of users whose first name is 'John', do you use this below?
    The user (domain object) is not what should return a collection of User objects. This is the responsibility of the UserMapper:

    PHP Code:
    <?php
    $mapper 
    =& new UserMapper($db);

    // returns an array of User objects
    $users $mapper->findUsersByName("John");

    foreach (
    $users as $user) {
        echo 
    $user->getId();
    }
    ?>
    JT

  15. #15
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The Data Row Gateway if I remember is for returning only the one row of data?

    In that case, isn't this a Data Row Gateway,

    PHP Code:
    $object = new User
    $where "first_name='John'"
    $data $object->getdata($where); 
    In which case is wrong no? Would need to look at Tony's script for myself to determine this though

  16. #16
    SitePoint Zealot
    Join Date
    Jul 2003
    Location
    Los Angeles
    Posts
    199
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    And now to really confuse you...the Propel way.

    PHP Code:
    $criteria = new Criteria();
    $criteria->add(UserPeer::NAME"%John%"Criteria::LIKE);
    $users UserPeer::doSelect($criteria);

    foreach(
    $users as $user)
    {
        echo 
    $user->getId();

        
    // Propel entity classes can save state so we could do this:
        // $user->setLastName('Smith');
        // $user->save();

    or you can write your own method and add it to the generated stub peer class.
    PHP Code:
    $users UserPeer::findUsersByName("John"); 
    Fun eh?

  17. #17
    ********* 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 Tony Marston
    Surely if you have information or processing for a user contained in more than one class you are breaking encapsulation?
    Encapsulation is about hiding implementation, which includes data. There is no requirement for every aspect of the "User" concept to be in a single class. In fact this is damaging, because such a kitchen sink class would be very inflexible. You are basically describing the Facade pattern, which is seldom used, never mind it being any kind of rule.

    Flexible classes have a single role within the system, a concept called "cohesion". However you don't usually want every single behaviour of a concept in a separate class either. That would be overkill. For that reason we usually split the concept into just enough classes to do the job in the myriad ways we need.

    A DataMapper splits persistence off from the domain object leaving both classes more cohesive. The price you pay is extra client code handling two objects. What you gain is divide and conquer on the complexity of the code. Smaller classes are easier to get right. You can also swap them around. You can use the application with different databases just by choosing a different mapper at run time without touching any of the domain object code. This makes it easier to test as well.

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

  18. #18
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Version0-00e
    The Data Row Gateway if I remember is for returning only the one row of data?

    In that case, isn't this a Data Row Gateway,

    PHP Code:
    $object = new User
    $where "first_name='John'"
    $data $object->getdata($where); 
    In which case is wrong no? Would need to look at Tony's script for myself to determine this though
    The Row Data Gateway represents/manages one row in the database. The Table Data Gateway represents/manages an entire table. They are both low-level data access patterns. They operate on the data model exclusively. The Data Mapper pattern, however, is a higher-level pattern which maps between the data model and the domain model.

    JT

  19. #19
    SitePoint Enthusiast MickoZ's Avatar
    Join Date
    Jul 2004
    Location
    Canada, Qc
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Tony, I readed a lot of your stuff tonight (mainly the 2 database/php articles + your FAQ). I like your style, your boldness (often people that are bold in their comment and not afraid to joke-around or criticize are very good, because they have to make up for their comment and attitude).

    I probably have had some comment and wondering about your way to do stuff while reading but I tried to see the big picture rather than do my often critic or try to test everything. But since you seem to like to be pragmatic, just doing a simple stuff in your sample application:

    Go there

    http://www.tonymarston.net/sample/person_add.php

    Enter anything in a field, let's say First name. Then click ENTER.

    It leads to a tree structure popup page.

    Uh oh?

    This can probably be explained, but I tried to be a simple user and just test your application and found this. Either I am lucky or what? ;-)

    No matter, what I readtonight was interesting, just your attitude is a great thing IMHO ;-) There is gazillions of way to do and sometime there is 2 way that is good, it all depend of your criteria of good and since you said it is like art (and I agree), then it is maybe just a matter of taste? ;-)

  20. #20
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by MickoZ
    Go there:

    http://www.tonymarston.net/sample/person_add.php

    Enter anything in a field, let's say First name. Then click ENTER.

    It leads to a tree structure popup page.

    Uh oh?
    Pressing the ENTER key is not the same as pressing the SUBMIT button. It actually presses the first available button (*) within the form which, in this case, is the popup button in the Organisation field.

    (*) Note: This behaviour is different with different browsers, so it is wrong to assume that the ENTER key is the same as the SUBMIT button, especially when the form contains more than one button.
    Last edited by Tony Marston; Nov 11, 2004 at 07:25.

  21. #21
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Encapsulation is about hiding implementation, which includes data. There is no requirement for every aspect of the "User" concept to be in a single class.
    According to this OOP Tutorial the term 'encapsulation' is defined as
    Encapsulation means that the class must define all the properties and methods which are common to all objects of that class. All those properties and methods must exist inside a single container or 'capsule', and must not be distributed across multiple locations.
    There is nothing in the principles of OOP which says that different aspects of an object must be contained within different classes, in fact it states quite the contrary. Therefore I consider your opinion to be totally wrong.

  22. #22
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by seratonin
    The user (domain object) is not what should return a collection of User objects. This is the responsibility of the UserMapper.
    I totally disagree. All communication regarding a user, whether it be reading, inserting, updating or deleting, goes through a single USER object. It is then up to this object to decide how to satisfy the particular request. If you have to have a separate UserMapper class (which I would not) then surely this should be accessed from the User class itself?

    Note that my User class does not access the database directly - it goes through a data access object which is reponsible for generating the actual SQL query. Perhaps this serves the same functionality as your userMapper?
    Last edited by Tony Marston; Nov 11, 2004 at 08:49.

  23. #23
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Therefore I consider your opinion to be totally wrong.


    Now, that is arrogance, and as one person after following many posts by lastcraft, I'd have to disagree with your statement Tony.

    Lastcraft has basically explained encapsulation, and from this statement is something I can take from it as I've near as damn it read something much along the same lines before elsewhere, Thinking In Java 3rd Edition if I remember?

    Take it easy, you'll end up with a bad reputation, and as someone talking from experience ( ) it doesn't do you any good around this parts

  24. #24
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Version0-00e
    Now that is arrogance
    How can I be arrogant for following the principle of encasulation which specifically states that all methods and properties for an object should be encapsulated in a single class? Thus if I want to do anything with a User I invoke a method on a single User class. I do not have a separate class which involves database access and one which does not. It is up to the User class to decide for itself how to satisfy that method. If it involves accessing a database, then so be it. If it involves pulling data out of thin air, then so be it. How a method is implemented is supposed to be irrelevant.

    If you believe that encapsulation means having properties and methods contained within more than one class then you are hopelessly wrong. If my bringing this to your attention makes me arrogant, then so be it. What does it make you?

  25. #25
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Tony Marston
    I totally disagree. All communication regarding a user, whether it be reading, inserting, updating or deleting, goes through a single USER object. It is then up to this object to decide how to satisfy the particular request. If you have to have a separate UserMapper class (which I would not) then surely this should be accessed from the User class itself?

    Note that my User class does not access the database directly - it goes through a data access object which is reponsible for generating the actual SQL query. Perhaps this serves the same functionality as your userMapper?
    Well, if that is the case then you do not have a true domain model (at least in the PoEAA sense). Which is fine. Your implementation is closer to the ActiveRecord pattern which mixes domain logic and data access logic.

    JT


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
  •