Model


Ice\Mvc\Model allows you to manipulate database records / documents as objects.

Model file

It's very easy to start using the models, just extends the Ice\Mvc\Model using the same class name as your table / collection.

namespace App\Models;

use Ice\Mvc\Model;

class Posts extends Model
{

}

The model App\Models\Posts will map to the table / collection posts. If you want to manually specify another name for the mapped source, you can set from attribute.

class Posts extends Model
{
    protected $from = 'articles'
}

Find one object

By using findOne method you can select one record / document and map it to an object to get easy access to the data.

// Find by id
$post = Posts::findOne(1);

// And access to the data
// In object way
echo $post->title;

// In array way
echo $post['title'];

// By a getter
echo $post->get('title');

Find many objects

The following examples will show you how to query multiple elements from a model. Use find method to create a set of objects.

$posts = Posts::find(['status' => 1], ['limit' => 10]);

foreach ($posts as $post) {
    echo $post->title;
}

Create (insert) a new object

To insert a new record / document use create method.

$post = new Posts();
$post->title = 'First post';
$post->create();

You can set the data in the constructor to avoid manually assigning each column.

$post = new Posts([
    'title' => 'Second post'
]);
$post->create();

Or set the data in the create method.

$post = new Posts();
$post->create([
    'title' => 'Third post'
]);

Put an array to set a whitelist of fields that will be taken during creation.

$post = new Posts();
$post->setData([
    'title' => 'Fourth post',
    'description' => 'Some description'
]);

// Only a title will be taken
$post->create(['title']);

Or set the valid fields in the fields attribute.

class Posts extends Model
{
    protected $fields = [
        'title',
    ];
}

And use the _POST global variable as the data.

$post = new Posts();
$post->create($_POST);

Add a Validation rules

A validation on create method is built-in and enabled by default, all you have to do is to add rules attribute.

class Posts extends Model
{
    protected $rules = [
        'title' => 'required',
    ];
}

And fetch the error messages if a title is missing.

$post = new Posts();

if ($post->create($_POST) !== true) {
    $errors = $post->getMessages();
}

Update

$post = Posts::findOne(1);

$post->title = 'A new title';
$post->update();

To the update method you can pass an array of data like to the create method.

$post = Posts::findOne(1);
$post->update([
    'title' => 'Update v2'
]);

If you have the fields attribute specified, only that fields will be taken from the data. The main difference to the create method is that the validation is not enabled by default. You have to use setValidation before the update method.

$validation = new Validation();
$validation->rules($this->getRules([
    'title',
]));
$this->setValidation($validation);

$this->update($_POST);

The save method allows you to create / update record according to whether they already exist in the table associated with a model.

$post = new Post();
$post->title = 'A new title';
$post->save();

$post->title = 'Updated title';
$post->save();

Relations

Specify the relations in the initialize method to easily get related model.


class Posts extends Model
{
    public function initialize()
    {
        $this->belongsTo('user_id', __NAMESPACE__ . '\Users', $this->getIdKey(), ['alias' => 'User']);
        $this->hasMany($this->getIdKey(), __NAMESPACE__ . '\Coments', 'post_id', ['alias' => 'Coments']);
    }
}
$post = Posts::findoOne(1);
$user = $post->getUser();

foreach ($post->getComments() as $comment) {
    echo $comment->content;
}

Services

Service is intermediary between Model and Controller. You can inject model into service constructor.

namespace App\Services;

use App\Models\Posts;
use Ice\Mvc\Service;

class PostService extends Service
{
    public function __construct(Posts $model)
    {
        $this->setModel($model);
    }

    public function add($data = [])
    {
        // Try to create a new post
        if ($this->create($data) === true) {
            // Return the object if it was created
            return $this->getModel();
        } else {
            // Return an array of error messages
            return $this->getMessages();
        }
    }
}

Then in the Controller you have access to all model and service methods.

namespace App\Modules\Admin\Controllers;

use App\Models\Posts;
use App\Services\PostService;
use Ice\Mvc\Controller;

class PostController extends Controler
{
    protected $service;

    public function __construct(PostService $service)
    {
        $this->service = $service;
    }

    public function addAction()
    {
        $post = $this->service->add($this->request->getPost()->getData());

        // Try to create a new post from _POST data
        if ($post instanceof Posts) {
            // Redirect to /post page
            $this->response->redirect('post');
        } else {
            // Send errors variable to the view
            $this->view->setVar('errors', $post);
        }
    }

    public function getDetailsAction()
    {
        // Try to find and load a post
        if ($post = $this->service->loadOne($this->dispatcher->getParam('param'))) {
            // Send a post variable to the view
            $this->view->setVar('post', $post);
        } else {
            // Display a not found page
            parent::notFound();
        }
    }
}

Hooks

It's possible to invoke some code by adding a hook.

class Users extends Model
{

    public function create($fields = [], Validation $extra = null)
    {
        $this->di->hook('model.after.validate', function ($this) {
            $this->set('password', md5($this->get('password')));
        });

        return parent::create($fields, $extra);
    }
}

Available hooks in the model: