PageRenderTime 99ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/redbean/rb.php

https://bitbucket.org/sanbrar/zurmo-invoice-example
PHP | 8325 lines | 3206 code | 220 blank | 4899 comment | 388 complexity | 54e32e252d292266a366dbd058c10e64 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, GPL-3.0, BSD-3-Clause
  1. <?php /*
  2. .______.
  3. _______ ____ __| _/\_ |__ ____ _____ ____
  4. \_ __ \_/ __ \ / __ | | __ \_/ __ \\__ \ / \
  5. | | \/\ ___
  6. |__| \___ >____ | |___ /\___ >____ /___| /
  7. \/ \/ \/ \/ \/ \/
  8. RedBean Database Objects -
  9. Written by Gabor de Mooij (c) copyright 2010
  10. RedBean is DUAL Licensed BSD and GPLv2. You may choose the license that fits
  11. best for your project.
  12. BSD/GPLv2 License
  13. Redistribution and use in source and binary forms, with or without
  14. modification, are permitted provided that the following conditions are met:
  15. * Redistributions of source code must retain the above copyright
  16. notice, this list of conditions and the following disclaimer.
  17. * Redistributions in binary form must reproduce the above copyright
  18. notice, this list of conditions and the following disclaimer in the
  19. documentation and/or other materials provided with the distribution.
  20. * Neither the name of RedBeanPHP nor the
  21. names of its contributors may be used to endorse or promote products
  22. derived from this software without specific prior written permission.
  23. THIS SOFTWARE IS PROVIDED BY GABOR DE MOOIJ ''AS IS'' AND ANY
  24. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. DISCLAIMED. IN NO EVENT SHALL GABOR DE MOOIJ BE LIABLE FOR ANY
  27. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  30. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. RedBeanPHP is Written by Gabor de Mooij (G.J.G.T de Mooij) Copyright (c) 2010.
  34. GPLv2 LICENSE
  35. GNU GENERAL PUBLIC LICENSE
  36. Version 2, June 1991
  37. Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  38. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  39. Everyone is permitted to copy and distribute verbatim copies
  40. of this license document, but changing it is not allowed.
  41. Preamble
  42. The licenses for most software are designed to take away your
  43. freedom to share and change it. By contrast, the GNU General Public
  44. License is intended to guarantee your freedom to share and change free
  45. software--to make sure the software is free for all its users. This
  46. General Public License applies to most of the Free Software
  47. Foundation's software and to any other program whose authors commit to
  48. using it. (Some other Free Software Foundation software is covered by
  49. the GNU Lesser General Public License instead.) You can apply it to
  50. your programs, too.
  51. When we speak of free software, we are referring to freedom, not
  52. price. Our General Public Licenses are designed to make sure that you
  53. have the freedom to distribute copies of free software (and charge for
  54. this service if you wish), that you receive source code or can get it
  55. if you want it, that you can change the software or use pieces of it
  56. in new free programs; and that you know you can do these things.
  57. To protect your rights, we need to make restrictions that forbid
  58. anyone to deny you these rights or to ask you to surrender the rights.
  59. These restrictions translate to certain responsibilities for you if you
  60. distribute copies of the software, or if you modify it.
  61. For example, if you distribute copies of such a program, whether
  62. gratis or for a fee, you must give the recipients all the rights that
  63. you have. You must make sure that they, too, receive or can get the
  64. source code. And you must show them these terms so they know their
  65. rights.
  66. We protect your rights with two steps: (1) copyright the software, and
  67. (2) offer you this license which gives you legal permission to copy,
  68. distribute and/or modify the software.
  69. Also, for each author's protection and ours, we want to make certain
  70. that everyone understands that there is no warranty for this free
  71. software. If the software is modified by someone else and passed on, we
  72. want its recipients to know that what they have is not the original, so
  73. that any problems introduced by others will not reflect on the original
  74. authors' reputations.
  75. Finally, any free program is threatened constantly by software
  76. patents. We wish to avoid the danger that redistributors of a free
  77. program will individually obtain patent licenses, in effect making the
  78. program proprietary. To prevent this, we have made it clear that any
  79. patent must be licensed for everyone's free use or not licensed at all.
  80. The precise terms and conditions for copying, distribution and
  81. modification follow.
  82. GNU GENERAL PUBLIC LICENSE
  83. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  84. 0. This License applies to any program or other work which contains
  85. a notice placed by the copyright holder saying it may be distributed
  86. under the terms of this General Public License. The "Program", below,
  87. refers to any such program or work, and a "work based on the Program"
  88. means either the Program or any derivative work under copyright law:
  89. that is to say, a work containing the Program or a portion of it,
  90. either verbatim or with modifications and/or translated into another
  91. language. (Hereinafter, translation is included without limitation in
  92. the term "modification".) Each licensee is addressed as "you".
  93. Activities other than copying, distribution and modification are not
  94. covered by this License; they are outside its scope. The act of
  95. running the Program is not restricted, and the output from the Program
  96. is covered only if its contents constitute a work based on the
  97. Program (independent of having been made by running the Program).
  98. Whether that is true depends on what the Program does.
  99. 1. You may copy and distribute verbatim copies of the Program's
  100. source code as you receive it, in any medium, provided that you
  101. conspicuously and appropriately publish on each copy an appropriate
  102. copyright notice and disclaimer of warranty; keep intact all the
  103. notices that refer to this License and to the absence of any warranty;
  104. and give any other recipients of the Program a copy of this License
  105. along with the Program.
  106. You may charge a fee for the physical act of transferring a copy, and
  107. you may at your option offer warranty protection in exchange for a fee.
  108. 2. You may modify your copy or copies of the Program or any portion
  109. of it, thus forming a work based on the Program, and copy and
  110. distribute such modifications or work under the terms of Section 1
  111. above, provided that you also meet all of these conditions:
  112. a) You must cause the modified files to carry prominent notices
  113. stating that you changed the files and the date of any change.
  114. b) You must cause any work that you distribute or publish, that in
  115. whole or in part contains or is derived from the Program or any
  116. part thereof, to be licensed as a whole at no charge to all third
  117. parties under the terms of this License.
  118. c) If the modified program normally reads commands interactively
  119. when run, you must cause it, when started running for such
  120. interactive use in the most ordinary way, to print or display an
  121. announcement including an appropriate copyright notice and a
  122. notice that there is no warranty (or else, saying that you provide
  123. a warranty) and that users may redistribute the program under
  124. these conditions, and telling the user how to view a copy of this
  125. License. (Exception: if the Program itself is interactive but
  126. does not normally print such an announcement, your work based on
  127. the Program is not required to print an announcement.)
  128. These requirements apply to the modified work as a whole. If
  129. identifiable sections of that work are not derived from the Program,
  130. and can be reasonably considered independent and separate works in
  131. themselves, then this License, and its terms, do not apply to those
  132. sections when you distribute them as separate works. But when you
  133. distribute the same sections as part of a whole which is a work based
  134. on the Program, the distribution of the whole must be on the terms of
  135. this License, whose permissions for other licensees extend to the
  136. entire whole, and thus to each and every part regardless of who wrote it.
  137. Thus, it is not the intent of this section to claim rights or contest
  138. your rights to work written entirely by you; rather, the intent is to
  139. exercise the right to control the distribution of derivative or
  140. collective works based on the Program.
  141. In addition, mere aggregation of another work not based on the Program
  142. with the Program (or with a work based on the Program) on a volume of
  143. a storage or distribution medium does not bring the other work under
  144. the scope of this License.
  145. 3. You may copy and distribute the Program (or a work based on it,
  146. under Section 2) in object code or executable form under the terms of
  147. Sections 1 and 2 above provided that you also do one of the following:
  148. a) Accompany it with the complete corresponding machine-readable
  149. source code, which must be distributed under the terms of Sections
  150. 1 and 2 above on a medium customarily used for software interchange; or,
  151. b) Accompany it with a written offer, valid for at least three
  152. years, to give any third party, for a charge no more than your
  153. cost of physically performing source distribution, a complete
  154. machine-readable copy of the corresponding source code, to be
  155. distributed under the terms of Sections 1 and 2 above on a medium
  156. customarily used for software interchange; or,
  157. c) Accompany it with the information you received as to the offer
  158. to distribute corresponding source code. (This alternative is
  159. allowed only for noncommercial distribution and only if you
  160. received the program in object code or executable form with such
  161. an offer, in accord with Subsection b above.)
  162. The source code for a work means the preferred form of the work for
  163. making modifications to it. For an executable work, complete source
  164. code means all the source code for all modules it contains, plus any
  165. associated interface definition files, plus the scripts used to
  166. control compilation and installation of the executable. However, as a
  167. special exception, the source code distributed need not include
  168. anything that is normally distributed (in either source or binary
  169. form) with the major components (compiler, kernel, and so on) of the
  170. operating system on which the executable runs, unless that component
  171. itself accompanies the executable.
  172. If distribution of executable or object code is made by offering
  173. access to copy from a designated place, then offering equivalent
  174. access to copy the source code from the same place counts as
  175. distribution of the source code, even though third parties are not
  176. compelled to copy the source along with the object code.
  177. 4. You may not copy, modify, sublicense, or distribute the Program
  178. except as expressly provided under this License. Any attempt
  179. otherwise to copy, modify, sublicense or distribute the Program is
  180. void, and will automatically terminate your rights under this License.
  181. However, parties who have received copies, or rights, from you under
  182. this License will not have their licenses terminated so long as such
  183. parties remain in full compliance.
  184. 5. You are not required to accept this License, since you have not
  185. signed it. However, nothing else grants you permission to modify or
  186. distribute the Program or its derivative works. These actions are
  187. prohibited by law if you do not accept this License. Therefore, by
  188. modifying or distributing the Program (or any work based on the
  189. Program), you indicate your acceptance of this License to do so, and
  190. all its terms and conditions for copying, distributing or modifying
  191. the Program or works based on it.
  192. 6. Each time you redistribute the Program (or any work based on the
  193. Program), the recipient automatically receives a license from the
  194. original licensor to copy, distribute or modify the Program subject to
  195. these terms and conditions. You may not impose any further
  196. restrictions on the recipients' exercise of the rights granted herein.
  197. You are not responsible for enforcing compliance by third parties to
  198. this License.
  199. 7. If, as a consequence of a court judgment or allegation of patent
  200. infringement or for any other reason (not limited to patent issues),
  201. conditions are imposed on you (whether by court order, agreement or
  202. otherwise) that contradict the conditions of this License, they do not
  203. excuse you from the conditions of this License. If you cannot
  204. distribute so as to satisfy simultaneously your obligations under this
  205. License and any other pertinent obligations, then as a consequence you
  206. may not distribute the Program at all. For example, if a patent
  207. license would not permit royalty-free redistribution of the Program by
  208. all those who receive copies directly or indirectly through you, then
  209. the only way you could satisfy both it and this License would be to
  210. refrain entirely from distribution of the Program.
  211. If any portion of this section is held invalid or unenforceable under
  212. any particular circumstance, the balance of the section is intended to
  213. apply and the section as a whole is intended to apply in other
  214. circumstances.
  215. It is not the purpose of this section to induce you to infringe any
  216. patents or other property right claims or to contest validity of any
  217. such claims; this section has the sole purpose of protecting the
  218. integrity of the free software distribution system, which is
  219. implemented by public license practices. Many people have made
  220. generous contributions to the wide range of software distributed
  221. through that system in reliance on consistent application of that
  222. system; it is up to the author/donor to decide if he or she is willing
  223. to distribute software through any other system and a licensee cannot
  224. impose that choice.
  225. This section is intended to make thoroughly clear what is believed to
  226. be a consequence of the rest of this License.
  227. 8. If the distribution and/or use of the Program is restricted in
  228. certain countries either by patents or by copyrighted interfaces, the
  229. original copyright holder who places the Program under this License
  230. may add an explicit geographical distribution limitation excluding
  231. those countries, so that distribution is permitted only in or among
  232. countries not thus excluded. In such case, this License incorporates
  233. the limitation as if written in the body of this License.
  234. 9. The Free Software Foundation may publish revised and/or new versions
  235. of the General Public License from time to time. Such new versions will
  236. be similar in spirit to the present version, but may differ in detail to
  237. address new problems or concerns.
  238. Each version is given a distinguishing version number. If the Program
  239. specifies a version number of this License which applies to it and "any
  240. later version", you have the option of following the terms and conditions
  241. either of that version or of any later version published by the Free
  242. Software Foundation. If the Program does not specify a version number of
  243. this License, you may choose any version ever published by the Free Software
  244. Foundation.
  245. 10. If you wish to incorporate parts of the Program into other free
  246. programs whose distribution conditions are different, write to the author
  247. to ask for permission. For software which is copyrighted by the Free
  248. Software Foundation, write to the Free Software Foundation; we sometimes
  249. make exceptions for this. Our decision will be guided by the two goals
  250. of preserving the free status of all derivatives of our free software and
  251. of promoting the sharing and reuse of software generally.
  252. NO WARRANTY
  253. 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  254. FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
  255. OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  256. PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  257. OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  258. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
  259. TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
  260. PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  261. REPAIR OR CORRECTION.
  262. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  263. WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  264. REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  265. INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  266. OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  267. TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  268. YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  269. PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  270. POSSIBILITY OF SUCH DAMAGES.
  271. */
  272. /**
  273. * RedBean_ObjectDatabase
  274. * @file RedBean/RedBean_ObjectDatabase.php
  275. * @description RedBean simulates an object oriented database. This interface
  276. * describes the API for the object database. It is the
  277. * abstract core of RedBean describing its main functionality.
  278. * @author Gabor de Mooij
  279. * @license BSD
  280. *
  281. *
  282. * (c) G.J.G.T. (Gabor) de Mooij
  283. * This source file is subject to the BSD/GPLv2 License that is bundled
  284. * with this source code in the file license.txt.
  285. */
  286. interface RedBean_ObjectDatabase {
  287. /**
  288. * This interface describes how ANY Object Database should
  289. * behave.For detailed descriptions of RedBean specific implementation
  290. * see: RedBean_OODB.
  291. * An Object Database should be able to load a bean using a $type and $id.
  292. * The $type argument indicated what kind of bean you are looking for.
  293. * The $id argument specifies the primary key ID; which links the bean to
  294. * a (series) of record(s) in the database.
  295. *
  296. * @param string $type
  297. * @param integer $id
  298. *
  299. * @return RedBean_OODBBean $bean
  300. */
  301. public function load( $type, $id );
  302. /**
  303. * This interface describes how ANY Object Database should
  304. * behave.For detailed descriptions of RedBean specific implementation
  305. * see: RedBean_OODB.
  306. * An Object Database should be able to store a RedBean_OODBBean $bean.
  307. *
  308. * @param RedBean_OODBBean $bean
  309. *
  310. * @return integer $newid
  311. */
  312. public function store( RedBean_OODBBean $bean );
  313. /**
  314. * This interface describes how ANY Object Database should
  315. * behave.For detailed descriptions of RedBean specific implementation
  316. * see: RedBean_OODB.
  317. *
  318. * @param RedBean_OODBBean $bean
  319. */
  320. public function trash( RedBean_OODBBean $bean );
  321. /**
  322. * This interface describes how ANY Object Database should
  323. * behave.For detailed descriptions of RedBean specific implementation
  324. * see: RedBean_OODB.
  325. *
  326. * @param string $type
  327. * @param array $ids
  328. *
  329. * @return array $beans
  330. */
  331. public function batch( $type, $ids );
  332. /**
  333. * This interface describes how ANY Object Database should
  334. * behave.For detailed descriptions of RedBean specific implementation
  335. * see: RedBean_OODB.
  336. *
  337. * @param string $type
  338. *
  339. * @return RedBean_OODBBean $bean
  340. */
  341. public function dispense( $type );
  342. /**
  343. * This interface describes how ANY Object Database should
  344. * behave.For detailed descriptions of RedBean specific implementation
  345. * see: RedBean_OODB.
  346. *
  347. * @param string $type
  348. *
  349. * @return integer $numbeans
  350. */
  351. public function count( $type );
  352. /**
  353. * This interface describes how ANY Object Database should
  354. * behave.For detailed descriptions of RedBean specific implementation
  355. * see: RedBean_OODB.
  356. *
  357. * @param string $type
  358. *
  359. * @return mixed $undefined (impl. specific)
  360. */
  361. public function wipe( $type );
  362. /**
  363. * =====================================================
  364. * Note: that not all methods in OODB are mentioned here;
  365. * freeze(), isFrozen(), convertToBeans() etc. are extra
  366. * services provided by OODB but not required for the
  367. * Object Database interface to be implemented!
  368. *
  369. * If you are writing Hyper-portable code, please do
  370. * not rely on OODB specific methods...!
  371. * =====================================================
  372. *
  373. */
  374. }
  375. /**
  376. * RedBean Plugin
  377. * @file RedBean/Plugin.php
  378. * @description Marker interface for plugins.
  379. *
  380. * @author Gabor de Mooij
  381. * @license BSD
  382. *
  383. * (c) G.J.G.T. (Gabor) de Mooij
  384. * This source file is subject to the BSD/GPLv2 License that is bundled
  385. * with this source code in the file license.txt.
  386. */
  387. interface RedBean_Plugin {
  388. }
  389. /**
  390. * Interface for database drivers
  391. * @file RedBean/Driver.php
  392. * @description Describes the API for database classes
  393. * The Driver API conforms to the ADODB pseudo standard
  394. * for database drivers.
  395. * @author Gabor de Mooij
  396. * @license BSD
  397. *
  398. *
  399. * (c) G.J.G.T. (Gabor) de Mooij
  400. * This source file is subject to the BSD/GPLv2 License that is bundled
  401. * with this source code in the file license.txt.
  402. */
  403. interface RedBean_Driver {
  404. /**
  405. * Implements Singleton (or multiton)
  406. * Requests an instance of the database
  407. * Returns an instance of the driver Driver wrapper.
  408. *
  409. * @param string $dsn Database connection string
  410. * @param string $user DB account to be used
  411. * @param string $pass password
  412. * @param string $dbname name of the database you
  413. *
  414. * @return RedBean_Driver $driver driver wrapper instance
  415. */
  416. public static function getInstance( $host, $user, $pass, $dbname );
  417. /**
  418. * Runs a query and fetches results as a multi dimensional array.
  419. *
  420. * @param string $sql SQL to be executed
  421. *
  422. * @return array $results result
  423. */
  424. public function GetAll( $sql, $aValues=array() );
  425. /**
  426. * Runs a query and fetches results as a column.
  427. *
  428. * @param string $sql SQL Code to execute
  429. *
  430. * @return array $results Resultset
  431. */
  432. public function GetCol( $sql, $aValues=array() );
  433. /**
  434. * Runs a query an returns results as a single cell.
  435. *
  436. * @param string $sql SQL to execute
  437. *
  438. * @return mixed $cellvalue result cell
  439. */
  440. public function GetCell( $sql, $aValues=array() );
  441. /**
  442. * Runs a query and returns a flat array containing the values of
  443. * one row.
  444. *
  445. * @param string $sql SQL to execute
  446. *
  447. * @return array $row result row
  448. */
  449. public function GetRow( $sql, $aValues=array() );
  450. /**
  451. * Returns the error constant of the most
  452. * recent error.
  453. *
  454. * @return mixed $error error code
  455. */
  456. public function ErrorNo();
  457. /**
  458. * Returns the error message of the most recent
  459. * error.
  460. *
  461. * @return string $message error message
  462. */
  463. public function Errormsg();
  464. /**
  465. * Executes SQL code and allows key-value binding.
  466. * This function allows you to provide an array with values to bind
  467. * to query parameters. For instance you can bind values to question
  468. * marks in the query. Each value in the array corresponds to the
  469. * question mark in the query that matches the position of the value in the
  470. * array. You can also bind values using explicit keys, for instance
  471. * array(":key"=>123) will bind the integer 123 to the key :key in the
  472. * SQL. This method has no return value.
  473. *
  474. * @param string $sql SQL Code to execute
  475. * @param array $aValues Values to bind to SQL query
  476. *
  477. * @return void
  478. */
  479. public function Execute( $sql, $aValues=array() );
  480. /**
  481. * Escapes a string for use in SQL using the currently selected
  482. * driver driver.
  483. *
  484. * @param string $string string to be escaped
  485. *
  486. * @return string $string escaped string
  487. */
  488. public function Escape( $str );
  489. /**
  490. * Returns the latest insert ID if driver does support this
  491. * feature.
  492. *
  493. * @return integer $id primary key ID
  494. */
  495. public function GetInsertID();
  496. /**
  497. * Returns the number of rows affected by the most recent query
  498. * if the currently selected driver driver supports this feature.
  499. *
  500. * @return integer $numOfRows number of rows affected
  501. */
  502. public function Affected_Rows();
  503. /**
  504. * Toggles debug mode. In debug mode the driver will print all
  505. * SQL to the screen together with some information about the
  506. * results. All SQL code that passes through the driver will be
  507. * passes on to the screen for inspection.
  508. * This method has no return value.
  509. *
  510. * @param boolean $trueFalse turn on/off
  511. *
  512. * @return void
  513. */
  514. public function setDebugMode( $tf );
  515. /**
  516. * Returns a raw result resource from the underlying driver driver.
  517. *
  518. * @return Resource $driverResult driver result resource object
  519. */
  520. public function GetRaw();
  521. /**
  522. * Starts a transaction.
  523. * This method is part of the transaction mechanism of
  524. * RedBeanPHP. All queries in a transaction are executed together.
  525. * In case of an error all commands will be rolled back so none of the
  526. * SQL in the transaction will affect the DB. Using transactions is
  527. * considered best practice.
  528. * This method has no return value.
  529. *
  530. * @return void
  531. */
  532. public function CommitTrans();
  533. /**
  534. * Commits a transaction.
  535. * This method is part of the transaction mechanism of
  536. * RedBeanPHP. All queries in a transaction are executed together.
  537. * In case of an error all commands will be rolled back so none of the
  538. * SQL in the transaction will affect the DB. Using transactions is
  539. * considered best practice.
  540. * This method has no return value.
  541. *
  542. * @return void
  543. */
  544. public function StartTrans();
  545. /**
  546. * Rolls back a transaction.
  547. * This method is part of the transaction mechanism of
  548. * RedBeanPHP. All queries in a transaction are executed together.
  549. * In case of an error all commands will be rolled back so none of the
  550. * SQL in the transaction will affect the DB. Using transactions is
  551. * considered best practice.
  552. * This method has no return value.
  553. *
  554. * @return void
  555. */
  556. public function FailTrans();
  557. }
  558. /**
  559. * PDO Driver
  560. * @file RedBean/PDO.php
  561. * @description PDO Driver
  562. * This Driver implements the RedBean Driver API
  563. * @author Desfrenes
  564. * @license BSD
  565. *
  566. *
  567. * (c) Desfrenes & Gabor de Mooij
  568. * This source file is subject to the BSD/GPLv2 License that is bundled
  569. * with this source code in the file license.txt.
  570. *
  571. */
  572. class RedBean_Driver_PDO implements RedBean_Driver {
  573. /**
  574. * @var string
  575. * Contains database DSN for connecting to database.
  576. */
  577. private $dsn;
  578. /**
  579. * @var RedBean_Driver_PDO
  580. * Holds the instance of this class.
  581. */
  582. private static $instance;
  583. /**
  584. * @var boolean
  585. * Whether we are in debugging mode or not.
  586. */
  587. private $debug = false;
  588. /**
  589. * @var PDO
  590. * Holds the PDO instance.
  591. */
  592. private $pdo;
  593. /**
  594. * @var integer
  595. * Holds integer number of affected rows from latest query
  596. * if driver supports this feature.
  597. */
  598. private $affected_rows;
  599. /**
  600. * @var resource
  601. * Holds result resource.
  602. */
  603. private $rs;
  604. /**
  605. * @var boolean
  606. * Flag, indicates whether SQL execution has taken place.
  607. */
  608. private $exc =0;
  609. /**
  610. * @var array
  611. * Contains arbitrary connection data.
  612. *
  613. */
  614. private $connectInfo = array();
  615. /**
  616. * @var bool
  617. * Whether you want to use classic String Only binding -
  618. * backward compatibility.
  619. */
  620. public $flagUseStringOnlyBinding = false;
  621. /**
  622. *
  623. * @var boolean
  624. *
  625. * Whether we are currently connected or not.
  626. * This flag is being used to delay the connection until necessary.
  627. * Delaying connections is a good practice to speed up scripts that
  628. * don't need database connectivity but for some reason want to
  629. * init RedbeanPHP.
  630. */
  631. private $isConnected = false;
  632. /**
  633. * Returns an instance of the PDO Driver.
  634. *
  635. * @param string $dsn Database connection string
  636. * @param string $user DB account to be used
  637. * @param string $pass password
  638. * @param string $dbname name of the database you
  639. *
  640. * @return RedBean_Driver_PDO $pdo PDO wrapper instance
  641. */
  642. public static function getInstance($dsn, $user, $pass, $dbname) {
  643. if(is_null(self::$instance)) {
  644. self::$instance = new RedBean_Driver_PDO($dsn, $user, $pass);
  645. }
  646. return self::$instance;
  647. }
  648. /**
  649. * Constructor. You may either specify dsn, user and password or
  650. * just give an existing PDO connection.
  651. * Examples:
  652. * $driver = new RedBean_Driver_PDO($dsn, $user, $password);
  653. * $driver = new RedBean_Driver_PDO($existingConnection);
  654. *
  655. * @param string|PDO $dsn database connection string
  656. * @param string $user optional
  657. * @param string $pass optional
  658. *
  659. * @return void
  660. */
  661. public function __construct($dsn, $user = NULL, $pass = NULL) {
  662. if ($dsn instanceof PDO) {
  663. $this->pdo = $dsn;
  664. $this->isConnected = true;
  665. $this->pdo->setAttribute(1002, 'SET NAMES utf8');
  666. $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  667. $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  668. $this->dsn = $this->getDatabaseType();
  669. } else {
  670. $this->dsn = $dsn;
  671. $this->connectInfo = array( "pass"=>$pass, "user"=>$user );
  672. }
  673. }
  674. /**
  675. * Establishes a connection to the database using PHP PDO
  676. * functionality. If a connection has already been established this
  677. * method will simply return directly. This method also turns on
  678. * UTF8 for the database and PDO-ERRMODE-EXCEPTION as well as
  679. * PDO-FETCH-ASSOC.
  680. *
  681. * @return void
  682. */
  683. public function connect() {
  684. if ($this->isConnected) return;
  685. $user = $this->connectInfo["user"];
  686. $pass = $this->connectInfo["pass"];
  687. $this->pdo = new PDO(
  688. $this->dsn,
  689. $user,
  690. $pass,
  691. array(1002 => 'SET NAMES utf8',
  692. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  693. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  694. )
  695. );
  696. $this->pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, TRUE);
  697. $this->isConnected = true;
  698. }
  699. /**
  700. * Runs a query and fetches results as a multi dimensional array.
  701. *
  702. * @param string $sql SQL to be executed
  703. *
  704. * @return array $results result
  705. */
  706. public function GetAll( $sql, $aValues=array() ) {
  707. $this->connect();
  708. $this->exc = 0;
  709. if ($this->debug) {
  710. echo "<HR>" . $sql.print_r($aValues,1);
  711. }
  712. try {
  713. if (strpos("pgsql",$this->dsn)===0) {
  714. $s = $this->pdo->prepare($sql, array(PDO::PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT => true));
  715. }
  716. else {
  717. $s = $this->pdo->prepare($sql);
  718. }
  719. if ($this->flagUseStringOnlyBinding) {
  720. $s->execute($aValues);
  721. }
  722. else {
  723. foreach($aValues as $key=>&$value) {
  724. if (is_integer($key)) {
  725. if (ctype_digit(strval($value)) && $value < 2147483648) { $s->bindParam($key+1,$value,PDO::PARAM_INT); }
  726. else $s->bindParam($key+1,$value,PDO::PARAM_STR);
  727. }
  728. else {
  729. if (ctype_digit(strval($value)) && $value < 2147483648) $s->bindParam($key,$value,PDO::PARAM_INT);
  730. else $s->bindParam($key,$value,PDO::PARAM_STR);
  731. }
  732. }
  733. $s->execute();
  734. }
  735. if ($s->columnCount()) {
  736. $this->rs = $s->fetchAll();
  737. }
  738. else {
  739. $this->rs = null;
  740. }
  741. $rows = $this->rs;
  742. }catch(PDOException $e) {
  743. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  744. $x = new RedBean_Exception_SQL( $e->getMessage(), 0);
  745. }
  746. else {
  747. $x = new RedBean_Exception_SQL( $e->getMessage(), 0, $e );
  748. }
  749. $x->setSQLState( $e->getCode() );
  750. throw $x;
  751. }
  752. if(!$rows) {
  753. $rows = array();
  754. }
  755. if ($this->debug) {
  756. if (count($rows) > 0) {
  757. echo "<br><b style='color:green'>resultset: " . count($rows) . " rows</b>";
  758. }
  759. }
  760. return $rows;
  761. }
  762. /**
  763. * Runs a query and fetches results as a column.
  764. *
  765. * @param string $sql SQL Code to execute
  766. *
  767. * @return array $results Resultset
  768. */
  769. public function GetCol($sql, $aValues=array()) {
  770. $this->connect();
  771. $this->exc = 0;
  772. $rows = $this->GetAll($sql,$aValues);
  773. $cols = array();
  774. if ($rows && is_array($rows) && count($rows)>0) {
  775. foreach ($rows as $row) {
  776. $cols[] = array_shift($row);
  777. }
  778. }
  779. return $cols;
  780. }
  781. /**
  782. * Runs a query an returns results as a single cell.
  783. *
  784. * @param string $sql SQL to execute
  785. *
  786. * @return mixed $cellvalue result cell
  787. */
  788. public function GetCell($sql, $aValues=array()) {
  789. $this->connect();
  790. $this->exc = 0;
  791. $arr = $this->GetAll($sql,$aValues);
  792. $row1 = array_shift($arr);
  793. $col1 = array_shift($row1);
  794. return $col1;
  795. }
  796. /**
  797. * Runs a query and returns a flat array containing the values of
  798. * one row.
  799. *
  800. * @param string $sql SQL to execute
  801. *
  802. * @return array $row result row
  803. */
  804. public function GetRow($sql, $aValues=array()) {
  805. $this->connect();
  806. $this->exc = 0;
  807. $arr = $this->GetAll($sql, $aValues);
  808. return array_shift($arr);
  809. }
  810. /**
  811. * Returns the error constant of the most
  812. * recent error.
  813. *
  814. * @return mixed $error error code
  815. */
  816. public function ErrorNo() {
  817. $this->connect();
  818. if (!$this->exc) return 0;
  819. $infos = $this->pdo->errorInfo();
  820. return $infos[1];
  821. }
  822. /**
  823. * Returns the error message of the most recent
  824. * error.
  825. *
  826. * @return string $message error message
  827. */
  828. public function Errormsg() {
  829. $this->connect();
  830. if (!$this->exc) return "";
  831. $infos = $this->pdo->errorInfo();
  832. return $infos[2];
  833. }
  834. /**
  835. * Executes SQL code and allows key-value binding.
  836. * This function allows you to provide an array with values to bind
  837. * to query parameters. For instance you can bind values to question
  838. * marks in the query. Each value in the array corresponds to the
  839. * question mark in the query that matches the position of the value in the
  840. * array. You can also bind values using explicit keys, for instance
  841. * array(":key"=>123) will bind the integer 123 to the key :key in the
  842. * SQL. This method has no return value.
  843. *
  844. * @param string $sql SQL Code to execute
  845. * @param array $aValues Values to bind to SQL query
  846. *
  847. * @return void
  848. */
  849. public function Execute( $sql, $aValues=array() ) {
  850. $this->connect();
  851. $this->exc = 0;
  852. if ($this->debug) {
  853. echo "<HR>" . $sql.print_r($aValues,1);
  854. }
  855. try {
  856. if (strpos("pgsql",$this->dsn)===0) {
  857. $s = $this->pdo->prepare($sql, array(PDO::PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT => true));
  858. }
  859. else {
  860. $s = $this->pdo->prepare($sql);
  861. }
  862. if ($this->flagUseStringOnlyBinding) {
  863. $s->execute($aValues);
  864. }
  865. else {
  866. foreach($aValues as $key=>&$value) {
  867. if (is_integer($key)) {
  868. if (ctype_digit(strval($value)) && $value < 2147483648) { $s->bindParam($key+1,$value,PDO::PARAM_INT); }
  869. else $s->bindParam($key+1,$value,PDO::PARAM_STR);
  870. }
  871. else {
  872. if (ctype_digit(strval($value)) && $value < 2147483648) $s->bindParam($key,$value,PDO::PARAM_INT);
  873. else $s->bindParam($key,$value,PDO::PARAM_STR);
  874. }
  875. }
  876. $s->execute();
  877. }
  878. $this->affected_rows=$s->rowCount();
  879. return $this->affected_rows;
  880. }
  881. catch(PDOException $e) {
  882. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  883. $x = new RedBean_Exception_SQL( $e->getMessage(), 0);
  884. }
  885. else {
  886. $x = new RedBean_Exception_SQL( $e->getMessage(), 0, $e );
  887. }
  888. $x->setSQLState( $e->getCode() );
  889. throw $x;
  890. }
  891. }
  892. /**
  893. * Escapes a string for use in SQL using the currently selected
  894. * PDO driver.
  895. *
  896. * @param string $string string to be escaped
  897. *
  898. * @return string $string escaped string
  899. */
  900. public function Escape( $str ) {
  901. $this->connect();
  902. return substr(substr($this->pdo->quote($str), 1), 0, -1);
  903. }
  904. /**
  905. * Returns the latest insert ID if driver does support this
  906. * feature.
  907. *
  908. * @return integer $id primary key ID
  909. */
  910. public function GetInsertID() {
  911. $this->connect();
  912. return (int) $this->pdo->lastInsertId();
  913. }
  914. /**
  915. * Returns the number of rows affected by the most recent query
  916. * if the currently selected PDO driver supports this feature.
  917. *
  918. * @return integer $numOfRows number of rows affected
  919. */
  920. public function Affected_Rows() {
  921. $this->connect();
  922. return (int) $this->affected_rows;
  923. }
  924. /**
  925. * Toggles debug mode. In debug mode the driver will print all
  926. * SQL to the screen together with some information about the
  927. * results. All SQL code that passes through the driver will be
  928. * passes on to the screen for inspection.
  929. * This method has no return value.
  930. *
  931. * @param boolean $trueFalse turn on/off
  932. *
  933. * @return void
  934. */
  935. public function setDebugMode( $tf ) {
  936. $this->connect();
  937. $this->debug = (bool)$tf;
  938. }
  939. /**
  940. * Returns a raw result resource from the underlying PDO driver.
  941. *
  942. * @return Resource $PDOResult PDO result resource object
  943. */
  944. public function GetRaw() {
  945. $this->connect();
  946. return $this->rs;
  947. }
  948. /**
  949. * Starts a transaction.
  950. * This method is part of the transaction mechanism of
  951. * RedBeanPHP. All queries in a transaction are executed together.
  952. * In case of an error all commands will be rolled back so none of the
  953. * SQL in the transaction will affect the DB. Using transactions is
  954. * considered best practice.
  955. * This method has no return value.
  956. *
  957. * @return void
  958. */
  959. public function StartTrans() {
  960. $this->connect();
  961. $this->pdo->beginTransaction();
  962. }
  963. /**
  964. * Commits a transaction.
  965. * This method is part of the transaction mechanism of
  966. * RedBeanPHP. All queries in a transaction are executed together.
  967. * In case of an error all commands will be rolled back so none of the
  968. * SQL in the transaction will affect the DB. Using transactions is
  969. * considered best practice.
  970. * This method has no return value.
  971. *
  972. * @return void
  973. */
  974. public function CommitTrans() {
  975. $this->connect();
  976. $this->pdo->commit();
  977. }
  978. /**
  979. * Rolls back a transaction.
  980. * This method is part of the transaction mechanism of
  981. * RedBeanPHP. All queries in a transaction are executed together.
  982. * In case of an error all commands will be rolled back so none of the
  983. * SQL in the transaction will affect the DB. Using transactions is
  984. * considered best practice.
  985. * This method has no return value.
  986. *
  987. * @return void
  988. */
  989. public function FailTrans() {
  990. $this->connect();
  991. $this->pdo->rollback();
  992. }
  993. /**
  994. * Returns the name of the database type/brand: i.e. mysql, db2 etc.
  995. *
  996. * @return string $typeName database identification
  997. */
  998. public function getDatabaseType() {
  999. $this->connect();
  1000. return $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
  1001. }
  1002. /**
  1003. * Returns the version number of the database.
  1004. *
  1005. * @return mixed $version version number of the database
  1006. */
  1007. public function getDatabaseVersion() {
  1008. $this->connect();
  1009. return $this->pdo->getAttribute(PDO::ATTR_CLIENT_VERSION);
  1010. }
  1011. /**
  1012. * Returns the underlying PHP PDO instance.
  1013. *
  1014. * @return PDO $pdo PDO instance used by PDO wrapper
  1015. */
  1016. public function getPDO() {
  1017. $this->connect();
  1018. return $this->pdo;
  1019. }
  1020. }
  1021. /**
  1022. * RedBean_OODBBean (Object Oriented DataBase Bean)
  1023. * @file RedBean/RedBean_OODBBean.php
  1024. * @description The Bean class used for passing information
  1025. * @author Gabor de Mooij
  1026. * @license BSD
  1027. *
  1028. *
  1029. * (c) G.J.G.T. (Gabor) de Mooij
  1030. * This source file is subject to the BSD/GPLv2 License that is bundled
  1031. * with this source code in the file license.txt.
  1032. */
  1033. class RedBean_OODBBean implements IteratorAggregate, ArrayAccess {
  1034. private $properties = array();
  1035. /**
  1036. * Meta Data storage. This is the internal property where all
  1037. * Meta information gets stored.
  1038. * @var array
  1039. */
  1040. private $__info = NULL;
  1041. public function getIterator() {
  1042. return new ArrayIterator($this->properties);
  1043. }
  1044. /**
  1045. * Imports all values in associative array $array. Every key is used
  1046. * for a property and every value will be assigned to the property
  1047. * identified by the key. So basically this method converts the
  1048. * associative array to a bean by loading the array. You can filter
  1049. * the values using the $selection parameter. If $selection is boolean
  1050. * false, no filtering will be applied. If $selection is an array
  1051. * only the properties specified (as values) in the $selection
  1052. * array will be taken into account. To skip a property, omit it from
  1053. * the $selection array. Also, instead of providing an array you may
  1054. * pass a comma separated list of property names. This method is
  1055. * chainable because it returns its own object.
  1056. * Imports data into bean
  1057. * @param array $array
  1058. * @param mixed $selection
  1059. * @param boolean $notrim
  1060. * @return RedBean_OODBBean $this
  1061. */
  1062. public function import( $arr, $selection=false, $notrim=false ) {
  1063. if (is_string($selection)) $selection = explode(",",$selection);
  1064. if (!$notrim && is_array($selection)) foreach($selection as $k=>$s){ $selection[$k]=trim($s); }
  1065. foreach($arr as $k=>$v) {
  1066. if ($k != "__info") {
  1067. if (!$selection || ($selection && in_array($k,$selection))) {
  1068. $this->$k = $v;
  1069. }
  1070. }
  1071. }
  1072. return $this;
  1073. }
  1074. /**
  1075. * Exports the bean as an array.
  1076. * This function exports the contents of a bean to an array and returns
  1077. * the resulting array. If $meta eq uals boolean TRUE, then the array will
  1078. * also contain the __info section containing the meta data inside the
  1079. * RedBean_OODBBean Bean object.
  1080. * @param boolean $meta
  1081. * @return array $arr
  1082. */
  1083. public function export($meta = false) {
  1084. $arr = array();
  1085. $arr = $this->properties;
  1086. if ($meta) $arr["__info"] = $this->__info;
  1087. return $arr;
  1088. }
  1089. /**
  1090. * Implements isset() function for use as an array.
  1091. * Returns whether bean has an element with key
  1092. * named $property. Returns TRUE if such an element exists
  1093. * and FALSE otherwise.
  1094. * @param string $property
  1095. * @return boolean $hasProperty
  1096. */
  1097. public function __isset( $property ) {
  1098. return (isset($this->properties[$property]));
  1099. }
  1100. /**
  1101. * Magic Getter. Gets the value for a specific property in the bean.
  1102. * If the property does not exist this getter will make sure no error
  1103. * occurs. This is because RedBean allows you to query (probe) for
  1104. * properties. If the property can not be found this method will
  1105. * return NULL instead.
  1106. * @param string $property
  1107. * @return mixed $value
  1108. */
  1109. public function __get( $property ) {
  1110. if (!isset($this->properties[$property])) return NULL;
  1111. return $this->properties[$property];
  1112. }
  1113. /**
  1114. * Magic Setter. Sets the value for a specific property.
  1115. * This setter acts as a hook for OODB to mark beans as tainted.
  1116. * The tainted meta property can be retrieved using getMeta("tainted").
  1117. * The tainted meta property indicates whether a bean has been modified and
  1118. * can be used in various caching mechanisms.
  1119. * @param string $property
  1120. * @param mixed $value
  1121. */
  1122. public function __set( $property, $value ) {
  1123. $this->setMeta("tainted",true);
  1124. if ($value===false) {
  1125. $value = "0";
  1126. }
  1127. if ($value===true) {
  1128. $value = "1";
  1129. }
  1130. $this->properties[$property] = $value;
  1131. }
  1132. /**
  1133. * Returns the value of a meta property. A meta property
  1134. * contains extra information about the bean object that will not
  1135. * get stored in the database. Meta information is used to instruct
  1136. * RedBean as well as other systems how to deal with the bean.
  1137. * For instance: $bean->setMeta("buildcommand.unique.0", array(
  1138. * "column1", "column2", "column3") );
  1139. * Will add a UNIQUE constaint for the bean on columns: column1, column2 and
  1140. * column 3.
  1141. * To access a Meta property we use a dot separated notation.
  1142. * If the property cannot be found this getter will return NULL instead.
  1143. * @param string $path
  1144. * @param mixed $default
  1145. * @return mixed $value
  1146. */
  1147. public function getMeta( $path, $default = NULL) {
  1148. return (isset($this->__info[$path])) ? $this->__info[$path] : $default;
  1149. }
  1150. /**
  1151. * Stores a value in the specified Meta information property. $value contains
  1152. * the value you want to store in the Meta section of the bean and $path
  1153. * specifies the dot separated path to the property. For instance "my.meta.property".
  1154. * If "my" and "meta" do not exist they will be created automatically.
  1155. * @param string $path
  1156. * @param mixed $value
  1157. */
  1158. public function setMeta( $path, $value ) {
  1159. $this->__info[$path] = $value;
  1160. }
  1161. /**
  1162. * Copies the meta information of the specified bean
  1163. * This is a convenience method to enable you to
  1164. * exchange meta information easily.
  1165. * @param RedBean_OODBBean $bean
  1166. * @return RedBean_OODBBean
  1167. */
  1168. public function copyMetaFrom( RedBean_OODBBean $bean ) {
  1169. $this->__info = $bean->__info;
  1170. return $this;
  1171. }
  1172. /**
  1173. * Sleep function fore serialize() call. This will be invoked if you
  1174. * perform a serialize() operation.
  1175. *
  1176. * @return mixed $array
  1177. */
  1178. public function __sleep() {
  1179. return array('properties','__info');
  1180. }
  1181. /**
  1182. * Reroutes a call to Model if exists. (new fuse)
  1183. * @param string $method
  1184. * @param array $args
  1185. * @return mixed $mixed
  1186. */
  1187. public function __call($method, $args) {
  1188. return null;
  1189. if (!isset($this->__info["model"])) {
  1190. $modelName = RedBean_ModelHelper::getModelName( $this->getMeta("type") );
  1191. if (!class_exists($modelName)) return null;
  1192. $obj = new $modelName();
  1193. $obj->loadBean($this);
  1194. $this->__info["model"] = $obj;
  1195. }
  1196. if (!method_exists($this->__info["model"],$method)) return null;
  1197. return call_user_func_array(array($this->__info["model"],$method), $args);
  1198. }
  1199. /**
  1200. * Implementation of __toString Method
  1201. * Routes call to Model.
  1202. * @return string $string
  1203. */
  1204. public function __toString() {
  1205. return $this->__call('__toString',array());
  1206. }
  1207. /**
  1208. * Implementation of Array Access Interface, you can access bean objects
  1209. * like an array.
  1210. * Call gets routed to __set.
  1211. *
  1212. * @param mixed $offset offset string
  1213. * @param mixed $value value
  1214. *
  1215. * @return void
  1216. */
  1217. public function offsetSet($offset, $value) {
  1218. $this->__set($offset, $value);
  1219. }
  1220. /**
  1221. * Implementation of Array Access Interface, you can access bean objects
  1222. * like an array.
  1223. *
  1224. * @param mixed $offset property
  1225. *
  1226. * @return
  1227. */
  1228. public function offsetExists($offset) {
  1229. return isset($this->properties[$offset]);
  1230. }
  1231. /**
  1232. * Implementation of Array Access Interface, you can access bean objects
  1233. * like an array.
  1234. * Unsets a value from the array/bean.
  1235. *
  1236. * @param mixed $offset property
  1237. *
  1238. * @return
  1239. */
  1240. public function offsetUnset($offset) {
  1241. unset($this->properties[$offset]);
  1242. }
  1243. /**
  1244. * Implementation of Array Access Interface, you can access bean objects
  1245. * like an array.
  1246. * Returns value of a property.
  1247. *
  1248. * @param mixed $offset property
  1249. *
  1250. * @return
  1251. */
  1252. public function offsetGet($offset) {
  1253. return $this->__get($offset);
  1254. }
  1255. }
  1256. /**
  1257. * Observable
  1258. * Base class for Observables
  1259. * @file RedBean/Observable.php
  1260. * @description Part of the observer pattern in RedBean
  1261. * @author Gabor de Mooij
  1262. * @license BSD
  1263. *
  1264. *
  1265. * (c) G.J.G.T. (Gabor) de Mooij
  1266. * This source file is subject to the BSD/GPLv2 License that is bundled
  1267. * with this source code in the file license.txt.
  1268. */
  1269. abstract class RedBean_Observable {
  1270. /**
  1271. *
  1272. * @var array
  1273. */
  1274. private $observers = array();
  1275. /**
  1276. * Adds a listener to this instance
  1277. * @param $eventname
  1278. * @param $observer
  1279. * @return unknown_type
  1280. */
  1281. public function addEventListener( $eventname, RedBean_Observer $observer ) {
  1282. if (!isset($this->observers[ $eventname ])) {
  1283. $this->observers[ $eventname ] = array();
  1284. }
  1285. foreach($this->observers[$eventname] as $o) if ($o==$observer) return;
  1286. $this->observers[ $eventname ][] = $observer;
  1287. }
  1288. /**
  1289. * Sends an event (signal) to the registered listeners
  1290. * @param $eventname
  1291. * @return unknown_type
  1292. */
  1293. public function signal( $eventname, $info ) {
  1294. if (!isset($this->observers[ $eventname ])) {
  1295. $this->observers[ $eventname ] = array();
  1296. }
  1297. foreach($this->observers[$eventname] as $observer) {
  1298. $observer->onEvent( $eventname, $info );
  1299. }
  1300. }
  1301. }
  1302. /**
  1303. * Observer
  1304. * @file RedBean/Observer.php
  1305. * @description Part of the observer pattern in RedBean
  1306. * @author Gabor de Mooij
  1307. * @license BSD
  1308. *
  1309. *
  1310. * (c) G.J.G.T. (Gabor) de Mooij
  1311. * This source file is subject to the BSD/GPLv2 License that is bundled
  1312. * with this source code in the file license.txt.
  1313. */
  1314. interface RedBean_Observer {
  1315. /**
  1316. * Part of the RedBean Observer Infrastructure.
  1317. * @param string $eventname
  1318. * @param RedBean_OODBBean $bean
  1319. */
  1320. public function onEvent( $eventname, $bean );
  1321. }
  1322. /**
  1323. * Adapter Interface
  1324. * @file RedBean/Adapter.php
  1325. * @description Describes the API for a RedBean Database Adapter.
  1326. * @author Gabor de Mooij
  1327. * @license BSD
  1328. *
  1329. * (c) G.J.G.T. (Gabor) de Mooij
  1330. * This source file is subject to the BSD/GPLv2 License that is bundled
  1331. * with this source code in the file license.txt.
  1332. *
  1333. */
  1334. interface RedBean_Adapter {
  1335. /**
  1336. * Returns the latest SQL statement
  1337. *
  1338. * @return string $SQLString SQLString
  1339. */
  1340. public function getSQL();
  1341. /**
  1342. * Escapes a value for usage in an SQL statement
  1343. *
  1344. * @param string $sqlvalue value
  1345. */
  1346. public function escape( $sqlvalue );
  1347. /**
  1348. * Executes an SQL Statement using an array of values to bind
  1349. * If $noevent is TRUE then this function will not signal its
  1350. * observers to notify about the SQL execution; this to prevent
  1351. * infinite recursion when using observers.
  1352. *
  1353. * @param string $sql SQL
  1354. * @param array $aValues values
  1355. * @param boolean $noevent no event firing
  1356. */
  1357. public function exec( $sql , $aValues=array(), $noevent=false);
  1358. /**
  1359. * Executes an SQL Query and returns a resultset.
  1360. * This method returns a multi dimensional resultset similar to getAll
  1361. * The values array can be used to bind values to the place holders in the
  1362. * SQL query.
  1363. *
  1364. * @param string $sql SQL
  1365. * @param array $aValues values
  1366. */
  1367. public function get( $sql, $aValues = array() );
  1368. /**
  1369. * Executes an SQL Query and returns a resultset.
  1370. * This method returns a single row (one array) resultset.
  1371. * The values array can be used to bind values to the place holders in the
  1372. * SQL query.
  1373. *
  1374. * @param string $sql SQL
  1375. * @param array $aValues values to bind
  1376. *
  1377. * @return array $aMultiDimArray row
  1378. */
  1379. public function getRow( $sql, $aValues = array() );
  1380. /**
  1381. * Executes an SQL Query and returns a resultset.
  1382. * This method returns a single column (one array) resultset.
  1383. * The values array can be used to bind values to the place holders in the
  1384. * SQL query.
  1385. *
  1386. * @param string $sql SQL
  1387. * @param array $aValues values to bind
  1388. *
  1389. * @return array $aSingleDimArray column
  1390. */
  1391. public function getCol( $sql, $aValues = array() );
  1392. /**
  1393. * Executes an SQL Query and returns a resultset.
  1394. * This method returns a single cell, a scalar value as the resultset.
  1395. * The values array can be used to bind values to the place holders in the
  1396. * SQL query.
  1397. *
  1398. * @param string $sql SQL
  1399. * @param array $aValues values to bind
  1400. *
  1401. * @return string $sSingleValue value from cell
  1402. */
  1403. public function getCell( $sql, $aValues = array() );
  1404. /**
  1405. * Executes the SQL query specified in $sql and takes
  1406. * the first two columns of the resultset. This function transforms the
  1407. * resultset into an associative array. Values from the the first column will
  1408. * serve as keys while the values of the second column will be used as values.
  1409. * The values array can be used to bind values to the place holders in the
  1410. * SQL query.
  1411. *
  1412. * @param string $sql SQL
  1413. * @param array $values values to bind
  1414. *
  1415. * @return array $associativeArray associative array result set
  1416. */
  1417. public function getAssoc( $sql, $values = array() );
  1418. /**
  1419. * Returns the latest insert ID.
  1420. *
  1421. * @return integer $id primary key ID
  1422. */
  1423. public function getInsertID();
  1424. /**
  1425. * Returns the number of rows that have been
  1426. * affected by the last update statement.
  1427. *
  1428. * @return integer $count number of rows affected
  1429. */
  1430. public function getAffectedRows();
  1431. /**
  1432. * Returns the original database resource. This is useful if you want to
  1433. * perform operations on the driver directly instead of working with the
  1434. * adapter. RedBean will only access the adapter and never to talk
  1435. * directly to the driver though.
  1436. *
  1437. * @return object $driver driver
  1438. */
  1439. public function getDatabase();
  1440. /**
  1441. * Returns the latest error message; if any.
  1442. *
  1443. * @return string $message error message from server
  1444. */
  1445. public function getErrorMsg();
  1446. /**
  1447. * This method is part of the RedBean Transaction Management
  1448. * mechanisms.
  1449. * Starts a transaction.
  1450. */
  1451. public function startTransaction();
  1452. /**
  1453. * This method is part of the RedBean Transaction Management
  1454. * mechanisms.
  1455. * Commits the transaction.
  1456. */
  1457. public function commit();
  1458. /**
  1459. * This method is part of the RedBean Transaction Management
  1460. * mechanisms.
  1461. * Rolls back the transaction.
  1462. */
  1463. public function rollback();
  1464. }
  1465. /**
  1466. * DBAdapter (Database Adapter)
  1467. * @file RedBean/Adapter/DBAdapter.php
  1468. * @description An adapter class to connect various database systems to RedBean
  1469. * @author Gabor de Mooij
  1470. * @license BSD
  1471. *
  1472. *
  1473. * (c) G.J.G.T. (Gabor) de Mooij
  1474. * This source file is subject to the BSD/GPLv2 License that is bundled
  1475. * with this source code in the file license.txt.
  1476. */
  1477. class RedBean_Adapter_DBAdapter extends RedBean_Observable implements RedBean_Adapter {
  1478. /**
  1479. * @var RedBean_Driver
  1480. *
  1481. * ADODB compatible class
  1482. */
  1483. private $db = null;
  1484. /**
  1485. * @var string
  1486. *
  1487. * Contains SQL snippet
  1488. */
  1489. private $sql = "";
  1490. /**
  1491. * Constructor.
  1492. * Creates an instance of the RedBean Adapter Class.
  1493. * This class provides an interface for RedBean to work
  1494. * with ADO compatible DB instances.
  1495. *
  1496. * @param RedBean_Driver $database ADO Compatible DB Instance
  1497. */
  1498. public function __construct($database) {
  1499. $this->db = $database;
  1500. }
  1501. /**
  1502. * Returns the latest SQL Statement.
  1503. *
  1504. * @return string $SQL latest SQL statement
  1505. */
  1506. public function getSQL() {
  1507. return $this->sql;
  1508. }
  1509. /**
  1510. * Escapes a string for use in a Query.
  1511. *
  1512. * @param string $sqlvalue SQL value to escape
  1513. *
  1514. * @return string $escapedValue escaped value
  1515. */
  1516. public function escape( $sqlvalue ) {
  1517. return $this->db->Escape($sqlvalue);
  1518. }
  1519. /**
  1520. * Executes SQL code; any query without
  1521. * returning a resultset.
  1522. * This function allows you to provide an array with values to bind
  1523. * to query parameters. For instance you can bind values to question
  1524. * marks in the query. Each value in the array corresponds to the
  1525. * question mark in the query that matches the position of the value in the
  1526. * array. You can also bind values using explicit keys, for instance
  1527. * array(":key"=>123) will bind the integer 123 to the key :key in the
  1528. * SQL.
  1529. *
  1530. * @param string $sql SQL Code to execute
  1531. * @param array $values assoc. array binding values
  1532. * @param boolean $noevent if TRUE this will suppress the event 'sql_exec'
  1533. *
  1534. * @return mixed $undefSet whatever driver returns, undefined
  1535. */
  1536. public function exec( $sql , $aValues=array(), $noevent=false) {
  1537. if (!$noevent) {
  1538. $this->sql = $sql;
  1539. $this->signal("sql_exec", $this);
  1540. }
  1541. return $this->db->Execute( $sql, $aValues );
  1542. }
  1543. /**
  1544. * Multi array SQL fetch. Fetches a multi dimensional array.
  1545. * This function allows you to provide an array with values to bind
  1546. * to query parameters. For instance you can bind values to question
  1547. * marks in the query. Each value in the array corresponds to the
  1548. * question mark in the query that matches the position of the value in the
  1549. * array. You can also bind values using explicit keys, for instance
  1550. * array(":key"=>123) will bind the integer 123 to the key :key in the
  1551. * SQL.
  1552. *
  1553. * @param string $sql SQL code to execute
  1554. * @param array $values assoc. array binding values
  1555. *
  1556. * @return array $result two dimensional array result set
  1557. */
  1558. public function get( $sql, $aValues = array() ) {
  1559. $this->sql = $sql;
  1560. $this->signal("sql_exec", $this);
  1561. return $this->db->GetAll( $sql,$aValues );
  1562. }
  1563. /**
  1564. * Executes SQL and fetches a single row.
  1565. * This function allows you to provide an array with values to bind
  1566. * to query parameters. For instance you can bind values to question
  1567. * marks in the query. Each value in the array corresponds to the
  1568. * question mark in the query that matches the position of the value in the
  1569. * array. You can also bind values using explicit keys, for instance
  1570. * array(":key"=>123) will bind the integer 123 to the key :key in the
  1571. * SQL.
  1572. *
  1573. * @param string $sql SQL code to execute
  1574. * @param array $values assoc. array binding values
  1575. *
  1576. * @return array $result one dimensional array result set
  1577. */
  1578. public function getRow( $sql, $aValues = array() ) {
  1579. $this->sql = $sql;
  1580. $this->signal("sql_exec", $this);
  1581. return $this->db->GetRow( $sql,$aValues );
  1582. }
  1583. /**
  1584. * Executes SQL and returns a one dimensional array result set.
  1585. * This function rotates the result matrix to obtain a column result set.
  1586. * This function allows you to provide an array with values to bind
  1587. * to query parameters. For instance you can bind values to question
  1588. * marks in the query. Each value in the array corresponds to the
  1589. * question mark in the query that matches the position of the value in the
  1590. * array. You can also bind values using explicit keys, for instance
  1591. * array(":key"=>123) will bind the integer 123 to the key :key in the
  1592. * SQL.
  1593. *
  1594. * @param string $sql SQL code to execute
  1595. * @param array $values assoc. array binding values
  1596. *
  1597. * @return array $result one dimensional array result set
  1598. */
  1599. public function getCol( $sql, $aValues = array() ) {
  1600. $this->sql = $sql;
  1601. $this->signal("sql_exec", $this);
  1602. return $this->db->GetCol( $sql,$aValues );
  1603. }
  1604. /**
  1605. * Executes an SQL Query and fetches the first two columns only.
  1606. * Then this function builds an associative array using the first
  1607. * column for the keys and the second result column for the
  1608. * values. For instance: SELECT id, name FROM... will produce
  1609. * an array like: id => name.
  1610. * This function allows you to provide an array with values to bind
  1611. * to query parameters. For instance you can bind values to question
  1612. * marks in the query. Each value in the array corresponds to the
  1613. * question mark in the query that matches the position of the value in the
  1614. * array. You can also bind values using explicit keys, for instance
  1615. * array(":key"=>123) will bind the integer 123 to the key :key in the
  1616. * SQL.
  1617. *
  1618. * @param string $sql SQL code to execute
  1619. * @param array $values assoc. array binding values
  1620. *
  1621. * @return array $result multi dimensional assoc. array result set
  1622. */
  1623. public function getAssoc( $sql, $aValues = array() ) {
  1624. $this->sql = $sql;
  1625. $this->signal("sql_exec", $this);
  1626. $rows = $this->db->GetAll( $sql, $aValues );
  1627. $assoc = array();
  1628. if ($rows) {
  1629. foreach($rows as $row) {
  1630. if (count($row)>0) {
  1631. $key = array_shift($row);
  1632. }
  1633. if (count($row)>0) {
  1634. $value = array_shift($row);
  1635. }
  1636. else {
  1637. $value = $key;
  1638. }
  1639. $assoc[ $key ] = $value;
  1640. }
  1641. }
  1642. return $assoc;
  1643. }
  1644. /**
  1645. * Retrieves a single cell.
  1646. * This function allows you to provide an array with values to bind
  1647. * to query parameters. For instance you can bind values to question
  1648. * marks in the query. Each value in the array corresponds to the
  1649. * question mark in the query that matches the position of the value in the
  1650. * array. You can also bind values using explicit keys, for instance
  1651. * array(":key"=>123) will bind the integer 123 to the key :key in the
  1652. * SQL.
  1653. *
  1654. * @param string $sql sql code to execute
  1655. * @param array $values assoc. array binding values
  1656. *
  1657. * @return array $result scalar result set
  1658. */
  1659. public function getCell( $sql, $aValues = array(), $noSignal = null ) {
  1660. $this->sql = $sql;
  1661. if (!$noSignal) $this->signal("sql_exec", $this);
  1662. $arr = $this->db->getCol( $sql, $aValues );
  1663. if ($arr && is_array($arr)) return ($arr[0]); else return false;
  1664. }
  1665. /**
  1666. * Returns latest insert id, most recently inserted id.
  1667. *
  1668. * @return integer $id latest insert ID
  1669. */
  1670. public function getInsertID() {
  1671. return $this->db->getInsertID();
  1672. }
  1673. /**
  1674. * Returns number of affected rows.
  1675. *
  1676. * @return integer $numOfAffectRows
  1677. */
  1678. public function getAffectedRows() {
  1679. return $this->db->Affected_Rows();
  1680. }
  1681. /**
  1682. * Unwrap the original database object.
  1683. *
  1684. * @return RedBean_Driver $database returns the inner database object
  1685. */
  1686. public function getDatabase() {
  1687. return $this->db;
  1688. }
  1689. /**
  1690. * Return latest error message.
  1691. *
  1692. * @return string $message most recent error message
  1693. */
  1694. public function getErrorMsg() {
  1695. return $this->db->Errormsg();
  1696. }
  1697. /**
  1698. * Transactions.
  1699. * Part of the transaction management infrastructure of RedBean.
  1700. * Starts a transaction.
  1701. */
  1702. public function startTransaction() {
  1703. return $this->db->StartTrans();
  1704. }
  1705. /**
  1706. * Transactions.
  1707. * Part of the transaction management infrastructure of RedBean.
  1708. * Commits a transaction.
  1709. */
  1710. public function commit() {
  1711. return $this->db->CommitTrans();
  1712. }
  1713. /**
  1714. * Transactions.
  1715. * Part of the transaction management infrastructure of RedBean.
  1716. * Rolls back transaction.
  1717. */
  1718. public function rollback() {
  1719. return $this->db->FailTrans();
  1720. }
  1721. }
  1722. /**
  1723. * QueryWriter
  1724. * Interface for QueryWriters
  1725. * @file RedBean/QueryWriter.php
  1726. * @description Describes the API for a QueryWriter
  1727. * @author Gabor de Mooij
  1728. * @license BSD
  1729. *
  1730. *
  1731. * (c) G.J.G.T. (Gabor) de Mooij
  1732. * This source file is subject to the BSD/GPLv2 License that is bundled
  1733. * with this source code in the file license.txt.
  1734. */
  1735. interface RedBean_QueryWriter {
  1736. /**
  1737. * QueryWriter Constant Identifier.
  1738. * Identifies a situation in which a table has not been found in
  1739. * the database.
  1740. */
  1741. const C_SQLSTATE_NO_SUCH_TABLE = 1;
  1742. /**
  1743. * QueryWriter Constant Identifier.
  1744. * Identifies a situation in which a perticular column has not
  1745. * been found in the database.
  1746. */
  1747. const C_SQLSTATE_NO_SUCH_COLUMN = 2;
  1748. /**
  1749. * QueryWriter Constant Identifier.
  1750. * Identifies a situation in which a perticular column has not
  1751. * been found in the database.
  1752. */
  1753. const C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION = 3;
  1754. /**
  1755. * Returns the table to store beans of a given type.
  1756. * @param string $type
  1757. */
  1758. public function getFormattedTableName($type);
  1759. /**
  1760. * Returns the tables that are in the database.
  1761. * @return array $arrayOfTables
  1762. */
  1763. public function getTables();
  1764. /**
  1765. * Creates the table with the specified name.
  1766. * @param string $table
  1767. */
  1768. public function createTable( $table );
  1769. /**
  1770. * Returns an array containing all the columns of the specified table.
  1771. * @param string $table
  1772. */
  1773. public function getColumns( $table );
  1774. /**
  1775. * Returns the type of a certain value.
  1776. * @param mixed $value
  1777. * @return integer $type
  1778. */
  1779. public function scanType( $value );
  1780. /**
  1781. * Adds the column to $table using column name $column and
  1782. * making it of type $type.
  1783. * @param string $table
  1784. * @param string $column
  1785. * @param integer $type
  1786. *
  1787. */
  1788. public function addColumn( $table, $column, $type );
  1789. /**
  1790. * Codes an SQL Column Type Description to a RedBean QueryWriter type.
  1791. * @param integer $typedescription
  1792. * @return integer $type
  1793. */
  1794. public function code( $typedescription );
  1795. /**
  1796. * Widens the column to support type $type.
  1797. * @param string $table
  1798. * @param string $column
  1799. * @param integer $type
  1800. */
  1801. public function widenColumn( $table, $column, $type );
  1802. /**
  1803. * Updates a record
  1804. * @param string $table
  1805. * @param array $updatevalues
  1806. * @param integer $id
  1807. */
  1808. public function updateRecord( $table, $updatevalues, $id);
  1809. /**
  1810. * Inserts a record
  1811. * @param string $table
  1812. * @param array $insertcolumns
  1813. * @param array $insertvalues
  1814. */
  1815. public function insertRecord( $table, $insertcolumns, $insertvalues );
  1816. /**
  1817. * Selects a record
  1818. * @param string $type
  1819. * @param integer $ids
  1820. */
  1821. public function selectRecord($type, $ids);
  1822. /**
  1823. * Removes a record from a table
  1824. * @param string $table
  1825. * @param integer $id
  1826. */
  1827. public function deleteRecord( $table, $id );
  1828. /**
  1829. * Adds a UNIQUE constraint index to a table on columns $columns.
  1830. * @param string $table
  1831. * @param array $columnsPartOfIndex
  1832. */
  1833. public function addUniqueIndex( $table,$columns );
  1834. /**
  1835. * Returns the property that contains the Primary Key ID in an
  1836. * OODBBean instance.
  1837. * @param string $tableOfTheBean
  1838. */
  1839. public function getIDField( $table );
  1840. /**
  1841. * Selects a set of columns using criteria.
  1842. * @param string $select - the column to be selected
  1843. * @param string $table - the name of the table
  1844. * @param string $column - name of the column that needs to be compared
  1845. * @param string $value - value to compare against
  1846. * @param boolean $withUnion - whether you want a union with inverted column
  1847. */
  1848. public function selectByCrit( $select, $table, $column, $value, $withUnion=false );
  1849. /**
  1850. * Deletes by criteria.
  1851. * @param string $table
  1852. * @param array $crits
  1853. */
  1854. public function deleteByCrit( $table, $crits );
  1855. /**
  1856. * Returns $str surrounded by keyword protecting / esc symbols
  1857. * @param string $str
  1858. */
  1859. public function noKW($str);
  1860. /**
  1861. * Checks whether the SQL state is in the list of specified states
  1862. * and returns true if it does appear in this list or false if it
  1863. * does not.
  1864. * @param string $state
  1865. * @param array $list
  1866. * @return boolean $isInList
  1867. */
  1868. public function sqlStateIn( $state, $list );
  1869. /**
  1870. * Returns a snippet of SQL to filter records using SQL and a list of
  1871. * keys.
  1872. *
  1873. * @param string $idfield ID Field to use for selecting primary key
  1874. * @param array $keys List of keys to use for filtering
  1875. * @param string $sql SQL to append, if any
  1876. * @param boolean $inverse Whether you want to inverse the selection
  1877. *
  1878. * @return string $snippet SQL Snippet crafted by function
  1879. */
  1880. public function getSQLSnippetFilter( $idfield, $keys, $sql=null, $inverse=false );
  1881. }
  1882. /**
  1883. * RedBean Abstract Query Writer
  1884. * @file RedBean/QueryWriter/AQueryWriter.php
  1885. * @description
  1886. * Represents an abstract Database to RedBean
  1887. * To write a driver for a different database for RedBean
  1888. * Contains a number of functions all implementors can
  1889. * inherit or override.
  1890. *
  1891. * @author Gabor de Mooij
  1892. * @license BSD
  1893. *
  1894. *
  1895. * (c) G.J.G.T. (Gabor) de Mooij
  1896. * This source file is subject to the BSD/GPLv2 License that is bundled
  1897. * with this source code in the file license.txt.
  1898. */
  1899. abstract class RedBean_QueryWriter_AQueryWriter {
  1900. /**
  1901. *
  1902. * @var RedBean_IBeanFormatter
  1903. * Holds the bean formatter to be used for applying
  1904. * table schema.
  1905. */
  1906. public $tableFormatter;
  1907. /**
  1908. * @var array
  1909. * Supported Column Types.
  1910. */
  1911. public $typeno_sqltype = array();
  1912. /**
  1913. *
  1914. * @var RedBean_Adapter_DBAdapter
  1915. * Holds a reference to the database adapter to be used.
  1916. */
  1917. protected $adapter;
  1918. /**
  1919. * @var string
  1920. * Indicates the field name to be used for primary keys;
  1921. * default is 'id'.
  1922. */
  1923. protected $idfield = "id";
  1924. /**
  1925. * @var string
  1926. * default value to for blank field (passed to PK for auto-increment)
  1927. */
  1928. protected $defaultValue = 'NULL';
  1929. /**
  1930. * @var string
  1931. * character to escape keyword table/column names
  1932. */
  1933. protected $quoteCharacter = '';
  1934. /**
  1935. * Do everything that needs to be done to format a table name.
  1936. *
  1937. * @param string $name of table
  1938. *
  1939. * @return string table name
  1940. */
  1941. public function safeTable($name, $noQuotes = false) {
  1942. $name = $this->getFormattedTableName($name);
  1943. $name = $this->check($name);
  1944. if (!$noQuotes) $name = $this->noKW($name);
  1945. return $name;
  1946. }
  1947. /**
  1948. * Do everything that needs to be done to format a column name.
  1949. *
  1950. * @param string $name of column
  1951. *
  1952. * @return string $column name
  1953. */
  1954. public function safeColumn($name, $noQuotes = false) {
  1955. $name = $this->check($name);
  1956. if (!$noQuotes) $name = $this->noKW($name);
  1957. return $name;
  1958. }
  1959. /**
  1960. * Returns the sql that should follow an insert statement.
  1961. *
  1962. * @param string $table name
  1963. *
  1964. * @return string sql
  1965. */
  1966. protected function getInsertSuffix ($table) {
  1967. return "";
  1968. }
  1969. /**
  1970. * Returns the string identifying a table for a given type.
  1971. *
  1972. * @param string $type
  1973. *
  1974. * @return string $table
  1975. */
  1976. public function getFormattedTableName($type) {
  1977. if ($this->tableFormatter) return $this->tableFormatter->formatBeanTable($type);
  1978. return $type;
  1979. }
  1980. /**
  1981. * Sets the Bean Formatter to be used to handle
  1982. * custom/advanced DB<->Bean
  1983. * Mappings. This method has no return value.
  1984. *
  1985. * @param RedBean_IBeanFormatter $beanFormatter the bean formatter
  1986. *
  1987. * @return void
  1988. */
  1989. public function setBeanFormatter( RedBean_IBeanFormatter $beanFormatter ) {
  1990. $this->tableFormatter = $beanFormatter;
  1991. }
  1992. /**
  1993. * Get sql column type.
  1994. *
  1995. * @param integer $type constant
  1996. *
  1997. * @return string sql type
  1998. */
  1999. public function getFieldType( $type = "" ) {
  2000. return array_key_exists($type, $this->typeno_sqltype) ? $this->typeno_sqltype[$type] : "";
  2001. }
  2002. /**
  2003. * Returns the column name that should be used
  2004. * to store and retrieve the primary key ID.
  2005. *
  2006. * @param string $type type of bean to get ID Field for
  2007. *
  2008. * @return string $idfieldtobeused ID field to be used for this type of bean
  2009. */
  2010. public function getIDField( $type ) {
  2011. $nArgs = func_num_args();
  2012. if ($nArgs>1) $safe = func_get_arg(1); else $safe = false;
  2013. if ($this->tableFormatter) return $this->tableFormatter->formatBeanID($type);
  2014. return $safe ? $this->safeColumn($this->idfield) : $this->idfield;
  2015. }
  2016. /**
  2017. * Checks table name or column name.
  2018. *
  2019. * @param string $table table string
  2020. *
  2021. * @return string $table escaped string
  2022. */
  2023. public function check($table) {
  2024. if ($this->quoteCharacter && strpos($table, $this->quoteCharacter)!==false) {
  2025. throw new Redbean_Exception_Security("Illegal chars in table name");
  2026. }
  2027. return $this->adapter->escape($table);
  2028. }
  2029. /**
  2030. * Puts keyword escaping symbols around string.
  2031. *
  2032. * @param string $str keyword
  2033. *
  2034. * @return string $keywordSafeString escaped keyword
  2035. */
  2036. public function noKW($str) {
  2037. $q = $this->quoteCharacter;
  2038. return $q.$str.$q;
  2039. }
  2040. /**
  2041. * Adds a column of a given type to a table.
  2042. *
  2043. * @param string $table name of the table
  2044. * @param string $column name of the column
  2045. * @param integer $type type
  2046. *
  2047. */
  2048. public function addColumn( $table, $column, $type ) {
  2049. $table = $this->safeTable($table);
  2050. $column = $this->safeColumn($column);
  2051. $type = $this->getFieldType($type);
  2052. $sql = "ALTER TABLE $table ADD $column $type ";
  2053. $this->adapter->exec( $sql );
  2054. }
  2055. /**
  2056. * Update a record using a series of update values.
  2057. *
  2058. * @param string $table table
  2059. * @param array $updatevalues update values
  2060. * @param integer $id primary key for record
  2061. */
  2062. public function updateRecord( $table, $updatevalues, $id) {
  2063. $idfield = $this->getIDField($table, true);
  2064. $table = $this->safeTable($table);
  2065. $sql = "UPDATE $table SET ";
  2066. $p = $v = array();
  2067. foreach($updatevalues as $uv) {
  2068. $p[] = " {$this->safeColumn($uv["property"])} = ? ";
  2069. $v[]=$uv["value"];
  2070. }
  2071. $sql .= implode(",", $p ) ." WHERE $idfield = ".intval($id);
  2072. $this->adapter->exec( $sql, $v );
  2073. }
  2074. /**
  2075. * Inserts a record into the database using a series of insert columns
  2076. * and corresponding insertvalues. Returns the insert id.
  2077. *
  2078. * @param string $table table to perform query on
  2079. * @param array $insertcolumns columns to be inserted
  2080. * @param array $insertvalues values to be inserted
  2081. *
  2082. * @return integer $insertid insert id from driver, new record id
  2083. */
  2084. public function insertRecord( $table, $insertcolumns, $insertvalues ) {
  2085. $default = $this->defaultValue;
  2086. $idfield = $this->getIDField($table, true);
  2087. $suffix = $this->getInsertSuffix($table);
  2088. $table = $this->safeTable($table);
  2089. if (count($insertvalues)>0 && is_array($insertvalues[0]) && count($insertvalues[0])>0) {
  2090. foreach($insertcolumns as $k=>$v) {
  2091. $insertcolumns[$k] = $this->safeColumn($v);
  2092. }
  2093. $insertSQL = "INSERT INTO $table ( $idfield, ".implode(",",$insertcolumns)." ) VALUES ";
  2094. $insertSQL .= "( $default, ". implode(",",array_fill(0,count($insertcolumns)," ? "))." ) $suffix";
  2095. $first=true;
  2096. foreach($insertvalues as $i=>$insertvalue) {
  2097. $ids[] = $this->adapter->getCell( $insertSQL, $insertvalue, $i );
  2098. }
  2099. $result = count($ids)===1 ? array_pop($ids) : $ids;
  2100. }
  2101. else {
  2102. $result = $this->adapter->getCell( "INSERT INTO $table ($idfield) VALUES($default) $suffix");
  2103. }
  2104. if ($suffix) return $result;
  2105. $last_id = $this->adapter->getInsertID();
  2106. return ($this->adapter->getErrorMsg()=="" ? $last_id : 0);
  2107. }
  2108. /**
  2109. * Selects a record based on type and id.
  2110. *
  2111. * @param string $type type
  2112. * @param integer $id id
  2113. *
  2114. * @return array $row resulting row or NULL if none has been found
  2115. */
  2116. public function selectRecord($type, $ids) {
  2117. $idfield = $this->getIDField($type, true);
  2118. $table = $this->safeTable($type);
  2119. $sql = "SELECT * FROM $table WHERE $idfield IN ( ".implode(',', array_fill(0, count($ids), " ? "))." )";
  2120. $rows = $this->adapter->get($sql,$ids);
  2121. return ($rows && is_array($rows) && count($rows)>0) ? $rows : NULL;
  2122. }
  2123. /**
  2124. * Deletes a record based on a table, column, value and operator
  2125. *
  2126. * @param string $table table
  2127. * @param integer $value primary key id
  2128. *
  2129. * @todo validate arguments for security
  2130. */
  2131. public function deleteRecord($table, $value) {
  2132. $column = $this->getIDField($table, true);
  2133. $table = $this->safeTable($table);
  2134. $this->adapter->exec("DELETE FROM $table WHERE $column = ? ",array(strval($value)));
  2135. }
  2136. /**
  2137. * Selects a record using a criterium.
  2138. * Specify the select-column, the target table, the criterium column
  2139. * and the criterium value. This method scans the specified table for
  2140. * records having a criterium column with a value that matches the
  2141. * specified value. For each record the select-column value will be
  2142. * returned, most likely this will be a primary key column like ID.
  2143. * If $withUnion equals true the method will also return the $column
  2144. * values for each entry that has a matching select-column. This is
  2145. * handy for cross-link tables like page_page.
  2146. *
  2147. * @param string $select the column to be selected
  2148. * @param string $table the table to select from
  2149. * @param string $column the column to compare the criteria value against
  2150. * @param string $value the criterium value to match against
  2151. * @param boolean $union with union (default is false)
  2152. * @param string $sql optional template (in this case rows are returned instead of keys)
  2153. *
  2154. * @return array $array selected column with values
  2155. */
  2156. public function selectByCrit( $select, $table, $column, $value, $withUnion = false, $sqlTemplate = false ) {
  2157. $table = $this->safeTable($table);
  2158. $select = $this->safeColumn($select);
  2159. $column = $this->safeColumn($column);
  2160. $value = $this->adapter->escape($value);
  2161. $sql = "SELECT $select FROM $table WHERE $column = ? ";
  2162. $values = array($value);
  2163. if ($withUnion) {
  2164. $sql .= " UNION SELECT $column FROM $table WHERE $select = ? ";
  2165. $values[] = $value;
  2166. }
  2167. if ($sqlTemplate) {
  2168. $sql = str_replace(":sql",$sql,$sqlTemplate);
  2169. return $this->adapter->get($sql,$values);
  2170. }
  2171. return $this->adapter->getCol($sql,$values);
  2172. }
  2173. /**
  2174. * This method takes an array with key=>value pairs.
  2175. * Each record that has a complete match with the array is
  2176. * deleted from the table.
  2177. *
  2178. * @param string $table table
  2179. * @param array $crits criteria
  2180. *
  2181. * @return integer $affectedRows num. of affected rows.
  2182. */
  2183. public function deleteByCrit( $table, $crits ) {
  2184. $table = $this->safeTable($table);
  2185. $values = array();
  2186. foreach($crits as $key=>$val) {
  2187. $values[] = $this->adapter->escape($val);
  2188. $conditions[] = $this->safeColumn($key) ."= ? ";
  2189. }
  2190. $sql = "DELETE FROM $table WHERE ".implode(" AND ", $conditions);
  2191. return (int) $this->adapter->exec($sql, $values);
  2192. }
  2193. /**
  2194. * Returns a snippet of SQL to filter records using SQL and a list of
  2195. * keys.
  2196. *
  2197. * @param string $idfield ID Field to use for selecting primary key
  2198. * @param array $keys List of keys to use for filtering
  2199. * @param string $sql SQL to append, if any
  2200. * @param boolean $inverse Whether you want to inverse the selection
  2201. *
  2202. * @return string $snippet SQL Snippet crafted by function
  2203. */
  2204. public function getSQLSnippetFilter( $idfield, $keys, $sql=null, $inverse=false ) {
  2205. if (!$sql) $sql=" 1 ";
  2206. if (!$inverse && count($keys)===0) return " 0 ";
  2207. $idfield = $this->noKW($idfield);
  2208. $sqlInverse = ($inverse) ? "NOT" : "";
  2209. $sqlKeyFilter = ($keys) ? " $idfield $sqlInverse IN (".implode(",",$keys).") AND " : " ";
  2210. $sqlSnippet = $sqlKeyFilter . $sql;
  2211. return $sqlSnippet;
  2212. }
  2213. /**
  2214. * Truncates a table
  2215. *
  2216. * @param string $table
  2217. */
  2218. public function wipe($table) {
  2219. $table = $this->safeTable($table);
  2220. $sql = "TRUNCATE $table ";
  2221. $this->adapter->exec($sql);
  2222. }
  2223. /**
  2224. * Counts rows in a table.
  2225. *
  2226. * @param string $beanType
  2227. *
  2228. * @return integer $numRowsFound
  2229. */
  2230. public function count($beanType) {
  2231. $table = $this->safeTable($beanType);
  2232. $sql = "SELECT count(*) FROM $table ";
  2233. return (int) $this->adapter->getCell($sql);
  2234. }
  2235. /**
  2236. * Optimized version for related + SQL.
  2237. * Facade uses this method if fearlesscode flag is 'on'.
  2238. *
  2239. * @param string $table reference table
  2240. * @param string $idfield ID field to be used
  2241. * @param string $sqlSnippet SQL snippet to include in the query
  2242. *
  2243. * @return string $sqlTemplate the resulting SQL code.
  2244. */
  2245. public function __fastSelectCritRelated($table, $idfield, $sqlSnippet = "1") {
  2246. $idfield = $this->safeColumn($idfield);
  2247. $sqlTemplate = " SELECT * FROM $table WHERE $idfield IN ( :sql ) AND $sqlSnippet ";
  2248. return $sqlTemplate;
  2249. }
  2250. }
  2251. /**
  2252. * RedBean MySQLWriter
  2253. *
  2254. * @file RedBean/QueryWriter/MySQL.php
  2255. * @description Represents a MySQL Database to RedBean
  2256. * To write a driver for a different database for RedBean
  2257. * you should only have to change this file.
  2258. * @author Gabor de Mooij
  2259. * @license BSD
  2260. *
  2261. *
  2262. * (c) G.J.G.T. (Gabor) de Mooij
  2263. * This source file is subject to the BSD/GPLv2 License that is bundled
  2264. * with this source code in the file license.txt.
  2265. */
  2266. class RedBean_QueryWriter_MySQL extends RedBean_QueryWriter_AQueryWriter implements RedBean_QueryWriter {
  2267. /**
  2268. * Here we describe the datatypes that RedBean
  2269. * Uses internally. If you write a QueryWriter for
  2270. * RedBean you should provide a list of types like this.
  2271. */
  2272. /**
  2273. * @var integer
  2274. *
  2275. * DATA TYPE
  2276. * Boolean Data type
  2277. */
  2278. const C_DATATYPE_BOOL = 0;
  2279. /**
  2280. *
  2281. * @var integer
  2282. *
  2283. * DATA TYPE
  2284. * Unsigned 8BIT Integer
  2285. *
  2286. */
  2287. const C_DATATYPE_UINT8 = 1;
  2288. /**
  2289. *
  2290. * @var integer
  2291. *
  2292. * DATA TYPE
  2293. * Unsigned 32BIT Integer
  2294. *
  2295. */
  2296. const C_DATATYPE_UINT32 = 2;
  2297. /**
  2298. * @var integer
  2299. *
  2300. * DATA TYPE
  2301. * Double precision floating point number and
  2302. * negative numbers.
  2303. *
  2304. */
  2305. const C_DATATYPE_DOUBLE = 3;
  2306. /**
  2307. * @var integer
  2308. *
  2309. * DATA TYPE
  2310. * Standard Text column (like varchar255)
  2311. * At least 8BIT character support.
  2312. *
  2313. */
  2314. const C_DATATYPE_TEXT8 = 4;
  2315. /**
  2316. * @var integer
  2317. *
  2318. * DATA TYPE
  2319. * Long text column (16BIT)
  2320. *
  2321. */
  2322. const C_DATATYPE_TEXT16 = 5;
  2323. /**
  2324. * @var integer
  2325. *
  2326. * DATA TYPE
  2327. * 32BIT long textfield (number of characters can be as high as 32BIT) Data type
  2328. * This is the biggest column that RedBean supports. If possible you may write
  2329. * an implementation that stores even bigger values.
  2330. *
  2331. */
  2332. const C_DATATYPE_TEXT32 = 6;
  2333. /**
  2334. * @var integer
  2335. *
  2336. * DATA TYPE
  2337. * Specified. This means the developer or DBA
  2338. * has altered the column to a different type not
  2339. * recognized by RedBean. This high number makes sure
  2340. * it will not be converted back to another type by accident.
  2341. *
  2342. */
  2343. const C_DATATYPE_SPECIFIED = 99;
  2344. /**
  2345. * @var array
  2346. * Supported Column Types
  2347. */
  2348. public $typeno_sqltype = array(
  2349. RedBean_QueryWriter_MySQL::C_DATATYPE_BOOL=>" SET('1') ",
  2350. RedBean_QueryWriter_MySQL::C_DATATYPE_UINT8=>" TINYINT(3) UNSIGNED ",
  2351. RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32=>" INT(11) UNSIGNED ",
  2352. RedBean_QueryWriter_MySQL::C_DATATYPE_DOUBLE=>" DOUBLE ",
  2353. RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT8=>" VARCHAR(255) ",
  2354. RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT16=>" TEXT ",
  2355. RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT32=>" LONGTEXT "
  2356. );
  2357. /**
  2358. *
  2359. * @var array
  2360. * Supported Column Types and their
  2361. * constants (magic numbers)
  2362. */
  2363. public $sqltype_typeno = array(
  2364. "set('1')"=>RedBean_QueryWriter_MySQL::C_DATATYPE_BOOL,
  2365. "tinyint(3) unsigned"=>RedBean_QueryWriter_MySQL::C_DATATYPE_UINT8,
  2366. "int(11) unsigned"=>RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32,
  2367. "double" => RedBean_QueryWriter_MySQL::C_DATATYPE_DOUBLE,
  2368. "varchar(255)"=>RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT8,
  2369. "text"=>RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT16,
  2370. "longtext"=>RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT32
  2371. );
  2372. /**
  2373. *
  2374. * @var RedBean_Adapter_DBAdapter
  2375. */
  2376. protected $adapter;
  2377. /**
  2378. * @var string
  2379. * character to escape keyword table/column names
  2380. */
  2381. protected $quoteCharacter = '`';
  2382. /**
  2383. * Constructor.
  2384. * The Query Writer Constructor also sets up the database.
  2385. *
  2386. * @param RedBean_Adapter_DBAdapter $adapter adapter
  2387. * @param boolean $frozen allow schema modif.?
  2388. *
  2389. *
  2390. */
  2391. public function __construct( RedBean_Adapter $adapter, $frozen = false ) {
  2392. $this->adapter = $adapter;
  2393. }
  2394. /**
  2395. * Returns all tables in the database.
  2396. *
  2397. * @return array $tables tables
  2398. */
  2399. public function getTables() {
  2400. return $this->adapter->getCol( "show tables" );
  2401. }
  2402. /**
  2403. * Creates an empty, column-less table for a bean.
  2404. *
  2405. * @param string $table table
  2406. */
  2407. public function createTable( $table ) {
  2408. $idfield = $this->getIDfield($table, true);
  2409. $table = $this->safeTable($table);
  2410. $sql = "
  2411. CREATE TABLE $table (
  2412. $idfield INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT ,
  2413. PRIMARY KEY ( $idfield )
  2414. ) ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
  2415. ";
  2416. $this->adapter->exec( $sql );
  2417. }
  2418. /**
  2419. * Returns an array containing the column names of the specified table.
  2420. *
  2421. * @param string $table table
  2422. *
  2423. * @return array $columns columns
  2424. */
  2425. public function getColumns( $table ) {
  2426. $table = $this->safeTable($table);
  2427. $columnsRaw = $this->adapter->get("DESCRIBE $table");
  2428. foreach($columnsRaw as $r) {
  2429. $columns[$r["Field"]]=$r["Type"];
  2430. }
  2431. return $columns;
  2432. }
  2433. /**
  2434. * Returns the MySQL Column Type Code (integer) that corresponds
  2435. * to the given value type.
  2436. *
  2437. * @param string $value value
  2438. *
  2439. * @return integer $type type
  2440. */
  2441. public function scanType( $value ) {
  2442. if (is_null($value)) {
  2443. return RedBean_QueryWriter_MySQL::C_DATATYPE_BOOL;
  2444. }
  2445. $orig = $value;
  2446. $value = strval($value);
  2447. if ($value=="1" || $value=="") {
  2448. return RedBean_QueryWriter_MySQL::C_DATATYPE_BOOL;
  2449. }
  2450. if (is_numeric($value) && (floor($value)==$value) && $value >= 0 && $value <= 255 ) {
  2451. return RedBean_QueryWriter_MySQL::C_DATATYPE_UINT8;
  2452. }
  2453. if (is_numeric($value) && (floor($value)==$value) && $value >= 0 && $value <= 4294967295 ) {
  2454. return RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32;
  2455. }
  2456. if (is_numeric($value)) {
  2457. return RedBean_QueryWriter_MySQL::C_DATATYPE_DOUBLE;
  2458. }
  2459. if (strlen($value) <= 255) {
  2460. return RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT8;
  2461. }
  2462. return RedBean_QueryWriter_MySQL::C_DATATYPE_TEXT16;
  2463. }
  2464. /**
  2465. * Returns the Type Code for a Column Description.
  2466. *
  2467. * @param string $typedescription description
  2468. *
  2469. * @return integer $typecode code
  2470. */
  2471. public function code( $typedescription ) {
  2472. return ((isset($this->sqltype_typeno[$typedescription])) ? $this->sqltype_typeno[$typedescription] : self::C_DATATYPE_SPECIFIED);
  2473. }
  2474. /**
  2475. * Change (Widen) the column to the give type.
  2476. *
  2477. * @param string $table table
  2478. * @param string $column column
  2479. *
  2480. * @param integer $type
  2481. */
  2482. public function widenColumn( $table, $column, $type ) {
  2483. $table = $this->safeTable($table);
  2484. $column = $this->safeColumn($column);
  2485. $newtype = $this->getFieldType($type);
  2486. $changecolumnSQL = "ALTER TABLE $table CHANGE $column $column $newtype ";
  2487. $this->adapter->exec( $changecolumnSQL );
  2488. }
  2489. /**
  2490. * Adds a Unique index constrain to the table.
  2491. *
  2492. * @param string $table table
  2493. * @param string $col1 column
  2494. * @param string $col2 column
  2495. *
  2496. * @return void
  2497. */
  2498. public function addUniqueIndex( $table,$columns ) {
  2499. $table = $this->safeTable($table);
  2500. sort($columns);
  2501. foreach($columns as $k=>$v) {
  2502. $columns[$k]= $this->safeColumn($v);
  2503. }
  2504. $r = $this->adapter->get("SHOW INDEX FROM $table");
  2505. $name = "UQ_".sha1(implode(',',$columns));
  2506. if ($r) {
  2507. foreach($r as $i) {
  2508. if ($i["Key_name"]== $name) {
  2509. return;
  2510. }
  2511. }
  2512. }
  2513. $sql = "ALTER IGNORE TABLE $table
  2514. ADD UNIQUE INDEX $name (".implode(",",$columns).")";
  2515. $this->adapter->exec($sql);
  2516. }
  2517. /**
  2518. * Tests whether a given SQL state is in the list of states.
  2519. *
  2520. * @param string $state code
  2521. * @param array $list array of sql states
  2522. *
  2523. * @return boolean $yesno occurs in list
  2524. */
  2525. public function sqlStateIn($state, $list) {
  2526. $sqlState = "0";
  2527. if ($state == "42S02") $sqlState = RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE;
  2528. if ($state == "42S22") $sqlState = RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN;
  2529. if ($state == "23000") $sqlState = RedBean_QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION;
  2530. return in_array($sqlState, $list);
  2531. }
  2532. }
  2533. /**
  2534. * RedBean SQLiteWriter
  2535. *
  2536. * @file RedBean/QueryWriter/SQLite.php
  2537. * @description Represents a SQLite Database to RedBean
  2538. * To write a driver for a different database for RedBean
  2539. * you should only have to change this file.
  2540. * @author Gabor de Mooij
  2541. * @license BSD
  2542. */
  2543. class RedBean_QueryWriter_SQLite extends RedBean_QueryWriter_AQueryWriter implements RedBean_QueryWriter {
  2544. /**
  2545. *
  2546. * @var RedBean_Adapter_DBAdapter
  2547. * Holds database adapter
  2548. */
  2549. protected $adapter;
  2550. /**
  2551. * @var string
  2552. * character to escape keyword table/column names
  2553. */
  2554. protected $quoteCharacter = '`';
  2555. /**
  2556. * Constructor
  2557. * The Query Writer Constructor also sets up the database
  2558. *
  2559. * @param RedBean_Adapter_DBAdapter $adapter adapter
  2560. */
  2561. public function __construct( RedBean_Adapter $adapter, $frozen = false ) {
  2562. $this->adapter = $adapter;
  2563. }
  2564. /**
  2565. * Returns all tables in the database
  2566. *
  2567. * @return array $tables tables
  2568. */
  2569. public function getTables() {
  2570. return $this->adapter->getCol( "SELECT name FROM sqlite_master
  2571. WHERE type='table' AND name!='sqlite_sequence';" );
  2572. }
  2573. /**
  2574. * Creates an empty, column-less table for a bean.
  2575. *
  2576. * @param string $table table
  2577. */
  2578. public function createTable( $table ) {
  2579. $idfield = $this->getIDfield($table, true);
  2580. $table = $this->safeTable($table);
  2581. $sql = "
  2582. CREATE TABLE $table ( $idfield INTEGER PRIMARY KEY AUTOINCREMENT )
  2583. ";
  2584. $this->adapter->exec( $sql );
  2585. }
  2586. /**
  2587. * Returns an array containing the column names of the specified table.
  2588. *
  2589. * @param string $table table
  2590. *
  2591. * @return array $columns columns
  2592. */
  2593. public function getColumns( $table ) {
  2594. $table = $this->safeTable($table, true);
  2595. $columnsRaw = $this->adapter->get("PRAGMA table_info('$table')");
  2596. $columns = array();
  2597. foreach($columnsRaw as $r) {
  2598. $columns[$r["name"]]=$r["type"];
  2599. }
  2600. return $columns;
  2601. }
  2602. /**
  2603. * Returns the MySQL Column Type Code (integer) that corresponds
  2604. * to the given value type.
  2605. *
  2606. * @param string $value value
  2607. *
  2608. * @return integer $type type
  2609. */
  2610. public function scanType( $value ) {
  2611. return 1;
  2612. }
  2613. /**
  2614. * Returns the Type Code for a Column Description
  2615. *
  2616. * @param string $typedescription type description
  2617. *
  2618. * @return integer $typecode type code
  2619. */
  2620. public function code( $typedescription ) {
  2621. return 1;
  2622. }
  2623. /**
  2624. * Change (Widen) the column to the give type.
  2625. *
  2626. * @param string $table table
  2627. * @param string $column column
  2628. *
  2629. * @param integer $type type
  2630. */
  2631. public function widenColumn( $table, $column, $type ) {
  2632. return true;
  2633. }
  2634. /**
  2635. * Adds a Unique index constrain to the table.
  2636. *
  2637. * @param string $table table
  2638. * @param string $column1 first column
  2639. * @param string $column2 second column
  2640. *
  2641. * @return void
  2642. */
  2643. public function addUniqueIndex( $table,$columns ) {
  2644. $table = $this->safeTable($table);
  2645. $name = "UQ_".sha1(implode(',',$columns));
  2646. $sql = "CREATE UNIQUE INDEX IF NOT EXISTS $name ON $table (".implode(",",$columns).")";
  2647. $this->adapter->exec($sql);
  2648. }
  2649. /**
  2650. * Given an Database Specific SQLState and a list of QueryWriter
  2651. * Standard SQL States this function converts the raw SQL state to a
  2652. * database agnostic ANSI-92 SQL states and checks if the given state
  2653. * is in the list of agnostic states.
  2654. *
  2655. * @param string $state state
  2656. * @param array $list list of states
  2657. *
  2658. * @return boolean $isInArray whether state is in list
  2659. */
  2660. public function sqlStateIn($state, $list) {
  2661. $sqlState = "0";
  2662. if ($state == "HY000") $sqlState = RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE;
  2663. if ($state == "23000") $sqlState = RedBean_QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION;
  2664. return in_array($sqlState, $list);
  2665. }
  2666. /**
  2667. * Counts rows in a table.
  2668. * Uses SQLite optimization for deleting all records (i.e. no WHERE)
  2669. *
  2670. * @param string $beanType
  2671. *
  2672. * @return integer $numRowsFound
  2673. */
  2674. public function wipe($type) {
  2675. $table = $this->safeTable($type);
  2676. $this->adapter->exec("DELETE FROM $table");
  2677. }
  2678. }
  2679. class RedBean_QueryWriter_SQLiteT extends RedBean_QueryWriter_SQLite {
  2680. /**
  2681. * Here we describe the datatypes that RedBean
  2682. * Uses internally. If you write a QueryWriter for
  2683. * RedBean you should provide a list of types like this.
  2684. */
  2685. /**
  2686. * DATA TYPE
  2687. * Integer Data type
  2688. * @var integer
  2689. */
  2690. const C_DATATYPE_INTEGER = 0;
  2691. /**
  2692. * DATA TYPE
  2693. * Numeric Data type (for REAL and date/time)
  2694. * @var integer
  2695. */
  2696. const C_DATATYPE_NUMERIC = 1;
  2697. /**
  2698. * DATA TYPE
  2699. * Text type
  2700. * @var integer
  2701. */
  2702. const C_DATATYPE_TEXT = 2;
  2703. /**
  2704. * DATA TYPE
  2705. * Specified. This means the developer or DBA
  2706. * has altered the column to a different type not
  2707. * recognized by RedBean. This high number makes sure
  2708. * it will not be converted back to another type by accident.
  2709. * @var integer
  2710. */
  2711. const C_DATATYPE_SPECIFIED = 99;
  2712. /**
  2713. * @var array
  2714. * Supported Column Types
  2715. */
  2716. public $typeno_sqltype = array(
  2717. RedBean_QueryWriter_SQLiteT::C_DATATYPE_INTEGER=>"INTEGER",
  2718. RedBean_QueryWriter_SQLiteT::C_DATATYPE_NUMERIC=>"NUMERIC",
  2719. RedBean_QueryWriter_SQLiteT::C_DATATYPE_TEXT=>"TEXT",
  2720. );
  2721. /**
  2722. *
  2723. * @var array
  2724. * Supported Column Types and their
  2725. * constants (magic numbers)
  2726. */
  2727. public $sqltype_typeno = array(
  2728. "INTEGER"=>RedBean_QueryWriter_SQLiteT::C_DATATYPE_INTEGER,
  2729. "NUMERIC"=>RedBean_QueryWriter_SQLiteT::C_DATATYPE_NUMERIC,
  2730. "TEXT"=>RedBean_QueryWriter_SQLiteT::C_DATATYPE_TEXT,
  2731. );
  2732. /**
  2733. * Returns the MySQL Column Type Code (integer) that corresponds
  2734. * to the given value type.
  2735. *
  2736. * @param string $value value
  2737. *
  2738. * @return integer $type type
  2739. */
  2740. public function scanType( $value ) {
  2741. if (is_numeric($value) && (intval($value)==$value) && $value<2147483648) return self::C_DATATYPE_INTEGER;
  2742. if ((is_numeric($value) && $value < 2147483648)
  2743. || preg_match("/\d\d\d\d\-\d\d\-\d\d/",$value)
  2744. || preg_match("/\d\d\d\d\-\d\d\-\d\d\s\d\d:\d\d:\d\d/",$value)
  2745. ) {
  2746. return self::C_DATATYPE_NUMERIC;
  2747. }
  2748. return self::C_DATATYPE_TEXT;
  2749. }
  2750. /**
  2751. * Adds a column of a given type to a table
  2752. *
  2753. * @param string $table table
  2754. * @param string $column column
  2755. * @param integer $type type
  2756. */
  2757. public function addColumn( $table, $column, $type) {
  2758. $table = $this->getFormattedTableName($table);
  2759. $column = $this->check($column);
  2760. $table = $this->check($table);
  2761. $type=$this->typeno_sqltype[$type];
  2762. $sql = "ALTER TABLE `$table` ADD `$column` $type ";
  2763. $this->adapter->exec( $sql );
  2764. }
  2765. /**
  2766. * Returns the Type Code for a Column Description
  2767. *
  2768. * @param string $typedescription description
  2769. *
  2770. * @return integer $typecode code
  2771. */
  2772. public function code( $typedescription ) {
  2773. return ((isset($this->sqltype_typeno[$typedescription])) ? $this->sqltype_typeno[$typedescription] : 99);
  2774. }
  2775. /**
  2776. * Quote Items, to prevent issues with reserved words.
  2777. *
  2778. * @param array $items items to quote
  2779. *
  2780. * @return $quotedfItems quoted items
  2781. */
  2782. private function quote( $items ) {
  2783. foreach($items as $k=>$item) {
  2784. $items[$k]=$this->noKW($item);
  2785. }
  2786. return $items;
  2787. }
  2788. /**
  2789. * Change (Widen) the column to the give type.
  2790. *
  2791. * @param string $table table to widen
  2792. * @param string $column column to widen
  2793. * @param integer $type new column type
  2794. */
  2795. public function widenColumn( $table, $column, $type ) {
  2796. $table = $this->getFormattedTableName($table);
  2797. $idfield = $this->idfield;
  2798. $column = $this->check($column);
  2799. $table = $this->check($table);
  2800. $newtype = $this->typeno_sqltype[$type];
  2801. $oldColumns = $this->getColumns($table);
  2802. $oldColumnNames = $this->quote(array_keys($oldColumns));
  2803. $newTableDefStr="";
  2804. foreach($oldColumns as $oldName=>$oldType) {
  2805. if ($oldName != $idfield) {
  2806. if ($oldName!=$column) {
  2807. $newTableDefStr .= ",`$oldName` $oldType";
  2808. }
  2809. else {
  2810. $newTableDefStr .= ",`$oldName` $newtype";
  2811. }
  2812. }
  2813. }
  2814. $q = array();
  2815. $q[] = "DROP TABLE IF EXISTS tmp_backup;";
  2816. $q[] = "CREATE TEMPORARY TABLE tmp_backup(".implode(",",$oldColumnNames).");";
  2817. $q[] = "INSERT INTO tmp_backup SELECT * FROM `$table`;";
  2818. $q[] = "DROP TABLE `$table`;";
  2819. $q[] = "CREATE TABLE `$table` ( `$idfield` INTEGER PRIMARY KEY AUTOINCREMENT $newTableDefStr );";
  2820. $q[] = "INSERT INTO `$table` SELECT * FROM tmp_backup;";
  2821. $q[] = "DROP TABLE tmp_backup;";
  2822. foreach($q as $sq) {
  2823. $this->adapter->exec($sq);
  2824. }
  2825. }
  2826. }
  2827. /**
  2828. * RedBean PostgreSQL Query Writer
  2829. * @file RedBean/QueryWriter/PostgreSQL.php
  2830. * @description QueryWriter for the PostgreSQL database system.
  2831. *
  2832. * @author Gabor de Mooij
  2833. * @license BSD
  2834. *
  2835. *
  2836. * (c) G.J.G.T. (Gabor) de Mooij
  2837. * This source file is subject to the BSD/GPLv2 License that is bundled
  2838. * with this source code in the file license.txt.
  2839. */
  2840. class RedBean_QueryWriter_PostgreSQL extends RedBean_QueryWriter_AQueryWriter implements RedBean_QueryWriter {
  2841. /**
  2842. * DATA TYPE
  2843. * Integer Data Type
  2844. * @var integer
  2845. */
  2846. const C_DATATYPE_INTEGER = 0;
  2847. /**
  2848. * DATA TYPE
  2849. * Double Precision Type
  2850. * @var integer
  2851. */
  2852. const C_DATATYPE_DOUBLE = 1;
  2853. /**
  2854. * DATA TYPE
  2855. * String Data Type
  2856. * @var integer
  2857. */
  2858. const C_DATATYPE_TEXT = 3;
  2859. /**
  2860. * @var array
  2861. * Supported Column Types
  2862. */
  2863. public $typeno_sqltype = array(
  2864. self::C_DATATYPE_INTEGER=>" integer ",
  2865. self::C_DATATYPE_DOUBLE=>" double precision ",
  2866. self::C_DATATYPE_TEXT=>" text "
  2867. );
  2868. /**
  2869. *
  2870. * @var array
  2871. * Supported Column Types and their
  2872. * constants (magic numbers)
  2873. */
  2874. public $sqltype_typeno = array(
  2875. "integer"=>self::C_DATATYPE_INTEGER,
  2876. "double precision" => self::C_DATATYPE_DOUBLE,
  2877. "text"=>self::C_DATATYPE_TEXT
  2878. );
  2879. /**
  2880. *
  2881. * @var RedBean_DBAdapter
  2882. * Holds Database Adapter
  2883. */
  2884. protected $adapter;
  2885. /**
  2886. * @var string
  2887. * character to escape keyword table/column names
  2888. */
  2889. protected $quoteCharacter = '"';
  2890. /**
  2891. *
  2892. * @var string
  2893. * Default Value
  2894. */
  2895. protected $defaultValue = 'DEFAULT';
  2896. /**
  2897. * Returns the insert suffix SQL Snippet
  2898. *
  2899. * @param string $table table
  2900. *
  2901. * @return string $sql SQL Snippet
  2902. */
  2903. protected function getInsertSuffix($table) {
  2904. return "RETURNING ".$this->getIDField($table);
  2905. }
  2906. /**
  2907. * Constructor
  2908. * The Query Writer Constructor also sets up the database
  2909. *
  2910. * @param RedBean_DBAdapter $adapter adapter
  2911. */
  2912. public function __construct( RedBean_Adapter_DBAdapter $adapter ) {
  2913. $this->adapter = $adapter;
  2914. }
  2915. /**
  2916. * Returns all tables in the database
  2917. *
  2918. * @return array $tables tables
  2919. */
  2920. public function getTables() {
  2921. return $this->adapter->getCol( "select table_name from information_schema.tables
  2922. where table_schema = 'public'" );
  2923. }
  2924. /**
  2925. * Creates an empty, column-less table for a bean.
  2926. *
  2927. * @param string $table table to create
  2928. */
  2929. public function createTable( $table ) {
  2930. $idfield = $this->getIDfield($table);
  2931. $table = $this->safeTable($table);
  2932. $sql = " CREATE TABLE $table ($idfield SERIAL PRIMARY KEY); ";
  2933. $this->adapter->exec( $sql );
  2934. }
  2935. /**
  2936. * Returns an array containing the column names of the specified table.
  2937. *
  2938. * @param string $table table to get columns from
  2939. *
  2940. * @return array $columns array filled with column (name=>type)
  2941. */
  2942. public function getColumns( $table ) {
  2943. $table = $this->safeTable($table, true);
  2944. $columnsRaw = $this->adapter->get("select column_name, data_type from information_schema.columns where table_name='$table'");
  2945. foreach($columnsRaw as $r) {
  2946. $columns[$r["column_name"]]=$r["data_type"];
  2947. }
  2948. return $columns;
  2949. }
  2950. /**
  2951. * Returns the pgSQL Column Type Code (integer) that corresponds
  2952. * to the given value type.
  2953. *
  2954. * @param string $value value to determine type of
  2955. *
  2956. * @return integer $type type code for this value
  2957. */
  2958. public function scanType( $value ) {
  2959. if (is_numeric($value)
  2960. && floor($value)==$value
  2961. && $value < 2147483648
  2962. && $value > -2147483648) {
  2963. return self::C_DATATYPE_INTEGER;
  2964. }
  2965. elseif(is_numeric($value)) {
  2966. return self::C_DATATYPE_DOUBLE;
  2967. }
  2968. else {
  2969. return self::C_DATATYPE_TEXT;
  2970. }
  2971. }
  2972. /**
  2973. * Returns the Type Code for a Column Description
  2974. *
  2975. * @param string $typedescription type description to get code for
  2976. *
  2977. * @return integer $typecode type code
  2978. */
  2979. public function code( $typedescription ) {
  2980. return ((isset($this->sqltype_typeno[$typedescription])) ? $this->sqltype_typeno[$typedescription] : 99);
  2981. }
  2982. /**
  2983. * Change (Widen) the column to the give type.
  2984. *
  2985. * @param string $table table to widen
  2986. * @param string $column column to widen
  2987. * @param integer $type new column type
  2988. */
  2989. public function widenColumn( $table, $column, $type ) {
  2990. $table = $this->safeTable($table);
  2991. $column = $this->safeColumn($column);
  2992. $newtype = $this->typeno_sqltype[$type];
  2993. $changecolumnSQL = "ALTER TABLE $table \n\t ALTER COLUMN $column TYPE $newtype ";
  2994. try {
  2995. $this->adapter->exec( $changecolumnSQL );
  2996. }catch(Exception $e) {
  2997. die($e->getMessage());
  2998. }
  2999. }
  3000. /**
  3001. * Gets information about changed records using a type and id and a logid.
  3002. * RedBean Locking shields you from race conditions by comparing the latest
  3003. * cached insert id with a the highest insert id associated with a write action
  3004. * on the same table. If there is any id between these two the record has
  3005. * been changed and RedBean will throw an exception. This function checks for changes.
  3006. * If changes have occurred it will throw an exception. If no changes have occurred
  3007. * it will insert a new change record and return the new change id.
  3008. * This method locks the log table exclusively.
  3009. *
  3010. * @param string $type type
  3011. * @param integer $id id
  3012. * @param integer $logid log id
  3013. *
  3014. * @return integer $newchangeid new change id
  3015. */
  3016. public function checkChanges($type, $id, $logid) {
  3017. $table = $this->safeTable($type);
  3018. $idfield = $this->getIDfield($type);
  3019. $id = (int) $id;
  3020. $logid = (int) $logid;
  3021. $num = $this->adapter->getCell("
  3022. SELECT count(*) FROM __log WHERE tbl=$table AND itemid=$id AND action=2 AND $idfield > $logid");
  3023. if ($num) {
  3024. throw new RedBean_Exception_FailedAccessBean("Locked, failed to access (type:$type, id:$id)");
  3025. }
  3026. $newid = $this->insertRecord("__log",array("action","tbl","itemid"),
  3027. array(array(2, $type, $id)));
  3028. if ($this->adapter->getCell("select id from __log where tbl=:tbl AND id < $newid and id > $logid and action=2 and itemid=$id ",
  3029. array(":tbl"=>$type))) {
  3030. throw new RedBean_Exception_FailedAccessBean("Locked, failed to access II (type:$type, id:$id)");
  3031. }
  3032. return $newid;
  3033. }
  3034. /**
  3035. * Adds a Unique index constrain to the table.
  3036. *
  3037. * @param string $table table to add index to
  3038. * @param string $col1 column to be part of index
  3039. * @param string $col2 column 2 to be part of index
  3040. *
  3041. * @return void
  3042. */
  3043. public function addUniqueIndex( $table,$columns ) {
  3044. $table = $this->safeTable($table, true);
  3045. sort($columns);
  3046. foreach($columns as $k=>$v) {
  3047. $columns[$k]=$this->safeColumn($v);
  3048. }
  3049. $r = $this->adapter->get("SELECT
  3050. i.relname as index_name
  3051. FROM
  3052. pg_class t,
  3053. pg_class i,
  3054. pg_index ix,
  3055. pg_attribute a
  3056. WHERE
  3057. t.oid = ix.indrelid
  3058. AND i.oid = ix.indexrelid
  3059. AND a.attrelid = t.oid
  3060. AND a.attnum = ANY(ix.indkey)
  3061. AND t.relkind = 'r'
  3062. AND t.relname = '$table'
  3063. ORDER BY t.relname, i.relname;");
  3064. /*
  3065. *
  3066. * ALTER TABLE testje ADD CONSTRAINT blabla UNIQUE (blaa, blaa2);
  3067. */
  3068. $name = "UQ_".sha1($table.implode(',',$columns));
  3069. if ($r) {
  3070. foreach($r as $i) {
  3071. if (strtolower( $i["index_name"] )== strtolower( $name )) {
  3072. return;
  3073. }
  3074. }
  3075. }
  3076. $sql = "ALTER TABLE \"$table\"
  3077. ADD CONSTRAINT $name UNIQUE (".implode(",",$columns).")";
  3078. $this->adapter->exec($sql);
  3079. }
  3080. /**
  3081. * Given an Database Specific SQLState and a list of QueryWriter
  3082. * Standard SQL States this function converts the raw SQL state to a
  3083. * database agnostic ANSI-92 SQL states and checks if the given state
  3084. * is in the list of agnostic states.
  3085. *
  3086. * @param string $state state
  3087. * @param array $list list of states
  3088. *
  3089. * @return boolean $isInArray whether state is in list
  3090. */
  3091. public function sqlStateIn($state, $list) {
  3092. $sqlState = "0";
  3093. if ($state == "42P01") $sqlState = RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE;
  3094. if ($state == "42703") $sqlState = RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN;
  3095. return in_array($sqlState, $list);
  3096. }
  3097. /**
  3098. * Returns a snippet of SQL to filter records using SQL and a list of
  3099. * keys.
  3100. *
  3101. * @param string $idfield ID Field to use for selecting primary key
  3102. * @param array $keys List of keys to use for filtering
  3103. * @param string $sql SQL to append, if any
  3104. * @param boolean $inverse Whether you want to inverse the selection
  3105. *
  3106. * @return string $snippet SQL Snippet crafted by function
  3107. */
  3108. public function getSQLSnippetFilter( $idfield, $keys, $sql=null, $inverse=false ) {
  3109. if (!$sql) $sql=" TRUE ";
  3110. if (!$inverse && count($keys)===0) return " TRUE ";
  3111. $idfield = $this->noKW($idfield);
  3112. $sqlInverse = ($inverse) ? "NOT" : "";
  3113. $sqlKeyFilter = ($keys) ? " $idfield $sqlInverse IN (".implode(",",$keys).") AND " : " ";
  3114. $sqlSnippet = $sqlKeyFilter . $sql;
  3115. return $sqlSnippet;
  3116. }
  3117. public function createIndexIfNotExist($table, $indexName, $indexColumns, $drop=true) {
  3118. $indexName = $this->adapter->escape($indexName);
  3119. $sql = "select
  3120. t.relname as table_name,
  3121. i.relname as index_name,
  3122. a.attname as column_name
  3123. from
  3124. pg_class t,
  3125. pg_class i,
  3126. pg_index ix,
  3127. pg_attribute a
  3128. where
  3129. t.oid = ix.indrelid
  3130. and i.oid = ix.indexrelid
  3131. and a.attrelid = t.oid
  3132. and a.attnum = ANY(ix.indkey)
  3133. and t.relkind = 'r'
  3134. and t.relname = ?
  3135. order by
  3136. t.relname,
  3137. i.relname;";
  3138. $indexes = $this->adapter->get($sql,array($table));
  3139. print_r($indexes);
  3140. foreach($indexes as $index) {
  3141. if ($index["index_name"]===$indexName) {
  3142. if (!$drop) return false;
  3143. $sql = "DROP INDEX $indexName ";
  3144. $this->adapter->exec($sql);
  3145. break;
  3146. }
  3147. }
  3148. foreach($indexColumns as $key=>$indexColumn) {
  3149. $indexColumns[$key] = $this->safeColumn($indexColumn);
  3150. }
  3151. $columnStr = implode(",", $indexColumns);
  3152. $indexName = $this->safeTable($indexName);
  3153. $sql = "CREATE INDEX $indexName ON ".$this->safeTable($table)." ($columnStr) ";
  3154. $this->adapter->exec($sql);
  3155. return true;
  3156. }
  3157. }
  3158. /**
  3159. * RedBean Exception Base
  3160. *
  3161. * @file RedBean/Exception.php
  3162. * @description Represents the base class
  3163. * for RedBean Exceptions
  3164. * @author Gabor de Mooij
  3165. * @license BSD
  3166. *
  3167. *
  3168. * (c) G.J.G.T. (Gabor) de Mooij
  3169. * This source file is subject to the BSD/GPLv2 License that is bundled
  3170. * with this source code in the file license.txt.
  3171. */
  3172. class RedBean_Exception extends Exception {
  3173. }
  3174. /**
  3175. * RedBean Exception SQL
  3176. *
  3177. * @file RedBean/Exception/SQL.php
  3178. * @description Represents a generic database exception independent of the
  3179. * underlying driver.
  3180. * @author Gabor de Mooij
  3181. * @license BSD
  3182. *
  3183. *
  3184. * (c) G.J.G.T. (Gabor) de Mooij
  3185. * This source file is subject to the BSD/GPLv2 License that is bundled
  3186. * with this source code in the file license.txt.
  3187. */
  3188. class RedBean_Exception_SQL extends Exception {
  3189. /**
  3190. * @var string
  3191. * Holds the current SQL Strate code.
  3192. */
  3193. private $sqlState;
  3194. /**
  3195. * Returns an ANSI-92 compliant SQL state.
  3196. *
  3197. * @return string $state ANSI state code
  3198. */
  3199. public function getSQLState() {
  3200. return $this->sqlState;
  3201. }
  3202. /**
  3203. * @todo parse state to verify valid ANSI92!
  3204. * Stores ANSI-92 compliant SQL state.
  3205. *
  3206. * @param string $sqlState code
  3207. */
  3208. public function setSQLState( $sqlState ) {
  3209. $this->sqlState = $sqlState;
  3210. }
  3211. /**
  3212. * To String prints both code and SQL state.
  3213. *
  3214. * @return string $message prints this exception instance as a string
  3215. */
  3216. public function __toString() {
  3217. return "[".$this->getSQLState()."] - ".$this->getMessage();
  3218. }
  3219. }
  3220. /**
  3221. * Exception Security.
  3222. * Part of the RedBean Exceptions Mechanism.
  3223. *
  3224. * @file RedBean/Exception
  3225. * @description Represents a subtype in the RedBean Exception System.
  3226. * @author Gabor de Mooij
  3227. * @license BSD
  3228. *
  3229. *
  3230. * (c) G.J.G.T. (Gabor) de Mooij
  3231. * This source file is subject to the BSD/GPLv2 License that is bundled
  3232. * with this source code in the file license.txt.
  3233. */
  3234. class RedBean_Exception_Security extends RedBean_Exception {
  3235. }
  3236. /**
  3237. * Exception Failed Access
  3238. * Part of the RedBean Exceptions Mechanism
  3239. *
  3240. * @file RedBean/Exception
  3241. * @description Represents a subtype in the RedBean Exception System
  3242. * @author Gabor de Mooij
  3243. * @license BSD
  3244. *
  3245. *
  3246. * (c) G.J.G.T. (Gabor) de Mooij
  3247. * This source file is subject to the BSD/GPLv2 License that is bundled
  3248. * with this source code in the file license.txt.
  3249. */
  3250. class RedBean_Exception_FailedAccessBean extends Exception {
  3251. }
  3252. /**
  3253. * Exception NotImplemented.
  3254. * Part of the RedBean Exceptions Mechanism.
  3255. *
  3256. * @file RedBean/Exception/NotImplemented
  3257. * @description Represents a subtype in the RedBean Exception System.
  3258. * This Exception indicates a certain feature has not been
  3259. * implemented yet and should be handled on Application level.
  3260. * @author Gabor de Mooij
  3261. * @license BSD
  3262. *
  3263. *
  3264. * (c) G.J.G.T. (Gabor) de Mooij
  3265. * This source file is subject to the BSD/GPLv2 License that is bundled
  3266. * with this source code in the file license.txt.
  3267. */
  3268. class RedBean_Exception_NotImplemented extends RedBean_Exception {
  3269. }
  3270. /**
  3271. * Exception Unsupported Database
  3272. * Part of the RedBean Exceptions Mechanism
  3273. *
  3274. * @file RedBean/Exception
  3275. * @description Represents a subtype in the RedBean Exception System
  3276. * @author Gabor de Mooij
  3277. * @license BSD
  3278. *
  3279. *
  3280. * (c) G.J.G.T. (Gabor) de Mooij
  3281. * This source file is subject to the BSD/GPLv2 License that is bundled
  3282. * with this source code in the file license.txt.
  3283. */
  3284. class RedBean_Exception_UnsupportedDatabase extends RedBean_Exception {
  3285. }
  3286. /**
  3287. * @name RedBean OODB
  3288. * @file RedBean
  3289. * @author Gabor de Mooij and the RedBean Team
  3290. * @copyright Gabor de Mooij (c)
  3291. * @license BSD
  3292. *
  3293. * The RedBean OODB Class is the main class of RedBean.
  3294. * It takes RedBean_OODBBean objects and stores them to and loads them from the
  3295. * database as well as providing other CRUD functions. This class acts as a
  3296. * object database.
  3297. *
  3298. *
  3299. * (c) G.J.G.T. (Gabor) de Mooij
  3300. * This source file is subject to the BSD/GPLv2 License that is bundled
  3301. * with this source code in the file license.txt.
  3302. */
  3303. class RedBean_OODB extends RedBean_Observable implements RedBean_ObjectDatabase {
  3304. /**
  3305. *
  3306. * @var array
  3307. */
  3308. private $stash = NULL;
  3309. /**
  3310. *
  3311. * @var RedBean_Adapter_DBAdapter
  3312. */
  3313. private $writer;
  3314. /**
  3315. *
  3316. * @var boolean
  3317. */
  3318. private $isFrozen = false;
  3319. /**
  3320. * The RedBean OODB Class is the main class of RedBean.
  3321. * It takes RedBean_OODBBean objects and stores them to and loads them from the
  3322. * database as well as providing other CRUD functions. This class acts as a
  3323. * object database.
  3324. * Constructor, requires a DBAadapter (dependency inversion)
  3325. * @param RedBean_Adapter_DBAdapter $adapter
  3326. */
  3327. public function __construct( RedBean_QueryWriter $writer ) {
  3328. $this->writer = $writer;
  3329. }
  3330. /**
  3331. * Toggles fluid or frozen mode. In fluid mode the database
  3332. * structure is adjusted to accomodate your objects. In frozen mode
  3333. * this is not the case.
  3334. * @param boolean $trueFalse
  3335. */
  3336. public function freeze( $tf ) {
  3337. $this->isFrozen = (bool) $tf;
  3338. }
  3339. /**
  3340. * Returns the current mode of operation of RedBean.
  3341. * In fluid mode the database
  3342. * structure is adjusted to accomodate your objects.
  3343. * In frozen mode
  3344. * this is not the case.
  3345. * @return <type>
  3346. */
  3347. public function isFrozen() {
  3348. return (bool) $this->isFrozen;
  3349. }
  3350. /**
  3351. * Dispenses a new bean (a RedBean_OODBBean Bean Object)
  3352. * of the specified type. Always
  3353. * use this function to get an empty bean object. Never
  3354. * instantiate a RedBean_OODBBean yourself because it needs
  3355. * to be configured before you can use it with RedBean. This
  3356. * function applies the appropriate initialization /
  3357. * configuration for you.
  3358. * @param string $type
  3359. * @return RedBean_OODBBean $bean
  3360. */
  3361. public function dispense($type ) {
  3362. $this->signal( "before_dispense", $type );
  3363. $bean = new RedBean_OODBBean();
  3364. $bean->setMeta("type", $type );
  3365. $idfield = $this->writer->getIDField($bean->getMeta("type"));
  3366. $bean->setMeta("sys.idfield",$idfield);
  3367. $bean->$idfield = 0;
  3368. if (!$this->isFrozen) $this->check( $bean );
  3369. $bean->setMeta("tainted",false);
  3370. $this->signal( "dispense", $bean );
  3371. return $bean;
  3372. }
  3373. /**
  3374. * Checks whether a RedBean_OODBBean bean is valid.
  3375. * If the type is not valid or the ID is not valid it will
  3376. * throw an exception: RedBean_Exception_Security.
  3377. * @throws RedBean_Exception_Security $exception
  3378. * @param RedBean_OODBBean $bean
  3379. */
  3380. public function check( RedBean_OODBBean $bean ) {
  3381. $idfield = $this->writer->getIDField($bean->getMeta("type"));
  3382. if (!isset($bean->$idfield) ) {
  3383. throw new RedBean_Exception_Security("Bean has incomplete Meta Information $idfield ");
  3384. }
  3385. if (!($bean->getMeta("type"))) {
  3386. throw new RedBean_Exception_Security("Bean has incomplete Meta Information II");
  3387. }
  3388. $pattern = '/[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]/';
  3389. if (preg_match($pattern,$bean->getMeta("type"))) {
  3390. throw new RedBean_Exception_Security("Bean Type is invalid");
  3391. }
  3392. foreach($bean as $prop=>$value) {
  3393. if (
  3394. is_array($value) ||
  3395. is_object($value) ||
  3396. strlen($prop)<1 ||
  3397. preg_match($pattern,$prop)
  3398. ) {
  3399. throw new RedBean_Exception_Security("Invalid Bean: property $prop ");
  3400. }
  3401. }
  3402. }
  3403. /**
  3404. * Checks whether the specified table already exists in the database.
  3405. * Not part of the Object Database interface!
  3406. * @param string $table
  3407. * @return boolean $exists
  3408. */
  3409. public function tableExists($table) {
  3410. $tables = $this->writer->getTables();
  3411. return in_array($this->writer->getFormattedTableName($table), $tables);
  3412. }
  3413. /**
  3414. * Stores a bean in the database. This function takes a
  3415. * RedBean_OODBBean Bean Object $bean and stores it
  3416. * in the database. If the database schema is not compatible
  3417. * with this bean and RedBean runs in fluid mode the schema
  3418. * will be altered to store the bean correctly.
  3419. * If the database schema is not compatible with this bean and
  3420. * RedBean runs in frozen mode it will throw an exception.
  3421. * This function returns the primary key ID of the inserted
  3422. * bean.
  3423. * @throws RedBean_Exception_Security $exception
  3424. * @param RedBean_OODBBean $bean
  3425. * @return integer $newid
  3426. */
  3427. public function store( RedBean_OODBBean $bean ) {
  3428. $this->signal( "update", $bean );
  3429. if (!$this->isFrozen) $this->check($bean);
  3430. $table = $bean->getMeta("type");
  3431. $idfield = $this->writer->getIDField($table);
  3432. if (!$this->isFrozen && !$this->tableExists($table)) {
  3433. $this->writer->createTable( $table );
  3434. }
  3435. if (!$this->isFrozen) {
  3436. $columns = $this->writer->getColumns($table) ;
  3437. }
  3438. $insertvalues = array();
  3439. $insertcolumns = array();
  3440. $updatevalues = array();
  3441. foreach( $bean as $p=>$v ) {
  3442. if ($p!=$idfield) {
  3443. if (!$this->isFrozen) {
  3444. if ($bean->getMeta("cast.$p",-1)!==-1) {
  3445. $cast = $bean->getMeta("cast.$p");
  3446. if ($cast=="string") {
  3447. $typeno = $this->writer->scanType("STRING");
  3448. }
  3449. else {
  3450. throw new RedBean_Exception("Invalid Cast");
  3451. }
  3452. }
  3453. else {
  3454. $typeno = $this->writer->scanType($v);
  3455. }
  3456. if (isset($columns[$p])) {
  3457. $sqlt = $this->writer->code($columns[$p]);
  3458. if ($typeno > $sqlt) {
  3459. $this->writer->widenColumn( $table, $p, $typeno );
  3460. }
  3461. }
  3462. else {
  3463. $this->writer->addColumn($table, $p, $typeno);
  3464. }
  3465. }
  3466. $insertvalues[] = $v;
  3467. $insertcolumns[] = $p;
  3468. $updatevalues[] = array( "property"=>$p, "value"=>$v );
  3469. }
  3470. }
  3471. if (!$this->isFrozen && ($uniques = $bean->getMeta("buildcommand.unique"))) {
  3472. foreach($uniques as $unique) {
  3473. $this->writer->addUniqueIndex( $table, $unique );
  3474. }
  3475. }
  3476. if ($bean->$idfield) {
  3477. if (count($updatevalues)>0) {
  3478. $this->writer->updateRecord( $table, $updatevalues, $bean->$idfield );
  3479. }
  3480. $bean->setMeta("tainted",false);
  3481. $this->signal( "after_update", $bean );
  3482. return (int) $bean->$idfield;
  3483. }
  3484. else {
  3485. $id = $this->writer->insertRecord( $table, $insertcolumns, array($insertvalues) );
  3486. $bean->$idfield = $id;
  3487. $bean->setMeta("tainted",false);
  3488. $this->signal( "after_update", $bean );
  3489. return (int) $id;
  3490. }
  3491. }
  3492. /**
  3493. * Loads a bean from the object database.
  3494. * It searches for a RedBean_OODBBean Bean Object in the
  3495. * database. It does not matter how this bean has been stored.
  3496. * RedBean uses the primary key ID $id and the string $type
  3497. * to find the bean. The $type specifies what kind of bean your
  3498. * are looking for; this is the same type as used with the
  3499. * dispense() function. If RedBean finds the bean it will return
  3500. * the RedBean_OODB Bean object; if it cannot find the bean
  3501. * RedBean will return a new bean of type $type and with
  3502. * primary key ID 0. In the latter case it acts basically the
  3503. * same as dispense().
  3504. * If the bean cannot be found in the database a new bean of
  3505. * the specified type will be generated and returned.
  3506. * @param string $type
  3507. * @param integer $id
  3508. * @return RedBean_OODBBean $bean
  3509. */
  3510. public function load($type, $id) {
  3511. $this->signal("before_open",array("type"=>$type,"id"=>$id));
  3512. $tmpid = intval( $id );
  3513. if ($tmpid < 0) throw new RedBean_Exception_Security("Id less than zero not allowed");
  3514. $bean = $this->dispense( $type );
  3515. if ($this->stash && isset($this->stash[$id])) {
  3516. $row = $this->stash[$id];
  3517. }
  3518. else {
  3519. try {
  3520. $rows = $this->writer->selectRecord($type,array($id));
  3521. }catch(RedBean_Exception_SQL $e ) {
  3522. if (
  3523. $this->writer->sqlStateIn($e->getSQLState(),
  3524. array(
  3525. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  3526. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  3527. )
  3528. ) {
  3529. $rows = 0;
  3530. if ($this->isFrozen) throw $e;
  3531. }
  3532. else throw $e;
  3533. }
  3534. if (!$rows) return $this->dispense($type);
  3535. $row = array_pop($rows);
  3536. }
  3537. foreach($row as $p=>$v) {
  3538. $bean->$p = $v;
  3539. }
  3540. $this->signal( "open", $bean );
  3541. $bean->setMeta("tainted",false);
  3542. return $bean;
  3543. }
  3544. /**
  3545. * Removes a bean from the database.
  3546. * This function will remove the specified RedBean_OODBBean
  3547. * Bean Object from the database.
  3548. * @throws RedBean_Exception_Security $exception
  3549. * @param RedBean_OODBBean $bean
  3550. */
  3551. public function trash( RedBean_OODBBean $bean ) {
  3552. $idfield = $this->writer->getIDField($bean->getMeta("type"));
  3553. $this->signal( "delete", $bean );
  3554. if (!$this->isFrozen) $this->check( $bean );
  3555. try {
  3556. $this->writer->deleteRecord( $bean->getMeta("type"), $bean->$idfield );
  3557. }catch(RedBean_Exception_SQL $e) {
  3558. if (!$this->writer->sqlStateIn($e->getSQLState(),
  3559. array(
  3560. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  3561. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  3562. )) throw $e;
  3563. }
  3564. $this->signal( "after_delete", $bean );
  3565. }
  3566. /**
  3567. * Loads and returns a series of beans of type $type.
  3568. * The beans are loaded all at once.
  3569. * The beans are retrieved using their primary key IDs
  3570. * specified in the second argument.
  3571. * @throws RedBean_Exception_Security $exception
  3572. * @param string $type
  3573. * @param array $ids
  3574. * @return array $beans
  3575. */
  3576. public function batch( $type, $ids ) {
  3577. if (!$ids) return array();
  3578. $collection = array();
  3579. try {
  3580. $rows = $this->writer->selectRecord($type,$ids);
  3581. }catch(RedBean_Exception_SQL $e) {
  3582. if (!$this->writer->sqlStateIn($e->getSQLState(),
  3583. array(
  3584. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  3585. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  3586. )) throw $e;
  3587. $rows = false;
  3588. }
  3589. $this->stash = array();
  3590. if (!$rows) return array();
  3591. foreach($rows as $row) {
  3592. $this->stash[$row[$this->writer->getIDField($type)]] = $row;
  3593. }
  3594. foreach($ids as $id) {
  3595. $collection[ $id ] = $this->load( $type, $id );
  3596. }
  3597. $this->stash = NULL;
  3598. return $collection;
  3599. }
  3600. /**
  3601. * This is a convenience method; it converts database rows
  3602. * (arrays) into beans.
  3603. * @param string $type
  3604. * @param array $rows
  3605. * @return array $collectionOfBeans
  3606. */
  3607. public function convertToBeans($type, $rows) {
  3608. $collection = array();
  3609. $this->stash = array();
  3610. foreach($rows as $row) {
  3611. $id = $row[$this->writer->getIDField($type)];
  3612. $this->stash[$id] = $row;
  3613. $collection[ $id ] = $this->load( $type, $id );
  3614. }
  3615. $this->stash = NULL;
  3616. return $collection;
  3617. }
  3618. /**
  3619. * Returns the number of beans we have in DB of a given type.
  3620. *
  3621. * @param string $type type of bean we are looking for
  3622. *
  3623. * @return integer $num number of beans found
  3624. */
  3625. public function count($type) {
  3626. try {
  3627. return (int) $this->writer->count($type);
  3628. }catch(RedBean_Exception_SQL $e) {
  3629. if (!$this->writer->sqlStateIn($e->getSQLState(),
  3630. array(RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  3631. )) throw $e;
  3632. }
  3633. return 0;
  3634. }
  3635. /**
  3636. * Trash all beans of a given type.
  3637. *
  3638. * @param string $type type
  3639. *
  3640. * @return boolean $yesNo whether we actually did some work or not..
  3641. */
  3642. public function wipe($type) {
  3643. try {
  3644. $this->writer->wipe($type);
  3645. return true;
  3646. }catch(RedBean_Exception_SQL $e) {
  3647. if (!$this->writer->sqlStateIn($e->getSQLState(),
  3648. array(RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  3649. )) throw $e;
  3650. }
  3651. return false;
  3652. }
  3653. }
  3654. /**
  3655. * ToolBox
  3656. * Contains most important redbean tools
  3657. * @file RedBean/ToolBox.php
  3658. * @description The ToolBox acts as a resource locator for RedBean but can
  3659. * be integrated in larger resource locators (nested).
  3660. * It does not do anything more than just store the three most
  3661. * important RedBean resources (tools): the database adapter,
  3662. * the redbean core class (oodb) and the query writer.
  3663. * @author Gabor de Mooij
  3664. * @license BSD
  3665. *
  3666. *
  3667. * (c) G.J.G.T. (Gabor) de Mooij
  3668. * This source file is subject to the BSD/GPLv2 License that is bundled
  3669. * with this source code in the file license.txt.
  3670. */
  3671. class RedBean_ToolBox {
  3672. /**
  3673. *
  3674. * @var RedBean_OODB
  3675. */
  3676. private $oodb;
  3677. /**
  3678. *
  3679. * @var RedBean_QueryWriter
  3680. */
  3681. private $writer;
  3682. /**
  3683. *
  3684. * @var RedBean_Adapter_DBAdapter
  3685. */
  3686. private $adapter;
  3687. /**
  3688. * Constructor.
  3689. * The Constructor of the ToolBox takes three arguments: a RedBean_OODB $redbean
  3690. * object database, a RedBean_Adapter $databaseAdapter and a
  3691. * RedBean_QueryWriter $writer. It stores these objects inside and acts as
  3692. * a micro service locator. You can pass the toolbox to any object that needs
  3693. * one of the RedBean core objects to interact with.
  3694. * @param RedBean_OODB $oodb
  3695. * @param RedBean_Adapter_DBAdapter $adapter
  3696. * @param RedBean_QueryWriter $writer
  3697. * return RedBean_ToolBox $toolbox
  3698. */
  3699. public function __construct( RedBean_OODB $oodb, RedBean_Adapter $adapter, RedBean_QueryWriter $writer ) {
  3700. $this->oodb = $oodb;
  3701. $this->adapter = $adapter;
  3702. $this->writer = $writer;
  3703. return $this;
  3704. }
  3705. /**
  3706. * The Toolbox acts as a kind of micro service locator, providing just the
  3707. * most important objects that make up RedBean. You can pass the toolkit to
  3708. * any object that needs one of these objects to function properly.
  3709. * Returns the QueryWriter; normally you do not use this object but other
  3710. * object might want to use the default RedBean query writer to be
  3711. * database independent.
  3712. * @return RedBean_QueryWriter $writer
  3713. */
  3714. public function getWriter() {
  3715. return $this->writer;
  3716. }
  3717. /**
  3718. * The Toolbox acts as a kind of micro service locator, providing just the
  3719. * most important objects that make up RedBean. You can pass the toolkit to
  3720. * any object that needs one of these objects to function properly.
  3721. * Retruns the RedBean OODB Core object. The RedBean OODB object is
  3722. * the ultimate core of Redbean. It provides the means to store and load
  3723. * beans. Extract this object immediately after invoking a kickstart method.
  3724. * @return RedBean_OODB $oodb
  3725. */
  3726. public function getRedBean() {
  3727. return $this->oodb;
  3728. }
  3729. /**
  3730. * The Toolbox acts as a kind of micro service locator, providing just the
  3731. * most important objects that make up RedBean. You can pass the toolkit to
  3732. * any object that needs one of these objects to function properly.
  3733. * Returns the adapter. The Adapter can be used to perform queries
  3734. * on the database directly.
  3735. * @return RedBean_Adapter_DBAdapter $adapter
  3736. */
  3737. public function getDatabaseAdapter() {
  3738. return $this->adapter;
  3739. }
  3740. }
  3741. /**
  3742. * CompatManager (Compatibility Management)
  3743. *
  3744. * @file RedBean/CompatManager.php
  3745. * @description Offers easy to use tools to check for database compatibility.
  3746. * @author Gabor de Mooij
  3747. * @license BSD
  3748. *
  3749. *
  3750. * (c) G.J.G.T. (Gabor) de Mooij
  3751. * This source file is subject to the BSD/GPLv2 License that is bundled
  3752. * with this source code in the file license.txt.
  3753. */
  3754. class RedBean_CompatManager {
  3755. /**
  3756. * List of Database constants to be used
  3757. * for version detection.
  3758. */
  3759. const C_SYSTEM_MYSQL = "mysql";
  3760. const C_SYSTEM_SQLITE = "sqlite";
  3761. const C_SYSTEM_DB2 = "db2";
  3762. const C_SYSTEM_POSTGRESQL = "pgsql";
  3763. const C_SYSTEM_ORACLE = "oracle";
  3764. const C_SYSTEM_MSSQL = "mssql";
  3765. const C_SYSTEM_HYPERTABLE = "hypertable";
  3766. const C_SYSTEM_INFORMIX = "informix";
  3767. const C_SYSTEM_SYBASE = "sybase";
  3768. const C_SYSTEM_FOXPRO = "foxpro";
  3769. /**
  3770. *
  3771. * @var boolean $ignoreWarning
  3772. */
  3773. private static $ignoreVersion = false;
  3774. /**
  3775. *
  3776. * @var string $messageUnsupported
  3777. */
  3778. protected $messageUnsupported = "
  3779. Unfortunately ##YOU## is not supported by this module or class.
  3780. Supported System(s): ##DBS##.
  3781. To suppress this Exception use: RedBean_CompatManager::ignore(TRUE); ";
  3782. /**
  3783. *
  3784. * @var array $supportedSystems
  3785. */
  3786. protected $supportedSystems = array();
  3787. /**
  3788. * This method toggles the exception system globally.
  3789. * If you set this to true exceptions will not be thrown. Use this
  3790. * if you think the version specification of a module is incorrect
  3791. * or too narrow.
  3792. * @param bool $ignore
  3793. */
  3794. public static function ignore( $tf = TRUE ) {
  3795. self::$ignoreVersion = (bool) $tf;
  3796. }
  3797. /**
  3798. * Scans the toolbox to determine whether the database adapter
  3799. * is compatible with the current class, plugin or module.
  3800. *
  3801. * @throws RedBean_Exception_UnsupportedDatabase $exception
  3802. *
  3803. * @param RedBean_ToolBox $toolbox toolbox
  3804. *
  3805. * @return bool $compatible compatible
  3806. */
  3807. public function scanToolBox( RedBean_ToolBox $toolbox ) {
  3808. $brand = strtolower(trim($toolbox->getDatabaseAdapter()->getDatabase()->getDatabaseType()));
  3809. $version = $toolbox->getDatabaseAdapter()->getDatabase()->getDatabaseVersion();
  3810. if (!is_numeric($version)) {
  3811. $version = 999;
  3812. }
  3813. if (isset($this->supportedSystems[$brand])
  3814. && ((float)$this->supportedSystems[$brand] <= (float) $version)
  3815. ) {
  3816. return true;
  3817. }
  3818. else {
  3819. if (!self::$ignoreVersion) {
  3820. $this->messageUnsupported = str_replace("##YOU##",$brand." v".$version,$this->messageUnsupported);
  3821. $list = array();
  3822. foreach($this->supportedSystems as $supported=>$version) {
  3823. $list[] = " ".$supported . " v".$version."+";
  3824. }
  3825. $this->messageUnsupported = str_replace("##DBS##",implode(",",$list),$this->messageUnsupported);
  3826. throw new RedBean_Exception_UnsupportedDatabase($this->messageUnsupported);
  3827. }
  3828. else {
  3829. return false;
  3830. }
  3831. }
  3832. }
  3833. /**
  3834. * Static Variant
  3835. * Scans the toolbox to determine whether the database adapter
  3836. * is compatible with the current class, plugin or module.
  3837. *
  3838. * @throws RedBean_Exception_UnsupportedDatabase $exception
  3839. *
  3840. * @param RedBean_ToolBox $toolbox toolbox
  3841. * @param array $list list of systems that are supported
  3842. *
  3843. * @return bool $compatible compatible
  3844. */
  3845. public static function scanDirect( RedBean_ToolBox $toolbox, $list = array() ) {
  3846. $compat = new RedBean_CompatManager();
  3847. $compat->supportedSystems = $list;
  3848. return $compat->scanToolBox($toolbox);
  3849. }
  3850. }
  3851. /**
  3852. * RedBean Association
  3853. * @file RedBean/AssociationManager.php
  3854. * @description Manages simple bean associations.
  3855. *
  3856. * @author Gabor de Mooij
  3857. * @license BSD
  3858. *
  3859. * (c) G.J.G.T. (Gabor) de Mooij
  3860. * This source file is subject to the BSD/GPLv2 License that is bundled
  3861. * with this source code in the file license.txt.
  3862. */
  3863. class RedBean_AssociationManager extends RedBean_CompatManager {
  3864. /**
  3865. * Specify what database systems are supported by this class.
  3866. * @var array $databaseSpecs
  3867. */
  3868. protected $supportedSystems = array(
  3869. RedBean_CompatManager::C_SYSTEM_MYSQL => "5",
  3870. RedBean_CompatManager::C_SYSTEM_SQLITE=>"3",
  3871. RedBean_CompatManager::C_SYSTEM_POSTGRESQL=>"8"
  3872. );
  3873. /**
  3874. * @var RedBean_OODB
  3875. */
  3876. protected $oodb;
  3877. /**
  3878. * @var RedBean_Adapter_DBAdapter
  3879. */
  3880. protected $adapter;
  3881. /**
  3882. * @var RedBean_QueryWriter
  3883. */
  3884. protected $writer;
  3885. /**
  3886. * Constructor
  3887. *
  3888. * @param RedBean_ToolBox $tools toolbox
  3889. */
  3890. public function __construct( RedBean_ToolBox $tools ) {
  3891. $this->oodb = $tools->getRedBean();
  3892. $this->adapter = $tools->getDatabaseAdapter();
  3893. $this->writer = $tools->getWriter();
  3894. }
  3895. /**
  3896. * Creates a table name based on a types array.
  3897. *
  3898. * @param array $types types
  3899. *
  3900. * @return string $table table
  3901. */
  3902. public function getTable( $types ) {
  3903. sort($types);
  3904. return ( implode("_", $types) );
  3905. }
  3906. /**
  3907. * Associates two beans with eachother.
  3908. *
  3909. * @param RedBean_OODBBean $bean1 bean1
  3910. * @param RedBean_OODBBean $bean2 bean2
  3911. */
  3912. public function associate(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2) {
  3913. $table = $this->getTable( array($bean1->getMeta("type") , $bean2->getMeta("type")) );
  3914. $bean = $this->oodb->dispense($table);
  3915. return $this->associateBeans( $bean1, $bean2, $bean );
  3916. }
  3917. /**
  3918. * Associates a pair of beans. This method associates two beans, no matter
  3919. * what types.
  3920. *
  3921. * @param RedBean_OODBBean $bean1 first bean
  3922. * @param RedBean_OODBBean $bean2 second bean
  3923. * @param RedBean_OODBBean $bean base bean
  3924. *
  3925. * @return mixed $id either the link ID or null
  3926. */
  3927. protected function associateBeans(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, RedBean_OODBBean $bean) {
  3928. $idfield1 = $this->writer->getIDField($bean1->getMeta("type"));
  3929. $idfield2 = $this->writer->getIDField($bean2->getMeta("type"));
  3930. $property1 = $bean1->getMeta("type") . "_id";
  3931. $property2 = $bean2->getMeta("type") . "_id";
  3932. if ($property1==$property2) $property2 = $bean2->getMeta("type")."2_id";
  3933. $bean->setMeta( "buildcommand.unique" , array( array( $property1, $property2 )));
  3934. $this->oodb->store($bean1);
  3935. $this->oodb->store($bean2);
  3936. $bean->$property1 = $bean1->$idfield1;
  3937. $bean->$property2 = $bean2->$idfield2;
  3938. try {
  3939. return $this->oodb->store( $bean );
  3940. }
  3941. catch(RedBean_Exception_SQL $e) {
  3942. if (!$this->writer->sqlStateIn($e->getSQLState(),
  3943. array(
  3944. RedBean_QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION
  3945. ))) throw $e;
  3946. }
  3947. }
  3948. /**
  3949. * Gets related beans of type $type for bean $bean
  3950. *
  3951. * @param RedBean_OODBBean $bean bean
  3952. * @param string $type type
  3953. * @param bool $linksOnly whether you want keys of links themselves
  3954. * @param string $sql optional SQL template to use,
  3955. *
  3956. * @return array $idsOrRows ids or rows
  3957. */
  3958. public function related( RedBean_OODBBean $bean, $type, $getLinks=false, $sql=false ) {
  3959. $table = $this->getTable( array($bean->getMeta("type") , $type) );
  3960. $idfield = $this->writer->getIDField($bean->getMeta("type"));
  3961. if ($type==$bean->getMeta("type")) {
  3962. $type .= "2";
  3963. $cross = 1;
  3964. }
  3965. else $cross=0;
  3966. if (!$getLinks) $targetproperty = $type."_id"; else $targetproperty="id";
  3967. $property = $bean->getMeta("type")."_id";
  3968. try {
  3969. if ($cross) {
  3970. $sqlFetchKeys = $this->writer->selectByCrit(
  3971. $targetproperty,
  3972. $table,
  3973. $property,
  3974. $bean->$idfield,
  3975. true,$sql
  3976. );
  3977. }
  3978. else {
  3979. $sqlFetchKeys = $this->writer->selectByCrit(
  3980. $targetproperty,
  3981. $table,
  3982. $property,
  3983. $bean->$idfield,false,$sql
  3984. );
  3985. }
  3986. return ( $sqlFetchKeys );
  3987. }catch(RedBean_Exception_SQL $e) {
  3988. if (!$this->writer->sqlStateIn($e->getSQLState(),
  3989. array(
  3990. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  3991. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  3992. )) throw $e;
  3993. return array();
  3994. }
  3995. }
  3996. /**
  3997. * Breaks the association between two beans
  3998. *
  3999. * @param RedBean_OODBBean $bean1 first bean
  4000. * @param RedBean_OODBBean $bean2 second bean
  4001. */
  4002. public function unassociate(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2) {
  4003. $this->oodb->store($bean1);
  4004. $this->oodb->store($bean2);
  4005. $table = $this->getTable( array($bean1->getMeta("type") , $bean2->getMeta("type")) );
  4006. $idfield1 = $this->writer->getIDField($bean1->getMeta("type"));
  4007. $idfield2 = $this->writer->getIDField($bean2->getMeta("type"));
  4008. $type = $bean1->getMeta("type");
  4009. if ($type==$bean2->getMeta("type")) {
  4010. $type .= "2";
  4011. $cross = 1;
  4012. }
  4013. else $cross = 0;
  4014. $property1 = $type."_id";
  4015. $property2 = $bean2->getMeta("type")."_id";
  4016. $value1 = (int) $bean1->$idfield1;
  4017. $value2 = (int) $bean2->$idfield2;
  4018. try {
  4019. $this->writer->deleteByCrit($table,array($property1=>$value1,$property2=>$value2));
  4020. if ($cross) {
  4021. $this->writer->deleteByCrit($table,array($property2=>$value1,$property1=>$value2));
  4022. }
  4023. }catch(RedBean_Exception_SQL $e) {
  4024. if (!$this->writer->sqlStateIn($e->getSQLState(),
  4025. array(
  4026. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  4027. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  4028. )) throw $e;
  4029. }
  4030. }
  4031. /**
  4032. * Removes all relations for a bean
  4033. *
  4034. * @param RedBean_OODBBean $bean bean
  4035. * @param string $type type
  4036. */
  4037. public function clearRelations(RedBean_OODBBean $bean, $type) {
  4038. $this->oodb->store($bean);
  4039. $table = $this->getTable( array($bean->getMeta("type") , $type) );
  4040. $idfield = $this->writer->getIDField($bean->getMeta("type"));
  4041. if ($type==$bean->getMeta("type")) {
  4042. $property2 = $type."2_id";
  4043. $cross = 1;
  4044. }
  4045. else $cross = 0;
  4046. $property = $bean->getMeta("type")."_id";
  4047. try {
  4048. $this->writer->deleteByCrit($table,array($property=>$bean->$idfield));
  4049. if ($cross) {
  4050. $this->writer->deleteByCrit($table,array($property2=>$bean->$idfield));
  4051. }
  4052. }catch(RedBean_Exception_SQL $e) {
  4053. if (!$this->writer->sqlStateIn($e->getSQLState(),
  4054. array(
  4055. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  4056. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  4057. )) throw $e;
  4058. }
  4059. }
  4060. /**
  4061. * @deprecated
  4062. * Creates a 1 to Many Association
  4063. * If the association fails it throws an exception.
  4064. * @throws RedBean_Exception_SQL $failedToEnforce1toN
  4065. *
  4066. * @param RedBean_OODBBean $bean1 bean1
  4067. * @param RedBean_OODBBean $bean2 bean2
  4068. *
  4069. * @return RedBean_AssociationManager $chainable chainable
  4070. */
  4071. public function set1toNAssoc(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2) {
  4072. $type = $bean1->getMeta("type");
  4073. $this->clearRelations($bean2, $type);
  4074. $this->associate($bean1, $bean2);
  4075. if (count( $this->related($bean2, $type) )===1) {
  4076. return $this;
  4077. }
  4078. else {
  4079. throw new RedBean_Exception_SQL("Failed to enforce 1toN Relation for $type ");
  4080. }
  4081. }
  4082. }
  4083. /**
  4084. * RedBean Tree
  4085. *
  4086. * @file RedBean/TreeManager.php
  4087. * @description Tree structure for beans.
  4088. * @author Gabor de Mooij
  4089. * @license BSD
  4090. *
  4091. *
  4092. * (c) G.J.G.T. (Gabor) de Mooij
  4093. * This source file is subject to the BSD/GPLv2 License that is bundled
  4094. * with this source code in the file license.txt.
  4095. */
  4096. class RedBean_TreeManager extends RedBean_CompatManager {
  4097. /**
  4098. * Specify what database systems are supported by this class.
  4099. * @var array $databaseSpecs
  4100. */
  4101. protected $supportedSystems = array(
  4102. RedBean_CompatManager::C_SYSTEM_MYSQL => "5",
  4103. RedBean_CompatManager::C_SYSTEM_SQLITE=>"3"
  4104. );
  4105. /**
  4106. *
  4107. * @var string
  4108. */
  4109. private $property = "parent_id";
  4110. /**
  4111. * @var RedBean_OODB
  4112. */
  4113. private $oodb;
  4114. /**
  4115. * @var RedBean_Adapter_DBAdapter
  4116. */
  4117. private $adapter;
  4118. /**
  4119. * @var RedBean_QueryWriter
  4120. */
  4121. private $writer;
  4122. /**
  4123. * Constructor.
  4124. * @param RedBean_ToolBox $tools
  4125. */
  4126. public function __construct( RedBean_ToolBox $tools ) {
  4127. $this->oodb = $tools->getRedBean();
  4128. $this->adapter = $tools->getDatabaseAdapter();
  4129. $this->writer = $tools->getWriter();
  4130. }
  4131. /**
  4132. * Checks whether types of beans match. If the types do not match
  4133. * this method will throw a RedBean_Exception_Security exception.
  4134. * @param RedBean_OODBBean $bean1
  4135. * @param RedBean_OODBBean $bean2
  4136. */
  4137. private function equalTypes( RedBean_OODBBean $bean1, RedBean_OODBBean $bean2 ) {
  4138. if ($bean1->getMeta("type")!==$bean2->getMeta("type")) {
  4139. throw new RedBean_Exception_Security("Incompatible types, tree can only work with identical types.");
  4140. }
  4141. }
  4142. /**
  4143. * Attaches the specified child node to the specified parent node.
  4144. * @param RedBean_OODBBean $parent
  4145. * @param RedBean_OODBBean $child
  4146. */
  4147. public function attach( RedBean_OODBBean $parent, RedBean_OODBBean $child ) {
  4148. $this->equalTypes( $parent, $child );
  4149. $idfield = $this->writer->getIDField($parent->getMeta("type"));
  4150. if (!intval($parent->$idfield)) $this->oodb->store($parent);
  4151. $child->{$this->property} = $parent->$idfield;
  4152. $this->oodb->store($child);
  4153. }
  4154. /**
  4155. * Returns all the nodes that have been attached to the specified
  4156. * parent node.
  4157. * @param RedBean_OODBBean $parent
  4158. * @return array $childObjects
  4159. */
  4160. public function children( RedBean_OODBBean $parent ) {
  4161. $idfield = $this->writer->getIDField($parent->getMeta("type"));
  4162. try {
  4163. $ids = $this->writer->selectByCrit( $idfield,
  4164. $parent->getMeta("type"),
  4165. $this->property,
  4166. intval( $parent->$idfield ) );
  4167. }
  4168. catch(RedBean_Exception_SQL $e) {
  4169. return array();
  4170. }
  4171. return $this->oodb->batch($parent->getMeta("type"),$ids );
  4172. }
  4173. public function getParent( RedBean_OODBBean $bean ) {
  4174. return $this->oodb->load( $bean->getMeta("type"), (int)$bean->parent_id);
  4175. }
  4176. }
  4177. /**
  4178. * RedBean Links
  4179. * @file RedBean/LinkManager.php
  4180. * @description Manages foreign keys
  4181. *
  4182. * @author Gabor de Mooij
  4183. * @license BSD
  4184. *
  4185. * (c) G.J.G.T. (Gabor) de Mooij
  4186. * This source file is subject to the BSD/GPLv2 License that is bundled
  4187. * with this source code in the file license.txt.
  4188. */
  4189. class RedBean_LinkManager extends RedBean_CompatManager {
  4190. /**
  4191. * Specify what database systems are supported by this class.
  4192. * @var array $databaseSpecs
  4193. */
  4194. protected $supportedSystems = array(
  4195. RedBean_CompatManager::C_SYSTEM_MYSQL => "5",
  4196. RedBean_CompatManager::C_SYSTEM_SQLITE=>"3",
  4197. RedBean_CompatManager::C_SYSTEM_POSTGRESQL=>"8"
  4198. );
  4199. /**
  4200. * @var RedBean_OODB
  4201. */
  4202. protected $oodb;
  4203. /**
  4204. * @var RedBean_Adapter_DBAdapter
  4205. */
  4206. protected $adapter;
  4207. /**
  4208. * @var RedBean_QueryWriter
  4209. */
  4210. protected $writer;
  4211. /**
  4212. * Constructor
  4213. * @param RedBean_ToolBox $tools
  4214. */
  4215. public function __construct( RedBean_ToolBox $tools ) {
  4216. $this->oodb = $tools->getRedBean();
  4217. $this->adapter = $tools->getDatabaseAdapter();
  4218. $this->writer = $tools->getWriter();
  4219. }
  4220. /**
  4221. * Returns the fieldname for a foreign key.
  4222. * @param string $typeName
  4223. * @return string $fieldName
  4224. */
  4225. public function getLinkField( $typeName, $name = null ) {
  4226. $fieldName = strtolower( $typeName )."_id";
  4227. if ($name !== null) {
  4228. $fieldName = "{$name}_$fieldName";
  4229. }
  4230. $fieldName = preg_replace( "/\W/","", $fieldName );
  4231. return $fieldName;
  4232. }
  4233. /**
  4234. * Adds a reference to bean2 in bean1.
  4235. * @param RedBean_OODBBean $bean1
  4236. * @param RedBean_OODBBean $bean2
  4237. */
  4238. public function link(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, $name = null) {
  4239. if (!$bean2->id) {
  4240. $this->oodb->store( $bean2 );
  4241. }
  4242. $fieldName = $this->getLinkField( $bean2->getMeta("type"), $name);
  4243. $bean1->$fieldName = $bean2->id;
  4244. return $this;
  4245. }
  4246. /**
  4247. * Returns a linked bean.
  4248. * @param RedBean_OODBBean $bean
  4249. * @param string $typeName
  4250. * @return RedBean_OODBBean $bean
  4251. */
  4252. public function getBean( RedBean_OODBBean $bean, $typeName, $name = null) {
  4253. $fieldName = $this->getLinkField($typeName, $name);
  4254. $id = (int)$bean->$fieldName;
  4255. if ($id) {
  4256. return $this->oodb->load($typeName, $id);
  4257. }
  4258. else {
  4259. return null;
  4260. }
  4261. }
  4262. /**
  4263. * Removes a linked bean.
  4264. * @param RedBean_OODBBean $bean
  4265. * @param string $typeName
  4266. */
  4267. public function breakLink( RedBean_OODBBean $bean, $typeName, $name = null) {
  4268. $fieldName = $this->getLinkField($typeName, $name);
  4269. $bean->$fieldName = NULL;
  4270. }
  4271. /**
  4272. * Returns a linked bean ID.
  4273. * @param RedBean_OODBBean $bean
  4274. * @param string $typeName
  4275. * @return RedBean_OODB $bean
  4276. */
  4277. public function getKey(RedBean_OODBBean $bean, $typeName, $name = null) {
  4278. $fieldName = $this->getLinkField($typeName, $name);
  4279. $id = (int)$bean->$fieldName;
  4280. return $id;
  4281. }
  4282. /**
  4283. * Returns all beans that are linked to the given bean.
  4284. * @param RedBean_OODBBean $bean
  4285. * @param string $typeName
  4286. * @return array $beans
  4287. */
  4288. public function getKeys( RedBean_OODBBean $bean, $typeName ) {
  4289. $fieldName = $this->getLinkField($typeName);
  4290. $id = (int)$bean->$fieldName;
  4291. $ids = $this->writer->selectByCrit($this->writer->getIDField($this->writer->getFormattedTableName($typeName)),
  4292. $typeName,
  4293. $bean->getMeta("type")."_id",
  4294. $bean->id);
  4295. return $ids;
  4296. }
  4297. }
  4298. /**
  4299. * RedBean Extended Association
  4300. * @file RedBean/ExtAssociationManager.php
  4301. * @description Manages complex bean associations.
  4302. *
  4303. * @author Gabor de Mooij
  4304. * @license BSD
  4305. *
  4306. * (c) G.J.G.T. (Gabor) de Mooij
  4307. * This source file is subject to the BSD/GPLv2 License that is bundled
  4308. * with this source code in the file license.txt.
  4309. */
  4310. class RedBean_ExtAssociationManager extends RedBean_AssociationManager {
  4311. /**
  4312. * Associates two beans with eachother.
  4313. *
  4314. * @param RedBean_OODBBean $bean1 bean 1
  4315. * @param RedBean_OODBBean $bean2 bean 2
  4316. *
  4317. */
  4318. public function extAssociate(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, RedBean_OODBBean $baseBean ) {
  4319. $table = $this->getTable( array($bean1->getMeta("type") , $bean2->getMeta("type")) );
  4320. $baseBean->setMeta("type", $table );
  4321. return $this->associateBeans( $bean1, $bean2, $baseBean );
  4322. }
  4323. }
  4324. /**
  4325. * RedBean Setup
  4326. * Helper class to quickly setup RedBean for you
  4327. * @file RedBean/Setup.php
  4328. * @description Helper class to quickly setup RedBean for you
  4329. * @author Gabor de Mooij
  4330. * @license BSD
  4331. *
  4332. *
  4333. * (c) G.J.G.T. (Gabor) de Mooij
  4334. * This source file is subject to the BSD/GPLv2 License that is bundled
  4335. * with this source code in the file license.txt.
  4336. */
  4337. class RedBean_Setup {
  4338. /**
  4339. *
  4340. * @var array
  4341. * Keeps track of the observers
  4342. */
  4343. private static $observers = array();
  4344. /**
  4345. *
  4346. * @var RedBean_ToolBox $toolbox
  4347. */
  4348. private static $toolbox = NULL;
  4349. /**
  4350. * This method checks the DSN string. If the DSN string contains a
  4351. * database name that is not supported by RedBean yet then it will
  4352. * throw an exception RedBean_Exception_NotImplemented. In any other
  4353. * case this method will just return boolean TRUE.
  4354. * @throws RedBean_Exception_NotImplemented
  4355. * @param string $dsn
  4356. * @return boolean $true
  4357. */
  4358. private static function checkDSN($dsn) {
  4359. $dsn = trim($dsn);
  4360. $dsn = strtolower($dsn);
  4361. if (
  4362. strpos($dsn, "mysql:")!==0
  4363. && strpos($dsn,"sqlite:")!==0
  4364. && strpos($dsn,"pgsql:")!==0
  4365. ) {
  4366. throw new RedBean_Exception_NotImplemented("
  4367. Support for this DSN has not been implemented yet. \n
  4368. Begin your DSN with: 'mysql:' or 'sqlite:'
  4369. ");
  4370. }
  4371. else {
  4372. return true;
  4373. }
  4374. }
  4375. /**
  4376. * Generic Kickstart method.
  4377. * This is the generic kickstarter. It will establish a database connection
  4378. * using the $dsn, the $username and the $password you provide.
  4379. * If $frozen is boolean TRUE it will start RedBean in frozen mode, meaning
  4380. * that the database cannot be altered. If RedBean is started in fluid mode
  4381. * it will adjust the schema of the database if it detects an
  4382. * incompatible bean.
  4383. * This method returns a RedBean_Toolbox $toolbox filled with a
  4384. * RedBean_Adapter, a RedBean_QueryWriter and most importantly a
  4385. * RedBean_OODB; the object database. To start storing beans in the database
  4386. * simply say: $redbean = $toolbox->getRedBean(); Now you have a reference
  4387. * to the RedBean object.
  4388. * Optionally instead of using $dsn you may use an existing PDO connection.
  4389. * Example: RedBean_Setup::kickstart($existingConnection, true);
  4390. *
  4391. * @param string|PDO $dsn
  4392. * @param string $username
  4393. * @param string $password
  4394. * @return RedBean_ToolBox $toolbox
  4395. */
  4396. public static function kickstart( $dsn, $username=NULL, $password=NULL, $frozen=false ) {
  4397. if ($dsn instanceof PDO) {
  4398. $pdo = new RedBean_Driver_PDO($dsn);
  4399. $dsn = $pdo->getDatabaseType() ;
  4400. }
  4401. else {
  4402. self::checkDSN($dsn);
  4403. $pdo = new RedBean_Driver_PDO( $dsn,$username,$password );
  4404. }
  4405. $adapter = new RedBean_Adapter_DBAdapter( $pdo );
  4406. if (strpos($dsn,"pgsql")===0) {
  4407. $writer = new RedBean_QueryWriter_PostgreSQL( $adapter, $frozen );
  4408. }
  4409. else if (strpos($dsn,"sqlite")===0) {
  4410. $writer = new RedBean_QueryWriter_SQLiteT( $adapter, $frozen );
  4411. }
  4412. else {
  4413. $writer = new RedBean_QueryWriter_MySQL( $adapter, $frozen );
  4414. }
  4415. $redbean = new RedBean_OODB( $writer );
  4416. $toolbox = new RedBean_ToolBox( $redbean, $adapter, $writer );
  4417. self::$toolbox = $toolbox;
  4418. return self::$toolbox;
  4419. }
  4420. /**
  4421. * Kickstart for development phase.
  4422. * Use this method to quickly setup RedBean for use during development phase.
  4423. * This Kickstart establishes a database connection
  4424. * using the $dsn, the $username and the $password you provide.
  4425. * It will start RedBean in fluid mode; meaning the database will
  4426. * be altered if required to store your beans.
  4427. * This method returns a RedBean_Toolbox $toolbox filled with a
  4428. * RedBean_Adapter, a RedBean_QueryWriter and most importantly a
  4429. * RedBean_OODB; the object database. To start storing beans in the database
  4430. * simply say: $redbean = $toolbox->getRedBean(); Now you have a reference
  4431. * to the RedBean object.
  4432. * @param string $dsn
  4433. * @param string $username
  4434. * @param string $password
  4435. * @return RedBean_ToolBox $toolbox
  4436. */
  4437. public static function kickstartDev( $dsn, $username="root", $password="" ) {
  4438. $toolbox = self::kickstart($dsn, $username, $password);
  4439. return $toolbox;
  4440. }
  4441. /**
  4442. * @param string $dsn
  4443. * @return RedBean_ToolBox $toolbox
  4444. */
  4445. public static function kickstartDevL( $dsn ) {
  4446. self::checkDSN($dsn);
  4447. $pdo = new RedBean_Driver_PDO( $dsn ,"","");
  4448. $adapter = new RedBean_Adapter_DBAdapter( $pdo );
  4449. $writer = new RedBean_QueryWriter_SQLiteT( $adapter, false );
  4450. $redbean = new RedBean_OODB( $writer );
  4451. $toolbox = new RedBean_ToolBox( $redbean, $adapter, $writer );
  4452. self::$toolbox = $toolbox;
  4453. return self::$toolbox;
  4454. }
  4455. /**
  4456. * Almost the same as Dev, but adds the journaling plugin by default for you.
  4457. * This Kickstart establishes a database connection
  4458. * using the $dsn, the $username and the $password you provide.
  4459. * The Journaling plugin detects Race Conditions, for more information please
  4460. * consult the RedBean_Plugin_ChangeLogger Documentation.
  4461. * This method returns a RedBean_Toolbox $toolbox filled with a
  4462. * RedBean_Adapter, a RedBean_QueryWriter and most importantly a
  4463. * RedBean_OODB; the object database. To start storing beans in the database
  4464. * simply say: $redbean = $toolbox->getRedBean(); Now you have a reference
  4465. * to the RedBean object.
  4466. * @param string $dsn
  4467. * @param string $username
  4468. * @param string $password
  4469. * @return RedBean_ToolBox $toolbox
  4470. */
  4471. public static function KickStartDevWithJournal($dsn, $username="root", $password="") {
  4472. $toolbox = self::kickstart($dsn, $username, $password);
  4473. $redbean = $toolbox->getRedBean();
  4474. $logger = new RedBean_Plugin_ChangeLogger( $toolbox );
  4475. self::$observers["logger"] = $logger;
  4476. $redbean->addEventListener( "open", $logger );
  4477. $redbean->addEventListener( "update", $logger);
  4478. $redbean->addEventListener( "delete", $logger);
  4479. return $toolbox;
  4480. }
  4481. /**
  4482. * Kickstart method for production environment.
  4483. * This Kickstart establishes a database connection
  4484. * using the $dsn, the $username and the $password you provide.
  4485. * This method will start RedBean in frozen mode which is
  4486. * the preferred mode of operation for a production environment.
  4487. * In frozen mode, RedBean will not alter the schema of the database;
  4488. * which improves performance and security.
  4489. * This method returns a RedBean_Toolbox $toolbox filled with a
  4490. * RedBean_Adapter, a RedBean_QueryWriter and most importantly a
  4491. * RedBean_OODB; the object database. To start storing beans in the database
  4492. * simply say: $redbean = $toolbox->getRedBean(); Now you have a reference
  4493. * to the RedBean object.
  4494. * @param string $dsn
  4495. * @param string $username
  4496. * @param string $password
  4497. * @return RedBean_ToolBox $toolbox
  4498. */
  4499. public static function kickstartFrozen( $dsn, $username, $password ) {
  4500. $toolbox = self::kickstart($dsn, $username, $password, true);
  4501. $toolbox->getRedBean()->freeze(true);
  4502. return $toolbox;
  4503. }
  4504. /**
  4505. * Kickstart Method for debugging.
  4506. * This method returns a RedBean_Toolbox $toolbox filled with a
  4507. * RedBean_Adapter, a RedBean_QueryWriter and most importantly a
  4508. * RedBean_OODB; the object database. To start storing beans in the database
  4509. * simply say: $redbean = $toolbox->getRedBean(); Now you have a reference
  4510. * to the RedBean object.
  4511. * @param string $dsn
  4512. * @param string $username
  4513. * @param string $password
  4514. * @return RedBean_ToolBox $toolbox
  4515. */
  4516. public static function kickstartDebug( $dsn, $username="root", $password="" ) {
  4517. $toolbox = self::kickstart($dsn, $username, $password);
  4518. $toolbox->getDatabaseAdapter()->getDatabase()->setDebugMode( true );
  4519. return $toolbox;
  4520. }
  4521. /**
  4522. * During a kickstart method observers may be attached to the RedBean_OODB object.
  4523. * Setup keeps track of the observers that are connected to RedBean.
  4524. * Returns the observers that have been attached by Setup.
  4525. * @return array $observers
  4526. */
  4527. public static function getAttachedObservers() {
  4528. return self::$observers;
  4529. }
  4530. /**
  4531. * This is a convenience method. By default a kickstart method
  4532. * returns the RedBean_ToolBox $toolbox for you with all necessary
  4533. * objects inside. If for some reason you need to have access to the
  4534. * latest toolbox that Setup has assembled you can use this function
  4535. * to retrieve it.
  4536. * Returns the most recently assembled toolbox
  4537. * @return RedBean_ToolBox $toolbox
  4538. */
  4539. public static function getToolBox() {
  4540. return self::$toolbox;
  4541. }
  4542. }
  4543. /**
  4544. * RedBean ChangeLogger
  4545. * Shields you from race conditions automatically.
  4546. * @file RedBean/ChangeLogger.php
  4547. * @description Shields you from race conditions automatically.
  4548. * @author Gabor de Mooij
  4549. * @license BSD
  4550. *
  4551. *
  4552. * (c) G.J.G.T. (Gabor) de Mooij
  4553. * This source file is subject to the BSD/GPLv2 License that is bundled
  4554. * with this source code in the file license.txt.
  4555. */
  4556. class RedBean_Plugin_ChangeLogger extends RedBean_CompatManager implements RedBean_Plugin,RedBean_Observer {
  4557. /**
  4558. * Specify what database systems are supported by this class.
  4559. * @var array $databaseSpecs
  4560. */
  4561. protected $supportedSystems = array(
  4562. RedBean_CompatManager::C_SYSTEM_MYSQL => "5",
  4563. );
  4564. /**
  4565. * @var RedBean_QueryWriter
  4566. * Contains a reference to the query writer.
  4567. */
  4568. private $writer;
  4569. /**
  4570. *
  4571. * @var RedBean_Adapter
  4572. * Contains a reference to the database adapter.
  4573. */
  4574. private $adapter;
  4575. /**
  4576. *
  4577. * @var array
  4578. * Our secret stash of redbeans... ;)
  4579. */
  4580. private $stash = array();
  4581. /**
  4582. *
  4583. * @var RedBean_OODB
  4584. * Contains a reference to the RedBean OODB object.
  4585. */
  4586. private $redbean;
  4587. /**
  4588. * Constructor, requires a writer
  4589. *
  4590. * @param RedBean_QueryWriter $writer
  4591. */
  4592. public function __construct(RedBean_ToolBox $toolbox) {
  4593. $this->scanToolBox( $toolbox );
  4594. $this->writer = $toolbox->getWriter();
  4595. $this->adapter = $toolbox->getDatabaseAdapter();
  4596. $this->redbean = $toolbox->getRedBean();
  4597. if (!$this->redbean->isFrozen()) {
  4598. $this->adapter->exec("
  4599. CREATE TABLE IF NOT EXISTS `__log` (
  4600. `id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  4601. `tbl` VARCHAR( 255 ) NOT NULL ,
  4602. `action` TINYINT( 2 ) NOT NULL ,
  4603. `itemid` INT( 11 ) NOT NULL
  4604. ) ENGINE = MYISAM ;
  4605. ");
  4606. }
  4607. $maxid = $this->adapter->getCell("SELECT MAX(id) FROM __log");
  4608. $this->adapter->exec("DELETE FROM __log WHERE id < $maxid - 200 ");
  4609. }
  4610. /**
  4611. * Throws an exception if information in the bean has been changed
  4612. * by another process or bean. This is actually the same as journaling
  4613. * using timestamps however with timestamps you risk race conditions
  4614. * when the measurements are not fine-grained enough; with
  4615. * auto-incremented primary key ids we dont have this risk.
  4616. *
  4617. * @param string $event event name
  4618. * @param RedBean_OODBBean $item item
  4619. */
  4620. public function onEvent( $event, $item ) {
  4621. $id = $item->id;
  4622. if (! ((int) $id)) $event="open";
  4623. $type = $item->getMeta("type");
  4624. if ($event=="open") {
  4625. if (isset($this->stash[$id])) {
  4626. $insertid = $this->stash[$id];
  4627. unset($this->stash[$id]);
  4628. return $insertid;
  4629. }
  4630. $insertid = $this->writer->insertRecord("__log",array("action","tbl","itemid"),
  4631. array(array(1, $type, $id)));
  4632. $item->setMeta("opened",$insertid);
  4633. }
  4634. if ($event=="update" || $event=="delete") {
  4635. if (($item->getMeta("opened"))) $oldid = $item->getMeta("opened"); else $oldid=0;
  4636. $newid = $this->checkChanges($type,$id, $oldid);
  4637. $item->setMeta("opened",$newid);
  4638. }
  4639. }
  4640. /**
  4641. * Facilitates preloading. If you want to load multiple beans at once
  4642. * these beans can be locked individually; given N beans this means approx.
  4643. * N*3 queries which is quite a lot. This method allows you to pre-lock or pre-open
  4644. * multiple entries at once. All beans will get an opened stamp that correspond to
  4645. * the first bean opened. This means this approach is conservative; it might
  4646. * produce a higher rate of false alarms but it does not compromise
  4647. * concurrency security.
  4648. *
  4649. * @param string $type type
  4650. * @param array $ids series of ids
  4651. */
  4652. public function preLoad( $type, $ids ) {
  4653. $this->adapter->exec("INSERT INTO __log (id,action,tbl,itemid)
  4654. VALUES(NULL, :action,:tbl,:id)",array(":action"=>1,":tbl"=>"__no_type__",":id"=>0));
  4655. $insertid = $this->adapter->getInsertID();
  4656. $values = array();
  4657. foreach($ids as $id) {
  4658. $this->stash[$id]=$insertid;
  4659. $values[] = array(1, $type, $id);
  4660. }
  4661. $this->writer->insertRecord("__log",array("action","tbl","itemid"), $values);
  4662. }
  4663. /**
  4664. * For testing only, dont use.
  4665. *
  4666. * @return array $stash stash
  4667. */
  4668. public function testingOnly_getStash() {
  4669. return $this->stash;
  4670. }
  4671. /**
  4672. * Gets information about changed records using a type and id and a logid.
  4673. * RedBean Locking shields you from race conditions by comparing the latest
  4674. * cached insert id with a the highest insert id associated with a write action
  4675. * on the same table. If there is any id between these two the record has
  4676. * been changed and RedBean will throw an exception. This function checks for changes.
  4677. * If changes have occurred it will throw an exception. If no changes have occurred
  4678. * it will insert a new change record and return the new change id.
  4679. * This method locks the log table exclusively.
  4680. *
  4681. * @param string $type type
  4682. * @param integer $id id
  4683. * @param integer $logid log id
  4684. *
  4685. * @return integer $newchangeid new id
  4686. */
  4687. public function checkChanges($type, $id, $logid) {
  4688. $type = $this->writer->check($type);
  4689. $id = (int) $id;
  4690. $logid = (int) $logid;
  4691. $num = $this->adapter->getCell("
  4692. SELECT count(*) FROM __log WHERE tbl=\"$type\" AND itemid=$id AND action=2 AND id > $logid");
  4693. if ($num) {
  4694. throw new RedBean_Exception_FailedAccessBean("Locked, failed to access (type:$type, id:$id)");
  4695. }
  4696. $this->adapter->exec("INSERT INTO __log (id,action,tbl,itemid) VALUES(NULL, 2,:tbl,:id)",array(":tbl"=>$type, ":id"=>$id));
  4697. $newid = $this->adapter->getInsertID();
  4698. if ($this->adapter->getCell("select id from __log where tbl=:tbl AND id < $newid and id > $logid and action=2 and itemid=$id ",
  4699. array(":tbl"=>$type))) {
  4700. throw new RedBean_Exception_FailedAccessBean("Locked, failed to access II (type:$type, id:$id)");
  4701. }
  4702. return $newid;
  4703. }
  4704. }
  4705. /**
  4706. * RedBean Bean Cache
  4707. * @file RedBean/Plugin/Cache.php
  4708. * @description Decorator for RedBean core class RedBean_OODB
  4709. * Adds primitive caching to RedBean.
  4710. *
  4711. * @author Gabor de Mooij
  4712. * @license BSD
  4713. *
  4714. *
  4715. * (c) G.J.G.T. (Gabor) de Mooij
  4716. * This source file is subject to the BSD/GPLv2 License that is bundled
  4717. * with this source code in the file license.txt.
  4718. */
  4719. class RedBean_Plugin_Cache extends RedBean_Observable implements RedBean_Plugin, RedBean_ObjectDatabase {
  4720. /**
  4721. * @var RedBean_OODB
  4722. * Contains a reference to the RedBean OODB object.
  4723. */
  4724. private $oodb;
  4725. /**
  4726. * @var RedBean_QueryWriter
  4727. * Contains a reference to the query writer.
  4728. */
  4729. private $writer;
  4730. /**
  4731. * @var array
  4732. * Cache array.
  4733. */
  4734. private $cache = array();
  4735. /**
  4736. * @var array
  4737. * Keeps track of original beans.
  4738. */
  4739. private $originals = array();
  4740. /**
  4741. * @var integer
  4742. * A simple column counter.
  4743. */
  4744. private $columnCounter = 0;
  4745. /**
  4746. * Constructor.
  4747. *
  4748. * @param RedBean_OODB $oodb object database
  4749. * @param RedBean_ToolBox $toolBox toolbox
  4750. */
  4751. public function __construct( RedBean_OODB $oodb, RedBean_ToolBox $toolBox ) {
  4752. $this->oodb = $oodb;
  4753. $this->writer = $toolBox->getWriter();
  4754. }
  4755. /**
  4756. * Adds event listener.
  4757. *
  4758. * @param string $event event identifier
  4759. * @param RedBean_Observer $observer observer
  4760. */
  4761. public function addEventListener($event, RedBean_Observer $o) {
  4762. $this->oodb->addEventListener($event, $o);
  4763. }
  4764. /**
  4765. * Generates a key based on the ID and TYPE of a bean to
  4766. * identify the bean in the cache.
  4767. *
  4768. * @param RedBean_OODBBean $bean bean to make fingerprint of
  4769. *
  4770. * @return string $key fingerprint of bean
  4771. */
  4772. private function generateKey( RedBean_OODBBean $bean ) {
  4773. $type=$bean->getMeta("type");
  4774. $idfield = $this->writer->getIDField($type);
  4775. $id = $bean->$idfield;
  4776. return sha1($type."-".$id);
  4777. }
  4778. /**
  4779. * Puts a bean in the cache and stores a copy of the bean in the
  4780. * cache archive.
  4781. *
  4782. * @param RedBean_OODBBean $bean bean to put in cache
  4783. *
  4784. * @return RedBean_Plugin_Cache $myself chainable
  4785. */
  4786. private function putInCache( RedBean_OODBBean $bean ) {
  4787. $key = $this->generateKey($bean);
  4788. $this->cache[$key]=$bean;
  4789. $copy = clone $bean;
  4790. $copy->copyMetaFrom($bean);
  4791. $this->originals[ $key ] = $copy;
  4792. return $this;
  4793. }
  4794. /**
  4795. * Fetches a bean from the cache or returns NULL.
  4796. *
  4797. * @param RedBean_OODBBean $bean bean
  4798. *
  4799. * @return RedBean_OODBBean $bean bean
  4800. */
  4801. private function fetchFromCache( RedBean_OODBBean $bean ) {
  4802. $key = $this->generateKey($bean);
  4803. if (isset($this->cache[$key])) {
  4804. return $this->cache[$key];
  4805. }
  4806. else {
  4807. return NULL;
  4808. }
  4809. }
  4810. /**
  4811. * Fetches a bean from the cache or returns NULL.
  4812. * This function takes a TYPE and ID.
  4813. *
  4814. * @param string $type type
  4815. * @param integer $id id
  4816. *
  4817. * @return RedBean_OODBBean $bean
  4818. */
  4819. private function fetchFromCacheByTypeID( $type, $id ) {
  4820. $bean = $this->oodb->dispense($type);
  4821. $idfield = $this->writer->getIDField($type);
  4822. $bean->$idfield = $id;
  4823. return $this->fetchFromCache($bean);
  4824. }
  4825. /**
  4826. * Fetches the original bean as it was stored in the cache
  4827. * archive or NULL.
  4828. *
  4829. * @param RedBean_OODBBean $bean bean
  4830. *
  4831. * @return RedBean_OODBBean $bean bean
  4832. */
  4833. private function fetchOriginal(RedBean_OODBBean $bean) {
  4834. $key = $this->generateKey($bean);
  4835. if (isset($this->originals[$key])) {
  4836. return $this->originals[$key];
  4837. }
  4838. else {
  4839. return NULL;
  4840. }
  4841. }
  4842. /**
  4843. * Removes a bean from the cache and the archive.
  4844. *
  4845. * @param RedBean_OODBBean $bean bean
  4846. */
  4847. private function removeFromCache( RedBean_OODBBean $bean ) {
  4848. $key = $this->generateKey($bean);
  4849. unset($this->cache[$key]);
  4850. unset($this->originals[$key]);
  4851. return $this;
  4852. }
  4853. /**
  4854. * Tries to load a bean from cache, if this fails, it asks
  4855. * the oodb object to load the bean from the database.
  4856. *
  4857. * @param string $type type of bean to load
  4858. * @param integer $id primary key of bean
  4859. *
  4860. * @return RedBean_OODB $bean the bean that was found in cache or DB
  4861. */
  4862. public function load( $type, $id ) {
  4863. $bean = $this->fetchFromCacheByTypeID($type, $id);
  4864. if ($bean) {
  4865. return $bean;
  4866. }
  4867. else {
  4868. $bean = $this->oodb->load($type, $id);
  4869. $this->putInCache($bean);
  4870. return $bean;
  4871. }
  4872. }
  4873. /**
  4874. * Stores a bean and updates cache.
  4875. *
  4876. * @param RedBean_OODBBean $bean bean
  4877. *
  4878. * @return integer $id id
  4879. */
  4880. public function store( RedBean_OODBBean $bean ) {
  4881. $this->columnCounter = 0;
  4882. $type=$bean->getMeta("type");
  4883. $idfield = $this->writer->getIDField($type);
  4884. $newbean = $this->oodb->dispense($type);
  4885. $newbean->$idfield = $bean->$idfield;
  4886. $oldBean = $this->fetchOriginal($bean);
  4887. if ($oldBean) {
  4888. $dirty = false;
  4889. foreach($oldBean as $p=>$v) {
  4890. if ($v !== $bean->$p && $p!=$idfield) {
  4891. $newbean->$p = $bean->$p;
  4892. $this->columnCounter++;
  4893. $dirty=true;
  4894. }
  4895. }
  4896. foreach($bean as $p=>$v) {
  4897. if (!isset($oldBean->$p)) {
  4898. $dirty=true;
  4899. $newbean->$p = $bean->$p;
  4900. $this->columnCounter++;
  4901. }
  4902. }
  4903. if ($dirty) {
  4904. $newbean->copyMetaFrom($bean);
  4905. $id = $this->oodb->store($newbean);
  4906. $bean->copyMetaFrom($newbean);
  4907. $this->putInCache($bean);
  4908. return $id;
  4909. }
  4910. else {
  4911. return $bean->$idfield;
  4912. }
  4913. }
  4914. else {
  4915. $id = $this->oodb->store($bean);
  4916. $this->putInCache($bean);
  4917. return $id;
  4918. }
  4919. }
  4920. /**
  4921. * Trashes a bean and removes the bean from cache.
  4922. * @param RedBean_OODBBean $bean
  4923. */
  4924. public function trash( RedBean_OODBBean $bean ) {
  4925. $this->removeFromCache($bean);
  4926. return $this->oodb->trash($bean);
  4927. }
  4928. /**
  4929. * Loads a batch of beans all at once.
  4930. * This function first inspects the cache; if every element in the batch
  4931. * is available in the cache, the function will return the collected beans
  4932. * from the cache. If one or more beans cannot be found, the function will
  4933. * ask oodb for the beans and update the cache.
  4934. *
  4935. * @param string $type type you are looking for
  4936. * @param integer $ids series of keys of beans you want to load in memory
  4937. *
  4938. * @return array $beans collection of beans
  4939. */
  4940. public function batch( $type, $ids ) {
  4941. $idfield = $this->writer->getIDField($type);
  4942. $collect = array();
  4943. foreach($ids as $id) {
  4944. $bean = $this->fetchFromCacheByTypeID($type, $id);
  4945. if ($bean) $collect[$id] = $bean;
  4946. }
  4947. if (count($collect) == count($ids)) {
  4948. return $collect;
  4949. }
  4950. else {
  4951. $beans = $this->oodb->batch($type, $ids);
  4952. foreach($beans as $bean) {
  4953. $this->putInCache( $bean );
  4954. }
  4955. return $beans;
  4956. }
  4957. }
  4958. /**
  4959. * Dispenses a bean, just like oodb does
  4960. *
  4961. * @param string $type type of the bean
  4962. *
  4963. * @return RedBean_OODBBean $bean freshly dispensed bean
  4964. */
  4965. public function dispense( $type ) {
  4966. return $this->oodb->dispense($type);
  4967. }
  4968. /**
  4969. * For testing only; returns the number of properties that has
  4970. * been updated in the latest store action.
  4971. *
  4972. * @return integer $count count
  4973. */
  4974. public function test_getColCount() {
  4975. return $this->columnCounter;
  4976. }
  4977. /**
  4978. * Added to comply with new interface Object Database
  4979. */
  4980. /**
  4981. * Returns the number of beans we have in DB of a given type.
  4982. *
  4983. * @todo implement Caching here
  4984. *
  4985. * @param string $type type of bean we are looking for
  4986. *
  4987. * @return integer $num number of beans found
  4988. */
  4989. public function count($type) {
  4990. try {
  4991. return (int) $this->writer->count($type);
  4992. }catch(RedBean_Exception_SQL $e) {
  4993. if (!$this->writer->sqlStateIn($e->getSQLState(),
  4994. array(RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  4995. )) throw $e;
  4996. }
  4997. return 0;
  4998. }
  4999. /**
  5000. * Trash all beans of a given type.
  5001. *
  5002. * @param string $type type
  5003. *
  5004. * @return boolean $yesNo whether we actually did some work or not..
  5005. */
  5006. public function wipe($type) {
  5007. try {
  5008. $this->writer->wipe($type);
  5009. $this->cache = array();
  5010. $this->originals = array();
  5011. return true;
  5012. }catch(RedBean_Exception_SQL $e) {
  5013. if (!$this->writer->sqlStateIn($e->getSQLState(),
  5014. array(RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  5015. )) throw $e;
  5016. }
  5017. return false;
  5018. }
  5019. }
  5020. /**
  5021. * RedBean Bean Finder
  5022. *
  5023. * @file RedBean/Plugin/Finder.php
  5024. * @description Provides a more convenient way to find beans
  5025. *
  5026. * @author Gabor de Mooij
  5027. * @license BSD
  5028. *
  5029. *
  5030. * (c) G.J.G.T. (Gabor) de Mooij
  5031. * This source file is subject to the BSD/GPLv2 License that is bundled
  5032. * with this source code in the file license.txt.
  5033. */
  5034. class RedBean_Plugin_Finder implements RedBean_Plugin {
  5035. /**
  5036. * Fetches a collection of OODB Bean objects based on the SQL
  5037. * criteria provided. For instance;
  5038. *
  5039. * - RedBean_Plugin_Finder::where("page", " name LIKE '%more%' ");
  5040. *
  5041. * Will return all pages that have the word 'more' in their name.
  5042. * The second argument is actually just plain SQL; the function expects
  5043. * this SQL to be compatible with a SELECT * FROM TABLE WHERE X query,
  5044. * where X is ths search string you provide in the second parameter.
  5045. * Another example, using slots:
  5046. *
  5047. * - RedBean_Plugin_Finder::where("page", " name LIKE :str ",array(":str"=>'%more%'));
  5048. *
  5049. * Also, note that the default search is always 1. So if you do not
  5050. * specify a search parameter this function will just return every
  5051. * bean of the given type:
  5052. *
  5053. * - RedBean_Plugin_Finder::where("page");
  5054. *
  5055. *
  5056. * @param string $type type of bean you are looking for
  5057. * @param string $SQL SQL code, start with 1 if you want no WHERE-clause
  5058. * @param array $values values to bind to slots in query
  5059. *
  5060. * @return array $beans beans we come up with..
  5061. */
  5062. public static function where( $type, $SQL = " 1 ", $values=array(),
  5063. $tools = false, $ignoreGSQLWarn = false ) {
  5064. if ($SQL==="") $SQL = " 1 ";
  5065. $type = preg_replace("/\W/","", $type);
  5066. if (!$tools) $tools = RedBean_Setup::getToolBox();
  5067. RedBean_CompatManager::scanDirect($tools, array(
  5068. RedBean_CompatManager::C_SYSTEM_MYSQL => "5",
  5069. RedBean_CompatManager::C_SYSTEM_SQLITE => "3",
  5070. RedBean_CompatManager::C_SYSTEM_POSTGRESQL => "7"
  5071. ));
  5072. $redbean = $tools->getRedBean();
  5073. $adapter = $tools->getDatabaseAdapter();
  5074. $writer = $tools->getWriter();
  5075. if (!$redbean->isFrozen()) {
  5076. $SQL = self::parseGoldSQL($SQL, $type, $tools);
  5077. }
  5078. else {
  5079. if (!$ignoreGSQLWarn && strpos($SQL,"@")!==false) {
  5080. throw new RedBean_Exception_SQL("Gold SQL is
  5081. only allowed in FLUID mode,
  5082. to ignore use extra argument TRUE for RedBean_Plugin_Finder::Where");
  5083. }
  5084. }
  5085. $table = $writer->getFormattedTableName($type);
  5086. try {
  5087. $SQL = "SELECT * FROM $table WHERE ".$SQL;
  5088. $rows = $adapter->get($SQL, $values);
  5089. }
  5090. catch(RedBean_Exception_SQL $e) {
  5091. if ($writer->sqlStateIn($e->getSQLState(),array(
  5092. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  5093. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE
  5094. ))) {
  5095. return array();
  5096. }
  5097. else {
  5098. throw $e;
  5099. }
  5100. }
  5101. return $redbean->convertToBeans($type, $rows);
  5102. }
  5103. /**
  5104. * Parses Gold SQL.
  5105. * Checks whether columns and tables prefixed with @ exists,
  5106. * if not they are being replaced by NULL leaving intact the
  5107. * rest of the query and making the SQL continue to work even
  5108. * if it's partially broken.
  5109. *
  5110. * @param string $SQL sql code to execute
  5111. * @param string $currentTable name of the table
  5112. * @param RedBean_ToolBox $toolbox toolbox to use
  5113. *
  5114. * @return string $SQL resulting sql
  5115. */
  5116. public static function parseGoldSQL( $SQL, $currentTable, RedBean_ToolBox $toolbox ) {
  5117. $writer = $toolbox->getWriter();
  5118. $matches = array();
  5119. $pattern = "/@[\w\.]+/";
  5120. if (preg_match_all($pattern, $SQL, $matches)) {
  5121. $columns = array_keys( $toolbox->getWriter()->getColumns($currentTable) );
  5122. $tables = $writer->getTables();
  5123. $checks = array_shift( $matches );
  5124. foreach($checks as $checkItem) {
  5125. $itemName = substr($checkItem, 1);
  5126. if (strpos($itemName,".")!==false) {
  5127. list($table, $column) = explode(".", $itemName);
  5128. if (!in_array($table, $tables)) {
  5129. $SQL = str_replace("@".$itemName, "NULL", $SQL);
  5130. }
  5131. else {
  5132. $tableCols = array_keys( $toolbox->getWriter()->getColumns($table) );
  5133. if (!in_array($column, ($tableCols))) {
  5134. $SQL = str_replace("@".$itemName, "NULL", $SQL);
  5135. }
  5136. else {
  5137. $SQL = str_replace("@".$itemName, $itemName, $SQL);
  5138. }
  5139. }
  5140. }
  5141. else {
  5142. if (!in_array($itemName, ($columns))) {
  5143. $SQL = str_replace("@".$itemName, "NULL", $SQL);
  5144. }
  5145. else {
  5146. $SQL = str_replace("@".$itemName, $itemName, $SQL);
  5147. }
  5148. }
  5149. }
  5150. }
  5151. return $SQL;
  5152. }
  5153. }
  5154. /**
  5155. * RedBean Bean Constraint
  5156. * @file RedBean/Plugin/Constraint.php
  5157. * @description Adds Cascaded Delete functionality for a pair of beans
  5158. *
  5159. * @author Gabor de Mooij
  5160. * @license BSD
  5161. *
  5162. *
  5163. * (c) G.J.G.T. (Gabor) de Mooij
  5164. * This source file is subject to the BSD/GPLv2 License that is bundled
  5165. * with this source code in the file license.txt.
  5166. */
  5167. class RedBean_Plugin_Constraint {
  5168. /**
  5169. *
  5170. * @var array
  5171. * Keeps track of foreign keys (only to improve fluid performance)
  5172. */
  5173. private static $fkcache = array();
  5174. private static $toolbox = null;
  5175. public static function setToolBox( RedBean_ToolBox $toolbox ) {
  5176. self::$toolbox = $toolbox;
  5177. }
  5178. /**
  5179. * Ensures that given an association between
  5180. * $bean1 and $bean2,
  5181. * if one of them gets trashed the association will be
  5182. * automatically removed.
  5183. *
  5184. * @param RedBean_OODBBean $bean1 bean
  5185. * @param RedBean_OODBBean $bean2 bean
  5186. *
  5187. * @return boolean $addedFKS whether we succeeded
  5188. */
  5189. public static function addConstraint( RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, $dontCache = false ) {
  5190. if ((self::$toolbox)) {
  5191. $toolbox = self::$toolbox;
  5192. }
  5193. else {
  5194. $toolbox = RedBean_Setup::getToolBox();
  5195. }
  5196. RedBean_CompatManager::scanDirect($toolbox, array(
  5197. RedBean_CompatManager::C_SYSTEM_MYSQL => "5",
  5198. RedBean_CompatManager::C_SYSTEM_SQLITE => "3",
  5199. RedBean_CompatManager::C_SYSTEM_POSTGRESQL => "7",));
  5200. $association = new RedBean_AssociationManager( $toolbox );
  5201. $writer = $toolbox->getWriter();
  5202. $oodb = $toolbox->getRedBean();
  5203. $adapter = $toolbox->getDatabaseAdapter();
  5204. if ($oodb->isFrozen()) return false;
  5205. $table1 = $bean1->getMeta("type");
  5206. $table2 = $bean2->getMeta("type");
  5207. $table = $association->getTable( array( $table1,$table2) );
  5208. $idfield1 = $writer->getIDField($bean1->getMeta("type"));
  5209. $idfield2 = $writer->getIDField($bean2->getMeta("type"));
  5210. $bean = $oodb->dispense($table);
  5211. $property1 = $bean1->getMeta("type") . "_id";
  5212. $property2 = $bean2->getMeta("type") . "_id";
  5213. if ($property1==$property2) $property2 = $bean2->getMeta("type")."2_id";
  5214. $table = $adapter->escape($table);
  5215. $table1 = $adapter->escape($table1);
  5216. $table2 = $adapter->escape($table2);
  5217. $property1 = $adapter->escape($property1);
  5218. $property2 = $adapter->escape($property2);
  5219. $fkCode = "fk".md5($table.$property1.$property2);
  5220. if (isset(self::$fkcache[$fkCode])) return false;
  5221. try {
  5222. if ($writer instanceof RedBean_QueryWriter_PostgreSQL) {
  5223. return self::constraintPostgreSQL($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache);
  5224. }
  5225. if ($writer instanceof RedBean_QueryWriter_SQLite) {
  5226. return self::constraintSQLite($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache);
  5227. }
  5228. if ($writer instanceof RedBean_QueryWriter_MySQL) {
  5229. return self::constraintMySQL($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache);
  5230. }
  5231. }
  5232. catch(RedBean_Exception_SQL $e) {
  5233. if (!$writer->sqlStateIn($e->getSQLState(),
  5234. array(
  5235. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  5236. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  5237. )) throw $e;
  5238. }
  5239. return false;
  5240. }
  5241. /**
  5242. * Add the constraints for a specific database driver: PostgreSQL.
  5243. * @todo Too many arguments; find a way to solve this in a neater way.
  5244. *
  5245. * @param RedBean_ToolBox $toolbox toolbox
  5246. * @param string $table table
  5247. * @param string $table1 table1
  5248. * @param string $table2 table2
  5249. * @param string $property1 property1
  5250. * @param string $property2 property2
  5251. * @param boolean $dontCache want to have cache?
  5252. *
  5253. * @return boolean $succes whether the constraint has been applied
  5254. */
  5255. private static function constraintPostgreSQL($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache) {
  5256. $writer = $toolbox->getWriter();
  5257. $oodb = $toolbox->getRedBean();
  5258. $adapter = $toolbox->getDatabaseAdapter();
  5259. $fkCode = "fk".md5($table.$property1.$property2);
  5260. $sql = "
  5261. SELECT
  5262. c.oid,
  5263. n.nspname,
  5264. c.relname,
  5265. n2.nspname,
  5266. c2.relname,
  5267. cons.conname
  5268. FROM pg_class c
  5269. JOIN pg_namespace n ON n.oid = c.relnamespace
  5270. LEFT OUTER JOIN pg_constraint cons ON cons.conrelid = c.oid
  5271. LEFT OUTER JOIN pg_class c2 ON cons.confrelid = c2.oid
  5272. LEFT OUTER JOIN pg_namespace n2 ON n2.oid = c2.relnamespace
  5273. WHERE c.relkind = 'r'
  5274. AND n.nspname IN ('public')
  5275. AND (cons.contype = 'f' OR cons.contype IS NULL)
  5276. AND
  5277. ( cons.conname = '{$fkCode}a' OR cons.conname = '{$fkCode}b' )
  5278. ";
  5279. $rows = $adapter->get( $sql );
  5280. if (!count($rows)) {
  5281. $table = $writer->getFormattedTableName($table);
  5282. $table1 = $writer->getFormattedTableName($table1);
  5283. $table2 = $writer->getFormattedTableName($table2);
  5284. if (!$dontCache) self::$fkcache[ $fkCode ] = true;
  5285. $sql1 = "ALTER TABLE $table ADD CONSTRAINT
  5286. {$fkCode}a FOREIGN KEY ($property1)
  5287. REFERENCES $table1 (id) ON DELETE CASCADE ";
  5288. $sql2 = "ALTER TABLE $table ADD CONSTRAINT
  5289. {$fkCode}b FOREIGN KEY ($property2)
  5290. REFERENCES $table2 (id) ON DELETE CASCADE ";
  5291. $adapter->exec($sql1);
  5292. $adapter->exec($sql2);
  5293. }
  5294. return true;
  5295. }
  5296. /**
  5297. * Add the constraints for a specific database driver: MySQL.
  5298. * @todo Too many arguments; find a way to solve this in a neater way.
  5299. *
  5300. * @param RedBean_ToolBox $toolbox toolbox
  5301. * @param string $table table
  5302. * @param string $table1 table1
  5303. * @param string $table2 table2
  5304. * @param string $property1 property1
  5305. * @param string $property2 property2
  5306. * @param boolean $dontCache want to have cache?
  5307. *
  5308. * @return boolean $succes whether the constraint has been applied
  5309. */
  5310. private static function constraintMySQL($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache) {
  5311. $writer = $toolbox->getWriter();
  5312. $oodb = $toolbox->getRedBean();
  5313. $adapter = $toolbox->getDatabaseAdapter();
  5314. $db = $adapter->getCell("select database()");
  5315. $fkCode = "fk".md5($table.$property1.$property2);
  5316. $fks = $adapter->getCell("
  5317. SELECT count(*)
  5318. FROM information_schema.KEY_COLUMN_USAGE
  5319. WHERE TABLE_SCHEMA ='$db' AND TABLE_NAME ='".$writer->getFormattedTableName($table)."' AND
  5320. CONSTRAINT_NAME <>'PRIMARY' AND REFERENCED_TABLE_NAME is not null
  5321. ");
  5322. if ($fks>0) return false;
  5323. if (!$dontCache) self::$fkcache[ $fkCode ] = true;
  5324. $columns = $writer->getColumns($table);
  5325. if ($writer->code($columns[$property1])!==RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32) {
  5326. $writer->widenColumn($table, $property1, RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32);
  5327. }
  5328. if ($writer->code($columns[$property2])!==RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32) {
  5329. $writer->widenColumn($table, $property2, RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32);
  5330. }
  5331. $table = $writer->getFormattedTableName($table);
  5332. $table1 = $writer->getFormattedTableName($table1);
  5333. $table2 = $writer->getFormattedTableName($table2);
  5334. $sql = "
  5335. ALTER TABLE ".$writer->noKW($table)."
  5336. ADD FOREIGN KEY($property1) references $table1(id) ON DELETE CASCADE;
  5337. ";
  5338. $adapter->exec( $sql );
  5339. $sql ="
  5340. ALTER TABLE ".$writer->noKW($table)."
  5341. ADD FOREIGN KEY($property2) references $table2(id) ON DELETE CASCADE
  5342. ";
  5343. $adapter->exec( $sql );
  5344. return true;
  5345. }
  5346. /**
  5347. * Add the constraints for a specific database driver: SQLite.
  5348. * @todo Too many arguments; find a way to solve this in a neater way.
  5349. *
  5350. * @param RedBean_ToolBox $toolbox toolbox
  5351. * @param string $table table
  5352. * @param string $table1 table1
  5353. * @param string $table2 table2
  5354. * @param string $property1 property1
  5355. * @param string $property2 property2
  5356. * @param boolean $dontCache want to have cache?
  5357. *
  5358. * @return boolean $succes whether the constraint has been applied
  5359. */
  5360. private static function constraintSQLite($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache) {
  5361. $writer = $toolbox->getWriter();
  5362. $oodb = $toolbox->getRedBean();
  5363. $adapter = $toolbox->getDatabaseAdapter();
  5364. $fkCode = "fk".md5($table.$property1.$property2);
  5365. $table = $writer->getFormattedTableName($table);
  5366. $table1 = $writer->getFormattedTableName($table1);
  5367. $table2 = $writer->getFormattedTableName($table2);
  5368. $sql1 = "
  5369. CREATE TRIGGER IF NOT EXISTS {$fkCode}a
  5370. BEFORE DELETE ON $table1
  5371. FOR EACH ROW BEGIN
  5372. DELETE FROM $table WHERE $table.$property1 = OLD.id;
  5373. END;
  5374. ";
  5375. $sql2 = "
  5376. CREATE TRIGGER IF NOT EXISTS {$fkCode}b
  5377. BEFORE DELETE ON $table2
  5378. FOR EACH ROW BEGIN
  5379. DELETE FROM $table WHERE $table.$property2 = OLD.id;
  5380. END;
  5381. ";
  5382. $adapter->exec($sql1);
  5383. $adapter->exec($sql2);
  5384. return true;
  5385. }
  5386. }
  5387. /**
  5388. * @name RedBean IBeanFormatter
  5389. * @file RedBean/IBeanFormatter.php
  5390. * @author Gabor de Mooij and the RedBean Team
  5391. * @copyright Gabor de Mooij (c)
  5392. * @license BSD
  5393. *
  5394. * The RedBean IBeanFormatter interface describes what methods
  5395. * a BeanFormatter class should implement.
  5396. *
  5397. *
  5398. * (c) G.J.G.T. (Gabor) de Mooij
  5399. * This source file is subject to the BSD/GPLv2 License that is bundled
  5400. * with this source code in the file license.txt.
  5401. */
  5402. interface RedBean_IBeanFormatter {
  5403. /**
  5404. *
  5405. * @param string $type type
  5406. */
  5407. public function formatBeanTable( $type );
  5408. /**
  5409. *
  5410. * @param string $type type
  5411. */
  5412. public function formatBeanID( $type );
  5413. }
  5414. /*
  5415. * @author Gabor de Mooij
  5416. * @license BSD
  5417. *
  5418. *
  5419. * (c) G.J.G.T. (Gabor) de Mooij
  5420. * This source file is subject to the BSD/GPLv2 License that is bundled
  5421. * with this source code in the file license.txt.
  5422. * Interface definition of a Model Formatter for Fuse
  5423. */
  5424. interface RedBean_IModelFormatter {
  5425. /**
  5426. * ModelHelper will call this method of the class
  5427. * you provide to discover the model
  5428. *
  5429. * @param string $model
  5430. *
  5431. * @return string $formattedModel
  5432. */
  5433. public function formatModel( $model );
  5434. }
  5435. /**
  5436. * @deprecated
  5437. *
  5438. * RedBean Domain Object
  5439. * @file RedBean/DomainObject.php
  5440. * @description This class serves as a source of inspiration and
  5441. * is an example how a layer super type pattern can be
  5442. * used with RedBean. This class has not been tested.
  5443. * @author Gabor de Mooij
  5444. * @license BSD
  5445. *
  5446. *
  5447. * (c) G.J.G.T. (Gabor) de Mooij
  5448. * This source file is subject to the BSD/GPLv2 License that is bundled
  5449. * with this source code in the file license.txt.
  5450. *
  5451. */
  5452. abstract class RedBean_DomainObject {
  5453. /**
  5454. *
  5455. * @var RedBean_ToolBox
  5456. */
  5457. protected $tools;
  5458. /**
  5459. *
  5460. * @var RedBean_OODB
  5461. */
  5462. protected $redbean;
  5463. /**
  5464. *
  5465. * @var RedBean_OODBBean
  5466. */
  5467. protected $bean;
  5468. /**
  5469. *
  5470. * @var RedBean_AssociationManager
  5471. */
  5472. protected $associationManager;
  5473. /**
  5474. *
  5475. * @var RedBean_TreeManager
  5476. */
  5477. protected $treeManager;
  5478. /**
  5479. *
  5480. * Constructor, requires a type name
  5481. * @param string $typeName typename
  5482. */
  5483. public function __construct( $typeName = false ) {
  5484. /**
  5485. * If no typeName has been specified,
  5486. * figure out the type of this model yourself.
  5487. * In this case the following rule applies:
  5488. * - the name of the model is the LAST part of the
  5489. * namespace.
  5490. * - Within that string, the name of the model is the LAST
  5491. * part of the poorman's name space.
  5492. *
  5493. * So the model name for class: /me/him/her is: her
  5494. * So the model name for class: /me/him/her_lover is: lover
  5495. */
  5496. if (!$typeName) {
  5497. $beanTypeName = get_class( $this );
  5498. $a = explode( "\\" , $beanTypeName );
  5499. $lastInNameSpace = array_pop( $a );
  5500. $a = explode( "_" , $lastInNameSpace );
  5501. $lastInPoormanNameSpace = array_pop( $a );
  5502. $beanTypeName = $lastInPoormanNameSpace;
  5503. }
  5504. else {
  5505. $beanTypeName = $typeName;
  5506. }
  5507. /*
  5508. * Now do a little check to see whether this name
  5509. * can be used. - Just a quick check, we will re-check later on
  5510. */
  5511. if ($beanTypeName && strlen($beanTypeName)>0) {
  5512. $this->tools = RedBean_Setup::getToolBox();
  5513. $this->redbean = $this->tools->getRedBean();
  5514. $this->bean = $this->redbean->dispense( strtolower( $beanTypeName ) );
  5515. $this->associationManager = new RedBean_AssociationManager($this->tools);
  5516. $this->treeManager = new RedBean_TreeManager($this->tools);
  5517. }
  5518. else {
  5519. throw new Exception("Invalid Domain Object TypeName");
  5520. }
  5521. }
  5522. /**
  5523. * Associates the bean inside with another OODBBean
  5524. *
  5525. * @param RedBean_DomainObject $other other
  5526. */
  5527. protected function associate(RedBean_DomainObject $other) {
  5528. $this->associationManager->associate($this->bean, $other->bean);
  5529. }
  5530. /**
  5531. * Breaks the association between this OODBBean an the one belonging
  5532. * to the other model.
  5533. *
  5534. * @param RedBean_DomainObject $other other
  5535. */
  5536. protected function unassociate(RedBean_DomainObject $other) {
  5537. $this->associationManager->unassociate($this->bean, $other->bean);
  5538. }
  5539. /**
  5540. * Fetches related domain objects.
  5541. *
  5542. * @param string $className class name
  5543. * @param mixed $constructorArg constructor arguments
  5544. *
  5545. * @return mixed $models
  5546. */
  5547. protected function related( $className, $constructorArg = null ) {
  5548. $models = array();
  5549. $model = new $className;
  5550. $keys = $this->associationManager->related($this->bean, $model->getBeanType());
  5551. foreach($keys as $key) {
  5552. $modelItem = new $className($constructorArg);
  5553. $modelItem->find( (int) $key );
  5554. $models[$key] = $modelItem;
  5555. }
  5556. return $models;
  5557. }
  5558. /**
  5559. * Returns the type of the bean.
  5560. *
  5561. * @return string $type type
  5562. */
  5563. protected function getBeanType() {
  5564. return $this->bean->getMeta("type");
  5565. }
  5566. /**
  5567. * Clears associations
  5568. */
  5569. protected function clearRelations( $type ) {
  5570. $this->associationManager->clearRelations($this->bean, $type);
  5571. }
  5572. /**
  5573. * Attach
  5574. *
  5575. * @param RedBean_DomainObject $other other
  5576. */
  5577. protected function attach(RedBean_DomainObject $other) {
  5578. $this->treeManager->attach($this->bean, $other->bean);
  5579. }
  5580. /**
  5581. * Loads the Bean internally
  5582. *
  5583. * @param integer $id id
  5584. */
  5585. public function find( $id ) {
  5586. $this->bean = $this->redbean->load( $this->bean->getMeta("type"), (int) $id );
  5587. }
  5588. /**
  5589. * Saves the current domain object.
  5590. * The function saves the inner bean to the database.
  5591. */
  5592. public function save() {
  5593. $this->redbean->store( $this->bean );
  5594. }
  5595. /**
  5596. * Deletes the inner bean from the database.
  5597. */
  5598. public function delete() {
  5599. $this->redbean->trash( $this->bean );
  5600. }
  5601. /**
  5602. * Returns the ID of the Model.
  5603. */
  5604. public function getID() {
  5605. $idField = $this->tools->getWriter()->getIDField( $this->bean->getMeta("type") );
  5606. return $this->bean->$idField;
  5607. }
  5608. /**
  5609. * Exports bean.
  5610. *
  5611. * @return array $array array
  5612. */
  5613. public function export() {
  5614. return $this->bean;
  5615. }
  5616. /**
  5617. * Exports beans.
  5618. *
  5619. * @return array $array array
  5620. */
  5621. public static function exportAll( $objects ) {
  5622. $beans = array();
  5623. foreach($objects as $object) {
  5624. $beans[] = $object->export();
  5625. }
  5626. return $beans;
  5627. }
  5628. /**
  5629. * Loads bean.
  5630. *
  5631. * @param RedBean_OODBBean $bean bean to load
  5632. */
  5633. public function loadBean( RedBean_OODBBean $bean ) {
  5634. $this->bean = $bean;
  5635. }
  5636. }
  5637. /**
  5638. * Optimizer
  5639. * @file RedBean/Optimizer.php
  5640. * @author Gabor de Mooij
  5641. * @license BSD
  5642. *
  5643. *
  5644. * (c) G.J.G.T. (Gabor) de Mooij
  5645. * This source file is subject to the BSD/GPLv2 License that is bundled
  5646. * with this source code in the file license.txt.
  5647. */
  5648. class RedBean_Plugin_Optimizer extends RedBean_CompatManager implements RedBean_Plugin,RedBean_Observer {
  5649. /**
  5650. * Specify what database systems are supported by this class.
  5651. * @var array $databaseSpecs
  5652. */
  5653. protected $supportedSystems = array(
  5654. RedBean_CompatManager::C_SYSTEM_MYSQL => "5"
  5655. );
  5656. /**
  5657. * @var RedBean_Adapter_DBAdapter
  5658. * Contains a reference to the database adapter.
  5659. */
  5660. private $adapter;
  5661. /**
  5662. * @var RedBean_OODB
  5663. * Contains a reference to the RedBean OODB object.
  5664. */
  5665. private $oodb;
  5666. /**
  5667. * @var RedBean_QueryWriter_MySQL
  5668. * Contains a reference to the query writer.
  5669. */
  5670. private $writer;
  5671. /**
  5672. * Contains an array filled with optimizers.
  5673. * @var RedBean_Plugin_IOptimizer $optimizers
  5674. */
  5675. protected $optimizers = array();
  5676. /**
  5677. * Constructor
  5678. * Handles the toolbox
  5679. *
  5680. * @param RedBean_ToolBox $toolbox
  5681. */
  5682. public function __construct( RedBean_ToolBox $toolbox ) {
  5683. $this->scanToolBox( $toolbox );
  5684. $this->oodb = $toolbox->getRedBean();
  5685. $this->adapter = $toolbox->getDatabaseAdapter();
  5686. $this->writer = $toolbox->getWriter();
  5687. }
  5688. /**
  5689. * Runs optimization Queue.
  5690. *
  5691. * @param string $table table to optimize
  5692. * @param string $column column to optimize
  5693. * @param string $value value to scan
  5694. *
  5695. */
  5696. protected function optimize($table,$column,$value) {
  5697. foreach($this->optimizers as $optimizer) {
  5698. $optimizer->setTable($table);
  5699. $optimizer->setColumn($column);
  5700. $optimizer->setValue($value);
  5701. if (!$optimizer->optimize()) break;
  5702. }
  5703. }
  5704. /**
  5705. * Does an optimization cycle for each UPDATE event.
  5706. *
  5707. * @param string $event event
  5708. * @param RedBean_OODBBean $bean bean
  5709. *
  5710. * @return void
  5711. */
  5712. public function onEvent( $event , $bean ) {
  5713. try {
  5714. if ($event=="update") {
  5715. $arr = $bean->export();
  5716. unset($arr["id"]);
  5717. if (count($arr)==0) return;
  5718. $table = $this->adapter->escape($bean->getMeta("type"));
  5719. $columns = array_keys($arr);
  5720. $column = $this->adapter->escape($columns[ array_rand($columns) ]);
  5721. $value = $arr[$column];
  5722. $this->optimize($table,$column,$value);
  5723. }
  5724. }catch(RedBean_Exception_SQL $e) {
  5725. }
  5726. }
  5727. /**
  5728. * Adds an optimizer to the optimizer collection.
  5729. *
  5730. * @param RedBean_Plugin_IOptimizer $optimizer
  5731. */
  5732. public function addOptimizer(RedBean_Plugin_IOptimizer $optimizer) {
  5733. $this->optimizers[] = $optimizer;
  5734. }
  5735. }
  5736. /**
  5737. * RedBean BeanMachine
  5738. *
  5739. * @file RedBean/BeanMachine.php
  5740. * @description Query Building System for Bean Machinery
  5741. * @author Gabor de Mooij
  5742. * @license BSD
  5743. *
  5744. * (c) G.J.G.T. (Gabor) de Mooij
  5745. * This source file is subject to the BSD/GPLv2 License that is bundled
  5746. * with this source code in the file license.txt.
  5747. */
  5748. class RedBean_Plugin_BeanMachine implements RedBean_Plugin {
  5749. /**
  5750. * @var RedBean_Plugin_BeanMachine_Group
  5751. */
  5752. protected $groups = null;
  5753. /**
  5754. * @var RedBean_Plugin_BeanMachine_Group
  5755. */
  5756. protected $selected = null;
  5757. /**
  5758. * @var array
  5759. */
  5760. protected $parameters = array();
  5761. /**
  5762. * @var array
  5763. */
  5764. protected $bookmarks = array();
  5765. /**
  5766. *
  5767. * Toolbox
  5768. * @var RedBean_ToolBox
  5769. */
  5770. protected $toolbox = null;
  5771. /**
  5772. * Initializes the Bean Machine
  5773. * @return void
  5774. */
  5775. private static function init() {
  5776. if (!class_exists("RedBean_Plugin_BeanMachine_Group")) {
  5777. RedBean_Plugin_BeanMachine_InnerClasses();
  5778. }
  5779. }
  5780. /**
  5781. * Private - use getInstance() instead, NOT a SINGLETON.
  5782. * Constructor bootstraps its own classes.
  5783. *
  5784. * @param RedBean_ToolBox $toolbox toolbox
  5785. *
  5786. * @return void
  5787. */
  5788. private function __construct(RedBean_ToolBox $toolbox) {
  5789. $this->groups = new RedBean_Plugin_BeanMachine_Group;
  5790. $this->groups->setTemplate("","");
  5791. $this->groups->setGlue(" \n ");
  5792. $this->selected = $this->groups;
  5793. $this->root = $this->groups;
  5794. $this->toolbox = $toolbox;
  5795. }
  5796. /**
  5797. * Gets an instance of the BeanMachine.
  5798. *
  5799. * @param RedBean_ToolBox $toolbox toolbox
  5800. *
  5801. * @return RedBean_Plugin_BeanMachine $machine the Bean Machine.
  5802. */
  5803. public static function getInstance( RedBean_ToolBox $toolbox ) {
  5804. self::init();
  5805. $inst = new self( $toolbox );
  5806. return $inst;
  5807. }
  5808. /**
  5809. * Binds a value to a key.
  5810. *
  5811. * @throws Exception
  5812. *
  5813. * @param string $key
  5814. * @param mixed $value
  5815. *
  5816. * @return void
  5817. */
  5818. public function bind( $key, $value ) {
  5819. if (isset($this->parameters[$key])) {
  5820. throw new Exception("Parameter set already!");
  5821. }
  5822. $this->parameters[$key] = $Value;
  5823. }
  5824. /**
  5825. * Finds the group in the Query and selects it, opens it.
  5826. *
  5827. * Usage:
  5828. * $q = RedBean_Plugin_BeanMachine::getInstance();
  5829. * $q->addGroup("SELECT-CLAUSE", " SELECT @ ", ",");
  5830. * ... do all kind of stuff...
  5831. * $q->openGroup("SELECT-CLAUSE");
  5832. *
  5833. *
  5834. * @throws Exception
  5835. * @param $key
  5836. * @return RedBean_Plugin_BeanMachine
  5837. */
  5838. public function openGroup( $key ) {
  5839. if (isset($this->bookmarks[$key])) {
  5840. $this->selected = $this->bookmarks[$key];
  5841. return $this;
  5842. }
  5843. throw new Exception("No Such Group");
  5844. }
  5845. /**
  5846. * Adds a new Group to the Query.
  5847. * Usage:
  5848. *
  5849. *
  5850. * $q->addGroup("WHERE-CLAUSE", " WHERE @ ", " AND ");
  5851. * $q->add(" color = :color ");
  5852. * $q->add(" smell = :smell ");
  5853. * (Outputs: WHERE color = :color AND smell = :smell )
  5854. *
  5855. *
  5856. * $q->openGroup("WHERE-CLAUSE");
  5857. * $q->addGroup("ROSES", " (@) ", " OR ");
  5858. * $q->add(" title = 'roses' ");
  5859. * $q->add(" description = 'roses' ");
  5860. *
  5861. *
  5862. * @param string $key ID to assign to this part of the Query
  5863. * @param string $template Template to use for this part of the Query, '@' is placeholder for SQL
  5864. * @param string $glue string to use to glue together SQL parts in group
  5865. *
  5866. * @return RedBean_Plugin_BeanMachine $bm Chainable
  5867. */
  5868. public function addGroup( $key, $template, $glue ) {
  5869. $this->bookmarks[$key]= $this->selected->addGroup( $key );
  5870. $this->latest = $key;
  5871. $this->bookmarks[$key]->setGlue($glue);
  5872. $templateSnippets = explode("@", $template);
  5873. $this->bookmarks[$key]->setTemplate($templateSnippets[0], $templateSnippets[1]);
  5874. return $this;
  5875. }
  5876. public function open() {
  5877. return $this->openGroup($this->latest);
  5878. }
  5879. /**
  5880. * Resets, re-selects the root group of the query.
  5881. * @return RedBean_Plugin_BeanMachine $bm Chainable
  5882. */
  5883. public function reset() {
  5884. $this->selected = $this->root;
  5885. return $this;
  5886. }
  5887. /**
  5888. * Adds a statement to the current part of the query.
  5889. *
  5890. * @throws Exception
  5891. *
  5892. * @param string $statement statement to add
  5893. *
  5894. * @return RedBean_Plugin_BeanMachine $bm Chainable
  5895. */
  5896. public function add( $statement ) {
  5897. if ($this->selected instanceof RedBean_Plugin_BeanMachine_Group) {
  5898. $this->selected->add( $statement );
  5899. }
  5900. else {
  5901. throw new Exception("No Group has been opened. Please open a group first.");
  5902. }
  5903. return $this;
  5904. }
  5905. /**
  5906. * Builds the Query, returns the string.
  5907. *
  5908. * @return string $querySQL SQL code
  5909. */
  5910. public function __toString() {
  5911. return (string) $this->groups;
  5912. }
  5913. /**
  5914. *
  5915. * Fetches a BeanMachine Plugin from the BeanMachine folder.
  5916. *
  5917. * @param string $name name ID of the BeanMachine plugin
  5918. */
  5919. public function getQueryByName( $name ) {
  5920. $className = "RedBean_Plugin_BeanMachine_".$name;
  5921. if (class_exists($className)) {
  5922. $inst = self::getInstance( $this->toolbox );
  5923. $beanMachineUser = new $className( $inst );
  5924. return $beanMachineUser;
  5925. }
  5926. else {
  5927. throw new RedBean_Exception("Could not find BeanMachine $name ", 0);
  5928. }
  5929. }
  5930. /**
  5931. *
  5932. * Produces the requested beans
  5933. *
  5934. *
  5935. */
  5936. public function getBeans($type, $machinery) {
  5937. $rows = $this->toolbox->getDatabaseAdapter()->get( $machinery );
  5938. $beanCollection = array();
  5939. foreach($rows as $row) {
  5940. $bean = $this->toolbox->getRedbean()->dispense($type);
  5941. foreach($row as $property=>$value) {
  5942. if (strpos($property,"_")===0) {
  5943. $bean->setMeta($property, $value);
  5944. }
  5945. else {
  5946. $bean->$property = $value;
  5947. }
  5948. }
  5949. $beanCollection[] = $bean;
  5950. }
  5951. return $beanCollection;
  5952. }
  5953. /**
  5954. *
  5955. * Convenience function for bean machine plugins to get hold
  5956. * of the toolbox.
  5957. *
  5958. * @return RedBean_ToolBox $toolbox toolbox
  5959. */
  5960. public function getToolBox() {
  5961. return $this->toolbox;
  5962. }
  5963. }
  5964. function RedBean_Plugin_BeanMachine_InnerClasses() {
  5965. class RedBean_Plugin_BeanMachine_Group {
  5966. private $parent = null;
  5967. private $glueChar = ",";
  5968. private $before = " ( ";
  5969. private $after = " ) ";
  5970. private $statements = array();
  5971. public function __construct( $parent = null ) {
  5972. $this->parent = $parent;
  5973. }
  5974. public function getParent() {
  5975. if ($this->parent) return $this->parent; else return $this;
  5976. }
  5977. public function setGlue( $glueChar ) {
  5978. $this->glueChar = $glueChar;
  5979. }
  5980. public function add( $statement = "" ) {
  5981. $this->statements[] = $statement;
  5982. }
  5983. public function setTemplate($before, $after) {
  5984. $this->before = $before;
  5985. $this->after = $after;
  5986. }
  5987. public function __toString() {
  5988. $gluedStatements = implode($this->glueChar, $this->statements);
  5989. return (string) $this->before . $gluedStatements . $this->after;
  5990. }
  5991. public function addGroup($key) {
  5992. $g = new self($this);
  5993. $this->statements[] = $g;
  5994. return $g;
  5995. }
  5996. }
  5997. return new RedBean_Plugin_BeanMachine_Group;
  5998. }
  5999. /**
  6000. * RedBean IOptimizer
  6001. * @file RedBean/Plugin/IOptimizer.php
  6002. * @description Describes the interface of an optimizer.
  6003. *
  6004. * @author Gabor de Mooij
  6005. * @license BSD
  6006. *
  6007. * (c) G.J.G.T. (Gabor) de Mooij
  6008. * This source file is subject to the BSD/GPLv2 License that is bundled
  6009. * with this source code in the file license.txt.
  6010. */
  6011. interface RedBean_Plugin_IOptimizer {
  6012. /**
  6013. * Each optimizer plugin should have a means to set basic
  6014. * information; table, column and value.
  6015. *
  6016. * @param string $table table
  6017. */
  6018. public function setTable($table);
  6019. /**
  6020. * Sets the column.
  6021. *
  6022. * @param string $column column
  6023. */
  6024. public function setColumn($column);
  6025. /**
  6026. * Sets the value.
  6027. *
  6028. * @param string $value value
  6029. */
  6030. public function setValue($value);
  6031. /**
  6032. * Called by the optimizer. This asks the plugin to optimize
  6033. * the table based on column and value information provided.
  6034. * If the optimize() method returns false, no further optimizations
  6035. * are allowed. In case of true the optimizer will advance to the next
  6036. * optimizer in the collection.
  6037. *
  6038. * @return boolean $yesNo further optimization allowed
  6039. */
  6040. public function optimize();
  6041. }
  6042. /**
  6043. * RedBean Optimizer Shrink
  6044. * @file RedBean/Plugin/Optimizer/Shrink.php
  6045. * @description An Optimizer Plugin for RedBean.
  6046. * This optimizer tries to narrow columns on the fly.
  6047. * If the values in a column can be stored in a smaller
  6048. * column type this plugin will try to adjust the column to the
  6049. * smaller type.
  6050. *
  6051. * @author Gabor de Mooij
  6052. * @license BSD
  6053. *
  6054. * (c) G.J.G.T. (Gabor) de Mooij
  6055. * This source file is subject to the BSD/GPLv2 License that is bundled
  6056. * with this source code in the file license.txt.
  6057. */
  6058. class RedBean_Plugin_Optimizer_Shrink extends RedBean_CompatManager implements RedBean_Plugin_IOptimizer {
  6059. /**
  6060. * An optimizer takes three arguments; a table, column and value.
  6061. * The table is the table that is being used for an update event at the moment,
  6062. * the Object Database will inform you about this because it might be an
  6063. * opportunity to perform optimization.
  6064. * Table to optimize.
  6065. *
  6066. * @var string $table name of the table to optimize
  6067. */
  6068. protected $table;
  6069. /**
  6070. * An optimizer takes three arguments; a table, column and value.
  6071. * The column is the column currently being updated, the Object Database
  6072. * will inform you about this because it might be an
  6073. * opportunity to perform optimization.
  6074. * Column to optimize.
  6075. *
  6076. * @var string $column column name
  6077. */
  6078. protected $column;
  6079. /**
  6080. * An optimizer takes three arguments; a table, column and value.
  6081. * The value is the piece of data that is being inserted in the column
  6082. * at this moment. The job of the optimizer is to check whether the column
  6083. * could be optimized based on the current contents and the value currently
  6084. * being inserted.
  6085. *
  6086. * @var string $value Value currently inserted in the column
  6087. */
  6088. protected $value;
  6089. /**
  6090. * Toolbox, contains everyting required for this instance to
  6091. * perform database operations within the RedBean framework.
  6092. *
  6093. * @var RedBean_Toolbox $toolbox a toolbox
  6094. */
  6095. protected $toolbox;
  6096. /**
  6097. * This is a convenience property so you don't have to
  6098. * ask the toolbox for this object every time you need it.
  6099. *
  6100. * @var RedBean_QueryWriter $writer query writer
  6101. */
  6102. protected $writer;
  6103. /**
  6104. * This is a convenience property so you don't have to
  6105. * ask the toolbox for this object every time you need it.
  6106. *
  6107. * @var RedBean_DatabaseAdapter $adapter database adapter
  6108. */
  6109. protected $adapter;
  6110. /**
  6111. * Describes to RedBean what kind of systems are supported.
  6112. * Associative array: keys are database brands, values are
  6113. * integer version numbers.
  6114. *
  6115. * @var array $collection Collection of Supported Systems and Version.
  6116. */
  6117. protected $supportedSystems = array(
  6118. RedBean_CompatManager::C_SYSTEM_MYSQL => "5"
  6119. );
  6120. /**
  6121. * Constructor.
  6122. * This Object requires a toolbox.
  6123. *
  6124. * @param RedBean_ToolBox $toolbox toolbox for DB operations.
  6125. */
  6126. public function __construct( RedBean_ToolBox $toolbox ) {
  6127. $this->scanToolBox($toolbox);
  6128. $this->writer = $toolbox->getWriter();
  6129. $this->adapter = $toolbox->getDatabaseAdapter();
  6130. }
  6131. /**
  6132. * An optimizer takes three arguments; a table, column and value.
  6133. * The table is the table that is being used for an update event at the moment,
  6134. * the Object Database will inform you about this because it might be an
  6135. * opportunity to perform optimization.
  6136. * Table to optimize.
  6137. *
  6138. * @param string $table name of the table to optimize
  6139. */
  6140. public function setTable( $table ) {
  6141. $this->table = $table;
  6142. }
  6143. /**
  6144. * An optimizer takes three arguments; a table, column and value.
  6145. * The column is the column currently being updated, the Object Database
  6146. * will inform you about this because it might be an
  6147. * opportunity to perform optimization.
  6148. * Column to optimize.
  6149. *
  6150. * @param string $column column name
  6151. */
  6152. public function setColumn( $column ) {
  6153. $this->column = $column;
  6154. }
  6155. /**
  6156. * An optimizer takes three arguments; a table, column and value.
  6157. * The value is the piece of data that is being inserted in the column
  6158. * at this moment. The job of the optimizer is to check whether the column
  6159. * could be optimized based on the current contents and the value currently
  6160. * being inserted.
  6161. *
  6162. * @param string $value Value currently inserted in the column
  6163. */
  6164. public function setValue( $value ) {
  6165. $this->value = $value;
  6166. }
  6167. /**
  6168. * Performs the actual optimization. In this case the optimizer looks
  6169. * at the size of the column and the size of the value. If the value size is
  6170. * smaller than the column size it tries to convert the column to a smaller
  6171. * size. Next, it counts if there is any different between the smaller column
  6172. * and the original column. If no differences are found the original column
  6173. * gets replaced.
  6174. * Like the other optimizers, this optimizer returns TRUE if it thinks
  6175. * further optimizations can happen, FALSE otherwise.
  6176. *
  6177. * @return boolean $yesNo advance to next optimizer
  6178. */
  6179. public function optimize() {
  6180. $type = $this->writer->scanType($this->value);
  6181. $fields = $this->writer->getColumns($this->table);
  6182. if (!in_array($this->column,array_keys($fields))) return false;
  6183. $typeInField = $this->writer->code($fields[$this->column]);
  6184. if ($type < $typeInField) {
  6185. try {
  6186. @$this->adapter->exec("alter table ".$this->writer->noKW($this->table)." drop __test");
  6187. }catch(Exception $e) {}
  6188. $type = $this->writer->typeno_sqltype[$type];
  6189. @$this->adapter->exec("alter table ".$this->writer->noKW($this->table)." add __test ".$type);
  6190. @$this->adapter->exec("update ".$this->writer->noKW($this->table)." set __test=".$this->writer->noKW($this->column)."");
  6191. $rows = $this->adapter->get("select ".$this->writer->noKW($this->column)." as a, __test as b from ".$this->writer->noKW($this->table));
  6192. $diff = 0;
  6193. foreach($rows as $row) {
  6194. $diff += ($row["a"]!=$row["b"]);
  6195. }
  6196. if (!$diff) {
  6197. @$this->adapter->exec("alter table ".$this->writer->noKW($this->table)." change ".$this->writer->noKW($this->column)." ".$this->writer->noKW($this->column)." ".$type);
  6198. }
  6199. @$this->adapter->exec("alter table ".$this->writer->noKW($this->table)." drop __test");
  6200. }
  6201. return false;
  6202. }
  6203. }
  6204. /**
  6205. * RedBean Optimizer DateTime
  6206. * @file RedBean/Plugin/Optimizer/DateTime.php
  6207. * @description An Optimizer Plugin for RedBean.
  6208. * Tries to convert columns to MySQL datetime
  6209. * if possible.
  6210. *
  6211. * @author Gabor de Mooij
  6212. * @license BSD
  6213. *
  6214. * (c) G.J.G.T. (Gabor) de Mooij
  6215. * This source file is subject to the BSD/GPLv2 License that is bundled
  6216. * with this source code in the file license.txt.
  6217. */
  6218. class RedBean_Plugin_Optimizer_Datetime extends RedBean_CompatManager implements RedBean_Plugin_IOptimizer {
  6219. /**
  6220. * An optimizer takes three arguments; a table, column and value.
  6221. * The table is the table that is being used for an update event at the moment,
  6222. * the Object Database will inform you about this because it might be an
  6223. * opportunity to perform optimization.
  6224. * Table to optimize.
  6225. *
  6226. * @var string $table name of the table to optimize
  6227. */
  6228. protected $table;
  6229. /**
  6230. * An optimizer takes three arguments; a table, column and value.
  6231. * The column is the column currently being updated, the Object Database
  6232. * will inform you about this because it might be an
  6233. * opportunity to perform optimization.
  6234. * Column to optimize.
  6235. *
  6236. * @var string $column column name
  6237. */
  6238. protected $column;
  6239. /**
  6240. * An optimizer takes three arguments; a table, column and value.
  6241. * The value is the piece of data that is being inserted in the column
  6242. * at this moment. The job of the optimizer is to check whether the column
  6243. * could be optimized based on the current contents and the value currently
  6244. * being inserted.
  6245. *
  6246. * @var string $value Value currently inserted in the column
  6247. */
  6248. protected $value;
  6249. /**
  6250. * Toolbox, contains everyting required for this instance to
  6251. * perform database operations within the RedBean framework.
  6252. *
  6253. * @var RedBean_Toolbox $toolbox a toolbox
  6254. */
  6255. protected $toolbox;
  6256. /**
  6257. * This is a convenience property so you don't have to
  6258. * ask the toolbox for this object every time you need it.
  6259. *
  6260. * @var RedBean_QueryWriter $writer query writer
  6261. */
  6262. protected $writer;
  6263. /**
  6264. * This is a convenience property so you don't have to
  6265. * ask the toolbox for this object every time you need it.
  6266. *
  6267. * @var RedBean_DatabaseAdapter $adapter database adapter
  6268. */
  6269. protected $adapter;
  6270. /**
  6271. * Describes to RedBean what kind of systems are supported.
  6272. * Associative array: keys are database brands, values are
  6273. * integer version numbers.
  6274. *
  6275. * @var array $collection Collection of Supported Systems and Version.
  6276. */
  6277. protected $supportedSystems = array(
  6278. RedBean_CompatManager::C_SYSTEM_MYSQL => "5"
  6279. );
  6280. /**
  6281. * Constructor.
  6282. * This Object requires a toolbox.
  6283. *
  6284. * @param RedBean_ToolBox $toolbox toolbox for DB operations.
  6285. */
  6286. public function __construct( RedBean_ToolBox $toolbox ) {
  6287. $this->scanToolBox($toolbox);
  6288. $this->writer = $toolbox->getWriter();
  6289. $this->adapter = $toolbox->getDatabaseAdapter();
  6290. }
  6291. /**
  6292. * An optimizer takes three arguments; a table, column and value.
  6293. * The table is the table that is being used for an update event at the moment,
  6294. * the Object Database will inform you about this because it might be an
  6295. * opportunity to perform optimization.
  6296. * Table to optimize.
  6297. *
  6298. * @param string $table name of the table to optimize
  6299. */
  6300. public function setTable( $table ) {
  6301. $this->table = $table;
  6302. }
  6303. /**
  6304. * An optimizer takes three arguments; a table, column and value.
  6305. * The column is the column currently being updated, the Object Database
  6306. * will inform you about this because it might be an
  6307. * opportunity to perform optimization.
  6308. * Column to optimize.
  6309. *
  6310. * @param string $column column name
  6311. */
  6312. public function setColumn( $column ) {
  6313. $this->column = $column;
  6314. }
  6315. /**
  6316. * An optimizer takes three arguments; a table, column and value.
  6317. * The value is the piece of data that is being inserted in the column
  6318. * at this moment. The job of the optimizer is to check whether the column
  6319. * could be optimized based on the current contents and the value currently
  6320. * being inserted.
  6321. *
  6322. * @param string $value Value currently inserted in the column
  6323. */
  6324. public function setValue( $value ) {
  6325. $this->value = $value;
  6326. }
  6327. /**
  6328. * Performs the actual optimization. In this case the optimizer first
  6329. * scans the value. If the value if of type 'datetime' and the column
  6330. * is not it tries to make the column datetime. If the column is 'datetime'
  6331. * and the value 'datetime' it blocks further optimization. If the value
  6332. * is NOT 'datetime' then it immediately returns true, thus allowing further
  6333. * optimization.
  6334. *
  6335. * @return boolean $yesNo advance to next optimizer
  6336. */
  6337. public function optimize() {
  6338. if (!$this->matchesDateTime($this->value)) return true;
  6339. $type = $this->writer->scanType($this->value);
  6340. $fields = $this->writer->getColumns($this->table);
  6341. if (!in_array($this->column,array_keys($fields))) return false;
  6342. $typeInField = $this->writer->code($fields[$this->column]);
  6343. if ($typeInField!="datetime") {
  6344. if ($this->matchesDateTime($this->value)) {
  6345. $cnt = (int) $this->adapter->getCell("select count(*) as n from {$this->table} where
  6346. {$this->column} regexp '[0-9]{4}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]'
  6347. OR {$this->column} IS NULL");
  6348. $total = (int) $this->adapter->getCell("SELECT count(*) FROM ".$this->writer->noKW($this->table));
  6349. if ($total===$cnt) {
  6350. $this->adapter->exec("ALTER TABLE ".$this->writer->noKW($this->table)." change ".$this->writer->noKW($this->column)." ".$this->writer->noKW($this->column)." datetime ");
  6351. }
  6352. return false;
  6353. }
  6354. return true;
  6355. }
  6356. else {
  6357. return false;
  6358. }
  6359. }
  6360. /**
  6361. * MatchesDateTime matches a value to determine whether it matches the
  6362. * MySQL datetime type.
  6363. *
  6364. * @param string $value Value to match
  6365. *
  6366. * @return boolean $yesNo Whether it is a datetime value
  6367. */
  6368. public function matchesDateTime($value) {
  6369. $pattern = "/^([0-9]{2,4})-([0-1][0-9])-([0-3][0-9]) (?:([0-2][0-9]):([0-5][0-9]):([0-5][0-9]))?$/";
  6370. return (boolean) (preg_match($pattern, $value));
  6371. }
  6372. }
  6373. /**
  6374. * Created by PhpStorm.
  6375. * User: prive
  6376. * Date: 3-feb-2011
  6377. * Time: 20:31:20
  6378. * To change this template use File | Settings | File Templates.
  6379. */
  6380. class RedBean_Plugin_QueryLogger implements RedBean_Plugin,RedBean_Observer {
  6381. protected $logs = array();
  6382. public static function getInstanceAndAttach( RedBean_Observable $adapter ) {
  6383. $queryLog = new RedBean_Plugin_QueryLogger;
  6384. $adapter->addEventListener( "sql_exec", $queryLog );
  6385. return $queryLog;
  6386. }
  6387. private function __construct(){
  6388. }
  6389. public function onEvent( $eventName, $adapter ) {
  6390. if ($eventName=="sql_exec") {
  6391. $sql = $adapter->getSQL();
  6392. $this->logs[] = $sql;
  6393. }
  6394. }
  6395. public function grep( $word ) {
  6396. $found = array();
  6397. foreach($this->logs as $log) {
  6398. if (strpos($log,$word)!==false) {
  6399. $found[] = $log;
  6400. }
  6401. }
  6402. return $found;
  6403. }
  6404. public function getLogs() {
  6405. return $this->logs;
  6406. }
  6407. }
  6408. /**
  6409. * RedBean NullWriter
  6410. * @file RedBean/QueryWriter/NullWriter.php
  6411. * @description Represents a NULL Database to RedBean
  6412. * This class simply registers all actions invoked.
  6413. * It can be used for so-called white box testing, to see
  6414. * if your algorithms active the right methods with proper
  6415. * arguments.
  6416. *
  6417. * @author Gabor de Mooij
  6418. * @license BSD
  6419. *
  6420. *
  6421. * (c) G.J.G.T. (Gabor) de Mooij
  6422. * This source file is subject to the BSD/GPLv2 License that is bundled
  6423. * with this source code in the file license.txt.
  6424. */
  6425. class RedBean_QueryWriter_NullWriter extends RedBean_QueryWriter_AQueryWriter implements RedBean_QueryWriter {
  6426. /**
  6427. * @var integer
  6428. *
  6429. * DATA TYPE
  6430. * Boolean Data type
  6431. *
  6432. */
  6433. const C_DATATYPE_BOOL = 0;
  6434. /**
  6435. * @var integer
  6436. *
  6437. * DATA TYPE
  6438. * Unsigned 8BIT Integer
  6439. *
  6440. */
  6441. const C_DATATYPE_UINT8 = 1;
  6442. /**
  6443. * @var integer
  6444. *
  6445. * DATA TYPE
  6446. * Unsigned 32BIT Integer
  6447. *
  6448. */
  6449. const C_DATATYPE_UINT32 = 2;
  6450. /**
  6451. * @var integer
  6452. *
  6453. * DATA TYPE
  6454. * Double precision floating point number and
  6455. * negative numbers.
  6456. *
  6457. */
  6458. const C_DATATYPE_DOUBLE = 3;
  6459. /**
  6460. * @var integer
  6461. *
  6462. * DATA TYPE
  6463. * Standard Text column (like varchar255)
  6464. * At least 8BIT character support.
  6465. *
  6466. */
  6467. const C_DATATYPE_TEXT8 = 4;
  6468. /**
  6469. * @var integer
  6470. *
  6471. * DATA TYPE
  6472. * Long text column (16BIT)
  6473. *
  6474. */
  6475. const C_DATATYPE_TEXT16 = 5;
  6476. /**
  6477. * @var integer
  6478. *
  6479. * DATA TYPE
  6480. * 32BIT long textfield (number of characters can be as high as 32BIT) Data type
  6481. * This is the biggest column that RedBean supports. If possible you may write
  6482. * an implementation that stores even bigger values.
  6483. *
  6484. */
  6485. const C_DATATYPE_TEXT32 = 6;
  6486. /**
  6487. * @var integer
  6488. *
  6489. * DATA TYPE
  6490. * Specified. This means the developer or DBA
  6491. * has altered the column to a different type not
  6492. * recognized by RedBean. This high number makes sure
  6493. * it will not be converted back to another type by accident.
  6494. *
  6495. */
  6496. const C_DATATYPE_SPECIFIED = 99;
  6497. /**
  6498. * Part of test system. This property captures interactions
  6499. * between this object and the one that is being tested.
  6500. * Used for scanning behavior of objects that use query writers.
  6501. *
  6502. * @var mixed
  6503. */
  6504. public $createTableArgument = NULL;
  6505. /**
  6506. * Part of test system. This property captures interactions
  6507. * between this object and the one that is being tested.
  6508. * Used for scanning behavior of objects that use query writers.
  6509. *
  6510. * @var mixed
  6511. */
  6512. public $getColumnsArgument = NULL;
  6513. /**
  6514. * Part of test system. This property captures interactions
  6515. * between this object and the one that is being tested.
  6516. * Used for scanning behavior of objects that use query writers.
  6517. *
  6518. * @var mixed
  6519. */
  6520. public $scanTypeArgument = NULL;
  6521. /**
  6522. * Part of test system. This property captures interactions
  6523. * between this object and the one that is being tested.
  6524. * Used for scanning behavior of objects that use query writers.
  6525. *
  6526. * @var mixed
  6527. */
  6528. public $addColumnArguments = array();
  6529. /**
  6530. * Part of test system. This property captures interactions
  6531. * between this object and the one that is being tested.
  6532. * Used for scanning behavior of objects that use query writers.
  6533. *
  6534. * @var mixed
  6535. */
  6536. public $codeArgument = NULL;
  6537. /**
  6538. * Part of test system. This property captures interactions
  6539. * between this object and the one that is being tested.
  6540. * Used for scanning behavior of objects that use query writers.
  6541. *
  6542. * @var mixed
  6543. */
  6544. public $widenColumnArguments = array();
  6545. /**
  6546. * Part of test system. This property captures interactions
  6547. * between this object and the one that is being tested.
  6548. * Used for scanning behavior of objects that use query writers.
  6549. *
  6550. * @var mixed
  6551. */
  6552. public $updateRecordArguments = array();
  6553. /**
  6554. * Part of test system. This property captures interactions
  6555. * between this object and the one that is being tested.
  6556. * Used for scanning behavior of objects that use query writers.
  6557. *
  6558. * @var mixed
  6559. */
  6560. public $insertRecordArguments = array();
  6561. /**
  6562. * Part of test system. This property captures interactions
  6563. * between this object and the one that is being tested.
  6564. * Used for scanning behavior of objects that use query writers.
  6565. *
  6566. * @var mixed
  6567. */
  6568. public $selectRecordArguments = array();
  6569. /**
  6570. * Part of test system. This property captures interactions
  6571. * between this object and the one that is being tested.
  6572. * Used for scanning behavior of objects that use query writers.
  6573. *
  6574. * @var mixed
  6575. */
  6576. public $deleteRecordArguments = array();
  6577. /**
  6578. * Part of test system. This property captures interactions
  6579. * between this object and the one that is being tested.
  6580. * Used for scanning behavior of objects that use query writers.
  6581. *
  6582. * @var mixed
  6583. */
  6584. public $checkChangesArguments = array();
  6585. /**
  6586. * Part of test system. This property captures interactions
  6587. * between this object and the one that is being tested.
  6588. * Used for scanning behavior of objects that use query writers.
  6589. *
  6590. * @var mixed
  6591. */
  6592. public $addUniqueIndexArguments = array();
  6593. /**
  6594. * Part of test system. This property captures interactions
  6595. * between this object and the one that is being tested.
  6596. * Used for scanning behavior of objects that use query writers.
  6597. *
  6598. * @var mixed
  6599. */
  6600. public $selectByCritArguments = array();
  6601. /**
  6602. * Part of test system. This property captures interactions
  6603. * between this object and the one that is being tested.
  6604. * Used for scanning behavior of objects that use query writers.
  6605. *
  6606. * @var mixed
  6607. */
  6608. public $deleteByCrit = array();
  6609. /**
  6610. * Part of test system. This property captures interactions
  6611. * between this object and the one that is being tested.
  6612. * Used for scanning behavior of objects that use query writers.
  6613. *
  6614. * @var mixed
  6615. */
  6616. public $returnTables = array();
  6617. /**
  6618. * Part of test system. This property captures interactions
  6619. * between this object and the one that is being tested.
  6620. * Used for scanning behavior of objects that use query writers.
  6621. *
  6622. * @var mixed
  6623. */
  6624. public $returnGetColumns = array();
  6625. /**
  6626. * Part of test system. This property captures interactions
  6627. * between this object and the one that is being tested.
  6628. * Used for scanning behavior of objects that use query writers.
  6629. *
  6630. * @var mixed
  6631. */
  6632. public $returnScanType = 1;
  6633. /**
  6634. * Part of test system. This property captures interactions
  6635. * between this object and the one that is being tested.
  6636. * Used for scanning behavior of objects that use query writers.
  6637. *
  6638. * @var mixed
  6639. */
  6640. public $returnAddColumn = NULL;
  6641. /**
  6642. * Part of test system. This property captures interactions
  6643. * between this object and the one that is being tested.
  6644. * Used for scanning behavior of objects that use query writers.
  6645. *
  6646. * @var mixed
  6647. */
  6648. public $returnCode = NULL;
  6649. /**
  6650. * Part of test system. This property captures interactions
  6651. * between this object and the one that is being tested.
  6652. * Used for scanning behavior of objects that use query writers.
  6653. *
  6654. * @var mixed
  6655. */
  6656. public $returnWidenColumn = NULL;
  6657. /**
  6658. * Part of test system. This property captures interactions
  6659. * between this object and the one that is being tested.
  6660. * Used for scanning behavior of objects that use query writers.
  6661. *
  6662. * @var mixed
  6663. */
  6664. public $returnUpdateRecord = NULL;
  6665. /**
  6666. * Part of test system. This property captures interactions
  6667. * between this object and the one that is being tested.
  6668. * Used for scanning behavior of objects that use query writers.
  6669. *
  6670. * @var mixed
  6671. */
  6672. public $returnInsertRecord = NULL;
  6673. /**
  6674. * Part of test system. This property captures interactions
  6675. * between this object and the one that is being tested.
  6676. * Used for scanning behavior of objects that use query writers.
  6677. *
  6678. * @var mixed
  6679. */
  6680. public $returnSelectRecord = NULL;
  6681. /**
  6682. * Part of test system. This property captures interactions
  6683. * between this object and the one that is being tested.
  6684. * Used for scanning behavior of objects that use query writers.
  6685. *
  6686. * @var mixed
  6687. */
  6688. public $returnDeleteRecord = NULL;
  6689. /**
  6690. * Part of test system. This property captures interactions
  6691. * between this object and the one that is being tested.
  6692. * Used for scanning behavior of objects that use query writers.
  6693. *
  6694. * @var mixed
  6695. */
  6696. public $returnCheckChanges = NULL;
  6697. /**
  6698. * Part of test system. This property captures interactions
  6699. * between this object and the one that is being tested.
  6700. * Used for scanning behavior of objects that use query writers.
  6701. *
  6702. * @var mixed
  6703. */
  6704. public $returnDeleteByCrit = NULL;
  6705. /**
  6706. * Part of test system. This property captures interactions
  6707. * between this object and the one that is being tested.
  6708. * Used for scanning behavior of objects that use query writers.
  6709. *
  6710. * @var mixed
  6711. */
  6712. public$returnSelectByCrit = NULL;
  6713. /**
  6714. * Part of test system. This property captures interactions
  6715. * between this object and the one that is being tested.
  6716. * Used for scanning behavior of objects that use query writers.
  6717. *
  6718. * @var mixed
  6719. */
  6720. public $returnAddUniqueIndex = NULL;
  6721. /**
  6722. * For testing purposes only. Returnes a predefined
  6723. * value.
  6724. *
  6725. * @return mixed
  6726. */
  6727. public function getTables() {
  6728. return $this->returnTables;
  6729. }
  6730. /**
  6731. * For testing purposes only. Returnes a predefined
  6732. * value.
  6733. *
  6734. * @return mixed
  6735. */
  6736. public function createTable( $table ) {
  6737. $this->createTableArgument = $table;
  6738. }
  6739. /**
  6740. * For testing purposes only. Returnes a predefined
  6741. * value.
  6742. *
  6743. * @return mixed
  6744. */
  6745. public function getColumns( $table ) {
  6746. $this->getColumnsArgument = $table;
  6747. return $this->returnGetColumns;
  6748. }
  6749. /**
  6750. * For testing purposes only. Returnes a predefined
  6751. * value.
  6752. *
  6753. * @return mixed
  6754. */
  6755. public function scanType( $value ) {
  6756. $this->scanTypeArgument = $value;
  6757. return $this->returnScanType;
  6758. }
  6759. /**
  6760. * For testing purposes only. Returnes a predefined
  6761. * value.
  6762. *
  6763. * @return mixed
  6764. */
  6765. public function addColumn( $table, $column, $type ) {
  6766. $this->addColumnArguments = array( $table, $column, $type );
  6767. return $this->returnAddColumn;
  6768. }
  6769. /**
  6770. * For testing purposes only. Returnes a predefined
  6771. * value.
  6772. *
  6773. * @return mixed
  6774. */
  6775. public function code( $typedescription ) {
  6776. $this->codeArgument = $typedescription;
  6777. return $this->returnCode;
  6778. }
  6779. /**
  6780. * For testing purposes only. Returnes a predefined
  6781. * value.
  6782. *
  6783. * @return mixed
  6784. */
  6785. public function widenColumn( $table, $column, $type ) {
  6786. $this->widenColumnArguments = array($table, $column, $type);
  6787. return $this->returnWidenColumn;
  6788. }
  6789. /**
  6790. * For testing purposes only. Returnes a predefined
  6791. * value.
  6792. *
  6793. * @return mixed
  6794. */
  6795. public function updateRecord( $table, $updatevalues, $id) {
  6796. $this->updateRecordArguments = array($table, $updatevalues, $id);
  6797. return $this->returnUpdateRecord;
  6798. }
  6799. /**
  6800. * For testing purposes only. Returnes a predefined
  6801. * value.
  6802. *
  6803. * @return mixed
  6804. */
  6805. public function insertRecord( $table, $insertcolumns, $insertvalues ) {
  6806. $this->insertRecordArguments = array( $table, $insertcolumns, $insertvalues );
  6807. return $this->returnInsertRecord;
  6808. }
  6809. /**
  6810. * For testing purposes only. Returnes a predefined
  6811. * value.
  6812. *
  6813. * @return mixed
  6814. */
  6815. public function selectRecord($type, $ids) {
  6816. $this->selectRecordArguments = array($type, $ids);
  6817. return $this->returnSelectRecord;
  6818. }
  6819. /**
  6820. * For testing purposes only. Returnes a predefined
  6821. * value.
  6822. *
  6823. * @return mixed
  6824. */
  6825. public function deleteRecord( $table, $id) {
  6826. $this->deleteRecordArguments = array($table, "id", $id);
  6827. return $this->returnDeleteRecord;
  6828. }
  6829. /**
  6830. * For testing purposes only. Returnes a predefined
  6831. * value.
  6832. *
  6833. * @return mixed
  6834. */
  6835. public function checkChanges($type, $id, $logid) {
  6836. $this->checkChangesArguments = array($type, $id, $logid);
  6837. return $this->returnCheckChanges;
  6838. }
  6839. /**
  6840. * For testing purposes only. Returnes a predefined
  6841. * value.
  6842. *
  6843. * @return mixed
  6844. */
  6845. public function addUniqueIndex( $table,$columns ) {
  6846. $this->addUniqueIndexArguments=array($table,$columns);
  6847. return $this->returnAddUniqueIndex;
  6848. }
  6849. /**
  6850. * For testing purposes only. Returnes a predefined
  6851. * value.
  6852. *
  6853. * @return mixed
  6854. */
  6855. public function selectByCrit( $select, $table, $column, $value, $withUnion=false, $sqlSnippet = false ) {
  6856. $this->selectByCritArguments=array($select, $table, $column, $value, $withUnion);
  6857. return $this->returnSelectByCrit;
  6858. }
  6859. /**
  6860. * For testing purposes only. Returnes a predefined
  6861. * value.
  6862. *
  6863. * @return mixed
  6864. */
  6865. public function deleteByCrit( $table, $crits ) {
  6866. $this->deleteByCrit=array($table, $crits );
  6867. return $this->returnDeleteByCrit;
  6868. }
  6869. /**
  6870. * For testing purposes only. Returnes a predefined
  6871. * value.
  6872. *
  6873. * @return mixed
  6874. */
  6875. public function getIDField( $type, $safe = null ) {
  6876. return "id";
  6877. }
  6878. /**
  6879. * For testing purposes only. Returnes a predefined
  6880. * value.
  6881. *
  6882. * @return mixed
  6883. */
  6884. public function noKW($str) {
  6885. return $str;
  6886. }
  6887. /**
  6888. * For testing purposes only. Returnes a predefined
  6889. * value.
  6890. *
  6891. * @return mixed
  6892. */
  6893. public function sqlStateIn($state,$list) {
  6894. return true;
  6895. }
  6896. /**
  6897. * Resets the mock object. All public
  6898. * properties will be assigned values like NULL or an empty
  6899. * array.
  6900. */
  6901. public function reset() {
  6902. $this->createTableArgument = NULL;
  6903. $this->getColumnsArgument = NULL;
  6904. $this->scanTypeArgument = NULL;
  6905. $this->addColumnArguments = array();
  6906. $this->codeArgument = NULL;
  6907. $this->widenColumnArguments = array();
  6908. $this->updateRecordArguments = array();
  6909. $this->insertRecordArguments = array();
  6910. $this->selectRecordArguments = array();
  6911. $this->deleteRecordArguments = array();
  6912. $this->checkChangesArguments = array();
  6913. $this->addUniqueIndexArguments = array();
  6914. $this->returnTables = array();
  6915. $this->returnGetColumns = array();
  6916. $this->returnScanType = 1;
  6917. $this->returnAddColumn = NULL;
  6918. $this->returnCode = NULL;
  6919. $this->returnWidenColumn = NULL;
  6920. $this->returnUpdateRecord = NULL;
  6921. $this->returnInsertRecord = NULL;
  6922. $this->returnSelectRecord = NULL;
  6923. $this->returnDeleteRecord = NULL;
  6924. $this->returnCheckChanges = NULL;
  6925. $this->returnAddUniqueIndex = NULL;
  6926. }
  6927. }
  6928. /**
  6929. * RedBean Domain Object
  6930. * @file RedBean/UnitOfWork.php
  6931. * @description This is an extra convenience class
  6932. * that implements my own version of the
  6933. * well known unit of work pattern using PHP 5.3 closures.
  6934. * @author Gabor de Mooij
  6935. * @license BSD
  6936. *
  6937. *
  6938. * (c) G.J.G.T. (Gabor) de Mooij
  6939. * This source file is subject to the BSD/GPLv2 License that is bundled
  6940. * with this source code in the file license.txt.
  6941. *
  6942. */
  6943. class RedBean_UnitOfWork {
  6944. /**
  6945. * Associative multi dimensional array
  6946. * containing all the tasks and their tags.
  6947. * @var array
  6948. */
  6949. private $todoList = array();
  6950. /**
  6951. * Adds a piece of work to the list.
  6952. * @param string $tagName
  6953. * @param closure $closure
  6954. */
  6955. public function addWork( $tagName, $closure ) {
  6956. if (strlen($tagName)>0) {
  6957. if (!isset($this->todoList[$tagName])) {
  6958. $this->todoList[$tagName]=array();
  6959. }
  6960. $this->todoList[$tagName][] = $closure;
  6961. }
  6962. }
  6963. /**
  6964. * Executes a piece of work (job) identified by the
  6965. * tagname argument.
  6966. * @param string $tagName
  6967. */
  6968. public function doWork( $tagName ) {
  6969. if (isset($this->todoList[$tagName])) {
  6970. foreach($this->todoList[$tagName] as $job) {
  6971. $job();
  6972. }
  6973. }
  6974. }
  6975. }
  6976. /**
  6977. * SimpleModel
  6978. * @file RedBean/SimpleModel.php
  6979. * @description Part of FUSE
  6980. * @author Gabor de Mooij
  6981. * @license BSD
  6982. *
  6983. *
  6984. * (c) G.J.G.T. (Gabor) de Mooij
  6985. * This source file is subject to the BSD/GPLv2 License that is bundled
  6986. * with this source code in the file license.txt.
  6987. */
  6988. class RedBean_SimpleModel {
  6989. /**
  6990. * Contains the inner bean.
  6991. * @var RedBean_OODBBean
  6992. */
  6993. protected $bean;
  6994. /**
  6995. * Used by FUSE: the ModelHelper class to connect a bean to a model.
  6996. * This method loads a bean in the model.
  6997. * @param RedBean_OODBBean $bean
  6998. */
  6999. public function loadBean( RedBean_OODBBean $bean ) {
  7000. $this->bean = $bean;
  7001. }
  7002. /**
  7003. * Magic Getter to make the bean properties available from
  7004. * the $this-scope.
  7005. * @param string $prop
  7006. * @return mixed $propertyValue
  7007. */
  7008. public function __get( $prop ) {
  7009. return $this->bean->$prop;
  7010. }
  7011. /**
  7012. * Magic Setter
  7013. * @param string $prop
  7014. * @param mixed $value
  7015. */
  7016. public function __set( $prop, $value ) {
  7017. $this->bean->$prop = $value;
  7018. }
  7019. protected function __hasProperties( $list ) {
  7020. $missing = array();
  7021. $properties = explode(",", $list);
  7022. foreach($properties as $property) {
  7023. if (empty($this->bean->$property)) {
  7024. $missing[] = $property;
  7025. }
  7026. }
  7027. return $missing;
  7028. }
  7029. public function __isset($key) {
  7030. return (isset($this->bean->$key));
  7031. }
  7032. }
  7033. /*
  7034. * ModelHelper
  7035. * @author Gabor de Mooij
  7036. * @license BSD
  7037. *
  7038. *
  7039. * (c) G.J.G.T. (Gabor) de Mooij
  7040. * This source file is subject to the BSD/GPLv2 License that is bundled
  7041. * with this source code in the file license.txt.
  7042. * Interface definition of a Model Formatter for Fuse
  7043. */
  7044. class RedBean_ModelHelper implements RedBean_Observer {
  7045. /**
  7046. * Holds a model formatter
  7047. * @var RedBean_IModelFormatter
  7048. */
  7049. private static $modelFormatter;
  7050. /**
  7051. * Connects OODB to a model if a model exists for that
  7052. * type of bean. This connector is used in the facade.
  7053. *
  7054. * @param string $eventName
  7055. * @param RedBean_OODBBean $bean
  7056. */
  7057. public function onEvent( $eventName, $bean ) {
  7058. $bean->$eventName();
  7059. }
  7060. /**
  7061. * Given a model ID (model identifier) this method returns the
  7062. * full model name.
  7063. *
  7064. * @param string $model
  7065. * @return string $fullname
  7066. */
  7067. public static function getModelName( $model ) {
  7068. if (self::$modelFormatter){
  7069. return self::$modelFormatter->formatModel($model);
  7070. }
  7071. else {
  7072. return "Model_".ucfirst($model);
  7073. }
  7074. }
  7075. /**
  7076. * Sets the model formatter to be used to discover a model
  7077. * for Fuse.
  7078. *
  7079. * @param string $modelFormatter
  7080. */
  7081. public static function setModelFormatter( RedBean_IModelFormatter $modelFormatter ) {
  7082. self::$modelFormatter = $modelFormatter;
  7083. }
  7084. }
  7085. /**
  7086. * RedBean Facade
  7087. * @file RedBean/Facade.php
  7088. * @description Convenience class for RedBeanPHP.
  7089. * This class hides the object landscape of
  7090. * RedBean behind a single letter class providing
  7091. * almost all functionality with simple static calls.
  7092. *
  7093. * @author Gabor de Mooij
  7094. * @license BSD
  7095. *
  7096. * (c) G.J.G.T. (Gabor) de Mooij
  7097. * This source file is subject to the BSD/GPLv2 License that is bundled
  7098. * with this source code in the file license.txt.
  7099. *
  7100. */
  7101. class R {
  7102. /**
  7103. *
  7104. * Constains an instance of the RedBean Toolbox
  7105. * @var RedBean_ToolBox
  7106. *
  7107. */
  7108. public static $toolbox;
  7109. /**
  7110. * Constains an instance of RedBean OODB
  7111. * @var RedBean_OODB
  7112. */
  7113. public static $redbean;
  7114. /**
  7115. * Contains an instance of the Query Writer
  7116. * @var RedBean_QueryWriter
  7117. */
  7118. public static $writer;
  7119. /**
  7120. * Contains an instance of the Database
  7121. * Adapter.
  7122. * @var RedBean_DBAdapter
  7123. */
  7124. public static $adapter;
  7125. /**
  7126. * Contains an instance of the Tree Manager
  7127. * @var RedBean_TreeManager
  7128. */
  7129. public static $treeManager;
  7130. /**
  7131. * Contains an instance of the Association Manager
  7132. * @var RedBean_AssociationManager
  7133. */
  7134. public static $associationManager;
  7135. /**
  7136. * Contains an instance of the Extended Association Manager
  7137. * @var RedBean_ExtAssociationManager
  7138. */
  7139. public static $extAssocManager;
  7140. /**
  7141. *
  7142. * Constains an instance of the RedBean Link Manager
  7143. * @var RedBean_LinkManager
  7144. *
  7145. */
  7146. public static $linkManager;
  7147. /**
  7148. * Returns version ID string
  7149. * Version No format: <Major>.<Minor>.<Maintenance>.<Fix/Update>
  7150. *
  7151. * @return string $version Version ID
  7152. */
  7153. public static function getVersion() {
  7154. return "1.3";
  7155. }
  7156. /**
  7157. * Flag to indicate whether experimental (fearless) code might be used.
  7158. * If you experience any problems with new features these can be degrade
  7159. * easily by doing R::$flagFearless = false;
  7160. * @var bool
  7161. */
  7162. public static $flagFearless = true;
  7163. /**
  7164. * Kickstarts redbean for you.
  7165. * @param string $dsn
  7166. * @param string $username
  7167. * @param string $password
  7168. */
  7169. public static function setup( $dsn="sqlite:/tmp/red.db", $username=NULL, $password=NULL ) {
  7170. RedBean_Setup::kickstart( $dsn, $username, $password );
  7171. $toolbox = RedBean_Setup::getToolBox();
  7172. self::configureFacadeWithToolbox($toolbox);
  7173. }
  7174. /**
  7175. * Toggles DEBUG mode.
  7176. * In Debug mode all SQL that happens under the hood will
  7177. * be printed to the screen.
  7178. *
  7179. * @param boolean $tf
  7180. */
  7181. public static function debug( $tf = true ) {
  7182. self::$adapter->getDatabase()->setDebugMode( $tf );
  7183. }
  7184. /**
  7185. * Stores a RedBean OODB Bean and returns the ID.
  7186. *
  7187. * @param RedBean_OODBBean $bean bean
  7188. *
  7189. * @return integer $id id
  7190. */
  7191. public static function store( RedBean_OODBBean $bean ) {
  7192. return self::$redbean->store( $bean );
  7193. }
  7194. /**
  7195. * Freezes RedBean. In frozen mode the schema cannot be altered.
  7196. * Frozen mode is recommended for production use because it is
  7197. * secure and fast.
  7198. *
  7199. * @param boolean $tf whether to turn it on or off.
  7200. *
  7201. * @return void
  7202. */
  7203. public static function freeze( $tf = true ) {
  7204. self::$redbean->freeze( $tf );
  7205. }
  7206. /**
  7207. * Loads the bean with the given type and id and returns it.
  7208. *
  7209. * @param string $type type
  7210. * @param integer $id id of the bean you want to load
  7211. *
  7212. * @return RedBean_OODBBean $bean
  7213. */
  7214. public static function load( $type, $id ) {
  7215. return self::$redbean->load( $type, $id );
  7216. }
  7217. /**
  7218. * Deletes the specified bean.
  7219. *
  7220. * @param RedBean_OODBBean $bean bean to be deleted
  7221. *
  7222. * @return mixed
  7223. */
  7224. public static function trash( RedBean_OODBBean $bean ) {
  7225. return self::$redbean->trash( $bean );
  7226. }
  7227. /**
  7228. * Dispenses a new RedBean OODB Bean for use with
  7229. * the rest of the methods.
  7230. *
  7231. * @param string $type type
  7232. *
  7233. * @return RedBean_OODBBean $bean a new bean
  7234. */
  7235. public static function dispense( $type ) {
  7236. return self::$redbean->dispense( $type );
  7237. }
  7238. /**
  7239. * Loads a bean if ID > 0 else dispenses.
  7240. *
  7241. * @param string $type type
  7242. * @param integer $id id
  7243. *
  7244. * @return RedBean_OODBBean $bean bean
  7245. */
  7246. public static function loadOrDispense( $type, $id = 0 ) {
  7247. return ($id ? R::load($type,(int)$id) : R::dispense($type));
  7248. }
  7249. /**
  7250. * Convience method. Tries to find beans of a certain type,
  7251. * if no beans are found, it dispenses a bean of that type.
  7252. *
  7253. * @param string $type type of bean you are looking for
  7254. * @param string $sql SQL code for finding the bean
  7255. * @param array $values parameters to bind to SQL
  7256. *
  7257. * @return array $beans Contains RedBean_OODBBean instances
  7258. */
  7259. public static function findOrDispense( $type, $sql, $values ) {
  7260. $foundBeans = self::find($type,$sql,$values);
  7261. if (count($foundBeans)==0) return array(self::dispense($type)); else return $foundBeans;
  7262. }
  7263. /**
  7264. * Associates two Beans. This method will associate two beans with eachother.
  7265. * You can then get one of the beans by using the related() function and
  7266. * providing the other bean. You can also provide a base bean in the extra
  7267. * parameter. This base bean allows you to add extra information to the association
  7268. * record. Note that this is for advanced use only and the information will not
  7269. * be added to one of the beans, just to the association record.
  7270. * It's also possible to provide an array or JSON string as base bean. If you
  7271. * pass a scalar this function will interpret the base bean as having one
  7272. * property called 'extra' with the value of the scalar.
  7273. *
  7274. * @param RedBean_OODBBean $bean1 bean that will be part of the association
  7275. * @param RedBean_OODBBean $bean2 bean that will be part of the association
  7276. * @param mixed $extra bean, scalar, array or JSON providing extra data.
  7277. *
  7278. * @return mixed
  7279. */
  7280. public static function associate( RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, $extra = null ) {
  7281. if (!$extra) {
  7282. return self::$associationManager->associate( $bean1, $bean2 );
  7283. }
  7284. else{
  7285. if (!is_array($extra)) {
  7286. $info = json_decode($extra,true);
  7287. if (!$info) $info = array("extra"=>$extra);
  7288. }
  7289. else {
  7290. $info = $extra;
  7291. }
  7292. $bean = R::dispense("typeLess");
  7293. $bean->import($info);
  7294. return self::$extAssocManager->extAssociate($bean1, $bean2, $bean);
  7295. }
  7296. }
  7297. /**
  7298. * Breaks the association between two beans.
  7299. * This functions breaks the association between a pair of beans. After
  7300. * calling this functions the beans will no longer be associated with
  7301. * eachother. Calling related() with either one of the beans will no longer
  7302. * return the other bean.
  7303. *
  7304. * @param RedBean_OODBBean $bean1 bean
  7305. * @param RedBean_OODBBean $bean2 bean
  7306. *
  7307. * @return mixed
  7308. */
  7309. public static function unassociate( RedBean_OODBBean $bean1, RedBean_OODBBean $bean2 ) {
  7310. return self::$associationManager->unassociate( $bean1, $bean2 );
  7311. }
  7312. /**
  7313. * Returns all the beans associated with $bean.
  7314. * This method will return an array containing all the beans that have
  7315. * been associated once with the associate() function and are still
  7316. * associated with the bean specified. The type parameter indicates the
  7317. * type of beans you are looking for. You can also pass some extra SQL and
  7318. * values for that SQL to filter your results after fetching the
  7319. * related beans.
  7320. *
  7321. * If 'fearless' mode is on, this method will try to take a shortcut and
  7322. * use a subquery instead.
  7323. *
  7324. * @param RedBean_OODBBean $bean the bean you have
  7325. * @param string $type the type of beans you want
  7326. * @param string $sql SQL snippet for extra filtering
  7327. * @param array $val values to be inserted in SQL slots
  7328. *
  7329. * @return array $beans beans yielded by your query.
  7330. */
  7331. public static function related( RedBean_OODBBean $bean, $type, $sql=null, $values=array()) {
  7332. if (empty($values) && $sql && method_exists(self::$writer,"__fastSelectCritRelated") && !isset($noFearlessCode)) {
  7333. $idfield = self::$writer->getIDField( $type );
  7334. $table = self::$writer->getFormattedTableName($type);
  7335. $rows = self::$associationManager->related($bean,$type, false, self::$writer->__fastSelectCritRelated($table, $idfield, $sql));
  7336. if (count($rows)==0) return array();
  7337. return self::convertToBeans($type,$rows);
  7338. }
  7339. $keys = self::$associationManager->related( $bean, $type );
  7340. if (count($keys)==0) return array();
  7341. if (!$sql) return self::batch($type, $keys);
  7342. $idfield = self::$writer->getIDField( $type );
  7343. $sqlSnippet = self::$writer->getSQLSnippetFilter($idfield, $keys, $sql);
  7344. return self::find( $type, $sqlSnippet, $values );
  7345. }
  7346. /**
  7347. * The opposite of related(). Returns all the beans that are not
  7348. * associated with the bean provided.
  7349. *
  7350. * @param RedBean_OODBBean $bean bean provided
  7351. * @param string $type type of bean you are searching for
  7352. * @param string $sql SQL for extra filtering
  7353. * @param array $values values to be inserted in SQL slots
  7354. *
  7355. * @return array $beans beans
  7356. */
  7357. public static function unrelated(RedBean_OODBBean $bean, $type, $sql=null, $values=array()) {
  7358. $keys = self::$associationManager->related( $bean, $type );
  7359. $idfield = self::$writer->getIDField( $type );
  7360. $sqlSnippet = self::$writer->getSQLSnippetFilter($idfield, $keys, $sql, true);
  7361. return self::find( $type, $sqlSnippet, $values );
  7362. }
  7363. /**
  7364. * Returns only single associated bean. This is the default way RedBean
  7365. * handles N:1 relations, by just returning the 1st one ;)
  7366. *
  7367. * @param RedBean_OODBBean $bean bean provided
  7368. * @param string $type type of bean you are searching for
  7369. * @param string $sql SQL for extra filtering
  7370. * @param array $values values to be inserted in SQL slots
  7371. *
  7372. *
  7373. * @return RedBean_OODBBean $bean
  7374. */
  7375. public static function relatedOne( RedBean_OODBBean $bean, $type, $sql='1', $values=array() ) {
  7376. $beans = self::related($bean, $type, $sql, $values);
  7377. if (count($beans)==0) return null;
  7378. return reset( $beans );
  7379. }
  7380. /**
  7381. * Clears all associated beans.
  7382. * @param RedBean_OODBBean $bean
  7383. * @param string $type
  7384. * @return mixed
  7385. */
  7386. public static function clearRelations( RedBean_OODBBean $bean, $type, RedBean_OODBBean $bean2 = null, $extra = null ) {
  7387. $r = self::$associationManager->clearRelations( $bean, $type );
  7388. if ($bean2) {
  7389. self::associate($bean, $bean2, $extra);
  7390. }
  7391. return $r;
  7392. }
  7393. /**
  7394. * Attaches $child bean to $parent bean.
  7395. *
  7396. * @param RedBean_OODBBean $parent parent
  7397. * @param RedBean_OODBBean $child child
  7398. * @return mixed
  7399. */
  7400. public static function attach( RedBean_OODBBean $parent, RedBean_OODBBean $child ) {
  7401. return self::$treeManager->attach( $parent, $child );
  7402. }
  7403. /**
  7404. * @deprecated
  7405. * Links two beans using a foreign key field, 1-N Assoc only.
  7406. *
  7407. * @param RedBean_OODBBean $bean1 bean1
  7408. * @param RedBean_OODBBean $bean2 bean2
  7409. *
  7410. * @return mixed
  7411. */
  7412. public static function link( RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, $name = null ) {
  7413. return self::$linkManager->link( $bean1, $bean2, $name );
  7414. }
  7415. /**
  7416. *
  7417. * @deprecated
  7418. * @param RedBean_OODBBean $bean bean
  7419. * @param string $typeName type
  7420. *
  7421. * @return mixed
  7422. */
  7423. public static function getBean( RedBean_OODBBean $bean, $typeName, $name = null ) {
  7424. return self::$linkManager->getBean($bean, $typeName, $name );
  7425. }
  7426. /**
  7427. * @deprecated
  7428. * @param RedBean_OODBBean $bean bean
  7429. * @param string $typeName type
  7430. *
  7431. * @return mixed
  7432. */
  7433. public static function getKey( RedBean_OODBBean $bean, $typeName, $name = null ) {
  7434. return self::$linkManager->getKey($bean, $typeName, $name );
  7435. }
  7436. /**
  7437. * @deprecated
  7438. *
  7439. * @param RedBean_OODBBean $bean bean
  7440. * @param string $typeName type
  7441. */
  7442. public static function breakLink( RedBean_OODBBean $bean, $typeName, $name = null ) {
  7443. return self::$linkManager->breakLink( $bean, $typeName, $name );
  7444. }
  7445. /**
  7446. * Returns all children beans under parent bean $parent
  7447. *
  7448. * @param RedBean_OODBBean $parent parent
  7449. *
  7450. * @return array $childBeans child beans
  7451. */
  7452. public static function children( RedBean_OODBBean $parent ) {
  7453. return self::$treeManager->children( $parent );
  7454. }
  7455. /**
  7456. * Returns the parent of a bean.
  7457. *
  7458. * @param RedBean_OODBBean $bean bean
  7459. *
  7460. * @return RedBean_OODBBean $bean bean
  7461. */
  7462. public static function getParent( RedBean_OODBBean $bean ) {
  7463. return self::$treeManager->getParent( $bean );
  7464. }
  7465. /**
  7466. * Finds a bean using a type and a where clause (SQL).
  7467. * As with most Query tools in RedBean you can provide values to
  7468. * be inserted in the SQL statement by populating the value
  7469. * array parameter; you can either use the question mark notation
  7470. * or the slot-notation (:keyname).
  7471. *
  7472. * @param string $type type
  7473. * @param string $sql sql
  7474. * @param array $values values
  7475. *
  7476. * @return array $beans beans
  7477. */
  7478. public static function find( $type, $sql="1", $values=array() ) {
  7479. return RedBean_Plugin_Finder::where( $type, $sql, $values );
  7480. }
  7481. /**
  7482. * @deprecated
  7483. *
  7484. * Use related() instead.
  7485. *
  7486. * Convenience Method
  7487. *
  7488. * @param RedBean_OODBBean $bean bean
  7489. * @param string $type type
  7490. * @param string $sql sql
  7491. * @param array $values values
  7492. *
  7493. * @return array $beans
  7494. */
  7495. public static function findRelated( RedBean_OODBBean $bean, $type, $sql=" id IN (:keys) ", $values=array() ) {
  7496. $keys = self::$associationManager->related($bean,$type);
  7497. $sql=str_replace(":keys",implode(",",$keys),$sql);
  7498. return self::find($type,$sql,$values);
  7499. }
  7500. /**
  7501. * @deprecated
  7502. *
  7503. * Use related() instead.
  7504. *
  7505. * Convenience Method
  7506. *
  7507. * @param RedBean_OODBBean $bean bean
  7508. * @param string $type type
  7509. * @param string $sql sql
  7510. * @param array $values values
  7511. *
  7512. * @return array $beans
  7513. */
  7514. public static function findLinks( RedBean_OODBBean $bean, $type, $sql=" id IN (:keys) ", $values=array() ) {
  7515. $keys = self::$linkManager->getKeys($bean,$type);
  7516. $sql=str_replace(":keys",implode(",",$keys),$sql);
  7517. return self::find($type,$sql,$values);
  7518. }
  7519. /**
  7520. * Finds a bean using a type and a where clause (SQL).
  7521. * As with most Query tools in RedBean you can provide values to
  7522. * be inserted in the SQL statement by populating the value
  7523. * array parameter; you can either use the question mark notation
  7524. * or the slot-notation (:keyname).
  7525. * The variation also exports the beans (i.e. it returns arrays).
  7526. *
  7527. * @param string $type type
  7528. * @param string $sql sql
  7529. * @param array $values values
  7530. *
  7531. * @return array $arrays arrays
  7532. */
  7533. public static function findAndExport($type, $sql="1", $values=array()) {
  7534. $items = RedBean_Plugin_Finder::where( $type, $sql, $values );
  7535. $arr = array();
  7536. foreach($items as $key=>$item) {
  7537. $arr[$key]=$item->export();
  7538. }
  7539. return $arr;
  7540. }
  7541. /**
  7542. * Finds a bean using a type and a where clause (SQL).
  7543. * As with most Query tools in RedBean you can provide values to
  7544. * be inserted in the SQL statement by populating the value
  7545. * array parameter; you can either use the question mark notation
  7546. * or the slot-notation (:keyname).
  7547. * This variation returns the first bean only.
  7548. *
  7549. * @param string $type type
  7550. * @param string $sql sql
  7551. * @param array $values values
  7552. *
  7553. * @return RedBean_OODBBean $bean
  7554. */
  7555. public static function findOne( $type, $sql="1", $values=array()) {
  7556. $items = R::find($type,$sql,$values);
  7557. return reset($items);
  7558. }
  7559. /**
  7560. * Finds a bean using a type and a where clause (SQL).
  7561. * As with most Query tools in RedBean you can provide values to
  7562. * be inserted in the SQL statement by populating the value
  7563. * array parameter; you can either use the question mark notation
  7564. * or the slot-notation (:keyname).
  7565. * This variation returns the last bean only.
  7566. *
  7567. * @param string $type type
  7568. * @param string $sql sql
  7569. * @param array $values values
  7570. *
  7571. * @return RedBean_OODBBean $bean
  7572. */
  7573. public static function findLast( $type, $sql="1", $values=array() )
  7574. {
  7575. $items = R::find( $type, $sql, $values );
  7576. return end( $items );
  7577. }
  7578. /**
  7579. * Returns an array of beans.
  7580. *
  7581. * @param string $type type
  7582. * @param array $ids ids
  7583. *
  7584. * @return array $beans
  7585. */
  7586. public static function batch( $type, $ids ) {
  7587. return self::$redbean->batch($type, $ids);
  7588. }
  7589. /**
  7590. * Returns a simple list instead of beans, based
  7591. * on a type, property and an SQL where clause.
  7592. *
  7593. * @param string $type type
  7594. * @param string $prop property
  7595. * @param string $where SQL
  7596. *
  7597. * @return array $list array items
  7598. */
  7599. public static function lst( $type,$prop,$sql=" 1 " ) {
  7600. $list = self::find($type,$sql);
  7601. $listItems = array();
  7602. foreach($list as $id=>$item) {
  7603. $listItems[] = $item->$prop;
  7604. }
  7605. return $listItems;
  7606. }
  7607. /**
  7608. * Convenience function to execute Queries directly.
  7609. * Executes SQL.
  7610. *
  7611. * @param string $sql sql
  7612. * @param array $values values
  7613. *
  7614. * @return array $results
  7615. */
  7616. public static function exec( $sql, $values=array() ) {
  7617. return self::secureExec(function($sql, $values) {
  7618. return R::$adapter->exec( $sql, $values );
  7619. }, NULL,$sql, $values );
  7620. }
  7621. /**
  7622. * Convenience function to execute Queries directly.
  7623. * Executes SQL.
  7624. *
  7625. * @param string $sql sql
  7626. * @param array $values values
  7627. *
  7628. * @return array $results
  7629. */
  7630. public static function getAll( $sql, $values=array() ) {
  7631. return self::secureExec(function($sql, $values) {
  7632. return R::$adapter->get( $sql, $values );
  7633. }, array(), $sql, $values);
  7634. }
  7635. /**
  7636. * Convenience function to execute Queries directly.
  7637. * Executes SQL.
  7638. *
  7639. * @param string $sql sql
  7640. * @param array $values values
  7641. *
  7642. * @return string $result scalar
  7643. */
  7644. public static function getCell( $sql, $values=array() ) {
  7645. return self::secureExec(function($sql, $values) {
  7646. return R::$adapter->getCell( $sql, $values );
  7647. }, NULL, $sql, $values);
  7648. }
  7649. /**
  7650. * Convenience function to execute Queries directly.
  7651. * Executes SQL.
  7652. *
  7653. * @param string $sql sql
  7654. * @param array $values values
  7655. *
  7656. * @return array $results
  7657. */
  7658. public static function getRow( $sql, $values=array() ) {
  7659. return self::secureExec(function($sql, $values) {
  7660. return R::$adapter->getRow( $sql, $values );
  7661. }, array(),$sql, $values);
  7662. }
  7663. /**
  7664. * Convenience function to execute Queries directly.
  7665. * Executes SQL.
  7666. *
  7667. * @param string $sql sql
  7668. * @param array $values values
  7669. *
  7670. * @return array $results
  7671. */
  7672. public static function getCol( $sql, $values=array() ) {
  7673. return self::secureExec(function($sql, $values) {
  7674. return R::$adapter->getCol( $sql, $values );
  7675. }, array(),$sql, $values);
  7676. }
  7677. /**
  7678. * Executes SQL function but corrects for SQL states.
  7679. *
  7680. * @param closure $func closure
  7681. * @param mixed $default default value to return
  7682. * @param string $sql SQL
  7683. * @param array $values values for slots
  7684. *
  7685. * @return mixed $results
  7686. */
  7687. private static function secureExec( $func, $default=NULL, $sql, $values ) {
  7688. if (!self::$redbean->isFrozen()) {
  7689. try {
  7690. $rs = $func($sql,$values);
  7691. }catch(RedBean_Exception_SQL $e) {
  7692. if(self::$writer->sqlStateIn($e->getSQLState(),
  7693. array(
  7694. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
  7695. RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE)
  7696. )) {
  7697. return $default;
  7698. }
  7699. else {
  7700. throw $e;
  7701. }
  7702. }
  7703. return $rs;
  7704. }
  7705. else {
  7706. return $func($sql,$values);
  7707. }
  7708. }
  7709. /**
  7710. * Makes a copy of a bean. This method copies the bean and
  7711. * adds the specified associations.
  7712. *
  7713. * For instance: R::copy( $book, "author,library" );
  7714. *
  7715. * Duplicates the $book bean and copies the association links
  7716. * author and library as well. Note that only many-to-many
  7717. * associations can be copied. Also note that no author or library
  7718. * beans are copied, only the connections or references to these
  7719. * beans.
  7720. *
  7721. * @param RedBean_OODBBean $bean bean
  7722. * @param string $associatedBeanTypesStr bean types associated
  7723. *
  7724. * @return array $copiedBean the duplicated bean
  7725. */
  7726. public static function copy($bean, $associatedBeanTypesStr="") {
  7727. $type = $bean->getMeta("type");
  7728. $copy = R::dispense($type);
  7729. $copy->import( $bean->export() );
  7730. $copy->copyMetaFrom( $bean );
  7731. $copy->id = 0;
  7732. R::store($copy);
  7733. $associatedBeanTypes = explode(",",$associatedBeanTypesStr);
  7734. foreach($associatedBeanTypes as $associatedBeanType) {
  7735. $assocBeans = R::related($bean, $associatedBeanType);
  7736. foreach($assocBeans as $assocBean) {
  7737. R::associate($copy,$assocBean);
  7738. }
  7739. }
  7740. $copy->setMeta("original",$bean);
  7741. return $copy;
  7742. }
  7743. /**
  7744. * Given an array of two beans and a property, this method
  7745. * swaps the value of the property.
  7746. * This is handy if you need to swap the priority or orderNo
  7747. * of an item (i.e. bug-tracking, page order).
  7748. *
  7749. * @param array $beans beans
  7750. * @param string $property property
  7751. */
  7752. public static function swap( $beans, $property ) {
  7753. $bean1 = array_shift($beans);
  7754. $bean2 = array_shift($beans);
  7755. $tmp = $bean1->$property;
  7756. $bean1->$property = $bean2->$property;
  7757. $bean2->$property = $tmp;
  7758. R::store($bean1);
  7759. R::store($bean2);
  7760. }
  7761. /**
  7762. * Converts a series of rows to beans.
  7763. *
  7764. * @param string $type type
  7765. * @param array $rows must contain an array of arrays.
  7766. *
  7767. * @return array $beans
  7768. */
  7769. public static function convertToBeans($type,$rows) {
  7770. return self::$redbean->convertToBeans($type,$rows);
  7771. }
  7772. /**
  7773. * Tags a bean or returns tags associated with a bean.
  7774. * If $tagList is null or omitted this method will return a
  7775. * comma separated list of tags associated with the bean provided.
  7776. * If $tagList is a comma separated list (string) of tags all tags will
  7777. * be associated with the bean.
  7778. * You may also pass an array instead of a string.
  7779. *
  7780. * @param RedBean_OODBBean $bean bean
  7781. * @param mixed $tagList tags
  7782. *
  7783. * @return string $commaSepListTags
  7784. */
  7785. public static function tag( RedBean_OODBBean $bean, $tagList = null ) {
  7786. if (is_null($tagList)) {
  7787. $tags = R::related( $bean, "tag");
  7788. $foundTags = array();
  7789. foreach($tags as $tag) {
  7790. $foundTags[] = $tag->title;
  7791. }
  7792. return implode(",",$foundTags);
  7793. }
  7794. if ($tagList!==false && !is_array($tagList)) $tags = explode( ",", (string)$tagList); else $tags=$tagList;
  7795. if (is_array($tags)) {
  7796. foreach($tags as $tag) {
  7797. if (preg_match("/\W/",$tag)) throw new RedBean_Exception("Invalid Tag. Tags may only contain alpha-numeric characters");
  7798. }
  7799. }
  7800. R::clearRelations( $bean, "tag" );
  7801. if ($tagList===false) return;
  7802. foreach($tags as $tag) {
  7803. $t = R::findOne("tag"," title = ? ",array($tag));
  7804. if (!$t) {
  7805. $t = R::dispense("tag");
  7806. $t->title = $tag;
  7807. R::store($t);
  7808. }
  7809. R::associate( $bean, $t );
  7810. }
  7811. }
  7812. /**
  7813. * @static
  7814. * Returns all beans that have been tagged with one of the tags given.
  7815. *
  7816. * @param $beanType
  7817. * @param $tagList
  7818. *
  7819. * @return array
  7820. */
  7821. public static function tagged( $beanType, $tagList ) {
  7822. if ($tagList!==false && !is_array($tagList)) $tags = explode( ",", (string)$tagList); else $tags=$tagList;
  7823. $collection = array();
  7824. foreach($tags as $tag) {
  7825. $retrieved = array();
  7826. $tag = R::findOne("tag"," title = ? ", array($tag));
  7827. if ($tag) $retrieved = R::related($tag, $beanType);
  7828. foreach($retrieved as $key=>$bean) $collection[$key]=$bean;
  7829. }
  7830. return $collection;
  7831. }
  7832. /**
  7833. * Wipes all beans of type $beanType.
  7834. *
  7835. * @param string $beanType type of bean you want to destroy entirely.
  7836. */
  7837. public static function wipe( $beanType ) {
  7838. R::$redbean->wipe($beanType);
  7839. }
  7840. /**
  7841. * Counts beans
  7842. *
  7843. * @param string $beanType type of bean
  7844. *
  7845. * @return integer $numOfBeans
  7846. */
  7847. public static function count( $beanType ) {
  7848. return R::$redbean->count($beanType);
  7849. }
  7850. /**
  7851. * Configures the facade, want to have a new Writer? A new Object Database or a new
  7852. * Adapter and you want it on-the-fly? Use this method to hot-swap your facade with a new
  7853. * toolbox.
  7854. *
  7855. * @static
  7856. * @param RedBean_ToolBox $tb toolbox
  7857. *
  7858. * @return RedBean_ToolBox $tb old, rusty, previously used toolbox
  7859. */
  7860. public static function configureFacadeWithToolbox( RedBean_ToolBox $tb ) {
  7861. $oldTools = self::$toolbox;
  7862. self::$toolbox = $tb;
  7863. self::$writer = self::$toolbox->getWriter();
  7864. self::$adapter = self::$toolbox->getDatabaseAdapter();
  7865. self::$redbean = self::$toolbox->getRedBean();
  7866. self::$associationManager = new RedBean_AssociationManager( self::$toolbox );
  7867. self::$treeManager = new RedBean_TreeManager( self::$toolbox );
  7868. self::$linkManager = new RedBean_LinkManager( self::$toolbox );
  7869. self::$extAssocManager = new RedBean_ExtAssociationManager( self::$toolbox );
  7870. $helper = new RedBean_ModelHelper();
  7871. self::$redbean->addEventListener("update", $helper );
  7872. self::$redbean->addEventListener("open", $helper );
  7873. self::$redbean->addEventListener("delete", $helper );
  7874. self::$redbean->addEventListener("after_delete", $helper );
  7875. self::$redbean->addEventListener("after_update", $helper );
  7876. self::$redbean->addEventListener("dispense", $helper );
  7877. return $oldTools;
  7878. }
  7879. /**
  7880. * facade method for Cooker.
  7881. *
  7882. * @static
  7883. * @param $arr
  7884. * @return array
  7885. */
  7886. public static function cooker($arr) {
  7887. return RedBean_Cooker::load($arr, R::$toolbox);
  7888. }
  7889. }
  7890. /**
  7891. * BeanCan
  7892. * A Server Interface for RedBean and Fuse.
  7893. *
  7894. * The BeanCan Server is a lightweight, minimalistic server interface for
  7895. * RedBean that can perfectly act as an ORM middleware solution or a backend
  7896. * for an AJAX application.
  7897. *
  7898. * By Gabor de Mooij
  7899. *
  7900. */
  7901. class RedBean_BeanCan {
  7902. /**
  7903. * Holds a FUSE instance.
  7904. * @var RedBean_ModelHelper
  7905. */
  7906. private $modelHelper;
  7907. /**
  7908. * Constructor.
  7909. */
  7910. public function __construct() {
  7911. $this->modelHelper = new RedBean_ModelHelper;
  7912. }
  7913. /**
  7914. * Writes a response object for the client (JSON encoded).
  7915. *
  7916. * @param mixed $result result
  7917. * @param integer $id request ID
  7918. * @param integer $errorCode error code from server
  7919. * @param string $errorMessage error message from server
  7920. *
  7921. * @return string $json JSON encoded response.
  7922. */
  7923. private function resp($result=null, $id=null, $errorCode="-32603",$errorMessage="Internal Error") {
  7924. $response = array(
  7925. "jsonrpc"=>"2.0",
  7926. );
  7927. if ($id) {
  7928. $response["id"] = $id;
  7929. }
  7930. if ($result) {
  7931. $response["result"]=$result;
  7932. }
  7933. else {
  7934. $response["error"] = array(
  7935. "code"=>$errorCode,
  7936. "message"=>$errorMessage
  7937. );
  7938. }
  7939. return (json_encode($response));
  7940. }
  7941. /**
  7942. * Processes a JSON object request.
  7943. *
  7944. * @param array $jsonObject JSON request object
  7945. *
  7946. * @return mixed $result result
  7947. */
  7948. public function handleJSONRequest( $jsonString ) {
  7949. $jsonArray = json_decode($jsonString,true);
  7950. if (!$jsonArray) return $this->resp(null,null,-32700,"Cannot Parse JSON");
  7951. if (!isset($jsonArray["jsonrpc"])) return $this->resp(null,null,-32600,"No RPC version");
  7952. if (($jsonArray["jsonrpc"]!="2.0")) return $this->resp(null,null,-32600,"Incompatible RPC Version");
  7953. if (!isset($jsonArray["id"])) return $this->resp(null,null,-32600,"No ID");
  7954. $id = $jsonArray["id"];
  7955. if (!isset($jsonArray["method"])) return $this->resp(null,$id,-32600,"No method");
  7956. if (!isset($jsonArray["params"])) {
  7957. $data = array();
  7958. }
  7959. else {
  7960. $data = $jsonArray["params"];
  7961. }
  7962. $method = explode(":",trim($jsonArray["method"]));
  7963. if (count($method)!=2) {
  7964. return $this->resp(null, $id, -32600,"Invalid method signature. Use: BEAN:ACTION");
  7965. }
  7966. $beanType = $method[0];
  7967. $action = $method[1];
  7968. if (preg_match("/\W/",$beanType)) return $this->resp(null, $id, -32600,"Invalid Bean Type String");
  7969. if (preg_match("/\W/",$action)) return $this->resp(null, $id, -32600,"Invalid Action String");
  7970. try {
  7971. switch($action) {
  7972. case "store":
  7973. if (!isset($data[0])) return $this->resp(null, $id, -32602,"First param needs to be Bean Object");
  7974. $data = $data[0];
  7975. if (!isset($data["id"])) $bean = R::dispense($beanType); else
  7976. $bean = R::load($beanType,$data["id"]);
  7977. $bean->import( $data );
  7978. $rid = R::store($bean);
  7979. return $this->resp($rid, $id);
  7980. break;
  7981. case "load":
  7982. if (!isset($data[0])) return $this->resp(null, $id, -32602,"First param needs to be Bean ID");
  7983. $bean = R::load($beanType,$data[0]);
  7984. return $this->resp($bean->export(),$id);
  7985. break;
  7986. case "trash":
  7987. if (!isset($data[0])) return $this->resp(null, $id, -32602,"First param needs to be Bean ID");
  7988. $bean = R::load($beanType,$data[0]);
  7989. R::trash($bean);
  7990. return $this->resp("OK",$id);
  7991. break;
  7992. default:
  7993. $modelName = $this->modelHelper->getModelName( $beanType );
  7994. if (!class_exists($modelName)) return $this->resp(null, $id, -32601,"No such bean in the can!");
  7995. $beanModel = new $modelName;
  7996. if (!method_exists($beanModel,$action)) return $this->resp(null, $id, -32601,"Method not found in Bean: $beanType ");
  7997. return $this->resp( call_user_func_array(array($beanModel,$action), $data), $id);
  7998. }
  7999. }
  8000. catch(Exception $exception) {
  8001. return $this->resp(null, $id, -32099,$exception->getCode()."-".$exception->getMessage());
  8002. }
  8003. }
  8004. }
  8005. /**
  8006. * @name RedBean Cooker
  8007. * @file RedBean
  8008. * @author Gabor de Mooij and the RedBean Team
  8009. * @copyright Gabor de Mooij (c)
  8010. * @license BSD
  8011. *
  8012. * The Cooker is a little candy to make it easier to read-in an HTML form.
  8013. * This class turns a form into a collection of beans plus an array
  8014. * describing the desired associations.
  8015. *
  8016. * (c) G.J.G.T. (Gabor) de Mooij
  8017. * This source file is subject to the BSD/GPLv2 License that is bundled
  8018. * with this source code in the file license.txt.
  8019. */
  8020. class RedBean_Cooker {
  8021. /**
  8022. * This method will inspect the array provided and load/dispense the
  8023. * desired beans. To dispense a new bean, the array must contain:
  8024. *
  8025. * array( "newuser"=> array("type"=>"user","name"=>"John") )
  8026. *
  8027. * - Creates a new bean of type user, property name is set to "John"
  8028. *
  8029. * To load a bean (for association):
  8030. *
  8031. * array( "theaddress"=> array("type"=>"address","id"=>2) )
  8032. *
  8033. * - Loads a bean of type address with ID 2
  8034. *
  8035. * Now to associate this bean in your form:
  8036. *
  8037. * array("associations"=>array( "0" => array( "newuser-theaddress" ) ))
  8038. *
  8039. * - Associates the beans under keys newuser and theaddress.
  8040. *
  8041. * To modify an existing bean:
  8042. *
  8043. * array("existinguser"=>array("type"=>"user","id"=>2,"name"=>"Peter"))
  8044. *
  8045. * - Changes name of bean of type user with ID 2 to 'Peter'
  8046. *
  8047. * This function returns:
  8048. *
  8049. * array(
  8050. * "can" => an array with beans, either loaded or dispensed and populated
  8051. * "pairs" => an array with pairs of beans to be associated
  8052. * );
  8053. *
  8054. * Note that this function actually does not store or associate anything at all,
  8055. * it just prepares two arrays.
  8056. *
  8057. * @static
  8058. * @param $post the POST array containing the form data
  8059. * @return array hash table containing 'can' and 'pairs'
  8060. *
  8061. */
  8062. public static function load($post, RedBean_ToolBox $toolbox) {
  8063. $writer = $toolbox->getWriter();
  8064. if (isset($post["associations"])) {
  8065. $associations = $post["associations"];
  8066. unset($post["associations"]);
  8067. }
  8068. $can = $pairs = array();
  8069. foreach($post as $key => $rawBean) {
  8070. if (is_array($rawBean) && isset($rawBean["type"])) {
  8071. $type = $rawBean["type"];
  8072. unset($rawBean["type"]);
  8073. $idfield = $writer->getIDField($type);
  8074. if (isset($rawBean[$idfield])) {
  8075. $id = $rawBean[$idfield];
  8076. if ($id==0 && count($rawBean)===1) continue;
  8077. unset($rawBean[$idfield]);
  8078. $bean = R::load($type, $id);
  8079. }
  8080. else {
  8081. $bean = R::dispense($type);
  8082. }
  8083. foreach($rawBean as $field=>$value){
  8084. if (!empty($value)) $bean->$field = $value;
  8085. }
  8086. $can[$key]=$bean;
  8087. }
  8088. }
  8089. if (isset($associations) && is_array($associations)) {
  8090. foreach($associations as $assoc) {
  8091. foreach($assoc as $info) {
  8092. if ($info=="0" || $info=="") continue;
  8093. $keys = explode("-", $info);
  8094. if (isset($can[$keys[0]])) $bean1 = $can[$keys[0]]; else {
  8095. $loader = explode(":",$keys[0]);
  8096. $bean1 = R::load( $loader[0], $loader[1] );
  8097. }
  8098. $bean2 = $can[$keys[1]];
  8099. $pairs[] = array( $bean1, $bean2 );
  8100. }
  8101. }
  8102. }
  8103. return array("can"=>$can, "pairs"=>$pairs);
  8104. }
  8105. }