Skip to content

Meeting 11

Pada pertemuan kali ini, kita akan membahas lebih dalam tentang controller, membuat koneksi aplikasi dengan database dan membuat model, membuat base class untuk validasi.

Koneksi Database

Pada pertemuan ke 9 sebelumnya kita sudah membahas bagaimana membuat koneksi dari PHP ke database, kita bisa menggunakan cara yang sama, salin file Database.php yang kita buat sebelumnya, ke dalam folder Libraries, namun kita akan sedikit melakukan perubahan pada sintaks sebelumnya yaitu menambahkan namespace agar class yang di salin dapat di panggil dari file lain, jangan lupa untuk memanggil class Database untuk menginisiasi koneksi ke database, dan class Database akan menjadi seperti di bawah ini:

php
<?php

namespace MiniMarkPlace\Libraries;

class Database {
    private $host     = 'localhost';
    private $username = 'root';
    private $password = '';
    private $database = 'markplace';
    private $connection;

    public function __construct() {
        $connect = new \mysqli(
            $this->host,
            $this->username,
            $this->password,
            $this->database
        );

        if ($connect->connect_error) {
            die("Koneksi gagal:  {$connect->connect_error}");
        }

        $this->connection = $connect;
    }

    public function connection() {
        return $this->connection;
    }
}
<?php

namespace MiniMarkPlace\Libraries;

class Database {
    private $host     = 'localhost';
    private $username = 'root';
    private $password = '';
    private $database = 'markplace';
    private $connection;

    public function __construct() {
        $connect = new \mysqli(
            $this->host,
            $this->username,
            $this->password,
            $this->database
        );

        if ($connect->connect_error) {
            die("Koneksi gagal:  {$connect->connect_error}");
        }

        $this->connection = $connect;
    }

    public function connection() {
        return $this->connection;
    }
}
php
use MiniMarkPlace\Libraries\Database;

$database = new Database();
use MiniMarkPlace\Libraries\Database;

$database = new Database();

Membuat Model

Model adalah komponen yang bertanggung jawab untuk berinteraksi dengan basis data dan mengelola data aplikasi. Model menggambarkan struktur dan logika data dalam aplikasi. Biasanya, model digunakan untuk mengambil, menyimpan, mengupdate, dan menghapus data dari basis data, serta menjalankan operasi lain yang berkaitan dengan data.

  • Buatlah folder baru dengan Models di dalam /src folder
  • Buat file baru dengan nama ProductCategory.php
  • dan buat class dengan nama ProductCategory atau salin dari sintaks di bawah ini:
php
<?php

namespace MiniMarkPlace\Models;

use MiniMarkPlace\Libraries\Database;

class ProductCategory extends Database {
    protected $table = 'product_categories';
}
<?php

namespace MiniMarkPlace\Models;

use MiniMarkPlace\Libraries\Database;

class ProductCategory extends Database {
    protected $table = 'product_categories';
}

Get Data

Pada pertemuan sebelumnya kita juga sudah membuat method untuk mengambil data dari database, kita akan membuat sesuatu yang sama namun padi kali ini, kita akan menambahkan untuk method mengambil satu data saja.

  • Mengambil semua data di beberapa kasus kita akan membutuh untuk mengambil data lebih dari satu dari database, kita akan memberi nama method kali ini dengan nama findAll(). dan memanggil method findAll() dari controller yang sudah kita buat.
php
public function findAll() {
    $sql = "SELECT * FROM {$this->table}";
    $result = $this->connection()->query($sql);

    if ($result->num_rows > 0) {
        $data = [];

        while ($row = $result->fetch_assoc()) {
            $data[] = $row;
        }

        return $data;
    }

    return [];
}
public function findAll() {
    $sql = "SELECT * FROM {$this->table}";
    $result = $this->connection()->query($sql);

    if ($result->num_rows > 0) {
        $data = [];

        while ($row = $result->fetch_assoc()) {
            $data[] = $row;
        }

        return $data;
    }

    return [];
}
php
use MiniMarkPlace\Models\ProductCategory;

public function index()
{
    $categories = (new ProductCategory)->findAll();

    return json_encode([
        'data' => $categories
    ]);
}
use MiniMarkPlace\Models\ProductCategory;

public function index()
{
    $categories = (new ProductCategory)->findAll();

    return json_encode([
        'data' => $categories
    ]);
}
  • Mengambil satu data Kali ini kita akan mengambil satu data saja, namun kita akan mengambil detail semua attribute dari data, untuk menampilkan detail data secara lengkap. kita juga membutuhkan id dari data yang akan di tampilkan.
php
public function findOne($id) {
    $sql = "SELECT * FROM {$this->table} WHERE id = ?";
    $stmt =  $this->connection()->prepare($sql);
    $stmt->bind_param("i", $id);

    if ($stmt->execute()) {
        $result = $stmt->get_result();

        return $result->fetch_assoc();
    }

    return [];
}
public function findOne($id) {
    $sql = "SELECT * FROM {$this->table} WHERE id = ?";
    $stmt =  $this->connection()->prepare($sql);
    $stmt->bind_param("i", $id);

    if ($stmt->execute()) {
        $result = $stmt->get_result();

        return $result->fetch_assoc();
    }

    return [];
}
php
use MiniMarkPlace\Models\ProductCategory;

public function show($id)
{
    $category = (new ProductCategory)->findOne($id);

    return json_encode([
        'data' => $category
    ]);
}
use MiniMarkPlace\Models\ProductCategory;

public function show($id)
{
    $category = (new ProductCategory)->findOne($id);

    return json_encode([
        'data' => $category
    ]);
}

Add Data

Melakukan penyimpanan data baru ke dalam database, kita akan membuat method baru di model atau class ProductCategory dengan nama method create(), dan memanggil method yang sudah di buat dari controller.

php
public function create($data) {
    $sql = "INSERT INTO {$this->table} (name) VALUES (?)";
    $stmt =  $this->connection()->prepare($sql);
    $stmt->bind_param("s", $data['name']);

    if ($stmt->execute()) {
        return $this->findOne($this->connection()->insert_id);
    }

    return [];
}
public function create($data) {
    $sql = "INSERT INTO {$this->table} (name) VALUES (?)";
    $stmt =  $this->connection()->prepare($sql);
    $stmt->bind_param("s", $data['name']);

    if ($stmt->execute()) {
        return $this->findOne($this->connection()->insert_id);
    }

    return [];
}
php
use MiniMarkPlace\Models\ProductCategory;

public function store()
{
    $data = $_POST;

    $category = new ProductCategory();
    $response = $category->create($data);

    return json_encode([
        'data' => $response
    ]);
}
use MiniMarkPlace\Models\ProductCategory;

public function store()
{
    $data = $_POST;

    $category = new ProductCategory();
    $response = $category->create($data);

    return json_encode([
        'data' => $response
    ]);
}

Update Data

Pada kali ini kita akan membuat method baru untuk memperbaharui data di database, dan memanggil method dari controller, karna secara resmi dari PHP hanya bisa menerima data dari method http GET dan POST saja, kita akan mengubah route di index.php untuk update data menggunakan method POST

php
public function update($id, $data) {
    $sql = "UPDATE {$this->table} SET name = ? WHERE id = ?";
    $stmt =  $this->connection()->prepare($sql);
    $stmt->bind_param("si", $data['name'], $id);

    if ($stmt->execute()) {
        return $this->findOne($id);
    }

    return [];
}
public function update($id, $data) {
    $sql = "UPDATE {$this->table} SET name = ? WHERE id = ?";
    $stmt =  $this->connection()->prepare($sql);
    $stmt->bind_param("si", $data['name'], $id);

    if ($stmt->execute()) {
        return $this->findOne($id);
    }

    return [];
}
php
use MiniMarkPlace\Models\ProductCategory;

public function update($id)
{
    $data = $_POST;

    $category = new ProductCategory();
    $response = $category->update($id, $data);

    return json_encode([
        'data' => $response
    ]);
}
use MiniMarkPlace\Models\ProductCategory;

public function update($id)
{
    $data = $_POST;

    $category = new ProductCategory();
    $response = $category->update($id, $data);

    return json_encode([
        'data' => $response
    ]);
}
php
$router->add('POST', '/product-category/:id', [ProductCategoryController::class, 'update']);
$router->add('POST', '/product-category/:id', [ProductCategoryController::class, 'update']);

Delete Data

Kita akan membuat method baru untuk menghapus data di database, jangan lupa untuk memperbaharui sintaks di controller untuk memanggil method delete() di model. walaupun php tidak dapat menggunakan method http GET dan POST, kita tetap akan menggunakan method http DELETE, karna hanya mengirim data melalui url parameter.

php
public function delete($id) {
    try {
        $sql = "DELETE FROM {$this->table} WHERE id = ?";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("i", $id);
        $stmt->execute();
    } catch (\Throwable $th) {
        throw $th;
    }
}
public function delete($id) {
    try {
        $sql = "DELETE FROM {$this->table} WHERE id = ?";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("i", $id);
        $stmt->execute();
    } catch (\Throwable $th) {
        throw $th;
    }
}
php
use MiniMarkPlace\Models\ProductCategory;

public function delete($id)
{
    $category = new ProductCategory();
    $category->delete($id);

    return json_encode([
        'message' => 'success'
    ]); 
}
use MiniMarkPlace\Models\ProductCategory;

public function delete($id)
{
    $category = new ProductCategory();
    $category->delete($id);

    return json_encode([
        'message' => 'success'
    ]); 
}

Aplikasi sederhana kita untuk modul Kategori Produk sudah selesai, kode lengkap dari aplikasi kita akan menjadi seperti ini:

php
<?php

require __DIR__.'/../vendor/autoload.php';

use MiniMarkPlace\Controllers\ProductCategoryController;
use MiniMarkPlace\Libraries\Database;
use MiniMarkPlace\Libraries\Routing;

$database = new Database();
$router = new Routing();

// Home page route
$router->add('GET', '/', function() {
    echo 'Hello world';
});

$router->add('GET', '/product-category', [ProductCategoryController::class, 'index']);
$router->add('GET', '/product-category/:id', [ProductCategoryController::class, 'show']);
$router->add('POST', '/product-category', [ProductCategoryController::class, 'store']);
$router->add('POST', '/product-category/:id', [ProductCategoryController::class, 'update']);
$router->add('DELETE', '/product-category/:id', [ProductCategoryController::class, 'delete']);

// Run the router
echo $router->run();
<?php

require __DIR__.'/../vendor/autoload.php';

use MiniMarkPlace\Controllers\ProductCategoryController;
use MiniMarkPlace\Libraries\Database;
use MiniMarkPlace\Libraries\Routing;

$database = new Database();
$router = new Routing();

// Home page route
$router->add('GET', '/', function() {
    echo 'Hello world';
});

$router->add('GET', '/product-category', [ProductCategoryController::class, 'index']);
$router->add('GET', '/product-category/:id', [ProductCategoryController::class, 'show']);
$router->add('POST', '/product-category', [ProductCategoryController::class, 'store']);
$router->add('POST', '/product-category/:id', [ProductCategoryController::class, 'update']);
$router->add('DELETE', '/product-category/:id', [ProductCategoryController::class, 'delete']);

// Run the router
echo $router->run();
php
<?php

namespace MiniMarkPlace\Controllers;

use MiniMarkPlace\Models\ProductCategory;

class ProductCategoryController
{
    public function index()
    {
        $categories = (new ProductCategory)->findAll();

        return json_encode([
            'data' => $categories
        ]);
    }

    public function store()
    {
        $data = $_POST;

        $category = new ProductCategory();
        $response = $category->create($data);

        return json_encode([
            'data' => $response
        ]);
    }

    public function show($id)
    {
        $category = (new ProductCategory)->findOne($id);

        return json_encode([
            'data' => $category
        ]);
    }

    public function update($id)
    {
        $data = $_POST;

        $category = new ProductCategory();
        $response = $category->update($id, $data);

        return json_encode([
            'data' => $response
        ]);
    }

    public function delete($id)
    {
        $category = new ProductCategory();
        $category->delete($id);

        return json_encode([
            'message' => 'success'
        ]); 
    }

}
<?php

namespace MiniMarkPlace\Controllers;

use MiniMarkPlace\Models\ProductCategory;

class ProductCategoryController
{
    public function index()
    {
        $categories = (new ProductCategory)->findAll();

        return json_encode([
            'data' => $categories
        ]);
    }

    public function store()
    {
        $data = $_POST;

        $category = new ProductCategory();
        $response = $category->create($data);

        return json_encode([
            'data' => $response
        ]);
    }

    public function show($id)
    {
        $category = (new ProductCategory)->findOne($id);

        return json_encode([
            'data' => $category
        ]);
    }

    public function update($id)
    {
        $data = $_POST;

        $category = new ProductCategory();
        $response = $category->update($id, $data);

        return json_encode([
            'data' => $response
        ]);
    }

    public function delete($id)
    {
        $category = new ProductCategory();
        $category->delete($id);

        return json_encode([
            'message' => 'success'
        ]); 
    }

}
php
<?php

namespace MiniMarkPlace\Models;

use MiniMarkPlace\Libraries\Database;

class ProductCategory extends Database {

    protected $table = 'product_categories';

    public function findAll() {
        $sql = "SELECT * FROM {$this->table}";
        $result = $this->connection()->query($sql);

        if ($result->num_rows > 0) {
            $data = [];

            while ($row = $result->fetch_assoc()) {
                $data[] = $row;
            }

            return $data;
        }

        return [];
    }

    public function findOne($id) {
        $sql = "SELECT * FROM {$this->table} WHERE id = ?";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("i", $id);

        if ($stmt->execute()) {
            $result = $stmt->get_result();

            return $result->fetch_assoc();
        }

        return [];
    }

    public function create($data) {
        $sql = "INSERT INTO {$this->table} (name) VALUES (?)";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("s", $data['name']);

        if ($stmt->execute()) {
            return $this->findOne($this->connection()->insert_id);
        }

        return [];
    }

    public function update($id, $data) {
        $sql = "UPDATE {$this->table} SET name = ? WHERE id = ?";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("si", $data['name'], $id);

        if ($stmt->execute()) {
            return $this->findOne($id);
        }

        return [];
    }

    public function delete($id) {
        try {
            $sql = "DELETE FROM {$this->table} WHERE id = ?";
            $stmt =  $this->connection()->prepare($sql);
            $stmt->bind_param("i", $id);
            $stmt->execute();
        } catch (\Throwable $th) {
            throw $th;
        }
    }
}
<?php

namespace MiniMarkPlace\Models;

use MiniMarkPlace\Libraries\Database;

class ProductCategory extends Database {

    protected $table = 'product_categories';

    public function findAll() {
        $sql = "SELECT * FROM {$this->table}";
        $result = $this->connection()->query($sql);

        if ($result->num_rows > 0) {
            $data = [];

            while ($row = $result->fetch_assoc()) {
                $data[] = $row;
            }

            return $data;
        }

        return [];
    }

    public function findOne($id) {
        $sql = "SELECT * FROM {$this->table} WHERE id = ?";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("i", $id);

        if ($stmt->execute()) {
            $result = $stmt->get_result();

            return $result->fetch_assoc();
        }

        return [];
    }

    public function create($data) {
        $sql = "INSERT INTO {$this->table} (name) VALUES (?)";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("s", $data['name']);

        if ($stmt->execute()) {
            return $this->findOne($this->connection()->insert_id);
        }

        return [];
    }

    public function update($id, $data) {
        $sql = "UPDATE {$this->table} SET name = ? WHERE id = ?";
        $stmt =  $this->connection()->prepare($sql);
        $stmt->bind_param("si", $data['name'], $id);

        if ($stmt->execute()) {
            return $this->findOne($id);
        }

        return [];
    }

    public function delete($id) {
        try {
            $sql = "DELETE FROM {$this->table} WHERE id = ?";
            $stmt =  $this->connection()->prepare($sql);
            $stmt->bind_param("i", $id);
            $stmt->execute();
        } catch (\Throwable $th) {
            throw $th;
        }
    }
}
php
<?php

namespace MiniMarkPlace\Libraries;

class Routing
{
    private $routes = [];

    public function add(string $method, string $path, $callback)
    {
        $this->routes[] = [
            'method'   => $method,
            'path'     => $path,
            'callback' => $callback
        ];
    }

    public function run()
    {
        $method = $_SERVER['REQUEST_METHOD'];
        $uri    = $_SERVER['REQUEST_URI'];

        foreach ($this->routes as $route) {
            if ($route['method'] != $method) {
                continue;
            }

            $regexPattern = preg_replace_callback('/:\w+/', function ($params) {
                return '([^/]+)';
                },
                $route['path']
            );
    
            if (preg_match("#^{$regexPattern}$#", $uri, $params)) {
                array_shift($params);

                if (is_callable($route['callback'])) {
                    return call_user_func_array($route['callback'], $params);
                } else {
                    list($controller, $method) = $route['callback'];
                    $instance = new $controller();
                    return $instance->$method(...$params);
                }
            }
        }

        header('HTTP/1.1 404 Not Found');
        die('404 Not Found');
    }
}
<?php

namespace MiniMarkPlace\Libraries;

class Routing
{
    private $routes = [];

    public function add(string $method, string $path, $callback)
    {
        $this->routes[] = [
            'method'   => $method,
            'path'     => $path,
            'callback' => $callback
        ];
    }

    public function run()
    {
        $method = $_SERVER['REQUEST_METHOD'];
        $uri    = $_SERVER['REQUEST_URI'];

        foreach ($this->routes as $route) {
            if ($route['method'] != $method) {
                continue;
            }

            $regexPattern = preg_replace_callback('/:\w+/', function ($params) {
                return '([^/]+)';
                },
                $route['path']
            );
    
            if (preg_match("#^{$regexPattern}$#", $uri, $params)) {
                array_shift($params);

                if (is_callable($route['callback'])) {
                    return call_user_func_array($route['callback'], $params);
                } else {
                    list($controller, $method) = $route['callback'];
                    $instance = new $controller();
                    return $instance->$method(...$params);
                }
            }
        }

        header('HTTP/1.1 404 Not Found');
        die('404 Not Found');
    }
}
php
<?php

namespace MiniMarkPlace\Libraries;

class Database {
    private $host     = 'localhost';
    private $username = 'root';
    private $password = '';
    private $database = 'markplace';
    private $connection;

    public function __construct() {
        $connect = new \mysqli(
            $this->host,
            $this->username,
            $this->password,
            $this->database
        );

        if ($connect->connect_error) {
            die("Koneksi gagal:  {$connect->connect_error}");
        }

        $this->connection = $connect;
    }

    public function connection() {
        return $this->connection;
    }
}
<?php

namespace MiniMarkPlace\Libraries;

class Database {
    private $host     = 'localhost';
    private $username = 'root';
    private $password = '';
    private $database = 'markplace';
    private $connection;

    public function __construct() {
        $connect = new \mysqli(
            $this->host,
            $this->username,
            $this->password,
            $this->database
        );

        if ($connect->connect_error) {
            die("Koneksi gagal:  {$connect->connect_error}");
        }

        $this->connection = $connect;
    }

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

Perubahan yang kita lakukan lumayan banyak, untuk memastikan struktur aplikasi yang di buat sama, pastikan struktur seperti di bawah ini:

├── src
│   ├── Controllers
│   │   ├── ProductCategoryController.php
│   ├── Libraries
│   │   ├── Database.php
│   │   ├── Routing.php
│   ├── Models
│   │   ├── ProductCategory.php
│   ├── index.php
├── vendor
├── .htaccess
└── composer.json
├── src
│   ├── Controllers
│   │   ├── ProductCategoryController.php
│   ├── Libraries
│   │   ├── Database.php
│   │   ├── Routing.php
│   ├── Models
│   │   ├── ProductCategory.php
│   ├── index.php
├── vendor
├── .htaccess
└── composer.json

Membuat Validasi