This extension originally started as a fork of YiiMongoDbSuite, written by canni and further improved by several developers.
This extension will add (one day) full featured Mongo DB support for Yii.
The goal of this extension is to cleanup and merge some of the various Mongo DB extensions available for Yii, and package them into a full-feature suite.
ActiveRecord like support for MongoDB in Yii is nearly complete, and has had (some) bug testing and fixing.
There isn't a way to do free-form queries, this will be added.
Use of Yii helpers such as logging, session, and data access are partially supported.
This extension originally started as a fork of YiiMongoDbSuite, written by canni and further improved by several developers (mintao, et al). YiiMongoDbSuite originally started as a fork of MongoRecord extension written by tyohan, to fix some major bugs, and add full featured suite for MongoDB developers.
PLEASE refer to the new FULL-Documentation page
Work-around for using the OR operator with this extension provided in comments
The current version is 1.4.1.
$set operator/featureEMongoPartialDocument class, that supports full-featured partial loading of documents from DBIMPORTANT: The version on GitHub is more up to date as fixes are pushed to the project. This may or may not get updated on a regular basis
In your protected/config/main.php config file. Comment out (or delete) the current 'db' array for your database in the components section, and add the following to the file:
~~~ [php] 'import' => array( ... 'ext.YiiMongoDbSuite.*', ), 'components' => array( ... 'mongodb' => array( 'class' => 'EMongoDB', 'connectionString' => 'mongodb://localhost', 'dbName' => 'myDatabaseName', 'fsyncFlag' => true, 'safeFlag' => true, 'useCursor' => false ), ), ~~~
'connectionString' => 'mongodb://username@xxx.xx.xx.xx' where xx.xx.xx.xx is
the ip (or hostname) of your webserver or host.That's all you have to do for setup. You can use it very much like the active record. For example:
~~~ [php] $client = new Client(); $client->first_name='something'; $client->save(); $clients = Client::model()->findAll(); ~~~
Just define following model:
~~~ [php] class User extends EMongoDocument { public $login; public $name; public $pass;
// This has to be defined in every model, this is same as with standard Yii ActiveRecord
public static function model($className=__CLASS__)
{
return parent::model($className);
}
// This method is required!
public function getCollectionName()
{
return 'users'; // should be lowercase.
}
// same as CActiveRecord
public function rules()
{
return array(
array('login, pass', 'required'),
array('login, pass', 'length', 'max' => 20),
array('name', 'length', 'max' => 255),
);
}
// same as CActiveRecord
public function attributeLabels()
{
return array(
'login' => 'User Login',
'name' => 'Full name',
'pass' => 'Password',
);
}
}
~~~
And that's it! Now start using this User model class like standard Yii AR model.
NOTE: For performance reasons embedded documents should extend from EMongoEmbeddedDocument instead of EMongoDocument.
EMongoEmbeddedDocument is almost identical as EMongoDocument, in fact EMongoDocument extends from EMongoEmbeddedDocument and adds to it the DB connection and related functions.
NOTE: Embedded documents should not have a static model() method!
So if you have a User.php model, and an UserAddress.php model which is the embedded document. Lest assume we have following embedded document:
~~~ [php] class UserAddress extends EMongoEmbeddedDocument { public $city; public $street; public $house; public $apartment; public $zip;
public function rules()
{
return array(
array('city, street, house', 'length', 'max'=>255),
array('house, apartment, zip', 'length', 'max'=>10),
);
}
public function attributeLabels()
{
return array(
'zip'=>'Postal Code',
);
}
}
~~~
Now we can add this method to our User model from previous section:
~~~ [php] class User extends EMongoDocument { ...
public function embeddedDocuments()
{
return array(
// property name => embedded document class name
'address'=>'UserAddress'
);
}
...
}
~~~
And using it is as easy as π!
~~~ [php] $client = new Client; $client->address->city='New York'; $client->save(); ~~~
This will automatically call validation for the model and all its embedded documents. You can even nest embedded documents in embedded documents, just define embeddedDocuments() method with array of another embedded documents. IMPORTANT: This mechanism uses recurrency, and will not handle circular nesting, so use this feature with care :P
You easily can store arrays in DB!
Simple arrays
Arrays of embedded documents
~~~ [php] // add a property for your array of embedded documents public $addresses;
// add EmbeddedArraysBehavior
public function behaviors()
{
return array(
array(
'class'=>'ext.YiiMongoDbSuite.extra.EEmbeddedArraysBehavior',
'arrayPropertyName'=>'addresses', // name of property
'arrayDocClassName'=>'ClientAddress' // class name of documents in array
),
);
}
~~~
So for the user, if you want them to be able to save multiple addresses, you can do this:
~~~ [php] $c = new Client; $c->addresses[0] = new ClientAddress; $c->addresses[0]->city='NY'; $c->save(); // behavior will handle validation of array too ~~~
or
~~~ [php] $c = Client::model()->find(); foreach($c->addresses as $addr) { echo $addr->city; } ~~~
This is one of the things that makes this extension great. It's very easy to query for the objects you want.
~~~ [php] // simple find first. just like normal AR. $object = ModelClass::model()->find() ~~~
Now suppose you want to only retrieve users, that have a status of 1 (active). There is an object just for that, making queries easy.
~~~ [php] $c = new EMongoCriteria; $c->status('==', 1); $users = ModelClass::model->findAll($c); ~~~
and now $users will be an array of all users with the status key in their document set to 1. This is a good way to list only active users. What's that? You only want to show the 10 most recent activated users? Thats easy too.
~~~ [php] $c = new EMongoCriteria; $c->active('==', 1)->limit(10);
$users = ModelClass::model->findAll($c);
~~~
It's that easy. In place of the 'equals' key, you can use any of the following operators:
~~~ - 'greater' | > - 'greaterEq' | >= - 'less' | < - 'lessEq' | <= - 'notEq' | !=, <> - 'in' | - 'notIn' | - 'all' | - 'size' | - 'exists' | - 'type' | // BSON type see mongodb docs for this - 'notExists' | - 'mod' | % - 'equals' | == - 'where' | // JavaScript operator ~~~
*NOTICE: the $or operator in newer versions of mongodb does NOT work with this extension yet. We will add it to the list above when it is fixed. Newer versions of MongoDB will work, just not the $or operator. For examples and use for how to use these operators effectively, use the MongoDB Operators Documentation here.
Here are a few more examples for using criteria:
~~~ [php] // first you must create a new criteria object $criteria = new EMongoCriteria;
// find the single user with the personal_number == 12345
$criteria->personal_number('==', 12345);
// OR like this:
$criteria->personal_number = 12345;
$user = User::model->find($criteria);
// find all users in New York. This will search in the embedded document of UserAddress
$criteria->address->city('==', 'New York');
// Or
$criteria->address->city = 'New York';
$users = User::model()->findAll($criteria);
// Ok now try this. Only active users, only show at most 10 users, and sort by first name, descending, and offset by 20 (pagination):
// note the sort syntax. it must have an array value and use the => syntax.
$criteria->status('==', 1)->limit(10)->sort(array('firstName' => EMongoCriteria::SORT_DESC))->offset(20);
$users = User::model()->findAll($criteria);
// A more advanced case. All users with a personal_number evenly divisible by 10, sorted by first name ascending, limit 10 users, offset by 25 users (pagination), and remove any address fields from the returned result.
$criteria->personal_number('%', array(10, 0)) // modulo => personal_number % 10 == 0
->sort(array('firstName' => EMongoCriteria::SORT_ASC))
->limit(10)
->offset(25);
$users = User::model()->findAll($criteria);
// You can even use the where operator with javascript like so:
$criteria->fieldName('where', ' expression in javascript ie: this.field > this.field2');
// but remember that this kind of query is a bit slower than normal finds.
~~~
You can use native PHP Mongo driver class MongoRegex, to query:
~~~ [php] // Create criteria $criteria = new EMongoCriteria; // Find all records witch have first name starring on a, b and c, case insensitive search $criteria->first_name = new MongoRegex('/[abc].*/i'); $clients = Client::model()->findAll($criteria); // see phpdoc for MongoRegex class for more examples ~~~
for reference on how to use query array see: http://www.php.net/manual/en/mongocollection.find.php
~~~ [php] // Example criteria $array = array( 'conditions'=>array( // field name => operator definition 'FieldName1'=>array('greaterEq' => 10), // Or 'FieldName1'=>array('>=', 10) 'FieldName2'=>array('in' => array(1, 2, 3)), 'FieldName3'=>array('exists'), ), 'limit'=>10, 'offset'=>25, 'sort'=>array('fieldName1'=>EMongoCriteria::SORTASC, 'fieldName4'=>EMongoCriteria::SORTDESC), ); $criteria = new EMongoCriteria($array); // or $clients = ClientModel::model()->findAll($array); ~~~
We stand upon the shoulders of giants: