SitePoint Sponsor

User Tag List

Page 1 of 5 12345 LastLast
Results 1 to 25 of 118

Thread: ActiveRecords

  1. #1
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    ActiveRecords

    Hi!

    I've been reading up on ActiveRecords and have a few questions.

    1. What are the cons of using it? Most articles seems to be written from a Ruby perspective and only speek of the positives. The advantages I see are basically that you don't need to write specific inserts/updates/deletes and you rely on finders to do most of the selection. Associations are probably powerful as well, but I have yet to study them in detail. Surely, there must be a downside as well?

    2. Because of the whole static problem with php, I created a separate Finder class with static findAll, findById, findBySQL etc methods. I call these from my controllers like so:
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    This seems acceptable to me. How are others coping with this problem?

    3. I have a base ActiveRecord class that all other records inherit from. In the base class I have my save() and delete() functions. A record represents a row in a table. Now, the table-columns need to be declared class members of the record, so the generic save() function knows what fields to insert into.

    To separate these properties from other ActiveRecord properties, such as $table or $hasMany, I created an array called $properties where the fields are stored. Like so:
    PHP Code:
    class ActiveRecord
    {
        protected 
    $_table# name of table
        
    protected $_properties = array(); # a record's properties
        
    public function __construct($properties = array())
        {
            foreach (
    $_properties as $property => $value)
            {
                
    $this->_properties[$property] = $value;
            }
        }

    Is that a good idea? I don't see how else to do it.

    Now, if people could set whatever keys they wanted into the array, the save() function would fail (it would try to update fields that don't exist in the table). Because of that, each "column" needs to be declared in the extending Record class:
    PHP Code:
    class Blog extends ActiveRecord
    {
        protected 
    $_properties = array('id' null'title' null'text' null);

    And then I use the __set() method in the base ActiveRecord class like so:
    PHP Code:
    public function __set($property$value)
    {
        if (
    array_key_exists($property$this->_properties))
        {
            
    $this->_properties[$property] = $value;
        }

    It's been hard trying to find any good articles about this, so I'd appreciate any input. I'm still waiting for my copy of PoEAA.
    Last edited by pakmannen; Sep 6, 2007 at 08:50.

  2. #2
    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 pakmannen View Post
    What are the cons of using it? Most articles seems to be written from a Ruby perspective and only speek of the positives. The advantages I see are basically that you don't need to write specific inserts/updates/deletes and you rely on finders to do most of the selection. Associations are probably powerful as well, but I have yet to study them in detail. Surely, there must be a downside as well?
    Depends on what you compare against. ActiveRecord is one way (pattern) of encapsulating data access. This can help to simplify your application, by creating an abstraction. It also has the benefit of greater flexibility between data access and business logic. One consequence of this is, that you can replace the data access layer with a different implementation, without changing the rest of your application.

    ActiveRecord is a simple way of separating data access from business logic. It can quickly become cluttered. A table data gateway or a data mapper solves this task more elegantly, but are also more complex patterns. Whether you need to use them, depends on the complexity of your application, as well as personal taste.

    Quote Originally Posted by pakmannen View Post
    Because of the whole static problem with php, I created a separate Finder class with static findAll, findById, findBySQL etc methods. I call these from my controllers like so:
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    This seems acceptable to me. How are others coping with this problem?
    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.

  3. #3
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    It also has the benefit of greater flexibility between data access and business logic ... ActiveRecord is a simple way of separating data access from business logic
    Let me see if I understand these terms correctly. Data access = the layer that access data from the database, that is, the finders? Business logic = the layer that inserts/updates/deletes from the database, the ActiveRecord?

    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.
    It seems kind of stupid to create an object whose sole purpose is to return another object. Also, I think Fowler says somewhere that Finders should be static methods? What's so bad about finders being "global"?

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

    > Let me see if I understand these terms correctly.

    In the case of the Active Record, what is particular special about it, is that business logic also resides on the Active Record in question, whereas with another domain pattern, as suggested by Kyber, the business logic would otherwise be encapsulated elsewhere.

    Business logic may be something such as to verify that a user is logged in for example? That is, a comparison of a database row against a users credentials, such as username and password.

    Another example, would be to keep a tally of a number of comments against a given blog post. You should now have a better picture of what I mean by business logic?

    The problem in my view is that Active Record can easily become bloated. That and that the Active Record in my mind, wasn't particularly well thought out in regards to database table relationships.

    As to RoR, if you do use that framework, your basically stuck with Active Record, as far as I can tell. I don't use RoR so that isn't my problem

    > I'm still waiting for my copy of PoEAA.

    I'm still waiting on the follow up, which goes further into domain modeling, and how patterns affect the design of a domain.
    Last edited by Dr Livingston; Sep 6, 2007 at 10:45. Reason: Added comment

  5. #5
    SitePoint Member
    Join Date
    Jul 2006
    Location
    Prague, Czech republic
    Posts
    16
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pakmannen View Post
    Let me see if I understand these terms correctly. Data access = the layer that access data from the database, that is, the finders? Business logic = the layer that inserts/updates/deletes from the database, the ActiveRecord?
    As I see it:
    Data access = the layer that works with database tables and records.
    Business logic = the layer that works with blogs and users.

  6. #6
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pakmannen View Post
    1. What are the cons of using it?
    There are three main ones:

    The first is that you end up with a 1 to 1 relationship between models and database tables. This can be problematic if your model frequently need to pull from multiple tables, or when you're dealing with a legacy database schemas.

    The second is performance; if your activerecord implementation isn't well designed, you can often run into 1+N problems, where you're performing multiple queries when you only really need two.

    The third is that you're mixing your database access with your business logic, which bothers some people.

    Speaking of business logic, I don't authentication or authorization are good examples, as I would consider those to be application logic. Business logic is things like calculating shipping costs based on client location and package size.

    Quote Originally Posted by pakmannen View Post
    2. Because of the whole static problem with php, I created a separate Finder class with static findAll, findById, findBySQL etc methods. I call these from my controllers like so:
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    This seems acceptable to me. How are others coping with this problem?
    It's important to note that there are no static calls in ruby; classes are objects, and Blog.findAll() is a class method (as opposed to an instance method).

    My problem with this approach (apart from the other issues with static calls) is that you can't write specific finder methods for your different models. For example, you might want to Blog.findLatestPosts(), and there's no simple way to do that with static calls. So the static approach seems convenient at first because you're saving yourself the trouble of creating objects, but it's very inflexible.

    The solution I'm considering is to use a registry of finders, so that you don't have to create a new object for each find call. Something like

    PHP Code:

    $registry
    ->finders->blog->findLatestPosts(); 
    Quote Originally Posted by pakmannen View Post
    3. I have a base ActiveRecord class that all other records inherit from. In the base class I have my save() and delete() functions...
    That's pretty much what I'm doing; a have an array of properties, and a separate array of column objects. The column objects are generated automatically via a DESCRIBE query, and provide additional information, such as default values. When the save method is called, I iterate over the columns array and save the relevant properties. The means that the model can have properties that are not present in the table, and it won't cause any problems (they're simply not saved)

  7. #7
    SitePoint Addict
    Join Date
    Aug 2007
    Location
    GR
    Posts
    352
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.
    Statics are used when you want a set of functions that are not associated with an object.

  8. #8
    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 _Steve_ View Post
    Statics are used when you want a set of functions that are not associated with an object.
    True. And if you program object oriented, all functions are associated with an object.

    Quote Originally Posted by pakmannen View Post
    What's so bad about finders being "global"?
    Global symbols makes the code inflexible, and introduces dependencies, which aren't explicit. The latter can lead to unforeseen side effects. It's actually quite hard to explain why globals are bad, with out getting very abstract and academic. This is because global symbols aren't as big a problem in a simple system (Which programming examples always are).

  9. #9
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees View Post
    My problem with this approach (apart from the other issues with static calls) is that you can't write specific finder methods for your different models. For example, you might want to Blog.findLatestPosts(), and there's no simple way to do that with static calls. So the static approach seems convenient at first because you're saving yourself the trouble of creating objects, but it's very inflexible.
    I have designed a class "supertype" (ideally probably an interface, in practice an abstract class), called "collection", which holds the information about a, well, collection of objects. The data is collected (from the db) at some point and (in current implementation) held internally as an array; when a particular item is requested the collection instantiates a specific item class (which currently employs active record, but it doesn't have to).

    In other words, a collection is a separate object from its items, and there is "findAll" static calls, as the Item class is not (and should not be) responsible for gathering collections of itself.

    I am a strong proponent of strong class vs. instance dichotomy, which many people tend to neglect. In my experience -- both programming and real-life -- it is extremely rarely that a type of objects does anything without it being done by its actual representatives. Static members have their place, but in almost all cases as programmer's shortcuts and conveniences, and not as actual class properties.

  10. #10
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Lo and behold, my copy of PoEAA arrived today. I'm ploughing through the first chapters now, which deals with domain logic and mapping to databases. It's nice to finally understand a bit about the terminology.

    The patterns he talks about are Row Data Gateway, Table Data Gateway, Active Record and Data Mapper. Active Record and Row Data Gateway are identical, except that Active Records also include domain logic. That is to say:
    PHP Code:
    class User # this could be a row data gateway...
    {
        
    $name;
        
    $email;

        function 
    insert();
        function 
    isOnline(); # what's this? domain logic! means we've got an active record

    Which is basically what Dr Livingstone already said. I can see that some people would prefer to keep the domain logic separate.

    You could still use Active Records, Row Data Gateways and Table Data Gateways when your Domain Model evolves and no longer corresponds with the database table structure, but it seems that a Data Mapper would be the logical choice in such a scenario. They do seem more complex though, so I think I will focus on the other patterns for now.

    Also, as for Table Gateways vs Row Gateways/Active Records I guess it depends on if your application mostly deals with result sets or rows?

    I know I completely ignored the static debate but I'm too tired right now..

  11. #11
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.
    Instances are variables, frequently global, and therefore a bad choice

    (btw, Fowler uses static methods without hesitation ...)

  12. #12
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok then.... so when it comes to web development, should we use SED instead?

  13. #13
    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 Mastodont View Post
    Instances are variables, frequently global, and therefore a bad choice
    Instance variables aren't global unless you declare them so. Static variables are always global. I have no problem with static variables, if they are local in scope, which they are in languages such as Ruby (Correct me if I'm wrong - I never wrote a single line of Ruby code).

    Quote Originally Posted by Mastodont View Post
    Fowler uses static methods without hesitation ...
    Mind you, Fowler is a technical writer, who often shows examples to make one particular point. In order to make this point clear, he may deliberately chose to neglect other aspects.

  14. #14
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There are more static methods in the Zend framework than messages in this forum. Don't forget, OOP is a programming paradigm

  15. #15
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Instance variables aren't global unless you declare them so. Static variables are always global.
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    Well, pakmannen wrote about static METHODS, not VARIABLES. If a file containing class with static methods is not included yet, this class could not be global.

    Sometimes it looks like there are two kinds of Sitepoint's religion: static is always Evil, dependency injection is always Good.

  16. #16
    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 Mastodont View Post
    Well, pakmannen wrote about static METHODS, not VARIABLES.
    Global (static) functions are perhaps not as problematic as global variables, but they still cause strong coupling. This makes the code inflexible.

    Quote Originally Posted by Mastodont View Post
    Sometimes it looks like there are two kinds of Sitepoint's religion: static is always Evil, dependency injection is always Good.
    Religion is - per definition - irrational. I find it quite rational to avoid global symbols, if the code is to be maintainable.

  17. #17
    SitePoint Addict
    Join Date
    Aug 2007
    Location
    GR
    Posts
    352
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So a private static var or method is global?

  18. #18
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    I find it quite rational to avoid global symbols, if the code is to be maintainable.
    What about factory object - do you always create new factory or have you got one global factory?? What about constants - they are always global

    Religion is - per definition - irrational.

    As well as fear of global and infinity.

  19. #19
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Religion is - per definition - irrational. I find it quite rational to avoid global symbols, if the code is to be maintainable.
    Saying that something is bad, per definition, is just like religion, isn't it?

    Quote Originally Posted by Mastodont View Post
    What about factory object - do you always create new factory or have you got one global factory?? What about constants - they are always global
    Constants and factories can usually not be changed so the do not pose the same threat as global variables.
    Design patterns: trying to do Smalltalk in Java.
    I blog too, you know.

  20. #20
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by BerislavLopac View Post
    In other words, a collection is a separate object from its items, and there is "findAll" static calls, as the Item class is not (and should not be) responsible for gathering collections of itself.
    Or you use a finder object, which you make an instance of and then use method calls;

    Quote Originally Posted by kyberfabrikken View Post
    I have no problem with static variables, if they are local in scope, which they are in languages such as Ruby (Correct me if I'm wrong - I never wrote a single line of Ruby code).
    Actually, ruby doesn't have static variables at all, and I haven't found any situations where I'd need on over simply using an instance variable.

    Quote Originally Posted by phpimpact View Post
    There are more static methods in the Zend framework than messages in this forum. Don't forget, OOP is a programming paradigm
    I'm not terribly familiar with the Zend framework, but it seems very much influenced by Java. Which, while certainly a proven approach to OOP, is not my favorite.

  21. #21
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    666
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by phpimpact View Post
    There are more static methods in the Zend framework than messages in this forum. Don't forget, OOP is a programming paradigm
    The Zend framework (V1.0) contains some 309 static methods. This forum has over 7,000 threads.

  22. #22
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jasper Bekkers View Post
    Constants and factories can usually not be changed so the do not pose the same threat as global variables.
    Accidentally overwriting is one of the problems with global variable, but isn't the main issue. Kyberfabrikken hit the nail on the head when he stated "Global symbols makes the code inflexible, and introduces dependencies, which aren't explicit". Constants and factories can simplify your code, but they do create hidden dependencies, and you have to be aware of the trade off when you make the decision to use them.

  23. #23
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I agree with Fowler, the author. Because if I need to coordinate actions across a system I'll definitely use the singleton pattern, and for that I need a static method.

    Now, when it comes to Singletons vs Global Variables, I recommend using Singletons. They are better because they don't pollute the global namespace with unnecessary variables. And they permit lazy allocation and initialization, where global variables in many languages will always consume resources. Not only in PHP, in Java, C# and C++ as well.

    The Zend framework (V1.0) contains some 309 static methods. This forum has over 7,000 threads.
    There you have it, 309

  24. #24
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Alright, so after reading a bit in PoEAA I've decided that Active Record makes sense for my purpose. I have a 1:1 relationship between my database and my models so a data mapper would be overkill. And I'm not bothered about mixing my domain logic in the Active Record. As a matter of fact, once you generalise the save/delete/get/set methods, there's not much left in them but the domain logic anyway.

    Quote Originally Posted by 33degrees View Post
    The second is performance; if your activerecord implementation isn't well designed, you can often run into 1+N problems, where you're performing multiple queries when you only really need two.
    Are you talking about table associations here? I've been thinking about how best to do that. I suspect you wouldn't want to pull all related tables at the same time. Imagine having a Group that contains many Users that in turn contains many Images. When pulling a list of the Groups, you maybe don't want all the Users and all their Images as well, as that could be thousands of objects. You don't need all that if you only want to, say, list the Groups.

    It's important to note that there are no static calls in ruby; classes are objects, and Blog.findAll() is a class method (as opposed to an instance method).
    Ah, okey. Didn't know that. (Never tried Ruby)

    My problem with this approach (apart from the other issues with static calls) is that you can't write specific finder methods for your different models. For example, you might want to Blog.findLatestPosts(), and there's no simple way to do that with static calls. So the static approach seems convenient at first because you're saving yourself the trouble of creating objects, but it's very inflexible.
    Yeah, I've been thinking about that as well. At first I was going to go with the controller supplying conditions, like so:
    PHP Code:
    $blog Finder::findAll('Blog''WHERE something'); 
    But that sort of defeats the purpose of putting all your SQL in one place. (Though I think Symfony does it like that)

    So do you create one Finder class for each Active Record? So you'd have a BlogFinder and a UserFinder? Alternative I guess is to put the Finder methods IN the Active Records, but I don't see how that's a good idea. Should they return instances of themselves, or just populate their members with what they find?

    That's pretty much what I'm doing; a have an array of properties, and a separate array of column objects. The column objects are generated automatically via a DESCRIBE query, and provide additional information, such as default values. When the save method is called, I iterate over the columns array and save the relevant properties. The means that the model can have properties that are not present in the table, and it won't cause any problems (they're simply not saved)
    Thanks for the tip, I implemented the DESCRIBE query. Works great, and saves me the trouble of having to declare the $columns array in each Active Record. Takes me back to what I said at the beginning, once you've generalised a lot of this stuff, the Active Record classes themselves are almost devoid of anything but the Domain Logic.

    One final, slightly OT question. Is the __set() method more resource intensive than just writing your own general set()? I read somewhere that they're error handlers so I figured maybe they're slower.

    And let's keep it civil folks, don't want this to end up like the last one.

  25. #25
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by phpimpact View Post
    Now, when it comes to Singletons vs Global Variables, I recommend using Singletons. They are better because they don't pollute the global namespace with unnecessary variables.
    OMG, you venture too much!! Singletons are here second ultimate EVIL


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
  •