Wrapper on catfan/Medoo
“We can solve any problem by introducing an extra level of indirection.”
- Using a Model
- Reusing models
- Configuring a Model
A basic framework for models related to a Database.
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!
Creating a new model for your application is easy, just extend the Model base class and define some settings.
To interact with the Database, it is used catfan/Medoo.
Open a terminal in your project directory and run:
composer require aryelgois/medools
Before using this framework, you need a config file somewhere in your application. It defines Servers and Databases that are accessed by the models.
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.
This file returns an array with the following keys:
servers: Lists database Servers that can be connected and their credentials. Each item is an array with the following keys:
database_typeIt needs the corresponding PHP_PDO extension
databases: List of Databases referenced in the models classes. Each item is an array that contains:
serverServer key from the previous list. If omitted,
A shortcut to only defining
database_nameis setting the database directly as string
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.
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.
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.
Also, you need to include this line in the beginning of your code:
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
MedooConnection works like a Medoo factory, but reuses its instances.
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.
Your changes are stored in that object, so you need to
save() in order to send
to the Database.
You can also
load() after creating the object.
save() to send all changes to the Database, and
update() to only send
Some columns you might have changed can have different values afterwards, due to some validation process or Database defaults.
If the model has SOFT_DELETE configured, it will just update that column. So
you are able to
Otherwise, it will completely delete the row from the Database, and
the model object.
You can use
isDeleted() to check if the model was deleted. It is useful when
SOFT_DELETE is configured.
Just like in any object:
$model->columnwill return the stored data, or a foreign model *
$model->column = valuewill set a new data
* It means that you can chain the models:
You can also get data with:
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:
fill(): Sets multiple columns from an array of column => value. It returns the object (is chainable)
A ModelIterator is provided to access multiple rows, but it provides only one at time.
Give it a model class you want to iterate over, and some filter
array. Then it will
load() each matched row, one by one.
A shortcut is calling
getIterator() directly from the model class, which just
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.
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.
⚠️ Warning: Be careful not to configure a circular foreign constraint. When serializing a model, it can fail because of recursion.
Useful methods that are available:
__isset(): Use with isset to check if a column is
__unset(): Use with unset to set a column to
__wakeup(): You can unserialize a model, i.e. save in
$_SESSIONand 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.
There are also event methods that are automatically called by some base methods.
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
getInstance() directly from the model, which just asks for
See more in the Advanced section.
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.
The settings are constants in each model class. You can omit some to reuse from parent class.
Database key in the Medools config file
Database's Table the model represents
The recomended is to use a plural name for the table and its singular in the model name
Columns the model expects to exist
The column may be followed by a prefered data type. If not specified, defaults
<?php const COLUMNS = [ 'id [Int]', 'name', 'data [JSON]', ];
Possible types are those supported by Medoo:
These types are used when accessing the column in the database, but since Medoo
has a type auto-detection, only
JSON are required to
automatically unserialize/decode arrays and objects. You can still use the
others for an explicit type casting.
Note that nullable/optional columns can have a
Primary Key column or columns
Auto Increment column
List of columns to receive the current timestamp automatically
The columns are automatically updated with the current timestamp on
update(). This constant allows multiple timestamp columns. If the column was
manually changed, it will not be overwritten.
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
The following structure is valid:
<?php const STAMP_COLUMNS = [ 'column_a' => 'datetime', 'column_b', 'column_c' => 'date', ];
column_b will use the default.
List of columns which have a default value or are nullable
You don't need to include implict optional columns, like AUTO_INCREMENT, STAMP_COLUMNS and SOFT_DELETE.
Foreign Keys map
A map of columns in the curent model which point to a column in another model
<?php const FOREIGN_KEYS = [ 'local_column' => [ 'Fully\\Qualified\\ClassName', 'foreign_column' ], ];
If the foreign class is in the same namespace, you can use
undelete() are disabled
delete() actually removes the row or if it changes a column
It defines the column affected by the soft delete
This column is implicitly optional, so you must define a default value in the database schema accordingly to SOFT_DELETE_MODE.
How the soft delete works
Which value SOFT_DELETE should be setted to.
|Possible value||When not deleted||When deleted|
There are some methods that can be extended by overriding event methods. It makes easier to extend some functionalities.
Currently, these events are available:
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
This class tracks every model loaded during a request. It aims to avoid model duplication, mainly in foreign keys.
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.