lindelius / laravel-mongo
Requires
- illuminate/database: ^5.5
- illuminate/support: ^5.5
- illuminate/validation: ^5.5
- mongodb/mongodb: ^1.1.0
Requires (Dev)
- phpunit/phpunit: 5.5.*
README
用于在 Laravel 和 Lumen 中处理 MongoDB 文档的便利库。
该库基于 官方 MongoDB PHP 库 构建,包括一个抽象模型、处理批量写入的辅助类、Laravel 和 Lumen 的数据库包装器以及一些必要的辅助函数。
请注意,此库不扩展 Eloquent,因为 Eloquent 是为 SQL 数据库设计和编写的。
要求
- PHP 5.6 或更高版本
- MongoDB PHP 驱动程序 1.2.*
- Laravel/Lumen 5.5.*
目录
安装
要安装此库,请在 Laravel 或 Lumen 项目的根目录中运行以下命令
composer require "lindelius/laravel-mongo=^0.4"
安装库后,通过向 config/database.php
文件中的 connections 数组添加以下内容来配置数据库连接(对于 Lumen 安装,您首先必须自己创建 config 目录,然后从 vendor/laravel/lumen-framework/config/
复制 database.php
文件)。如果您想覆盖默认值,还需要将 DB_AUTHSOURCE
和 DB_RSNAME
变量添加到环境文件中。
'mongodb' => [ 'driver' => 'mongodb', 'hosts' => env('DB_HOST', 'localhost:27017'), 'database' => env('DB_DATABASE', 'test'), 'username' => env('DB_USERNAME', ''), 'password' => env('DB_PASSWORD', ''), 'uriOptions' => [ 'authSource' => env('DB_AUTHSOURCE', 'admin'), 'replicaSet' => empty(env('DB_RSNAME')) ? null : env('DB_RSNAME', 'rs1'), ], 'driverOptions' => [], ],
Laravel
对于 Laravel 安装,请将包含的服务提供者添加到 config/app.php
文件中的 providers 数组中。
Lindelius\LaravelMongo\MongoDbServiceProvider::class,
Lumen
对于 Lumen 安装,请将包含的服务提供者添加到 bootstrap/app.php
文件中。
$app->register(Lindelius\LaravelMongo\MongoDbServiceProvider::class);
使用
数据库连接器
配置连接后,可以使用数据库连接器(请参阅安装说明)。通过连接器,您可以从应用程序容器中解析 MongoDB\Client
、MongoDB\Database
和 MongoDB\Collection
实例。
/** * @var Lindelius\LaravelMongo\MongoDbConnection $connection */ $connection = app('db'); /** * @var MongoDB\Client $client * @var MongoDB\Database $database * @var MongoDB\Collection $collection */ $client = $connection->getClient(); $database = $connection->getDatabase(); $collection = $connection->getCollection('collection_name');
批量构建器
批量构建器旨在使更新扩展 Model
类的多个对象变得非常简单。您只需创建一个 BulkBuilder
实例,并使用 BulkBuilder::add()
方法将对象添加到其中。批量构建器将自动选择与第一个添加的对象关联的集合,并在调用 BulkBuilder::execute()
方法时在该集合上执行写操作。
$bulk = new BulkBuilder(); foreach ($jedis as $jedi) { $bulk->add($jedi); } /** * @var MongoDB\BulkWriteResult $result */ $result = $bulk->execute();
该类还包括用于添加自定义写操作的辅助函数(即不直接从 Model
对象中获取的操作)。这些操作可以通过 BulkBuilder::deleteMany()
、BulkBuilder::deleteOne()
、BulkBuilder::insertOne()
、BulkBuilder::replaceOne()
、BulkBuilder::updateMany()
和 BulkBuilder::updateOne()
方法添加到批量中。在这种情况下,您必须手动将集合注入到 BulkBuilder
中,无论是通过其构造函数还是通过 BulkBuilder::setCollection()
方法。
$bulk = new BulkBuilder($collection); foreach ($jedis as $jedi) { $bulk->insertOne(['name' => $jedi->name]); } $bulk->execute();
抽象模型
如前所述,此库还包括一个抽象模型,您可以使用它作为 MongoDB 支持的对象模型的基类。
use Lindelius\LaravelMongo\Model; /** * Class Jedi * * @property string $name */ class Jedi extends Model { /** * The name of the database collection. * * @var string */ protected static $collectionName = 'jedi'; /** * Gives the Jedi a new name, and returns the old one. * * @param string $name * @return string */ public function setName($name) { return $this->updateProperty('name', $name); } /** * Gets the Jedi's current name. * * @return string */ public function getName() { return $this->returnProperty('name'); } }
在扩展了 Model
类并添加了必要的属性(Model::$collectionName
)后,我们现在可以轻松地管理我们的 Jedis。
$jedi = new Jedi(); $jedi->setName('Anakin Skywalker'); // or $jedi->name = 'Anakin Skywalker'; if ($jedi->save()) { echo 'Uh, I think we just made a horrible decision...'; } else { echo 'We failed to teach ' . $jedi->name . ' to use the Force.'; echo 'Oh, well. It was probably for the better.'; }
如上例所示,抽象的 Model
类覆盖了魔法方法 __get()
和 __set()
,允许您像对常规公共属性一样分配和访问对象的字段值。
实例方法
asBulkOperation
这是一个获取任何未保存的对象更新的批量操作格式的便利方法。如果没有要进行的更新,则此方法返回 null
。
delete
Model::delete()
方法允许您从数据库中删除对象。在成功调用时,对象中的 _id
字段以及自动的时间戳字段(如果使用)将被取消设置。所有其他属性仍然在对象上可用,并且它们也将准备好作为“更新”,以防您想再次保存对象。
$masterYoda = new Jedi(); $masterYoda->name = 'Yoda'; // Approximately 900 years later... if ($masterYoda->delete()) { echo 'RIP ' . $masterYoda->name; }
如果您已将此模型的 Model::$softDeletes
设置为 true
,则 deleted_at
字段将设置为当前时间,而不是实际从数据库中删除对象。如果您使用此选项,则实体可以从应用程序知道已删除,但仍然可以保留数据以备以后恢复。
如果您希望硬删除使用软删除的对象,可以通过将 true
作为参数传递给 delete()
方法来实现。
if ($objectUsingSoftDeletes->delete(true)) { echo 'The object has now been deleted from the database.'; }
fill
此方法主要用于内部使用,但可以在任何需要使用属性数组填充模型对象数据的地方使用。
$jedi = new Jedi(); $jedi->fill(['name' => 'Luke Skywalker']);
getCreatedAt
这是一个获取“创建时间”的获取方法,它可以是 DateTime
对象或 null
。
getDeletedAt
这是一个获取“删除时间”的获取方法,它可以是 DateTime
对象或 null
。
getId
这是一个获取模型对象主ID值(即_id
字段)的获取器方法。
getUpdatedAt
这是一个获取“更新时间”日期的获取器方法,该日期可以是DateTime
对象或null
。
isDeleted
这个便利方法检查对象是否已被“软删除”。为了使用软删除,您必须重写Model::$softDeletes
属性并将其设置为true
。
isPersisted
这个便利方法检查对象是否已以前保存到数据库中。
restore
如果对象之前已被“软删除”,则Model::restore()
方法将恢复对象。
if ($objectUsingSoftDeletes->delete()) { echo 'The object has been soft deleted.'; if ($objectUsingSoftDeletes->restore()) { echo 'The object has been restored.'; } }
请注意,如果您将true
传递给Model::delete()
方法,它将完全从数据库中删除对象,这意味着您将无法恢复它。不过,只要您不删除PHP对象,您仍然可以再次保存它。
if ($objectUsingSoftDeletes->delete(true)) { echo 'The object has been hard deleted.'; if ($objectUsingSoftDeletes->save()) { echo 'The object has been saved.'; } }
save
Model::save()
方法将对象保存到数据库。根据模型使用的ID类型以及对象是否已持久化,保存方法将调用两个内部方法之一,即Model::insert()
或Model::upsert()
。您无需自己考虑这一点。无论您只是更新了一个字段,还是从头开始创建了对象并需要插入整个对象,只需调用save()
并让它为您完成一切即可。
$jedi = new Jedi(); $jedi->name = 'Anakin Skywalker'; $jedi->save(); // Saves the entire object // Shit happens... Poor decisions are made... $sith = $jedi; unset($jedi); $sith->name = 'Darth Vader'; $sith->save(); // Just saves the new value for the name field
toArray
这是一个访问内部属性数组的便利方法。
$jedi = new Jedi(); $jedi->name = 'Rey'; var_dump($jedi->toArray()); /** * Outputs: * array(1) { ["name"] => string(3) "Rey" } */
类方法
aggregate
此方法在模型相关集合上执行聚合管道。此方法包装了官方MongoDB PHP库中的Collection::aggregate()
方法。您可以在他们的文档中找到示例和其他使用信息。
count
此方法返回模型的对象计数。如果您只想计算对象的一个子集,您可以在计数查询中添加一个过滤器。
$totalCount = Jedi::count(); $skywalkerCount = Jedi::count(['name' => ['$regex' => 'Skywalker']]);
deleteMany
此方法删除所有与给定过滤器匹配的对象,然后返回被删除的对象数量。默认过滤器是一个空数组,因此如果您不传递自己的过滤器,此方法将删除使用此模型的所有对象。
$yodasDeleted = Jedi::deleteMany(['name' => 'Yoda']); $jedisDeleted = Jedi::deleteMany();
deleteOne
此方法删除第一个与给定过滤器匹配的对象,然后返回被删除的对象数量(1或0)。与Model::deleteMany()
方法类似,过滤器默认为空数组,因此如果您想删除特定的对象,您必须指定一个过滤器。
if (Jedi::deleteOne() === 1) { echo 'A Jedi was deleted.'; } if (Jedi::deleteOne(['name' => 'Mace Windu']) === 1) { echo 'Mace Windu was deleted.'; }
distinct
此方法用于查找与模型关联的集合中给定字段和过滤器下的所有不同值。此方法封装了来自官方 MongoDB PHP 库的 Collection::distinct()
方法。您可以在他们的 文档 中找到示例和其他使用信息。
find
此方法用于查找所有匹配给定过滤器的对象。如果您未指定过滤器,则返回所有对象。
/** * @var Jedi[] $allJedis * @var Jedi[] $skywalkers */ $allJedis = Jedi::find(); $skywalkers = Jedi::find(['name' => ['$regex' => 'Skywalker']]);
findById
此方法通过其主键 ID 查找对象。通常这是一个 MongoDB\BSON\ObjectID
对象。
/** * @var Jedi|null $yoda */ $yoda = Jedi::findById($yodasId); if ($yoda === null) { echo 'Unable to find Master Yoda.'; }
findOne
此方法与 Model::findById()
类似,但您可以在任何地方进行匹配,而不仅仅是主键 ID。如果您要查找特定对象,请确保指定一个过滤器。
/** * @var Jedi|null $yoda */ $yoda = Jedi::findOne(['name' => 'Yoda']); if ($yoda === null) { echo 'Unable to find Master Yoda.'; }
扩展抽象模型
保存后
模型提供了一个方法 —— Model::afterSave()
—— 在每次成功保存操作后触发。此方法将注入一个数组,其中包含在保存操作期间更新的属性字段名称。如果您需要在其他集合或其他任何地方更新数据,请重写此方法。
保存前
模型提供了一个方法 —— Model::beforeSave()
—— 在每次保存操作之前触发。如果您需要在保存前进行任何验证、计算或其他操作,请重写此方法。
连接设置
如前所述(在用法示例中),您必须重写的抽象模型的唯一部分是 Model::$collectionName
属性。只需将其设置为相关 MongoDB 集合的名称即可。
protected static $collectionName = 'name_of_collection';
默认情况下,模型使用包含的 "mongodb" 连接。如果您只需要为您的应用程序使用一个数据库,您不需要进行任何更改。只需确保注册包含的服务提供程序并正确配置 MongoDB 连接(请参阅 安装章节)。但是,如果您的用例需要多个数据库,或者出于某种原因您想要重命名连接,您还必须在模型内部重写默认设置。幸运的是,这非常简单。您只需通过更改静态 Model::$connectionName
属性的值来重写连接的名称。
自定义文档 ID
如果您的模型需要自定义 ID,即除了 MongoDB\BSON\ObjectID
对象之外的其他值,您必须重写 Model::getId()
方法。如果依赖于 ID 的值没有正确设置,您必须确保该方法返回 false
,否则对象将保存为带有不正确的值或 MongoDB\BSON\ObjectID
对象作为其 ID。
public function getId() { $id = $this->returnProperty('_id'); if (empty($id['account']) || empty($id['date'])) { return false; } return $id; }
属性
由于模型的工作方式,对象的属性实际上不是以公共属性的形式存储,而是以键值对的形式存储在内部数组中。由于模型默认重写了魔法方法 __get()
和 __set()
,因此您可以像使用任何普通对象一样使用实例。然而,实际上底层发生的是调用 Model::returnProperty()
和 Model::updateProperty()
方法。
这两个方法都支持点符号来访问嵌套字段,除此之外它们相当直观。请参考 抽象模型 章节的开头部分的 Jedi
类,以了解如何使用它们。
读取偏好
模型对象的读取偏好设置使用 MongoDB 默认值,当前为 "从任何副本集的主节点读取"。但是,您可以通过更改静态属性 Model::$readFromSets
和 Model::$readPreference
,或者重写静态方法 Model::readPreference()
来轻松覆盖此设置。
有关更多信息,请参阅 MongoDB 关于 读取偏好 的文档。
软删除
该模型提供了一个使用“软”删除的选项,这意味着当在应用程序中删除文档时,实际上不会从数据库中删除文档。而不是硬删除文档,而是在文档上设置一个字段(deleted_at
)。可以通过使用方法 Model::isDeleted()
在应用程序中检查文档的状态。
默认情况下,软删除是禁用的,但您可以通过将静态属性 Model::$softDeletes
设置为 true
来启用它。
时间戳
默认情况下,模型自动将时间戳添加到 MongoDB 文档中。时间戳在创建(created_at
)、更新(updated_at
)和软删除(deleted_at
)时添加。字段被填充为 MongoDB\BSON\UTCDateTime
对象,但在将文档加载到 PHP 时自动转换为 DateTime
对象。
您可以通过将静态属性 Model::$timestamps
设置为 false
来关闭自动时间戳。您还可以通过重写静态属性 Model::$timestampFields
来自定义时间戳字段的名称。
protected static $timestampFields = [ 'create' => 'registered_at', 'delete' => 'deactivated_at', 'update' => 'updated_at' ];
取消设置空值字段
由于使用 WiredTiger 存储引擎的数据库(由于其压缩特性)并不实用,因此模型包含一个选项,可以自动取消设置空值字段,而不是存储字段及其值。
此功能默认是禁用的,但您可以通过将静态属性 Model::$unsetNulls
设置为 true
来启用它。
写入关注点
模型对象的写入关注点设置使用 MongoDB 默认值,当前为 "等待 1 服务器确认,但不需要等待日志"。但是,您可以通过更改静态属性 Model::$waitForJournal
和 Model::$writeConcern
,或者重写静态方法 Model::writeConcern()
来轻松覆盖此设置。
有关更多信息,请参阅 MongoDB 关于 写入关注点 的文档。