$ composer require martynbiz/php-mongo
\MartynBiz\Mongo\Connection::getInstance()->init(array(
'db' => 'mydb',
'username' => 'myuser',
'password' => '89dD7HH7di!89',
'classmap' => array(
'users' => '\\App\\Model\\User',
),
));
Create models by extending the Mongo class, be sure to define $collection and $whitelist:
<?php
use MartynBiz\Mongo;
class User extends Mongo
{
// required - collection this model refers to
protected static $collection = 'users';
// required - define on the fields that can be saved
protected static $whitelist = array(
'name',
'email',
'username',
'password',
);
}
If only using a single database, this is not neccessary. However, if you need to connect to multiple databases, give a unique name to each connection:
Connection::getInstance('conn1')->init(array(
...
));
// also, checking if an instance exists
if (! Connection::hasInstance('conn2')) {
Connection::getInstance('conn2')->init(array(
...
));
}
Also, remember to declare which $conn in the model:
<?php
use MartynBiz\Mongo;
class User extends mongo
{
// optional - if using multiple connections/databases
protected static $conn = 'conn1';
.
.
.
}
// statically
$users = User::find(array(
'status' => 1,
));
// dynamically
$col = new User();
$users = $col->find(array(
'status' => 1,
));
// statically
$user = User::findOne(array(
'email' => 'info@examle.com',
));
// dynamically
$col = new User();
$user = $col->findOne(array(
'email' => 'info@examle.com',
));
Model instances can also be passed, the find method will convert it to DBRef internally (e.g. 'friend' => $friend will do the same as 'friend' => $friend->getDBRef())
$friend = User::findOne(array(
//...
));
$user = User::find(array(
'friend' => $friend,
));
// setting
// on instantiation -- will be filtered against $whitelist
$article = new Article(array(
'title' => 'My title',
));
$author = User::findOne(array(
//...
));
// single value properties -- no param filtering
$article->status = 2;
$article->author = $author;
// AND/OR set() method, with Mongo instance -- suited for unit testing, no param filtering
$user = User::findOne(array(
//...
));
$article->set('author', $author);
// set value as query result (will be stored as an array of dbrefs)
$tags = Tag::find(array(
//...
));
$article->tags = $tags;
// lastly, params can be passed with save() -- will be filtered against $whitelist
$article->save(array(
'content' => $text,
))
// getting
$article = Article::findOne(array(
//...
));
// single value properties -- no param filtering
echo $article->status;
echo $article->author->name;
echo $article->tags[0]->name;
echo $article->get('author');
Save method is used on an instantiated object of the model class. It can be called after assigning values to properties, or by passing name/values as arguments. Note: when passing name/values, values will be whitelisted
$user->name = 'Jim';
$user->save();
$user->save(array(
'name' => 'Jim',
));
Create method doesn't require an instance, by will accept name\values upon which it will insert into the collection. It will return an instance of the created document. Note: when passing name/values, values will be whitelisted
// statically
$user = User::create(array(
'name' => 'Jim',
));
// dynamically (e.g. service locator pattern, or DI)
$col = new User();
$user = $col->create(array(
'name' => 'Jim',
));
Factory method doesn't actually insert, but will generate an instance with values. It can then be altered and inserted with it's save method:
// statically
$user = User::factory(array(
'name' => 'Jim',
));
// dynamically
$col = new User();
$user = $col->factory(array(
'name' => 'Jim',
));
$user->save();
Although having multiple methods may seem a little much, it does give the option to keep you code tidy and more flexible for mocking methods during testing.
Note: push with $each is the default behaviour here, although this can be overridden with 'each'=>false in the options array (see below)
// push one object, will convert to DBRef
$user->push(array(
'friends' => $friend,
));
// push multi object, will convert to DBRef
$user->push(array(
'friends' => array(
$friend,
$friend2,
),
));
// push MongoIterator object (from find() call)
$user->push(array(
'friends' => $friends,
));
// push multiple properties at once
$user->push(array(
'friends' => $friends,
'enemies' => $enemies,
));
// push without $each setting, will push the whole array as a single element
$user->push(array(
'friends' => array(
$friend,
$friend2,
),
), array('each' => false));
An instance can delete itself from the database with the delete method:
$user->delete();
To delete multiple documents from a collection by query, use the remove method:
User::remove(array(
'type' => 'boring',
), $options);
$user->toArray(3); // convert nested 3 deep to array (optional)
Before saving to the database, the validate method is called. If it returns false, the data will not be saved.
class User extends mongo
{
.
.
.
public function validate()
{
$this->resetErrors();
if (empty($this->data['name'])) {
$this->setError('Name is missing.');
}
return empty( $this->getErrors() ); // true if none
}
}
The following example uses martynbiz/php-validator library here.
<?php
use MartynBiz\Validator;
class User extends mongo
{
.
.
.
public function validate()
{
$this->resetErrors();
$validator = new Validator($this->data);
$validator->check('name')
->isNotEmpty('Name is missing');
$validator->check('email')
->isNotEmpty('Email address is missing')
->isEmail('Invalid email address');
$message = 'Password must contain upper and lower case characters, and have more than 8 characters';
$validator->check('password')
->isNotEmpty($message)
->hasLowerCase($message)
->hasUpperCase($message)
->hasNumber($message)
->isMinimumLength($message, 8);
// update the model's errors with the validators
$this->setError( $validator->getErrors() );
return empty($this->getErrors());
}
}
To automatically convert values when getting, you can define custom methods to automatically convert the value of a property. This may be useful when formatting strings such as dates to human readable.
<?php
use MartynBiz\Mongo;
class User extends Mongo
{
.
.
.
public function getCreatedAt($value)
{
return date('Y-M-d h:i:s', $this->data['created_at']->sec);
}
public function setPassword($value)
{
return password_hash($value, PASSWORD_BCRYPT);
}
}
TODO
- dot syntax support? find(array('model.name' => 'Martyn')), set/get(array(model.name' => 'Martyn'))