SitePoint Sponsor

User Tag List

Results 1 to 15 of 15
  1. #1
    SitePoint Enthusiast
    Join Date
    Feb 2008
    Location
    london, UK
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Help with a 'posts' class

    Ok, so i have two classes for a blog application i'm creating; post and posts. I'm not too sure how to design the posts class.

    post holds the information for each individual post

    I want posts to hold a collection of posts. Could be all the posts in the database, or a select few. I'm pretty new to OOP so unsure on best practice for something like this. What i was thinking though..
    PHP Code:
    $all_posts = new Posts() 
    // would return of all individual posts and their data


    // In some situations i would want to limit the 
    // returned posts by some conditions
    // input would be mysql conditions, slapped on to 
    // the end of a query run by the constructor
    $today_posts = new Posts("WHERE date_submitted = '$today'")
    // would return array of posts only submitted today 
    dunno if that made sense. In short: designing blog, need help

  2. #2
    SitePoint Guru
    Join Date
    Sep 2004
    Posts
    613
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    First what you should do is make sure you're naming your classes properly. Naming is very important because if your site gets big and you need to hire a freelancer, or ever need anyone to look at your code for any reason, good names can really make it more readable. Instead of having post/posts I would recommend "article" and "comment", unless "posts" was meant to be a series of articles posted to the blog in which case that's a step back from OOP to use a posts class.

    I structure my classes for elements of the site as follows
    PHP Code:
    <?php
    class article {
        
        function 
    __construct ($input) {        
            if (
    is_array($input)) {
                
    $this->data $input;
            } elseif (
    $input 0) {
                
    $this->getData($input);
            }
        }
        
    /*===========================================*/
        /* Public Functions
        /*===========================================*/
        
    function getCategory () {
            
    //returns an object of this article's parent category
        
    }
        
        function 
    getCommentList () {
            
    //returns an array of comment objects
        
    }
        function 
    getAuthor () {
            
    //returns a member object for the author
        
    }
        function 
    getData ($id) {
            
    $this->tru->query->select(array(
                
    //sql select data
            
    ));
            
            if (
    $this->tru->query->getRowCount("article-get-data") > 0) {
                
    $this->data $this->tru->query->getArray("article-get-data");
                return 
    true;
            } else {
                
    $this->tru->error->add(array(
                    
    "type" => "article-noexist",
                    
    "data" => array(
                        
    "id" => $id
                    
    ),
                    
    "terminate" => false
                
    ));
                return 
    false;
            }
        }
        function 
    getId () {
            return 
    $this->data["id"];
        }
        function 
    setAuthorId ($author_id) {
            
    $this->data["author_id"] = $author_id;
        }
        function 
    getAuthorId () {
            return 
    $this->data["author_id"];
        }
        function 
    getTitle () {
            return 
    $this->data["title"];
        }
        function 
    setTitle ($title) {
            
    $this->data["title"] = $title;
        }
    }
    ?>
    This allows me to call the class like:
    PHP Code:
    $article = new article($data); 
    where $data can be either an ID in which case it will fetch the data automatically for the article, or I can just input the straight up data.

    We control everything using get/set functions rather than calling data array values because what it does is it creates a terminating php error if the function name is wrong, whereas if you just try to get data based off of an array value $article->data["id"] and the key id doesn't exist it won't throw an error, only create a bug in your script.

    Using this structure, there's no need to have a posts class that handles multiple posts.

    On that same note, within the category class for the parent category, we would use a getArticles function which would work like you see below:
    PHP Code:
    function getArticles ($start 0$count 15) {
         
    //sql to get articles based on $start and $count

        
    $articles = array();
        require_once 
    "path-to-file/article.php";
        while (
    $tempArticle $this->tru->query->getArray("query-name") {
            
    $articles[] = new article($tempArticle);
        }
        return 
    $articles;

    I hope this helps. The query stuff we use for select/getArray is a custom api, you could easily replace it with base mysql functions.

    Something else worth noting is we name our classes based on their location within the file structure. For instance, ArticleCategory instead of Category. Because you could very easily have more than 1 Category class, this way the class names remain specific and never get overwritten and it prevents you from re-including files that are already included because the class was overwritten by something else.

  3. #3
    SitePoint Enthusiast
    Join Date
    Feb 2008
    Location
    london, UK
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question

    ^^^^^^
    thanks. helped a lot.


    1. where would you put your function 'getArticles'. Would that be in a common functions class or what?

    2. Also, looking at your get/set functions for each property, what is the benefit of using functions for each individual property, rather than a generic method to handle them all. i.e.
    PHP Code:
    // you have:
    function getTitle () {
        return 
    $this->data["title"];
    }
    function 
    setTitle ($title) {
        
    $this->data["title"] = $title;
    }

    // why not:
    function getProperty ($property_name) {
        return 
    $this->data[$property_name];
    }
    function 
    setProperty ($property_name$value) {
        
    $this->data[$property_name] = $value;


    3. One last thing, what is the benefit of storing properties the way you do (in the $data array) rather then their own name?
    PHP Code:
    // your way
    article {
         
    data {
              
    'title' => 'This is my title'
              'content'  
    => 'And here is the content'
         
    }
    }

    // call title by
    $MyArticle->data['title'];







    // alternative way
    article {
        
    'title'   => 'This is my title'
        'content'  
    => 'And here is the content'
    }

    // call title by
    $MyArticle->title

  4. #4
    SitePoint Guru
    Join Date
    Sep 2004
    Posts
    613
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by strungoutyeh View Post
    ^^^^^^
    thanks. helped a lot.


    1. where would you put your function 'getArticles'. Would that be in a common functions class or what?
    getArticles() would go on your category object and would get the articles within that specific category. If you're needing a general class that will get the most recent and things like that, those are page-specific features and do not belong in an object model. Ideally you should have an object for each page which consists of a show() function which executes every page.
    Quote Originally Posted by strungoutyeh View Post
    2. Also, looking at your get/set functions for each property, what is the benefit of using functions for each individual property, rather than a generic method to handle them all. i.e.
    PHP Code:
    // you have:
    function getTitle () {
        return 
    $this->data["title"];
    }
    function 
    setTitle ($title) {
        
    $this->data["title"] = $title;
    }

    // why not:
    function getProperty ($property_name) {
        return 
    $this->data[$property_name];
    }
    function 
    setProperty ($property_name$value) {
        
    $this->data[$property_name] = $value;

    Because if you use a general function like $class->getProperty("author_id") it doesn't throw an error if author_id doesn't exist. By utilizing the functions an error will be thrown forcing you to take a closer look at your code. So This way is less error prone in a live site environment, especially when you start changing db structure and things start evolving.

    If you look at our objects the get/set functions are exactly what you see in our database. So if you run onto a page where $class->getAuthorId() is not a function, then either the object model is out of date, or author_id doesn't exist in the database and you meant getMemberId(). We use it for consistency so you're not always looking back going "wait, what was the column name?". It makes it easier to develop on a larger system because we share the same variable names everywhere (although in our PHP the column would be author_id and in PHP we always use camelcase such as authorId)

    Does that make sense?
    Quote Originally Posted by strungoutyeh View Post
    3. One last thing, what is the benefit of storing properties the way you do (in the $data array) rather then their own name?
    PHP Code:
    // your way
    article {
         
    data {
              
    'title' => 'This is my title'
              'content'  
    => 'And here is the content'
         
    }
    }

    // call title by
    $MyArticle->data['title'];







    // alternative way
    article {
        
    'title'   => 'This is my title'
        'content'  
    => 'And here is the content'
    }

    // call title by
    $MyArticle->title
    Look at my getData function example, all we do is $this->data = $SqlArray to set our object data from the database. It's riskier to do this if you're not using a control shell like data to store everything. As a side note, we always have a save() function on every object model. This isn't in the example I gave you because the article example I showed you pulls data from wordpress and we only read the data not modify it through this model. Here's what save() does on every model

    PHP Code:
    function save () {
           
    //sql select to see if $this->data["id"] > 0 AND item exists

           
    if ($this->tru->query->getRowCount("article-verify-exist") > 0) {
                 
    //this exists, lets UPDATE
           
    } else {
                 
    //it doesn't exist, INSERT
           
    }

    By utilizing this method your code can look as simple as:

    PHP Code:
    $article = new article();

    $article->setTitle($_POST["title"]);
    $article->setDescription($_POST["description"]);

    $article->save() 
    I would also HIGHLY recommend using Smarty Template Engine

  5. #5
    SitePoint Enthusiast
    Join Date
    Feb 2008
    Location
    london, UK
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the quality replies. Seriously helping me a lot. I've only been writing OOP for about a month now so some of it can be very confusing but i'm understanding most of what you've written.

    Quote Originally Posted by Webnet View Post
    getArticles() would go on your category object and would get the articles within that specific category. If you're needing a general class that will get the most recent and things like that, those are page-specific features and do not belong in an object model. Ideally you should have an object for each page which consists of a show() function which executes every page.
    Ok i understand the category object and how that pulls articles.
    The next bit i get a bit lost on. I don't understand "do not belong in an object model". I also do not have an object for each page.
    Basically, at the moment i have a 'blog' page where i want to create a list of all the blog posts (articles if you wish).

    Because if you use a general function like $class->getProperty("author_id") it doesn't throw an error if author_id doesn't exist. By utilizing the functions an error will be thrown forcing you to take a closer look at your code. So This way is less error prone in a live site environment, especially when you start changing db structure and things start evolving.

    If you look at our objects the get/set functions are exactly what you see in our database. So if you run onto a page where $class->getAuthorId() is not a function, then either the object model is out of date, or author_id doesn't exist in the database and you meant getMemberId(). We use it for consistency so you're not always looking back going "wait, what was the column name?". It makes it easier to develop on a larger system because we share the same variable names everywhere (although in our PHP the column would be author_id and in PHP we always use camelcase such as authorId)

    Does that make sense?
    perfect sense

    Look at my getData function example, all we do is $this->data = $SqlArray to set our object data from the database. It's riskier to do this if you're not using a control shell like data to store everything. As a side note, we always have a save() function on every object model. This isn't in the example I gave you because the article example I showed you pulls data from wordpress and we only read the data not modify it through this model. Here's what save() does on every model

    PHP Code:
    function save () {
           
    //sql select to see if $this->data["id"] > 0 AND item exists

           
    if ($this->tru->query->getRowCount("article-verify-exist") > 0) {
                 
    //this exists, lets UPDATE
           
    } else {
                 
    //it doesn't exist, INSERT
           
    }

    By utilizing this method your code can look as simple as:

    PHP Code:
    $article = new article();

    $article->setTitle($_POST["title"]);
    $article->setDescription($_POST["description"]);

    $article->save() 
    I would also HIGHLY recommend using Smarty Template Engine
    Also makes sense (i think). Have heard about Smarty, will look into it

  6. #6
    SitePoint Guru
    Join Date
    Sep 2004
    Posts
    613
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's not a problem, I remember when I was learning PHP and people helped me out, it makes all the difference in the world.

    An object model would be the object for an article, or category. It's a model of what you're dealing with, and it's an object.

    Each page should be an object. Ie - your index.php for a given directory should require_once a page based on the url and load that site's object and execute run()

    PHP Code:
    //this is sloppy and should be done better
    require_once $_GET["page"];

    $page = new $_GET["page"];

    $page->show(); 
    Then on that page you can have seperate functions such as getRecentArticles().

    In this example:
    PHP Code:
    $article = new article(); 

    $article->setTitle($_POST["title"]); 
    $article->setDescription($_POST["description"]); 

    $article->save() 
    A new article would be created because it does not have an ID, thus is not found in the database. Whereas if you specified an id (IDs should not have a SET function, the id should be passed through the object constructor) it would be an existing article.

  7. #7
    SitePoint Enthusiast
    Join Date
    Feb 2008
    Location
    london, UK
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ahhh yes i think i'm following you now. Thank you

    god that second bit you wrote makes much more sense than what i had. brb rewriting class

  8. #8
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    May wan't to look at ActiveRecord and ORM.

  9. #9
    SitePoint Guru
    Join Date
    Sep 2004
    Posts
    613
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I wouldn't recommend ActiveRecord, mainly because it goes against the reason of the error being thrown when you're getting using the set/get functions.

  10. #10
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    PHP Code:
    $article = new article(); 

    $article->setTitle($_POST["title"]); 
    $article->setDescription($_POST["description"]); 

    $article->save() 
    This is a AR implementation.

    Quote Originally Posted by Webnet
    A new article would be created because it does not have an ID, thus is not found in the database. Whereas if you specified an id (IDs should not have a SET function, the id should be passed through the object constructor) it would be an existing article
    Given a primary key that is not a auto generated this fails. Its much better to chart changes and make the decision whether to update or insert based on whether the object has really been changed from its row level equivalent.

    This is how I have set up the data container so that changes can be charted and its possible to revert all changes.

    PHP Code:
    // your way
    article {
         
    data {
              
    'title' => array('This is my title','Previous Title','Original Ttitle')
              
    'content'  => array('And here is the content','Previous Content')
         }

    Also, every time a property is set that change is logged inside a changes array based on the property name.

    PHP Code:
    class Article {

           private 
    $_changes = array();

           public function 
    setProperty($name,$value) {

                    if(!
    in_array($name,$this->_changes)) $this->_changes[] = $name;
                   
                    .... 

            }


    Last edited by oddz; Jun 4, 2009 at 00:04.

  11. #11
    SitePoint Guru
    Join Date
    Sep 2004
    Posts
    613
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What do you mean AR?

    Its much better to chart changes and make the decision whether to update or insert based on whether the object has really been changed from its row level equivalent.
    Isn't that what I just did? It compares via ID to the row existing in the database. In most cases, if the ID doesn't exist it's insert, if it does, it's update. That's all there is to it most of the time.

    Why do you store actual changes? How is that useful?

  12. #12
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Quote Originally Posted by Webnet
    What do you mean AR?
    ActiveRecord

    Quote Originally Posted by Webnet
    Isn't that what I just did? It compares via ID to the row existing in the database. In most cases, if the ID doesn't exist it's insert, if it does, it's update. That's all there is to it most of the time.
    Unless the primary key is not auto generated.

    Quote Originally Posted by Webnet
    Why do you store actual changes? How is that useful?
    Only changed properties are updated.

  13. #13
    SitePoint Guru
    Join Date
    Sep 2004
    Posts
    613
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Perhaps on a rare case if it's not automatically generated. In which cause we would use a set*Id() function. I have a * in there because I've never found an instance in my experience where the id hasn't been auto_increment from the SQL. I'm not saying it's not possible, there may be instances, I've just never run into them.

  14. #14
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Yeah… I know what you mean. However, there may be occasions where a string is used. Your right though normally the primary key is auto generated. By chance that it isn't though my system is smart enough to insert rather the update. That is based on whether the primary key either isn't present or has changed. Once a record has a primary key its a relatively safe assumption that it won't change. So based on that the only time when it changes would be when its assigned as a string when first inserting data. Otherwise, it should generally stay the same.

  15. #15
    SitePoint Guru
    Join Date
    Sep 2004
    Posts
    613
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    How come you use a string as a unique identifier? I've never understood that concept, it's just more processing....


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
  •