Guest User

Untitled

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