mawelous/yamop

PHP的另一个MongoDB ODM。没有不必要的功能,易于连接。

0.2.1 2013-11-27 10:39 UTC

This package is not auto-updated.

Last update: 2024-09-28 13:35:31 UTC


README

PHP的另一个MongoDB ODM

这是什么?

这是另一个开源且非常简单的MongoDB ODM。它的工作方式与标准的MongoDB PHP扩展接口相同,但返回对象而不是数组(作为ODM)。查询保持不变。它最酷的功能之一是连接,允许您查询相关对象。

功能列表

需求

  • PHP 5.3+
  • PHP MongoDB 扩展

安装

您可以直接从这里下载或使用Composer

composer.json文件中的require键中添加以下内容

    "mawelous/yamop": "dev-master"

保存并运行Composer更新命令

$ composer update

Composer完成后,您只需要将以下行添加到您的代码中

    $connection = new \MongoClient( 'your_host' );
    \Mawelous\Yamop\Mapper::setDatabase( $connection->your_db_name );

您可以将任何MongoDB实例传递给setDatabase函数。

现在,在您的任何模型中扩展Mawelous\Yamop\Model

    class User extends \Mawelous\Yamop\Model
    {
        protected static $_collectionName = 'users';    
    }

就这样!

##使用方法

每个对象都有一个_id,它是一个MongoId,以及一个id键,它是其字符串表示。

MongoDB中的每个文档都作为对象返回,每个键都是一个属性——以下是一个MongoDB中的示例文档

     {
       "_id": ObjectId("51b6ea4fb7846c9410000001"),
       "name": "John Doe",
       "birthdate": ISODate("2013-05-25T12:15:25.0Z"),
       "email": "john@something.com"
    }    

上述文档在PHP中的表示如下

    object(User)[44]
      public '_id' => 
        object(MongoId)[46]
          public '$id' => string '51b6ea4fb7846c9410000001' (length=24)
      public 'name' => string 'John Doe' (length=8)
      public 'birthdate' => 
        object(MongoDate)[47]
          public 'sec' => int 1369484125
          public 'usec' => int 0
      public 'email' => string 'john@something.com' (length=18)
      public 'id' => string '51b6ea4fb7846c9410000001' (length=24)

有几种方法可以将属性传递给对象

    // properties as array
    $user = new User( array( 'name' => 'John', 'email' => 'email@email.com' ) );
    
    // or each property separately
    $user = new User;
    $user->name = 'John';
    $user->email = 'email@email.com';

从版本0.2.1开始(不包括它),当尝试获取不存在的属性时,Yamop返回null

获取数据

想要通过id获取文档?有一种简单的方法。

    $user = User::findById( '51a61930b7846c400f000002' )
    //or
    $mongoId = new MongoId( '51a61930b7846c400f000002' );
    $user = User::findById( $mongoId )

通过查询获取单个文档也很简单。方法findOne与原生的findOne完全相同,但返回一个对象。作为第二个参数,您可以传递一个字段数组。这意味着参数和查询保持不变,这非常好!

    $user = User::findOne( array( 'email' => 'user@mail.com' ) );
    //or
    $user = User::findOne( array( 'email' => 'user@mail.com' ), array( 'email', 'username', 'birthdate' ) );

介绍Mapper

Yamop中有一个Mapper类,它负责检索数据。我将它从Model中分离出来,使其成为一个数据容器。如果您想要创建更复杂的查询,请使用mapper。您可以通过使用getMapper方法或通过传递模型类字符串创建它的新实例来获取它。

    //first possibility
    $mapper = User::getMapper();
    //second possibility
    $mapper = new Mawelous\Yamop\Mapper( 'User' );

查找方法

前面为Model引入的findOne方法是Mapper的方法。Model只是引用它。您可以这样调用它

    //findOne with Mapper
    $user = User::getMapper()->findOne( array( 'email' => 'user@mail.com' ) );

存在一个可以获取多个文档的 find 方法。它也像本地 find 一样工作,但返回一个 Mapper。您可以在其上执行其他操作,如 sortlimitskip,它们都像本地一样工作。要获取对象数组,请使用 get 方法。

    //You can call it directly with Model
    $messages = Message::find( array( 'to_id' => new MongoId( $stringId ), 'to_status' => Message::STATUS_UNREAD ) )
        ->sort( array( 'created_at' => -1 ) )
        ->limit( 10 )
        ->get(); 

    //or using Mapper itself
    $messages = Message::getMapper()
        ->find( array( 'to_id' => new MongoId( $stringId ), 'to_status' => Message::STATUS_UNREAD ) )
        ->sort( array( 'created_at' => -1 ) )
        ->limit( 10 )
        ->get(); 

findAndModify 与本地 findAndModify 相同,但用于对象。

保存、更新和删除

save 方法用于创建和更新对象。以下代码用于创建新对象并将其写入数据库:

    $user = new User( array( 'name' => 'John', 'email' => 'email@email.com' ) );
    $user->save();

您可以在 save 后立即获取新创建对象的 _id

删除很简单

    $user->remove();

这些方法返回的结果与本地 removesave 方法相同。如果您想更新多个文档,请使用本地的函数,例如 这里

扩展 Mapper

如果您想添加更多方法,可以扩展 Mapper。例如,我创建了 UserMapper,它有一个在用户的 Facebook 墙上发布消息的方法。只需让 Mapper 知道要使用哪个 Model 类。

class UserMapper extends Mawelous\Yamop\Mapper
{   
    protected $_modelClassName = 'User';    
    
    public function findActiveUsers( $limit = 10, $sort = 'birthdate' )
    {
        //method code
    }    
}    

如果您想为模型注册不同的 Mapper,只需在模型中声明它。

class User extends Model
{
    ...
    protected static $_mapperClassName = 'UserMapper';
    ...

现在只需执行 Mapper

    $mapper = User::getMapper();
    //and then
    $mapper->findActiveUsers( 5 );

这将返回一个 UserMapper 实例。您也可以创建一个新的 mapper。

    $userMapper = new UserMapper; 
    //and then
    $userMapper->findActiveUsers( 5 );

计数、索引、多更新和其他

所有在 Mapper 上调用但不存在的方法都传递给原始的 MongoCollection。因此,您可以直接使用本地方法来使用 updatecountbatchInsertensureIndexdrop

    //count
    Message::getMapper()->count( array( 'to_id' => $userId, 'to_status' => Message::STATUS_UNREAD ) );
    //update
    Contest::getMapper()->update(
            array('status' => Contest::STATUS_READY_DRAFT,
                  'start_date' => array ('$lte' => new MongoDate(strtotime('midnight')) )),
            array('$set' => array( 'status' => Contest::STATUS_ACTIVE) ),
            array('multiple' => true)
        );
    //drop
    Contest::getMapper()->drop();

内嵌对象

您当前对象内部是否有更多对象?Yamop 会自动转换。只需让它知道。

class User extends \Mawelous\Yamop\Model
{
    protected static $_collectionName = 'users';

    // One Address object embedded in address property
    protected static $_embeddedObject = array (
        'address' => 'Address',
    );
    // Many Notification objects embedded in array that is kept ass notifications
    protected static $_embeddedObjectList = array (
        'notifications' => 'Notification',
    );
}     

然后它将转换 address 字段中嵌入的对象到 Address PHP 对象,并将 notifications 对象数组转换为 Notification PHP 对象数组。所有嵌入的对象都可以是纯模型 - 它们只能扩展 \Mawelous\Yamop\Model

相关对象

如果对象之间存在关系(有时有),并且您想“连接”它们,这比您预期的要简单,即使是与 MongoDB 一起。您只需要在基本对象中保持相关对象的 MongoId

您不需要在任何地方注册它。在我看来,最好明确这样做并避免在后台进行查询。

这是魔法

一个

每个 Model 中的 joinOne 方法接受三个参数。第一个是保存相关对象 MongoId 的属性的名称,第二个是相关对象类,第三个是可选的,它是连接的属性名称。

    // contest_id property holds MongoId of related Contest object
    $user = User::findById( new MongoId( $stringId ) )->joinOne( 'contest_id', 'Contest', 'contest')
    // and there it is
    $contest = $user->contest;

多个

每个 Model 中的 joinMany 方法也有三个参数。第一个是保存一个 MongoId 数组的属性的名称,第二个是相关对象类,第三个是可选的,它是连接的属性名称。

    // contests field is array of MongoIds
    $user = User::findById( new MongoId( $stringId ) )->joinMany( 'contests', 'Contest', 'contests')
    // and you have array of contests there
    $contests = $user->contests;

如果您想将项目连接到项目列表,请在 Mapper 中使用 join。参数与 joinOne 中的参数相同。

    $commentsList = Comment::getMapper()
        ->find( array( 'contest_id' => new MongoId( $contestId ) ) )
        ->join( 'user_id', 'User', 'author' )
        ->limit( 10 )
        ->get();

输出格式

默认获取模式将数组转换为对象,但您也可以使用 getArraygetJson 获取数组或 JSON。默认情况下,getArray 返回一个键为 MongoId 的字符串的数组。如果您想接收数字数组,请使用带有 false 参数的 getArray(false)

    //first possibility
    Comment::getMapper()
        ->find( array( 'contest_id' => new MongoId( $contestId ) ) )
        ->getArray();
        
    Comment::getMapper()
        ->find( array( 'contest_id' => new MongoId( $contestId ) ) )
        ->getJson();
    
    /* second possibility
        four fetch types as constants in Mapper
        FETCH_OBJECT
        FETCH_ARRAY
        FETCH_NUMERIC_ARRAY
        FETCH_JSON  
    */
    Comment::getMapper( \Mawelous\Yamop\Mapper::FETCH_JSON )
        ->find( array( 'contest_id' => new MongoId( $contestId ) ) )
        ->get();
        
    /* third possibility */
    Comment::getMapper()
        ->setFetchType(\Mawelous\Yamop\Mapper::FETCH_JSON )
        ->find( array( 'contest_id' => new MongoId( $contestId ) ) )
        ->get();        

您还可以通过调用 getCursor 方法来获取本地的 MongoCursor

分页

Yamop 支持分页,需要您的一点点帮助。它有一个 getPaginator 方法,有三个参数。第一个是每页的项目数量,第二个是当前页码,第三个是你可以传递给分页器的变量。这三个参数都是可选的。

    User::getMapper()
        ->find( 'status' => array ( '$ne' => User::STATUS_DELETED )) )
        ->sort( array( $field => $direction ) )
        ->getPaginator( $perPage, $page, $options );

您的框架可能有自己的分页器。在使用 getPaginator 方法之前,您必须在扩展 Mawelous\Yamop\Mapper 的映射器中实现 _createPaginator 方法。

例如,Laravel 可以这样扩展

<?php

class Mapper extends \Mawelous\Yamop\Mapper
{
    protected function _createPaginator($results, $totalCount, $perPage, $page, $options)
    {
        return \Paginator::make( $results, $totalCount, $perPage ); 
    }
}

时间戳

在我们的对象中通常会有一个 created_atupdated_at 键。如果您想自动设置您的 Model 中的它们,只需声明即可

class User extends Model
{
    ...
    public static $timestamps = true;   
    ....

打印日期和时间

无论您是否有时间戳,您可能仍然想打印日期或时间。建议将日期保持为 MongoDate,这样您就可以使用 getTimegetDate 来打印它,这两个方法都接受两个参数。第一个是 MongoDate 属性名,第二个是一个字符串,表示传递给 PHP date 函数的格式

    //date as string
    $user->getDate( 'birthdate', 'Y/m/d' );
    //time as string
    $user->getTime( 'created_at', 'Y/m/d H:i');
    //time as string using default format set in $dateFormat
    $user->getTime( 'created_at' );    

Mawelous\Yamop\Model 在其公共静态属性 $dateFormat 中定义了默认日期格式,在 $timeFormat 中定义了时间格式。如果您愿意,可以覆盖它们。

事务

实验性! - 这是 Yamop 的一个附加功能,它独立工作。它不支持两阶段提交,但至少它可以撤销更改。

这就是 Mawelous\Yamop\Transaction 的用途。首先,您必须处理错误并在其中运行 rollback 方法。

类似于这样

    set_error_handler( function($code, $error, $file, $line) {
        Transaction::rollback();
        require_once path('sys').'error'.EXT;
        Laravel\Error::native($code, $error, $file, $line);
    });

然后您可以开始使用 add 方法。使用 add,您可以添加代码来撤销您通过保存或更新所做的更改。您可以使用闭包来完成此操作。

以下是一个示例

    User::getMapper()->update(
        array('_id' => array ( '$in' => $userIds )),
        array('$inc' => array ('active_contests' => -1 )),
        array('multiple' => true)
    );
    
    Transaction::add( function () use ( $userIds ) {
        User::getMapper()->update(
            array('_id' => array ( '$in' => $userIds )),
            array('$inc' => array ('active_contests' => 1 )),
            array('multiple' => true)
            );
    });

现在当错误发生时,rollback 将调用所有添加的方法。

高级

多连接

为模型设置不同连接很简单。setDatabase 可以接受 MongoDbMongoDbs 的数组作为参数。数组的键是连接名称。

    $db1 = ( new \MongoClient( 'your_first_host' ) )->first_db;
    $db2 = ( new \MongoClient( 'your_second_host' ) )->second_db;
    \Mawelous\Yamop\Mapper::setDatabase( array( 'default' => $db1, 'special' => $db2 ) );

这是如何在模型中指定连接名称

    protected static $_connectionName = 'special';

如果没有指定,模型将使用第一个连接。

问题

如有任何问题或疑问,请在此处报告

许可证

Yamop 是在 MIT 许可证条款下分发的免费软件