在使用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。详情请参考官方文档。