init
This commit is contained in:
183
vendor/yiisoft/yii2-mongodb/src/file/ActiveQuery.php
vendored
Normal file
183
vendor/yiisoft/yii2-mongodb/src/file/ActiveQuery.php
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
use yii\db\ActiveQueryInterface;
|
||||
use yii\db\ActiveQueryTrait;
|
||||
use yii\db\ActiveRelationTrait;
|
||||
|
||||
/**
|
||||
* ActiveQuery represents a Mongo query associated with an file Active Record class.
|
||||
*
|
||||
* ActiveQuery instances are usually created by [[ActiveRecord::find()]].
|
||||
*
|
||||
* Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]],
|
||||
* [[orderBy()]] to customize the query options.
|
||||
*
|
||||
* ActiveQuery also provides the following additional query options:
|
||||
*
|
||||
* - [[with()]]: list of relations that this query should be performed with.
|
||||
* - [[asArray()]]: whether to return each record as an array.
|
||||
*
|
||||
* These options can be configured using methods of the same name. For example:
|
||||
*
|
||||
* ```php
|
||||
* $images = ImageFile::find()->with('tags')->asArray()->all();
|
||||
* ```
|
||||
*
|
||||
* @property Collection $collection Collection instance. This property is read-only.
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ActiveQuery extends Query implements ActiveQueryInterface
|
||||
{
|
||||
use ActiveQueryTrait;
|
||||
use ActiveRelationTrait;
|
||||
|
||||
/**
|
||||
* @event Event an event that is triggered when the query is initialized via [[init()]].
|
||||
*/
|
||||
const EVENT_INIT = 'init';
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param array $modelClass the model class associated with this query
|
||||
* @param array $config configurations to be applied to the newly created query object
|
||||
*/
|
||||
public function __construct($modelClass, $config = [])
|
||||
{
|
||||
$this->modelClass = $modelClass;
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the object.
|
||||
* This method is called at the end of the constructor. The default implementation will trigger
|
||||
* an [[EVENT_INIT]] event. If you override this method, make sure you call the parent implementation at the end
|
||||
* to ensure triggering of the event.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$this->trigger(self::EVENT_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildCursor($db = null)
|
||||
{
|
||||
if ($this->primaryModel !== null) {
|
||||
// lazy loading
|
||||
if ($this->via instanceof self) {
|
||||
// via pivot collection
|
||||
$viaModels = $this->via->findJunctionRows([$this->primaryModel]);
|
||||
$this->filterByModels($viaModels);
|
||||
} elseif (is_array($this->via)) {
|
||||
// via relation
|
||||
/* @var $viaQuery ActiveQuery */
|
||||
list($viaName, $viaQuery) = $this->via;
|
||||
if ($viaQuery->multiple) {
|
||||
$viaModels = $viaQuery->all();
|
||||
$this->primaryModel->populateRelation($viaName, $viaModels);
|
||||
} else {
|
||||
$model = $viaQuery->one();
|
||||
$this->primaryModel->populateRelation($viaName, $model);
|
||||
$viaModels = $model === null ? [] : [$model];
|
||||
}
|
||||
$this->filterByModels($viaModels);
|
||||
} else {
|
||||
$this->filterByModels([$this->primaryModel]);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::buildCursor($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes query and returns all results as an array.
|
||||
* @param \yii\mongodb\Connection $db the Mongo connection used to execute the query.
|
||||
* If null, the Mongo connection returned by [[modelClass]] will be used.
|
||||
* @return array|ActiveRecord the query results. If the query results in nothing, an empty array will be returned.
|
||||
*/
|
||||
public function all($db = null)
|
||||
{
|
||||
return parent::all($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes query and returns a single row of result.
|
||||
* @param \yii\mongodb\Connection $db the Mongo connection used to execute the query.
|
||||
* If null, the Mongo connection returned by [[modelClass]] will be used.
|
||||
* @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
|
||||
* the query result may be either an array or an ActiveRecord object. Null will be returned
|
||||
* if the query results in nothing.
|
||||
*/
|
||||
public function one($db = null)
|
||||
{
|
||||
$row = parent::one($db);
|
||||
if ($row !== false) {
|
||||
$models = $this->populate([$row]);
|
||||
return reset($models) ?: null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Mongo collection for this query.
|
||||
* @param \yii\mongodb\Connection $db Mongo connection.
|
||||
* @return Collection collection instance.
|
||||
*/
|
||||
public function getCollection($db = null)
|
||||
{
|
||||
/* @var $modelClass ActiveRecord */
|
||||
$modelClass = $this->modelClass;
|
||||
if ($db === null) {
|
||||
$db = $modelClass::getDb();
|
||||
}
|
||||
if ($this->from === null) {
|
||||
$this->from = $modelClass::collectionName();
|
||||
}
|
||||
|
||||
return $db->getFileCollection($this->from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the raw query results into the format as specified by this query.
|
||||
* This method is internally used to convert the data fetched from MongoDB
|
||||
* into the format as required by this query.
|
||||
* @param array $rows the raw query result from MongoDB
|
||||
* @return array the converted query result
|
||||
*/
|
||||
public function populate($rows)
|
||||
{
|
||||
if (empty($rows)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$indexBy = $this->indexBy;
|
||||
$this->indexBy = null;
|
||||
$rows = parent::populate($rows);
|
||||
$this->indexBy = $indexBy;
|
||||
|
||||
$models = $this->createModels($rows);
|
||||
|
||||
if (!empty($this->with)) {
|
||||
$this->findWith($this->with, $models);
|
||||
}
|
||||
if (!$this->asArray) {
|
||||
foreach ($models as $model) {
|
||||
$model->afterFind();
|
||||
}
|
||||
}
|
||||
|
||||
return parent::populate($models);
|
||||
}
|
||||
}
|
||||
335
vendor/yiisoft/yii2-mongodb/src/file/ActiveRecord.php
vendored
Normal file
335
vendor/yiisoft/yii2-mongodb/src/file/ActiveRecord.php
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\db\StaleObjectException;
|
||||
use yii\web\UploadedFile;
|
||||
|
||||
/**
|
||||
* ActiveRecord is the base class for classes representing Mongo GridFS files in terms of objects.
|
||||
*
|
||||
* To specify source file use the [[file]] attribute. It can be specified in one of the following ways:
|
||||
* - string - full name of the file, which content should be stored in GridFS
|
||||
* - \yii\web\UploadedFile - uploaded file instance, which content should be stored in GridFS
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```php
|
||||
* $record = new ImageFile();
|
||||
* $record->file = '/path/to/some/file.jpg';
|
||||
* $record->save();
|
||||
* ```
|
||||
*
|
||||
* You can also specify file content via [[newFileContent]] attribute:
|
||||
*
|
||||
* ```php
|
||||
* $record = new ImageFile();
|
||||
* $record->newFileContent = 'New file content';
|
||||
* $record->save();
|
||||
* ```
|
||||
*
|
||||
* Note: [[newFileContent]] always takes precedence over [[file]].
|
||||
*
|
||||
* @property null|string $fileContent File content. This property is read-only.
|
||||
* @property resource $fileResource File stream resource. This property is read-only.
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class ActiveRecord extends \yii\mongodb\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return ActiveQuery the newly created [[ActiveQuery]] instance.
|
||||
*/
|
||||
public static function find()
|
||||
{
|
||||
return Yii::createObject(ActiveQuery::className(), [get_called_class()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Mongo GridFS collection instance for this AR class.
|
||||
* @return Collection collection instance.
|
||||
*/
|
||||
public static function getCollection()
|
||||
{
|
||||
return static::getDb()->getFileCollection(static::collectionName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all attribute names of the model.
|
||||
* This method could be overridden by child classes to define available attributes.
|
||||
* Note: all attributes defined in base Active Record class should be always present
|
||||
* in returned array.
|
||||
* For example:
|
||||
*
|
||||
* ```php
|
||||
* public function attributes()
|
||||
* {
|
||||
* return array_merge(
|
||||
* parent::attributes(),
|
||||
* ['tags', 'status']
|
||||
* );
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @return array list of attribute names.
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'_id',
|
||||
'filename',
|
||||
'uploadDate',
|
||||
'length',
|
||||
'chunkSize',
|
||||
'md5',
|
||||
'file',
|
||||
'newFileContent'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ActiveRecord::insert()
|
||||
*/
|
||||
protected function insertInternal($attributes = null)
|
||||
{
|
||||
if (!$this->beforeSave(true)) {
|
||||
return false;
|
||||
}
|
||||
$values = $this->getDirtyAttributes($attributes);
|
||||
if (empty($values)) {
|
||||
$currentAttributes = $this->getAttributes();
|
||||
foreach ($this->primaryKey() as $key) {
|
||||
$values[$key] = isset($currentAttributes[$key]) ? $currentAttributes[$key] : null;
|
||||
}
|
||||
}
|
||||
$collection = static::getCollection();
|
||||
if (isset($values['newFileContent'])) {
|
||||
$newFileContent = $values['newFileContent'];
|
||||
unset($values['newFileContent']);
|
||||
}
|
||||
if (isset($values['file'])) {
|
||||
$newFile = $values['file'];
|
||||
unset($values['file']);
|
||||
}
|
||||
if (isset($newFileContent)) {
|
||||
$newId = $collection->insertFileContent($newFileContent, $values);
|
||||
} elseif (isset($newFile)) {
|
||||
$fileName = $this->extractFileName($newFile);
|
||||
$newId = $collection->insertFile($fileName, $values);
|
||||
} else {
|
||||
$newId = $collection->insert($values);
|
||||
}
|
||||
if ($newId !== null) {
|
||||
$this->setAttribute('_id', $newId);
|
||||
$values['_id'] = $newId;
|
||||
}
|
||||
|
||||
$changedAttributes = array_fill_keys(array_keys($values), null);
|
||||
$this->setOldAttributes($values);
|
||||
$this->afterSave(true, $changedAttributes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ActiveRecord::update()
|
||||
* @throws StaleObjectException
|
||||
*/
|
||||
protected function updateInternal($attributes = null)
|
||||
{
|
||||
if (!$this->beforeSave(false)) {
|
||||
return false;
|
||||
}
|
||||
$values = $this->getDirtyAttributes($attributes);
|
||||
if (empty($values)) {
|
||||
$this->afterSave(false, $values);
|
||||
return 0;
|
||||
}
|
||||
|
||||
$collection = static::getCollection();
|
||||
if (isset($values['newFileContent'])) {
|
||||
$newFileContent = $values['newFileContent'];
|
||||
unset($values['newFileContent']);
|
||||
}
|
||||
if (isset($values['file'])) {
|
||||
$newFile = $values['file'];
|
||||
unset($values['file']);
|
||||
}
|
||||
if (isset($newFileContent) || isset($newFile)) {
|
||||
$fileAssociatedAttributeNames = [
|
||||
'filename',
|
||||
'uploadDate',
|
||||
'length',
|
||||
'chunkSize',
|
||||
'md5',
|
||||
'file',
|
||||
'newFileContent'
|
||||
];
|
||||
$values = array_merge($this->getAttributes(null, $fileAssociatedAttributeNames), $values);
|
||||
$rows = $this->deleteInternal();
|
||||
$insertValues = $values;
|
||||
$insertValues['_id'] = $this->getAttribute('_id');
|
||||
if (isset($newFileContent)) {
|
||||
$collection->insertFileContent($newFileContent, $insertValues);
|
||||
} else {
|
||||
$fileName = $this->extractFileName($newFile);
|
||||
$collection->insertFile($fileName, $insertValues);
|
||||
}
|
||||
$this->setAttribute('newFileContent', null);
|
||||
$this->setAttribute('file', null);
|
||||
} else {
|
||||
$condition = $this->getOldPrimaryKey(true);
|
||||
$lock = $this->optimisticLock();
|
||||
if ($lock !== null) {
|
||||
if (!isset($values[$lock])) {
|
||||
$values[$lock] = $this->$lock + 1;
|
||||
}
|
||||
$condition[$lock] = $this->$lock;
|
||||
}
|
||||
// We do not check the return value of update() because it's possible
|
||||
// that it doesn't change anything and thus returns 0.
|
||||
$rows = $collection->update($condition, $values);
|
||||
if ($lock !== null && !$rows) {
|
||||
throw new StaleObjectException('The object being updated is outdated.');
|
||||
}
|
||||
}
|
||||
|
||||
$changedAttributes = [];
|
||||
foreach ($values as $name => $value) {
|
||||
$changedAttributes[$name] = $this->getOldAttribute($name);
|
||||
$this->setOldAttribute($name, $value);
|
||||
}
|
||||
$this->afterSave(false, $changedAttributes);
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts filename from given raw file value.
|
||||
* @param mixed $file raw file value.
|
||||
* @return string file name.
|
||||
* @throws \yii\base\InvalidParamException on invalid file value.
|
||||
*/
|
||||
protected function extractFileName($file)
|
||||
{
|
||||
if ($file instanceof UploadedFile) {
|
||||
return $file->tempName;
|
||||
} elseif (is_string($file)) {
|
||||
if (file_exists($file)) {
|
||||
return $file;
|
||||
}
|
||||
throw new InvalidParamException("File '{$file}' does not exist.");
|
||||
}
|
||||
|
||||
throw new InvalidParamException('Unsupported type of "file" attribute.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the [[file]] attribute from file collection, using current primary key.
|
||||
* @return \MongoGridFSFile|null refreshed file value.
|
||||
*/
|
||||
public function refreshFile()
|
||||
{
|
||||
$mongoFile = $this->getCollection()->get($this->getPrimaryKey());
|
||||
$this->setAttribute('file', $mongoFile);
|
||||
|
||||
return $mongoFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated file content.
|
||||
* @return null|string file content.
|
||||
* @throws \yii\base\InvalidParamException on invalid file attribute value.
|
||||
*/
|
||||
public function getFileContent()
|
||||
{
|
||||
$file = $this->getAttribute('file');
|
||||
if (empty($file) && !$this->getIsNewRecord()) {
|
||||
$file = $this->refreshFile();
|
||||
}
|
||||
|
||||
if (empty($file)) {
|
||||
return null;
|
||||
} elseif ($file instanceof Download) {
|
||||
$fileSize = $file->getSize();
|
||||
return empty($fileSize) ? null : $file->toString();
|
||||
} elseif ($file instanceof UploadedFile) {
|
||||
return file_get_contents($file->tempName);
|
||||
} elseif (is_string($file)) {
|
||||
if (file_exists($file)) {
|
||||
return file_get_contents($file);
|
||||
}
|
||||
throw new InvalidParamException("File '{$file}' does not exist.");
|
||||
}
|
||||
|
||||
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 bool 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 Download) {
|
||||
return ($file->toFile($filename) == $file->getSize());
|
||||
} elseif ($file instanceof UploadedFile) {
|
||||
return copy($file->tempName, $filename);
|
||||
} elseif (is_string($file)) {
|
||||
if (file_exists($file)) {
|
||||
return copy($file, $filename);
|
||||
}
|
||||
throw new InvalidParamException("File '{$file}' does not exist.");
|
||||
}
|
||||
|
||||
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 Download) {
|
||||
return $file->getResource();
|
||||
} elseif ($file instanceof UploadedFile) {
|
||||
return fopen($file->tempName, 'r');
|
||||
} elseif (is_string($file)) {
|
||||
if (file_exists($file)) {
|
||||
return fopen($file, 'r');
|
||||
}
|
||||
throw new InvalidParamException("File '{$file}' does not exist.");
|
||||
}
|
||||
|
||||
throw new InvalidParamException('Unsupported type of "file" attribute.');
|
||||
}
|
||||
}
|
||||
327
vendor/yiisoft/yii2-mongodb/src/file/Collection.php
vendored
Normal file
327
vendor/yiisoft/yii2-mongodb/src/file/Collection.php
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
use MongoDB\BSON\ObjectID;
|
||||
use yii\mongodb\Exception;
|
||||
use Yii;
|
||||
use yii\web\UploadedFile;
|
||||
|
||||
/**
|
||||
* Collection represents the Mongo GridFS collection information.
|
||||
*
|
||||
* A file collection object is usually created by calling [[Database::getFileCollection()]] or [[Connection::getFileCollection()]].
|
||||
*
|
||||
* File collection inherits all interface from regular [[\yii\mongo\Collection]], adding methods to store files.
|
||||
*
|
||||
* @property \yii\mongodb\Collection $chunkCollection Mongo collection instance. This property is read-only.
|
||||
* @property \yii\mongodb\Collection $fileCollection Mongo collection instance. This property is read-only.
|
||||
* @property string $prefix Prefix of this file collection.
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Collection extends \yii\mongodb\Collection
|
||||
{
|
||||
/**
|
||||
* @var \yii\mongodb\Database MongoDB database instance.
|
||||
*/
|
||||
public $database;
|
||||
|
||||
/**
|
||||
* @var string prefix of this file collection.
|
||||
*/
|
||||
private $_prefix;
|
||||
/**
|
||||
* @var \yii\mongodb\Collection file chunks MongoDB collection.
|
||||
*/
|
||||
private $_chunkCollection;
|
||||
/**
|
||||
* @var \yii\mongodb\Collection files MongoDB collection.
|
||||
*/
|
||||
private $_fileCollection;
|
||||
/**
|
||||
* @var bool whether file related fields indexes are ensured for this collection.
|
||||
*/
|
||||
private $indexesEnsured = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return string prefix of this file collection.
|
||||
*/
|
||||
public function getPrefix()
|
||||
{
|
||||
return $this->_prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix prefix of this file collection.
|
||||
*/
|
||||
public function setPrefix($prefix)
|
||||
{
|
||||
$this->_prefix = $prefix;
|
||||
$this->name = $prefix . '.files';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates upload command.
|
||||
* @param array $options upload options.
|
||||
* @return Upload file upload instance.
|
||||
* @since 2.1
|
||||
*/
|
||||
public function createUpload($options = [])
|
||||
{
|
||||
$config = $options;
|
||||
$config['collection'] = $this;
|
||||
return new Upload($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates download command.
|
||||
* @param array|ObjectID $document file document ot be downloaded.
|
||||
* @return Download file download instance.
|
||||
* @since 2.1
|
||||
*/
|
||||
public function createDownload($document)
|
||||
{
|
||||
return new Download([
|
||||
'collection' => $this,
|
||||
'document' => $document,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MongoDB collection for the file chunks.
|
||||
* @param bool $refresh whether to reload the collection instance even if it is found in the cache.
|
||||
* @return \yii\mongodb\Collection mongo collection instance.
|
||||
*/
|
||||
public function getChunkCollection($refresh = false)
|
||||
{
|
||||
if ($refresh || !is_object($this->_chunkCollection)) {
|
||||
$this->_chunkCollection = Yii::createObject([
|
||||
'class' => 'yii\mongodb\Collection',
|
||||
'database' => $this->database,
|
||||
'name' => $this->getPrefix() . '.chunks'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->_chunkCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MongoDB collection for the files.
|
||||
* @param bool $refresh whether to reload the collection instance even if it is found in the cache.
|
||||
* @return \yii\mongodb\Collection mongo collection instance.
|
||||
* @since 2.1
|
||||
*/
|
||||
public function getFileCollection($refresh = false)
|
||||
{
|
||||
if ($refresh || !is_object($this->_fileCollection)) {
|
||||
$this->_fileCollection = Yii::createObject([
|
||||
'class' => 'yii\mongodb\Collection',
|
||||
'database' => $this->database,
|
||||
'name' => $this->name
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->_fileCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function drop()
|
||||
{
|
||||
return parent::drop() && $this->database->dropCollection($this->getChunkCollection()->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return Cursor cursor for the search results
|
||||
*/
|
||||
public function find($condition = [], $fields = [], $options = [])
|
||||
{
|
||||
return new Cursor($this, parent::find($condition, $fields, $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove($condition = [], $options = [])
|
||||
{
|
||||
$fileCollection = $this->getFileCollection();
|
||||
$chunkCollection = $this->getChunkCollection();
|
||||
|
||||
if (empty($condition) && empty($options['limit'])) {
|
||||
// truncate :
|
||||
$deleteCount = $fileCollection->remove([], $options);
|
||||
$chunkCollection->remove([], $options);
|
||||
return $deleteCount;
|
||||
}
|
||||
|
||||
$batchSize = 200;
|
||||
$options['batchSize'] = $batchSize;
|
||||
$cursor = $fileCollection->find($condition, ['_id'], $options);
|
||||
unset($options['limit']);
|
||||
$deleteCount = 0;
|
||||
$deleteCallback = function ($ids) use ($fileCollection, $chunkCollection, $options) {
|
||||
$chunkCollection->remove(['files_id' => ['$in' => $ids]], $options);
|
||||
return $fileCollection->remove(['_id' => ['$in' => $ids]], $options);
|
||||
};
|
||||
|
||||
$ids = [];
|
||||
$idsCount = 0;
|
||||
foreach ($cursor as $row) {
|
||||
$ids[] = $row['_id'];
|
||||
$idsCount++;
|
||||
if ($idsCount >= $batchSize) {
|
||||
$deleteCount += $deleteCallback($ids);
|
||||
$ids = [];
|
||||
$idsCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($ids)) {
|
||||
$deleteCount += $deleteCallback($ids);
|
||||
}
|
||||
|
||||
return $deleteCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new file in GridFS collection from given local filesystem file.
|
||||
* Additional attributes can be added file document using $metadata.
|
||||
* @param string $filename name of the file to store.
|
||||
* @param array $metadata other metadata fields to include in the file document.
|
||||
* @param array $options list of options in format: optionName => optionValue
|
||||
* @return mixed the "_id" of the saved file document. This will be a generated [[\MongoId]]
|
||||
* unless an "_id" was explicitly specified in the metadata.
|
||||
* @throws Exception on failure.
|
||||
*/
|
||||
public function insertFile($filename, $metadata = [], $options = [])
|
||||
{
|
||||
$options['document'] = $metadata;
|
||||
$document = $this->createUpload($options)->addFile($filename)->complete();
|
||||
return $document['_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new file in GridFS collection with specified content.
|
||||
* Additional attributes can be added file document using $metadata.
|
||||
* @param string $bytes string of bytes to store.
|
||||
* @param array $metadata other metadata fields to include in the file document.
|
||||
* @param array $options list of options in format: optionName => optionValue
|
||||
* @return mixed the "_id" of the saved file document. This will be a generated [[\MongoId]]
|
||||
* unless an "_id" was explicitly specified in the metadata.
|
||||
* @throws Exception on failure.
|
||||
*/
|
||||
public function insertFileContent($bytes, $metadata = [], $options = [])
|
||||
{
|
||||
$options['document'] = $metadata;
|
||||
$document = $this->createUpload($options)->addContent($bytes)->complete();
|
||||
return $document['_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new file in GridFS collection from uploaded file.
|
||||
* Additional attributes can be added file document using $metadata.
|
||||
* @param string $name name of the uploaded file to store. This should correspond to
|
||||
* the file field's name attribute in the HTML form.
|
||||
* @param array $metadata other metadata fields to include in the file document.
|
||||
* @param array $options list of options in format: optionName => optionValue
|
||||
* @return mixed the "_id" of the saved file document. This will be a generated [[\MongoId]]
|
||||
* unless an "_id" was explicitly specified in the metadata.
|
||||
* @throws Exception on failure.
|
||||
*/
|
||||
public function insertUploads($name, $metadata = [], $options = [])
|
||||
{
|
||||
$uploadedFile = UploadedFile::getInstanceByName($name);
|
||||
if ($uploadedFile === null) {
|
||||
throw new Exception("Uploaded file '{$name}' does not exist.");
|
||||
}
|
||||
|
||||
$options['filename'] = $uploadedFile->name;
|
||||
$options['document'] = $metadata;
|
||||
$document = $this->createUpload($options)->addFile($uploadedFile->tempName)->complete();
|
||||
return $document['_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the file with given _id.
|
||||
* @param mixed $id _id of the file to find.
|
||||
* @return Download|null found file, or null if file does not exist
|
||||
* @throws Exception on failure.
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$document = $this->getFileCollection()->findOne(['_id' => $id]);
|
||||
return empty($document) ? null : $this->createDownload($document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the file with given _id.
|
||||
* @param mixed $id _id of the file to find.
|
||||
* @return bool whether the operation was successful.
|
||||
* @throws Exception on failure.
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$this->remove(['_id' => $id], ['limit' => 1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that indexes, which are crucial for the file processing,
|
||||
* exist at this collection and [[chunkCollection]].
|
||||
* The check result is cached per collection instance.
|
||||
* @param bool $force whether to ignore internal collection instance cache.
|
||||
* @return $this self reference.
|
||||
*/
|
||||
public function ensureIndexes($force = false)
|
||||
{
|
||||
if (!$force && $this->indexesEnsured) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->ensureFileIndexes();
|
||||
$this->ensureChunkIndexes();
|
||||
|
||||
$this->indexesEnsured = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures indexes at file collection.
|
||||
*/
|
||||
private function ensureFileIndexes()
|
||||
{
|
||||
$indexKey = ['filename' => 1, 'uploadDate' => 1];
|
||||
foreach ($this->listIndexes() as $index) {
|
||||
if ($index['key'] === $indexKey) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->createIndex($indexKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures indexes at chunk collection.
|
||||
*/
|
||||
private function ensureChunkIndexes()
|
||||
{
|
||||
$chunkCollection = $this->getChunkCollection();
|
||||
$indexKey = ['files_id' => 1, 'n' => 1];
|
||||
foreach ($chunkCollection->listIndexes() as $index) {
|
||||
if (!empty($index['unique']) && $index['key'] === $indexKey) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$chunkCollection->createIndex($indexKey, ['unique' => true]);
|
||||
}
|
||||
}
|
||||
149
vendor/yiisoft/yii2-mongodb/src/file/Cursor.php
vendored
Normal file
149
vendor/yiisoft/yii2-mongodb/src/file/Cursor.php
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
/**
|
||||
* Cursor is a wrapper around [[\MongoDB\Driver\Cursor]], which allows returning of the
|
||||
* record with [[Download]] instance attached.
|
||||
*
|
||||
* @method \MongoDB\Driver\Cursor getInnerIterator()
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.1
|
||||
*/
|
||||
class Cursor extends \IteratorIterator implements \Countable
|
||||
{
|
||||
/**
|
||||
* @var Collection related GridFS collection instance.
|
||||
*/
|
||||
public $collection;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param Collection $collection
|
||||
* @param \MongoDB\Driver\Cursor $cursor
|
||||
*/
|
||||
public function __construct($collection, $cursor)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
parent::__construct($cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current element
|
||||
* This method is required by the interface [[\Iterator]].
|
||||
* @return mixed current row
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$value = parent::current();
|
||||
if (!isset($value['file'])) {
|
||||
$value['file'] = $this->collection->createDownload(array_intersect_key($value, ['_id' => true, 'filename' => true, 'length' => true, 'chunkSize' => true]));
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count elements of this cursor.
|
||||
* This method is required by the interface [[\Countable]].
|
||||
* @return int elements count.
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->cursor);
|
||||
}
|
||||
|
||||
// Mock up original cursor interface :
|
||||
|
||||
/**
|
||||
* Returns an array containing all results for this cursor
|
||||
* @return array containing all results for this cursor.
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this as $key => $value) {
|
||||
$result[$key] = $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID for this cursor.
|
||||
* @return \MongoDB\Driver\CursorId cursor ID.
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->getInnerIterator()->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a type map to use for BSON unserialization.
|
||||
* @param array $typemap type map.
|
||||
*/
|
||||
public function setTypeMap($typemap)
|
||||
{
|
||||
$this->getInnerIterator()->setTypeMap($typemap);
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP magic method, which is invoked on attempt of invocation not existing method.
|
||||
* It redirects method call to inner iterator.
|
||||
* @param string $name method name.
|
||||
* @param array $arguments method arguments
|
||||
* @return mixed method result.
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
return call_user_func_array([$this->getInnerIterator(), $name], $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP magic method, which is invoked on attempt of setting not existing property.
|
||||
* It passes value to the inner iterator.
|
||||
* @param string $name field name.
|
||||
* @param mixed $value field value.
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->getInnerIterator()->{$name} = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP magic method, which is invoked on attempt of getting not existing property.
|
||||
* It returns value from the inner iterator.
|
||||
* @param string $name field name.
|
||||
* @return mixed field value.
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->getInnerIterator()->{$name};
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP magic method, which is invoked on attempt of checking if a property is set.
|
||||
* @param string $name field name.
|
||||
* @return bool whether field exists or not.
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
$cursor = $this->getInnerIterator();
|
||||
return isset($cursor->$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP magic method, which is invoked on attempt of unsetting of property.
|
||||
* @param string $name field name.
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
$cursor = $this->getInnerIterator();
|
||||
unset($cursor->$name);
|
||||
}
|
||||
}
|
||||
319
vendor/yiisoft/yii2-mongodb/src/file/Download.php
vendored
Normal file
319
vendor/yiisoft/yii2-mongodb/src/file/Download.php
vendored
Normal file
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
use MongoDB\BSON\ObjectID;
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\base\BaseObject;
|
||||
use yii\helpers\FileHelper;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* Download represents the GridFS download operation.
|
||||
*
|
||||
* A `Download` object is usually created by calling [[Collection::get()]] or [[Collection::createDownload()]].
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```php
|
||||
* Yii::$app->mongodb->getFileCollection()->createDownload($document['_id'])->toFile('/path/to/file.dat');
|
||||
* ```
|
||||
*
|
||||
* You can use `Download::substr()` to read a specific part of the file:
|
||||
*
|
||||
* ```php
|
||||
* $filePart = Yii::$app->mongodb->getFileCollection()->createDownload($document['_id'])->substr(256, 1024);
|
||||
* ```
|
||||
*
|
||||
* @property string $bytes File content. This property is read-only.
|
||||
* @property \MongoDB\Driver\Cursor $chunkCursor Chuck list cursor. This property is read-only.
|
||||
* @property \Iterator $chunkIterator Chuck cursor iterator. This property is read-only.
|
||||
* @property array $document Document to be downloaded. Note that the type of this property differs in getter
|
||||
* and setter. See [[getDocument()]] and [[setDocument()]] for details.
|
||||
* @property string|null $filename File name. This property is read-only.
|
||||
* @property resource $resource File stream resource. This property is read-only.
|
||||
* @property int $size File size. This property is read-only.
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.1
|
||||
*/
|
||||
class Download extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @var Collection file collection to be used.
|
||||
*/
|
||||
public $collection;
|
||||
|
||||
/**
|
||||
* @var array|ObjectID document to be downloaded.
|
||||
*/
|
||||
private $_document;
|
||||
/**
|
||||
* @var \MongoDB\Driver\Cursor cursor for the file chunks.
|
||||
*/
|
||||
private $_chunkCursor;
|
||||
/**
|
||||
* @var \Iterator iterator for [[chunkCursor]].
|
||||
*/
|
||||
private $_chunkIterator;
|
||||
/**
|
||||
* @var resource|null
|
||||
*/
|
||||
private $_resource;
|
||||
|
||||
|
||||
/**
|
||||
* @return array document to be downloaded.
|
||||
* @throws InvalidConfigException on invalid document configuration.
|
||||
*/
|
||||
public function getDocument()
|
||||
{
|
||||
if (!is_array($this->_document)) {
|
||||
if (is_scalar($this->_document) || $this->_document instanceof ObjectID) {
|
||||
$document = $this->collection->findOne(['_id' => $this->_document]);
|
||||
if (empty($document)) {
|
||||
throw new InvalidConfigException('Document id=' . $this->_document . ' does not exist at collection "' . $this->collection->getFullName() . '"');
|
||||
}
|
||||
$this->_document = $document;
|
||||
} else {
|
||||
$this->_document = (array)$this->_document;
|
||||
}
|
||||
}
|
||||
return $this->_document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data of the document to be downloaded.
|
||||
* Document can be specified by its ID, in this case its data will be fetched automatically
|
||||
* via extra query.
|
||||
* @param array|ObjectID $document document raw data or document ID.
|
||||
*/
|
||||
public function setDocument($document)
|
||||
{
|
||||
$this->_document = $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the associated file.
|
||||
* @return int file size.
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
$document = $this->getDocument();
|
||||
return isset($document['length']) ? $document['length'] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns associated file's filename.
|
||||
* @return string|null file name.
|
||||
*/
|
||||
public function getFilename()
|
||||
{
|
||||
$document = $this->getDocument();
|
||||
return isset($document['filename']) ? $document['filename'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file chunks read cursor.
|
||||
* @param bool $refresh whether to recreate cursor, if it is already exist.
|
||||
* @return \MongoDB\Driver\Cursor chuck list cursor.
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public function getChunkCursor($refresh = false)
|
||||
{
|
||||
if ($refresh || $this->_chunkCursor === null) {
|
||||
$file = $this->getDocument();
|
||||
$this->_chunkCursor = $this->collection->getChunkCollection()->find(
|
||||
['files_id' => $file['_id']],
|
||||
[],
|
||||
['sort' => ['n' => 1]]
|
||||
);
|
||||
}
|
||||
return $this->_chunkCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns iterator for the file chunks cursor.
|
||||
* @param bool $refresh whether to recreate iterator, if it is already exist.
|
||||
* @return \Iterator chuck cursor iterator.
|
||||
*/
|
||||
public function getChunkIterator($refresh = false)
|
||||
{
|
||||
if ($refresh || $this->_chunkIterator === null) {
|
||||
$this->_chunkIterator = new \IteratorIterator($this->getChunkCursor($refresh));
|
||||
$this->_chunkIterator->rewind();
|
||||
}
|
||||
return $this->_chunkIterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves file into the given stream.
|
||||
* @param resource $stream stream, which file should be saved to.
|
||||
* @return int number of written bytes.
|
||||
*/
|
||||
public function toStream($stream)
|
||||
{
|
||||
$bytesWritten = 0;
|
||||
foreach ($this->getChunkCursor() as $chunk) {
|
||||
$bytesWritten += fwrite($stream, $chunk['data']->getData());
|
||||
}
|
||||
return $bytesWritten;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves download to the physical file.
|
||||
* @param string $filename name of the physical file.
|
||||
* @return int number of written bytes.
|
||||
*/
|
||||
public function toFile($filename)
|
||||
{
|
||||
$filename = Yii::getAlias($filename);
|
||||
FileHelper::createDirectory(dirname($filename));
|
||||
return $this->toStream(fopen($filename, 'w+'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string of the bytes in the associated file.
|
||||
* @return string file content.
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
$result = '';
|
||||
foreach ($this->getChunkCursor() as $chunk) {
|
||||
$result .= $chunk['data']->getData();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an opened stream resource, which can be used to read file.
|
||||
* Note: each invocation of this method will create new file resource.
|
||||
* @return resource stream resource.
|
||||
*/
|
||||
public function toResource()
|
||||
{
|
||||
$protocol = $this->collection->database->connection->registerFileStreamWrapper();
|
||||
|
||||
$context = stream_context_create([
|
||||
$protocol => [
|
||||
'download' => $this,
|
||||
]
|
||||
]);
|
||||
|
||||
$document = $this->getDocument();
|
||||
$url = "{$protocol}://{$this->collection->database->name}.{$this->collection->prefix}?_id={$document['_id']}";
|
||||
return fopen($url, 'r', false, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return part of a file.
|
||||
* @param int $start reading start position.
|
||||
* If non-negative, the returned string will start at the start'th position in file, counting from zero.
|
||||
* If negative, the returned string will start at the start'th character from the end of file.
|
||||
* @param int $length number of bytes to read.
|
||||
* If given and is positive, the string returned will contain at most length characters beginning from start (depending on the length of file).
|
||||
* If given and is negative, then that many characters will be omitted from the end of file (after the start position has been calculated when a start is negative).
|
||||
* @return string|false the extracted part of file or `false` on failure
|
||||
*/
|
||||
public function substr($start, $length)
|
||||
{
|
||||
$document = $this->getDocument();
|
||||
|
||||
if ($start < 0) {
|
||||
$start = max($document['length'] + $start, 0);
|
||||
}
|
||||
|
||||
if ($start > $document['length']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($length < 0) {
|
||||
$length = $document['length'] - $start + $length;
|
||||
if ($length < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$chunkSize = $document['chunkSize'];
|
||||
|
||||
$startChunkNumber = floor($start / $chunkSize);
|
||||
|
||||
$chunkIterator = $this->getChunkIterator();
|
||||
|
||||
if (!$chunkIterator->valid()) {
|
||||
// invalid iterator state - recreate iterator
|
||||
// unable to use `rewind` due to error "Cursors cannot rewind after starting iteration"
|
||||
$chunkIterator = $this->getChunkIterator(true);
|
||||
}
|
||||
|
||||
if ($chunkIterator->key() > $startChunkNumber) {
|
||||
// unable to go back by iterator
|
||||
// unable to use `rewind` due to error "Cursors cannot rewind after starting iteration"
|
||||
$chunkIterator = $this->getChunkIterator(true);
|
||||
}
|
||||
|
||||
$result = '';
|
||||
|
||||
$chunkDataOffset = $start - $startChunkNumber * $chunkSize;
|
||||
while ($chunkIterator->valid()) {
|
||||
if ($chunkIterator->key() >= $startChunkNumber) {
|
||||
$chunk = $chunkIterator->current();
|
||||
$data = $chunk['data']->getData();
|
||||
|
||||
$readLength = min($chunkSize - $chunkDataOffset, $length);
|
||||
|
||||
$result .= StringHelper::byteSubstr($data, $chunkDataOffset, $readLength);
|
||||
|
||||
$length -= $readLength;
|
||||
if ($length <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
$chunkDataOffset = 0;
|
||||
}
|
||||
|
||||
$chunkIterator->next();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Compatibility with `MongoGridFSFile` :
|
||||
|
||||
/**
|
||||
* Alias of [[toString()]] method.
|
||||
* @return string file content.
|
||||
*/
|
||||
public function getBytes()
|
||||
{
|
||||
return $this->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of [[toFile()]] method.
|
||||
* @param string $filename name of the physical file.
|
||||
* @return int number of written bytes.
|
||||
*/
|
||||
public function write($filename)
|
||||
{
|
||||
return $this->toFile($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns persistent stream resource, which can be used to read file.
|
||||
* @return resource file stream resource.
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
if ($this->_resource === null) {
|
||||
$this->_resource = $this->toResource();
|
||||
}
|
||||
return $this->_resource;
|
||||
}
|
||||
}
|
||||
39
vendor/yiisoft/yii2-mongodb/src/file/Query.php
vendored
Normal file
39
vendor/yiisoft/yii2-mongodb/src/file/Query.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Query represents Mongo "find" operation for GridFS collection.
|
||||
*
|
||||
* Query behaves exactly as regular [[\yii\mongodb\Query]].
|
||||
* Found files will be represented as arrays of file document attributes with
|
||||
* additional 'file' key, which stores [[\MongoGridFSFile]] instance.
|
||||
*
|
||||
* @property Collection $collection Collection instance. This property is read-only.
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Query extends \yii\mongodb\Query
|
||||
{
|
||||
/**
|
||||
* Returns the Mongo collection for this query.
|
||||
* @param \yii\mongodb\Connection $db Mongo connection.
|
||||
* @return Collection collection instance.
|
||||
*/
|
||||
public function getCollection($db = null)
|
||||
{
|
||||
if ($db === null) {
|
||||
$db = Yii::$app->get('mongodb');
|
||||
}
|
||||
|
||||
return $db->getFileCollection($this->from);
|
||||
}
|
||||
}
|
||||
415
vendor/yiisoft/yii2-mongodb/src/file/StreamWrapper.php
vendored
Normal file
415
vendor/yiisoft/yii2-mongodb/src/file/StreamWrapper.php
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\base\BaseObject;
|
||||
use yii\di\Instance;
|
||||
use yii\helpers\StringHelper;
|
||||
use yii\mongodb\Connection;
|
||||
|
||||
/**
|
||||
* StreamWrapper provides stream wrapper for MongoDB GridFS, allowing file operations via
|
||||
* regular PHP stream resources.
|
||||
*
|
||||
* Before feature can be used this wrapper should be registered via [[register()]] method.
|
||||
* It is usually performed via [[yii\mongodb\Connection::registerFileStreamWrapper()]].
|
||||
*
|
||||
* Note: do not use this class directly - its instance will be created and maintained by PHP internally
|
||||
* once corresponding stream resource is created.
|
||||
*
|
||||
* Resource path should be specified in following format:
|
||||
*
|
||||
* ```
|
||||
* 'protocol://databaseName.fileCollectionPrefix?file_attribute=value'
|
||||
* ```
|
||||
*
|
||||
* Write example:
|
||||
*
|
||||
* ```php
|
||||
* $resource = fopen('gridfs://mydatabase.fs?filename=new_file.txt', 'w');
|
||||
* fwrite($resource, 'some content');
|
||||
* // ...
|
||||
* fclose($resource);
|
||||
* ```
|
||||
*
|
||||
* Read example:
|
||||
*
|
||||
* ```php
|
||||
* $resource = fopen('gridfs://mydatabase.fs?filename=my_file.txt', 'r');
|
||||
* $fileContent = stream_get_contents($resource);
|
||||
* ```
|
||||
*
|
||||
* @see http://php.net/manual/en/function.stream-wrapper-register.php
|
||||
*
|
||||
* @property array $contextOptions Context options. This property is read-only.
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.1
|
||||
*/
|
||||
class StreamWrapper extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @var resource associated stream resource context.
|
||||
* This property is set automatically by PHP once wrapper is instantiated.
|
||||
*/
|
||||
public $context;
|
||||
|
||||
/**
|
||||
* @var array context options associated with [[context]].
|
||||
*/
|
||||
private $_contextOptions;
|
||||
/**
|
||||
* @var string protocol associated with stream
|
||||
*/
|
||||
private $_protocol;
|
||||
/**
|
||||
* @var string namespace in format 'databaseName.collectionName' associated with stream.
|
||||
*/
|
||||
private $_namespace;
|
||||
/**
|
||||
* @var array query parameters passed for the stream.
|
||||
*/
|
||||
private $_queryParams = [];
|
||||
/**
|
||||
* @var Upload file upload instance
|
||||
*/
|
||||
private $_upload;
|
||||
/**
|
||||
* @var Download file upload instance
|
||||
*/
|
||||
private $_download;
|
||||
/**
|
||||
* @var int file pointer offset.
|
||||
*/
|
||||
private $_pointerOffset = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Registers this steam wrapper.
|
||||
* @param string $protocol name of the protocol to be used.
|
||||
* @param bool $force whether to register wrapper, even if protocol is already taken.
|
||||
*/
|
||||
public static function register($protocol = 'gridfs', $force = false)
|
||||
{
|
||||
if (in_array($protocol, stream_get_wrappers())) {
|
||||
if (!$force) {
|
||||
return;
|
||||
}
|
||||
stream_wrapper_unregister($protocol);
|
||||
}
|
||||
|
||||
stream_wrapper_register($protocol, get_called_class(), STREAM_IS_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns options associated with [[context]].
|
||||
* @return array context options.
|
||||
*/
|
||||
public function getContextOptions()
|
||||
{
|
||||
if ($this->_contextOptions === null) {
|
||||
$this->_contextOptions = stream_context_get_options($this->context);
|
||||
}
|
||||
return $this->_contextOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses stream open path, initializes internal parameters.
|
||||
* @param string $path stream open path.
|
||||
*/
|
||||
private function parsePath($path)
|
||||
{
|
||||
$pathInfo = parse_url($path);
|
||||
|
||||
$this->_protocol = $pathInfo['scheme'];
|
||||
$this->_namespace = $pathInfo['host'];
|
||||
parse_str($pathInfo['query'], $this->_queryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares [[Download]] instance for the read operations.
|
||||
* @return bool success.
|
||||
* @throws InvalidConfigException on invalid context configuration.
|
||||
*/
|
||||
private function prepareDownload()
|
||||
{
|
||||
$contextOptions = $this->getContextOptions();
|
||||
if (isset($contextOptions[$this->_protocol]['download'])) {
|
||||
$download = $contextOptions[$this->_protocol]['download'];
|
||||
if (!$download instanceof Download) {
|
||||
throw new InvalidConfigException('"download" context option should be an instance of "' . Download::className() . '"');
|
||||
}
|
||||
$this->_download = $download;
|
||||
return true;
|
||||
}
|
||||
|
||||
$collection = $this->fetchCollection();
|
||||
if (empty($this->_queryParams)) {
|
||||
return false;
|
||||
}
|
||||
$file = $collection->findOne($this->_queryParams);
|
||||
if (empty($file)) {
|
||||
throw new InvalidConfigException('Requested file does not exits.');
|
||||
}
|
||||
|
||||
$this->_download = $file['file'];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares [[Upload]] instance for the write operations.
|
||||
* @return bool success.
|
||||
* @throws InvalidConfigException on invalid context configuration.
|
||||
*/
|
||||
private function prepareUpload()
|
||||
{
|
||||
$contextOptions = $this->getContextOptions();
|
||||
if (isset($contextOptions[$this->_protocol]['upload'])) {
|
||||
$upload = $contextOptions[$this->_protocol]['upload'];
|
||||
if (!$upload instanceof Upload) {
|
||||
throw new InvalidConfigException('"upload" context option should be an instance of "' . Upload::className() . '"');
|
||||
}
|
||||
$this->_upload = $upload;
|
||||
return true;
|
||||
}
|
||||
|
||||
$collection = $this->fetchCollection();
|
||||
$this->_upload = $collection->createUpload(['document' => $this->_queryParams]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches associated file collection from stream options.
|
||||
* @return Collection file collection instance.
|
||||
* @throws InvalidConfigException on invalid stream options.
|
||||
*/
|
||||
private function fetchCollection()
|
||||
{
|
||||
$contextOptions = $this->getContextOptions();
|
||||
|
||||
if (isset($contextOptions[$this->_protocol]['collection'])) {
|
||||
$collection = $contextOptions[$this->_protocol]['collection'];
|
||||
if ($collection instanceof Collection) {
|
||||
throw new InvalidConfigException('"collection" context option should be an instance of "' . Collection::className() . '"');
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
$connection = isset($contextOptions[$this->_protocol]['db'])
|
||||
? $contextOptions[$this->_protocol]['db']
|
||||
: 'mongodb';
|
||||
|
||||
/* @var $connection Connection */
|
||||
$connection = Instance::ensure($connection, Connection::className());
|
||||
|
||||
list($databaseName, $collectionPrefix) = explode('.', $this->_namespace, 2);
|
||||
return $connection->getDatabase($databaseName)->getFileCollection($collectionPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default template for file statistic data set.
|
||||
* @see stat()
|
||||
* @return array statistic information.
|
||||
*/
|
||||
private function fileStatisticsTemplate()
|
||||
{
|
||||
return [
|
||||
0 => 0, 'dev' => 0,
|
||||
1 => 0, 'ino' => 0,
|
||||
2 => 0, 'mode' => 0,
|
||||
3 => 0, 'nlink' => 0,
|
||||
4 => 0, 'uid' => 0,
|
||||
5 => 0, 'gid' => 0,
|
||||
6 => -1, 'rdev' => -1,
|
||||
7 => 0, 'size' => 0,
|
||||
8 => 0, 'atime' => 0,
|
||||
9 => 0, 'mtime' => 0,
|
||||
10 => 0, 'ctime' => 0,
|
||||
11 => -1, 'blksize' => -1,
|
||||
12 => -1, 'blocks' => -1,
|
||||
];
|
||||
}
|
||||
|
||||
// Stream Interface :
|
||||
|
||||
/**
|
||||
* Closes a resource.
|
||||
* This method is called in response to `fclose()`.
|
||||
* @see fclose()
|
||||
*/
|
||||
public function stream_close()
|
||||
{
|
||||
if ($this->_upload !== null) {
|
||||
$this->_upload->complete();
|
||||
$this->_upload = null;
|
||||
}
|
||||
if ($this->_download !== null) {
|
||||
$this->_download = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for end-of-file on a file pointer.
|
||||
* This method is called in response to `feof()`.
|
||||
* @see feof()
|
||||
* @return bool `true` if the read/write position is at the end of the stream and
|
||||
* if no more data is available to be read, or `false` otherwise.
|
||||
*/
|
||||
public function stream_eof()
|
||||
{
|
||||
return $this->_download !== null
|
||||
? ($this->_pointerOffset >= $this->_download->getSize())
|
||||
: true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens file.
|
||||
* This method is called immediately after the wrapper is initialized (f.e. by `fopen()` and `file_get_contents()`).
|
||||
* @see fopen()
|
||||
* @param string $path specifies the URL that was passed to the original function.
|
||||
* @param string $mode mode used to open the file, as detailed for `fopen()`.
|
||||
* @param int $options additional flags set by the streams API.
|
||||
* @param string $openedPath real opened path.
|
||||
* @return bool whether operation is successful.
|
||||
*/
|
||||
public function stream_open($path, $mode, $options, &$openedPath)
|
||||
{
|
||||
if ($options & STREAM_USE_PATH) {
|
||||
$openedPath = $path;
|
||||
}
|
||||
|
||||
$this->parsePath($path);
|
||||
|
||||
switch ($mode) {
|
||||
case 'r':
|
||||
return $this->prepareDownload();
|
||||
case 'w':
|
||||
return $this->prepareUpload();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from stream.
|
||||
* This method is called in response to `fread()` and `fgets()`.
|
||||
* @see fread()
|
||||
* @param int $count count of bytes of data from the current position should be returned.
|
||||
* @return string|false if there are less than count bytes available, return as many as are available.
|
||||
* If no more data is available, return `false`.
|
||||
*/
|
||||
public function stream_read($count)
|
||||
{
|
||||
if ($this->_download === null) {
|
||||
return false;
|
||||
}
|
||||
$result = $this->_download->substr($this->_pointerOffset, $count);
|
||||
$this->_pointerOffset += $count;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes to stream.
|
||||
* This method is called in response to `fwrite()`.
|
||||
* @see fwrite()
|
||||
* @param string $data string to be stored into the underlying stream.
|
||||
* @return int the number of bytes that were successfully stored.
|
||||
*/
|
||||
public function stream_write($data)
|
||||
{
|
||||
if ($this->_upload === null) {
|
||||
return false;
|
||||
}
|
||||
$this->_upload->addContent($data);
|
||||
$result = StringHelper::byteLength($data);
|
||||
$this->_pointerOffset += $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called in response to `fflush()` and when the stream is being closed
|
||||
* while any unflushed data has been written to it before.
|
||||
* @see fflush()
|
||||
* @return bool whether cached data was successfully stored.
|
||||
*/
|
||||
public function stream_flush()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve information about a file resource.
|
||||
* This method is called in response to `stat()`.
|
||||
* @see stat()
|
||||
* @return array file statistic information.
|
||||
*/
|
||||
public function stream_stat()
|
||||
{
|
||||
$statistics = $this->fileStatisticsTemplate();
|
||||
|
||||
if ($this->_download !== null) {
|
||||
$statistics[7] = $statistics['size'] = $this->_download->getSize();
|
||||
}
|
||||
if ($this->_upload !== null) {
|
||||
$statistics[7] = $statistics['size'] = $this->_pointerOffset;
|
||||
}
|
||||
|
||||
return $statistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to specific location in a stream.
|
||||
* This method is called in response to `fseek()`.
|
||||
* @see fseek()
|
||||
* @param int $offset The stream offset to seek to.
|
||||
* @param int $whence
|
||||
* Possible values:
|
||||
*
|
||||
* - SEEK_SET - Set position equal to offset bytes.
|
||||
* - SEEK_CUR - Set position to current location plus offset.
|
||||
* - SEEK_END - Set position to end-of-file plus offset.
|
||||
*
|
||||
* @return bool Return true if the position was updated, false otherwise.
|
||||
*/
|
||||
public function stream_seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
switch ($whence) {
|
||||
case SEEK_SET:
|
||||
if ($offset < $this->_download->getSize() && $offset >= 0) {
|
||||
$this->_pointerOffset = $offset;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case SEEK_CUR:
|
||||
if ($offset >= 0) {
|
||||
$this->_pointerOffset += $offset;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case SEEK_END:
|
||||
if ($this->_download->getSize() + $offset >= 0) {
|
||||
$this->_pointerOffset = $this->_download->getSize() + $offset;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current position of a stream.
|
||||
* This method is called in response to `fseek()` to determine the current position.
|
||||
* @see fseek()
|
||||
* @return int Should return the current position of the stream.
|
||||
*/
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->_pointerOffset;
|
||||
}
|
||||
}
|
||||
280
vendor/yiisoft/yii2-mongodb/src/file/Upload.php
vendored
Normal file
280
vendor/yiisoft/yii2-mongodb/src/file/Upload.php
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\mongodb\file;
|
||||
|
||||
use MongoDB\BSON\Binary;
|
||||
use MongoDB\BSON\ObjectID;
|
||||
use MongoDB\BSON\UTCDatetime;
|
||||
use MongoDB\Driver\Exception\InvalidArgumentException;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\base\BaseObject;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* Upload represents the GridFS upload operation.
|
||||
*
|
||||
* An `Upload` object is usually created by calling [[Collection::createUpload()]].
|
||||
*
|
||||
* Note: instance of this class is 'single use' only. Do not attempt to use same `Upload` instance for
|
||||
* multiple file upload.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```php
|
||||
* $document = Yii::$app->mongodb->getFileCollection()->createUpload()
|
||||
* ->addContent('Part 1')
|
||||
* ->addContent('Part 2')
|
||||
* // ...
|
||||
* ->complete();
|
||||
* ```
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.1
|
||||
*/
|
||||
class Upload extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @var Collection file collection to be used.
|
||||
*/
|
||||
public $collection;
|
||||
/**
|
||||
* @var string filename to be used for file storage.
|
||||
*/
|
||||
public $filename;
|
||||
/**
|
||||
* @var array additional file document contents.
|
||||
* Common GridFS columns:
|
||||
*
|
||||
* - metadata: array, additional data associated with the file.
|
||||
* - aliases: array, an array of aliases.
|
||||
* - contentType: string, content type to be stored with the file.
|
||||
*/
|
||||
public $document = [];
|
||||
/**
|
||||
* @var int chunk size in bytes.
|
||||
*/
|
||||
public $chunkSize = 261120;
|
||||
/**
|
||||
* @var int total upload length in bytes.
|
||||
*/
|
||||
public $length = 0;
|
||||
/**
|
||||
* @var int file chunk counts.
|
||||
*/
|
||||
public $chunkCount = 0;
|
||||
|
||||
/**
|
||||
* @var ObjectID file document ID.
|
||||
*/
|
||||
private $_documentId;
|
||||
/**
|
||||
* @var resource has context for collecting md5 hash
|
||||
*/
|
||||
private $_hashContext;
|
||||
/**
|
||||
* @var string internal data buffer
|
||||
*/
|
||||
private $_buffer;
|
||||
/**
|
||||
* @var bool indicates whether upload is complete or not.
|
||||
*/
|
||||
private $_isComplete = false;
|
||||
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* Makes sure abandoned upload is cancelled.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (!$this->_isComplete) {
|
||||
$this->cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->_hashContext = hash_init('md5');
|
||||
|
||||
if (isset($this->document['_id'])) {
|
||||
if ($this->document['_id'] instanceof ObjectID) {
|
||||
$this->_documentId = $this->document['_id'];
|
||||
} else {
|
||||
try {
|
||||
$this->_documentId = new ObjectID($this->document['_id']);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
// invalid id format
|
||||
$this->_documentId = $this->document['_id'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->_documentId = new ObjectID();
|
||||
}
|
||||
|
||||
$this->collection->ensureIndexes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds string content to the upload.
|
||||
* This method can invoked several times before [[complete()]] is called.
|
||||
* @param string $content binary content.
|
||||
* @return $this self reference.
|
||||
*/
|
||||
public function addContent($content)
|
||||
{
|
||||
$freeBufferLength = $this->chunkSize - StringHelper::byteLength($this->_buffer);
|
||||
$contentLength = StringHelper::byteLength($content);
|
||||
if ($contentLength > $freeBufferLength) {
|
||||
$this->_buffer .= StringHelper::byteSubstr($content, 0, $freeBufferLength);
|
||||
$this->flushBuffer(true);
|
||||
return $this->addContent(StringHelper::byteSubstr($content, $freeBufferLength));
|
||||
} else {
|
||||
$this->_buffer .= $content;
|
||||
$this->flushBuffer();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds stream content to the upload.
|
||||
* This method can invoked several times before [[complete()]] is called.
|
||||
* @param resource $stream data source stream.
|
||||
* @return $this self reference.
|
||||
*/
|
||||
public function addStream($stream)
|
||||
{
|
||||
while (!feof($stream)) {
|
||||
$freeBufferLength = $this->chunkSize - StringHelper::byteLength($this->_buffer);
|
||||
|
||||
$streamChunk = fread($stream, $freeBufferLength);
|
||||
if ($streamChunk === false) {
|
||||
break;
|
||||
}
|
||||
$this->_buffer .= $streamChunk;
|
||||
$this->flushBuffer();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file content to the upload.
|
||||
* This method can invoked several times before [[complete()]] is called.
|
||||
* @param string $filename source file name.
|
||||
* @return $this self reference.
|
||||
*/
|
||||
public function addFile($filename)
|
||||
{
|
||||
if ($this->filename === null) {
|
||||
$this->filename = basename($filename);
|
||||
}
|
||||
|
||||
$stream = fopen($filename, 'r+');
|
||||
if ($stream === false) {
|
||||
throw new InvalidParamException("Unable to read file '{$filename}'");
|
||||
}
|
||||
return $this->addStream($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes upload.
|
||||
* @return array saved document.
|
||||
*/
|
||||
public function complete()
|
||||
{
|
||||
$this->flushBuffer(true);
|
||||
|
||||
$document = $this->insertFile();
|
||||
|
||||
$this->_isComplete = true;
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the upload.
|
||||
*/
|
||||
public function cancel()
|
||||
{
|
||||
$this->_buffer = null;
|
||||
|
||||
$this->collection->getChunkCollection()->remove(['files_id' => $this->_documentId], ['limit' => 0]);
|
||||
$this->collection->remove(['_id' => $this->_documentId], ['limit' => 1]);
|
||||
|
||||
$this->_isComplete = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes [[buffer]] to the chunk if it is full.
|
||||
* @param bool $force whether to enforce flushing.
|
||||
*/
|
||||
private function flushBuffer($force = false)
|
||||
{
|
||||
if ($this->_buffer === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($force || StringHelper::byteLength($this->_buffer) == $this->chunkSize) {
|
||||
$this->insertChunk($this->_buffer);
|
||||
$this->_buffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts file chunk.
|
||||
* @param string $data chunk binary content.
|
||||
*/
|
||||
private function insertChunk($data)
|
||||
{
|
||||
$chunkDocument = [
|
||||
'files_id' => $this->_documentId,
|
||||
'n' => $this->chunkCount,
|
||||
'data' => new Binary($data, Binary::TYPE_GENERIC),
|
||||
];
|
||||
|
||||
hash_update($this->_hashContext, $data);
|
||||
|
||||
$this->collection->getChunkCollection()->insert($chunkDocument);
|
||||
$this->length += StringHelper::byteLength($data);
|
||||
$this->chunkCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts [[document]] into file collection.
|
||||
* @return array inserted file document data.
|
||||
*/
|
||||
private function insertFile()
|
||||
{
|
||||
$fileDocument = [
|
||||
'_id' => $this->_documentId,
|
||||
'uploadDate' => new UTCDateTime(round(microtime(true) * 1000)),
|
||||
];
|
||||
if ($this->filename === null) {
|
||||
$fileDocument['filename'] = $this->_documentId . '.dat';
|
||||
} else {
|
||||
$fileDocument['filename'] = $this->filename;
|
||||
}
|
||||
|
||||
$fileDocument = array_merge(
|
||||
$fileDocument,
|
||||
$this->document,
|
||||
[
|
||||
'chunkSize' => $this->chunkSize,
|
||||
'length' => $this->length,
|
||||
'md5' => hash_final($this->_hashContext),
|
||||
]
|
||||
);
|
||||
|
||||
$this->collection->insert($fileDocument);
|
||||
return $fileDocument;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user