http://www.symfony-project.org/jobeet/1_2/Propel/ja/03
この節では、symfonyのデフォルトのORMであるPropelにおける内容を記載しております。
第3日目のチュートリアルが完了するまでの目安
3時間~10時間
DB周りの設定やデータモデルの検討をします。
第3日目は、第1日目と同様に結構重めのタスクになります。
さらっと流すと3時間、じっくり試すと10時間かかると思われます。
エンティティ関係図(Entiry-Relation図)を作成します。
ER図を描くツールは、いくつかありますが、MySQLをRDBMSに選択した場合、[MySQL Workbench]を選択すべきでしょう。
MySQL Workbenchを使用したいがために、MySQLを選択するというのも有りだと思います。
MySQL Workbenchのインストール方法は、以下の記事を参照してください。
論理DBのER図を描くためには、日本語が表示できなければなりません。
このため、[Tools]-[Options...]を選択します。
フォントタブを選択し、フォントフェイスを[メイリオ]のような日本語フォントを選択します。
特に[メイリオ]で無くとも構わず、[MS ゴシック]でも構いません。日本語が表示できるフォントであることが必要になります。
ちなみに全部、修正する必要があります。
MySQL Workbenchを使用して論理DBを描いてみました。

作成した論理モデルです。
これにより、論理DBでお話ができるようになります。
MySQL Workbenchを使用して、物理DBを描いてみました。

作成した物理モデルです。
これにより、このようにDDLスクリプトが作成できます。
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
CREATE SCHEMA IF NOT EXISTS `jobeet` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `jobeet`;
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_category`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_category` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'ID' ,
`name` VARCHAR(255) NOT NULL COMMENT 'カテゴリ名' ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `uk_name` USING BTREE (`name` ASC) )
ENGINE = InnoDB
COMMENT = 'カテゴリ';
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_job`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_job` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'ID' ,
`category_id` INT NOT NULL COMMENT 'カテゴリID' ,
`type` VARCHAR(255) NULL COMMENT '契約条件' ,
`company` VARCHAR(255) NOT NULL COMMENT '企業名' ,
`logo` BLOB NULL COMMENT 'ロゴ' ,
`url` VARCHAR(255) NULL COMMENT 'URL' ,
`position` VARCHAR(255) NOT NULL COMMENT '業務' ,
`location` VARCHAR(255) NOT NULL COMMENT '就業場所' ,
`description` LONGTEXT NOT NULL COMMENT '仕事の説明' ,
`how_to_apply` LONGTEXT NOT NULL COMMENT '応募方法' ,
`token` VARCHAR(255) NOT NULL COMMENT 'トークンキー' ,
`is_public` BOOLEAN NOT NULL DEFAULT TRUE COMMENT '公開' ,
`is_activated` BOOLEAN NOT NULL DEFAULT FALSE COMMENT '有効' ,
`email` VARCHAR(255) NOT NULL COMMENT 'E-Mail' ,
`expires_at` TIMESTAMP NOT NULL COMMENT '有効期限' ,
`created_at` TIMESTAMP NOT NULL COMMENT '作成日時' ,
`updated_at` TIMESTAMP NOT NULL COMMENT '更新日時' ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `uk_token` USING BTREE (`token` ASC) ,
INDEX `fk_category` (`category_id` ASC) ,
CONSTRAINT `fk_category`
FOREIGN KEY (`category_id` )
REFERENCES `jobeet`.`jobeet_category` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
COMMENT = '求人';
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_affiliate`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_affiliate` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'ID' ,
`url` VARCHAR(255) NOT NULL COMMENT 'URL' ,
`email` VARCHAR(255) NOT NULL COMMENT 'E-Mail' ,
`token` VARCHAR(255) NOT NULL COMMENT 'トークンキー' ,
`is_active` BOOLEAN NOT NULL DEFAULT FALSE COMMENT '有効' ,
`created_at` TIMESTAMP NOT NULL COMMENT '作成日時' ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `uk_affiliate` USING BTREE (`email` ASC) )
ENGINE = InnoDB
COMMENT = 'アフィリエイト';
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_category_affiliate`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_category_affiliate` (
`category_id` INT NOT NULL COMMENT 'カテゴリID' ,
`affiliate_id` INT NOT NULL COMMENT 'アフィリエイトID' ,
PRIMARY KEY (`category_id`, `affiliate_id`) ,
INDEX `fk_category` (`category_id` ASC) ,
INDEX `fk_affiliate` (`affiliate_id` ASC) ,
CONSTRAINT `fk_category`
FOREIGN KEY (`category_id` )
REFERENCES `jobeet`.`jobeet_category` (`id` )
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_affiliate`
FOREIGN KEY (`affiliate_id` )
REFERENCES `jobeet`.`jobeet_affiliate` (`id` )
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB
COMMENT = 'カテゴリ-アフィリエイト';
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
かなり道を外れてしまったので、もとに戻ります。
チュートリアルでは、データベースモデルをYAML形式で作成した後、PHPモデル、DBのDDLを作るという順序で
DB周りの設定をしようとしています。
チュートリアルのschema.ymlは、以下のようになっています。
# config/schema.yml
propel:
jobeet_category:
id: ~
name: { type: varchar(255), required: true, index: unique }
jobeet_job:
id: ~
category_id: { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true }
type: { type: varchar(255) }
company: { type: varchar(255), required: true }
logo: { type: varchar(255) }
url: { type: varchar(255) }
position: { type: varchar(255), required: true }
location: { type: varchar(255), required: true }
description: { type: longvarchar, required: true }
how_to_apply: { type: longvarchar, required: true }
token: { type: varchar(255), required: true, index: unique }
is_public: { type: boolean, required: true, default: 1 }
is_activated: { type: boolean, required: true, default: 0 }
email: { type: varchar(255), required: true }
expires_at: { type: timestamp, required: true }
created_at: ~
updated_at: ~
jobeet_affiliate:
id: ~
url: { type: varchar(255), required: true }
email: { type: varchar(255), required: true, index: unique }
token: { type: varchar(255), required: true }
is_active: { type: boolean, required: true, default: 0 }
created_at: ~
jobeet_category_affiliate:
category_id: { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true, primaryKey: true, onDelete: cascade }
affiliate_id: { type: integer, foreignTable: jobeet_affiliate, foreignReference: id, required: true, primaryKey: true, onDelete: cascade }
schema.yml から DDLスクリプトを作成するタスクを実行するには、以下のようなコマンドを打ちます。
symfony propel:build-sql
出来上がったDDLスクリプトは、以下のファイルになります。
# This is a fix for InnoDB in MySQL >= 4.1.x # It "suspends judgement" for fkey relationships until are tables are set. SET FOREIGN_KEY_CHECKS = 0; #----------------------------------------------------------------------------- #-- jobeet_category #----------------------------------------------------------------------------- DROP TABLE IF EXISTS `jobeet_category`; CREATE TABLE `jobeet_category` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `jobeet_category_U_1` (`name`) )Type=InnoDB; #----------------------------------------------------------------------------- #-- jobeet_job #----------------------------------------------------------------------------- DROP TABLE IF EXISTS `jobeet_job`; CREATE TABLE `jobeet_job` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `category_id` INTEGER NOT NULL, `type` VARCHAR(255), `company` VARCHAR(255) NOT NULL, `logo` VARCHAR(255), `url` VARCHAR(255), `position` VARCHAR(255) NOT NULL, `location` VARCHAR(255) NOT NULL, `description` TEXT NOT NULL, `how_to_apply` TEXT NOT NULL, `token` VARCHAR(255) NOT NULL, `is_public` TINYINT default 1 NOT NULL, `is_activated` TINYINT default 0 NOT NULL, `email` VARCHAR(255) NOT NULL, `expires_at` DATETIME NOT NULL, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`), UNIQUE KEY `jobeet_job_U_1` (`token`), INDEX `jobeet_job_FI_1` (`category_id`), CONSTRAINT `jobeet_job_FK_1` FOREIGN KEY (`category_id`) REFERENCES `jobeet_category` (`id`) )Type=InnoDB; #----------------------------------------------------------------------------- #-- jobeet_affiliate #----------------------------------------------------------------------------- DROP TABLE IF EXISTS `jobeet_affiliate`; CREATE TABLE `jobeet_affiliate` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `url` VARCHAR(255) NOT NULL, `email` VARCHAR(255) NOT NULL, `token` VARCHAR(255) NOT NULL, `is_active` TINYINT default 0 NOT NULL, `created_at` DATETIME, PRIMARY KEY (`id`), UNIQUE KEY `jobeet_affiliate_U_1` (`email`) )Type=InnoDB; #----------------------------------------------------------------------------- #-- jobeet_category_affiliate #----------------------------------------------------------------------------- DROP TABLE IF EXISTS `jobeet_category_affiliate`; CREATE TABLE `jobeet_category_affiliate` ( `category_id` INTEGER NOT NULL, `affiliate_id` INTEGER NOT NULL, PRIMARY KEY (`category_id`,`affiliate_id`), CONSTRAINT `jobeet_category_affiliate_FK_1` FOREIGN KEY (`category_id`) REFERENCES `jobeet_category` (`id`) ON DELETE CASCADE, INDEX `jobeet_category_affiliate_FI_2` (`affiliate_id`), CONSTRAINT `jobeet_category_affiliate_FK_2` FOREIGN KEY (`affiliate_id`) REFERENCES `jobeet_affiliate` (`id`) ON DELETE CASCADE )Type=InnoDB; # This restores the fkey checks, after having unset them earlier SET FOREIGN_KEY_CHECKS = 1;
MySQL Workbenchで作成した[jobeet.sql]と[lib.model.schema.sql]を比較して判ったこと
propel:insert-sql タスクを実行すると、[lib.model.schema.sql]で定義されたDDLでスキーマーが上書き、保存されてしまいます。
もちろん、スキーマの情報が消えるという警告は出ます。
とはいえ、propel:insert-sqlは実行する可能性が高く、[lib.model.schema.sql]と[jobeet.sql]が不一致である点はいただけません。
このため、RAD開発を維持するため、外部定義のDDLは、symfonyが想定するDDL定義を同一にする必要があります。
ということで、物理モデルを修正してみました。

作成した物理モデルです。
新しいDDLスクリプトです。
これにより、ほとんど一緒になります。
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
CREATE SCHEMA IF NOT EXISTS `jobeet` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `jobeet`;
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_category`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_category` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'ID' ,
`name` VARCHAR(255) NOT NULL COMMENT 'カテゴリ名' ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `uk_name` USING BTREE (`name` ASC) )
ENGINE = InnoDB
COMMENT = 'カテゴリ';
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_job`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_job` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'ID' ,
`category_id` INT NOT NULL COMMENT 'カテゴリID' ,
`type` VARCHAR(255) NULL COMMENT '契約条件' ,
`company` VARCHAR(255) NOT NULL COMMENT '企業名' ,
`logo` BLOB NULL COMMENT 'ロゴ' ,
`url` VARCHAR(255) NULL COMMENT 'URL' ,
`position` VARCHAR(255) NOT NULL COMMENT '業務' ,
`location` VARCHAR(255) NOT NULL COMMENT '就業場所' ,
`description` TEXT NOT NULL COMMENT '仕事の説明' ,
`how_to_apply` TEXT NOT NULL COMMENT '応募方法' ,
`token` VARCHAR(255) NOT NULL COMMENT 'トークンキー' ,
`is_public` TINYINT NOT NULL DEFAULT 1 COMMENT '公開' ,
`is_activated` TINYINT NOT NULL DEFAULT 0 COMMENT '有効' ,
`email` VARCHAR(255) NOT NULL COMMENT 'E-Mail' ,
`expires_at` DATETIME NOT NULL COMMENT '有効期限' ,
`created_at` DATETIME NULL COMMENT '作成日時' ,
`updated_at` DATETIME NULL COMMENT '更新日時' ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `uk_token` USING BTREE (`token` ASC) ,
INDEX `fk_category` (`category_id` ASC) ,
CONSTRAINT `fk_category`
FOREIGN KEY (`category_id` )
REFERENCES `jobeet`.`jobeet_category` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
COMMENT = '求人';
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_affiliate`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_affiliate` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'ID' ,
`url` VARCHAR(255) NOT NULL COMMENT 'URL' ,
`email` VARCHAR(255) NOT NULL COMMENT 'E-Mail' ,
`token` VARCHAR(255) NOT NULL COMMENT 'トークンキー' ,
`is_active` TINYINT NOT NULL DEFAULT 0 COMMENT '有効' ,
`created_at` DATETIME NULL COMMENT '作成日時' ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `uk_affiliate` USING BTREE (`email` ASC) )
ENGINE = InnoDB
COMMENT = 'アフィリエイト';
-- -----------------------------------------------------
-- Table `jobeet`.`jobeet_category_affiliate`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `jobeet`.`jobeet_category_affiliate` (
`category_id` INT NOT NULL COMMENT 'カテゴリID' ,
`affiliate_id` INT NOT NULL COMMENT 'アフィリエイトID' ,
PRIMARY KEY (`category_id`, `affiliate_id`) ,
INDEX `fk_category` (`category_id` ASC) ,
INDEX `fk_affiliate` (`affiliate_id` ASC) ,
CONSTRAINT `fk_category_affiate_category`
FOREIGN KEY (`category_id` )
REFERENCES `jobeet`.`jobeet_category` (`id` )
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_category_affiate_affiliate`
FOREIGN KEY (`affiliate_id` )
REFERENCES `jobeet`.`jobeet_affiliate` (`id` )
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB
COMMENT = 'カテゴリ-アフィリエイト';
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
データベースに、ユーザーとスキーマを作成します。
チュートリアルでは、rootでログインしていますが、アプリケーション用のユーザーを作成するのが一般的です。
MySQL Administratorで、[jobeet]ユーザーを作ってみました。
ユーザー名とパスワードは同一です。(公開していないので、パスワードを公開しても大丈夫です。)

symfonyにJobeetプロジェクト用にこのデータベースを使うことを伝えます。
symfony configure:database "mysql:host=localhost;dbname=jobeet" jobeet jobeet
これにより、config/databases.yml ファイルが以下のように更新されます。
dev:
propel:
param:
classname: DebugPDO
test:
propel:
param:
classname: DebugPDO
all:
propel:
class: sfPropelDatabase
param:
classname: PropelPDO
dsn: 'mysql:host=localhost;dbname=jobeet'
username: jobeet
password: jobeet
encoding: utf8
persistent: true
pooling: true
データベースへの接続情報が設定されます。
[lib.model.schema.sql]を使って、MySQLの[jobeet]スキーマに、DDLを流してスキーマを構成します。
以下のコマンドを投入します。
symfony propel:insert-sql
symfonyには、2つのORM(PropelとDoctrine)がビルトインされています。
ここでは、PropelというORM(O/R Mapper)を使用して、テーブルレコードをオブジェクトにマッピングするPHPクラスを作ります。
以下のコマンドを入力します。
symfony propel:build-model
すると、/lib/model のディレクトリに、20個のPHPクラスが作成されます。
テーブル単位に4つのクラスとチュートリアルに書かれていますが、実際には5つファイルが作成されます。
チュートリアルは、[jobeet_job]テーブルについての解説をしていますので、確認してみます。
作成されるモデルのクラス図を描いてみました。
クラスのパッケージの図について、うそが書かれていますが、正確に書くとごちゃごちゃしてしまうため、あえて間違って書いています。

lib.model.omの中で定義されているクラスは、フレームワークが定義する部分であるため、修正することはできません。
クラスを拡張したい場合には、派生クラスからオーバーライドする必要があります。
BaseObjectは、ライブラリに含まれているため、実際には、このパッケージには含まれていません。
BaseJobeetJobは抽象クラスで、Persistentインタフェースを実装しています。
抽象クラスであるため、かならず、派生クラスを作る必要があります。
そのクラスが[JobeetJob]クラスになります。
Persistentインタフェースは、DBの永続化するために実装しなければならない永続化インタフェースです。
PropelのHPページは、以下のURLになります。
http://propel.phpdb.org/trac/
http://propel.phpdb.org/docs/api/current/runtime/propel-om/_om---BaseObject.php.html
BaseObjectクラスの詳細です。
| No | 名前 | 種類 | 可視性 |
| 1 | $modifiedColumns | Class Variables | protected |
| 2 | equals() | Class Methods | public |
| 3 | getModifiedColumns() | ||
| 4 | hashCode() | ||
| 5 | isColumnModified() | ||
| 6 | isDeleted() | ||
| 7 | isModified() | ||
| 8 | isNew() | ||
| 9 | log() | protected | |
| 10 | resetModified() | public | |
| 11 | setDeleted() | ||
| 12 | setNew() |
http://propel.phpdb.org/docs/api/current/runtime/propel-om/Persistent.html
Persistentインタフェースの詳細です。
| No | 名前 | 種類 | 可視性 |
| 1 | delete() | Class Methods | public |
| 2 | getPrimaryKey() | ||
| 3 | isColumnModified() | ||
| 4 | isDeleted() | ||
| 5 | isModified() | ||
| 6 | isNew() | ||
| 7 | resetModified() | ||
| 8 | save() | ||
| 9 | setDeleted() | ||
| 10 | setNew() | ||
| 11 | setPrimaryKey() |
BaseJobeetJob抽象クラスの詳細です。
| No | 名前 | 種類 | 可視性 |
| 1 | $peer | Class Variables | protected |
| 2 | $id | ||
| 3 | $category_id | ||
| 4 | $type | ||
| 5 | $company | ||
| 6 | $logo | ||
| 7 | $url | ||
| 8 | $position | ||
| 9 | $location | ||
| 10 | $description | ||
| 11 | $how_to_apply | ||
| 12 | $token | ||
| 13 | $is_public | ||
| 14 | $is_activated | ||
| 15 | |||
| 16 | $expires_at | ||
| 17 | $created_at | ||
| 18 | $updated_at | ||
| 19 | $aJobeetCategory | ||
| 20 | $alreadyInSave | ||
| 21 | $alreadyInValidation | ||
| 22 | __construct() | Class Methods | public |
| 23 | applyDefaultValues() | ||
| 24 | getId() | ||
| 25 | getCategoryId() | ||
| 26 | getType() | ||
| 27 | getCompany() | ||
| 28 | getLogo() | ||
| 29 | getUrl() | ||
| 30 | getPosition() | ||
| 31 | getLocation() | ||
| 32 | getDescription() | ||
| 33 | getHowToApply() | ||
| 34 | getToken() | ||
| 35 | getIsPublic() | ||
| 36 | getIsActivated() | ||
| 37 | getEmail() | ||
| 38 | getExpiresAt() | ||
| 39 | getCreatedAt() | ||
| 40 | getUpdatedAt() | ||
| 41 | setId() | ||
| 42 | setCategoryId() | ||
| 43 | setType() | ||
| 44 | setCompany() | ||
| 45 | setLogo() | ||
| 46 | setUrl() | ||
| 47 | setPosition() | ||
| 48 | setLocation() | ||
| 49 | setDescription() | ||
| 50 | setHowToApply() | ||
| 51 | setToken() | ||
| 52 | setIsPublic() | ||
| 53 | setIsActivated() | ||
| 54 | setEmail() | ||
| 55 | setExpiresAt() | ||
| 56 | setCreatedAt() | ||
| 57 | setUpdatedAt() | ||
| 58 | hasOnlyDefaultValues() | ||
| 59 | hydrate() | ||
| 60 | ensureConsistency() | ||
| 61 | reload() | ||
| 62 | delete() | ||
| 63 | save() | ||
| 64 | doSave() | protected | |
| 65 | $validationFailure | Class Variables | protected |
| 66 | getValidationFailuresy() | Class Methods | public |
| 67 | validate() | ||
| 68 | doValidate() | protected | |
| 69 | getByName() | public | |
| 70 | getByPosition() | ||
| 71 | toArray() | ||
| 72 | setByName() | ||
| 73 | setByPosition() | ||
| 74 | fromArray() | ||
| 75 | buildCriteria() | ||
| 76 | buildPkeyCriteria() | ||
| 77 | getPrimaryKey() | ||
| 78 | setPrimaryKey() | ||
| 79 | copyInto() | ||
| 80 | copy() | ||
| 81 | getPeer() | ||
| 82 | setJobeetCategory() | ||
| 83 | getJobeetCategory() | ||
| 84 | clearAllReferences() | ||
| 85 | __call() |
BaseJobeetJobPeer抽象クラスの詳細です。
| No | 名前 | 種類 | 可視性 |
| 1 | $instances | Class Variables | public |
| 2 | getMapBuilder() | Class Methods | public |
| 3 | translateFieldName() | ||
| 4 | getFieldNames() | ||
| 5 | alias() | ||
| 6 | addSelectColumns() | ||
| 7 | doCount() | ||
| 8 | doSelectOne() | ||
| 9 | doSelect() | ||
| 10 | doSelectStmt() | ||
| 11 | addInstanceToPool() | ||
| 12 | removeInstanceFromPool() | ||
| 13 | getInstanceFromPool() | ||
| 14 | clearInstancePool() | ||
| 15 | getPrimaryKeyHashFromRow() | ||
| 16 | populateObjects() | ||
| 17 | doCountJoinJobeetCategory() | ||
| 18 | doSelectJoinJobeetCategory() | ||
| 19 | doCountJoinAll() | ||
| 20 | doSelectJoinAll() | ||
| 21 | getUniqueColumnNames() | ||
| 22 | getOMClass() | ||
| 23 | doInsert() | ||
| 24 | doUpdate() | ||
| 25 | doDeleteAll() | ||
| 26 | doDelete() | ||
| 27 | doValidate() | ||
| 28 | retrieveByPK() | ||
| 29 | retrieveByPKs() |
これらの資料をみると、あぁ、いろいろ便利に定義されているなと関心に思えます。
2つのファイルを作成しました。
[010_categories.yml]と[020_jobs.yml]です。
このファイルを /data/fixturesのディレクトリに格納します。
そして、このコマンドを投入します。
symfony propel:data-load
データがこのように格納されました。Rowsが増えているのが判ります。

テーブルに対するCRUD(Create/Read/Update/Delete)アプリケーションを自動で作成するタスクが、symfonyには組みつけられています。
以下のコマンドを投入します。
symfony propel:generate-module --with-show --non-verbose-templates frontend job JobeetJob symfony propel:generate-module --with-show --non-verbose-templates frontend category JobeetCategory symfony propel:generate-module --with-show --non-verbose-templates frontend affiliate JobeetAffiliate
これにより、[jobeet_job]、[jobeet_category]、[jobeet_affiliate]のテーブルを編集するモジュール
[job]、[category]、[affiliate]の3つ作成されます。
以下のURLにアクセスし、実際に動作させたアプリのキャプチャが以下のとおりです。
http://jobeet.localhost/frontend_dev.php/job

アプリは、エディットしようとすると例外が発生します。__toString()メソッドを実装しなさいといいます。

チュートリアルの指示通りに修正すると、以下のように動作するようになりました。

チュートリアルのキャプチャの状況をみると、MaxOS Xで開発をしているようです。
MaxOS Xは、FreeBSDに良く似た[Darwin]というOSをベースにしており、ほぼUNIX系のOSとみなせます。
CRUDアプリケーションをRAD的に作成することができることが確認できました。
以上です。