serebro / reach-mongo
MongoDB ODM
0.9
2014-12-16 22:07 UTC
Requires
- php: >=5.4.0
- ext-mongo: >=1.5
- serebro/reach-common: dev-master
Requires (Dev)
- athletic/athletic: dev-master
- chriskite/phactory: dev-master
- phpunit/phpunit: ~4.0
- satooshi/php-coveralls: dev-master
This package is not auto-updated.
Last update: 2024-11-05 03:38:18 UTC
README
Requirements
- PHP >= 5.4;
- ext-mongo >= 1.5
The key feature list:
- Simple, Powerful, Ultrafast
- Support of schema-less documents
- Ability to use efficient result set iterator instead of raw arrays of results
- Lazy loading/creating of documents
- Support for partial loading of documents from DB
- Unit of work (Reduce the number of database requests/updates. Prevent redundant requests and multiple updates to the same document)
- References and embeds
- Events (system:
before*()
,after*()
; custom:on()
,off()
,trigger()
) - Query builder
- Extensions: Reach can be customized infinitely with behaviours.
- Creating an auto-incrementing sequence field
- Batch inserting, Pagination, Logging
- Integration with IDEs
Installation
{ "require": { "serebro/reach-mongo": "dev-master" } }
$config = [ 'class' => '\Reach\Mongo\Connection' 'database' => 'testing', 'host' => 'localhost', 'port' => 27017, ]; \Reach\Service\Container::register('mongo', $config);
Basic usage
<?php // Create model $client = new Client(); $client->name = 'Google'; // or $client = new Client(['name' => 'Yandex']); // or $client = new Client(); $client->setName('Google')->setDescription('Good Corporation'); // Save $client->save(); // Count the number of active clients echo Client::count(['status' => Client::STATUS_ACTIVE]); // 1000 // Get customers as an array $array = Client::find()->limit(3)->asArray(); // Get a list of the top 10 active clients sorted in alphabetical order $clients = Client::find(['status' => Client::STATUS_ACTIVE])->sort(['name' => 1])->limit(10); echo $clients->count(); // 10 echo count($clients); // 10 // Get an array of "_id" all clients $array_of_mongo_ids = $clients->pluck('_id'); // Convert a list of customers in the array and delete the two attribute $array_document = $clients->toArray(['exclude' => ['balance', 'partners']]); // Merge the results of queries $clients_inactive = Client::find(['status' => Client::STATUS_INACTIVE])->limit(2); $clients = $clients->mergeWith($clients_inactive); echo $clients->count(); // 12 // Iterate through the list of clients foreach($clients as $client) { echo $client->name; } // or $clients->map(function($client){ echo $client->name; }); // Additional information about the query used indexes, etc. $clients->explain(); // Get one customer from the database $client = Client::findOne(['status' => Client::STATUS_ACTIVE]); $client = Client::findOne($mongoId); // Deleting $client->delete(); Client::deleteAll(['status' => Client::STATUS_INACTIVE]);
Create your model
<?php class Client extends \Reach\Mongo\Document { const STATUS_INACTIVE = 0; const STATUS_ACTIVE = 1; // Attributes /** @var \MongoId */ public $_id; /** @var int */ public $sequence_id; public $status = self::STATUS_INACTIVE; public $name = ''; public $balance = 0; /** @var \Reach\Mongo\Behavior\LangText */ public $description; /** @var \City */ public $city; /** @var \Partners[] */ public $partners = []; /** @var \MongoDate */ public $created_at; /** @var \MongoDate */ public $updated_at; // Behaviors and relations public function behaviors() { return [ // Create an auto-incrementing sequence field 'sequence_id' => ['class' => '\Reach\Mongo\Behavior\Generator\SequenceId'], 'city' => ['class' => Relation::REF_PK, 'ref' => '\City', 'key' => 'city_id'], 'partners' => ['class' => Relation::REF_MANY, 'ref' => '\Partner'], 'description' => ['class' => '\Reach\Mongo\Behavior\LangText'], ]; } // Methods public static function getCollectionName() { return 'client'; } public function beforeInsert() { $this->created_at = new \MongoDate(); return parent::beforeInsert(); } public function beforeUpdate() { $this->updated_at = new \MongoDate(); return parent::beforeUpdate(); } public function toArray(array $params = []) { $array = parent::toArray($params); $array['created_at'] = self::date($this->created_at->sec); $array['updated_at'] = self::date($this->updated_at->sec); return $array; } }
Query Builder
<?php $criteria1 = new \Reach\Mongo\Criteria(); $criteria1->addOr(['status' => Client::STATUS_INACTIVE]); $criteria1->addOr('created', '<', new \MongoDate()); $criteria2 = new \Reach\Mongo\Criteria(); $criteria2->orderBy(['title' => -1]); $criteria2->add($criteria1); $query = TestSchema::query($criteria2); $resultSet = $query->all()->limit(2);
Criteria methods
add()
- Joins query clauses with a logical AND returns all documents that match the conditions of both clauses.addOr()
- Joins query clauses with a logical OR returns all documents that match the conditions of either clause.addNor()
- Joins query clauses with a logical NOR returns all documents that fail to match both clauses.where()
- Matches documents that satisfy a JavaScript expression.orderBy()
- Returns a cursor with documents sorted according to a sort specification.comment()
- Adds a comment to the query to identify queries in the database profiler output.hint()
- Forces MongoDB to use a specific index.maxScan()
- Limits the number of documents scanned.maxTimeMS()
- Specifies a cumulative time limit in milliseconds for processing operations on a cursor.max()
- Specifies an exclusive upper limit for the index to use in a query.min()
- Specifies an inclusive lower limit for the index to use in a query.
Query methods
all()
-one()
-asArray()
-
Scopes
Two steps are required to define a scope.
First create a custom query class for your model and define the needed scope methods in this class.
<?php class ClientQuery extends \Reach\Mongo\Query { public function active($status = Client::STATUS_ACTIVE) { $this->add(['status' => $status]); return $this; // it is important } }
Second, override \Reach\Mongo\Document::query() to use the custom query class instead of the regular.
<?php class Client extends \Reach\Mongo\Document { public static function query(CriteriaInterface $criteria = null) { return new ClientQuery($criteria, get_called_class()); } }
Using
<?php $activeClients = Client::query()->active()->find(); $inactiveClients = Client::query()->active(false)->find();
Connecting
<?php $config = [ 'class' => '\Reach\Mongo\Connection' 'database' => 'testing', 'host' => 'localhost', 'port' => 27017, 'username' => 'root', // or null 'password' => 'wut5oot5fo1hec', // or null 'options' => ['connect' => true, 'socketTimeoutMS' => 60000], 'connection_attempts' => 3, 'connection_timeout' => 1, // seconds ]; \Reach\Service\Container::register('mongo', $config);
Getting instance of connection
<?php $connection = \Reach\Service\Container::get('mongo'); $db_name = $connection->getDbName(); // Getting instance of native MongoDB class $clientMongoCollection = $connection->getMongoCollection('client');
Connecting to another database
<?php $connection_name = 'logs'; \Reach\Service\Container::register($connection_name, $logs_config); $logsСonnection = \Reach\Service\Container::get($connection_name); // Getting document from another connection $client = Client::getCollection($connection_name)->findOne($id);
Unit of work
<?php \Reach\Mongo\Buffer::open(); $client = new Client(['_id' => 1, 'name' => 'Yandex']); $client->save(); $client->name = 'Google'; $client->save(); \Reach\Mongo\Buffer::flush(); \Reach\Mongo\Buffer::close();
Events
<?php $client = new Client(); $func1 = function($event){ echo 'fn #1 '; }; $func2 = function($event){ echo 'fn #2'; }; $client->on('add_new_partner', $func1); $client->on('add_new_partner', $func2); $client->partner[] = 'Google'; $client->trigger('add_new_partner'); // fn #1 fn #2
System events
init
afterFind
beforeInsert
afterInsert
beforeUpdate
afterUpdate
beforeSave
afterSave
beforeDelete
afterDelete
Caching with MongoDB
<?php $cache = new \Reach\Mongo\Cache(); $ttl = 60; // seconds $cache->set('key', ['info' => 123], $ttl); $cache->get('key'); // ['info' => 123] $cache->delete('key') // true $cache->get('key'); // null // To initialize cache collection $cache->initCollection();
Pagination
<?php $active = (int)$_GET['active']; // 1 $limit = (int)$_GET['limit']; // 10 $current_page = (int)$_GET['current']; // 2 $resultSet = Client::find(['active' => $active]); // Setting filter $paginator = new \Reach\Mongo\Paginator($resultSet, $limit, $current_page); // Create pagination instance $page = $paginator->getPaginate(); echo $page->first; // 1 echo $page->current; // 2 echo $page->next; // 3 echo $page->prev; // 1 echo $page->last; // 10 echo $page->pages; // 10 echo $page->total_items; // 100 echo count($page->items); // 10 $page->items; // \Reach\Mongo\ResultSet
Benchmarking
Roadmap
- Two Phase Commits (transaction)
- Behaviors: soft delete, alnum id generator
- Queries: geo
- GridFS