SitePoint Sponsor

User Tag List

Page 2 of 5 FirstFirst 12345 LastLast
Results 26 to 50 of 118

Thread: ActiveRecords

  1. #26
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    pakmannen:

    As for DESCRIBE queries, IMHO is better put all this stuff in some type of config file.

  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 _Steve_ View Post
    So a private static var or method is global?
    Yes.

    I can see how that may sound weird at first, but the static variable belongs to a class, and this class is a global symbol. The special case about a private static variable is, that it isn't directly accessible from your code. Even then, it still is a global symbol. If you change the variable (Which can only be done indirectly), it will have consequences for all parts of the code. The thing, that makes it a global symbol is, that it has the same meaning from all places in your application. The fact, that it isn't directly accessible isn't relevant. For example, let's say you had the following class, encapsulating database access:
    PHP Code:
    class Database
    {
      static private 
    $connection;

      static public function 
    Connect($host$user$password$database) {
        
    self::$connection mysql_connect($host$user$password);
        
    mysql_select_db($databaseself::$connection);
      }

      static public function 
    Query($sql) {
        return 
    mysql_query($sqlself::$connection);
      }

    It's a na´ve example, but try to bear with me - Examples usually are.

    Now assume, that you had two applications, which used different databases. If the both used the same class, they would get in conflict, because the $connection property of Database is global. While this example may appear a bit conceived, it's exactly how the legacy mysql_* functions work in PHP. Most programs don't pass the (optional) $link argument along to the mysql_* functions. This will then, implicitly, use an internal (private, if you may) value. This is causing problems when you try to make two applications work together.

    Quote Originally Posted by Mastodont View Post
    What about factory object - do you always create new factory or have you got one global factory??
    That's a good point. Because of how the language is constructed, you have to use a global symbol, to create instances. Eg. a class is a global symbol. Factories can be used to decouple this dependency, but eventually they can only minimise the impact - not completely eliminate it.

    Quote Originally Posted by Mastodont View Post
    What about constants - they are always global
    And that they are. I would never use a constant for anything, which isn't truly constant. For example, I wouldn't recommend this:
    PHP Code:
    define('DB_USERNAME''root'); 
    Whereas I can live with this:
    PHP Code:
    $result->fetch(PDO::FETCH_ASSOC); 
    Quote Originally Posted by Jasper Bekkers View Post
    Saying that something is bad, per definition, is just like religion, isn't it?
    Only if I refuse to give any argument, other than the will of God.

    Quote Originally Posted by pakmannen View Post
    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.
    It depends on the type of application. Many web applications revolves around retrieving, storing and presenting data. When this is the case, an active record may be the best choice, because the complexity doesn't warrant splitting the model up in two distinct layers.

    Quote Originally Posted by pakmannen View Post
    And let's keep it civil folks, don't want this to end up like the last one.
    Yes, this is getting a bit out of control.

  3. #28
    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
    ... assume, that you had two applications, which used different databases. If the both used the same class, they would get in conflict, because the $connection property of Database is global ...
    Same class from the SAME storage??

  4. #29
    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 pakmannen View Post
    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.
    My Collection class solves this quite nicely.

  5. #30
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    It's a naïve example, but try to bear with me - Examples usually are.

    Now assume, that you had two applications, which used different databases. If the both used the same class, they would get in conflict, because the $connection property of Database is global. While this example may appear a bit conceived, it's exactly how the legacy mysql_* functions work in PHP. Most programs don't pass the (optional) $link argument along to the mysql_* functions. This will then, implicitly, use an internal (private, if you may) value. This is causing problems when you try to make two applications work together.
    You can connect to different databases using the same class, you only need to change the example you posted above:

    PHP Code:
    class Database
    {
        protected static 
    $_instance = array();
        protected 
    $_connection false

        public static function 
    getInstance($handler
        {
            if (!isset(
    self::$_instance[$handler])) {
                
    self::$_instance[$handler] = new self();
            }
            
            return 
    self::$_instance[$handler];
        }
        
        public function 
    connect($host$user$password
        {
            
    $this->_connection mysql_connect($host$user$password);
        }

    Last edited by phpimpact; Sep 8, 2007 at 13:56.

  6. #31
    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
    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.
    In my experience, I've come across very few situations where Active Record was not flexible enough for my needs.


    Quote Originally Posted by pakmannen View Post
    Are you talking about table associations here? I've been thinking about how best to do that.
    What I mean is this: Let's say you have a table of blog posts, and each blog posts references an author in a users table. What you want to avoid is querying the blog table, and then for each entry, querying the users table to get the name of the author, which is referred to as the 1 + N problem. Rail's ActiveRecord has eager loading of associations, which creates joins for you, reducing your queries to one.


    Quote Originally Posted by pakmannen View Post
    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?
    Exactly, I have a finder class for each active record; it was the easiest solution to the problems I was having. And for example, my UserFinder will have a method called findByCredentials($username, $password), which might be implemented differently in different projects (for example, if I'm storing password hashes, or hashes and salts). You could put everything in one class, but there is a clear separation of concerns between the two, so it makes sense to keep the separate.

    As it turns out, I've been using my finders to implement any method that implicates multiple rows, or the entire table, giving them some of the responsibilities of a table data gateway.

    Quote Originally Posted by pakmannen View Post
    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.
    One thing you might want to implement is a cache for that information, so you don't have the query the database for this information on every request.

    Quote Originally Posted by pakmannen View Post
    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.
    Maybe they are, but I bet that compared to the time it takes to connect to a database and query information from it, the difference is negligible.

  7. #32
    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 33degrees View Post
    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.
    Because of the eagerness to post a reply I sinfully forgot. You're right .

    Quote Originally Posted by phpimpact View Post
    A working example of this would be:
    Now try finding that bug in a decade old application that suddenly stops working after making some trivial change to the code.

    Quote Originally Posted by kyberfabrikken View Post
    That's a good point. Because of how the language is constructed, you have to use a global symbol, to create instances. Eg. a class is a global symbol. Factories can be used to decouple this dependency, but eventually they can only minimise the impact - not completely eliminate it.
    Most, if not all, design patterns are workarounds to flaws in current programming languages. What amazes me is that instead of actually fixing the language, people recommend them as something good. Factories tend to 'fix' the lack of polymorphism with the constructor, visitors hide the lack of support for double dispatching, memento makes up for the missing transactional support in OOP languages (imagine being able to rollback a function call!), a proper event mechanism would replace the observer pattern. And best of all, they all violate the DRY principle.
    Design patterns: trying to do Smalltalk in Java.
    I blog too, you know.

  8. #33
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is a great post by Flinn Mueller:

    Why ActiveRecord Doesn’t work in PHP

    So since I’m moving back to a PHP environment my mind is again on Rails bits in PHP. When I first ported ActiveRecord to PHP from Ruby I wasn’t nearly as familiar with Ruby as I am now. I’m looking at PHP again and I understand why the ActiveRecord pattern doesn’t work in PHP nearly as well as it does in Ruby. ActiveRecord in PHP probably works just as well in Java.

    ...

  9. #34
    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 phpimpact View Post
    You can connect to different databases using the same class, you only need to change the example you posted above:
    Sure you can. I was only trying to show that a private static property is indeed a global symbol. Whether anybody would ever implement a database connection object as a static class is a different story.

    Quote Originally Posted by Mastodont View Post
    Same class from the SAME storage??
    Not sure, what you mean?

  10. #35
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    kyberfabrikken
    Now assume, that you had two applications, which used different databases. If the both used the same class, they would get in conflict, because the $connection property of Database is global.

    I mean that only completely dumbbell would write shared component with one static shared property. So I consider your example as useless.

  11. #36
    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
    I mean that only completely dumbbell would write shared component with one static shared property. So I consider your example as useless.
    Steve: A private, static property isn't a global symbol.
    Me: Example showing, that a private, static variable is indeed a global symbol.
    Mastodont: Nobody would use a static variable. The example is therefore useless.

    You miss the point, and you're being rude. I can't relate to that.

  12. #37
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry for going off topic, but why is Mastodont being rude Kyber?

  13. #38
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nobody would use a static variable.

    Sorry, but I didn't write such sentence. And dumbell was not in any case meant personally.

    But I would like to know why kyber constantly turns to static variables, though originally were meant static methods. Static methods are not evil, only tool.

  14. #39
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Let's keep this thread on topic people.

    Quote Originally Posted by 33degrees View Post
    What I mean is this: Let's say you have a table of blog posts, and each blog posts references an author in a users table. What you want to avoid is querying the blog table, and then for each entry, querying the users table to get the name of the author, which is referred to as the 1 + N problem. Rail's ActiveRecord has eager loading of associations, which creates joins for you, reducing your queries to one.
    Yeah, that makes sense. I'll look into the whole association thing when I've got the basics covered.

    Exactly, I have a finder class for each active record; it was the easiest solution to the problems I was having. And for example, my UserFinder will have a method called findByCredentials($username, $password), which might be implemented differently in different projects (for example, if I'm storing password hashes, or hashes and salts).
    Would people completely rule out putting some of your search conditions in the controller?
    PHP Code:
    $blog $finder->findAll('Blog''WHERE username = ? AND password = ?'); 
    One thing you might want to implement is a cache for that information, so you don't have the query the database for this information on every request.
    Makes sense I guess. I've no idea how to implement a cache but I'll look around. Do you have a cache object? If anyone have some good links on the subject feel free.

    Question: Do your finders return an array containing Active Record objects? That's the way I have it now but I was thinking about places where only one row is found, do you skip the array and only return the object? That would be problematic of course where you don't KNOW how many rows you'll get. But in the cases where you KNOW you'll only get one row, do you have a special thingy in place so you'll only get one object back?
    PHP Code:
    $blogs findMany();
    foreach (
    $blogs as $blog
    {
        
    $blog->stuff();
    }

    $blog findOne();
    $blog[0]->stuff(); # this aint good
    $blog->stuff(); # this is better 
    Another question: Do you pass the request object to the finder? The finders obviously need to know about limits and orderbys. To reuse my earlier example:
    PHP Code:
    $blog $finder->findAll('Blog''LIMIT ? ORDER BY ?'$request); 

  15. #40
    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 pakmannen View Post
    Do your finders return an array containing Active Record objects?
    Well, it depends on target. If the finder returns data for view, no. Result is passed to block template.

    Quote Originally Posted by pakmannen View Post
    Another question: Do you pass the request object to the finder?
    What exactly is request object?

  16. #41
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    Well, it depends on target. If the finder returns data for view, no. Result is passed to block template.
    What? Block template? Also, what I wondered was more, do you make a difference between returning ONE row versus MULTIPLE rows.

    What exactly is request object?
    An object containing, among other things, the $_GET variables? You'd probably specify LIMIT and ORDER BY in the URL like so: www.domain.com/index.php?orderby=name&limit=5. And your finder needs to know this in order to query the database correctly. So my question was: do you pass this info from the controller to the finder, or do the finder just grab the info by itself?

  17. #42
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    pakmannen:

    In my world is final page constructed from blocks (content, menu, header etc.), which have assigned some content (component or module). So "block template" is a component's template for content displaying.

    do you make a difference between returning ONE row versus MULTIPLE rows

    Yes, I do. URL www.site.com/articles is in my Dispatcher translated into action ListItems, while www.site.com/articles/big-success is translated into action ViewItem. Block template for one item looks of course different than block template for more articles on one page.

    do you pass this info from the controller to the finder, or do the finder just grab the info by itself

    Component's object with finder methods has access to dispatcher's properties (action, filter, page, ...). I don't probably fully adhere to common implementations

  18. #43
    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 Dr Livingston View Post
    Sorry for going off topic, but why is Mastodont being rude Kyber?
    I took the dumbbell part personal. Reading the post again, maybe I shouldn't.

    Quote Originally Posted by Mastodont View Post
    But I would like to know why kyber constantly turns to static variables, though originally were meant static methods.
    Because they are related. Both static methods and global variables are global in scope.

  19. #44
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, I apologize myself for all and kyberfabrikken particularly for wrong expression. I don't want to rude anyone here. But please, dont' submit improbable examples. Thanks for attention and let the static battle transfer to another thread.

  20. #45
    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
    Sure you can. I was only trying to show that a private static property is indeed a global symbol. Whether anybody would ever implement a database connection object as a static class is a different story.
    Now, you make me think. My db class is all static. Why? Because I only need one connection for one database and the connection private variables will never change and the meaning of private is that only the class can change the variables, I know you know it but you put it with another meaning.
    I've never run into the case of having the $conn object interact with 2 dbs so I stick to static. It's just what fits the project, because at work (.NET) there are some times where my db class must be instantiated.

    Sticking to PHP things are different. Whilst you say they are global, you have to include the file first, just like you do with other classes, which in turn when you instantiate, if they have public vars - they are accessible through out your script. I can compare PHP's includes to namespaces somehow. But old-fashioned $_GLOBALS are pure globals, they exist for all the application.

    Did I convince you?

  21. #46
    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
    Sticking to PHP things are different. Whilst you say they are global, you have to include the file first, just like you do with other classes, which in turn when you instantiate, if they have public vars - they are accessible through out your script. I can compare PHP's includes to namespaces somehow. But old-fashioned $_GLOBALS are pure globals, they exist for all the application.

    Did I convince you?
    I think I follow you. PHP is interpreted, so a symbol may not be available in the running program from start to end. As such, you might argue that a symbol isn't global, because it's not until it's evaluated, that it exists. It's the same way, that a constant isn't really a constant in PHP. In a compiled language, this time-factor doesn't exist, because all code must be loaded, before it can execute.
    I would say, that this is something different from scope. The symbol is global nonetheless, but its existence may be determined by the application state. One of the concepts has to do with time, while the other has to do with space (scope).

  22. #47
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by _Steve_ View Post
    I've never run into the case of having the $conn object interact with 2 dbs so I stick to static. It's just what fits the project, because at work (.NET) there are some times where my db class must be instantiated.
    If you were (unit) testing data access classes, and using the same connection throughout, connection state left over from one test could contaminate the next.

  23. #48
    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
    Would people completely rule out putting some of your search conditions in the controller?
    PHP Code:
    $blog $finder->findAll('Blog''WHERE username = ? AND password = ?'); 
    I wouldn't completely rule it out, but I find it adds a lot of noise when you read the code

    Quote Originally Posted by pakmannen View Post
    Makes sense I guess. I've no idea how to implement a cache but I'll look around. Do you have a cache object? If anyone have some good links on the subject feel free.
    The easiest way to cache objects in php is to serialize them and save them in a text file. You can do something like this:


    PHP Code:

    function getColumnInfo($table) {
      if (
    file_exists($this->cache_dir.$table)) {
        return 
    unserialize(file_get_contents($this->cache_dir.$table));
      }

      
    $result $this->db->describe($table);

      
    file_put_contents($this->cache_dir.$tableserialize($result));

      return 
    $result;


    Quote Originally Posted by pakmannen View Post
    Question: Do your finders return an array containing Active Record objects? That's the way I have it now but I was thinking about places where only one row is found, do you skip the array and only return the object? That would be problematic of course where you don't KNOW how many rows you'll get. But in the cases where you KNOW you'll only get one row, do you have a special thingy in place so you'll only get one object back?
    You can just use one method to return an array, and another to return a single object. I in fact don't use arrays, but an iterator which grabs the next row as required.

    Quote Originally Posted by pakmannen View Post
    Another question: Do you pass the request object to the finder? The finders obviously need to know about limits and orderbys. To reuse my earlier example:
    PHP Code:
    $blog $finder->findAll('Blog''LIMIT ? ORDER BY ?'$request); 
    No, the only object that should know about the request, IMO, is the controller. Besides, for limits and offsets, I use page numbers, which get translated by an intermediate object into limit and offset.

  24. #49
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by _Steve_ View Post
    I've never run into the case of having the $conn object interact with 2 dbs so I stick to static. It's just what fits the project, because at work (.NET) there are some times where my db class must be instantiated.
    You can say that now, but the day may come where you find you need multiple instances, which might turn out to be quite complicated to implement; which is exactly what happened to me a while ago. So never take for granted that you'll only every need one instance of something...

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

    > ... I was thinking about places where only one row is found, do you skip the array and
    > only return the object?

    I just return an array regardless of how many rows are expected, and leave it to the client script to work it out; Why complicate your domain layer even more?

    In some cases if no records are found, it's an empty array that would be returned in that case.


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
  •