Posted by & filed under FuelPHP, Tech.

Orm---robot-arm---labelOrm—robot-arm—label / Marshall Astor – Food Fetishist

 

ORマッパーを全く知らない初心者がせっかくなのでOrmパッケージを使用してCRUDしてみるセクション。
Relating Modelsって?状態からスタート。対象はMySQLです。

usersprofilesというテーブルを使って実演してみます。

ads


ふたつのテーブルは
親 : users -> Has One
子 : profiles -> Belongs To
という関係です。

↓準備は以下。

CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`password` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
 
CREATE TABLE IF NOT EXISTS `profiles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`nickname` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

/fuel/app/classes/model/user.php

<?php
namespace Model;
 
class User extends \Orm\Model
{
    protected static $_has_one = array(
        'profile' => array(
            'key_from' => 'id',
            'model_to' => 'Model\Profile',
            'key_to' => 'user_id',
            'cascade_save' => true,
            'cascade_delete' => true,
        ),
    );
 
    protected static $_observers = array(
        'Orm\\Observer_CreatedAt' => array(
            'events' => array('before_insert'),
            'mysql_timestamp' => true,
            'property' => 'created_at',
        ),
        'Orm\\Observer_UpdatedAt' => array(
            'events' => array('before_save'),
            'mysql_timestamp' => true,
            'property' => 'updated_at',
        ),
    );
 
    protected static $_properties = array(
        'id',
        'password',
        'created_at',
        'updated_at',
    );
}
/* End of user.php */

/fuel/app/classes/model/profile.php

<?php
namespace Model;
 
class Profile extends \Orm\Model
{
    protected static $_belongs_to = array(
        'user' => array(
        'key_from' => 'user_id',
        'model_to' => 'Model\User',
        'key_to' => 'id',
        'cascade_save' => false,
        'cascade_delete' => false,
        )
    );
 
    protected static $_observers = array(
        'Orm\\Observer_CreatedAt' => array(
            'events' => array('before_insert'),
            'mysql_timestamp' => true,
            'property' => 'created_at',
        ),
        'Orm\\Observer_UpdatedAt' => array(
            'events' => array('before_save'),
            'mysql_timestamp' => true,
            'property' => 'updated_at',
        ),
    );
 
    protected static $_properties = array(
        'id',
        'user_id',
        'nickname',
        'created_at',
        'updated_at',
    );
}
/* End of profile.php */

 

CREATE

まずは挿入。users,profilesテーブル共にレコードを挿入します。

$user = new Model\User();
// $_has_oneで設定した値(この場合は profile)の配列キーにDBカラム名をセットします
$user->profile = new Model\Profile();
$user->password = 'password';
$user->profile->nickname = 'Gibson';
$user->save();

実行されるSQLは

INSERT INTO `users` (`password`, `created_at`, `updated_at`) VALUES ('password', '2012-06-11 20:03:05', '2012-06-11 20:03:05');
INSERT INTO `profiles` (`user_id`, `nickname`, `created_at`, `updated_at`) VALUES (1, 'Gibson', '2012-06-11 20:03:05', '2012-06-11 20:03:05');

の2件。

Belongs Toで設定した値名を間違えると、以下のエラーメッセージが出ます。
例: $user->profil = new Model\Profile(); と記述した場合。

OutOfBoundsException [ Error ]: Property "profil" not found for Model\User.

 

UPDATE

usres.id = 1の各レコードを更新します。

$user = Model\User::find(1);
$user->password = 'パスワード';
// $_has_oneで設定した値( この場合は profile)の配列キーにDBカラム名をセットします
$user->profile->nickname = "Epiphone";
$user->save();

実行されるSQLは以下。

SELECT `t0`.`id` AS `t0_c0`, `t0`.`password` AS `t0_c1`, `t0`.`created_at` AS `t0_c2`, `t0`.`updated_at` AS `t0_c3` FROM `users` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1;
SELECT `t0`.`id` AS `t0_c0`, `t0`.`user_id` AS `t0_c1`, `t0`.`nickname` AS `t0_c2`, `t0`.`created_at` AS `t0_c3`, `t0`.`updated_at` AS `t0_c4` FROM `profiles` AS `t0` WHERE `t0`.`user_id` = '1' LIMIT 1;
UPDATE `users` SET `password` = 'パスワード', `created_at` = '2012-06-11 20:03:05', `updated_at` = '2012-06-11 20:05:47' WHERE `id` = '1' LIMIT 1;
UPDATE `profiles` SET `user_id` = '1', `nickname` = 'Epiphone', `created_at` = '2012-06-11 20:03:05', `updated_at` = '2012-06-11 20:05:47' WHERE `id` = '1' LIMIT 1;

 

READ

次に検索結果をリレーショナルなオブジェクトにしてみます。

検索対象はusers.id = 1のレコードデータです。

$user = Model\User::find(1);

実行されるSQLは

SELECT `t0`.`id` AS `t0_c0`, `t0`.`password` AS `t0_c1`, `t0`.`created_at` AS `t0_c2`, `t0`.`updated_at` AS `t0_c3` FROM `users` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1;

usersテーブルのレコードのみ抽出します。

両テーブルのレコードを抽出する場合は

$user = Model\User::find(1);
$user->profile = Model\Profile::find(1);

実行されるSQLは

SELECT `t0`.`id` AS `t0_c0`, `t0`.`password` AS `t0_c1`, `t0`.`created_at` AS `t0_c2`, `t0`.`updated_at` AS `t0_c3` FROM `users` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1;
SELECT `t0`.`id` AS `t0_c0`, `t0`.`user_id` AS `t0_c1`, `t0`.`nickname` AS `t0_c2`, `t0`.`created_at` AS `t0_c3`, `t0`.`updated_at` AS `t0_c4` FROM `profiles` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1;

となります。

なお、更新直後にSELECTした場合(LAST_INSERT_IDを使用する場合?)は
Model\Userfindを行ってもSQLは実行されませんでした。

$user = Model\User::find(1);
$user->password = 'PassWord';
// $_has_one で設定した値の配列キーに DB カラム名をセットします
$user->profile->nickname = "Fender";
$user->save();
 
$user = Model\User::find($user->id);

実行されるSQLは

SELECT `t0`.`id` AS `t0_c0`, `t0`.`password` AS `t0_c1`, `t0`.`created_at` AS `t0_c2`, `t0`.`updated_at` AS `t0_c3` FROM `users` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1;
SELECT `t0`.`id` AS `t0_c0`, `t0`.`user_id` AS `t0_c1`, `t0`.`nickname` AS `t0_c2`, `t0`.`created_at` AS `t0_c3`, `t0`.`updated_at` AS `t0_c4` FROM `profiles` AS `t0` WHERE `t0`.`user_id` = '1' LIMIT 1;
UPDATE `users` SET `password` = 'PassWord', `created_at` = '2012-06-11 20:03:05', `updated_at` = '2012-06-11 20:09:54' WHERE `id` = '1' LIMIT 1;
UPDATE `profiles` SET `user_id` = '1', `nickname` = 'Fender', `created_at` = '2012-06-11 20:03:05', `updated_at` = '2012-06-11 20:09:54' WHERE `id` = '1' LIMIT 1;

となります。

※この場合、変数$user->idLAST_INSERT_IDとなります。詳しくはコチラ

プロファイラの結果から確認したところ

  • 更新があった場合は [save()前に実行している]SELECT + UPDATEクエリ
  • 更新がなかった場合は[save()前に実行している]SELECTクエリのみ

が実行されました。オブジェクトを格納している変数に差異がないから、という事でしょうかね。
 

DELETE

最後に削除の場合、

$user = Model\User::find(1);
$user->delete();

実行されたSQLは

SELECT `t0`.`id` AS `t0_c0`, `t0`.`password` AS `t0_c1`, `t0`.`created_at` AS `t0_c2`, `t0`.`updated_at` AS `t0_c3` FROM `users` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1;
SELECT `t0`.`id` AS `t0_c0`, `t0`.`user_id` AS `t0_c1`, `t0`.`nickname` AS `t0_c2`, `t0`.`created_at` AS `t0_c3`, `t0`.`updated_at` AS `t0_c4` FROM `profiles` AS `t0` WHERE `t0`.`user_id` = '1' LIMIT 1;
DELETE FROM `users` WHERE `id` = '1' LIMIT 1;
SELECT `t0`.`id` AS `t0_c0`, `t0`.`password` AS `t0_c1`, `t0`.`created_at` AS `t0_c2`, `t0`.`updated_at` AS `t0_c3` FROM `users` AS `t0` WHERE `t0`.`id` IS null LIMIT 1;
DELETE FROM `profiles` WHERE `id` = '1' LIMIT 1;

の5件。
途中のIS NULL の SELECTはなんだろう..未調査です。
 

備考

クエリの結果は以下の形で取得出来ます。

\Debug::dump(
    $user,
    $user->id,
    $user->password,
    $user->profile->nickname,
);

 

まとめ

それぞれのテーブルがHas One ⇔ Belongsというリレーショナルで関係なので当然ですが複数のテーブル操作に記述がひとつ、というのが慣れない感じがします。
なんだかんだでLEFT JOININSART ALLみたいなことが可能なのかな、と思ってましたが単純に複数クエリ投げてる形でした。まぁそのための relatedなんでしょうけども。

なんとなくORマッパーがつかめてきたかも。

Related Posts Plugin for WordPress, Blogger...

Leave a Reply

  • (will not be published)