MongoDB.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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\WriteConcern;
  25. const PROFILING_OFF = 0;
  26. const PROFILING_SLOW = 1;
  27. const PROFILING_ON = 2;
  28. /**
  29. * @var MongoClient
  30. */
  31. protected $connection;
  32. /**
  33. * @var \MongoDB\Database
  34. */
  35. protected $db;
  36. /**
  37. * @var string
  38. */
  39. protected $name;
  40. /**
  41. * Creates a new database
  42. *
  43. * 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()}.
  44. * @link http://www.php.net/manual/en/mongodb.construct.php
  45. * @param MongoClient $conn Database connection.
  46. * @param string $name Database name.
  47. * @throws Exception
  48. * @return MongoDB Returns the database.
  49. */
  50. public function __construct(MongoClient $conn, $name)
  51. {
  52. $this->connection = $conn;
  53. $this->name = $name;
  54. $this->setReadPreferenceFromArray($conn->getReadPreference());
  55. $this->setWriteConcernFromArray($conn->getWriteConcern());
  56. $this->createDatabaseObject();
  57. }
  58. /**
  59. * @return \MongoDB\Database
  60. * @internal
  61. */
  62. public function getDb()
  63. {
  64. return $this->db;
  65. }
  66. /**
  67. * The name of this database
  68. * @link http://www.php.net/manual/en/mongodb.--tostring.php
  69. * @return string Returns this database's name.
  70. */
  71. public function __toString()
  72. {
  73. return $this->name;
  74. }
  75. /**
  76. * Gets a collection
  77. *
  78. * @link http://www.php.net/manual/en/mongodb.get.php
  79. * @param string $name The name of the collection.
  80. * @return MongoCollection
  81. */
  82. public function __get($name)
  83. {
  84. // Handle w and wtimeout properties that replicate data stored in $readPreference
  85. if ($name === 'w' || $name === 'wtimeout') {
  86. return $this->getWriteConcern()[$name];
  87. }
  88. return $this->selectCollection($name);
  89. }
  90. /**
  91. * @param string $name
  92. * @param mixed $value
  93. */
  94. public function __set($name, $value)
  95. {
  96. if ($name === 'w' || $name === 'wtimeout') {
  97. $this->setWriteConcernFromArray([$name => $value] + $this->getWriteConcern());
  98. $this->createDatabaseObject();
  99. }
  100. }
  101. /**
  102. * (PECL mongo &gt;= 1.3.0)<br/>
  103. * @link http://www.php.net/manual/en/mongodb.getcollectionnames.php
  104. * Get all collections from this database
  105. * @return array Returns the names of the all the collections in the database as an
  106. * {@link http://www.php.net/manual/en/language.types.array.php array}.
  107. */
  108. public function getCollectionNames(array $options = [])
  109. {
  110. if (is_bool($options)) {
  111. $options = ['includeSystemCollections' => $options];
  112. }
  113. $collections = $this->db->listCollections($options);
  114. $getCollectionName = function (CollectionInfo $collectionInfo) {
  115. return $collectionInfo->getName();
  116. };
  117. return array_map($getCollectionName, (array) $collections);
  118. }
  119. /**
  120. * @return MongoClient
  121. * @internal This method is not part of the ext-mongo API
  122. */
  123. public function getConnection()
  124. {
  125. return $this->connection;
  126. }
  127. /**
  128. * (PECL mongo &gt;= 0.9.0)<br/>
  129. * Fetches toolkit for dealing with files stored in this database
  130. * @link http://www.php.net/manual/en/mongodb.getgridfs.php
  131. * @param string $prefix [optional] The prefix for the files and chunks collections.
  132. * @return MongoGridFS Returns a new gridfs object for this database.
  133. */
  134. public function getGridFS($prefix = "fs")
  135. {
  136. return new \MongoGridFS($this, $prefix, $prefix);
  137. }
  138. /**
  139. * (PECL mongo &gt;= 0.9.0)<br/>
  140. * Gets this database's profiling level
  141. * @link http://www.php.net/manual/en/mongodb.getprofilinglevel.php
  142. * @return int Returns the profiling level.
  143. */
  144. public function getProfilingLevel()
  145. {
  146. return static::PROFILING_OFF;
  147. }
  148. /**
  149. * (PECL mongo &gt;= 1.1.0)<br/>
  150. * Get slaveOkay setting for this database
  151. * @link http://www.php.net/manual/en/mongodb.getslaveokay.php
  152. * @return bool Returns the value of slaveOkay for this instance.
  153. */
  154. public function getSlaveOkay()
  155. {
  156. return false;
  157. }
  158. /**
  159. * (PECL mongo &gt;= 0.9.0)<br/>
  160. * Sets this database's profiling level
  161. * @link http://www.php.net/manual/en/mongodb.setprofilinglevel.php
  162. * @param int $level Profiling level.
  163. * @return int Returns the previous profiling level.
  164. */
  165. public function setProfilingLevel($level)
  166. {
  167. return static::PROFILING_OFF;
  168. }
  169. /**
  170. * (PECL mongo &gt;= 0.9.0)<br/>
  171. * Drops this database
  172. * @link http://www.php.net/manual/en/mongodb.drop.php
  173. * @return array Returns the database response.
  174. */
  175. public function drop()
  176. {
  177. return $this->db->drop();
  178. }
  179. /**
  180. * Repairs and compacts this database
  181. * @link http://www.php.net/manual/en/mongodb.repair.php
  182. * @param bool $preserve_cloned_files [optional] <p>If cloned files should be kept if the repair fails.</p>
  183. * @param bool $backup_original_files [optional] <p>If original files should be backed up.</p>
  184. * @return array <p>Returns db response.</p>
  185. */
  186. public function repair($preserve_cloned_files = FALSE, $backup_original_files = FALSE)
  187. {
  188. return [];
  189. }
  190. /**
  191. * (PECL mongo &gt;= 0.9.0)<br/>
  192. * Gets a collection
  193. * @link http://www.php.net/manual/en/mongodb.selectcollection.php
  194. * @param string $name <b>The collection name.</b>
  195. * @throws Exception if the collection name is invalid.
  196. * @return MongoCollection <p>
  197. * Returns a new collection object.
  198. * </p>
  199. */
  200. public function selectCollection($name)
  201. {
  202. return new MongoCollection($this, $name);
  203. }
  204. /**
  205. * (PECL mongo &gt;= 1.1.0)<br/>
  206. * Change slaveOkay setting for this database
  207. * @link http://php.net/manual/en/mongodb.setslaveokay.php
  208. * @param bool $ok [optional] <p>
  209. * If reads should be sent to secondary members of a replica set for all
  210. * possible queries using this {@link http://www.php.net/manual/en/class.mongodb.php MongoDB} instance.
  211. * </p>
  212. * @return bool Returns the former value of slaveOkay for this instance.
  213. */
  214. public function setSlaveOkay ($ok = true)
  215. {
  216. return false;
  217. }
  218. /**
  219. * Creates a collection
  220. * @link http://www.php.net/manual/en/mongodb.createcollection.php
  221. * @param string $name The name of the collection.
  222. * @param array $options [optional] <p>
  223. * <p>
  224. * An array containing options for the collections. Each option is its own
  225. * element in the options array, with the option name listed below being
  226. * the key of the element. The supported options depend on the MongoDB
  227. * server version. At the moment, the following options are supported:
  228. * </p>
  229. * <p>
  230. * <b>capped</b>
  231. * <p>
  232. * If the collection should be a fixed size.
  233. * </p>
  234. * </p>
  235. * <p>
  236. * <b>size</b>
  237. * <p>
  238. * If the collection is fixed size, its size in bytes.</p></p>
  239. * <p><b>max</b>
  240. * <p>If the collection is fixed size, the maximum number of elements to store in the collection.</p></p>
  241. * <i>autoIndexId</i>
  242. *
  243. * <p>
  244. * If capped is <b>TRUE</b> you can specify <b>FALSE</b> to disable the
  245. * automatic index created on the <em>_id</em> field.
  246. * Before MongoDB 2.2, the default value for
  247. * <em>autoIndexId</em> was <b>FALSE</b>.
  248. * </p>
  249. * </p>
  250. * @return MongoCollection <p>Returns a collection object representing the new collection.</p>
  251. */
  252. public function createCollection($name, $options)
  253. {
  254. $this->db->createCollection($name, $options);
  255. return $this->selectCollection($name);
  256. }
  257. /**
  258. * (PECL mongo &gt;= 0.9.0)<br/>
  259. * @deprecated Use MongoCollection::drop() instead.
  260. * Drops a collection
  261. * @link http://www.php.net/manual/en/mongodb.dropcollection.php
  262. * @param MongoCollection|string $coll MongoCollection or name of collection to drop.
  263. * @return array Returns the database response.
  264. */
  265. public function dropCollection($coll)
  266. {
  267. return $this->db->dropCollection((string) $coll);
  268. }
  269. /**
  270. * (PECL mongo &gt;= 0.9.0)<br/>
  271. * Get a list of collections in this database
  272. * @link http://www.php.net/manual/en/mongodb.listcollections.php
  273. * @param bool $includeSystemCollections [optional] <p>Include system collections.</p>
  274. * @return array Returns a list of MongoCollections.
  275. */
  276. public function listCollections(array $options = [])
  277. {
  278. return array_map([$this, 'selectCollection'], $this->getCollectionNames($options));
  279. }
  280. /**
  281. * (PECL mongo &gt;= 0.9.0)<br/>
  282. * Creates a database reference
  283. * @link http://www.php.net/manual/en/mongodb.createdbref.php
  284. * @param string $collection The collection to which the database reference will point.
  285. * @param mixed $document_or_id <p>
  286. * If an array or object is given, its <em>_id</em> field will be
  287. * used as the reference ID. If a {@see MongoId} or scalar
  288. * is given, it will be used as the reference ID.
  289. * </p>
  290. * @return array <p>Returns a database reference array.</p>
  291. * <p>
  292. * If an array without an <em>_id</em> field was provided as the
  293. * <em>document_or_id</em> parameter, <b>NULL</b> will be returned.
  294. * </p>
  295. */
  296. public function createDBRef($collection, $document_or_id)
  297. {
  298. if (is_object($document_or_id)) {
  299. $id = isset($document_or_id->_id) ? $document_or_id->_id : null;
  300. // $id = $document_or_id->_id ?? null;
  301. } elseif (is_array($document_or_id)) {
  302. if (! isset($document_or_id['_id'])) {
  303. return null;
  304. }
  305. $id = $document_or_id['_id'];
  306. } else {
  307. $id = $document_or_id;
  308. }
  309. return [
  310. '$ref' => $collection,
  311. '$id' => $id,
  312. '$db' => $this->name,
  313. ];
  314. }
  315. /**
  316. * (PECL mongo &gt;= 0.9.0)<br/>
  317. * Fetches the document pointed to by a database reference
  318. * @link http://www.php.net/manual/en/mongodb.getdbref.php
  319. * @param array $ref A database reference.
  320. * @return array Returns the document pointed to by the reference.
  321. */
  322. public function getDBRef(array $ref)
  323. {
  324. $this->notImplemented();
  325. }
  326. /**
  327. * (PECL mongo &gt;= 0.9.3)<br/>
  328. * Runs JavaScript code on the database server.
  329. * @link http://www.php.net/manual/en/mongodb.execute.php
  330. * @param MongoCode|string $code Code to execute.
  331. * @param array $args [optional] Arguments to be passed to code.
  332. * @return array Returns the result of the evaluation.
  333. */
  334. public function execute($code, array $args = array())
  335. {
  336. $this->notImplemented();
  337. }
  338. /**
  339. * Execute a database command
  340. * @link http://www.php.net/manual/en/mongodb.command.php
  341. * @param array $data The query to send.
  342. * @param array() $options [optional] <p>
  343. * This parameter is an associative array of the form
  344. * <em>array("optionname" =&gt; &lt;boolean&gt;, ...)</em>. Currently
  345. * supported options are:
  346. * </p><ul>
  347. * <li><p><em>"timeout"</em></p><p>Deprecated alias for <em>"socketTimeoutMS"</em>.</p></li>
  348. * </ul>
  349. * @return array Returns database response.
  350. * Every database response is always maximum one document,
  351. * which means that the result of a database command can never exceed 16MB.
  352. * The resulting document's structure depends on the command,
  353. * but most results will have the ok field to indicate success or failure and results containing an array of each of the resulting documents.
  354. */
  355. public function command(array $data, $options, &$hash)
  356. {
  357. try {
  358. $cursor = new \MongoCommandCursor($this->connection, $this->name, $data);
  359. $cursor->setReadPreference($this->getReadPreference());
  360. return iterator_to_array($cursor)[0];
  361. } catch (\MongoDB\Driver\Exception\RuntimeException $e) {
  362. return [
  363. 'ok' => 0,
  364. 'errmsg' => $e->getMessage(),
  365. 'code' => $e->getCode(),
  366. ];
  367. }
  368. }
  369. /**
  370. * (PECL mongo &gt;= 0.9.5)<br/>
  371. * Check if there was an error on the most recent db operation performed
  372. * @link http://www.php.net/manual/en/mongodb.lasterror.php
  373. * @return array Returns the error, if there was one.
  374. */
  375. public function lastError()
  376. {
  377. $this->notImplemented();
  378. }
  379. /**
  380. * (PECL mongo &gt;= 0.9.5)<br/>
  381. * Checks for the last error thrown during a database operation
  382. * @link http://www.php.net/manual/en/mongodb.preverror.php
  383. * @return array Returns the error and the number of operations ago it occurred.
  384. */
  385. public function prevError()
  386. {
  387. $this->notImplemented();
  388. }
  389. /**
  390. * (PECL mongo &gt;= 0.9.5)<br/>
  391. * Clears any flagged errors on the database
  392. * @link http://www.php.net/manual/en/mongodb.reseterror.php
  393. * @return array Returns the database response.
  394. */
  395. public function resetError()
  396. {
  397. $this->notImplemented();
  398. }
  399. /**
  400. * (PECL mongo &gt;= 0.9.5)<br/>
  401. * Creates a database error
  402. * @link http://www.php.net/manual/en/mongodb.forceerror.php
  403. * @return boolean Returns the database response.
  404. */
  405. public function forceError()
  406. {
  407. $this->notImplemented();
  408. }
  409. /**
  410. * (PECL mongo &gt;= 1.0.1)<br/>
  411. * Log in to this database
  412. * @link http://www.php.net/manual/en/mongodb.authenticate.php
  413. * @param string $username The username.
  414. * @param string $password The password (in plaintext).
  415. * @return array <p>Returns database response. If the login was successful, it will return 1.</p>
  416. * <p>
  417. * <span style="color: #0000BB">&lt;?php<br></span><span style="color: #007700">array(</span><span style="color: #DD0000">"ok"&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">);<br></span><span style="color: #0000BB">?&gt;</span>
  418. * </span>
  419. * </code></div>
  420. * </div>
  421. * </p>
  422. * <p> If something went wrong, it will return </p>
  423. * <p>
  424. * <div class="example-contents">
  425. * <div class="phpcode"><code><span style="color: #000000">
  426. * <span style="color: #0000BB">&lt;?php<br></span><span style="color: #007700">array(</span><span style="color: #DD0000">"ok"&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"errmsg"&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #DD0000">"auth&nbsp;fails"</span><span style="color: #007700">);<br></span><span style="color: #0000BB">?&gt;</span></p>
  427. * <p>("auth fails" could be another message, depending on database version and
  428. * what went wrong)</p>
  429. */
  430. public function authenticate($username, $password)
  431. {
  432. $this->notImplemented();
  433. }
  434. /**
  435. * {@inheritdoc}
  436. */
  437. public function setReadPreference($readPreference, $tags = null)
  438. {
  439. $result = $this->setReadPreferenceFromParameters($readPreference, $tags);
  440. $this->createDatabaseObject();
  441. return $result;
  442. }
  443. /**
  444. * {@inheritdoc}
  445. */
  446. public function setWriteConcern($wstring, $wtimeout = 0)
  447. {
  448. $result = $this->setWriteConcernFromParameters($wstring, $wtimeout);
  449. $this->createDatabaseObject();
  450. return $result;
  451. }
  452. protected function notImplemented()
  453. {
  454. throw new \Exception('Not implemented');
  455. }
  456. /**
  457. * @return \MongoDB\Database
  458. */
  459. private function createDatabaseObject()
  460. {
  461. $options = [
  462. 'readPreference' => $this->readPreference,
  463. 'writeConcern' => $this->writeConcern,
  464. ];
  465. if ($this->db === null) {
  466. $this->db = $this->connection->getClient()->selectDatabase($this->name, $options);
  467. } else {
  468. $this->db = $this->db->withOptions($options);
  469. }
  470. }
  471. }