EMongoFile.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. /**
  3. * The MongoYii representation of a helper for uploading files to GridFS.
  4. *
  5. * It can accept an input file from $_FILES via ::populate and can also do find() and findOne() on the files collection.
  6. * This file is specifically designed for uploading files from a form to GridFS and is merely a helper, IT IS IN NO WAY REQUIRED.
  7. */
  8. class EMongoFile extends EMongoDocument
  9. {
  10. /**
  11. * Our file object, can be either the MongoGridFSFile or CUploadFile
  12. */
  13. private $_file;
  14. // Helper functions to get some common functionality on this class
  15. /**
  16. * @return string|bool
  17. */
  18. public function getFilename()
  19. {
  20. if($this->getFile() instanceof MongoGridFSFile){
  21. return $this->getFile()->getFilename();
  22. }
  23. if($this->getFile() instanceof CUploadedFile){
  24. return $this->getFile()->getTempName();
  25. }
  26. if(is_string($this->getFile()) && is_file($this->getFile())){
  27. return $this->getFile();
  28. }
  29. return false;
  30. }
  31. /**
  32. * @return int|bool
  33. */
  34. public function getSize()
  35. {
  36. if($this->getFile() instanceof MongoGridFSFile || $this->getFile() instanceof CUploadedFile){
  37. return $this->getFile()->getSize();
  38. }
  39. if(is_file($this->getFile())){
  40. return filesize($this->getFile());
  41. }
  42. return false;
  43. }
  44. /**
  45. * @return string|bool
  46. */
  47. public function getBytes()
  48. {
  49. if($this->getFile() instanceof MongoGridFSFile){
  50. return $this->getFile()->getBytes();
  51. }
  52. if($this->getFile() instanceof CUploadedFile || (is_file($this->getFile()) && is_readable($this->getFile()))){
  53. return file_get_contents($this->getFilename());
  54. }
  55. return false;
  56. }
  57. /**
  58. * Gets the file object
  59. */
  60. public function getFile()
  61. {
  62. // This if statement allows for you to continue using this class AFTER insert
  63. // basically it will only get the file if you plan on using it further which means that
  64. // otherwise it omits at least one database call each time
  65. if($this->_id instanceof MongoId && !$this->_file instanceof MongoGridFSFile){
  66. return $this->_file = $this->getCollection()->get($this->_id);
  67. }
  68. return $this->_file;
  69. }
  70. /**
  71. * Sets the file object
  72. */
  73. public function setFile($v)
  74. {
  75. $this->_file = $v;
  76. }
  77. /**
  78. * This denotes the prefix to all gridfs collections set by this class
  79. * @return string
  80. */
  81. public function collectionPrefix()
  82. {
  83. return 'fs';
  84. }
  85. /**
  86. * Returns the static model of the specified AR class.
  87. * @param string $className
  88. * @return EMongoDocument - User the static model class
  89. */
  90. public static function model($className = __CLASS__)
  91. {
  92. return parent::model($className);
  93. }
  94. /**
  95. * Magic will either call a function on the file if it exists or bubble to parent
  96. * @see EMongoDocument::__call()
  97. */
  98. public function __call($name, $parameters)
  99. {
  100. if($this->getFile() instanceof MongoGridFSFile && method_exists($this->getFile(), $name)){
  101. return call_user_func_array(array($this->getFile(), $name), $parameters);
  102. }
  103. return parent::__call($name, $parameters);
  104. }
  105. /**
  106. * This can populate from a $_FILES instance
  107. * @param CModel $model
  108. * @param string $attribute
  109. * @return boolean|EMongoFile|null
  110. */
  111. public static function populate($model, $attribute)
  112. {
  113. if($file = CUploadedFile::getInstance($model, $attribute)){
  114. $model=new EMongoFile();
  115. $model->setFile($file);
  116. return $model;
  117. }
  118. return null;
  119. }
  120. /**
  121. * This function populates from a stream
  122. *
  123. * You must unlink the tempfile yourself by calling unlink($file->getFilename())
  124. * @param string $stream
  125. * @return EMongoFile the new file generated from the stream
  126. public static function stream($stream){
  127. $tempFile = tempnam(null, 'tmp'); // returns a temporary filename
  128. $fp = fopen($tempFile, 'wb'); // open temporary file
  129. $putData = fopen($stream, 'rb'); // open input stream
  130. stream_copy_to_stream($putData, $fp); // write input stream directly into file
  131. fclose($putData);
  132. fclose($fp);
  133. $file = new EMongoFile();
  134. $file->setFile($tempFile);
  135. return $file;
  136. }
  137. */
  138. /**
  139. * Replaces the normal populateRecord specfically for GridFS by setting the attributes from the
  140. * MongoGridFsFile object correctly and other file details like size and name.
  141. * @see EMongoDocument::populateRecord()
  142. * @param array $attributes
  143. * @param bool $callAfterFind
  144. * @param bool $partial
  145. * @return EMongoDocument|null
  146. */
  147. public function populateRecord($attributes, $callAfterFind = true, $partial = false)
  148. {
  149. if($attributes === false){
  150. return null;
  151. }
  152. // the cursor will actually input a MongoGridFSFile object as the "document"
  153. // so what we wanna do is get the attributes or metadata attached to the file object
  154. // set it as our attributes and then set this classes file as the first param we got
  155. $file = $attributes;
  156. $attributes = $file->file;
  157. $record = $this->instantiate($attributes);
  158. $record->setFile($file);
  159. $record->setScenario('update');
  160. $record->setIsNewRecord(false);
  161. $record->init();
  162. $labels = array();
  163. foreach($attributes as $name => $value){
  164. $labels[$name] = 1;
  165. $record->$name = $value;
  166. }
  167. if($partial){
  168. $record->setIsPartial(true);
  169. $record->setProjectedFields($labels);
  170. }
  171. //$record->_pk=$record->primaryKey();
  172. $record->attachBehaviors($record->behaviors());
  173. if($callAfterFind){
  174. $record->afterFind();
  175. }
  176. return $record;
  177. }
  178. /**
  179. * Inserts the file.
  180. *
  181. * The only difference between the normal insert is that this uses the storeFile function on the GridFS object
  182. * @see EMongoDocument::insert()
  183. * @param array $attributes
  184. * @return bool
  185. * @throws EMongoException
  186. */
  187. public function insert($attributes = null)
  188. {
  189. if(!$this->getIsNewRecord()){
  190. throw new EMongoException(Yii::t('yii','The active record cannot be inserted to database because it is not new.'));
  191. }
  192. if(!$this->beforeSave()){
  193. return false;
  194. }
  195. $this->trace(__FUNCTION__);
  196. if($attributes === null){
  197. $document=$this->getRawDocument();
  198. }else{
  199. $document=$this->filterRawDocument($this->getAttributes($attributes));
  200. }
  201. if(YII_DEBUG){
  202. // we're actually physically testing for Yii debug mode here to stop us from
  203. // having to do the serialisation on the update doc normally.
  204. Yii::trace('Executing storeFile: {$document:' . json_encode($document) . '}', 'extensions.MongoYii.EMongoDocument');
  205. }
  206. if($this->getDbConnection()->enableProfiling){
  207. $this->profile('extensions.MongoYii.EMongoFile.insert({$document:' . json_encode($document) . '})', 'extensions.MongoYii.EMongoFile.insert');
  208. }
  209. if($_id = $this->getCollection()->storeFile($this->getFilename(), $document)){ // The key change
  210. $this->_id = $_id;
  211. $this->afterSave();
  212. $this->setIsNewRecord(false);
  213. $this->setScenario('update');
  214. return true;
  215. }
  216. return false;
  217. }
  218. /**
  219. * Get collection will now return the GridFS object from the driver
  220. * @see EMongoDocument::getCollection()
  221. */
  222. public function getCollection()
  223. {
  224. return $this->getDbConnection()->getDB()->getGridFS($this->collectionPrefix());
  225. }
  226. /**
  227. * Produces a trace message for functions in this class
  228. * @param string $func
  229. */
  230. public function trace($func)
  231. {
  232. Yii::trace(get_class($this) . '.' . $func.'()', 'extensions.MongoYii.EMongoFile');
  233. }
  234. }