SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 69

Hybrid View

  1. #1
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Post First Steps in OOP (n00bs digest)

    Goodafternoon Everyone,

    First off, apologies if this is the wrong place to post this, but I didn't think that it'd be noticed enough in the basic PHP forum...

    I've taken a project to give myself something to look upon as a reference when doing other projects.

    I've done some reading and although some points I've somewhat understood, it just doesn't "click" as yet.

    So following the gurus that posted in this age old classic post:
    http://www.sitepoint.com/forums/show...898#post439958

    I'm just going to dive in.

    I've read a fair bit. I'm looking at HarryFs PHP Anthology VII on my desk right now. I must be missing some things as I still don't get it.

    So, I'm just going to dive in.

    I'd like to ask you guys to give me a hand in the form of tips and prods in the right direction...

    What am I doing wrong?
    Why won't my proposed way not work?
    Is there a better way of doing it?
    Should I have thought differently?

    Here's the brief for my little inhouse project:

    I'm making a timesheet application where users enter details of each task they do throughout the day.

    • Users need to log in and have 2 levels - administrator and user


    • The login form consists of username and password


    • Once logging in they are presented with a form that lists current jobs.


    • The jobs are listed down the page.


    • Users can update current jobs (update jobtable SET $updatelist WHERE idusers = $idusers).


    • Users can add new jobs (INSERT INTO $fields VALUES ($values)).


    gah I'm getting kicked out of my office

    - to be continued -

    'cholic

  2. #2
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    - continued -

    Here are the classes I'm planning to create and use:

    • Database Class - Will have methods which connect to, disconnect from and check for errors with database, run queries and instantiate QueryResult class

    • Query Result Class - Composed by Database class, process query result and return a 2 dimensional array $result[record][field] OR boolean depending on query

    • Form Class($name,$value,$attributes) - Methods to create form elements like textfields/textarea/radiobutton/checkboxes/hidden fields etc

    • Authentication Class($username,$password) - Will have methods which login and logout users

    • Page class - Methods to create page elements like nav/header/footer/body


    I'll probably draw up some static methods to loop through the results acquired from query result class although that was something that just jumped into my head just then and I've noted down.

    Loop Results class - will have static methods to loop through array etc. not entirely sure, but I think I need this here.

    I might write this up to be somethin' following this pseudo code:

    login page
    Code:
    - instantiate form class
    - instantiate page class
    - page->writeHeader()
    - page->writeContent (
        name: form->textfield("username",""," size=\"30\"")) 
        password: form->password("password",""," size=\"30\"")
        form->submit("submit","LOGIN","class=\"buttons\")
    )
    - page->writeFooter()
    - if $_POST['submit'] then instantiate database class
    - instantiate authenticate class->validate($username,$password)
    - if (authenticate->pass) {
    - write cookie/session (not sure yet)
    - redirect to current job list page
    job list page
    Code:
    - instantiate form class
    - instantiate database class
    - instantiate page class
    - instantiate authentication class
    - if (!authentication->checkcookie/sess) then
    - redirect to login page.
    - database->connect
    - $recordArr = database->query("SELECT...")
    - loopRecords::fetch(form->textfield("jobs[]",$recordArr[0][$i],"class=\"textfields\"))
    - form->submit("submit","UPDATE JOBS","class=\"buttons\")
    Damn, I think I'll start from here...

    I guess you could say that this is the somewhat semi complete application design?

    ...

    *twiddles thumbs*

    I'll be refactoring soon no doubt...

    I'll get working and document progress (be it positive or negative)

    regards,


    Melan'

  3. #3
    ********* 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 melancholic
    • Database Class - Will have methods which connect to, disconnect from and check for errors with database, run queries and instantiate QueryResult class

    • Query Result Class - Composed by Database class, process query result and return a 2 dimensional array $result[record][field] OR boolean depending on query

    • Form Class($name,$value,$attributes) - Methods to create form elements like textfields/textarea/radiobutton/checkboxes/hidden fields etc

    • Authentication Class($username,$password) - Will have methods which login and logout users

    • Page class - Methods to create page elements like nav/header/footer/body
    You have done a structural decomposition. I don't know if your decomposition is teh right one, because structural decomposition is very very hard. I would hazard a guess that you have got it just as wrong as I would have done. Likely your design is woolly and you will start to thrash as you code at the margins of what's clear.

    What you actually want is a role based decomposition.

    Suppose you are hiring for a business. You could structural decompose you business into sales, marketing, personal, accounts, business development, office manager and so on. The business would start up and no one would be quite sure who's job it is to deal with a customer billing enquiry, in particular draughting the e-mail. After all, all e-mails should be monitored for cost, they should bundle promotional material and if it's a new service request then business development will want to know. Perhaps half these people aren't even needed. Of course people are adaptable, so this problem would all get resolved by trial and error. That won't work for software.

    If we take a different approach and start with business specifics, rather than a general model, let's see what happens. Say it's a used car dealership. We are about to start on day one and we have never run a dealership before, but luckily the job agency is next door with a long queue. I am going to start with one thread of business only.

    Firstly we will get passing trade. We need a ForecourtCarSeller role to handle this (hopefully with multiple instances). If they sell a car then asking them to settle the accounts is a bit much. We thus hire a SaleProcessor that the ForecourtCarSeller will liase with. We will need to replace that car and so will need a CarPurchaser to handle the nitty gritty of this. They will have to choose a car, but with the PurchasePolicy this is no problem. The PurchasePolicy can query all of the ForecourtCarSellers to find out the most popular models if necessary.

    What's happening? I think this is much clearer and more defined than the first example because we haven't generalised on a first pass. The roles are very precise and as classes probably have just one method each. We are letting the thread of execution define the minimum role to get the job done. Not much good for "reuse", but reuse is a lousy goal. Get the "use" right first. These classes would be easy to code.

    Assuming we have coded this up and it works, we go on to the next part of the design. Another thread: the phone rings. We need a PhoneAnswerer from next door. If it is a potential sale then teh PhoneAnswerer is best delegating to the ForecourtCarSeller. Of course this is not a forecourt sale, so at this point we rename that class to CarSeller. Iteratively it gets more general, but only on demand (and only with care). It now looks like...
    PHP Code:
    class CarSeller {
        function 
    attemptForecourtSale($passer_by$inventory) { ... }
        function 
    attemptPhoneSale($ad_answerer$inventory) { ... }

    Basically we generalise only when the code tells us too. I glossed over a useful point there. We can rename the class very easily with OO (less easily the methods). This is the power of OO, you can dig a big hole for yourself and then refactor your way out again. This means that you can design as you go. Don't worry about screwing up royally, just worry about getting confused when everything becomes too abstract.

    Basically:
    1) Do one story or thread at a time.
    2) Be specific until it's definitely advantageous to generalise.
    3) Inject the design after you have started coding.

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

  4. #4
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by melancholic
    I'm just going to dive in.
    That's a great way.
    Although, the way I've learnt best is to do a project while reading a great book. That way you can apply all the theory from the book.
    May I suggest either of these two greats which reading while doing a project will help enourmously:

    Domain-Driven Design
    Patterns of Enterprise Application Architecture

    Quote Originally Posted by melancholic

    • Users need to log in and have 2 levels - administrator and user
    I would suggest the ability to allow multi-level authentication as this can be quite alot of work to change later. I would suggest groups where a user can belong to multiple authentication groups (ie many-to-many relationship).


    Regards,
    Eli

  5. #5
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lazy_yogi
    That's a great way.
    Although, the way I've learnt best is to do a project while reading a great book. That way you can apply all the theory from the book.
    May I suggest either of these two greats which reading while doing a project will help enourmously:

    Domain-Driven Design
    Patterns of Enterprise Application Architecture



    I would suggest the ability to allow multi-level authentication as this can be quite alot of work to change later. I would suggest groups where a user can belong to multiple authentication groups (ie many-to-many relationship).


    Regards,
    Eli
    Cheers Eli, I think the same too, I try to work off the thoery being preached within the texts I'm currently reading but then I try to do my own thing doing my best on doing it without copying the code char for char (don't know if it's more like a blind leap because it gets confusing sometimes).

    I'll be sure to give one or both of those books you suggested a go and thanks for the recommendation regarding the multi-level authentication.

    I'm not up to it just yet, I can't think of any other properties that would be in the authentication other than level and allowed would username and password be here as properties? (or member vars?)

    Code:
    Authentication Class
    properties:
    level 
    allowed
    
    methods: 
    login
    logout
    redirect
    I'm not exactly sure how I'll go about this one, maybe I'll read over the examples HarryF has given in his Anthology book V2 and create a session class to be composed by the auth class.

    err... in a different zone ATM :/

    I'll get back to it later, thanks again for the feedback

  6. #6
    SitePoint Member Don Wilson's Avatar
    Join Date
    Sep 2004
    Location
    Dallas
    Posts
    10
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Could someone show an example of a form class? I've never thought of making one and hate writing forms.

    Many thanks.

  7. #7
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I recently bought Domain Driven Design (Evans) myself, and it has helped me understand a few things better

    I can recommend it, and I bought it on the many recommendation from other members, such as Lastcraft. I would also recommend you look at Unit Testing as well if you haven't yet? Test Driven Development (Beck).

    As to your planning, I think your taking the right steps? What I'd do is to google for white papers on 'modular, re-useable design' to get another perspective on how to design and develop a framework (in this case, your timesheet application).

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

    Looks like I've a bit to learn yet Lastcraft?

  9. #9
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think lastcraft has set you on the design path and from what you posted you have defined what you need to build. Even if you can't fully embrace what lastcraft is talking about, I recommed nudging yourself in that direction a little further each project. You will be a better and happier programmer if you do.

    Your own description lays is out:

    * User Accounts with access levels, username and password

    * Jobs which appear to have an associted user

    * Tasks which I infered from your "details of each task" comment that are associated with a job and have "details" which it take to mean date, duration, user, notes, etc.

    So I would build those objects and see what kind of data they need. Then mock up some data access classes to give the objects some values to try the thing out (or unit tests). Finally create a database with the necessary tables and add your database connect code.

    PS - If you add Projects and Clients let me know because I, and probably many others, could use a well written web app that does this as well.
    Christopher

  10. #10
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi there,

    My humble thanks for the input and feedback, especially to Marcus who has always taken the time to reply to my questions.

    <thoery>
    Alright... back to ye' olde whiteboard then eh?

    I guess what's confusing me is the general conception of objects as "Lego" - reusable code... To me, reusable code means general rather than specific.

    Make general components (like database, pagewriters, forms, pdfRenderer) and piece them together to make an application - much like procedural modules, but neater, easier to follow and relate to each other.

    Which is why I've done (what I now know as) a structural decomposition. This indeed can get pretty messy and I can see how that could happen - I understand what LastCraft's analogy is painting. One object has a certain role which involves related tasks within the application rather than one task per class?.

    I've redrafted the design - I was just going to incorporate the clients administration functionality (which just allows administrator to add clients) later as an extension, but well, I guess I'll just incorporate it just to keep things simple.

    Here's how it's lookin...

    PREVIOUS
    Code:
    APPLICATION 
      | - Database {connect, disconnect, &query, iserror}
           | - QueryResult { }
      | - Forms {textfield, textArea, submit, button, radiobutton, checkbox }
      | - Authentication { login, logout }
      | - Page { writeHeader, writeFooter, writeContent, writeNav }
      | - RENDER [STATIC] { buildGrid, buildForm(?) }
    CURRENT
    Code:
    APPLICATION 
      | - Users { loginUser, logoutUser, redirect }
           | - Tasks { addTask, deleteTask, updateTask }
      | - Admin { loginAdmin, logoutAdmin, redirect }
           | - Clients { addClient, deleteClient, updateClient, addUser, deleteUser, updateUser }
           | - Reports { viewTasks, makeReport }
      | - Database { connect, disconnect, &query, isError }
      | - QueryResult { fetch, size, isError }
      | - Page { writeHeader, writeFooter, writeContent, writeNav }
      | - RenderData [STATIC]
      | - Forms { textfield, textArea, submit, button, radiobutton, checkbox }
    But I have a suspicion that I am only half getting the point or completely missing it. :/
    It's kind of clouding up again... after a sureal "moment of clarity"
    </thoery>

    <practical>
    Here is my YADA class and QueryResult class. I tried to put in an errorMsg property which gets populated when errors occur, but no dice... there was one stage where it got me confused... so I dumped it ... for now anyway...

    I've tested it on SELECT, INSERT, UPDATE and DELETE queries and it works fine.

    Database Class
    PHP Code:
    class Database {

        
    /**
         * Database Server Host Address
         * @access private
         * @var string
         */
        
    var $host;
        
    /**
         * Database Username
         * @access private
         * @var string
         */
        
    var $username
        
    /**
         * Database Password
         * @access private
         * @var unknown_type
         */
        
    var $password
        
        
    /**
         * Database Name property
         * @access private
         * @var string
         */
        
    var $database;
        
        
    /**
         * Connection Resource ID property
         * @access private
         * @var resource
         */
        
    var $connId;
        
        
    /**
         * Constructor
         *
         * @param string $host
         * @param string $username
         * @param string $password
         * @param string $database
         * @access public
         */
        
    function Database($host$username$password$database)
        {
            
    $this->host $host;
            
    $this->username $username;
            
    $this->password $password;
            
    $this->database $database;
            
    $this->connectDb();
        }
        
        
    /**
         * Connect to database method
         * @access private
         * @return void
         */
        
    function connectDb()
        {
            
    $this->connId = @mysql_connect($this->host,$this->username,$this->password);
            if (
    $this->connId) {
                if (!@
    mysql_select_db($this->database$this->connId)) {
                    die(
    "COULD NOT SELECT DB".mysql_error());
                }
            } else {
                die(
    "COULD NOT CONNECT TO DB SERVER");
            }
        }
        
        
    /**
         * Disconnect from database method
         * @access public
         * @return void
         */
        
    function disconnectDb()
        {
            
    $test mysql_close($this->connid);
            if (!
    $test) {
                die(
    "disconnect error: Connection Does not Exist\n".mysql_error($this->connId));
            }
        }
        
        
    /**
         * Instantiates queryResult object
         * @access public
         * @return void
         */
        
    function &query($sqlString)
        {
            
    $result mysql_query($sqlString,$this->connId);
            if (!
    $result) {
                die(
    "Query could not be executed\n".mysql_error($this->connId));
            } else {
                return new 
    queryResult($this$result);
            }
        }


    queryResult class
    PHP Code:
    class queryResult {
        var 
    $dbObject;
        var 
    $result;
        var 
    $resultOut;
        
        function 
    queryResult(&$dbObject,$result)
        {
            
    $this->dbObject = &$dbObject;
            
    $this->result $result;
            
    $this->resultOut = array();
        }
        
        function 
    size()
        {
            return 
    mysql_num_rows($this->result);
        }
        
        function 
    fetch() 
        {
            while(
    $row mysql_fetch_row($this->result)) {
                
    $this->resultOut[] = $row;
            }
            return 
    $this->resultOut;
        }

    Admitedly, this class is partly inspired by HarryF's example in his book... So I couldn't really say that I wrote this from scratch.

    I feel that it's still half baked however, but I guess it does the job for now. It runs queries and can fetch results into a 2 dimensional array [record][field] when required.

    We'll see how we go later on.

    I'm going to leave the DB Class at this for the mean time.
    </practical>



    Quote Originally Posted by Don Wilson
    Could someone show an example of a form class? I've never thought of making one and hate writing forms.

    Many thanks.
    Don, you can look up PEAR's HTML_quickforms at http://pear.php.net/HTML_QuickForm/

    Quote Originally Posted by arborint
    PS - If you add Projects and Clients let me know because I, and probably many others, could use a well written web app that does this as well.
    Arborint, I'll most probably extend the application to that include projects down the track. But I don't know how long that's going to take heh

  11. #11
    SitePoint Member Don Wilson's Avatar
    Join Date
    Sep 2004
    Location
    Dallas
    Posts
    10
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't care for PEAR too much, but thanks for the link. I've already started to build my own Form class.

    Don

  12. #12
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Maybe start with something like this and start building out just the functions you need:
    PHP Code:
    class UserAccount {
    var 
    $id;
    var 
    $password;
    var 
    $access_level;

    }

    class 
    Job {
    var 
    $id;
    var 
    $userID;
    var 
    $name;
    var 
    $tasks = array();

    }

    class 
    Task {
    var 
    $id;
    var 
    $jobID;
    var 
    $userID;
    var 
    $name;
    var 
    $date;
    var 
    $notes;


    Christopher

  13. #13
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    Maybe start with something like this and start building out just the functions you need:
    PHP Code:
    class UserAccount {
    var 
    $id;
    var 
    $password;
    var 
    $access_level;

    }

    class 
    Job {
    var 
    $id;
    var 
    $userID;
    var 
    $name;
    var 
    $tasks = array();

    }

    class 
    Task {
    var 
    $id;
    var 
    $jobID;
    var 
    $userID;
    var 
    $name;
    var 
    $date;
    var 
    $notes;


    That seems like great advice Christopher
    thanks... I thought about the methods but not the properties.
    I'll put that to work with my planning.

    What I am up to now is making the form class... it's a little difficult to nut out exactly what goes into this one...

    I'm not making a form class per say, but more a form elements class...

    here's how I would write it using procedural notation.

    PHP Code:
    function writeFormElement($type$value$name$attributes=""$options
    {
        switch (
    $type)
            case 
    "button":
            case ...   
            case ...
                  
    $formElementOut "<input type=\"$type\" name = \"$name\" $attributes>";
            case 
    "select":
                  
    $formElementOut "<select name=\"$name\">
                  foreach (
    $options as $key=>$value) {
                         
    $formElementOut .= "<option value\"$value\">$key</option>";
                  }
                  
    $formElementOut .= "</select>";
                  break;
            case 
    "textarea":
            case default:
                  
    $formElementOut "INVALID ELEMENT TYPE ERROR";
        }
        return 
    $formElementOut;

    oop:
    PHP Code:
    class formElements {

    var 
    $validTypes;
    var 
    $isValid
    var $ 
    gah dinner time my wife is starvin (and so am I quite frankly)

    - to be continued -

    'cholic

  14. #14
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    For form generation there are many ways to go. You could have a base class and a class for each type and a Factory to create an instance depending on the type. Or you can just go for a straight class with a method for each type. I haven't found one better than the other. You also get into the issue that it is really a HTML generator and should probably inherit a base HTML class. (I would be interested in how others do this)

    For a form controller the most common problem is starting like you are with the details and then growing it. That is because you really don't know how to arrange the methods/parameters until you get to the end. So I would recommend starting at the top and working down to the specifics as you need them.

    For example, a form controller would probably be passed a Request object or just one of the PHP globals for the request. Then it needs to know what form fields/parameters it is dealing with, so it needs an object for each of those (there's a FormField class). And those needs a Filter and a Validator (two standard classes). Then once you've checked the form values you either need to regenerate the form with the values (the 1st time or if there is an error) or do something with those values if everything is OK. So that sound like you need to pass the values to some object that knows about the data source. And so on...

    Just keep working your way from the top down and implement just the classes and methods you need as you go. You can always refactor later, or just throw it away and start over because you'll know more about the problem and how to solve it.
    Christopher

  15. #15
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Arborint,

    Quote Originally Posted by arborint
    For example, a form controller would probably be passed a Request object or just one of the PHP globals for the request. Then it needs to know what form fields/parameters it is dealing with, so it needs an object for each of those (there's a FormField class). And those needs a Filter and a Validator (two standard classes). Then once you've checked the form values you either need to regenerate the form with the values (the 1st time or if there is an error) or do something with those values if everything is OK. So that sound like you need to pass the values to some object that knows about the data source. And so on...
    What is a "request object"? How exactly would this model you are proposing look like?

    is this anywhere close to what you're suggesting?
    PHP Code:
    class formController {
         function 
    formController(&$formfilter,&formvalidator)
         {
         }
    }

    class 
    formFilter()
    {
    }

    class 
    formValidator() 
    {

    please pardon my ignorance... I'll have smarter things to say tomorrow...

    Thanks for the help tonight

    regards,


    Melan'

  16. #16
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    - continued this has been sitting here for at least 3 hours -

    ... thought of something...

    that's going off a wild tangent... I should still be thinking about design...

    I gotta step back...

    Here are the concerns that are currently floating in my head...

    What types of classes would I need to put this whole thing together?

    I'm a little cloudy as to how the application can comprise of 3 classes - I'm thinking maybe we'd need utility (if that's the right term) classes like database, form and page classes to put it all together...

    This is where I'm getting stuck

    ok so basically this is what it's lookin' like so far...
    PHP Code:
    <?php 

    class users {
        var 
    $firstname;
        var 
    $surname;
        var 
    $username;
        var 
    $password;
        var 
    $state;
        var 
    $level;

        function 
    users($username,$password)
        {
            
    $this->firstname "";
            
    $this->surname "";
            
    $this->username $username;
            
    $this->password $password;
            
    $this->state "";
            
    $this->level 0;
        }
        
        function 
    login()
        {
        }
        
        function 
    logout()
        {
        }
    }

    class 
    projects {
        var 
    $projectNo;
        var 
    $projectId;
        var 
    $description;
        
        function 
    projects() 
        {
            
    $this->projectNo "";
            
    $this->projectId "";
            
    $this->description "";
        }
        function 
    createProject()
        {
        }
        
        function 
    updateProject()
        {
        }
        
        function 
    deleteProject()
        {
        }
    }

    class 
    tasks {
        var 
    $userId;
        var 
    $clientId;
        var 
    $projectId;

        function 
    tasks($user$clientId$projectId
        {
            
    $this->user $userId;
            
    $this->client $clientId;
            
    $this->projectId $projectId;        
        }
        
        function 
    addTask()
        {
        }
        
        function 
    deleteTask()
        {
        }
        
        function 
    updateTask()
        {
        }
    }
        
    class 
    clients {
        var 
    $clientName;
        var 
    $clientId;
        
        function 
    addClient()
        {
        }
        
        function 
    deleteClient()
        {
        }
        
        function 
    updateClient()
        {
        }
    }

    class 
    Database {
        var 
    $host;
        var 
    $username
        var 
    $password
        var 
    $database;
        var 
    $connId;
        
        function 
    Database($host$username$password$database)
        {
            
    $this->host $host;
            
    $this->username $username;
            
    $this->password $password;
            
    $this->database $database;
            
    $this->connectDb();
        }
        function 
    connectDb()
        {
        }
        
        function 
    disconnectDb()
        {
        }
        
        function &
    query()
        {
        }
        
        function 
    refIntegrity($child$parent$childId$parentId)
        {
        }
    }

    class 
    queryResult {
        var 
    $dbObject;
        var 
    $result;
        var 
    $resultOut;
        
        function 
    queryResult(&$dbObject,$result)
        {
            
    $this->dbObject = &$dbObject;
            
    $this->result $result;
            
    $this->resultOut = array();
        }
        
        function 
    size()
        {
        }
        
        function 
    fetch() 
        {
        }
    }

    class 
    page {
        var 
    $htmlOut;
        function 
    page()
        {
            
    $this->htmlOut;
        }
        
        function 
    addHeader()
        {
        }
        
        function 
    addFooter()
        {
        }
        
        function 
    addNav()
        {
        }
        
        function 
    addContent()
        {
        }
    }

    class 
    formFields {
        var 
    $field;
        function 
    setField($fieldHtml)
        {
            
    $this->field $fieldHtml;
        }
        
        function 
    getField()
        {
            return 
    $this->field;
        }
    }

    class 
    genericField extends formFields {
        function 
    genericField($type$name$attributes$value="")
        {
        }
    }

    class 
    selectField extends formFields {
        function 
    selectField($name$attributes$options)
        {
        }
    }

    class 
    textarea extends formFields  {
        function 
    textarea() 
        {
        }
    }
    ?>
    alright... I'm not sure if creating an abstract and concrete classes is going overkill...
    but we'll see how I go I guess...

    I feel like this is a product of lots of half absorbed examples and thoery.
    time for redirection... am I going the right way?
    Where am I going wrong?
    Am I implementing "unOOPish" methods in developing this application design?

    I think I'm going to read over the posts again...

  17. #17
    SitePoint Zealot
    Join Date
    Mar 2004
    Location
    netherlands
    Posts
    104
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, I have some thoughts on this subject, although it might not be as helpfull as lastcrafts post or others, I just hope it will give you some new insight on how you CAN () structure your objects.

    Lets take 1 problem; displaying the jobs in a form. Structural wise you might say: ok, there would obviously be a form object involved. Lets leave that for a second. If we think in what we must accomplish only, by defining types responsibilities we must need, we get another composition. (Part of Marcus' post is also based on this thought).

    So... we need to create a list of jobs somehow .. hoho! We got our first resposiblity! Lets say:

    PHP Code:
    $creator = new JobListCreator();
    echo 
    $creator->createFrom($jobs); //where jobs is just a simple array 
    We can implement this by putting all the displaying mechanisms hardcoded in the createFrom method.

    PHP Code:
    class JobListCreator
    {
        function 
    createFrom($jobs)
        {
            
    $result $this->_startForm('JobList');
            
    $result .= $this->_createOptionsFor($jobs);
            return 
    $result $this->_endForm();
        }

    This is pretty basic and mimimal. Good, thats the way it should be. We can now start finding the appropriate jobs to create from. heyhey, theres our second object.

    PHP Code:
    class JobFinder
    {
        function 
    findAll()
        {
            return array(
                            array(
                                    
    'id' => 1,
                                    
    'title' => 'job1'
                                
    ),
                            array(
                                    
    'id' => 2,
                                    
    'title' => 'job2'
                                
    )
                        );
        }

    I just make this an array here. The nice thing with OO is, that you can always change the implentation, with minimal changes. So if you want to find the jobs in the db, just place a query there.

    This total example is very mimimal. Good again. .. Ohoh, I just found a mixing in resposibilities. Yes, I hadn't noticed it before, but the JobListCreator _creates_ a list, so by that I ment constructing the list (like additional decorating or something, to make the list more complete if the finders information is not good enough). This is not in our initial requirements, so we could change it to JobListDisplayer. When we change the name and responsibility (you can now see by the name, that the object's responsibility is now to _display_ the list), we can easily extend the JobListDisplayer to display the list in another way.

    Now, I still want the constructing responsibility of the creator class (to name the form like we did above with '$this->_startForm('JobList')', and I also want to have that central point to turn to when constructing a list. So therefor Im meeting a new problem: I want a new object to somehow format my constructed list to a displayable string. Yep, we found a new object: A formatter.

    edit: to maybe clear up some confusions, I used the name 'formatter' instead of a 'displayer', because I think of the responsibility 'displaying' to be something to print directly to the screen, so thats not what I want . If you don't think of displaying to be something printed directly to the string, you could use the name 'displayer' instead ofcourse

    PHP Code:
    class ListCreator
    {
        function 
    ListCreator($listFormatter)
        {
            
    $this->_formatter $listFormatter;
        }
        
        
        function 
    createFrom($jobs)
        {
            
    $result $this->_formatter->start('JobListening');
            
    $result .= $this->_formatter->formatAll($jobs);
            return 
    $result $this->_formatter->end();
        }

    And:

    PHP Code:
    class JobListFormatter
    {
        function 
    start($title)
        {
            
    $result '<form action="'.$_SERVER['PHP_SELF'].'" method="post">'."\n";
            return 
    $result '<select name="'.$title.'">'."\n";
        }


        function 
    formatAll($list)
        {
            
    $result '';
            foreach(
    $list AS $item)
            {
                
    $result .= $this->formatSingle($item);
            }
            return 
    $result;
        }
        
        
        function 
    formatSingle($item)
        {
            return 
    '<option value="'.$item['id'].'">'.$item['title'].'</option>';
        }
        
        
        function 
    end()
        {
            
    $result "</select>\n";
            
    $result .= '<input type="submit" name="submit" value="submit">'."\n";
            return 
    $result "</form>\n";
        }

    We basicly moved the formatting methods from the original ListCreator class to the new Formatter class. Now the responsibilities fit again.

    Whats the gain you get from this structure? Well, seperating resposibilities gives you an almost instant reusability level. Lets say, we want to display the list in just a list with <br />'s. We can just extend the JobListFormatter to:

    PHP Code:
    class ListFormatter
    {
        function 
    start($title)
        {
            return 
    "<h2>".$title."</h2>\n";
        }
        
        
        function 
    formatAll($list)
        {
            
    $result '';
            foreach(
    $list AS $item)
            {
                
    $result .= $this->formatSingle($item);
            }
            return 
    $result;
        }
        
        
        function 
    formatSingle($item)
        {
            return 
    $item['title'] . "<br />\n";
        }
        
        
        function 
    end()
        {
            return 
    '// end of list';
        }

    In fact, we can refactor to a nice hierarcy with base methods like formatAll($list), because that method seems in this cases to always stay the same (see refactoring' from Martin Fowler for more neat tricks like these ).

    We can also extend JobFinder to for example; TextBasedJobFinder, to let the object search through text files. This way you can have all kinds of jobfinders at the same time, instead of keeping changing in the sourcecode.

    And we can even extend the JobListCreator to any listCreator, which all can use the formatters you pass it.

    This way it is much easier to think about objects and to implement them, than lets say, the structural decomposition.

    Im not saying this way it will work the best, and you might even say: "Noo, I think you got it totally wrong" , but hey, thats fine with me too

  18. #18
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Off Topic:

    You must spread some Reputation around before giving it to Manor again.


    Very insightful

  19. #19
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for input manor and chris... it's greatly appreciated...
    It has definately shed some light on what I see as a cloudy convoluted subject and reaffirmed what lastcraft and arborint are saying - "role based decomposition" (...right?)

    Dr. Livingston... what's your take on this? are you understanding this better than I am?
    You're hardcore in procedural php | intermediate in oop (I'm an avid reader of your posts) whereas I see myself more as an intermediate procedural PHPer | beginner oop PHPer (not even). Seeing that you're digesting some things from this too, it'd be great to see what kind of summaries you can come up with.

    It'd aid not only myself, but perhaps you also

    I find that the things I've learnt are cemented in when explaining to others what it is.

    Anyway, I've decided to start from scratch...

    Here's my thinking... (I feel so hopeless)

    I'll start with the user class... using my YADA class - once this is done, then I'll go start the other ones.

    - A user can login and logout and has the following properties:
    Username, Password, Level, id, Firstname, Surname, Email, LoginCount

    - It would pass the username, password and connection when instantiated.

    PHP Code:
    class users {
        
    // properties

        
    var $username;
        var 
    $password
        var 
    $db
        
    var $level;
        var 
    $id;
        var 
    $firstname;
        var 
    $surname;
        var 
    $email;
        var 
    $loginCount;
        var 
    $sessionId// right? 

        // constructor 
        
    function users($username$password, &$db// what exactly does &$db mean? I'm passing the object through as a reference yes, but what would be the difference if I didn't pass by reference? - I think I've just answered my own question in my head look at my comments below and tell me if I'm wrong. 
        
    {
            
    $this->username $username;
            
    $this->password $password;
            
    $this->db = &$db;
            
    $this->login();
        }

        function 
    login()
        {
            
    $this->level $db->getField('level');
            
    $this->id $db->getField('id');
            
    $this->firstname $db->getField('firstname');
            
    $this->surname $db->getField('surname');
            
    $this->email $db->getField('email');
            
    $this->loginCount $db->getField('loginCount');
            
    $this->sessionId $_SESSION[SID];
        }

        function 
    logout()
        {
        }

    It's not finished just yet, but eh...
    Feel free to tell me if I'm wrong.

  20. #20
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Aggregation...

    Here's my understanding of aggregation in a nutshell...

    You have two classes:
    - Database
    - User class

    The user class needs to connect to the database to retrieve some data regarding the user so the code kind of looks like this
    PHP Code:
    $dbObj = &new database($server,$user,$pass,$dbname);  // create database object
    $userObj = &new user($username,$password,&$db); // instantiate user class 
    The user object ($userObj) will encapsulate the database objects functionality within it.

    PHP Code:
    function login() 
    {
        
    $this->userinfo $this->db->query($sql);
        if (
    $recordsArr) {
            
    $this->level $this->userinfo[0][0];
            
    $this->id $this->userinfo[0][1];
            
    $this->firstname $this->userinfo[0][2];
            
    $this->surname $this->userinfo[0][3];
            
    //etc
        
    } else { 
            
    // do something;
        
    }

    this is what I plan on doing...
    we'll see how it works out down the track...

  21. #21
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Google is indeed my friend...

    I've done a search and realised that this is not the path for me at this point in time...

    I'm taking a step back for now and going to sink into thoery...

    I don't think "diving in" is what's productive at this point in time because I feel like I'm playing a game of "mastermind" with the OOP gurus heh

    me: "RED BLACK WHITE PINK BLUE GREEN ORANGE! Is that what you're thinking?"

    you: "No... you got nothing right..."

    me: "RED BLACK WHITE PINK BLUE GREEN ORANGE! Is that what you're thinking?"

    you: "No... that's the same as last time..."
    I've found this link that explains the basic concepts of OOP, not specifically in PHP, it's in C++ and heck it's pretty old (1996).

    But still, I think I might need some more grounding in thoery so that at least I know where I am going... I'm using "being busy" as an excuse for not ducking over to Dymocks and finding the OOP books suggested by Yogi and Dr Livingston.

    I'll have a look at this link and if it's still murky, I'll drag my lazy *** over to the bookstore...

    http://people.cs.vt.edu/~kafura/cs27....concepts.html

    Sorry if it seems like I'm making this my blog, but what I'm trying to do is leave some crumbs for the next guy who has decided to go from Procedural to OOP and only knowing OOP to be "Lego" or encapsulated functions (within static classes) without knowing how to implement it properly.

    regards,

    Hans- errr Melan'

  22. #22
    Compulsive Clubber icky_bu's Avatar
    Join Date
    Aug 2003
    Location
    Portugal
    Posts
    352
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dont give up... errr... step back. You seemed to be making progress. And sense!!!
    I'm also a new OOPer, so I'll set in some of my thoughts later on. I'm busy coding something and if it works out, I think it will be on the right track to my full understanding of this (to me new) concept.

  23. #23
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Melan'...don't give up - I found that the best way is to start slowly - go through the articles/topics in the Advanced PHP Resources thread and over at phpPatterns again and again till things start to sink in. There are some great guys on here who really know their stuff; I won't name loads of names for fear of leaving somebody out but I will mention one name and I'm sure many of the other gurus on here would agree with me:

    Vincent Oostindie.

    Track down his posts - he just seems to have a knack for describing things in a way that just make lots and lots of sense. I owe my current OOP knowledge to plenty of posters on here, but Vincent is the guy who got me going on the right track to begin with.

  24. #24
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hang in there!! Now that you have the basic OOP syntax down, you might want to check out this book recomendation as an alternative to help you progress down the path of OOPness.
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  25. #25
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you iky_bu, Luke and sweatje, I'm not giving up, just filling myself up with the basics first...

    I gotta take a strategic step backwards and explore the thoery behind the concept that's behind OOP first (I REALLY wasn't exaggerating when I said I said I was a n00b in oop)... it'll probably take me a day to read through some of my planned online material and RnD.

    Throughout the thread people are advising that I head toward role based composition (in their own different ways) and certain books...

    I'm trying to think about things with the role based composition psyche and when payday comes, I'm off to amazon.com


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
  •