マニュアルにはこんな風に書いてあります。
スキーマの規約
id
で命名された空のカラムはプライマリキーとみなされます。id
で終わる空のカラムは外部キーとみなされ、自動的に最初の部分の名前に一致するテーブルに関連付けられます。created_at
またはupdated_at
で命名されたカラムは自動的にtimestamp
型にセットされます。すべてのこれらのカラムにとって、型を指定する必要はありません。なぜなら、symfony はそれらの名前から推測するからです。 こうすることによってschema.xml
はより簡単に記述することができるようになっています。
でも、そうはなりませんでした。困りました。そんなときが訪れた私の戦いの記録です。
まず、状況を整理します。
- DBはmysql、テーブルはDB上に作成済み
- timestamp型のデフォルト値をCURRENT_TIMESTAMPにしていた。
- ちなみに、↓に書きますように、1970-01-01以前の日付でもエラーが出ます
- schema.ymlはDBから自動生成(下記コマンド)
./symfony propel-build-schema
- propel object (またはOR mapper)はschema.ymlから自動生成(下記コマンド)
./symfony propel-build-model
◇はまりポイント1
最初、
./symfony propel-build-model
がエラーになりました。マニュアルによれば、
date
とtimestamp
タイプは Unix 日付の限定があるので、1970-01-01 より以前は指定できません。より古い日付を利用するのであれば ( 例えば誕生日など ) 、’ Unix 以前’ の日付フォーマットをbu_date
やbu_timestamp
などと一緒に使う必要があります。
つまり、デフォルト値をCURRENT_TIMESTAMPにできないということです。
そこで、下記コマンドによりデフォルト値を変更します。これでうまくいきました。
perl -i -pe 's|default: CURRENT_TIMESTAMP|default: 1970-01-01 00:00:00|g' ./config/schema.yml
◇はまりポイント2
この記事のタイトルの現象です。
具体的には、
- peopleというテーブルと、announceというテーブルがあった
- announceテーブルにはpeople_idカラムがあった
という状態です。schema.ymlの中身を抜粋します。
announce: _attributes: idMethod: native id: type: INTEGER required: true autoIncrement: true primaryKey: true people_id: type: INTEGER required: true default: 0
このとき、マニュアルの通りであれば
- ./lib/model/om/BasePeople.php には announce と1対多の関係にあることを示すプロパティやメソッドが存在する
- protected $collAnnounces;
- protected $lastAnnounceCriteria = null;
- public function initAnnounces()
- public function getAnnounces($criteria = null, $con = null)
- public function countAnnounces($criteria = null, $distinct = false, $con= null)
- public function addAnnounce(Announce $l)
- ./lib/model/om/BaseAnnounce.php には people と多対1の関係にあることを示すプロパティやメソッドが存在する
- protected $people_id;
- protected $aPeople;
- public function getPeopleId()
- public function setPeople($v)
- public function getPeople($con = null)
でも、ありませんでした。だまされてるのか、と思いましたが、調べてみるとうまくいくようですし、同じschema.ymlファイルを作成して、うまくいくことを確かめました。
試しに、schema.ymlファイルを編集して、明示的にforeign keyの設定を入れています。最後の3行です。
announce: _attributes: idMethod: native id: type: INTEGER required: true autoIncrement: true primaryKey: true people_id: type: INTEGER required: true default: 0 foreignTable: people foreignReference: id onDelete: cascade
これで ./symfony propel-build-model するとうまく上にあげたプロパティやメソッドが生成されます。
ここで試行錯誤を行いました。結論からいくと、
announce: _attributes: idMethod: native id: type: INTEGER required: true autoIncrement: true primaryKey: true people_id:
とすることで、うまくいきます。つまり、自動でforegin key扱いしてほしいフィールド、ここではpeople_idの定義(type、required、defaultなどすべて)を空にすればいいのです。
参考にできる置換スクリプトです。-i オプションを外すとどのような出力が出るのか確認できます。
perl -i -0 -pe 's|_id:\\s*type: INTEGER\\s*required: true\\s*default: 0|_id:|sg' ./config/schema.yml
mysql、symfony、propelの組み合わせ、かつ、データベースからスキーマやORマッパーオブジェクトを自動生成するときは、schema.yml の forein key の定義は空にしておきましょう!