Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP OOP approach difficultiues

Tags:

oop

php

Please see edit below

I'm trying to dive into OOP development in PHP and i'm really starting to develop a headache or ulcer. I just can't wrap my head around it, parts seem too illogical to me, and i have no clue where to start and it really frustrates me because i believe it's worth the effort to try to learn it and it provides my a better overview about my code.

Yesterday i spent the whole day searching for practical examples and explanational articles on the internet, but now i have the feeling that only confuses me more. I need some practical tips, not examples like


class person {
     var $name;
     function set_name($new_name) {
          $this->name = $new_name;
     }
     function get_name() {
          return $this->name;
     }
}
$stefan = new person();
$jimmy = new person;

$stefan->set_name("Stefan"); $jimmy->set_name("Jimmy");

echo "Stefan's full name: " . $stefan->get_name(); echo "Jimmy's full name: " . $jimmy->get_name();

Examples like this makes me question why i shouldn't (because it's all defined in the same page) just do

$name = "Stefan"; 
echo "Stefan's full name: ".$name;

Shorter (less code) and more obvious if you ask me?

Nou to my project.

The thing i'm trying to make is a simple portfolio website. Herefore i only need 4 pages, a home page, information page, a page about my work and a contact form. I use three tables clients, content and media which i want to use on the my work page.

I was thinking about my structure and came up (in my head, no clue how to achieve it) with something like

class Database{}
class Content extends Database{}
     function showMenu(){}
     function showContent{}
class Clients extends Database{}
     function showClientList{}
     function showClientDetails{}
class Media extends Database{}

I already made a database class that establishes a database connection with a public method query($qry). I started with the Content class and it looks like this at the moment:


class Content extends Database {
    public function topMenu($page){
        $db = new Database();
        $db->connect();
        $db->query("SELECT m_link, m_title, m_accesskey FROM menu WHERE m_type = 'top'"); 
        $res = $db->getResult();
        foreach($res AS $show){
            if($page == $show['m_link']){
                echo("<li id="active">$show['m_title']."</li>\n");
            }else{
                echo("<li>$show['m_title']."</li>\n");
            }
        }
    }
}

Does this make any sense at all by the way?

On my index.php i have the following lines to display the menu (which work fine) $content = new Content(); $content->topMenu($_aGET[0]);

The point where i'm loosing it is the way top display either the client list or the client details, which depends on the variable $_aGET[0] (which holds the url)

Suppose i want to display the client details, herefore i need records from all three the tables, so normally i would use a couple of join's, like so

$query = "
    SELECT cl.c_id, cl.c_client, cl.c_client_desc, ncc.clco_cl_id, ncc.clco_co_id, co.c_content, ncm.clme_me_id, ncm.clme_cl_id, GROUP_CONCAT(me.m_link) AS images_link
    FROM clienten AS cl
    LEFT JOIN norm_cl_co_rel AS ncc ON cl.c_id = ncc.clco_cl_id
    LEFT JOIN content AS co ON ncc.clco_co_id = co.c_id
    LEFT JOIN norm_cl_me_rel AS ncm ON cl.c_id = ncm.clme_cl_id
    LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
    WHERE cl.c_client = '".mysql_real_escape_string($_aGET[1])."'
    AND cl.c_language_id = '"._LANGUAGE."' 
    AND cl.c_active = '1'
";

But as far is i understand the OOP thoughts, i should have a method for each tables defined in a class (right?) But how am i going to join these?

Or does my 'story' looks something like: 'Dude, just drop it and stick with procedural coding'?

EDIT:

Ok, after Fluffeh's post i used his example and modified it a bit to test it. The problem is that i do get some output, but not the desired. My output is like below

ID: CompanyName
C
Desc: C
Media:
: 
: 
: 
: 
:

while i should get (values are in the database):

ID: CompanyName
CompanyName
Desc: CompanyName is a company
Media:
: Image 1
: Image 2
: Image 3
: Image 4
: Image 5

My code looks like so:

class media{
    public $type;
    public $title;
    public $image;
    public $desc;
}

class client{
    public $name;
    public $desc;
}

class clientDetails{

    private $clientID;
    public $clientName;
    public $clientDesc;
    public $clientMedia = array();
    public $clientMediaFiles = 0;

    public function __construct($myID){
        $this->clientID = $myID;
    }

    public function getMyDetails(){

        $db = new Database();
        $db->connect();
        $db->query("
            SELECT c_client, c_client_desc 
            FROM clienten 
            WHERE c_client = '".mysql_real_escape_string($this->clientID)."'
        ");
        foreach($db->getResult() as $client){
            $this->name = $client['c_client'];
            $this->desc = $client['c_client_desc'];
        }

        $db = new Database();
        $db->connect();
        $db->query("
            SELECT ncm.clme_me_id, ncm.clme_cl_id, cl.c_id, me.m_id, me.m_type, me.m_title, me.m_desc, me.m_link
            FROM norm_cl_me_rel AS ncm
            LEFT JOIN clienten AS cl ON cl.c_id = ncm.clme_cl_id
            LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
            WHERE me.m_id IN(1,2,3,4,5)
        ");
        foreach($db->getResult() as $media){
            $this->clientMedia[$i]= new media();
            $this->clientMedia[$i]->type = $media['m_type'];
            $this->clientMedia[$i]->title = $media['m_title'];
            $this->clientMedia[$i]->image = $media['m_image'];
            $this->clientMedia[$i]->desc = $media['m_desc'];
            $this->clientMediaFiles++;
        }
    }

    public function displayMyResults(){
        echo "ID: $this->clientID";
        echo "&lt;div>&lt;h3>".$this->name."&lt;/h3>";
        echo "Desc: ".$this->desc."&lt;br>";
        echo "Media:&lt;br>";
        for($i=0;$i<$this->clientMediaFiles;$i++){
            echo $this->clientMedia[$i]->title." : ".$this->clientMedia[$i]->desc."&lt;br>";
        }
        echo "&lt;/div>";
    }

}
like image 549
Maurice Avatar asked Oct 23 '22 14:10

Maurice


1 Answers

Keep going with OOP. Once you get it, you will never want to go back to pesky, troublesome, nasty, horrible, rabid procedural code.

To take the example of this: Suppose i want to display the client details, herefore i need records from all three the tables, so normally i would use a couple of join's, like so...

This is a great example that can be used to show you how useful OOP can be.

Create a class for ClientDetails

  • Create a constructor within it that accepts the clientID as an argument.
  • Inside this constructor, have it run the code and populate it's internal variables with the data that is returned by the query.
  • Create a function that outputs the data that is returned into a nice format.
  • Now create it from your main code and have it display it's details

Suddenly you have a few lines of code in a class, but can display your data perfectly in 2 lines of code.

I will be adding some example code shortly, will see if I can rummage some of my classes for a demo.

Edit: Dammit, no rummaging of old classes, much too detailed for this, but I wrote some code for an example:

<?php

class clientContact
{
    public $name;
    public $phone;
}

class clientDetails
{
    private $clientID;      //only this class can access this variable.
    public $clientName;     // Anything can change these.
    public $clientPhone;
    public $additionalContacts= array();
    public $associates=0;

    public function __construct($myID)
    // This is a magic function that is called every time we make a new object of this class.
    {
        $this->$clientID=$myID;
    }

    public function getMyDetails()
    // This function will query the database to get it's information properly
    // and populate itself with everything it needs. You could do this as part
    // of the __construct() call, but I didn't want to do TOO much code.
    {
        $sql="select clientName, clientPhone from clients where clientID=".$this->clientID.";";
        // skipping over full SQl bits...
        foreach($stmt as $clientContact)
        {
            $this->clientName=$clientContact->clientName;
            $this->clientPhone=$clientContact->clientPhone;
        }

        $sql="select clientName, clientPhone from associates where assocID=".$this->clientID.";";
        // skipping over full SQl bits...
        foreach($stmt as $clientContact)
        {
            $this->additionalContacts[$i]= new clientContact();
            $this->additionalContacts[$i]->name=$clientContact->name;
            $this->additionalContacts[$i]->phone=$clientContact->phone;
            $this->associates++;
        }

    }

    public function displayMyResults()
    // This function will simply display everything it has in a nicely format
    {
        echo "<div><h3>".$this->clientName."</h3>";
        echo "My contact phone number is :".$this->phone."<br>";
        echo "My associates are:<br>";
        for($i=0;$i<$this-associates;$i++)
        {
            echo $this->additionalContacts[$i]->name." : ".$this->additionalContacts[$i]->phone."<br>";
        }
        echo "</div>";

    }
}

?>

Good god, that's long and horrible right?

Not really. Here is why.

Sure, there is a bit of code in the class, but now, you can do the following on your main page:

<?php 

    $someArray=array(36, 25, 76); 
    // This could be from a query, or a form, or anything else

    for($i=0;$i<count($someArray);$i++)
    {
        $currentContact= new clientDetails($someArray[$i]);
        // This is how we create the object.

        $currentContact->getMyDetails();
        // This now tells the object to get it's own data

        $currentContact->displayMyResults();
        // This now displays the data in the object to the page.
        echo "<hr>";
        unset($currentContact);
    }
?>

And with that TINY snippet of code, you have just displayed all the contacts, formatted as you want and you just perfectly displayed all the contacts exactly how you wanted them.

Now imagine that instead of just one little example like this, you use these sort of objects for ALL your content. A post on a forum? One object. A complex calculation for a business KPI? One Object that can get all of the data it has, then calculate a prediction, display the result in a graph and email it to the users that need it.

OOP can have a steep learning curve when you come from a background of HTML and PHP script which executes from top to bottom, but when you start getting the hang of it, you will wish you had learned it from the start.

Edit:

You don't seem to have the column m_image in your query:

    $db = new Database();
    $db->connect();
    $db->query("
        SELECT cl.c_id, ncm.clme_me_id, ncm.clme_cl_id, me.m_type, me.m_title, me.m_desc, me.m_link, m_image
        FROM clienten AS cl
        LEFT JOIN norm_cl_me_rel AS ncm ON cl.c_id = ncm.clme_cl_id
        LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
        WHERE me.m_id IN(1,2,3,4,5)
    ");
    foreach($db->getResult() as $media){
        $this->clientMedia[$i]= new media();
        $this->clientMedia[$i]->type = $media['m_type'];
        $this->clientMedia[$i]->title = $media['m_title'];
        $this->clientMedia[$i]->image = $media['m_image'];
        $this->clientMedia[$i]->desc = $media['m_desc'];
        $this->clientMediaFiles++;
    }

Edit 2: I am not 100% sure, but it might be the field names being returned. Try replaceing the query with this:

SELECT cl.c_id as c_id, ncm.clme_me_id as clme_me_id, ncm.clme_cl_id as clme_cl_id, me.m_type as m_type, me.m_title as m_title, me.m_desc as m_desc, me. as m_link
FROM clienten AS cl
LEFT JOIN norm_cl_me_rel AS ncm ON cl.c_id = ncm.clme_cl_id
LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
WHERE me.m_id IN(1,2,3,4,5)
like image 65
Fluffeh Avatar answered Nov 03 '22 03:11

Fluffeh