Commit 04fb75b6 by Paul Klimov

File retrieve methods added to Mongo File Active Record.

parent c0d5c785
......@@ -129,33 +129,13 @@ class Query extends Component implements QueryInterface
* @throws Exception on failure.
* @return array|boolean result.
*/
protected function fetchRows(\MongoCursor $cursor, $all = true, $indexBy = null)
protected function fetchRows($cursor, $all = true, $indexBy = null)
{
$token = 'Querying: ' . Json::encode($cursor->info());
Yii::info($token, __METHOD__);
try {
Yii::beginProfile($token, __METHOD__);
$result = [];
if ($all) {
foreach ($cursor as $row) {
if ($indexBy !== null) {
if (is_string($indexBy)) {
$key = $row[$indexBy];
} else {
$key = call_user_func($indexBy, $row);
}
$result[$key] = $row;
} else {
$result[] = $row;
}
}
} else {
if ($cursor->hasNext()) {
$result = $cursor->getNext();
} else {
$result = false;
}
}
$result = $this->fetchRowsInternal($cursor, $all, $indexBy);
Yii::endProfile($token, __METHOD__);
return $result;
} catch (\Exception $e) {
......@@ -165,6 +145,39 @@ class Query extends Component implements QueryInterface
}
/**
* @param \MongoCursor $cursor Mongo cursor instance to fetch data from.
* @param boolean $all whether to fetch all rows or only first one.
* @param string|callable $indexBy value to index by.
* @return array|boolean result.
* @see Query::fetchRows()
*/
protected function fetchRowsInternal($cursor, $all, $indexBy)
{
$result = [];
if ($all) {
foreach ($cursor as $row) {
if ($indexBy !== null) {
if (is_string($indexBy)) {
$key = $row[$indexBy];
} else {
$key = call_user_func($indexBy, $row);
}
$result[$key] = $row;
} else {
$result[] = $row;
}
}
} else {
if ($cursor->hasNext()) {
$result = $cursor->getNext();
} else {
$result = false;
}
}
return $result;
}
/**
* Executes the query and returns all results as an array.
* @param Connection $db the Mongo connection used to execute the query.
* If this parameter is not given, the `mongo` application component will be used.
......
......@@ -205,7 +205,7 @@ class ActiveRecord extends \yii\mongo\ActiveRecord
/**
* Returns the associated file content.
* @return null|string file content.
* @throws \yii\base\InvalidParamException on invalid file value.
* @throws \yii\base\InvalidParamException on invalid file attribute value.
*/
public function getFileContent()
{
......@@ -227,6 +227,67 @@ class ActiveRecord extends \yii\mongo\ActiveRecord
} elseif (is_string($file)) {
if (file_exists($file)) {
return file_get_contents($file);
} else {
throw new InvalidParamException("File '{$file}' does not exist.");
}
} else {
throw new InvalidParamException('Unsupported type of "file" attribute.');
}
}
/**
* Writes the the internal file content into the given filename.
* @param string $filename full filename to be written.
* @return boolean whether the operation was successful.
* @throws \yii\base\InvalidParamException on invalid file attribute value.
*/
public function writeFile($filename)
{
$file = $this->getAttribute('file');
if (empty($file) && !$this->getIsNewRecord()) {
$file = $this->refreshFile();
}
if (empty($file)) {
throw new InvalidParamException('There is no file associated with this object.');
} elseif ($file instanceof \MongoGridFSFile) {
return ($file->write($filename) == $file->getSize());
} elseif ($file instanceof UploadedFile) {
return copy($file->tempName, $filename);
} elseif (is_string($file)) {
if (file_exists($file)) {
return copy($file, $filename);
} else {
throw new InvalidParamException("File '{$file}' does not exist.");
}
} else {
throw new InvalidParamException('Unsupported type of "file" attribute.');
}
}
/**
* This method returns a stream resource that can be used with all file functions in PHP,
* which deal with reading files. The contents of the file are pulled out of MongoDB on the fly,
* so that the whole file does not have to be loaded into memory first.
* @return resource file stream resource.
* @throws \yii\base\InvalidParamException on invalid file attribute value.
*/
public function getFileResource()
{
$file = $this->getAttribute('file');
if (empty($file) && !$this->getIsNewRecord()) {
$file = $this->refreshFile();
}
if (empty($file)) {
throw new InvalidParamException('There is no file associated with this object.');
} elseif ($file instanceof \MongoGridFSFile) {
return $file->getResource();
} elseif ($file instanceof UploadedFile) {
return fopen($file->tempName, 'r');
} elseif (is_string($file)) {
if (file_exists($file)) {
return fopen($file, 'r');
} else {
throw new InvalidParamException("File '{$file}' does not exist.");
}
} else {
throw new InvalidParamException('Unsupported type of "file" attribute.');
......
......@@ -33,50 +33,39 @@ class Query extends \yii\mongo\Query
}
/**
* Fetches rows from the given Mongo cursor.
* @param \MongoCursor $cursor Mongo cursor instance to fetch data from.
* @param \MongoGridFSCursor $cursor Mongo cursor instance to fetch data from.
* @param boolean $all whether to fetch all rows or only first one.
* @param string|callable $indexBy the column name or PHP callback,
* by which the query results should be indexed by.
* @throws Exception on failure.
* @param string|callable $indexBy value to index by.
* @return array|boolean result.
* @see Query::fetchRows()
*/
protected function fetchRows(\MongoCursor $cursor, $all = true, $indexBy = null)
protected function fetchRowsInternal($cursor, $all, $indexBy)
{
$token = 'Querying: ' . Json::encode($cursor->info());
Yii::info($token, __METHOD__);
try {
Yii::beginProfile($token, __METHOD__);
$result = [];
if ($all) {
foreach ($cursor as $file) {
$row = $file->file;
$row['file'] = $file;
if ($indexBy !== null) {
if (is_string($indexBy)) {
$key = $row[$indexBy];
} else {
$key = call_user_func($indexBy, $row);
}
$result[$key] = $row;
$result = [];
if ($all) {
foreach ($cursor as $file) {
$row = $file->file;
$row['file'] = $file;
if ($indexBy !== null) {
if (is_string($indexBy)) {
$key = $row[$indexBy];
} else {
$result[] = $row;
$key = call_user_func($indexBy, $row);
}
}
} else {
if ($cursor->hasNext()) {
$file = $cursor->getNext();
$result = $file->file;
$result['file'] = $file;
$result[$key] = $row;
} else {
$result = false;
$result[] = $row;
}
}
Yii::endProfile($token, __METHOD__);
return $result;
} catch (\Exception $e) {
Yii::endProfile($token, __METHOD__);
throw new Exception($e->getMessage(), (int)$e->getCode(), $e);
} else {
if ($cursor->hasNext()) {
$file = $cursor->getNext();
$result = $file->file;
$result['file'] = $file;
} else {
$result = false;
}
}
return $result;
}
}
\ No newline at end of file
......@@ -2,6 +2,8 @@
namespace yiiunit\extensions\mongo\file;
use Yii;
use yii\helpers\FileHelper;
use yiiunit\extensions\mongo\MongoTestCase;
use yii\mongo\file\ActiveQuery;
use yiiunit\data\ar\mongo\file\ActiveRecord;
......@@ -22,15 +24,31 @@ class ActiveRecordTest extends MongoTestCase
parent::setUp();
ActiveRecord::$db = $this->getConnection();
$this->setUpTestRows();
$filePath = $this->getTestFilePath();
if (!file_exists($filePath)) {
FileHelper::createDirectory($filePath);
}
}
protected function tearDown()
{
$filePath = $this->getTestFilePath();
if (file_exists($filePath)) {
FileHelper::removeDirectory($filePath);
}
$this->dropFileCollection(CustomerFile::collectionName());
parent::tearDown();
}
/**
* @return string test file path.
*/
protected function getTestFilePath()
{
return Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . basename(get_class($this)) . '_' . getmypid();
}
/**
* Sets up test rows.
*/
protected function setUpTestRows()
......@@ -256,4 +274,50 @@ class ActiveRecordTest extends MongoTestCase
$this->assertEquals($record->status, $record2->status);
$this->assertEquals($updateFileContent, $record2->getFileContent());
}
/**
* @depends testInsertFileContent
*/
public function testWriteFile()
{
$record = new CustomerFile;
$record->tag = 'new new';
$record->status = 7;
$newFileContent = 'Test new file content';
$record->setAttribute('newFileContent', $newFileContent);
$record->save();
$outputFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . 'out.txt';
$this->assertTrue($record->writeFile($outputFileName));
$this->assertEquals($newFileContent, file_get_contents($outputFileName));
$record2 = CustomerFile::find($record->_id);
$outputFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . 'out_refreshed.txt';
$this->assertTrue($record2->writeFile($outputFileName));
$this->assertEquals($newFileContent, file_get_contents($outputFileName));
}
/**
* @depends testInsertFileContent
*/
public function testGetFileResource()
{
$record = new CustomerFile;
$record->tag = 'new new';
$record->status = 7;
$newFileContent = 'Test new file content';
$record->setAttribute('newFileContent', $newFileContent);
$record->save();
$fileResource = $record->getFileResource();
$contents = stream_get_contents($fileResource);
fclose($fileResource);
$this->assertEquals($newFileContent, $contents);
$record2 = CustomerFile::find($record->_id);
$fileResource = $record2->getFileResource();
$contents = stream_get_contents($fileResource);
fclose($fileResource);
$this->assertEquals($newFileContent, $contents);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment