Help us understand the problem. What is going on with this article?

PHP7 + Doctrine ODMでMongoDBを使う

More than 3 years have passed since last update.

Symfony Advent Calendar 2016 8日目の記事です。


SymfonyでMongoDBを扱う場合、Doctrine ODM(Object Document Mapper)を使うと、ORMと同様のAPIで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を扱うこともできます。詳細は公式ドキュメントを参照してください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした