Discite-PHP is a lightweight and extensible query builder for PHP using MySQLi. It provides an expressive, object-oriented API to manage SQL operations easily.
Discite-PHP helps manipulate, format, correct, and secure SQL queries based on the MySQL manager. The library uses MySQLi.
Several operating modes are available to best suit each use case. The library requires minimal initialization to reduce overhead.
Only the connection must be initialized outside the library for security reasons.
- Object-oriented and fluent interface
- Automatic SQL injection protection
- Modular configuration system
- Charset, collation, naming convention, aliasing, prefixing control
- Loose or strict usage modes for tables and keys
- Field (key) declarations with type, index, nullable, default
- Built-in query modifiers and logical operators
- Installation
- Usage Example
- General Functionality
- Configuration
- General Configuration
- Usage Modes
- Keys (Columns)
- Tables
- Query Operators
- Manipulate Queries
- Fetching Results
- Project Structure
- License
--
Install with Composer:
composer require discite/discite-php
This snippet demonstrates how to initialize DisciteDB, configure it, and run a SELECT
query with condition modifiers:
use DisciteDB\Config\Enums\QueryLocation;
use DisciteDB\DisciteDB;
use DisciteDB\Methods\QueryCondition;
ini_set('display_errors','1');
ini_set('display_startup_errors','1');
error_reporting(E_ALL);
require 'default_file.php';
// Define your connection
$_connection = new mysqli('localhost','root','','test_db');
// Snitialize DisciteDB Database
$disciteDB = new \DisciteDB\Database($_connection);
// Set some configurations
// Charset conf
$disciteDB->configuration()->setCharset(DisciteDB::CHARSET_UTF8MB4);
// Collation conf
$disciteDB->config()->setCollation(DisciteDB::COLLATION_UTF8MB4_UNICODE_CI);
// Table usage conf (look at [Usage Modes] for more informations)
$disciteDB->conf()->setTableUsage(DisciteDB::TABLE_USAGE_LOOSE);
// Key usage conf (look at [Usage Modes] for more informations)
$disciteDB->conf()->setKeyUsage(DisciteDB::KEY_USAGE_LOOSE);
//Here, I decide to list all rows from 'disciteDB_FakeItems'
//That match the following arguments :
// name is not "White Widget"
// description start contains "and"
// price is less or equal "25"
$queryFakeItems = $disciteDB->table('disciteDB_FakeItems')->listing([
'name'=>QueryCondition::Not('White Widget'),
'description'=>QueryCondition::Contains('and', DisciteDB::QUERY_LOCATION_BETWEEN),
'price' => QueryCondition::LessOrEqual(25),
]);
// You can, after that :
// retrieve the SQL Query
echo '<b>QUERY</b>';
var_dump($queryFakeItems->fetchQuery());
// Retrieve informations (affected rows, time, statut, etc)
echo '<b>INFORMATIONS ONLY</b>';
var_dump($queryFakeItems->fetchInformations());
// Fetch the next data
// Is like mysqli_fetch_row || mysqli_result::fetch_row
echo '<b>NEXT DATA</b>';
var_dump($queryFakeItems->fetchNext());
// Fetch all datas
// Is like mysqli_fetch_all($result, MYSQLI_ASSOC); || mysqli_result::fetch_all(int $mode = MYSQLI_ASSOC)
echo '<b>ALL DATA</b>';
var_dump($queryFakeItems->fetchAll());
// Fetch all datas AND informations as an associative array
echo '<b>ALL DATA AND INFORMATIONS</b>';
var_dump($queryFakeItems->fetchArray());
To begin using the library, you need a MySQLi connection and to initialize the database manager.
// Initialize your connection as usual
$connection = new mysqli('host', 'username', 'password', 'database', 'port');
// Initialize the DisciteDB Manager
$disciteDB = new \DisciteDB\Database($connection);
If no connection is provided, the manager will use the following default values:
Attribute | Value | |
---|---|---|
Host | localhost | |
Username | root | |
Password | null | |
Database | db | |
Port | null |
if you want to keep strict
mode (and so, have security, auto-join, etc) available, you can - if you don't want to make manuals definitions - load database directly from a file or the database.
// Initialize the DisciteDB Manager
$disciteDB = new \DisciteDB\Database($connection);
// Perform loading
$disciteDB->loadFromFile($path, $updatingTime);
The library will load tables and columns from a file.
To improve some performances, you can add $updatingTime
in seconds. If the file is older than the max storage time (createdTime + $updatingTime
), the library will update the file.
If you want to update the file each time you initialize the library, just set the time to 0
.
// Initialize the DisciteDB Manager
$disciteDB = new \DisciteDB\Database($connection);
// Perform loading
$disciteDB->loadFromDatabase();
The library will load tables and columns directly from database connection.
You can retrieve SQLmap
as an array with a simple method.
// Initialize the DisciteDB Manager
$disciteDB = new \DisciteDB\Database($connection);
// Perform loading
$disciteDB->map();
You can configure the manager to meet your needs until its destruction.
With the database manager initiated, access the configuration manager with:
$disciteDB->configuration();
Aliases:
$disciteDB->config();
$disciteDB->conf();
To configure the manager without having to import configuration classes, you can call constants via:
use DisciteDB\DisciteDB;
// Example usage
DisciteDB::CONST_NAME;
You can define the charset of the database. By default, the charset used is utf8mb4
.
$disciteDB->config()->setCharset(selected_charset);
To retrieve the current charset:
$disciteDB->config()->getCharset();
Constant | Value | Default? |
---|---|---|
CHARSET_UTF8 | utf8 | |
CHARSET_UTF8MB4 | utf8mb4 | ✓ |
You can define the collation associated with the charset. By default, the collation used is utf8mb4_unicode_ci
.
$disciteDB->config()->setCollation(selected_collation);
To retrieve the current collation:
$disciteDB->config()->getCollation();
Constant | Value | Default? |
---|---|---|
COLLATION_UTF8_GENERAL_CI | utf8_general_ci | |
COLLATION_UTF8MB4_BIN | utf8mb4_bin | |
COLLATION_UTF8MB4_UNICODE_CI | utf8mb4_unicode_ci | ✓ |
Can be used only in strict
mode
You can define the naming convention to use. The library will automatically change the names and aliases to conform to the selected convention. By default, no convention is selected.
$disciteDB->config()->setNamingConvention(selected_naming_convention);
To get the current naming convention:
$disciteDB->config()->getNamingConvention();
Constant | Value | Default? |
---|---|---|
NAMING_CONVENTION_UNDEFINED | Undefined | ✓ |
NAMING_CONVENTION_CAMEL_CASE | camelCase | |
NAMING_CONVENTION_PASCAL_CASE | PascalCase | |
NAMING_CONVENTION_SNAKE_CASE | snake_case | |
NAMING_CONVENTION_SNAKE_UPPERCASE | SNAKE_UPPERCASE |
You can define if the library automaticly sort the database and if so, from desc
or asc
.
By default, the sorting method used is no_sort
.
$disciteDB->config()->setSort(selected_sorting_method);
To retrieve the current sorting method:
$disciteDB->config()->getSort();
Constant | Value | Default? |
---|---|---|
SORT_NO_SORT | null | ✓ |
SORT_DESC | DESC | |
SORT_ASC | ASC |
Can be used only in strict
mode
The Discite-php library allow you to make auto-joining from defined database.
By default, the sorting method used is no_join
.
$disciteDB->config()->setJoinMethod(selected_joining_method);
To retrieve the current joining method:
$disciteDB->config()->getJoinMethod();
You can also set the max occurences of joining the database will throw.
By default, the max interations is set to 0
. No maximum will be used.
You can set joining iterations by :
$disciteDB->config()->setJoinMaxIterations(max_interations);
To retrieve the current joining method:
$disciteDB->config()->getJoinMaxIterations();
You can also set the separator used and retun in CONCAT
mode.
By default, the separator is set to ,
.
You can set joining separator by :
$disciteDB->config()->setJoinSeparator(max_interations);
To retrieve the current joining method:
$disciteDB->config()->getJoinSeparator();
Constant | Method | Default? |
---|---|---|
JOIN_METHOD_NO_JOIN | no joining | ✓ |
JOIN_METHOD_FLAT | joined using INNER RIGHT sql | |
JOIN_METHOD_CONCAT | joined using CONCAT sql, return in plain text | |
JOIN_METHOD_JSON | joined using JSON_AGG sql, return in json | |
JOIN_METHOD_MULTIDIMENSIONAL_ARRAY | joined using JSON_AGG, return in php array |
The library allows formatting, correction, and adding keys or values to limit errors and reduce tasks.
You can select independently for tables and columns ("keys") either strict or permissive usage modes.
You can choose strict or permissive usage for tables. Default is strict usage.
$disciteDB->config()->setTableUsage(selected_table_usage);
To retrieve the current table usage:
$disciteDB->config()->getTableUsage();
Constant | Value | Default? |
---|---|---|
TABLE_USAGE_STRICT | Strict usage | ✓ |
TABLE_USAGE_LOOSE | Loose usage |
You can choose strict or permissive usage for keys (columns). Default is strict usage.
$disciteDB->config()->setKeyUsage(selected_key_usage);
To retrieve the current key usage:
$disciteDB->config()->getKeyUsage();
Constant | Value | Default? |
---|---|---|
KEY_USAGE_STRICT | Strict usage | ✓ |
KEY_USAGE_LOOSE | Loose usage |
If you are in loose
usage mode, you may skip this section.
Access key configuration with:
$disciteDB->keys();
A key has several parameters:
Parameter | Type | Usage | Default | Nullable ? |
---|---|---|---|---|
name |
string |
Showed name as object | `` | |
alias |
string |
Used name in database | $name |
✓ |
prefix |
string |
Used prefix in database | null |
✓ |
type |
DisciteDB::TYPE_[...] |
Used in strict mode 1 |
DisciteDB::TYPE_STRING_STRING |
✓ |
index |
DisciteDB::INDEX_TYPE_[...] |
Used if you want to set index 2 | DisciteDB::INDEX_TYPE_NONE |
✓ |
indexTable |
Table or string |
Used if you previously set index type | null |
✓ |
default |
DisciteDB::DEFAULT_VALUE_[...] or your own value 3 |
Used to define default value | DisciteDB::DEFAULT_VALUE_EMPTY_STRING |
✓ |
nullable |
bool |
Used in strict mode. 4 |
false |
✓ |
secure |
bool |
Used in strict mode. 5 |
false |
✓ |
updatable |
bool |
Used in strict mode. 6 |
false |
✓ |
You can select key type. It will be usefull while formatting values. It will escape values which aren't the same as selected type.
Groups are available to help definition :
Binary Type
Constant | Value | Size |
---|---|---|
TYPE_BINARY_BLOB | blob | ✓ |
TYPE_BINARY_TINYBLOB | tinyblob | |
TYPE_BINARY_MEDIUMBLOB | mediumblob | |
TYPE_BINARY_LONGBLOB | longblob | |
TYPE_BINARY_JSON | json | |
TYPE_BINARY_FILE | file |
Date Type
Constant | Value | Size |
---|---|---|
TYPE_DATE_DATE | date | ✓ |
TYPE_DATE_TIME | time | |
TYPE_DATE_DATETIME | datetime | |
TYPE_DATE_TIMESTAMP | timestamp | |
TYPE_DATE_YEAR | year |
String Type
Constant | Value | Size |
---|---|---|
TYPE_STRING_STRING | string | ✓ |
TYPE_STRING_SMALLTEXT | smalltext | |
TYPE_STRING_MEDIUMTEXT | mediumtext | |
TYPE_STRING_LONGTEXT | longtext | |
TYPE_STRING_UUID | uuid | |
TYPE_STRING_EMAIL | ||
TYPE_STRING_URL | url | |
TYPE_STRING_IP | ip | |
TYPE_STRING_USERNAME | username | |
TYPE_STRING_PASSWORD | password |
Integer Type
Constant | Value | Size |
---|---|---|
TYPE_INTEGER_BOOLEAN | boolean | ✓ |
TYPE_INTEGER_INT | int | |
TYPE_INTEGER_BIGINT | bigint | |
TYPE_INTEGER_TINYINT | tinyint | |
TYPE_INTEGER_MEDIUMINT | mediumint | |
TYPE_INTEGER_SMALLINT | smallint | |
TYPE_INTEGER_UNIXTIME | unixtime |
Float Type
Constant | Value | Size |
---|---|---|
TYPE_FLOAT_FLOAT | float | ✓ |
TYPE_FLOAT_DOUBLE | double | |
TYPE_FLOAT_DECIMAL | decimal |
You can select key index.
Index will be usefull if you decide to make SQL joining method.
Const | Usage | Default ? |
---|---|---|
DisciteDB::INDEX_TYPE_NONE |
null | ✓ |
DisciteDB::INDEX_TYPE_INDEX |
||
DisciteDB::INDEX_TYPE_UNIQUE |
||
DisciteDB::INDEX_TYPE_PRIMARY |
||
DisciteDB::INDEX_TYPE_FULLTEXT |
||
DisciteDB::INDEX_TYPE_SPATIAL |
You can put a table name as indexTable
. Usefull to rach joining methods.
You can decide if a column can be nullable or not.
In strict
mode, secured values will not be returning. Such as password.
In the futur, I would like to implement a few new operators such as login who would return only true or false if password match.
In strict
mode, this will disable updatable column value. Would be useful for id.
You can specify default values. Or you define a string, integer, flaot, etc or you decide to use default pre-defined values.
Const | Value | |
---|---|---|
DisciteDB::DEFAULT_VALUE_NULL |
null |
|
DisciteDB::DEFAULT_VALUE_CURRENT_TIMESTAMP |
CURRENT_TIMESTAMP() |
|
DisciteDB::DEFAULT_VALUE_ZERO |
0 | |
DisciteDB::DEFAULT_VALUE_EMPTY_STRING |
|
|
DisciteDB::DEFAULT_VALUE_UUIDV4 |
uuid() |
|
DisciteDB::DEFAULT_VALUE_NOW |
CURRENT_TIMESTAMP() |
You can create keys in two ways:
$disciteDB->keys()->create('key_name', [
'alias' => 'alias_name',
'prefix' => 'wanted_prefix',
'Type' => TYPE_STRING_STRING,
// etc...
]);
or
$disciteDB->keys()->add();
WIP - documentation
If you are in loose
usage mode, you may skip this section.
Access key configuration with:
$disciteDB->tables();
A table has several parameters:
Parameter | Type | Usage | Default | Nullable ? |
---|---|---|---|---|
name |
string |
Showed name as object | `` | |
alias |
string |
Used name in database | $name |
✓ |
prefix |
string |
Used prefix in database | null |
✓ |
primaryKey |
BaseKey |
Used to define primary key | null |
✓ |
sort |
DisciteDB::SORT_[...] |
Used if you want to set a default sorting method | DisciteDB::SORT_NO_SORT |
✓ |
You will be able to make queries with multiples operators.
Theses operators are :
All
;Count
;Listing
;Retrieve
;Update
;Delete
;Create
Still not implemented ;Compare
Still not implemented ;Keys
Still not implemented;
This operator will return every data in selected table
$resultObject = $disciteDb->table('tableName')->all();
This operator will return a count value.
$resultObject = $disciteDb->table('tableName')->count($args);
You can put filters as arguments. Arguments must be an array. You're able to put flat values, Query Conditions.
$args = [
'columnName' => 'value',
'columnName' => QueryCondition::Or('value_1', 'value_2');,
];
This operator will return a values based on filters. It's like all
operator with arguments.
$resultObject = $disciteDb->table('tableName')->listing($args);
You can put filters as arguments. Arguments must be an array. You're able to put flat values, Query Conditions or Query modifiers.
$args = [
'columnName' => 'value',
'columnName' => QueryCondition::Or('value_1', 'value_2');,
QueryModifier::Sort(DisciteDB::SORT_DESC, 'id');
];
This operator will be used to retrieve single data.
$resultObject = $disciteDb->table('tableName')->retrieve($uuid);
UUID can be a string
, an integer
or an array
. For the two first, in strict
mode, primary indexed key will be used as id. If you want to manually specify uuid key name, you must set UUID as an array.
// String or integer definition
$uuid = 3;
// Array definition
$uuid = [
'columnName' => 'value',
];
This operator will be used to update data.
$resultObject = $disciteDb->table('tableName')->update($uuid, $args);
UUID can be a string
, an integer
or an array
. For the two first, in strict
mode, primary indexed key will be used as id. If you want to manually specify uuid key name, you must set UUID as an array.
// String or integer definition
$uuid = 3;
// Array definition
$uuid = [
'columnName' => 'value',
];
You must put values as arguments. Arguments must be an array. You're able to put flat values only.
$args = [
'columnName' => 'value',
];
This operator will be used to delete data.
$resultObject = $disciteDb->table('tableName')->delete($uuid);
UUID can be a string
, an integer
or an array
. For the two first, in strict
mode, primary indexed key will be used as id. If you want to manually specify uuid key name, you must set UUID as an array.
// String or integer definition
$uuid = 3;
// Array definition
$uuid = [
'columnName' => 'value',
];
This operator will be used to create data.
In strict
mode, undefined values will be generate by the library with default previously defined values.
$resultObject = $disciteDb->table('tableName')->create($args);
You must put values as arguments. Arguments must be an array. You're able to put flat values only.
$args = [
'columnName' => 'value',
];
You are able to manipulate queries. At this time, with previously showed $args
. You would just set an equal
condition and default sorting/limit.
With theses user-friendly queries "manipulators", you'll see that is easy to perform a strong query.
Theses methods, used in listing
and count
, will auto-format (even in loose usage mode) query based on parameters you give.
Simple Condition. Must not be used because you can perform this condition with a standard argument.
QueryCondition::Equal('value');
You can put every values as you want to check.
QueryCondition::Or('value_1','value_2');
Library will format like this :
('columnName' = 'value_1' OR 'columnName' = 'value_2')
You must send location. Default used const is QUERY_LOCATION_BETWEEN
.
QueryCondition::Contains('value', DisciteDB::QUERY_LOCATION_[...]);
Library will format like this :
'columnName' LIKE '%value%'
Location will format value as :
Const | Value format |
---|---|
DisciteDB::QUERY_LOCATION_STARTWITH |
%value |
DisciteDB::QUERY_LOCATION_ENDWITH |
value% |
DisciteDB::QUERY_LOCATION_BETWEEN |
%value% |
You can put every values as you want to check.
QueryCondition::Between(10, 20);
Library will format like this :
'columnName' BETWEEN 10 AND 20
QueryCondition::Not('value');
Library will format like this :
'columnName' != 'value'
if you specify more than one argument. NotIn
condition will replace Not
condition automaticly.
QueryCondition::NotIn('value_1','value_2');
Library will format like this :
'columnName' NOT IN ('value_1', 'value_2')
if you specify only one argument. Not
condition will replace NotIn
condition automaticly.
You must send location. Default used const is QUERY_LOCATION_BETWEEN
.
QueryCondition::NotContains('value', DisciteDB::QUERY_LOCATION_[...]);
Library will format like this :
'columnName' NOT LIKE '%value%'
Location will format value as :
Const | Value format |
---|---|
DisciteDB::QUERY_LOCATION_STARTWITH |
%value |
DisciteDB::QUERY_LOCATION_ENDWITH |
value% |
DisciteDB::QUERY_LOCATION_BETWEEN |
%value% |
You must send location. Default used const is QUERY_LOCATION_BETWEEN
.
QueryCondition::Like('value', DisciteDB::QUERY_LOCATION_[...]);
Library will format like this :
'columnName' LIKE '%value%'
Location will format value as :
Const | Value format |
---|---|
DisciteDB::QUERY_LOCATION_STARTWITH |
%value |
DisciteDB::QUERY_LOCATION_ENDWITH |
value% |
DisciteDB::QUERY_LOCATION_BETWEEN |
%value% |
Aliase of NotContains
.
QueryCondition::NotBetween(10, 20);
Library will format like this :
'columnName' NOT BETWEEN 10 AND 20
QueryCondition::MoreThan(10);
Library will format like this :
'columnName' > 10
QueryCondition::LessThan(10);
Library will format like this :
'columnName' < 10
QueryCondition::MoreOrEqual(10);
Library will format like this :
'columnName' >= 10
QueryCondition::LessOrEqual(10);
Library will format like this :
'columnName' <= 10
Theses methods, used in listing
, will give you additionals methods for results.
QueryModifier::Order(DisciteDB::SORT_[...], 'columnName');
Library will format like this :
ORDER BY 'columnName' 'DESC'
Sorting available constants are :
Const | Value format |
---|---|
DisciteDB::SORT_DESC |
DESC sorting |
DisciteDB::SORT_ASC |
ASC sorting |
DisciteDB::SORT_NO_SORT |
null |
Aliase of order modifier.
If you decide to use limit modifier, you must specify a limit
in integer
.
Define Offset
is optional.
QueryModifier::Limit($limit, ?$offset);
Library will format like this :
LIMIT 10 OFFSET 20
Once you perform your query with operator. You will be able to retrieve results.
Method | Description |
---|---|
fetchQuery() |
Returns SQL string only |
fetchAll() |
Gets all matching rows |
fetchNext() |
Gets the next row |
fetchArray() |
Gets all rows and schema info |
fetchInformations() |
Meta-information (types, keys, etc.) |
You'll retrieve the query as string
$result = $disciteDB->table('disciteDB_FakeItems')->all();
// Fetching query for example.
print_r($result->fetchQuery());
Result will be :
string(45) "SELECT * FROM `test_db`.`disciteDB_FakeItems`"
You'll retrieve all results as array
.
Doing this will make the same result as : mysqli_fetch_all($result, MYSQLI_ASSOC)
or mysqli_result::fetch_all(int $mode = MYSQLI_ASSOC)
$result = $disciteDB->table('disciteDB_FakeItems')->all();
// Fetching all datas for example.
print_r($result->fetchAll());
Result will be :
array(12) {
[0]=>
array(6) {
["id"]=>
int(2)
["category_id"]=>
int(1)
["name"]=>
string(10) "Red Widget"
["description"]=>
string(29) "A slightly larger red widget."
["price"]=>
float(15.4900000000000002131628207280300557613372802734375)
["created_at"]=>
string(19) "2025-06-04 19:45:27"
}
[1]=>
array(6) {
["id"]=>
int(3)
["category_id"]=>
int(1)
["name"]=>
string(12) "Green Widget"
["description"]=>
string(23) "A stylish green widget."
["price"]=>
float(13.75)
["created_at"]=>
string(19) "2025-06-04 19:45:27"
}
// .........
}
You'll retrieve the next result as array
.
Doing this will make the same result as : mysqli_fetch_row($result)
or mysqli_result::fetch_row()
.
Informations will be also returned.
$result = $disciteDB->table('disciteDB_FakeItems')->all();
// Fetching next data for example.
print_r($result->fetchNext());
Result will be :
array(2) {
["data"]=>
array(6) {
["id"]=>
int(1)
["category_id"]=>
int(1)
["name"]=>
string(11) "Blue Widget"
["description"]=>
string(32) "A small blue widget for testing."
["price"]=>
float(10.9900000000000002131628207280300557613372802734375)
["created_at"]=>
string(19) "2025-06-04 19:45:27"
}
["info"]=>
array(4) {
["status"]=>
string(7) "success"
["time"]=>
int(1749059127)
["query"]=>
array(5) {
["operator"]=>
string(3) "All"
["table"]=>
string(19) "disciteDB_FakeItems"
["context"]=>
NULL
["gaveArgments"]=>
int(0)
["affectedRows"]=>
int(12)
}
["error"]=>
NULL
}
}
You'll retrieve all datas as array
.
Doing this will make the same result as : mysqli_fetch_all($result, MYSQLI_ASSOC)
or mysqli_result::fetch_all(int $mode = MYSQLI_ASSOC)
.
Informations will be also returned.
$result = $disciteDB->table('disciteDB_FakeItems')->all();
// Fetching array datas for example.
print_r($result->fetchArray());
Result will be :
array(2) {
["data"]=>
array(12) {
// Datas
}
["info"]=>
array(4) {
["status"]=>
string(7) "success"
["time"]=>
int(1749059127)
["query"]=>
array(5) {
["operator"]=>
string(3) "All"
["table"]=>
string(19) "disciteDB_FakeItems"
["context"]=>
NULL
["gaveArgments"]=>
int(0)
["affectedRows"]=>
int(12)
}
["error"]=>
NULL
}
}
You'll retrieve informations only as array
.
$result = $disciteDB->table('disciteDB_FakeItems')->all();
// Fetching informations for example.
print_r($result->fetchInformations());
Result will be :
array(4) {
["status"]=>
string(7) "success"
["time"]=>
int(1749059127)
["query"]=>
array(5) {
["operator"]=>
string(3) "All"
["table"]=>
string(19) "disciteDB_FakeItems"
["context"]=>
NULL
["gaveArgments"]=>
int(0)
["affectedRows"]=>
int(12)
}
["error"]=>
NULL
}
src/
– Core library filesexample/
– Usage demonstrationstests/
– PHPUnit testing
MIT License — see LICENSE
file.
Created by Romain QUINTAINE.