May 22, 2015

Simple Image Gallery CRUD with CodeIgniter 3

Go into folder application/config/ and open file routes.php where you can find the default controller. Change it to:
$route['default_controller'] = 'gallery';

Database Structure

CREATE TABLE IF NOT EXISTS `images` (
  `id` int(10) NOT NULL,
  `file` text NOT NULL,
  `caption` text NOT NULL,
  `description` text NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

The Model

To interact with data in the database, we should first create a model for our gallery. Now go into folder application/models/ then create a new file Gallery_model.php. Our model structure should be designed like this:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Gallery_model extends CI_Model {

 public function all() {}

 public function find($id) {}

 public function create($data) {}

 public function update($id, $data) {}

 public function delete($id) {}

}

To create a new record storing our uploaded image, we write a function called create($data). The parameter should be in associative array format containing our image data. And if something goes wrong while inserting, we should echo out the errors.
   public function create($data)
   {
      try{
         $this->db->insert('images', $data);
         return true;
      }catch(Exception $e){
         echo $e->getMessage();
      }
   }
To retrieve all records from our table, we write a function called all() and it should be as simple as this:
   public function all()
   {
      $result = $this->db->get('images');
      return $result;
   }
To retrieve a specific record identified by it's ID, we can write a function called find($id). The parameter is an integer identifying the record we are looking for.
   public function find($id)
   {
      $row = $this->db->where('id',$id)->limit(1)->get('images');
      return $row;
   }
To update a record, we need to know the ID of record and also the new data to replace the old ones. In this case, we can write a function called update($id, $data). The first parameter is an integer and the second one should be a variable representing an associative array format.
   public function update($id, $data)
   {
      try{
         $this->db->where('id',$id)->limit(1)->update('images', $data);
         return true;
      }catch(Exception $e){
         echo $e->getMessage();
      }
   }
Lastly in our model, is the delete($id) function. The only parameter we need is an integer defining ID of the record we want to delete.
   public function delete($id)
   {
      try {
         $this->db->where('id',$id)->delete('images');
         return true;
      }

      //catch exception
      catch(Exception $e) {
        echo $e->getMessage();
      }
   }
That's it! We have just finished the model. Next we are going to design three HTML files for the views.

The Views

The first HTML file will be a list of all uploaded images on the gallery. Create a new file under the application/views/gallery/ directory and name it index.php.
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?><!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8">
   <title>CodeIgniter Image Gallery</title>

   <link href='http://fonts.googleapis.com/css?family=Oxygen' rel='stylesheet' type='text/css'>
   <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
   <style type="text/css">

   ::selection { background-color: #E13300; color: white; }
   ::-moz-selection { background-color: #E13300; color: white; }

   body {
      background-color: #fff;
      margin: 40px;
      font: 16px/24px normal 'Oxygen', sans-serif;
      color: #4F5155;
   }

   a {
      color: #003399;
      background-color: transparent;
      font-weight: normal;
   }

   h1 {
      color: #444;
      background-color: transparent;
      border-bottom: 1px solid #D0D0D0;
      font-size: 19px;
      font-weight: normal;
      margin: 0 0 14px 0;
      padding: 14px 15px 10px 15px;
   }

   code {
      font-family: Consolas, Monaco, Courier New, Courier, monospace;
      font-size: 12px;
      background-color: #f9f9f9;
      border: 1px solid #D0D0D0;
      color: #002166;
      display: block;
      margin: 14px 0 14px 0;
      padding: 12px 10px 12px 10px;
   }

   #body {
      margin: 0 15px 0 15px;
   }

   p.footer {
      text-align: right;
      font-size: 11px;
      border-top: 1px solid #D0D0D0;
      line-height: 32px;
      padding: 0 10px 0 10px;
      margin: 20px 0 0 0;
   }

   #container {
      margin: 10px;
      border: 1px solid #D0D0D0;
      box-shadow: 0 0 8px #D0D0D0;
   }
   </style>
</head>
<body>

<div id="container">
   <h1>CodeIgniter Image Gallery</h1>

   <div id="body">
      <?php if($images->num_rows() > 0) : ?>
         
         <?php if($this->session->flashdata('message')) : ?>
            <div class="alert alert-success" role="alert" align="center">
               <?=$this->session->flashdata('message')?>
            </div>
         <?php endif; ?>

         <div align="center"><?=anchor('gallery/add','Add a new image',['class'=>'btn btn-primary'])?></div>
         <hr />   
         <div class="row">
            <?php foreach($images->result() as $img) : ?>
            <div class="col-md-3">
               <div class="thumbnail">
                  <?=img($img->file)?>
                  <div class="caption">
                     <h3><?=$img->caption?></h3>
                     <p><?=substr($img->description, 0,100)?>...</p>
                     <p>
                        <?=anchor('gallery/edit/'.$img->id,'Edit',['class'=>'btn btn-warning', 'role'=>'button'])?>
                        <?=anchor('gallery/delete/'.$img->id,'Delete',['class'=>'btn btn-danger', 'role'=>'button','onclick'=>'return confirm(\'Are you sure?\')'])?>
                     </p>
                  </div>
               </div>
            </div>
            <?php endforeach; ?>
         </div>
      <?php else : ?>
         <div align="center">We don't have any image yet, go ahead and <?=anchor('gallery/add','add a new one')?>.</div>
      <?php endif; ?>
   </div>

   <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo  (ENVIRONMENT === 'development') ?  'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
</div>

</body>
</html>
The second HTML file is the add new image form page. Create a new file under application/views/gallery/ directoy and name it add_image.php.
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?><!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8">
   <title>Add New Image</title>

   <link href='http://fonts.googleapis.com/css?family=Oxygen' rel='stylesheet' type='text/css'>
   <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
   <style type="text/css">

   ::selection { background-color: #E13300; color: white; }
   ::-moz-selection { background-color: #E13300; color: white; }

   body {
      background-color: #fff;
      margin: 40px;
      font: 16px/24px normal 'Oxygen', sans-serif;
      color: #4F5155;
   }

   a {
      color: #003399;
      background-color: transparent;
      font-weight: normal;
   }

   h1 {
      color: #444;
      background-color: transparent;
      border-bottom: 1px solid #D0D0D0;
      font-size: 19px;
      font-weight: normal;
      margin: 0 0 14px 0;
      padding: 14px 15px 10px 15px;
   }

   code {
      font-family: Consolas, Monaco, Courier New, Courier, monospace;
      font-size: 12px;
      background-color: #f9f9f9;
      border: 1px solid #D0D0D0;
      color: #002166;
      display: block;
      margin: 14px 0 14px 0;
      padding: 12px 10px 12px 10px;
   }

   #body {
      margin: 0 15px 0 15px;
   }

   p.footer {
      text-align: right;
      font-size: 11px;
      border-top: 1px solid #D0D0D0;
      line-height: 32px;
      padding: 0 10px 0 10px;
      margin: 20px 0 0 0;
   }

   #container {
      margin: 10px;
      border: 1px solid #D0D0D0;
      box-shadow: 0 0 8px #D0D0D0;
   }
   </style>
</head>
<body>

<div id="container">
   <h1>Add New Image</h1>

   <div id="body">
      <?php if(validation_errors() || isset($error)) : ?>
         <div class="alert alert-danger" role="alert" align="center">
            <?=validation_errors()?>
            <?=(isset($error)?$error:'')?>
         </div>
      <?php endif; ?>
      <?=form_open_multipart('gallery/add')?>

        <div class="form-group">
          <label for="userfile">Image File</label>
          <input type="file" class="form-control" name="userfile">
        </div>

        <div class="form-group">
          <label for="caption">Caption</label>
          <input type="text" class="form-control" name="caption" value="">
        </div>

        <div class="form-group">
          <label for="description">Description</label>
          <textarea class="form-control" name="description"></textarea>
        </div>

        <button type="submit" class="btn btn-primary">Upload</button>
        <?=anchor('gallery','Cancel',['class'=>'btn btn-warning'])?>

      </form>
   </div>

   <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo  (ENVIRONMENT === 'development') ?  'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
</div>

</body>
</html>
And the third HTML file is the edit form for uploaded image. Create a new file under application/views/gallery/ directory and name it edit_image.php.
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
if($this->input->post()){
   $caption       = set_value('caption');
   $description    = set_value('description');
} else {
   $caption       = $image->caption;
   $description    = $image->description;
}
?><!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8">
   <title>Update Existing Image</title>

   <link href='http://fonts.googleapis.com/css?family=Oxygen' rel='stylesheet' type='text/css'>
   <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
   <style type="text/css">

   ::selection { background-color: #E13300; color: white; }
   ::-moz-selection { background-color: #E13300; color: white; }

   body {
      background-color: #fff;
      margin: 40px;
      font: 16px/24px normal 'Oxygen', sans-serif;
      color: #4F5155;
   }

   a {
      color: #003399;
      background-color: transparent;
      font-weight: normal;
   }

   h1 {
      color: #444;
      background-color: transparent;
      border-bottom: 1px solid #D0D0D0;
      font-size: 19px;
      font-weight: normal;
      margin: 0 0 14px 0;
      padding: 14px 15px 10px 15px;
   }

   code {
      font-family: Consolas, Monaco, Courier New, Courier, monospace;
      font-size: 12px;
      background-color: #f9f9f9;
      border: 1px solid #D0D0D0;
      color: #002166;
      display: block;
      margin: 14px 0 14px 0;
      padding: 12px 10px 12px 10px;
   }

   #body {
      margin: 0 15px 0 15px;
   }

   p.footer {
      text-align: right;
      font-size: 11px;
      border-top: 1px solid #D0D0D0;
      line-height: 32px;
      padding: 0 10px 0 10px;
      margin: 20px 0 0 0;
   }

   #container {
      margin: 10px;
      border: 1px solid #D0D0D0;
      box-shadow: 0 0 8px #D0D0D0;
   }
   </style>
</head>
<body>

<div id="container">
   <h1>Update Image</h1>

   <div id="body">
      <?php if(validation_errors() || isset($error)) : ?>
         <div class="alert alert-danger" role="alert" align="center">
            <?=validation_errors()?>
            <?=(isset($error)?$error:'')?>
         </div>
      <?php endif; ?>
      <?=form_open_multipart('gallery/edit/'.$image->id)?>

        <div class="form-group">
          <label for="userfile">Image File</label>
          <div class="row" style="margin-bottom:5px"><div class="col-xs-12 col-sm-6 col-md-3"><?=img(['src'=>$image->file,'width'=>'100%'])?></div></div>
          <input type="file" class="form-control" name="userfile">
        </div>

        <div class="form-group">
          <label for="caption">Caption</label>
          <input type="text" class="form-control" name="caption" value="<?=$caption?>">
        </div>

        <div class="form-group">
          <label for="description">Description</label>
          <textarea class="form-control" name="description"><?=$description?></textarea>
        </div>

        <button type="submit" class="btn btn-primary">Save</button>
        <?=anchor('gallery','Cancel',['class'=>'btn btn-warning'])?>

      </form>
   </div>

   <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo  (ENVIRONMENT === 'development') ?  'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
</div>

</body>
</html>
Of course it is your homework to make the three files more compact by separating the header and footer part ffrom the middle main content. Next we are going to write the controller.

The Controller

Start by creating a new file under the application/controllers/ directory and name it Gallery.php. Here is the global structure of our gallery controller:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Gallery extends CI_Controller {
   public function __construct()
   {
      parent::__construct();
      $this->load->model('Gallery_model');
      $this->load->helper(['url','html','form']);
      $this->load->database();
      $this->load->library(['form_validation','session']);
   }

   public function index() {}

   public function add() {}

   public function edit($id) {}

   public function delete($id) {}
}
The index() method will call the all() method from Gallery_model class. The result of the all() method then will be passed into the application/views/gallery/index.php view file to be displayed. 
   public function index()
   {
      $data = [
         'images'   => $this->Gallery_model->all()
      ];
      $this->load->view('gallery/index', $data);
   }
The add() method will validate our form inputs, upload the selected image, and then store the image location into the database by calling the create() method from Gallery_model class.
   public function add(){
      $rules =    [
                    [
                            'field' => 'caption',
                            'label' => 'Caption',
                            'rules' => 'required'
                    ],
                    [
                            'field' => 'description',
                            'label' => 'Description',
                            'rules' => 'required'
                    ]
               ];

      $this->form_validation->set_rules($rules);

      if ($this->form_validation->run() == FALSE)
      {
         $this->load->view('gallery/add_image');
      }
      else
      {

         /* Start Uploading File */
         $config =   [
                     'upload_path'   => './uploads/',
                        'allowed_types' => 'gif|jpg|png',
                        'max_size'      => 100,
                        'max_width'     => 1024,
                        'max_height'    => 768
                     ];

            $this->load->library('upload', $config);

            if ( ! $this->upload->do_upload())
            {
                    $error = array('error' => $this->upload->display_errors());

                    $this->load->view('gallery/add_image', $error);
            }
            else
            {
                    $file = $this->upload->data();
                    //print_r($file);
                    $data = [
                             'file'          => 'uploads/' . $file['file_name'],
                             'caption'      => set_value('caption'),
                             'description'   => set_value('description')
                          ];
                    $this->Gallery_model->create($data);
               $this->session->set_flashdata('message','New image has been added..');
               redirect('gallery');
            }
      }
   }
Similar to the add() method, The edit() method will display a selected recor on a form. Then after the form is submitted, the edit() method validate our form inputs, upload the selected image, and then replace the updated image data on the database by calling the update() method from Gallery_model class.
   public function edit($id){
      $rules =    [
                    [
                            'field' => 'caption',
                            'label' => 'Caption',
                            'rules' => 'required'
                    ],
                    [
                            'field' => 'description',
                            'label' => 'Description',
                            'rules' => 'required'
                    ]
               ];

      $this->form_validation->set_rules($rules);
      $image = $this->Gallery_model->find($id)->row();

      if ($this->form_validation->run() == FALSE)
      {
         $this->load->view('gallery/edit_image',['image'=>$image]);
      }
      else
      {
         if(isset($_FILES["userfile"]["name"]))
         {
            /* Start Uploading File */
            $config =   [
                        'upload_path'   => './uploads/',
                           'allowed_types' => 'gif|jpg|png',
                           'max_size'      => 100,
                           'max_width'     => 1024,
                           'max_height'    => 768
                        ];

               $this->load->library('upload', $config);

               if ( ! $this->upload->do_upload())
               {
                       $error = array('error' => $this->upload->display_errors());
                  $this->load->view('gallery/edit_image',['image'=>$image,'error'=>$error]);
               }
               else
               {
                       $file = $this->upload->data();
                       $data['file'] = 'uploads/' . $file['file_name'];
                  unlink($image->file);
               }
         }

         $data['caption']      = set_value('caption');
         $data['description']   = set_value('description');
         
         $this->Gallery_model->update($id,$data);
         $this->session->set_flashdata('message','New image has been updated..');
         redirect('gallery');
      }
   }
The last method is the delete() method. Simply it calls the  edit() method from Gallery_model class.
   public function delete($id)
   {
      $this->Gallery_model->delete($id);
      $this->session->set_flashdata('message','Image has been deleted..');
      redirect('gallery');
   }
That's it, we just write our own Image Gallery Application.. Yeaay. Don't forget to make the uploads/ directory and give it a write permission. Here's the source code if you want to take a peek.

9 comments: