Jobeetをやってみる 3日目

  1. DBのセットアップ
  2. Doctrine用のschemaの設定ファイルを作る*1
  3. schemaファイルからテーブルとデータモデルを生成

sfDoctrinePluginを利用するための設定

設定ファイルの変更

<?php
// config/ProjectConfiguration.class.php
public function setup()
{
  $this->enableAllPluginsExcept(array('sfPropelPlugin', 'sfCompat10Plugin'));
}

そして変更を反映と確認

$ symfomy cc
$ symfony plugin:public-assets

Propel用のファイルを削除

$ rm web/sfPropelPlugin
$ rm config/propel.ini
$ rm config/schema.yml

Doctrine用の設定ファイルを置く場所を作成

$ mkdir config/doctrine

テーブルschemaを定義

作るテーブルのER図を見て納得する

# config/doctrine/schema.yml
JobeetCategory:
  actAs: { Timestampable: ~ }
  columns:
    name: { type: string(255), notnull: true, unique: true }
JobeetJob:
  actAs: { Timestampable: ~ }
  columns:
    category_id:  { type: integer, notnull: true }
    type:         { type: string(255) }
    company:      { type: string(255), notnull: true }
    logo:         { type: string(255) }
    url:          { type: string(255) }
    position:     { type: string(255), notnull: true }
    location:     { type: string(255), notnull: true }
    description:  { type: string(4000), notnull: true }
    how_to_apply: { type: string(4000), notnull: true }
    token:        { type: string(255), notnull: true, unique: true }
    is_public:    { type: boolean, notnull: true, default: 1 }
    is_activated: { type: boolean, notnull: true, default: 0 }
    email:        { type: string(255), notnull: true }
    expires_at:   { type: timestamp, notnull: true }
  relations:
    JobeetCategory: { local: category_id, foreign: id, foreignAlias: JobeetJobs }
JobeetAffiliate:
  actAs: { Timestampable: ~ }
  columns:
    url:       { type: string(255), notnull: true }
    email:     { type: string(255), notnull: true, unique: true }
    token:     { type: string(255), notnull: true }
    is_active: { type: boolean, notnull: true, default: 0 }
  relations:
    JobeetCategories:
      class: JobeetCategory
      refClass: JobeetCategoryAffiliate
      local: affiliate_id
      foreign: category_id
      foreignAlias: JobeetAffiliates
JobeetCategoryAffiliate:
  columns:
    category_id:  { type: integer, primary: true  }
    affiliate_id: { type: integer, primary: true }
  relations:
    JobeetCategory:  { onDelete: CASCADE, local:  category_id, foreign: id }
    JobeetAffiliate: { onDelete: CASCADE, local: affiliate_id, foreign: id }

既にテーブルが作られている場合は、下記コマンドでschema.ymlが作成できる

$ symfony doctrine:build-schema
schema.ymlのカラムに対する設定について
  • type: カラムの型
    (boolean, integer, float, decimal, string, array, object, blob, clob, timestamp, time, data, enum*2, gzip)
  • notnull: いわゆるNOT NULL設定
  • unique: UNIQUE 指定のOn/Off

YAMLの書式について

重要なのはインデントはタブではなくスペースを使うこと

DBを作る

$ sudo /etc/init.d/mysql start
$ sudo mysqladmin -uroot -p create jobeet

接続設定ファイルを作成

初期設定で置いてあるのはPropelを利用するようになっているので、作り直す

$ rm config/databases.yml
$ symfony configure:database \
--name=doctrine \
--class=sfDoctrineDatabase \
"mysql:host=localhost;dbname=jobeet" username password

色々自動生成

データモデルを生成

$ symfony doctrine:build-model

lib/model/doctrine/ に作られる

SQLファイルを生成

$ symfony doctrine:build-sql

data/sql/ に作られる

作り終ったらcacheをclear

$ symfony cc

データモデルの使用について

ここまでやったことを一発で

色々symfonyコマンドを使って生成してきたけど、設定ファイルを作ってから

$ symfony doctrine:build-all

でDBからデータモデルからschemaからSQLファイルまで、全て生成してくれる

最終問題の1000Pで一発逆転のチャンスみたいだ

初期データの設定

開発には色んなデータが必要

  • 初期値データ
  • Test Unit用データ
  • ユーザによって作られるデータ

そんなデータを設定ファイルにて作成する

# data/fixtures/categories.yml
JobeetCategory:
  design:
    name: Design
  programming:
    name: Programming
  manager:
    name: Manager
  administrator:
    name: Administrator
# data/fixtures/jobs.yml
JobeetJob:
  job_sensio_labs:
    JobeetCategory: programming
    type:          full-time
    company:       Sensio Labs
    logo:          sensio-labs.gif
    url:           http://www.sensiolabs.com/
    position:      Web Developer
    location:      Paris, France
    description: |
      You've already developed websites with symfony and you want to work
      with Open-Source technologies. You have a minimum of 3 years
      experience in web development with PHP or Java and you wish to
      participate to development of Web 2.0 sites using the best
      frameworks available.
    how_to_apply: |
      Send your resume to fabien.potencier [at] sensio.com
    is_public:     true
    is_activated: true
    token:         job_sensio_labs
    email:         job@example.com
    expires_at:    '2010-10-10'
  job_extreme_sensio:
    JobeetCategory: design
    type:          part-time
    company:       Extreme Sensio
    logo:          extreme-sensio.gif
    url:           http://www.extreme-sensio.com/
    position:      Web Designer
    location:      Paris, France
    description: |
      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
      eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
      enim ad minim veniam, quis nostrud exercitation ullamco laboris
      nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
      in reprehenderit in.
      Voluptate velit esse cillum dolore eu fugiat nulla pariatur.
      Excepteur sint occaecat cupidatat non proident, sunt in culpa
      qui officia deserunt mollit anim id est laborum.
    how_to_apply: |
      Send your resume to fabien.potencier [at] sensio.com
    is_public:     true
    is_activated: true
    token:         job_extreme_sensio
    email:         job@example.com
    expires_at:    '2010-10-10'

データの挿入

$ symfony doctrine:data-load

ここまでの処理を一発で

$ symfony doctrine:build-all-reload
jobs.ymlに関する補足説明

YAMLでpipe(|)を使用すると、multilineな文字列が定義できる

Actionの生成

$ symfony doctrine:generate-module --with-show --non-verbose-templates frontend job JobeetJob

これで以下の構成で生成される

  • actions/ このモジュールのアクション
    • index : リスト表示
    • show : 詳細表示
    • new : 登録フォーム
    • create : 登録処理
    • edit : 編集フォーム
    • update : 編集処理
    • delete : 削除処理
  • templates/ : このモジュールのテンプレート
ちょっと変更を加える

Propelの場合はデータモデルクラスに__toString()を定義してやらないとなにかと不便になるけど、Doctrineだとnameカラムを利用しようとするようだ。
今回はcategoriesにはnameがあるので、カテゴリのセレクトボックスのところでエラーにはならない。

他のテーブルにはnameカラムはないので、__toString()を定義する

<?php
// lib/model/doctrine/JobeetJob.class.php
class JobeetJob extends BaseJobeetJob
{
  public function __toString()
  {
    return sprintf('%s at %s (%s)', $this->getPosition(),
        $this->getCompany(), $this->getLocation());
  }
}
<?php
// lib/model/doctrine/JobeetAffiliate.class.php
class JobeetAffiliate extends BaseJobeetAffiliate
{
  public function __toString()
  {
    return $this->getUrl();
  }
}

バリデーションを試す

not nullな項目に対して、空で更新しようとすると「Required.」とエラー表示が出る

これはスキーマから基本的なバリデーションを用意してくれるおかげ。


あー長かった。。。
説明文はほとんどチンプンカンプンだけど、コードと辞書でなんとなーく理解。



*1:天邪鬼だからDoctrine版でやってるよ

*2:PostgreSQLだとエラーになるんかな?