ID列名がidではないテーブルをgasormで使えるようにしてみる

[gasorm](http://gasorm-doc.taufanaditya.com/)はcodeigniter用のORMですが、
今回少し使ってみたので、単純に既存のテーブル構造から、シンプルにデータを抜いてくるところまでを作ってみました。

既存のテーブルを題材にしたので、idとか user_idのように綺麗にORMに適用できなかったので、少し手こずりました。


- お客様モデル

```php:customer.php
<?php namespace Model;
use \Gas\Core;
use \Gas\ORM;

if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Customer extends ORM{

    public function _init()
    {
        /**
         * プライマリキー 単に "id"の場合は省略できます。
         */
        $this->primary_key = "CUSTOMER_NO";
        /**
         * リレーション
         * ねぎテーブル側にCUSTOMER_NOがあり、belongs_toでCustomerに属するようにする。
         * ねぎは一つしか持てません。
         */
        self::$relationships = array (
            'green_onion' => ORM::has_one('\\Model\\Green_onion')
        );

        /**
         * フィルード定義とバリデーションルール
         */
        self::$fields = array(
            'CUSTOMER_NO' => ORM::field('int[8]'),
            'NAME' =>  ORM::field('char[128]'),
            "CREATE_AT" => ORM::field("datetime"),
            "UPDATE_AT" => ORM::field("datetime"),
        );

    }
}
```

- ねぎモデル

```php:green_onion.php
<?php namespace Model;
use \Gas\Core;
use \Gas\ORM;

if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Green_onion extends ORM{


    /**
     * プライマリキー 単に "id"の場合は省略できます。
     */
    public $primary_key="GREEN_ONION_NO";
    /**
     * 外部キー 参照先テーブル名_id の場合は省略できます
     * このモデルのテーブルに持っている、お客様を示す外部キーを指定する。
     */
    public $foreign_key = array('\\Model\\Customer' => 'CUSTOMER_NO');

    public function _init()
    {

       /**
         * リレーション
         */
        self::$relationships = array (
            'customer'          =>     ORM::belongs_to('\\Model\\Customer')
        );

        /**
         * フィルード定義とバリデーションルール
         * 定義しておかないと値が取れません。
         */
        self::$fields= array(
            "GREEN_ONION_NO" => ORM::field("int[8]"),
            "CUSTOMER_NO" => ORM::field("char[8]"),
            "CREATE_AT" => ORM::field("datetime"),
            "UPDATE_AT" => ORM::field("datetime"),
        );

    }
}
```

- ねぎコントローラ

```php:green_onions.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Green_onions extends CI_Controller
{

    public function __construct()
    {
        parent::__construct();
    }

    public function show_list() {

        $green_onion = new Model\Green_onion();
        $onions = $green_onion->all();
        $data["onions"]=$onions;

        $this->load->view("green_onions_list",$data);
    }

}
```

- ねぎ一覧ビュー

```php:green_onions_list.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');?>
<h1>ねぎ一覧</h1>

<table class="data_tables">
    <thead>
        <tr>
            <th>ねぎ番号</th>
            <th>ねぎを持っているお客様</th>
        </tr>
    </thead>

    <tbody>
        <?php foreach ($onions as $onion) { ?>
        <tr>
            <td><?php echo $onion->GREEN_ONION_NO ?></td>
            <td><?php echo $onion->green_onion()->NAME ?></td>
        <?php } ?>
    </tbody>
</table>

```

使い方的にはこれでいけるはずなのですが...

しかしこれだと取ってこれませんでした。
あまり日本語の情報がないので、結局gasormのコードを読んだのですが。
orm.phpのコンストラクタで、プライマリキーが設定されていると外部キーを設定しない条件があり、そこを修正せざるをえませんでした。

正しい修正の方法なのか、いまいちよくわかりません。
間違っていたら教えてください。

```php:third_party/gas/classes/orm.php


        // We really deal with composite keys here
        //@remark プライマリキーの条件を削除、設定されていようがいまいが、外部キーを処理する
        /*
        if (empty($this->primary_key))
		{
        */
			if ( ! empty($this->foreign_key))
			{
				// Validate foreign keys for consistency naming convention recognizer
				$foreign_key = array();

				foreach($this->foreign_key as $namespace => $fk)
				{
					$foreign_key[strtolower($namespace)] = $fk;
				}

				$this->foreign_key = $foreign_key;
			}
			else
			{
				// If so far we didnt have any keys yet, 
				// then hopefully someone is really follow Gas convention
				// while he define his entity relationship (yes, YOU!)
				foreach ($this->meta->get('entities') as $name => $entity)
				{
					if ($entity['type'] == 'belongs_to')
					{
						$child_name     = $entity['child'];
						$child_instance = new $child_name;
						$child_table    = $child_instance->table;
						$child_key      = $child_instance->primary_key;

						$this->foreign_key[strtolower($child_name)] = $child_table.'_'.$child_key;
					}
				}
			}
		//}


```

gasormは気になるコメントがコード内のそこここに書かれています。
大丈夫なのでしょうか。


補足で、二つほど単純なhackを書いておきます。

- テーブル名を大文字にしたい場合のhack

```php:third_party/gas/classes/orm.php
	final public function validate_table()
	{
		// If there is no table name set, use model name based by namespace path
		if (empty($this->table))
		{
			// Parse namespace into table spec
			if (array_key_exists($this->namespace, Core::$path['model']))
			{
				// Namespace already in the correct position
				$namespace = strtolower($this->namespace);
			}
			else
			{
				// Get the namespace from parent
				foreach (Core::$path['model'] as $parent => $path)
				{
					if (strpos($this->namespace, $parent) !== FALSE)
					{
						$namespace = strtolower($parent);
						break;
					}
				}
			}

			// Define table, path and set the table properties
			$table       = str_replace($namespace.'\\', '', $this->model());
            //@remark テーブル名を大文字に変更
            /*
			$path        = strtolower(str_replace('\\', '_', $table));
			$this->table = strtolower($path);
            */
            $path        = strtoupper(str_replace('\\', '_', $table));
            $this->table = strtoupper($path);
		}
		
		return $this;
	}

```


- IDの値に数値ではなく文字列を使いたい場合のhack

```php:third_party/gas/classes/core.php

	public static function generate_clause($domain, $key, $identifier, $ids = '')
	{
       //...(中略)                 

		// Do we need to replace the string identifier
		// Either into sub-query or the real COLUMN value(s) ?
　　　　　      // @remark ↑うん、やってよ！ と思いました。
		if ( ! empty($ids))
		{
		    //@remark idsが通常だとクオート処理されないので、文字列ならクオート処理する。
		    if (is_string($ids)) {
		       $ids="'".$ids."'";
           　}
			$pattern = sprintf($pattern, $ids);
		}

		// Statement is ready
		return $pattern;
    }
```