[Symfony2]BalibaliBlogBundleを導入してみる

Symfony2についてQuick Tourを見ただけじゃ全くわからないので、まずは先人の知恵を借りることにします。balibaliさんがSymfony2でブログを作ったときのバンドルを公開されているので、インストールしてみることにします(詳細:Symfony2 で バリバリ日記2 をつくってみた – バリバリ日記II)。Symfony2初心者がバリバリ日記2を導入するメリットとしては

  • Symfony2が学べる
  • Doctrine MongoDB ODMが学べる
  • Twigが学べる
  • バンドルの再利用の概念が学べる

などが挙げられます。このバンドルをひと通り理解(し、カスタマイズ)出来れば、Symfony2の多くの機能に触れたことになるわけです。BalibaliBlogBundleはX11ライセンスです。balibaliさんに感謝!

まずはインストールから始めましょう。インストール方法はgithubのREADMEを参照しています。Apache、PHP5.3、Symfony-sandbox(github最新版)がインストール済みで、VirtualHostなどでブラウザからアクセスできている状態を前提とします。MongoDBはインストール方法をここで学びます。なお、2010/11/15時点での動作確認ですので、それ以降のSymfony2の変更により、動かなくなる可能性が大いにあります。

MongoDBのインストール(CentOS 5.5 yum)

公式のサイトを見ると、CentOSやFerora用のパッケージというページがあります。ここに、CentOS 5.4のi386とx86_64のレポジトリのパスが有ります。海外のサイトで、CentOS 5.5でインストールしている人がいるので、このまま続けたいと思います。(参考:Install MongoDB 1.6.0 on Fedora 13, CentOS 5.5, Red Hat (RHEL) 5.5さくらのVPSにMongoDB+PHP+Apacheをインストールしたメモ | cloudrop
[shcode]
# yumレポジトリの追加
sudo vim /etc/yum.repos.d/10gen-mongodb.repo
### [10gen]
### name=10gen Repository
### baseurl=http://downloads.mongodb.org/distros/centos/5.4/os/x86_64/
### gpgcheck=0
### enabled=0

# stable版をインストール(2010/11/14時点で、Ver 1.6.4)
sudo yum install -y –enablerepo=10gen mongo-stable mongo-stable-server
# 各種パスはデフォルトで以下の通り
## デーモン起動ファイル
### /etc/init.d/mongod
## 設定ファイル
### /etc/mongod.conf
## デーモン設定ファイル?
### /etc/sysconfig/mongod
## ログファイル
### /var/log/mongo/mongod.log
## データディレクトリ
### /var/lib/mongo
## コマンドライン版実行ファイル?
### /usr/bin/mongo
## DBバージョン実行ファイル
### /usr/bin/mongod

# デーモン起動(と自動起動)
sudo /etc/init.d/mongod start
sudo chkconfig mongod on
[/shcode]

BalibaliBlogBundleのインストール

[shcode]
# 私のSymfony2のsandboxのルートディレクトリに行きます(※ちなみに、VMware Fusionの共有フォルダのCentOS側のパスです)
cd /mnt/hgfs/localhost/symfony-sandbox
# バンドルをsrc/Bundle/Balibaliディレクトリに追加します
mkdir src/Bundle/Balibali
git submodule add git://github.com/balibali/BalibaliBlogBundle.git src/Bundle/Balibali/BlogBundle
[/shcode]

MarkdownBundleのインストール

[shcode]
git submodule add git://github.com/knplabs/MarkdownBundle.git src/Bundle/MarkdownBundle
[/shcode]

BalibaliBlogBundleの登録

AppKernelにバンドルとそのディレクトリパスを登録します。
[phpcode]
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(

new Bundle\Balibali\BlogBundle\BalibaliBlogBundle(),
new Bundle\MarkdownBundle\MarkdownBundle(),
);
}

public function registerBundleDirs()
{
return array(

‘Bundle\\Balibali’ => __DIR__.’/../src/Bundle/Balibali’,
);
}
[/phpcode]

DoctrineMongoDBBundleとTwigBundleを有効にします

[phpcode]
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(

new Symfony\Bundle\DoctrineMongoDBBundle\DoctrineMongoDBBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),

);
}
[/phpcode]

  1. // app/config/config.yml
  2. twig.config:
  3.     auto_reload: true
  4.  
  5. doctrine_odm.mongodb:
  6.     server: "mongodb://localhost:27017"
  7.     default_database: symfony_%kernel.environment%
  8.  
  9. markdown.parser: ~

ブログのルーティングルールをアプリケーションに登録します

  1. // app/config/routing.yml
  2. blog:
  3.     resource: Balibali/BlogBundle/Resources/config/routing.yml
  4.     prefix:   /blog

2010/11/09〜14あたりのsandboxでは動かないところを修正する

BalibaliBlogBundleのREADMEを見ると、次はapp/consoleでassets:installする手順なのですが、現在のsandboxではファイルが足りないためFatal Errorが出て先に進めません。とりあえず、全く意味も分かっては居ないものの、コア修正を最低限にしつつ、コマンドが通るように修正します。

まずは、「src/vendor/doctrine-mongodb/lib/Doctrine/ODM/MongoDB/Tools/Console/Command/Schema/」ディレクトリを作成します。
[shcode]
mkdir src/vendor/doctrine-mongodb/lib/Doctrine/ODM/MongoDB/Tools/Console/Command/Schema/
[/shcode]
どうやらこのディレクトリに存在するはずの幾つかのクラスファイルが足りないようです。ちなみにDoctrine本体のほうはSchemaではなくSchemaToolとディレクトリ名が変わっているので、いずれここも名前が変わってしまう可能性がありますが、今回はコア修正を最低限にするために、ディレクトリ名はこのままで行きます。

次に、CreateCommand.phpとDropCommand.phpを以下のように作成します。

[phpcode]
// CreateCommand.php
.
*/

namespace Doctrine\ODM\MongoDB\Tools\Console\Command\Schema;

use Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Output\OutputInterface,
Doctrine\ORM\Tools\Console\Command\SchemaTool\AbstractCommand,
Doctrine\ORM\Tools\SchemaTool;

/**
* Command to create the database schema for a set of classes based on their mappings.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Roman Borschel
*/
class CreateCommand extends AbstractCommand
{
/**
* @see Console\Command\Command
*/
protected function configure()
{
}

protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas)
{
}
}
[/phpcode]

[phpcode]
// DropCommand.php
.
*/

namespace Doctrine\ODM\MongoDB\Tools\Console\Command\Schema;

use Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Output\OutputInterface,
Doctrine\ORM\Tools\Console\Command\SchemaTool\AbstractCommand,
Doctrine\ORM\Tools\SchemaTool;

/**
* Command to drop the database schema for a set of classes based on their mappings.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Roman Borschel
*/
class DropCommand extends AbstractCommand
{
/**
* @see Console\Command\Command
*/
protected function configure()
{
}

protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas)
{
}
}
[/phpcode]
たぶんこれで次の手順に進めると思います。

アセットのインストール

[shcode]
app/console assets:install web
### Installing assets for Symfony\Bundle\FrameworkBundle
### Installing assets for Bundle\Balibali\BlogBundle
### Installing assets for Symfony\Bundle\WebProfilerBundle
[/shcode]

ブログの設定

  1. // app/config/config.yml
  2. parameters:
  3.     # Set your blog title and description:
  4.     balibali.blog.title: "Balibali Blog"
  5.     balibali.blog.description: "Blog written by Rimpei Ogawa."
  6.     # Here is an example of using global layout:
  7.     #balibali.blog.layout: "::layout"

BalibaliBlogBundleの修正

Symfony2は日々進化しているので、古いコードは動かなくなっていくことが有ります。それを修正していきます。とりあえず直ったらよしとするので、正しい修正であるかはわかりません。ただし、最低限の修正で直るようには心がけています。

// 「Template name “Balibali/BlogBundle:Post:index:twig” is not valid.」の修正
// src/Bundle/Balibali/BlogBundle/Controller/PostController.php L125
[phpcode]
$view = ‘Balibali/BlogBundle:Post:’.$view.’:twig’;
// ↓最後のコロンをドットに変更
$view = ‘Balibali/BlogBundle:Post:’.$view.’.twig’;
[/phpcode]

// 「Unknown tag name “route” in /…../index.twig」の修正(Symfony2 Ticket #9528に関連?)
// src/Bundle/Balibali/BlogBundle/Resources/views/Post/index.twig L2

  1. {% block head %}<link rel="alternate" type="application/rss+xml" title="Recent Posts" href="{% route 'balibali_blog_frontend_feed' with ['_format': 'xml'] %}">{% endblock %}
  2. // ↓routeをpathに変更
  3. {% block head %}<link rel="alternate" type="application/rss+xml" title="Recent Posts" href="{% path 'balibali_blog_frontend_feed' with ['_format': 'xml'] %}">{% endblock %}

どうやら2010/11/03の5b94dcb6f07f9f5e8d46のコミットで、ドキュメントの大物ファイルが更新されていて、routeじゃなくてpathに変わっていました。

// 「Template name “Balibali\BlogBundle::layout” is not valid.」の修正
// src/Bundle/Balibali/BlogBundle/Controller/PostController.php L129
[phpcode]
‘layout’ => $this->getParameter(‘layout’, ‘Balibali\\BlogBundle::layout’),
// ↓最後のコロンをドットに変更
‘layout’ => $this->getParameter(‘layout’, ‘Balibali\\BlogBundle::layout.twig’),
[/phpcode]

// 「Class Bundle\Balibali\BlogBundle\Document\Post is not a valid document or mapped super class.」の修正
// この原因を調べるのに4時間かかった。。。
// src/Bundle/Balibali/BlogBundle/Document/Post.php
// ↓すべてのアノテーションにmongodb:エイリアスを付与(変更後のみ掲載)
[phpcode]
publishedAt = new \DateTime();
}

public function getId()
{
return $this->id;
}

public function getSlug()
{
return $this->slug;
}

public function setSlug($slug)
{
$this->slug = $this->slugify($slug);
}

public function slugify($text, $default = ‘blog-post’)
{
$text = strtolower($text);
$text = preg_replace(‘/[^a-z0-9]/’, ‘-‘, $text);
$text = preg_replace(‘/-+/’, ‘-‘, $text);
$text = trim($text, ‘-‘);

return $text ? $text : $default;
}

public function getTitle()
{
return $this->title;
}

public function setTitle($title)
{
$this->title = $title;
}

public function getBody()
{
return $this->body;
}

public function setBody($body)
{
$this->body = $body;
}

public function getPublishedAt()
{
return $this->publishedAt;
}

public function getFormat()
{
return $this->format ? $this->format : ‘html’;
}

public function setFormat($format)
{
if ($format === ‘markdown’) {
$this->format = $format;
}
}
}
[/phpcode]

// その他
// src/Bundle/Balibali/BlogBundle/Resources/views/Post/*.twig
// 「route」を「path」に置換
個々のソースコードは省略します。

ちょっと動いた!

試しに「http://localhost/app_dev.php/blog/」にアクセスしてみると、データは空ですが、動きました

BalibaliBlogは管理画面も持っています。管理画面はprefixがbackendなので、「http://localhost/app_dev.php/blog/backend/」にアクセスしてみます。最後のスラッシュは必要です。「The filter “safe” does not exist in n/a line 27」とエラーが発生しました。また修正が幾つか入ります。

// 「The filter “safe” does not exist in n/a line 27」の修正
// Twigのsafeフィルターはrawフィルターに名前が変わったようです。
// src/Bundle/Balibali/BlogBundle/Resources/views/Post/edit.twig L13 「|safe」→「|raw」
// src/Bundle/Balibali/BlogBundle/Resources/views/Post/manage.twig L27 「|safe」→「|raw」
// src/Bundle/Balibali/BlogBundle/Resources/views/Post/show.twig L9 「|safe」→「|raw」
// src/Bundle/Balibali/BlogBundle/Resources/views/Post/new.twig L12 「|safe」→「|raw」

// 「Fatal error: Call to undefined method Bundle\Balibali\BlogBundle\Form\PostForm::setRenderer() 」の修正
// src/Bundle/Balibali/BlogBundle/Form/PostForm.php L34
[phpcode]
$this->setRenderer(new DivRenderer());
// ↓setRenderer()メソッドはもうないらしいので、とりあえずコメントアウト
//$this->setRenderer(new DivRenderer());
[/phpcode]

// フォームが表示されない修正
// src/Bundle/Balibali/BlogBundle/Resources/views/Post/new.twig

  1. <form action="{% path 'balibali_blog_backend_create' %}" method="post">
  2. {{ form.render|raw }}
  3. // ↓
  4. <form action="{% path 'balibali_blog_backend_create' %}" {{ form|render_enctype }} method="post">
  5. {{ form|render }}

// src/Bundle/Balibali/BlogBundle/Resources/views/Post/edit.twig L13

  1. {{ form.render|raw }}
  2. // ↓
  3. {{ form|render }}

たぶん、こでで動くように成りました!

いやー長かった。エラーを自力で解決するのは、いい勉強になりました。

About: uechoco