技術めも

PHP シンプルORM Active Record

オフィシャルサイト

http://www.phpactiverecord.org/

シンプルORM。PHP5.3以上

composer require php-activerecord/php-activerecord

初期設定

イニシャライズ

require_once 'php-activerecord/ActiveRecord.php';

ActiveRecord\Config::initialize(function($cfg)
{
    $cfg->set_model_directory(dirname(__FILE__).'/classes/models');            // ← modelの置き場所
    $cfg->set_connections(array(
        'development' => 'mysql://username:password@localhost/database_name',  // ← DB接続情報
    ));
});

モデル

set_model_directory() で指定したディレクトリにモデルclassを配置

メソッドでビジネスロジックを記載

class User extends ActiveRecord\Model
{
    static $table_name = 'users';       // ← テーブル名(デフォルト:小文字クラス名+s)
    static $primary_key = 'id';         // ← プライマリーカラム(デフォルト:id)
    static $connection = 'production';  // ← コネクション名(デフォルト:development)
    static $db = 'mydb';                // ← DB名(コネクション設定で指定されていたら不要)
}

テーブル名は複数形(books)推奨

クラスの名前はテーブル名の単数形(Book)。

class Book extends ActiveRecord\Model {}

特別なパターンもある(テーブル名が "people")

class Person extends ActiveRecord\Model {}

SELECT

http://www.phpactiverecord.org/projects/main/wiki/Finders

find

Book::find(2);   // プライマリーキーでの指定

プライマリーキーを複数記載可能

Book::find(2,3);

下記でも同じ動作になる

Book::find(array(2,3));

引数に first, last, all を指定可能

Book::find('first');
Book::find('last');
Book::find('all');

下記でも同じ動作になる

Book::first();
Book::last();
Book::all();

SQL記載

$book = Book::find_by_sql('select title from `books`');   // SQLを記載

条件 WHERE

第2引数に 条件Array を 'conditions' で設定する

キー'conditions'の値は、配列で複数指定する

「?」が置き換えられる(sprintf記法)

$options = array('conditions' => array('price < ?', 15.00));
Book::find('all', $options);

下記でも同じ動作になる

$options = array('conditions' => array('price < ?', 15.00));
Book::all($options);

複数の?の場合(sprintf記法)

$options = array('conditions' => array('genre = ? AND price < ?', 'Romance', 15.00));
Book::find('all', $options);

IN 条件の場合は、?に入る値を配列で指定

$options = array('conditions' => array('author_id in (?)', array(1,2,3)));
Book::find('all', $options);

条件 LIMIT, OFFSET, ORDER

第2引数に 条件Array を 'limit','offset','order' で設定する

$options = array('limit' => 2);
Book::find('all', $options);

下記でも同じ動作になる

$options = array('limit' => 2);
Book::all($options);

LIMIT, OFFSET 指定する場合

Book::find('all', array('limit' => 10, 'offset' => 5));

ORDER BY を指定する場合

Book::find('all', array('order' => 'title desc'));
Book::find('all', array('order' => 'price desc, title asc'));

取得するカラムを指定

取得するカラムを 'select' で指定する

id, title だけを取得( SELECT id, title FROM books )

Book::find('all', array('select' => 'id, title'));

取得した情報を as で別カラム名に変更

Book::find('all', array('select' => 'avg(price) as avg_price, avg(tax) as avg_tax'));

JOIN

条件Arrayで 'joins' を指定

$joinOption = 'LEFT JOIN authors a ON(books.author_id = a.author_id)';
$book = Book::find('all', array('joins' => $joinOption));

→ SELECT books.* FROM books LEFT JOIN authors a ON(books.author_id = a.author_id)

GROUP, HAVING

条件Arrayで 'group' を指定

Book::find('all', array('group' => 'price'));

条件Arrayで 'having' を指定

Book::find('all', array('group' => 'price', 'having' => 'price > 45.00'));

ダイナミック Finder

findby[カラム名] メソッド で条件にあったデータを取得

$book = Book::find_by_title('War and Peace');

__find_allby[カラム名] メソッド__ で条件にあった複数のデータを取得

$books = Book::find_all_by_discounted(1);

__find_allby[カラム名]and[カラム名]__ で複数の条件にあった複数のデータを取得

1つのデータを取得する場合は、findby[カラム名]and[カラム名]

$books = Book::find_all_by_discounted_and_author_id(1, 5);

 → SELECT * FROM books WHERE discounted = 1 AND author_id = 5

__find_allby[カラム名]or[カラム名]__ で複数の条件のどれかにあった複数のデータを取得

1つのデータを取得する場合は、findby[カラム名]or[カラム名]

$books = Book::find_by_discounted_or_price(1, 5.00);

 → SELECT * FROM books WHERE discounted = 1 OR price = 5.00

CREATE

http://www.phpactiverecord.org/projects/main/wiki/Basic_CRUD

new でオブジェクトを作成。情報を入れて save()

$post = new Post();
$post->title = 'My first blog post!!';
$post->author_id = 5;
$post->save();

オブジェクトを作成するときに、情報を入力することも可能

$attributes = array('title' => 'My first blog post!!', 'author_id' => 5);
$post = new Post($attributes);
$post->save();

createメソッドを使用するとダイレクトに作成(saveメソッド不要)

$attributes = array('title' => 'My first blog post!!', 'author_id' => 5);
$post = Post::create($attributes);

UPDATE

オブジェクトを取得して、情報を書き込んで save()

$post = Post::find(1);
echo $post->title;
$post->title = 'Some real title';
$post->save();

UPDATE or INSERT

もしオブジェクトがあれば UPDATE、なければ INSERT を行いたいときは、empty で評価

$post = Post::find_by_title('Some real title');
 if (empty($post)) {
    $post = new Post();
    $post->title = 'Some real title';
}
$post->author = 'Dr.Anyone';
$post->price = 18;
$post->save();

複数一斉UPDATE

デーブルのオブジェクトを取得、UPDATE内容と条件を引数で指定

Model::table()->update(AttributesToUpdate, WhereToUpdate);

$updateValues = array('title' => 'Massive title!');
$whereOptions  array('id' => array(1, 3, 7));
Post::table()->update($updateValues, $whereOptions);

【注意】ダイレクトに引数に並列を指定すると、動かない(php5.3)

https://github.com/kla/php-activerecord/issues/151

DELETE

オブジェクトを取得して deleteメソッド実行

$post = Post::find(1);
$post->delete();

複数一斉DELETE

デーブルのオブジェクトを取得、DELETE条件を引数で指定

Model::table()->delete(WhereToDelete);

$whereOptions = array('id' => array(5, 9, 26, 30));
Post::table()->delete($whereOptions);

第1引数に「条件文字列」を記載したら動いた(個人的メモ)

Post::table()->delete('DATE_ADD(created_at,INTERVAL 1 HOUR) < NOW()');

【注意】ダイレクトに引数に並列を指定すると、動かない(php5.3)

https://github.com/kla/php-activerecord/issues/151

特記事項

複数一斉DELETE で Warning

第1引数に「条件文字列」を記載して一斉削除する場合、Warning が表示される

Post::table()->delete('DATE_ADD(created_at,INTERVAL 1 HOUR) < NOW()');
Warning: Invalid argument supplied for foreach() in /home/lib/activerecord/lib/Table.php on line 387

理由は引数の文字列を foreach 処理を行なっているから。

だがその後の処理で文字列だった場合、SQLをダイレクト実行しているので記載的には問題ない。

コードを変更して対応する場合は、下記の1行を Table.php のメソッドに追加。

private function &process_data($hash)
{
    if (!$hash)
       return $hash;
       
   if (is_string($hash)) return $hash; // ★ 2013.06.09 add tatenosystem
   
   foreach ($hash as $name => &$value)
   {
       if ($value instanceof \DateTime)
       {
           if (isset($this->columns[$name]) && $this->columns[$name]->type == Column::DATE)
               $hash[$name] = $this->conn->date_to_string($value);
           else
               $hash[$name] = $this->conn->datetime_to_string($value);
       }
       else
           $hash[$name] = $value;
   }
   return $hash;
}