rancoud/model

Model package

4.3.0 2024-12-07 23:05 UTC

README

Packagist PHP Version Support Packagist Version Packagist Downloads Composer dependencies Test workflow Codecov

Abstract Model for better data manipulation between code and database.

Dependencies

Database package: https://github.com/rancoud/Database

Installation

composer require rancoud/model

How to use it?

Extends Rancoud\Model\Model to your class.
You have to implement two abstract methods setFields and setTable.

  • setFields is for setting the fields in table
  • setTable is for setting the table in database
class User extends Model
{
    protected function setFields(): void
    {
        $this->fields = [
            'id'       => new Field('int', ['not_null', 'unsigned', 'pk']),
            'nickname' => new Field('varchar', ['max:255', 'not_null'])
        ];
    }

    protected function setTable(): void
    {
        $this->table = 'user';
    }
}

What is Field?

Field represent a field in the table.
It have 3 arguments:

  1. field type
  2. rules
  3. default value

Field type

It support those field type

  • int
  • float
  • char
  • varchar
  • text
  • date
  • datetime
  • time
  • timestamp
  • year
  • enum:x,y,z (x,y,z represent each possible value)

Rules

  • pk : primary key
  • fk : foreign key
  • unsigned : only positive value
  • email : check if it is valid email
  • not_null : can't be null
  • max:x : max size (x is size)
  • min:x : min size (x is size)
  • range:x,y : min size + max size (x is min size, y is max size)

Custom rule

class MyRule extends CustomRule
{
    public function applyRule($value)
    {
        if ($value === 'azerty') {
            throw new FieldException('invalid azerty value');
        }

        return $value;
    }
}

Default

When value is not setted it can be set with those argument

Helpers

It have methods for pagination, create, read, update and delete.

// $database is an instance of Rancoud\Database\Database
$user = new User($database);

$newId = $user->create(['nickname' => 'rancoud']);

$row = $user->one($newId);
// you will have an array representing data in database with correct types
// here : ['id' => 1, 'nickname' => 'rancoud'];
$rows = $user->all();
// here it's all rows in table : [ ['id' => 1, 'nickname' => 'rancoud'] ] 

$user->update(['nickname' => 'rancoud2'], $newId);

$user->delete($newId);

Model::all() accept an array with some keys that triggers specific actions

// $database is an instance of Rancoud\Database\Database
$user = new User($database);

// 50 rows using LIMIT 50 OFFSET 50
$rows = $user->all(['page' => 1]);
// 10 rows using LIMIT 10 OFFSET 10
$rows = $user->all(['count' => 10, 'page' => 1]);

// count rows in table
$count = $user->all(['rows_count' => 1]);

// return all rows with no limit 
$count = $user->all(['no_limit' => 1]);

// change order by
$count = $user->all(['order' => 'nickname']);
// change order by and order
$count = $user->all(['order' => 'nickname|desc']);
// multiple change order by and order
$count = $user->all(['order' => 'nickname|desc,id|asc']);

You can change values output in Model::all() with override functions:

  • getSqlAllSelectAndFillSqlParams(params: array)
  • getSqlAllJoinAndFillSqlParams(params: array)
  • getSqlAllWhereAndFillSqlParams(params: array)

Callbacks

You can add callback before and after create, update and delete.

$model->addBeforeCreate('a', function($sql, $params){
    // for modifying sql and params use this return otherwise don't
    return [$sql, $params];
});

$model->addAfterCreate('a', function($newId, $params){
    // for modifying params use this return otherwise don't
    return $params;
});

$model->addBeforeUpdate('a', function($sql, $params){
    // for modifying sql and params use this return otherwise don't
    return [$sql, $params];
});

$model->addAfterUpdate('a', function($params){
    // for modifying params use this return otherwise don't
    return $params;
});

$model->addBeforeDelete('a', function($sql, $params){
    // for modifying sql and params use this return otherwise don't
    return [$sql, $params];
});

$model->addAfterDelete('a', function($params){
    // for modifying params use this return otherwise don't
    return $params;
});

You can use JsonOutput trait for adding json format for the model.

Field Constructor

Settings

Mandatory

Optionnals

Field Methods

  • isPrimaryKey(): bool
  • isForeignKey(): bool
  • isNotNull(): bool
  • getDefault(): mixed
  • formatValue(value: mixed): ?mixed

Model Constructor

Settings

Mandatory

Model Methods

General Commands

  • all(params: array, [validFields: array = []]): array|bool|int
  • one(id: mixed, [...ids: mixed = []]): array
  • create(args: array): bool|int
  • update(args: array, id: mixed, [...ids: mixed = []]): void
  • delete(id: mixed, [...ids: mixed = []]): void
  • getLastInsertId(): ?int

Database error

  • getDatabaseErrors(): ?array
  • getDatabaseLastError(): ?array

Callbacks

Add

  • addBeforeCreate(name: string, callback: mixed): void
  • addAfterCreate(name: string, callback: mixed): void
  • addBeforeUpdate(name: string, callback: mixed): void
  • addAfterUpdate(name: string, callback: mixed): void
  • addBeforeDelete(name: string, callback: mixed): void
  • addAfterDelete(name: string, callback: mixed): void

Remove

  • removeBeforeCreate(name: string): void
  • removeAfterCreate(name: string): void
  • removeBeforeUpdate(name: string): void
  • removeAfterUpdate(name: string): void
  • removeBeforeDelete(name: string): void
  • removeAfterDelete(name: string): void

Static Helper Methods

  • getCountPerPage(args: array): int
  • getLimitOffsetCount(args: array): array
  • getOrderByOrderField(args: array, [validFields: array = []]): array
  • getPageNumberForHuman(args: array): int
  • getPageNumberForSql(args: array): int
  • hasInvalidPrimaryKey(value: int): bool
  • hasLimit(args: array): bool
  • implodeOrder(orders: array): string
  • isRowsCount(args: array): bool
  • isValidFieldForOrderBy(field: string, [validFields: array = []]): bool

How to Dev

docker compose build && docker compose run lib composer ci for launching tests