You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
7.5 KiB
266 lines
7.5 KiB
<?php |
|
/** |
|
* @link http://www.yiiframework.com/ |
|
* @copyright Copyright (c) 2008 Yii Software LLC |
|
* @license http://www.yiiframework.com/license/ |
|
*/ |
|
|
|
namespace yii\mongo; |
|
|
|
use yii\base\InvalidParamException; |
|
use yii\base\Object; |
|
use Yii; |
|
|
|
/** |
|
* Collection represents the Mongo collection information. |
|
* |
|
* @author Paul Klimov <klimov.paul@gmail.com> |
|
* @since 2.0 |
|
*/ |
|
class Collection extends Object |
|
{ |
|
/** |
|
* @var \MongoCollection Mongo collection instance. |
|
*/ |
|
public $mongoCollection; |
|
|
|
/** |
|
* Drops this collection. |
|
*/ |
|
public function drop() |
|
{ |
|
$this->mongoCollection->drop(); |
|
} |
|
|
|
/** |
|
* @param array $condition |
|
* @param array $fields |
|
* @return \MongoCursor |
|
*/ |
|
public function find($condition = [], $fields = []) |
|
{ |
|
return $this->mongoCollection->find($this->buildCondition($condition), $fields); |
|
} |
|
|
|
/** |
|
* @param array $condition |
|
* @param array $fields |
|
* @return array |
|
*/ |
|
public function findAll($condition = [], $fields = []) |
|
{ |
|
$cursor = $this->find($condition, $fields); |
|
$result = []; |
|
foreach ($cursor as $data) { |
|
$result[] = $data; |
|
} |
|
return $result; |
|
} |
|
|
|
/** |
|
* Inserts new data into collection. |
|
* @param array|object $data data to be inserted. |
|
* @param array $options list of options in format: optionName => optionValue. |
|
* @return \MongoId new record id instance. |
|
* @throws Exception on failure. |
|
*/ |
|
public function insert($data, $options = []) |
|
{ |
|
$token = 'Inserting data into ' . $this->mongoCollection->getName(); |
|
Yii::info($token, __METHOD__); |
|
try { |
|
Yii::beginProfile($token, __METHOD__); |
|
$this->tryResultError($this->mongoCollection->insert($data, $options)); |
|
Yii::endProfile($token, __METHOD__); |
|
return is_array($data) ? $data['_id'] : $data->_id; |
|
} catch (\Exception $e) { |
|
Yii::endProfile($token, __METHOD__); |
|
throw new Exception($e->getMessage(), (int)$e->getCode(), $e); |
|
} |
|
} |
|
|
|
/** |
|
* Inserts several new rows into collection. |
|
* @param array $rows array of arrays or objects to be inserted. |
|
* @param array $options list of options in format: optionName => optionValue. |
|
* @return array inserted data, each row will have "_id" key assigned to it. |
|
* @throws Exception on failure. |
|
*/ |
|
public function batchInsert($rows, $options = []) |
|
{ |
|
$token = 'Inserting batch data into ' . $this->mongoCollection->getName(); |
|
Yii::info($token, __METHOD__); |
|
try { |
|
Yii::beginProfile($token, __METHOD__); |
|
$this->tryResultError($this->mongoCollection->batchInsert($rows, $options)); |
|
Yii::endProfile($token, __METHOD__); |
|
return $rows; |
|
} catch (\Exception $e) { |
|
Yii::endProfile($token, __METHOD__); |
|
throw new Exception($e->getMessage(), (int)$e->getCode(), $e); |
|
} |
|
} |
|
|
|
/** |
|
* Updates the rows, which matches given criteria by given data. |
|
* @param array $condition description of the objects to update. |
|
* @param array $newData the object with which to update the matching records. |
|
* @param array $options list of options in format: optionName => optionValue. |
|
* @return integer|boolean number of updated documents or whether operation was successful. |
|
* @throws Exception on failure. |
|
*/ |
|
public function update($condition, $newData, $options = []) |
|
{ |
|
$token = 'Updating data in ' . $this->mongoCollection->getName(); |
|
Yii::info($token, __METHOD__); |
|
try { |
|
Yii::beginProfile($token, __METHOD__); |
|
$result = $this->mongoCollection->update($this->buildCondition($condition), $newData, $options); |
|
$this->tryResultError($result); |
|
Yii::endProfile($token, __METHOD__); |
|
if (is_array($result) && array_key_exists('n', $result)) { |
|
return $result['n']; |
|
} else { |
|
return true; |
|
} |
|
} catch (\Exception $e) { |
|
Yii::endProfile($token, __METHOD__); |
|
throw new Exception($e->getMessage(), (int)$e->getCode(), $e); |
|
} |
|
} |
|
|
|
/** |
|
* Update the existing database data, otherwise insert this data |
|
* @param array|object $data data to be updated/inserted. |
|
* @param array $options list of options in format: optionName => optionValue. |
|
* @return \MongoId updated/new record id instance. |
|
* @throws Exception on failure. |
|
*/ |
|
public function save($data, $options = []) |
|
{ |
|
$token = 'Saving data into ' . $this->mongoCollection->getName(); |
|
Yii::info($token, __METHOD__); |
|
try { |
|
Yii::beginProfile($token, __METHOD__); |
|
$this->tryResultError($this->mongoCollection->save($data, $options)); |
|
Yii::endProfile($token, __METHOD__); |
|
return is_array($data) ? $data['_id'] : $data->_id; |
|
} catch (\Exception $e) { |
|
Yii::endProfile($token, __METHOD__); |
|
throw new Exception($e->getMessage(), (int)$e->getCode(), $e); |
|
} |
|
} |
|
|
|
/** |
|
* Removes data from the collection. |
|
* @param array $condition description of records to remove. |
|
* @param array $options list of options in format: optionName => optionValue. |
|
* @return integer|boolean number of updated documents or whether operation was successful. |
|
* @throws Exception on failure. |
|
*/ |
|
public function remove($condition = [], $options = []) |
|
{ |
|
$token = 'Removing data from ' . $this->mongoCollection->getName(); |
|
Yii::info($token, __METHOD__); |
|
try { |
|
Yii::beginProfile($token, __METHOD__); |
|
$result = $this->mongoCollection->remove($this->buildCondition($condition), $options); |
|
$this->tryResultError($result); |
|
Yii::endProfile($token, __METHOD__); |
|
if (is_array($result) && array_key_exists('n', $result)) { |
|
return $result['n']; |
|
} else { |
|
return true; |
|
} |
|
} catch (\Exception $e) { |
|
Yii::endProfile($token, __METHOD__); |
|
throw new Exception($e->getMessage(), (int)$e->getCode(), $e); |
|
} |
|
} |
|
|
|
/** |
|
* Checks if command execution result ended with an error. |
|
* @param mixed $result raw command execution result. |
|
* @throws Exception if an error occurred. |
|
*/ |
|
protected function tryResultError($result) |
|
{ |
|
if (is_array($result)) { |
|
if (!empty($result['err'])) { |
|
throw new Exception($result['errmsg'], (int)$result['code']); |
|
} |
|
} elseif (!$result) { |
|
throw new Exception('Unknown error, use "w=1" option to enable error tracking'); |
|
} |
|
} |
|
|
|
/** |
|
* Converts user friendly condition keyword into actual Mongo condition keyword. |
|
* @param string $key raw condition key. |
|
* @return string actual key. |
|
*/ |
|
protected function normalizeConditionKeyword($key) |
|
{ |
|
static $map = [ |
|
'or' => '$or', |
|
'>' => '$gt', |
|
'>=' => '$gte', |
|
'<' => '$lt', |
|
'<=' => '$lte', |
|
'!=' => '$ne', |
|
'<>' => '$ne', |
|
'in' => '$in', |
|
'not in' => '$nin', |
|
'all' => '$all', |
|
'size' => '$size', |
|
'type' => '$type', |
|
'exists' => '$exists', |
|
'notexists' => '$exists', |
|
'elemmatch' => '$elemMatch', |
|
'mod' => '$mod', |
|
'%' => '$mod', |
|
'=' => '$$eq', |
|
'==' => '$$eq', |
|
'where' => '$where' |
|
]; |
|
$key = strtolower($key); |
|
if (array_key_exists($key, $map)) { |
|
return $map[$key]; |
|
} else { |
|
return $key; |
|
} |
|
} |
|
|
|
/** |
|
* Builds up Mongo condition from user friendly condition. |
|
* @param array $condition raw condition. |
|
* @return array normalized Mongo condition. |
|
* @throws \yii\base\InvalidParamException on invalid condition given. |
|
*/ |
|
public function buildCondition($condition) |
|
{ |
|
if (!is_array($condition)) { |
|
throw new InvalidParamException('Condition should be an array.'); |
|
} |
|
$result = []; |
|
foreach ($condition as $key => $value) { |
|
if (is_array($value)) { |
|
$actualValue = $this->buildCondition($value); |
|
} else { |
|
$actualValue = $value; |
|
} |
|
if (is_numeric($key)) { |
|
$result[] = $actualValue; |
|
} else { |
|
$key = $this->normalizeConditionKeyword($key); |
|
if (strncmp('$', $key, 1) !== 0 && array_key_exists(0, $actualValue)) { |
|
// shortcut for IN condition |
|
$result[$key]['$in'] = $actualValue; |
|
} else { |
|
$result[$key] = $actualValue; |
|
} |
|
} |
|
} |
|
return $result; |
|
} |
|
} |