SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Enthusiast
    Join Date
    Nov 2002
    Posts
    32
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    PHP OOP Help with basics

    I am fairly new to OOP and PHP. I worked my way through Kevin Yank's book and wanted to keep advancing to some OOP concepts. But I am a bit lost and I need help.

    I followed Kevin's instructions and created a db.inc.php file for my PDO db connection:

    Code:
    <?php 
    
    
    //db connection using PDO class object
    
    
    try {
    
    
        //create new PDO class object
        $pdo = new PDO('mysql:host=122.2.2.2;port=3307;dbname=mydbname','dbuser','password');
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $pdo->exec('SET NAMES "utf8"');
        
    }
    catch (PDOException $e)
    {
        //if unable to connect, tell us why
        $output = 'Unable to connect to the database server 2.'.$e->getMessage();
        include 'output.html.php';
        exit();
    
    
    }
    I created a the following class:

    Code:
    <?php
    
    
    class Vendor {
        
        protected $name;
        protected $address;
        protected $city;
        protected $state;
        protected $postal;
        protected $country;
        protected $tel;
        protected $email;
        protected $web;
         
         
        public function __construct(){
            //typically first function to appear in a class
            // Constructor using MagicMethod
            $this->name = $name;
            $this->address = $address;
            $this->city = $city;
            $this->state = $state;
            $this->postal = $postal;
            $this->country = $country;
            $this->tel= $tel;
            $this->email = $email;
            $this->web = $web;
           
        }
        
        public  function getVendors($pdo){
        
            //get all vendor data from db
            try
            {
                //prepares a statement for execution and returns a statement object
                $query = $pdo->prepare("SELECT * FROM vendor ORDER BY name");
                $query->execute();
                
                $vendors = array();
                foreach ($query->fetchAll() as $row){
                    
                    //create array of member objects
                    $vendors[] = new Vendor($row);
                }
                
                return array($vendors);
            
            }
            catch (PDOException $e)
            {
                //handle any errors
                $output = 'Error fetching vendors: ' . $e->getMessage();
                include 'output.html.php';
                exit();
    
    
            }//end try catch
        }//end function
        
        
        //setters
                      
        public function setName( $name ){
            $this->name = $value;
        }
            
        public function setAddress( $address ){
            $this->address = $value;
        }
                
       public function setCity( $city ){
            $this->city = $value;
        }
                
       public function setState( $state ){
            $this->state = $value;
        }
                
        public function setPostal( $postal ){
            $this->postal = $value;
        }
                
        public function setCountry( $country ){
            $this->country = $value;
        }
                
        public function setTel( $tel ){
            $this->tel = $value;
        }
                
        public function setEmail( $email ){
            $this->email = $value;
        }
                
        public function setWeb( $web ){
            $this->web = $value;
        }
                
      
        //getters
        
        public function getName(){
            return $this->name;
        }
        
       public function getAddress(){
            return $this->address;
        }
        
        public function getCity(){
            return $this->city;
        }
      
        public function getState(){
            return $this->state;
        }
        
        public function getPostal(){
            return $this->postal;
        }
        
        public function getCountry(){
            return $this->country;
        }
        
        public function getTel(){
            return $this->tel;
        }
        
        public function getEmail(){
            return $this->email;
        }
        
        public function getWeb(){
            return $this->web;
        }
         
    }
    I have an index.php file that is calling the list of vendors

    Code:
    <?php 
    
    
    //get all vendors
    
    
    include_once $_SERVER['DOCUMENT_ROOT'] .'/db.inc.php'; 
    include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/Vendor.Class.php'; 
    
    
    //instantiate class
    $vendor = new Vendor();
    
    //calling my function to get a list of vendors
    $vendors = $vendor->getVendors($pdo);
    
    //trying to receive an array of objects but basically getting empty objects
    echo $vendors;
    print_r($vendors);
    
    
    
    
    //output to template
    include 'output.html.php';
    The idea is to then use a template/output html file to output data:

    Code:
    <?php foreach ($vendors as $vendor){
                
                $name = $vendor->getName();
                $address2 = $vendor->getAddress2();
                $city = $vendor->getCity();
                $zip = $vendor->getZip();
                $web = $vendor->getWeb();
                $phone = $vendor->getTel();
    
    
     ?>
    My questions:

    1. In my vendor class I am creating an array of Vendor Objects - is this the correct OOP way of returning my rows from DB?
    2. If my country and city are IDs, and each has their own class, when and where is the appropriate time to call those classes and use getCity($id) and getCountry($id) to get name values instead of ids?
    3. Also, if am have to loop through the result set, and that does involve getting the city and country name values, is it ok to do that in the html output file? or should that be done in my index.php file (controller)?

    Any assistance is greatly appreciated.

  2. #2
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,397
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Hi xuamox,

    First off, I spotted a small problem with your Vendor class. You're trying to pass in a row from the DB when you create a new instance, but the constructor doesn't have any arguments defined. What you want is something like this:

    PHP Code:
    public function __construct(array $values){
            
    $this->name $values['name'];
            
    $this->address $values['address'];
            
    $this->city $values['city'];
            
    $this->state $values['state'];
            
    $this->postal $values['posta']l;
            
    $this->country $values['country'];
            
    $this->tel $values['tel'];
            
    $this->email $values['email'];
            
    $this->web $values['web'];

    also, in your getVendors method, when you return the array of vendors you're actually wrapping it in a second array.

    In answer to your questions:

    Quote Originally Posted by xuamox View Post
    1. In my vendor class I am creating an array of Vendor Objects - is this the correct OOP way of returning my rows from DB?
    I think it would be better to have a separate mapper class that is responsible for retrieving and persisting Vendor objects.

    PHP Code:
    class VendorMapper
    {
        protected 
    $pdo;

        public function 
    __construct(PDO $pdo)
        {
            
    $this->pdo $pdo;
        }

        public function 
    fetchAll()
        {
            
    $query $this->pdo->prepare("SELECT * FROM vendor ORDER BY name");
            
    $query->execute();
                
            
    $vendors = array();
            foreach (
    $query->fetchAll(PDO::FETCH_ASSOC) as $row)
            {
                
    $vendors[] = new Vendor($row);
            }
                
            return 
    $vendors;
        }

        public function 
    fetchById($id)
        {
            
    // ...
        
    }

        public function 
    save(Vendor $vendor)
        {
            
    // ...
        
    }

    }

    $mapper = new VendorMapper($pdo);
    $vendors $mapper->fetchAll(); 
    Quote Originally Posted by xuamox View Post
    2. If my country and city are IDs, and each has their own class, when and where is the appropriate time to call those classes and use getCity($id) and getCountry($id) to get name values instead of ids?
    I would say objects for concepts like City and Country are better represented as value objects, rather than entities (i.e the object should be immutable and its identity comes from its values, not an id).

    PHP Code:
    class City
    {
        private 
    $name;

        public function 
    __construct($name)
        {
            
    $this->name $name;
        }

        public function 
    getName()
        {
            return 
    $this->name;
        }

        public function 
    __toString()
        {
            return 
    $this->name;
        }
    }

    // In your VendorMapper (or wherever you create your Vendor objects
    $this->city = new City($values['city']); 
    Quote Originally Posted by xuamox View Post
    3. Also, if am have to loop through the result set, and that does involve getting the city and country name values, is it ok to do that in the html output file? or should that be done in my index.php file (controller)?
    You don't want to be retrieving any data from the DB within your view, as it's the controller's responsibility to pass data to the view. In my answer to your second question, I added a __toString magic method to the City class, which means that in your view you can just do:
    PHP Code:
    echo $vendor->getCity() 
    "There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies."

  3. #3
    SitePoint Enthusiast
    Join Date
    Nov 2002
    Posts
    32
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for your input.
    So you are suggesting that I use Mapper Classes to handle all DB interactions?
    And can you explain what you mean by using value objects vs. entities for fields such as city and country?

  4. #4
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Yeah its a very good practice to use data mapper classes to handle DB interactions, you can even further factor out query factories outside of data mapper but for beginners the data mappers are sufficient to carry out all SQL database interaction code. Its about separation of concerns/responsibilities, and to modularize your code into reusable classes.

    The difference between value objects and entities is that the former is immutable, by immutable I mean that they are read-only objects whose internal values do not get changed at runtime. A city for instance, remains the same city throughout the lifetime of your script. You can create other cities, but when you do so you create a different value object. Entities, on the other hand, get changed frequently in your script, they are mutable.

  5. #5
    Always A Novice bronze trophy
    K. Wolfe's Avatar
    Join Date
    Nov 2003
    Location
    Columbus, OH
    Posts
    2,181
    Mentioned
    65 Post(s)
    Tagged
    2 Thread(s)
    Fret, stopping in with a suggestion to fetch all (and the whole class in general) you may want to return the PDOStatement object immediately after execute, and let the itteration occur procedurally so that the entire result does not have to be read into memory (may be dealing with a large table).
    Last edited by K. Wolfe; Apr 24, 2014 at 11:45. Reason: PDOStatement object not PDO object

  6. #6
    SitePoint Enthusiast
    Join Date
    Nov 2002
    Posts
    32
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally, I thought I would have a table for "cities" and a table for "countries", and then I would store the ID of each city and country in my Vendor table. I would then create a class for each entity. But it sounds like you guys are recommending a different approach. Do I still store cities and countries in a db table, and do I create classes and mapper classes for them?

    On a separate note, do you know of any good books that explain these concepts? I have read Kevin Yanks book PHP & MySQL: Novice To Ninja, 5th Edition, and started to read "PHP Master: Write Cutting-edge Code" as well as Beginning PHP 5.3 by Matt Doyle. None of these books mention "Mapper Classes" or "immutable ojects". I find that there seems to be a large information gap between coding a data driven PHP website procedurally, and an OOP data driven one - especially for beginners.

  7. #7
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,397
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by K. Wolfe View Post
    Fret, stopping in with a suggestion to fetch all (and the whole class in general) you may want to return the PDOStatement object immediately after execute, and let the itteration occur procedurally so that the entire result does not have to be read into memory (may be dealing with a large table).
    That's a fair point, but it seems odd to be mapping the DB results to objects outside of the mapper class. What about a creating a collection class which wraps the PDOStatement and creates Vendor objects as it's iterated over?

    Quote Originally Posted by xuamox View Post
    Originally, I thought I would have a table for "cities" and a table for "countries", and then I would store the ID of each city and country in my Vendor table. I would then create a class for each entity. But it sounds like you guys are recommending a different approach. Do I still store cities and countries in a db table, and do I create classes and mapper classes for them?
    I'm in the process of learning to incorporate value objects in my code more myself, so others here might have more experience on the best way to deal with persisting them in the DB. I'd say you probably still want a table for countries and cities to be able to generate dropdown lists for forms etc.

    The VendorMapper class should be responsible for building out the Vendor object though, including any objects that it's composed of. If your city is linked to a vendor by an ID, you pull it in together with the vendor data via a JOIN query. Alternatively, you could denormalize the data a little by simply store the city name directly in the vendor table.

    Quote Originally Posted by xuamox View Post
    On a separate note, do you know of any good books that explain these concepts? I have read Kevin Yanks book PHP & MySQL: Novice To Ninja, 5th Edition, and started to read "PHP Master: Write Cutting-edge Code" as well as Beginning PHP 5.3 by Matt Doyle. None of these books mention "Mapper Classes" or "immutable ojects". I find that there seems to be a large information gap between coding a data driven PHP website procedurally, and an OOP data driven one - especially for beginners.
    Check out PHP 5 Objects, Patterns, and Practice by Matt Zandstra, it covers things such as value objects, entities, mappers and other design patterns.
    "There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies."

  8. #8
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,397
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    You might also find this SitePoint article interesting: http://www.sitepoint.com/integrating-the-data-mappers/
    "There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies."


Tags for this Thread

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
  •