Welcome Guest, Not a member yet? Register   Sign In
Use object oriented programming in CI
#1

Hello, 

my name is Akis and I've just sign up the forum but I'm not new in CI. I love this framework. I'm using it for 5 years now and I think I will be using it for many years more. I'm exciting for being informed that CI 4 is about to released ...

Since now I write code without using oop logic in my project (ofcourse except the CI core logic which is object oriented). I just use cmv model without write any class: in controller files I manage the data, in model file I have my sqls and in view files I have the output.

I'm never wrote any fully object oriented project in any program language or framework but I'm familiar with it.

The fact is that I'm not sure how I can use oop logic in CI. Let me use an example to deploy my thinking. Let's say we have the following simple db schema:

Office
  id
  floor
  number
  descr

Employee
  id
  name
  sirname
  office_id (foreign key)


In oop I would created two classes for these two tables. The code below is the class for Office:

Class Office {
  public $id, $floor, $number, $descr

  // Construct method without any param
  function __construct() {
    // code
  }

  // Overloading construct method using param to get the data from db for a specific office
  function __construct($office_id) {
    // Reference to model file (sqls.php)
    $office_details = $this->sqls->get_office($office_id);

    $id = $office_details['id'];
    $floor = $office_details['floor'];
    $number = $office_details['number'];
    $descr = $office_details['descr'];
  }

  // Add office in DB method
  public addOffice {
    // Reference to model file (sqls.php)
    $new_id = $this->sqls->add_office();
  }

  // Delete office from DB method
  public deleteOffice($office_id) {
    // Reference to model file (sqls.php)
    $this->sqls->delete_office($office_id);
  }

  ...
}

Since I'm done with writing all Classes, I imagine that I must import the file that contains all classes into the controller file. Lets say I want to  show in a html table all the offices. Should I create as many objects of Office class as the number of the rows in db table 'Office' like below?
 
// Reference to model file (sqls.php)
$offices = $this->sqls->get_offices();

foreach ($offices as $o) {
  $office_object = new Office($o['id']);

  // pass data to view file via $data variable
  $data[$o['id']]['floor'] = $office_object->floor;
  $data[$o['id']]['number'] = $office_object->number;
  $data[$o['id']]['descr'] = $office_object->descr;
}


Is my way of thinking right?? Because it seems logically wrong to create so many objects. I dont know if I'm right. 

Is there a better way to use oop in CI? 

Thank you very much
Akis
Reply
#2

There are multiple ways to do this using CI - here is one way. I only address the "Offices" table but the structure will transfer to Employee easily enough.

One of the great things about the CI model class is that it will create/return objects based on the query. So you don't have to create them yourself. (But you can if you want. Read the docs to see how.)

Here is the model for 'offices'
file: /application/models/Offices_model.php

Code:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/*
* The table 'office' has these fields
  id (a unique value, auto incrementing field)
  floor
  number (unique values)
  descr
*/

class Offices_model extends CI_Model
{
    public function __construct()
    {
        parent::__construct();
        $this->load->database(); //could be autoloaded via /config/autoload.php instead
    }

    /**
     * Returns data about a specific office based on the value of $office_id matching the 'number' field
     * Assumes that the 'number' field contains unique values. Only a single db row is returned.
     *
     * @param string $office_number The 'number' of the office you are interested in
     * @return array Where the only item is an object where each property is a named field.
     * If no data is found the return will be array with a message in the 'descr' field of the array's only item
     */
    public function get_office($office_number)
    {
        if(empty($office_number))
        {
            return $this->fallback_result("Need an office number - none provided");
        }
        $sql = "SELECT * from office WHERE number = ?";
        $query = $this->db->query($sql, array($office_number));
        //If $office_id === "12345" produces SELECT * FROM office WHERE number=`12345`
        //returns only a single row in an array

        return $query->num_rows() > 0 ? $query->result() : $this->fallback_result("Office number $office_number not found.");
    }

    /**
     * Get all the office table data
     *
     * @return array Either an array of "row" objects or a "fallback" array if no rows are found
     */
    public function get_all()
    {
        $query = $this->db->get('office');
        return $query->num_rows() > 0 ? $query->result() : $this->fallback_result('No Offices Available');
    }

    /**
     * Insert a new office into the database
     *
     * @param array $data Is the info to be inserted e.g.
     *     array('floor'=>'22', 'number'=>'12345', 'descr'=>'Naughty Programmers')
     * @return mixed Either the 'id' of the newly inserted row or NULL if the insert fails
     */
    public function add_office($data)
    {
        $result = $this->db->insert('office', $data);
        // Using the $data array in the above comment would produce:
        //     INSERT INTO office (floor, number, descr) VALUES ('22', '12345', 'Naughty Programmers')

        return $result ? $this->db->insert_id() : NULL;
    }

    /**
     * Delete an office from the database
     *
     * @param string $office_id The 'number' of the office to be deleted
     * @return mixed Either a CI_DB_query_builder instance (for method chaining) or FALSE on failure
     */
    public function delete_office($office_id)
    {
        return $this->db->delete('office', array('number' => $office_id));
        //If $office_id === "12345" produces DELETE FROM office WHERE number=`12345`
    }

    /**
     * Constructs an object that will be useable by the controller in cases where query results are empty
     *
     * @param string $message That will be put in the 'descr' property
     * @return \stdClass
     */
    protected function fallback_result($message)
    {
        //Build and return a fallback object
        $out = new stdClass();
        $out->id = "";
        $out->floor = "";
        $out->number = "";
        $out->descr = $message;
        return array($out);
    }

}

Here is a very simple controller that utilizes the model. It has two methods: one to show all the offices and another to show a single office.

file: /application/controllers/Offices.php

Code:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Offices extends CI_Controller
{
    function __construct()
    {
        parent::__construct();
        $this->load->model('offices_model'); //load the model
    }

    /*
     * The default for this controller will be to show all the offices
     */
    public function index()
    {
        $data['offices'] = $this->offices_model->get_all();
        $this->load->view('offices_view', $data);
    }

    /*
     * View only a single office. Assuming the site is example.com  would use the URL
     * http://example.com/offices/office/12345  (A route could be defined to get around this ugly URL)
     */
    public function office($param)
    {
        $data['offices'] = $this->offices_model->get_office($param);
        //we use the same view as index() as it will work for this example
        //a 'real' site would probably need a separate view file
        $this->load->view('offices_view', $data);
    }

}

The view file is very, very simple.

Note, I prefer to drop in and out of the PHP interpreter instead of using 'echo' with concatenated strings. I usually get my intended results more quickly that way. Adjust according to your style.

file: /application/views/offices_view.php

Code:
<?php foreach($offices as $office): ?>
    <p> Office: <?= $office->descr; ?> Floor: <?= $office->floor; ?> Number: <?= $office->number; ?></p>
<?php
endforeach;
Reply
#3

Yeah that's much more easier than the way I described. I will test it soon...

Thank you very much
Reply




Theme © iAndrew 2016 - Forum software by © MyBB