Medools
âWe can solve any problem by introducing an extra level of indirection.â, (*1)
Index:, (*2)
Intro
A basic framework for models related to a Database., (*3)
With this framework, you configure just the minimal for your models and then you
focus on your own code. Abstract the communication with your Database!, (*4)
Creating a new model for your application is easy, just extend the Model base
class and define some settings., (*5)
To interact with the Database, it is used catfan/Medoo., (*6)
Install
Open a terminal in your project directory and run:, (*7)
composer require aryelgois/medools
, (*8)
Setup
Before using this framework, you need a config file somewhere in your
application. It defines Servers and Databases that are accessed by the models., (*9)
The reason for the config file being .php
is that it contains sensitive data,
and if a client could request it, nothing would be returned., (*10)
Basically, it contains data to instantiate catfan/Medoo objects. See details
in its guide. You can also follow the config example., (*11)
This file returns an array with the following keys:, (*12)
-
servers
: Lists database Servers that can be connected and their credentials.
Each item is an array with the following keys:, (*13)
server
-
port
(optional)
username
password
-
database_type
It needs the corresponding PHP_PDO extension
-
databases
: List of Databases referenced in the models classes. Each item is
an array that contains:, (*14)
-
server
Server key from the previous list. If omitted, default
is used
database_name
A shortcut to only defining database_name
is setting the database directly
as string, (*15)
There are other configurations that can be used, see the guide for
more. You can add them where it is reasonable. When connecting to a database,
its array is merged on top of the server's. It means that a database can
overwrite a server configuration., (*16)
If the database server is not a servers
key, it is used as it is. So the
servers array is totally optional, as long as the database contains all required
data to connect to the Database., (*17)
The whole point of this config file is that you can define multiple databases
in the same Server without repeating its configurations, as well define
databases in different servers., (*18)
Also, you need to include this line in the beginning of your code:, (*19)
<?php
aryelgois\Medools\MedooConnection::loadConfig('path/to/config/medools.php');
It's a good idea to put in something like a bootstrap.php
, which also requires
composer's autoload (prior to the line above), and is always required by your
scripts., (*20)
MedooConnection works like a Medoo factory, but reuses its instances., (*21)
Using a Model
Creating a new Model
You can instantiate a new Model, without any parameters, to create a fresh model
object. Then add data into its columns, like in any other object. Your code
should known which columns are available, but you can call getColumns()
for a
complete list from that model., (*22)
Your changes are stored in that object, so you need to save()
in order to send
to the Database., (*23)
Loading from Database
Instantiate the model with a value for its PRIMARY_KEY, or specify an
associative array with which columns you would like to filter.
Only one row is loaded., (*24)
You can also load()
after creating the object., (*25)
Saving into Database
Use save()
to send all changes to the Database, and update()
to only send
some., (*26)
Some columns you might have changed can have different values afterwards, due to
some validation process or Database defaults., (*27)
Deleting from Database
Simply use delete()
., (*28)
If the model has SOFT_DELETE configured, it will just update that column. So
you are able to undelete()
later., (*29)
Otherwise, it will completely delete the row from the Database, and reset()
the model object., (*30)
You can use isDeleted()
to check if the model was deleted. It is useful when
SOFT_DELETE is configured., (*31)
Accessing and manipulating data
Just like in any object:, (*32)
-
$model->column
will return the stored data, or a foreign model *
-
$model->column = value
will set a new data
* It means that you can chain the models:
$model->foreign->column
, (*33)
You can also get data with:, (*34)
-
dump()
: Returns data from model's Table, you can filter which rows
and which columns you want
-
getPrimaryKey()
: Returns the last saved Primary Key
-
toArray()
: Returns data from the model in an array (foreigns included)
And change data with:, (*35)
-
fill()
: Sets multiple columns from an array of column => value. It returns
the object (is chainable)
Iterating over many rows
A ModelIterator is provided to access multiple rows, but it provides only one
at time., (*36)
Give it a model class you want to iterate over, and some filter
array. Then it will load()
each matched row, one by one., (*37)
A shortcut is calling getIterator()
directly from the model class, which just
asks for $where
., (*38)
Foreign models
This framework supports foreign models. You can configure them in the model
class, and access $model->foreign_column
. They are simply other models,
referenced in your model., (*39)
They are loaded on demand, so you don't need to worry about loading lots of
foreigns just because you want a single column from the model., (*40)
:warning: Warning: Be careful not to configure a circular foreign constraint.
When serializing a model, it can fail because of recursion., (*41)
Other methods
Useful methods that are available:, (*42)
-
__isset()
: Use with isset to check if a column is null
-
__unset()
: Use with unset to set a column to null
-
__wakeup()
: You can unserialize a model, i.e. save in $_SESSION
and
recover in a another request
-
getChangedColumns()
: Lists changed columns
-
getCurrentTimestamp()
: Selects the current timestamp from Database, useful
to keep timezone consistent
-
getData()
: Gives currently stored data
-
getDatabase()
: Gives a direct access to the Database, already connected and
ready to use. See catfan/Medoo for details
-
getRequiredColumns()
: Gives a list of columns that must be set before saving
-
getStampColumns()
: Gives a list of columns that receives a timestamp
automatically
-
isFresh()
: Tells if the object is a new Model
-
jsonSerialize()
: You can json_encode models! It expands foreign models
-
reload()
: Use to re fetch the row with model's Primary Key
-
undo()
: Removes changes. Pass a column name to only remove that column,
otherwise it removes all changes
You can also add custom methods in your models, to automatically get some data
in a format, or for doing a specific task., (*43)
There are also event methods that are automatically called by some
base methods., (*44)
Reusing models
To avoid creating multiple instances for the same model, there is a
ModelManager class which contains pointers to models already created. To
retrieve them, use the getInstance()
method, which asks for a model class and
a where clause (only one row is selected). A shortcut is calling
the getInstance()
directly from the model, which just asks for $where
., (*45)
See more in the Advanced section., (*46)
If you wish, you can still create a new instance for an already existing model.
The new object will not contain changes made in the old one., (*47)
Configuring a Model
The settings are constants in each model class. You can omit some to reuse from
parent class., (*48)
Only TABLE and COLUMNS are required to define a new model., (*49)
DATABASE
Database key in the Medools config file, (*50)
- Type:
string
- Default:
'default'
TABLE
Database's Table the model represents, (*51)
The recomended is to use a plural name for the table and its singular in the
model name, (*52)
COLUMNS
Columns the model expects to exist, (*53)
- Type:
string[]
- Default:
['id']
The column may be followed by a prefered data type. If not specified, defaults
to string
:, (*54)
<?php
const COLUMNS = [
'id [Int]',
'name',
'data [JSON]',
];
Possible types are those supported by Medoo:
- Bool
- Int
- JSON
- Number
- Object
- String
, (*55)
These types are used when accessing the column in the database, but since Medoo
has a type auto-detection, only Object
and JSON
are required to
automatically unserialize/decode arrays and objects. You can still use the
others for an explicit type casting., (*56)
Note that nullable/optional columns can have a null
value., (*57)
PRIMARY_KEY
Primary Key column or columns, (*58)
- Type:
string[]
- Default:
['id']
AUTO_INCREMENT
Auto Increment column, (*59)
- Type:
string|null
- Default:
'id'
STAMP_COLUMNS
List of columns to receive the current timestamp automatically, (*60)
- Type:
string[]
- Values:
'auto'
, 'date'
, 'time'
or 'datetime'
- Default:
'datetime'
The columns are automatically updated with the current timestamp on save()
and
update()
. This constant allows multiple timestamp columns. If the column was
manually changed, it will not be overwritten., (*61)
These columns are implicitly optional, because they are changed before
saving/updating the model. The exception is auto
columns, which must be
controlled by the Database (MySQL only allows one timestamp
)., (*62)
The following structure is valid:, (*63)
<?php
const STAMP_COLUMNS = [
'column_a' => 'datetime',
'column_b',
'column_c' => 'date',
];
Here, column_b
will use the default., (*64)
OPTIONAL_COLUMNS
List of columns which have a default value or are nullable, (*65)
You don't need to include implict optional columns, like AUTO_INCREMENT,
STAMP_COLUMNS and SOFT_DELETE., (*66)
FOREIGN_KEYS
Foreign Keys map, (*67)
A map of columns in the curent model which point to a column in another model, (*68)
Example:, (*69)
<?php
const FOREIGN_KEYS = [
'local_column' => [
'Fully\\Qualified\\ClassName',
'foreign_column'
],
];
If the foreign class is in the same namespace, you can use ClassName::class
., (*70)
READ_ONLY
If __set()
, save()
, update()
, delete()
and undelete()
are disabled, (*71)
- Type:
boolean
- Default:
false
SOFT_DELETE
If delete()
actually removes the row or if it changes a column, (*72)
It defines the column affected by the soft delete, (*73)
- Type:
string|null
- Default:
null
This column is implicitly optional, so you must define a default value in
the database schema accordingly to SOFT_DELETE_MODE., (*74)
SOFT_DELETE_MODE
How the soft delete works, (*75)
Which value SOFT_DELETE should be setted to., (*76)
- Type:
string
- Default:
'deleted'
Possible value |
When not deleted |
When deleted |
'deleted' |
0 |
1 |
'active' |
1 |
0 |
'stamp' |
null |
current timestamp |
Advanced
Events
There are some methods that can be extended by overriding event methods. It
makes easier to extend some functionalities., (*77)
Currently, these events are available:, (*78)
-
onColumnChange()
: Called when a column is changed. Useful to filter data
before storing in the model
-
onFirstSave()
: Called on the first time a model is saved
-
onSave()
: Called every time a model is saved
-
onValidate()
: Called when data needs to be validated, before storig in the
Database
ModelManager
This class tracks every model loaded during a request. It aims
to avoid model duplication, mainly in foreign keys., (*79)
If you create a new instance for an already existing model, the new instance
replaces the old one in this class, but other pointers to the old instance are
not updated. To avoid this, use the getInstance()
method provided either in
this class or in the model., (*80)