プログラミング - THIS IS IT !

より良い開発をすべく日々奮闘しているプログラマーのブログです。設計に興味があります。主にPHPネタを書いてます 日本Symfonyユーザー会

DoctrineMigrationsBundleの使い方について - Symfony Advent Calender 2012 9日目

こんにちは。@です。

この記事は Symfony Advent Calender 2012 Day9の記事です。
Symfony界のイケメンさんからバトンを引き継ぎ次に繋ぎたいと思います。
昨日の Day8の記事ではSymfonyユーザー会やそのコミュニティーについてご紹介されています。

この記事では、あまり日本語情報のないDoctrineMigrationsBundleについて紹介したいと思います。

マイグレーションとは

Railsでは言わずと知れた機能ですね。通常DBテーブルを新規に作成したり、カラムの追加、変更を行うにはSQLを実行するのですが、マイグレーション機能では事前にスクリプトファイル(=マイグレーションファイル)さえ用意しておけばコマンドを実行することでDBスキーマの変更を容易に行うことができます。
DBの変更の度にSQLファイルをコミットして、他の開発者にはそれを流してもらうのは非効率ですのでコマンド一発で実行できるこの機能は非常に便利です。

コマンドから容易にスキーマ変更を行えるといことは、デプロイの自動化にも利用できます。公式ドキュメントにも記載されている通り、

またマイグレーションの機能として、変更したスキーマを元に戻すこともできますので、万一リリースで問題が発生した場合にも簡単に切り戻しを行うこともできます。
また、Git等のバージョン管理を用いて開発している場合、そのコミット時点でのDBスキーマに戻すこともできます。

Symfony2には公式ドキュメントにも記載されている「DoctrineMigrationsBundle」という素晴らしいバンドルがあるのでこれを利用することで簡単にマイグレーション機能を利用することができます。

公式ドキュメント(英語)
Symfony2.1系
http://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html
Symfony2.0系
http://symfony.com/doc/2.0/bundles/DoctrineMigrationsBundle/index.html
Doctrine Migration
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/toc.html

対象

対象バージョン

この記事ではSymfony2.0系での説明をしていきます。

対象データベースはMySQLになります。PostgreSQL等他のDBでの動作は検証していませんし、MySQL前提で話を進めます。

検証環境

Symfony 2.0.19
Mysql 5.5.27
php 5.3.17

インストール

Symfony2.0系のインストール方法です。Symfony2.1系をお使いの方は適宜読み替えて下さい。

depsファイルへの記述

[doctrine-migrations]
    git=http://github.com/doctrine/migrations.git

[DoctrineMigrationsBundle]
    git=http://github.com/doctrine/DoctrineMigrationsBundle.git
    target=/bundles/Symfony/Bundle/DoctrineMigrationsBundle
    version=origin/2.0

vendorライブラリの更新&インストール

$ php bin/vendors install

次に、bundleの登録を行います。
app/autoload.phpとapp/AppKernel.phpファイルに書き足します。

app/autoload.php

<?php
$loader->registerNamespaces(array(
    //...
    'Doctrine\\DBAL\\Migrations' => __DIR__.'/../vendor/doctrine-migrations/lib',
    'Doctrine\\DBAL'             => __DIR__.'/../vendor/doctrine-dbal/lib',
));

app/AppKernel.php

<?php
public function registerBundles()
{
    $bundles = array(
        //...
        new Symfony\Bundle\DoctrineMigrationsBundle\DoctrineMigrationsBundle(),
    );
}

コマンド一覧

php app/console とすると実行できるコメンドの一覧が表示されます。

doctrine:migrations:diff Generate a migration by comparing your current database to your mapping information.
doctrine:migrations:execute Execute a single migration version up or down manually.
doctrine:migrations:generate Generate a blank migration class.
doctrine:migrations:migrate Execute a migration to a specified version or the latest available version.
doctrine:migrations:status View the status of a set of migrations.
doctrine:migrations:version Manually add and delete migration versions from the version table.


それぞれのコマンドが取れる引数は--helpで確認して下さい。
例)

php app/console doctrine:migrations:diff --help

Usage:
 doctrine:migrations:diff [--editor-cmd[="..."]] [--configuration[="..."]] [--db-configuration[="..."]] [--filter-expression[="..."]] [--em[="..."]]

Options:
 --editor-cmd         Open file with this command upon creation.
 --configuration      The path to a migrations configuration file.
 --db-configuration   The path to a database connection configuration file.
 --filter-expression  Tables which are filtered by Regular Expression.
 --em                 The entity manager to use for this command.

Help:
 The doctrine:migrations:diff command generates a migration by comparing your current database to your mapping information:
 
     app/console doctrine:migrations:diff
 
 You can optionally specify a --editor-cmd option to open the generated file in your favorite editor:
 
     app/console doctrine:migrations:diff --editor-cmd=mate

アーキテクチャ

DoctorineMigrationBundleのアーキテクチャは非常にシンプルです。

使い方

それでは使い方を順を追って解説していきます

はじめ方

doctrine:migrations:status(初期化と状態の確認)

まずはこのコマンドを実行し、初期化します。

$ php app/console doctrine:migrations:status

 == Configuration

    >> Name:                                   Application Migrations
    >> Database Driver:                        pdo_mysql
    >> Database Name:                          my_symfony
    >> Configuration Source:                   manually configured
    >> Version Table Name:                     migration_versions
    >> Migrations Namespace:                   Application\Migrations
    >> Migrations Directory:                   /private/var/www/html/My_Symfony/app/DoctrineMigrations
    >> Current Version:                        0
    >> Latest Version:                         0
    >> Executed Migrations:                    0
    >> Executed Unavailable Migrations:        0
    >> Available Migrations:                   0
    >> New Migrations:                         0
Current Version
今のバージョン
Latest Version
最新のバージョン
Executed Migrations
実行したマイグレーション
Executed Unavailable
Migrations実行したけど利用できなかったマイグレーション数(SQLExceptionが発生した等何かしらの要因で実行できなかったファイル数と思われる。未確認)
Available Migrations
利用可能なマイグレーション(「app/DoctrineMigrations/」以下にあるマイグレーションファイル)

:New Migrations 新しく実行するマイグレーション

この時、データベースに「migration_versions」というテーブルが作成されます。

マイグレーションファイルの作成

doctrine:migrations:generate(マイグレーションファイルの雛形生成)

このコマンドでマイグレーションファイルの雛形を生成することができます。DBスキーマを変更する場合にはこのコマンドを実行します。

デフォルトでは「app/DoctrineMigrations/」ディレクトリ以下に生成され、ファイル名は「Version【現在日時】.php」となます。

<?php
// app/DoctrineMigrations/Version20121209120000.php

namespace Application\Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration,
    Doctrine\DBAL\Schema\Schema;

class Version20121209120000 extends AbstractMigration
{
    // DB変更する内容
    public function up(Schema $schema)
    {
    }
    // 元に戻す内容
    public function down(Schema $schema)
    {
    }
}

マイグレーションファイルに記述をします。マイグレーションファイルには、今回変更したい内容と、その変更を戻したい場合のメソッドの2つを定義します。

記述の仕方は2パターンあります。1つ目はDoctrineのSchemaクラスを用いて記述する方法で2つ目がSQLを直接記述する方法です。以下のサンプルはUserテーブルを新しく追加する場合のコードになります。

<?php
    :
    public function up(Schema $schema)
    {
        $table = $schema->createTable('user');
        $table->addColumn('id', 'integer', array('autoincrement' => true, 'comment' => 'PK'));
        $table->addColumn('username', 'string', array('length' => '255', 'notnull' => true,));
          :
        $table->addColumn('created_at', 'datetime', array('notnull' => true, 'comment' => '作成日時'));
        $table->addColumn('updated_at', 'datetime', array('notnull' => true, 'comment' => '更新日時'));
        $table->setPrimaryKey(array('id'));
    }
    public function down(Schema $schema)
    {
        $schema->dropTable('user_append')
    }
}

ただし、見ての通り非常に記述が面倒くさいので以下の通りSQLで書くことをオススメします。こちらのほうが直感的に書けると思いますし、DoctrineのMappingは完璧ではないのでそれも含めてこちらで記述しておいた方が良いでしょう。
例えばDoctrineではtimestamp型を扱えないのですが、どうしても扱いたい場合には下記の様に記述します。

<?php
    :
    public function up(Schema $schema)
    {
        $this->addSql('
            CREATE TABLE `user` (
              `id` int NOT NULL AUTO_INCREMENT,
              `username` varchar(255) NOT NULL,
              `password` varchar(255) NOT NULL,
              `salt` varchar(255) NOT NULL,
              `created_at` datetime` NOT NULL,
              `updated_at timestamp` NOT NULL,
              PRIMARY KEY (`id`)
            ) ENGINE=InnoDB
        ');
    }
    public function down(Schema $schema)
    {
        $this->addSql('DROP TABLE user');
    }
}

マイグレーションファイルを記述する時には変更を元に戻すDownメソッドは気を付けて記述するようにしましょう。ここを間違えているときちんと元のバージョンに戻すことができなくなります。

doctrine:migrations:migrate(特定バージョンor最新バージョンへマイグレーションの実行)

このコマンドでマイグレーションを実行できます。このコマンドをversionの引数なしで実行すると最新バージョンになるようマイグレーションが実行されます。

$ php app/console doctrine:migrations:migrate
                                                              
                    Application Migrations                    
                                                              
WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)y   ←yを入力しEnter
Migrating up to 20121209120000 from 0

  ++ migrating 20121209120000
     -> 
            CREATE TABLE `user` (
                `id` int NOT NULL AUTO_INCREMENT,
                `username` varchar(255) NOT NULL,
                `password` varchar(255) NOT NULL,
                `salt` varchar(255) NOT NULL,
                `created_at` datetime NOT NULL,
                `updated_at` timestamp NOT NULL,
                PRIMARY KEY (`id`)
            ) ENGINE=InnoDB

  ++ migrated (0.07s)

  ------------------------

  ++ finished in 0.07
  ++ 1 migrations executed
  ++ 1 sql queries

データベースを見るとバージョン20121209120000のマイグレーションが実行されていることが分かります。「doctrine:migrations:status」コマンドはversionカラムとマイグレーションファイルを比較することで状態を判定しているようです。

mysql> select * from migration_versions;
+----------------+
| version        |
+----------------+
| 20121209120000 |
+----------------+

カラムの追加(や変更)も同様にマイグレーションファイルを記述します。

<?php
    :
    public function up(Schema $schema)
    {
        $this->addSql('ALTER TABLE user ADD COLUMN lastname varchar(255) NULL AFTER salt');
        $this->addSql('ALTER TABLE user ADD COLUMN firstname varchar(255) NULL AFTER lastname');
    }
    public function down(Schema $schema)
    {
       $this->addSql('ALTER TABLE user DROP COLUMN lastname'); 
       $this->addSql('ALTER TABLE user DROP COLUMN firstname');
    }
}

実行

$ php app/console doctrine:migrations:migrate

マイグレーションを用いてバージョン管理

DBを戻したくなったり特定のバージョンに進めたい場合には、versionを指定して実行することで行えます。

例)
$ php app/console doctrine:migrations:migrate 20121209150000 --no-interaction

ちなみにですが、「--no-interaction」を付けることで毎回yes/noを聞かれることがなくなります。自動デプロイ時には必須なので知っておくと便利です。(先ほど紹介した通りコマンドの後に「--help」を付けるとオプションが確認できます)

doctrine:migrations: execute(特定のマイグレーションバージョンだけ実行)

あまり利用することはないと思いますが、特定のマイグレーションだけ実行したり戻したりすることもできます。

// バージョン20121209120000で実行した変更だけを戻す
$ php app/console doctrine:migrations:execute 20121209150000 --down
// バージョン20121209120000の変更だけ実行
$ php app/console doctrine:migrations:execute 20121209150000 --up
doctrine:migrations: version(migration_versionsテーブルから特定バージョンを追加or削除)

これもあまり使うことはないかと思います。が一応説明を。

「doctrine:migrations: execute」を使った場合など、データベースとマイグレーションファイルに不整合が起こる場合があります。
例)php app/console doctrine:migrations:execute 20121209120000 --down を実行してuser テーブルを削除したけど、「20121209150000」は「migration_versions」テーブルに残っている。「20121209150000」はuserテーブルのカラム変更なので実行しようとすると「SQLException」が発生する。

そういう場合はこのコマンドを用いて手動で削除することができます。

$ php app/console doctrine:migrations:version 20121209150000 --delete

マイグレーションファイルの自動生成

マイグレーションファイルの自動生成もできます。

doctrine:migrations:diff

このコマンドは現在のDBとマッピング情報を比較して、マイグレーションファイルを生成してくれます。マッピング情報を書いてこのコマンドを実行するとマイグレーションファイルを生成してくれます。

例えばgroupテーブルのマッピング情報(annotation、yml等)を新規に用意してコマンドを実行すると以下のようなマイグレーションファイルが生成されます。

<?php
    :
    public function up(Schema $schema)
    {
        $this->addSql("CREATE TABLE group (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB");
    }

    public function down(Schema $schema)
    {
        $this->addSql("DROP TABLE group");
    }
}

Doctrineがマッピングできない情報を利用したり(先ほどのtimestampなど)カラム追加する場合には多少修正してやる必要があります。
マッピング情報に「birthday」を足して実行した場合以下のようなファイルが生成されます。

<?php

namespace Application\Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration,
    Doctrine\DBAL\Schema\Schema;

class Version20121209190000 extends AbstractMigration
{
    public function up(Schema $schema)
    {
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");        
        $this->addSql("ALTER TABLE user ADD birthday DATE DEFAULT NULL, CHANGE updated_at updated_at DATETIME NOT NULL");
    }

    public function down(Schema $schema)
    {
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
        $this->addSql("ALTER TABLE User DROP birthday, CHANGE updated_at updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL");
    }
}

1つ目「updated_at」のtimestamp型がdatetime型に変更されてしまう。
→CHANGE updated_at〜の部分を消す。(datetime型でもういい気がします)

2つ目は「birthday」カラムがUserテーブルの一番最後にカラム追加されてしまう。
→好みの問題ですが、カラムの順番を気にする人もいるでしょう。「ALTER TABLE user ADD birthday DATE DEFAULT NULL AFTER firstname」などとしておくと任意の場所にカラム追加できて良いと思います。

「doctrine:migrations:diff」を使いつつ、必要に応じて修正するのが良いのではないかと思います。

まとめ

  • DoctrineMigrationsBundleを使えば、データベースの更新作業を簡単に共有できます。
  • 特定のデータベーススキーマに戻すことも容易です。


主な使い方についてはほとんど解説したつもりですが、ちょっとしたtipsなど時間があればまた紹介したいと思います。

引き続き「Symfony Advent Calender 2012」をお楽しみ下さい。明日は、@77webさんの「Symfony2で翻訳ファイルを使ってフォームを日本語化する方法」の予定です。

以上、「DoctrineMigrationsBundleの使い方について 」でした。

SonataAdminBundleを翻訳してみたよ

(2013/5/26追記)
こちらの情報はインストール手順等が既にに古くなっています。新し目の翻訳情報はこちらにまとめています。
http://okapon-pon.hatenablog.com/entry/2012/12/24/235408
(追記終わり)

(この記事ははてなダイアリーからのインポート記事になります)
おかぽんと申します。本エントリーが初投稿となりますよろしくお願いします。

このエントリーは「Symfony Advent Calendar JP 2011」の23日目の記事になります。
アドベントカレンダーをご存知ない方はこちらをどうぞ。http://gihyo.jp/news/info/2011/12/0101

今回が初ブログでAdvent Calendarに参加するために作ったわけですが、完全にボリュームを見誤り日付が変わってしまいました。1週間ぐらい前から地道に翻訳を始めたのですが・・・

それはさておき、さっそく本題に入りたいと思います。

このエントリーではSymfony2のAdminGeneratorであるSonataAdminBundleのドキュメントを翻訳したのでご紹介していきたいと思います。<2012/12/3追記>
SonataAdminBundleですが、2012/12/3インストール方法が変わっていますのでこの記事のままだと動きません。このあたりの翻訳も時間があるときにやりたいなとは思っています。

そもそもバンドルとは

symfony2をある程度使っている方なら(ましてアドベントカレンダーを楽しみにしている方ならなおさら)説明は不要かと思いますが、symfony2では「バンドル」という機構を利用してサードパーティ製のライブラリーを組み込むことができます。(プラグインのようなものですが、単なるプラグインではないです。そこらへんの説明は省略します。)

既にたくさんのサードパーティ製バンドルが公開されており*1、非常な便利なものがたくさんあります。
(といいつつ僕はほとんど使ったことないのであんまり詳しくないです)

その中でもユーザ認証関連を提供している「FOSUserBundle」やDB管理機能を提供している「SonataAdminBundle」は非常に有名です。

ただ、ここで問題なのがこれらサードパーティ製バンドルのドキュメントはほとんどが英語なんですね。。。僕もそうですが英語が苦手な人はどうもとっつきづらい。。。

じゃあ翻訳してみよう

ということで今回の英語が苦手な方に向けて翻訳にトライしてみました。
翻訳したのはタイトルにもある通りSonataAdminBundleです。

最初に謝っておきますが、まだ翻訳は全部できてません。
そもそも時間が。。 原文自体更新されてるし。。 ごめんなさい。力不足でした。随時更新していきたいと思います。
僕自身英語が苦手なので「この訳が変だ!」とかありましたらご教授いただけますと幸いです。

翻訳文は以下githubで公開しています。(forkして「translation」ブランチ作って翻訳しています)
SonataAdminBundle(翻訳)
SonataDoctrineORMAdminBundle(翻訳)
ただ、日本語を追記しているだけなので非常に見にくいのが現状です。何かいいアイデアがあれば教えてください。
せめてREADMEぐらい置けばよかった。。
<2011/12/25追記>READMEファイル置きました。

はい!翻訳もgithubにアップしたからこれでおしまい!
って終わるのもあれですので、使い方について簡単に説明していきたいと思います。

はじめに

先程も述べたようにAdminBundleは、Symfony2におけるAdminGeneratorになります。DB管理画面に必要な機能をひと通り提供してくれています。

このAdminBundleですが、まだまだ開発途中であり日々アップデートされています。(同様にドキュメントもちょくしょく更新されてますorz.)そのためこのエントリーの記述されている内容は古くなったり、正常に動作しなくなる可能性もあるためご了承ください。

僕が初めてAdminBundleを触りだした10月末頃はAdminBundle単体で動いていたのですがいつの間にか4つのbundleに分かれていました*2
そのため、AdminBundle以外にも別途bundleをインストールしなければ動かすことができません。

例えば、MysqlのDB管理を行いたければ実際にDBと連携するDoctrinORM向けの「SonataDoctrineORMAdminBundle」もインストールする必要があります。

SonataAdminBundleの特徴

メリット
  • DB管理に必要なcreate,update,deleteなど(CRUD)の機能を簡単に作成できる
  • いけてるインターフェースの管理画面がお手軽に構築できる
  • 一括処理(デフォルトで用意されているのは一括削除のみ)ができる
  • DBテーブルの関連性を持たせることができる(例えば、あるカテゴリーに属した商品を登録できる)
  • FOSUserBundleを内包したSonataUserBundleを利用することでAdminユーザの管理ができる(まだ試せてない)
  • simplethings/EntityAudit というbundleを使うことでDBのバージョン管理ができる(まだ試せてない)
その他

なおデフォルトではログイン機能は提供されていません。
SonataUserBundleがその機能を提供しているみたいなのでそちらを使うことになるかと思います。

もちろんsymfony2のセキュリティーコンポーネントを用いて自分で作るのもありだと思います。僕はFouUserBundleに関して理解できていないので自分でセキュリティエリアを設定して使っています。

また、編集の確認画面がないので必要であれば作る必要があります。海外ではフォーム入力後の確認画面がないと聞きます。(本当か?)そのため日本向けにカスタマイズするのであれば自分でカスタマイズして組み込む必要がありそうですね。

インストール方法

ここではMySQLを使用していることを前提に「SonataAdminBundle」と「SonataDoctrineORMAdminBundle」インストールします。

オプションのEntityAuditは別途DBテーブルを作らないと動かないみたいなので今回はなしで。<2012/12/26追記>詳しくはAuditの翻訳を参照

bundleをインストールするにはdeps ファイルに記述します。

[SonatajQueryBundle]
    git=http://github.com/sonata-project/SonatajQueryBundle.git
    target=/bundles/Sonata/jQueryBundle

[SonataUserBundle]
    git=http://github.com/sonata-project/SonataUserBundle.git
    target=/bundles/Sonata/UserBundle

[SonataAdminBundle]
    git=http://github.com/sonata-project/SonataAdminBundle.git
    target=/bundles/Sonata/AdminBundle

[KnpMenuBundle]
    git=https://github.com/KnpLabs/KnpMenuBundle.git
    target=/bundles/Knp/Bundle/MenuBundle

[KnpMenu]
    git=https://github.com/KnpLabs/KnpMenu.git
    target=/knp/menu

[SonataDoctrineORMAdminBundle]
    git=http://github.com/sonata-project/SonataDoctrineORMAdminBundle.git
    target=/bundles/Sonata/DoctrineORMAdminBundle

そして

bin/vendors install

を実行しadminbundleをインストール!

次に、bundleの登録を行います。
app/AppKernel.phpとapp/autoload.phpファイルに書き足します。

<?php
// app/autoload.php
$loader->registerNamespaces(array(
    // ...
    'Sonata'           => __DIR__.'/../vendor/bundles',
    'Knp\\Bundle'      => __DIR__.'/../vendor/bundles',
    'Knp\\Menu'        => __DIR__.'/../vendor/knp/menu/src',
    )
);
// app/AppKernel.php
public function registerBundles()
{
    return array(
        // ...
        new Sonata\jQueryBundle\SonatajQueryBundle(),
        new Sonata\AdminBundle\SonataAdminBundle(),
        new Knp\Bundle\MenuBundle\KnpMenuBundle(),
        // ...
    );
}

そしてルートを記述します。prefixはそれぞれの環境に合わせて下さい。

# app/config/routing.yml
admin:
    resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
    prefix: /admin

_sonata_admin:
    resource: .
    type: sonata_admin
    prefix: /admin

そしてアセットをインストールします。

app/console assets:install web --symlink

ここまでできたら、「http://yoursite.local/admin/dashboard」にアクセスすることで下のようなダッシュボードが表示されます。

sonata adminの設定

少し表示を変えてみましょう。

# app/config/config.yml
sonata_admin:
    title:      プロジェクト管理画面
    title_logo: /bundles/sonataadmin/logo_title.png #ロゴはデフォルト
    dashboard_groups:
        管理項目1:
            items: ~

タイトルが変更され、ダッシュボードグループができましまた。

※別に「dashboard_groups」設定しなくともAdminaバンドルはデフォルト設定でいい感じに動いてくれます。

adminクラスの作成

エンティティを管理するためには、Adminクラスを作成しサービスに登録する必要があります。

まず管理したいDBテーブルを登録します。
通常プロジェクトを作っている場合、既にエンティティは作成していると思いますが今回は初めから作ります。

以下のようなcategoryテーブルの管理サービスを作成します。

id int(10)
name varchar(20)
created_at datetime
updated_at timestamp

mysqlで以下を実行(symfony2でのコンソールコマンドだとtimestamp型にできないと思われるので。間違ってたらごめんなさい)

# クエリ実行
CREATE TABLE `category` (
 id int NOT NULL  AUTO_INCREMENT PRIMARY KEY,
 name varchar(20)    NOT NULL,
 created_at datetime    NOT NULL,
 updated_at timestamp    NOT NULL
) ENGINE = INNODB DEFAULT CHARSET=utf8;

# Categoryエンティティ作成
app/console generate:doctrine:entity --entity=AcmeDemoBundle:Category --format=yml --fields="name:string(20) created_at:datetime updated_at:datetime"
# yml設定とかは略します。

次にcategoryテーブルを管理するために必要なCategoryAdminコントローラーとCategoryAdminクラスを作成します。

# コントローラー作成
#src/Acme/DemoBundle/Controller/CategoryAdminController.php
<?php
namespace Acme\DemoBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
  
class CategoryAdminController extends Controller
{

}

# CategoryAdminクラス作成
#src/Acme/DemoBundle/Admin/CategoryAdmin.php
<?php
namespace Acme\Demobundle\Admin;
 
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Show\ShowMapper;

use Knp\Menu\ItemInterface as MenuItemInterface;
 
#use Application\Sonata\NewsBundle\Entity\Comment;
use Dgtw\DaigakutownBundle\Util\SystemTime;

class CategoryAdmin extends Admin
{
    protected function configureShowField(ShowMapper $showMapper)
    {
        // showアクションで表示したい項目を設定
        $showMapper
            ->add('id')
            ->add('name','string',array('label'=> 'カテゴリー名'))
            ->add('created_at',null, array('label' => '作成日'))
            ->add('updated_at',null, array('label' => '更新日'))
        ;
    }
    protected function configureFormFields(FormMapper $formMapper)
    {
        // editアクションのformで編集したい項目を設定
        // 通常created_atはライフサイクルコールバックで自動登録しそうだがとりあえず設定
        $formMapper
            ->add('name','text',array('label'=> 'カテゴリー名'))
            ->add('created_at',null, array('label' => '作成日'))
            ->add('updated_at',null, array('label' => '更新日'))
            ->end()
        ;
    }
    protected function configureListFields(ListMapper $listMapper)
    {
        // listアクションで一覧に表示したい項目
        $listMapper
            ->addIdentifier('name',null,array('label'=> 'カテゴリー名'))
            ->add('_action', 'actions', array(
                'actions' => array(
                    'view' => array(),
                    'edit' => array(),
                )
            ))
        ;
    }
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        // 検索フィルターを使用する項目を設定
        $datagridMapper
            ->add('name')
        ;
    }
}

Adminクラスを作り終えたらサービスを登録します。

<del># app/config/routing.yml</del> (正しくはconfig.ymlでした。)
# app/config/config.yml
services:
    acme.demobundle.admin.category:
        class: Acme\DemoBundle\Admin\CategoryAdmin
        tags:
            - { name: sonata.admin, manager_type: orm, group: 管理項目1, label: カテゴリー }
        arguments: [null, Acme\DemoBundle\Entity\Category, AcmeDemoBundle:CategoryAdmin]

↑tags の groupの値を「sonata_admin」のところで設定したdashboard_groupsと値を揃えることでダッシュボードの「管理項目1」にカテゴリーが表示されます(下画像)


日本語化

この状態でもとりあえず動きます。
管理画面として機能しています。ですが、表記が英語のままなのでなんとかしたいですね。
SonataAdminBundleは多国語翻訳されているアプリケーションで、幸いなことに日本語にも翻訳されています。

では、言語を日本語に切り替えてみましょう。

symfony2に詳しい人はご存知でしょうが、symfony2にはロケール設定といものがあります。
以下の様に設定して下さい。

# app/config/parameters.ini
    locale            = ja_JP

# app/config/config.yml
framework:
    #esi:             ~ 
    translator:      { fallback: %locale% } ←デフォルトでコメントアウトされてるのを外す
    ...

更新したら日本語化されると思いきやされない。どうやらセッションが効いているようなのでブラウザ閉じてリロード。
(そういえば昔もはまったような。。。)

「追加」「一覧」と無事日本語化されました。その他のページも「新規作成」など日本語化されています。

これでとりあえずAdminBundleが使えるようになりました。

終わりに

ホントはもう少し詳しく書こうかと思っていましたが、時間の関係上これで今回の記事はこれで終了します。
翻訳や記事の続きはまた書いていく予定ですので暖かく見守ってください。

明日はアドベントカレンダー最後日ですが、24日朝5時時点ではまだ埋まっていませんね。
どなたが書かれるのか期待ですね。

それでは皆様よいクリスマスを〜(*´∀`)

*1:12/23現在 927バンドル登録されています。knpBundlesをご覧下さい。

*2:Admin Bundleの目次に書かれています