Puko Framework logo Puko Framework

Let’s get to know about model. The (M) layer of puko framework HMVC pattern. This part of puko has responsible to connecting your app with a database or multiple database for Create, Read, Update and Delete operations. Database in puko handled by the DataBase Interface (DBI) singleton objects.

But, before that, we need setup a database connections. To summarize the process we often using pukoconsole command:

php puko setup db

Items asked:

Items Description Examples
Database Type only supports MySQL for now mysql
Hostname Databaase IP address localhost
Port Databaase port address 3306
Schema Name Schema name as identifier for multiple database primary
Database Name Name of databases inventory
Username User databases root
Password Paassword databases **

At the end wizard is asking for another connection you can answer with y/n

What this process means?

Puko will save the connection setting in config/database.php file and generate corresponding PHP class model as data object wiring with your database model. Those files generated and saved in plugins/model/<schema> directory.

That file should not be modified

So, why we need data object wiring?

At concept level, data object wiring inspired by Data Access Object (DAO) patterns but only implement the wiring mechanism to keep it small and simple. And because we usually don’t remember clearly the column on database entity. So with object wiring you now have clues about your column on the database in case you forget. Especially when used with good IDE, those tools can provide auto-completions trough your data. Enough theory, let’s see it in action.

Assumed you have basic knowledge on MySQL and have a database table inventory and you already done executing setup db command above. This is example of what inside table inventory:

id name created descriptions
1 Chair 2020-08-15 Minimalist chair made from pine woods
2 Laptop 2020-08-16 Gaming notebooks with core i7 and RTX2070 Max-Q

Alert: tables name must only contain letters without special character or space due to limitations of php class name rules.

Create or save operations:

$inventory = new plugins\model\primary\inventory();
$inventory->id = $_POST['id'];
$inventory->name = $_POST['name'];
$inventory->created = date('Y-m-d H:i:s');
$inventory->descriptions = $_POST['descriptions'];

$inventory->save();

Read operations:

$inventory = new plugins\model\primary\inventory(1);

echo (array) $inventory;

Update or modify operations:

$inventory = new plugins\model\primary\inventory(1);
$inventory->id = $_POST['id'];
$inventory->name = $_POST['name'];
$inventory->created = date('Y-m-d');
$inventory->descriptions = $_POST['descriptions'];

$inventory->modify();

Delete or remove operations:

$inventory = new plugins\model\primary\inventory(1);

$inventory->remove();

Get all data:

$all = plugins\model\primary\inventory::GetAll();

As you can see. Basic CRUD operations is simple and don’t need to use any manual typed SQL query.

The DataBase Interface (DBI) in puko framework for now only support MySQL and MariaDB.

But then how about run the stored procedure or executing complex query like join operations?

For executing stored procedure you can follow this example:

DBI::Call('stored_procedure_name', [
    $parameter1, $parameter2
]);

For complex query you can extends the model classes and implement ModelContracts in order to have uniformity. Let’s see by example:

Create new php file: model/InventoryModel.php

class InventoryModel extends inventory implements ModelContracts {

The ModelContracts interface will be forcing you to implement 9 abstract method.

GetData() This method should return data available on the database in array structure

GetById($id) This method should return one row from database specified by id

IsExists($id) This method should return true if row found or false if not found from database specified by id

IsExistsWhere($column, $value) This method should return true if row found or false if not found from database specified by custom selection

GetDataSize() This method should return count of the data on the database

GetDataSizeWhere($condition) This method should return count of the data on the database with selected conditions

GetLastData() This method should return last inserted data

SearchData($keyword) This method should return search result data available on the database in array structure

GetDataTable($condition) This method should return search result data available on the database in datatables json format

These pre-defined method above created to give developer the start point. Puko framework have this to offer consistency and because most database operation can handled by these pre-defined method. Let’s see it through sample code:

InventoryModel.php

public static function SearchData($keyword = []) {
    $strings = "";
    foreach ($keyword as $column => $values) {
        $strings .= sprintf(" AND (%s = '%s') ", $column, $values);
    }

    $sql = sprintf("SELECT i.id, i.created, i.name, i.descriptions
    FROM inventory i
    WHERE (i.created IS NOT NULL) %s;", $strings);

    return DBI::Prepare($sql)->GetData();
}
//now we using InventoryModel. Our custom class that extends inventory plugin model.
$inventoru = InventoryModel::SearchData([
    'created' => '2020-08-14'
]);

Why puko have this type of interface? The goal is uniformity. But keep in mind it’s optional, you can have your own way to work with the databases.


DBI

You already know how to do CRUD operations with data object wiring. This section will explain with code sample another set of feature available in DBI.

To pass your sql query into DBI classes.

$sql = "SELECT * FROM inventory WHERE (id = @1);";
$response = DBI::Prepare($sql);

Used to retrieve all data from the database in arrays indexed format. Prepared statement is also available. You can se it from example below:

$sql = "SELECT * FROM inventory WHERE (id = @1);";
$response = DBI::Prepare($sql)->GetData($id);
$sql = "SELECT * FROM inventory WHERE (id = @1) AND (name = @2);";
$response = DBI::Prepare($sql)->GetData($id, $name);
$sql = "SELECT * FROM inventory WHERE (id = @1) AND (name = @2) AND (created = @3);";
$response = DBI::Prepare($sql)->GetData($id, $name, $created);

As GetData() but only retrieve 1 row data in single array formats. Prepared statement is also available. You can se it from example below:

$sql = "SELECT * FROM inventory WHERE (id = @1) LIMIT 1;";
$response = DBI::Prepare($sql)->FirstRow();

For executing query. Usually used for executing stored procedure and non select query.

$sql = "UPDATE inventory SET name = 'Laptop Ultrabooks' WHERE (id = @1);";
$response = DBI::Prepare($sql)->Run($id);