FuelPHPのORMが使いづらいから少しだけ便利にするtrait

# 前提

- Rails(ActiveRecord)に慣れている
- なんらかの深遠なる理由でFuelPHPを使う事になった

という感じの人間にとっては頭の整理＆少し便利になると思われるtips。

# FuelPHPのORM

ActiveRecordと比較して書いてみる

## User.where(name: 'hoge').first

```php
User::find('first', ['where' => [['name', 'hoge']]]);
```

## User.where(enabled: true).all

```php
User::find('all', ['where' => [['enabled', 1]]]);
```

※ 正確には `User.where(enabled: true).all.index_by(&:id)` で得られるハッシュのような形になっている

## User.where(enabled: true).limit(10).offset(30).all

```php
User::find('all', ['where' => [['enabled', 1]], 'limit' => 10, 'offset' => 30]);
```

# 使いづらいと思った点

- `find`のオプションとして渡す配列が読みにくい
- ORMのキャッシュが悪さする事が多くデフォルトで使いたくない
	- http://tech.respect-pal.jp/fuelphp-orm-cache/

と言うわけで、ここを改善するメソッドを生やす。

```php
<?php

trait OrmFindMethods
{
    public static function find_by($conditions)
    {
        $options = static::build_options($conditions);
        return static::find('first', $options);
    }

    public static function find_all($conditions = [], $limit = null, $offset = null)
    {
        $options = static::build_options($conditions, $limit, $offset);
        return static::find('all', $options);
    }

    protected static function build_options($conditions, $limit = null, $offset = null)
    {
        $where = [];
        foreach ($conditions as $key => $value) {
            if (is_array($value)) {
                $where[] = [$key, 'IN', $value];
            } else {
                $where[] = [$key, $value];
            }
        }

        $options = [
            'where' => $where,
            'from_cache' => false,
        ];

        if (isset($limit) && is_numeric($limit) && $limit > 0) {
            $options['limit'] = (int)$limit;
        }

        if (isset($offset) && is_numeric($offset) && $offset >= 0) {
            $options['offset'] = (int)$offset;
        }

        return $options;
    }
}

```

というtraitを用意して

```php
<?php

class User extends \Orm\Model {
  use OrmFindMethods;
  
  …
}
```

とかやってやる。

このtraitを使うと

```php
User::find_by(['name' => 'hoge']);
```

```php
User::find_all(['enabled' => 1])
```

```php
User::find_all(['enabled' => 1], 10, 30);
```

という感じになる。

ついでに、Railsだと

```ruby
User.where(id: [1, 2, 3]).all
```

と書いていた奴は

```php
User::find_all('id' => [1, 2, 3])
```

と書けるようになる。

# おまけ

```php
trait OrmFindMethods
{
	…
	
    public static function find_or_initialize_by($conditions)
    {
        $obj = static::find_by($conditions);
        if (!static::is_present($obj)) {
            return $obj;
        }

        $obj = new static();

        foreach ($conditions as $key => $value) {
            $obj->$key = $value;
        }

        return $obj;
    }

    public static function find_or_create_by($conditions, \Closure $block = null)
    {
        $obj = static::find_by($conditions);
        if (!static::is_present($obj)) {
            return $obj;
        }

        $obj = new static();

        foreach ($conditions as $key => $value) {
            $obj->$key = $value;
        }

        if (isset($block)) {
            $obj->tap($block);
        }

        $obj->save();

        return $obj;
    }
    
    public static function is_present($obj)
    {
    	return isset($obj) && !empty($obj);
    }
    
    public function tap(\Closure $block)
    {
        $block($this);
        return $this;
    }
    
    …
}
```

までお膳立てするとさらに便利。