Symfony Advent Calendar 2016 8日目の記事です。
SymfonyでMongoDBを扱う場合、Doctrine ODM(Object Document Mapper)を使うと、ORMと同様のAPIでMongoDBを扱うことができます。
必要なもの
- MongoDB
- PHP5系+ext-mongo または PHP7系+ext-mongodb
$ mongo --version
MongoDB shell version v3.4.0
$ php -v
PHP 7.1.0 (cli) (built: Dec 2 2016 11:32:42) ( NTS )
$ php -m | grep mongo
mongodb
インストール
Doctrine ODMは単独のライブラリとしても使えますが、ここではDoctrineMongoDBBundleを使って、Symfonyと一緒に使ってみます。
Symfonyのインストール方法については公式サイトを参照してください。
以下はSymfonyインストーラーを使った例です。
$ symfony new doctrine_odm
$ cd doctrine_odm
$ php bin/console --version
Symfony 3.2.0 (kernel: app, env: dev, debug: true)
次にDoctrineMongoDBBundleをインストールします。
PHP5の場合とPHP7の場合で手順が異なります。
PHP5の場合
composer.jsonに以下の2行を追加します。
{
"require": {
"doctrine/mongodb-odm": "^1.1",
"doctrine/mongodb-odm-bundle": "^3.2"
}
}
次に、composer update
を実行します。
PHP7の場合
composer.jsonに以下の3行を追加します。
{
"require": {
"alcaeus/mongo-php-adapter": "^1.0",
"doctrine/mongodb-odm": "^1.1",
"doctrine/mongodb-odm-bundle": "^3.2"
}
}
MongoDBのドライバは、PHP5とPHP7で異なります。
PHP5のext-mongoは、PHP7では動作しません。
逆に、PHP7のext-mongodbもPHP5では使えません。
alcaeus/mongo-php-adapterは、PHP7のMongoDBドライバをPHP5のMongoDBドライバと同様のAPIで使えるようにするアダプタです。
Doctrine ODMはPHP5のMongoDBドライバを前提としているので、PHP7+Doctrine ODMの組み合わせで使うには、このアダプタが必要です。
本アダプタの注意点として、ネイティブの実装に比べてパフォーマンスが低いという問題が指摘されています(GitHub Issues)。
インストールにはcomposer update --ignore-platform-reqs
を実行します。
--ignore-platform-reqs
は、PHPのバージョンやPHP拡張等の依存関係チェックを無視するオプションです。
doctrine/mongodbのcomposer.jsonにはext-mongo(PHP5のMongoDBドライバ)が依存ライブラリとして指定されているため、このライブラリを使えないPHP7では、上記オプションを使用する必要があります。
Symfonyの設定
オートローダー設定
// app/autoload.php
use Doctrine\ODM\MongoDB\Mapping\Driver\AnnotationDriver;
AnnotationDriver::registerAnnotationClasses();
AppKernelに登録
// app/AppKernel.php
public function registerBundles()
{
$bundles = [
// ...
new Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle(),
];
// ...
}
設定ファイル
# app/config/parameters.yml
parameters:
mongodb_server: "mongodb://localhost:27017"
# app/config/config.yml
doctrine_mongodb:
connections:
default:
server: "%mongodb_server%"
options: {}
default_database: test_database
document_managers:
default:
auto_mapping: true
ドキュメントクラスの追加
$ mkdir src/AppBundle/Document
$ touch src/AppBundle/Document/Product.php
Product.phpの中身は以下。Doctrine ORMと同様、アノテーションでマッピング情報を追加します。
<?php
// src/AppBundle/Document/Product.php
namespace AppBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* @MongoDB\Document
*/
class Product
{
/**
* @MongoDB\Id
*/
protected $id;
/**
* @MongoDB\Field(type="string")
*/
protected $name;
/**
* @MongoDB\Field(type="float")
*/
protected $price;
}
以下のコマンドでgetter/setterを生成します。この辺もORMと同じですね。
$ php bin/console doctrine:mongodb:generate:documents AppBundle
実行テスト
src/AppBundle/Command/MongoDBTestCommand.php に、以下の内容のファイルを作成します。
<?php
namespace AppBundle\Command;
use AppBundle\Document\Product;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class MongoDBTestCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('app:mongo-test')
->setDescription('...')
->addArgument('argument', InputArgument::OPTIONAL, 'Argument description')
->addOption('option', null, InputOption::VALUE_NONE, 'Option description')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// データの永続化
$product = new Product();
$product->setName('Foobar');
$product->setPrice(19.99);
$dm = $this->getContainer()->get('doctrine_mongodb')->getManager();
$dm->persist($product);
$dm->flush();
// データ取得
$product = $dm->getRepository('AppBundle:Product')
->findOneBy(['name' => 'Foobar']);
if (!$product) {
$output->writeln('Product not found');
}
var_dump($product->getName(), $product->getPrice());
}
}
上記コマンドで実行確認できます。
$ php bin/console app:mongo-test
MongoDBクライアントでも結果を確認してみましょう。
$ mongo test_database
> db.Product.find();
{ "_id" : ObjectId("584559656adfe57b63216d51"), "name" : "Foobar", "price" : 19.99 }
上記手順で作成したプロジェクトはGitHubで公開しています。
まとめ
以上、Doctrine ODMの基本的な使い方です。基本的なAPIはORMと似ていますが、MongoDB独特のAPIを扱うこともできます。詳細は公式ドキュメントを参照してください。