MongoDB.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. */
  15. use Alcaeus\MongoDbAdapter\Helper;
  16. use MongoDB\Model\CollectionInfo;
  17. /**
  18. * Instances of this class are used to interact with a database.
  19. * @link http://www.php.net/manual/en/class.mongodb.php
  20. */
  21. class MongoDB
  22. {
  23. use Helper\ReadPreference;
  24. use Helper\SlaveOkay;
  25. use Helper\WriteConcern;
  26. const PROFILING_OFF = 0;
  27. const PROFILING_SLOW = 1;
  28. const PROFILING_ON = 2;
  29. /**
  30. * @var MongoClient
  31. */
  32. protected $connection;
  33. /**
  34. * @var \MongoDB\Database
  35. */
  36. protected $db;
  37. /**
  38. * @var string
  39. */
  40. protected $name;
  41. /**
  42. * Creates a new database
  43. *
  44. * This method is not meant to be called directly. The preferred way to create an instance of MongoDB is through {@see Mongo::__get()} or {@see Mongo::selectDB()}.
  45. * @link http://www.php.net/manual/en/mongodb.construct.php
  46. * @param MongoClient $conn Database connection.
  47. * @param string $name Database name.
  48. * @throws Exception
  49. * @return MongoDB Returns the database.
  50. */
  51. public function __construct(MongoClient $conn, $name)
  52. {
  53. $this->connection = $conn;
  54. $this->name = $name;
  55. $this->setReadPreferenceFromArray($conn->getReadPreference());
  56. $this->setWriteConcernFromArray($conn->getWriteConcern());
  57. $this->createDatabaseObject();
  58. }
  59. /**
  60. * @return \MongoDB\Database
  61. * @internal This method is not part of the ext-mongo API
  62. */
  63. public function getDb()
  64. {
  65. return $this->db;
  66. }
  67. /**
  68. * The name of this database
  69. *
  70. * @link http://www.php.net/manual/en/mongodb.--tostring.php
  71. * @return string Returns this database's name.
  72. */
  73. public function __toString()
  74. {
  75. return $this->name;
  76. }
  77. /**
  78. * Gets a collection
  79. *
  80. * @link http://www.php.net/manual/en/mongodb.get.php
  81. * @param string $name The name of the collection.
  82. * @return MongoCollection
  83. */
  84. public function __get($name)
  85. {
  86. // Handle w and wtimeout properties that replicate data stored in $readPreference
  87. if ($name === 'w' || $name === 'wtimeout') {
  88. return $this->getWriteConcern()[$name];
  89. }
  90. return $this->selectCollection($name);
  91. }
  92. /**
  93. * @param string $name
  94. * @param mixed $value
  95. */
  96. public function __set($name, $value)
  97. {
  98. if ($name === 'w' || $name === 'wtimeout') {
  99. $this->setWriteConcernFromArray([$name => $value] + $this->getWriteConcern());
  100. $this->createDatabaseObject();
  101. }
  102. }
  103. /**
  104. * Returns information about collections in this database
  105. *
  106. * @link http://www.php.net/manual/en/mongodb.getcollectioninfo.php
  107. * @param array $options An array of options for listing the collections.
  108. * @return array
  109. */
  110. public function getCollectionInfo(array $options = [])
  111. {
  112. // The includeSystemCollections option is no longer supported
  113. if (isset($options['includeSystemCollections'])) {
  114. unset($options['includeSystemCollections']);
  115. }
  116. $collections = $this->db->listCollections($options);
  117. $getCollectionInfo = function (CollectionInfo $collectionInfo) {
  118. return [
  119. 'name' => $collectionInfo->getName(),
  120. 'options' => $collectionInfo->getOptions(),
  121. ];
  122. };
  123. return array_map($getCollectionInfo, iterator_to_array($collections));
  124. }
  125. /**
  126. * Get all collections from this database
  127. *
  128. * @link http://www.php.net/manual/en/mongodb.getcollectionnames.php
  129. * @param array $options An array of options for listing the collections.
  130. * @return array Returns the names of the all the collections in the database as an array
  131. */
  132. public function getCollectionNames(array $options = [])
  133. {
  134. // The includeSystemCollections option is no longer supported
  135. if (isset($options['includeSystemCollections'])) {
  136. unset($options['includeSystemCollections']);
  137. }
  138. $collections = $this->db->listCollections($options);
  139. $getCollectionName = function (CollectionInfo $collectionInfo) {
  140. return $collectionInfo->getName();
  141. };
  142. return array_map($getCollectionName, iterator_to_array($collections));
  143. }
  144. /**
  145. * @return MongoClient
  146. * @internal This method is not part of the ext-mongo API
  147. */
  148. public function getConnection()
  149. {
  150. return $this->connection;
  151. }
  152. /**
  153. * Fetches toolkit for dealing with files stored in this database
  154. *
  155. * @link http://www.php.net/manual/en/mongodb.getgridfs.php
  156. * @param string $prefix The prefix for the files and chunks collections.
  157. * @return MongoGridFS Returns a new gridfs object for this database.
  158. */
  159. public function getGridFS($prefix = "fs")
  160. {
  161. return new \MongoGridFS($this, $prefix, $prefix);
  162. }
  163. /**
  164. * Gets this database's profiling level
  165. *
  166. * @link http://www.php.net/manual/en/mongodb.getprofilinglevel.php
  167. * @return int Returns the profiling level.
  168. */
  169. public function getProfilingLevel()
  170. {
  171. $result = $this->command(['profile' => -1]);
  172. return ($result['ok'] && isset($result['was'])) ? $result['was'] : 0;
  173. }
  174. /**
  175. * Sets this database's profiling level
  176. *
  177. * @link http://www.php.net/manual/en/mongodb.setprofilinglevel.php
  178. * @param int $level Profiling level.
  179. * @return int Returns the previous profiling level.
  180. */
  181. public function setProfilingLevel($level)
  182. {
  183. $result = $this->command(['profile' => $level]);
  184. return ($result['ok'] && isset($result['was'])) ? $result['was'] : 0;
  185. }
  186. /**
  187. * Drops this database
  188. *
  189. * @link http://www.php.net/manual/en/mongodb.drop.php
  190. * @return array Returns the database response.
  191. */
  192. public function drop()
  193. {
  194. return $this->db->drop();
  195. }
  196. /**
  197. * Repairs and compacts this database
  198. *
  199. * @link http://www.php.net/manual/en/mongodb.repair.php
  200. * @param bool $preserve_cloned_files [optional] <p>If cloned files should be kept if the repair fails.</p>
  201. * @param bool $backup_original_files [optional] <p>If original files should be backed up.</p>
  202. * @return array <p>Returns db response.</p>
  203. */
  204. public function repair($preserve_cloned_files = FALSE, $backup_original_files = FALSE)
  205. {
  206. return [];
  207. }
  208. /**
  209. * Gets a collection
  210. *
  211. * @link http://www.php.net/manual/en/mongodb.selectcollection.php
  212. * @param string $name <b>The collection name.</b>
  213. * @throws Exception if the collection name is invalid.
  214. * @return MongoCollection Returns a new collection object.
  215. */
  216. public function selectCollection($name)
  217. {
  218. return new MongoCollection($this, $name);
  219. }
  220. /**
  221. * Creates a collection
  222. *
  223. * @link http://www.php.net/manual/en/mongodb.createcollection.php
  224. * @param string $name The name of the collection.
  225. * @param array $options
  226. * @return MongoCollection Returns a collection object representing the new collection.
  227. */
  228. public function createCollection($name, $options)
  229. {
  230. $this->db->createCollection($name, $options);
  231. return $this->selectCollection($name);
  232. }
  233. /**
  234. * Drops a collection
  235. *
  236. * @link http://www.php.net/manual/en/mongodb.dropcollection.php
  237. * @param MongoCollection|string $coll MongoCollection or name of collection to drop.
  238. * @return array Returns the database response.
  239. *
  240. * @deprecated Use MongoCollection::drop() instead.
  241. */
  242. public function dropCollection($coll)
  243. {
  244. if ($coll instanceof MongoCollection) {
  245. $coll = $coll->getName();
  246. }
  247. return $this->db->dropCollection((string) $coll);
  248. }
  249. /**
  250. * Get a list of collections in this database
  251. *
  252. * @link http://www.php.net/manual/en/mongodb.listcollections.php
  253. * @param array $options
  254. * @return MongoCollection[] Returns a list of MongoCollections.
  255. */
  256. public function listCollections(array $options = [])
  257. {
  258. return array_map([$this, 'selectCollection'], $this->getCollectionNames($options));
  259. }
  260. /**
  261. * Creates a database reference
  262. *
  263. * @link http://www.php.net/manual/en/mongodb.createdbref.php
  264. * @param string $collection The collection to which the database reference will point.
  265. * @param mixed $document_or_id
  266. * @return array Returns a database reference array.
  267. */
  268. public function createDBRef($collection, $document_or_id)
  269. {
  270. if ($document_or_id instanceof \MongoId) {
  271. $id = $document_or_id;
  272. } elseif (is_object($document_or_id)) {
  273. if (! isset($document_or_id->_id)) {
  274. return null;
  275. }
  276. $id = $document_or_id->_id;
  277. } elseif (is_array($document_or_id)) {
  278. if (! isset($document_or_id['_id'])) {
  279. return null;
  280. }
  281. $id = $document_or_id['_id'];
  282. } else {
  283. $id = $document_or_id;
  284. }
  285. return MongoDBRef::create($collection, $id, $this->name);
  286. }
  287. /**
  288. * Fetches the document pointed to by a database reference
  289. *
  290. * @link http://www.php.net/manual/en/mongodb.getdbref.php
  291. * @param array $ref A database reference.
  292. * @return array Returns the document pointed to by the reference.
  293. */
  294. public function getDBRef(array $ref)
  295. {
  296. return MongoDBRef::get($this, $ref);
  297. }
  298. /**
  299. * Runs JavaScript code on the database server.
  300. *
  301. * @link http://www.php.net/manual/en/mongodb.execute.php
  302. * @param MongoCode|string $code Code to execute.
  303. * @param array $args [optional] Arguments to be passed to code.
  304. * @return array Returns the result of the evaluation.
  305. */
  306. public function execute($code, array $args = [])
  307. {
  308. return $this->command(['eval' => $code, 'args' => $args]);
  309. }
  310. /**
  311. * Execute a database command
  312. *
  313. * @link http://www.php.net/manual/en/mongodb.command.php
  314. * @param array $data The query to send.
  315. * @param array $options
  316. * @return array Returns database response.
  317. */
  318. public function command(array $data, $options = [], &$hash = null)
  319. {
  320. try {
  321. $cursor = new \MongoCommandCursor($this->connection, $this->name, $data);
  322. $cursor->setReadPreference($this->getReadPreference());
  323. return iterator_to_array($cursor)[0];
  324. } catch (\MongoDB\Driver\Exception\RuntimeException $e) {
  325. return [
  326. 'ok' => 0,
  327. 'errmsg' => $e->getMessage(),
  328. 'code' => $e->getCode(),
  329. ];
  330. }
  331. }
  332. /**
  333. * Check if there was an error on the most recent db operation performed
  334. *
  335. * @link http://www.php.net/manual/en/mongodb.lasterror.php
  336. * @return array Returns the error, if there was one.
  337. */
  338. public function lastError()
  339. {
  340. return $this->command(array('getLastError' => 1));
  341. }
  342. /**
  343. * Checks for the last error thrown during a database operation
  344. *
  345. * @link http://www.php.net/manual/en/mongodb.preverror.php
  346. * @return array Returns the error and the number of operations ago it occurred.
  347. */
  348. public function prevError()
  349. {
  350. return $this->command(array('getPrevError' => 1));
  351. }
  352. /**
  353. * Clears any flagged errors on the database
  354. *
  355. * @link http://www.php.net/manual/en/mongodb.reseterror.php
  356. * @return array Returns the database response.
  357. */
  358. public function resetError()
  359. {
  360. return $this->command(array('resetError' => 1));
  361. }
  362. /**
  363. * Creates a database error
  364. *
  365. * @link http://www.php.net/manual/en/mongodb.forceerror.php
  366. * @return boolean Returns the database response.
  367. */
  368. public function forceError()
  369. {
  370. return $this->command(array('forceerror' => 1));
  371. }
  372. /**
  373. * Log in to this database
  374. *
  375. * @link http://www.php.net/manual/en/mongodb.authenticate.php
  376. * @param string $username The username.
  377. * @param string $password The password (in plaintext).
  378. * @return array Returns database response. If the login was successful, it will return 1.
  379. */
  380. public function authenticate($username, $password)
  381. {
  382. $this->notImplemented();
  383. }
  384. /**
  385. * {@inheritdoc}
  386. */
  387. public function setReadPreference($readPreference, $tags = null)
  388. {
  389. $result = $this->setReadPreferenceFromParameters($readPreference, $tags);
  390. $this->createDatabaseObject();
  391. return $result;
  392. }
  393. /**
  394. * {@inheritdoc}
  395. */
  396. public function setWriteConcern($wstring, $wtimeout = 0)
  397. {
  398. $result = $this->setWriteConcernFromParameters($wstring, $wtimeout);
  399. $this->createDatabaseObject();
  400. return $result;
  401. }
  402. protected function notImplemented()
  403. {
  404. throw new \Exception('Not implemented');
  405. }
  406. /**
  407. * @return \MongoDB\Database
  408. */
  409. private function createDatabaseObject()
  410. {
  411. $options = [
  412. 'readPreference' => $this->readPreference,
  413. 'writeConcern' => $this->writeConcern,
  414. ];
  415. if ($this->db === null) {
  416. $this->db = $this->connection->getClient()->selectDatabase($this->name, $options);
  417. } else {
  418. $this->db = $this->db->withOptions($options);
  419. }
  420. }
  421. }