在使用PHP7 + Doctrine ODM时,使用MongoDB

这是 Symfony Advent Calendar 2016 的第八篇文章。


如果要在Symfony中处理MongoDB,可以使用Doctrine ODM(Object Document Mapper),它可以以类似ORM的API来处理MongoDB。

需要的东西 de

    • 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文件中添加以下两行内容。

{
    "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上被指出。

进行安装时,请执行composer update –ignore-platform-reqs命令。
–ignore-platform-reqs是一个选项,可以忽略PHP版本和PHP扩展等依赖关系检查。
由于doctrine/mongodb的composer.json文件中指定了ext-mongo(PHP5的MongoDB驱动程序)作为依赖库,因此在无法使用这个库的PHP7中,需要使用上述选项。

用中文翻译以上内容:
Symfony的配置设置

自动装载器设置 qì

// app/autoload.php
use Doctrine\ODM\MongoDB\Mapping\Driver\AnnotationDriver;
AnnotationDriver::registerAnnotationClasses();

将AppKernel注册到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。详情请参考官方文档。

广告
将在 10 秒后关闭
bannerAds