Active Record
Active Record is a way to work with a table through a class: a table has a model class, and every row is an object of it. Table columns become object properties automatically, so you do not write SQL.
The model class
Models live in the models folder. Create the file models/Post.php by hand:
// models/Post.php
namespace app\models;
use yii\db\ActiveRecord;
class Post extends ActiveRecord
{
public static function tableName(): string
{
return 'post';
}
}That is enough: Yii reads the column list of the post table from the database itself. The tableName() method names the table; without it Yii takes the class name in lower case.
Creating a record
A model is called from a controller. Add the line use app\models\Post; and an action to PostController:
// controllers/PostController.php
public function actionSeed(): string
{
$post = new Post();
$post->user_id = 1;
$post->title = 'First post';
$post->body = 'Text of the post';
$post->created_at = time();
$post->updated_at = time();
$post->save();
return "Created post number {$post->id}";
}Open /post/seed: a row appears in the table, and the page shows its number. After save() the id property holds the identifier of the new row.
Reading
$post = Post::findOne(5); // by primary key
$post = Post::findOne(['slug' => 'first']); // by a column value
$posts = Post::find()->all(); // all records
$count = Post::find()->count(); // the number of recordsfindOne() returns an object, or null if there is no such row. find() starts a query, and all() runs it and returns an array of objects.
Now the controller actions can take posts from the database:
public function actionIndex(): string
{
return $this->render('index', ['posts' => Post::find()->all()]);
}
public function actionView(int $id): string
{
$post = Post::findOne($id);
if ($post === null) {
throw new NotFoundHttpException('Post not found.');
}
return $this->render('view', ['post' => $post]);
}In a view columns are accessed as properties: $post->title, $post->body. In the view views/post/index.php from the previous chapter replace $post['title'] with $post->title.
Updating
$post = Post::findOne(5);
$post->title = 'New title';
$post->save();The same save() method updates an existing row. Yii sends only the changed columns to the database.
Deleting
$post = Post::findOne(5);
$post->delete();Row number 5 disappears from the table.
Bulk operations
When objects are not needed, rows are changed with one query:
Post::updateAll(['status' => 0], ['user_id' => 5]);
Post::deleteAll(['status' => 0]);The first argument of updateAll() is the new values, the second is the selection condition.
Common mistake
Before writing, save() validates the data against the model rules. If validation fails, it does not throw an exception but returns false, and the record is silently not saved. Always check the result:
if (!$post->save()) {
Yii::error($post->errors);
}Validation errors are in the $post->errors property.