CakePHPのORMとは
CakePHPは、PHPで広く使われるフルスタックWebフレームワークです。その中でも**ORM(Object-Relational Mapper)**は、データベース操作をPHPオブジェクトとして扱えるようにする中核機能です。
CakePHPのORMはLaravelのEloquentとは設計思想が異なり、TableクラスとEntityクラスの2層構造になっています。
- Tableクラス:テーブル全体を表し、クエリ・バリデーション・アソシエーションを担う
- Entityクラス:1行のレコードを表すオブジェクト
この分離のおかげで、複雑なビジネスロジックを整理しやすくなっています。
環境準備
CakePHPプロジェクトはComposerで作成できます。
composer create-project --prefer-dist cakephp/app:~4.0 myapp
cd myapp
config/app_local.php にデータベース接続情報を設定します。
'Datasources' => [
'default' => [
'host' => 'localhost',
'username' => 'root',
'password' => 'secret',
'database' => 'myapp_db',
'driver' => 'Cake\Database\Driver\Mysql',
],
],
Tableクラスを作る
Artisanに相当するCakePHPのCLIツール「bake」でTableクラスを自動生成できます。
bin/cake bake model Articles
src/Model/Table/ArticlesTable.php が生成されます。手動で作る場合は以下のようになります。
<?php
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class ArticlesTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('articles'); // テーブル名
$this->setPrimaryKey('id'); // 主キー
$this->setEntityClass('App\Model\Entity\Article');
// タイムスタンプ自動更新
$this->addBehavior('Timestamp');
}
// バリデーション定義
public function validationDefault(Validator $validator): Validator
{
$validator
->notEmptyString('title', 'タイトルは必須です')
->maxLength('title', 255, 'タイトルは255文字以内です')
->notEmptyString('body', '本文は必須です');
return $validator;
}
}
Entityクラスを作る
Entityは1レコードを表します。アクセス可能なフィールドを $_accessible で宣言します。
<?php
// src/Model/Entity/Article.php
namespace App\Model\Entity;
use Cake\ORM\Entity;
class Article extends Entity
{
// mass assignmentを許可するフィールド
protected array $_accessible = [
'title' => true,
'body' => true,
'published' => true,
'created' => true,
'modified' => true,
];
// 仮想プロパティ:タイトルを大文字に変換して返す
protected function _getTitleUpper(): string
{
return strtoupper($this->title);
}
}
コントローラから $article->title_upper でアクセスできます。
クエリビルダで検索する
基本的な取得
// コントローラ内での利用例
$articlesTable = $this->fetchTable('Articles');
// 全件取得
$articles = $articlesTable->find()->all();
// 主キーで1件取得
$article = $articlesTable->get(1);
// 条件付き取得
$published = $articlesTable->find()
->where(['published' => true])
->orderBy(['created' => 'DESC'])
->limit(10)
->all();
SELECT・LIKE・IN句
// 特定のカラムだけ取得
$titles = $articlesTable->find()
->select(['id', 'title'])
->all();
// LIKEで部分一致検索
$results = $articlesTable->find()
->where(['title LIKE' => '%CakePHP%'])
->all();
// IN句を使う
$specific = $articlesTable->find()
->where(['id IN' => [1, 2, 3]])
->all();
カスタムFinderを定義する
Tableクラスにカスタムfinderを追加することで、クエリを再利用しやすくなります。
// ArticlesTable.php に追加
public function findPublished(Query $query, array $options): Query
{
return $query->where(['published' => true])
->orderBy(['created' => 'DESC']);
}
呼び出しはシンプルです。
$articles = $articlesTable->find('published')->all();
レコードの保存・更新・削除
新規保存
$article = $articlesTable->newEmptyEntity();
$article = $articlesTable->patchEntity($article, [
'title' => 'CakePHP入門',
'body' => 'ORMを学ぼう',
'published' => true,
]);
if ($articlesTable->save($article)) {
echo "保存成功: ID = " . $article->id;
} else {
// バリデーションエラーの取得
$errors = $article->getErrors();
}
更新
$article = $articlesTable->get(1);
$article = $articlesTable->patchEntity($article, ['title' => '更新されたタイトル']);
$articlesTable->save($article);
削除
$article = $articlesTable->get(1);
$articlesTable->delete($article);
アソシエーション(テーブル間の関連)
CakePHPのORMは hasMany / belongsTo / hasOne / belongsToMany をサポートしています。
// ArticlesTable.php
public function initialize(array $config): void
{
parent::initialize($config);
// 1記事は複数コメントを持つ
$this->hasMany('Comments', [
'foreignKey' => 'article_id',
]);
// 1記事は1ユーザーに属する
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
]);
}
関連データを含めて取得するには contain を使います。
$article = $articlesTable->get(1, contain: ['Comments', 'Users']);
echo $article->user->name;
foreach ($article->comments as $comment) {
echo $comment->body;
}
まとめ
CakePHPのORMをざっくりまとめると以下のとおりです。
| 概念 | 役割 |
|---|---|
| Tableクラス | テーブル全体の操作・バリデーション・アソシエーション |
| Entityクラス | 1レコードの表現・仮想プロパティ |
| QueryBuilder | 柔軟なSELECT / WHERE / ORDER句の構築 |
| カスタムFinder | 再利用可能なクエリの定義 |
LaravelのEloquentに慣れた方には最初少し戸惑うかもしれませんが、責務が明確に分離されているため、大規模なアプリケーションでも管理しやすいのがCakePHP ORMの強みです。ぜひ実際のプロジェクトで試してみてください。