Windwalker Record is a simple ActiveRecord to operate database row.

New a instance.

use Windwalker\Record\Record;

// Record object for users table
$user = new Record('users');

Or create a class:

use Windwalker\Record\Record;

class UserRecord extends Record
    protected $table = 'users';

$user = new UserRecord;

Load A Record

$user->load(25); // Load by primary key

$user->load(array('alias' => $alias)); // Load by field name.

Check row exists

catch (NoResultException $e)
    // Handle error

Bind Data

$data = array(
    'name'     => 'Sakura',
    'username' => 'sakura',
    'alias'    => 'sakura',
    'password' => '1234',
    'desc'     => 'foo bar.'


$user->name; // Sakura

If we have a table with only 3 columns:


The fields which not in this table will be remove after binding data.

$user->alias; // null

That makes our fields in Record will always same as DB table.


Create A New Row

If primary not exists, Record will create a new row in table.

$data = array(
    'name'     => 'Sakura',
    'username' => 'sakura',
    'password' => '1234'



echo $user->id; // Auto generated id

Update A Existing Row

If primary key exists, Record will update it.

$data = array(
    'id'       => 30,
    'name'     => 'Sakura',
    'username' => 'sakura',
    'password' => '1234'




Check method help you validate data.

class UserRecord extends Record
    // ...

    public function validate()
        if (!$this['name'])
            throw new InvalidArgumentException('Name empty.');

        return true;

Then we call validate() before store().



$result = $user->delete(); // boolean

// OR delete by conditions

$result = $user->delete(30); // boolean
$result = $user->delete(array('username' => $username)); // boolean

Mutator and Accessor

Mutator and accessor is a setter and getter to do some extra modification when you access value via magic methods.

This is an example of mutator:

class ArticleRecord extends Record
    protected function setCreatedDateValue($value)
        if ($value instanceof \DateTime)
            $value = $value->format('Y-m-d H:i:s');

        $this->data['created_date'] = $value;

Use camel-case style to define a method, then when you access the created_date field, this method will be auto executed.

$articleRecord->created_date = new \DateTime('now');

echo $articleRecord->created_date; // 2016-03-02 12:30:29

And an example of accessor:

class ArticleRecord extends Record
    protected function getCreatedDateValue($value)
        return new \DateTime($value);

And now you can get DateTime object back:

echo $articleRecord->created_date->format('Y-m-d H:i:s'); // 2016-03-02 12:30:29


Add casts to auto convert value type after read from DB:

class SakuraRecord extends Record
    protected $casts = [
        'id' => 'int',
        'price' => 'string',
        'created' => 'datetime',
        'modified' => 'timestamp',
        'images' => 'object', // or array will be json decoded
        'params' => \Windwalker\Structure\Structure::class,
        'other' => ['SomeClass', 'handle'] // Use callback


$sakuraRecord->id; // 3
$sakuraRecord->price; // '1200.00'
$sakuraRecord->created->format('Y/d/m'); // Auto convert to DateTime object
$sakuraRecord->modified; // 1497067876
$sakuraRecord->images[0]->url; // Store json in DB, can will auto decode to object.
$sakuraRecord->params->get(''); // Use class name to store value to object

Supports casts:

  • int | integer
  • real | float | double
  • string
  • bool | boolean
  • object
  • array | json
  • date | datetime
  • timestamp
  • (Class name)
  • (Callback array)


NestedRecord is a tool help us handle Nested Set Model.

Create Table

Name: categories

Name Type Description Need For NestedRecord
id int Primary Key
parent_id int ID of Parent Node V
title varchar Category title
path varchar Node path V
lft int Left key V
rgt int Right key V
level int Node level V


Every nested set should have a root node.

$cat = new NestedRecord('categories');


NOTE: The root node id is 1.

Create Node

Set as first child of ROOT

    ->setLocation(1, NestedRecord::LOCATION_FIRST_CHILD)

Now we will have a new node and it id is 2. Create a new node as last child of 2.

    ->setLocation(2, NestedRecord::LOCATION_LAST_CHILD)

Available positions:


Move Node

Re Ordering

$cat->move(1); // move up
$cat->move(-1); // Move down

Move To Other Node

Move to node 3 as last child.

$cat->moveByReference(3, NestedRecord::LOCATION_LAST_CHILD);


If a tree was not correct, using rebuild to reset all lft, rgt of this branch.

$cat->rebuild(); // Rebuild node: 5 and it's children.


Method to get an array of nodes from a given node to its root.

$path = $cat->getPath();


Method to get a node and all its child nodes.

$records = $cat->getTree();


Record has an event system that we can process logic before & after every DB operation.

Add event methods in your Record class.

class UserRecord extends Record
    public function onAfterLoad(Event $event)
        $this->foo = array('a', 'b', 'c');

Or add listeners to Dispatcher (You must install windwalker/event first).

// Use listener object
$record->getDispatcher()->addListener(new MyRecordListener);

// Use callback
$record->getDispatcher()->listen('onAfterStore', function (Event $event)
    // Process your logic

Available events:

  • onBeforeLoad
  • onAfterLoad
  • onBeforeStore
  • onAfterStore
  • onBeforeDelete
  • onAfterDelete
  • onBeforeBind
  • onAfterBind
  • onBeforeCreate
  • onAfterCreate
  • onBeforeUpdate
  • onAfterUpdate

See Events

If you found a typo or error, please help us improve this document.