Skip to content

Commit

Permalink
Added utils to MongoYii
Browse files Browse the repository at this point in the history
  • Loading branch information
Sammaye committed Nov 1, 2013
1 parent f4e8a13 commit 0985602
Show file tree
Hide file tree
Showing 3 changed files with 500 additions and 0 deletions.
75 changes: 75 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,81 @@ This extension does not rely on `EMongoCriteria` internally.

So I expect all modifications to certain parts of MongoYii to be compatible with and without `EMongoCriteria`.

# Utilities

The `util` folder contains general awesome extensions to MongoYii that people may find useful. The sort of things that count as part of this folder are replacements for internal pieces
of Yii that might seem outside of the scope of the root of this repository.

THESE ARE NOT MADE BY THE AUTHOR OF MONGOYII. That being said I will attempt to maintain them.

## EMongoCache

This is a MongoYii implementation of `CCache` by [Rajcsányi Zoltán](http://ezmegaz.hu/).

To use it first place it in your configuration:

'components'=>array(
...
'cache' => array(
'class'=>'application.extensions.MongoYii.util.EMongoCache',
// 'ensureIndex' => true, //set to false after first use of the cache
// 'mongoConnectionId' => 'mongodb',
// 'collectionName' => 'mongodb_cache',
),
}

The commented out lines are optional parameters you can send in if required.

And now an example of its usage:

// flush cache
Yii::app()->cache->flush();

// add data to cache
Yii::app()->cache->set('apple', 'fruit');
Yii::app()->cache->set('onion', 'vegetables');
Yii::app()->cache->set(1, 'one');
Yii::app()->cache->set(2, 'two');
Yii::app()->cache->set('one', 1);
Yii::app()->cache->set('two', 2);

// delete from cache
Yii::app()->cache->delete(1);
Yii::app()->cache->delete('two');

// read from cache
echo Yii::app()->cache->get(2);

// multiple read from cache
$arr = Yii::app()->cache->mget(array('apple', 1, 'two'));

print_r($arr); // Array( [apple] => fruit [1] => 'one' [two] => 2 )

## EMongoMessageSource

This is a MongoYii `Yii::t()` implementation by [Rajcsányi Zoltán](http://ezmegaz.hu/).

To use it first add it to your configuration:

'components' => array(
...
'messages' => array(
'class' => 'application.extensions.MongoYii.util.EMongoMessageSource',
// 'mongoConnectionId' => 'mongodb',
// 'collectionName' => 'YiiMessages',
)
)

The commented out lines are optional parameters you can send in if required.

And then add some messages to the translation table:

db.YiiMessages.insert( { category:"users", message:"Freund", translations: [ {language:"eng", message:"Friend"} ] } );

And then simply get that message:

<?=Yii::t('users', 'Freund'); ?>

## Upgrade Notes

There has been a small but dramatic change between version 1.x and 2.x of MongoYii. The `compare()` function within the `EMongoCriteria` now no longer uses partial matching by
Expand Down
282 changes: 282 additions & 0 deletions util/EMongoCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
<?php
/**
* Extends the Yii class 'CCache' to store cached data in mongoDB.
*
* PHP version 5.2+
* MongoDB version >= 1.5.3
* required extensions: MongoYii (for the configuration of the mongoDB connection)
*
* @author Zoltan Rajcsanyi <[email protected]>
* @copyright 2013 Zoltan Rajcsanyi
* @license New BSD License
* @category Database
* @version 1.0
*/

/**
* EMongoCache implements a cache application component by storing cached data in a mongodb.
*
* EMongoDBCache stores cache data in a collection named {@link collectionName}.
* If the collection does not exist, it will be automatically created.
*
* You can also specify {@link mongoConnectionId} to select a mongoDb
*
* See {@link CCache} manual for common cache operations that are supported by EMongoCache.
*/
class EMongoCache extends CCache
{
/**
* @var string the ID of a {@link CDbConnection} application component.
*/
public $mongoConnectionId='mongodb'; // public $mongoConnectionId = 'mongodb';

public $connectionID;

/**
* @var string name of the collection to store cache content. Defaults to 'YiiCache'.
* The items are stored withe following structure:
* <pre>
* key: string,
* value: string
* expire: integer
* </pre>
*/
public $collectionName = 'YiiCache';
public $ensureIndex = true; //set to false after first use of the cache

/**
* @var EMongoClient the DB connection instance
*/
private $_db;

private $_gcProbability=100;
private $_gced=false;

/**
* Initializes this application component.
* ensureIndex 'key' if $ensureIndex = true
* Set $ensureIndex to false after first use to increase performance
*
* This method is required by the {@link IApplicationComponent} interface.
* It ensures the existence of the cache DB table.
* It also removes expired data items from the cache.
*/
public function init()
{
parent::init();

if ($this->ensureIndex) {
$this->getCollection()->ensureIndex( array('key' => 1)); // create index on "key"
}
}

/**
* @return EMongoClient the DB connection instance
* @throws CException if {@link connectionID} does not point to a valid application component.
*/
protected function getDbConnection()
{
if ($this->_db !== null) {
return $this->_db;
} elseif (($id=$this->connectionID) !==null) {
if (($this->_db=Yii::app()->getComponent($id)) instanceof CDbConnection) {
return $this->_db;
} else {
throw new CException(Yii::t('yii','EMongoCache.connectionID "{id}" is invalid. Please make sure it refers to the ID of a EMongoClient application component.',
array('{id}'=>$id)));
}
} else {
return $this->_db=Yii::app()->getComponent('mongodb');
}
}

/**
* Returns current MongoCollection object
*
* @return MongoCollection
*/
protected function getCollection()
{
return $this->getDbConnection()->{$this->collectionName};
}

/**
* @return integer the probability (parts per million) that garbage collection (GC) should be performed
* when storing a piece of data in the cache. Defaults to 100, meaning 0.01% chance.
* @since 1.0.9
*/
public function getGCProbability()
{
return $this->_gcProbability;
}

/**
* @param integer $value the probability (parts per million) that garbage collection (GC) should be performed
* when storing a piece of data in the cache. Defaults to 100, meaning 0.01% chance.
* This number should be between 0 and 1000000. A value 0 meaning no GC will be performed at all.
* @since 1.0.9
*/
public function setGCProbability($value)
{
$value=(int)$value;

if ($value < 0) {
$value=0;
} elseif ($value > 1000000) {
$value=1000000;
}

$this->_gcProbability=$value;
}

/**
* Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired.
*/
protected function getValue($key)
{
$time=time();

$criteria = array(
'key' => (string)$key,
'$or' => array(
array('expire' => 0),
array('expire' => array('$gt'=> $time)),
),
);

$data = $this->getCollection()->findOne($criteria);

return $data===null?'':$data['value'];
}

/**
* Retrieves multiple values from cache with the specified keys.
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/
protected function getValues($keys)
{
if (empty($keys)) {
return array();
}

$results=array();
$time=time();

$criteria = array(
'key' => array('$in'=>$keys),
'$or' => array(
array('expire' => 0),
array('expire' => array('$gt'=> $time)),
),
);


$data = $this->getCollection()->find($criteria);

if (!empty($data) && $data->count()) {
foreach ($data as $id => $value) {
$results[$value['key']] = $value['value'];
}
}

return $results;
}

/**
* Stores a value identified by a key in cache.
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param string $value the value to be cached
* @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/
protected function setValue($key, $value, $expire)
{
return $this->addValue($key, $value, $expire);
}

/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* This is the implementation of the method declared in the parent class.
*
* If the key exists the value will be updated, otherwise inserted
*
* @param string $key the key identifying the value to be cached
* @param string $value the value to be cached
* @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/
protected function addValue($key, $value, $expire)
{
if (!$this->_gced && mt_rand(0,1000000) < $this->_gcProbability) {
$this->gc();
$this->_gced=true;
}

if ($expire > 0) {
$expire+=time();
} else {
$expire=0;
}

$criteria = array('key' => (string)$key);

$data = array(
'key' => (string)$key,
'value' => (string)$value,
'expire' => (int)$expire,
);

$options = array('upsert'=>true);

try {
return $this->getCollection()->update($criteria, $data, $options);
} catch(Exception $e) {
return false;
}
}

/**
* Deletes a value with the specified key from cache
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return boolean if no error happens during deletion
*/
protected function deleteValue($key)
{
$criteria = array('key' => (string)$key);
$data = $this->getCollection()->remove($criteria);
return true;
}

/**
* Removes the expired data values.
*/
protected function gc()
{
//delete expired entries
$criteria = array(
'expired' => array('$gt' => 0),
'expired' => array('$lt' => time()),
);

$this->getCollection()->remove($criteria);

}

/**
* Deletes all values from cache.
* This is the implementation of the method declared in the parent class.
* @return boolean whether the flush operation was successful.
*/
protected function flushValues()
{
$this->getCollection()->remove();
return true;
}
}
Loading

0 comments on commit 0985602

Please sign in to comment.