Symfony で ./symfony propel-build-model しても foreign key を自動対応してくれない、そんなとき

マニュアルにはこんな風に書いてあります。

スキーマの規約

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

がエラーになりました。マニュアルによれば、

datetimestamp タイプは Unix 日付の限定があるので、1970-01-01 より以前は指定できません。より古い日付を利用するのであれば ( 例えば誕生日など ) 、’ Unix 以前’ の日付フォーマットを bu_datebu_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 の定義は空にしておきましょう!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>