Yaffs site version 1.1
[yaffs-website] / vendor / gabordemooij / redbean / RedBeanPHP / Facade.php
1 <?php
2
3 namespace RedBeanPHP;
4
5 use RedBeanPHP\QueryWriter as QueryWriter;
6 use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
7 use RedBeanPHP\RedException\SQL as SQLException;
8 use RedBeanPHP\Logger as Logger;
9 use RedBeanPHP\Logger\RDefault as RDefault;
10 use RedBeanPHP\Logger\RDefault\Debug as Debug;
11 use RedBeanPHP\Adapter as Adapter;
12 use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
13 use RedBeanPHP\RedException as RedException;
14 use RedBeanPHP\BeanHelper\SimpleFacadeBeanHelper as SimpleFacadeBeanHelper;
15 use RedBeanPHP\Driver\RPDO as RPDO;
16 use RedBeanPHP\Util\MultiLoader as MultiLoader;
17 use RedBeanPHP\Util\Transaction as Transaction;
18 use RedBeanPHP\Util\Dump as Dump;
19 use RedBeanPHP\Util\DispenseHelper as DispenseHelper;
20 use RedBeanPHP\Util\ArrayTool as ArrayTool;
21
22 /**
23  * RedBean Facade
24  *
25  * Version Information
26  * RedBean Version @version 4.3
27  *
28  * This class hides the object landscape of
29  * RedBeanPHP behind a single letter class providing
30  * almost all functionality with simple static calls.
31  *
32  * @file    RedBeanPHP/Facade.php
33  * @author  Gabor de Mooij and the RedBeanPHP Community
34  * @license BSD/GPLv2
35  *
36  * @copyright
37  * copyright (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community
38  * This source file is subject to the BSD/GPLv2 License that is bundled
39  * with this source code in the file license.txt.
40  */
41 class Facade
42 {
43         /**
44          * RedBeanPHP version constant.
45          */
46         const C_REDBEANPHP_VERSION = '4.3';
47
48         /**
49          * @var ToolBox
50          */
51         public static $toolbox;
52
53         /**
54          * @var OODB
55          */
56         private static $redbean;
57
58         /**
59          * @var QueryWriter
60          */
61         private static $writer;
62
63         /**
64          * @var DBAdapter
65          */
66         private static $adapter;
67
68         /**
69          * @var AssociationManager
70          */
71         private static $associationManager;
72
73         /**
74          * @var TagManager
75          */
76         private static $tagManager;
77
78         /**
79          * @var DuplicationManager
80          */
81         private static $duplicationManager;
82
83         /**
84          * @var LabelMaker
85          */
86         private static $labelMaker;
87
88         /**
89          * @var Finder
90          */
91         private static $finder;
92
93         /**
94          * @var Logger
95          */
96         private static $logger;
97
98         /**
99          * @var array
100          */
101         private static $plugins = array();
102
103         /**
104          * @var string
105          */
106         private static $exportCaseStyle = 'default';
107
108         /**
109          * Not in use (backward compatibility SQLHelper)
110          */
111         public static $f;
112
113         /**
114          * @var string
115          */
116         public static $currentDB = '';
117
118         /**
119          * @var array
120          */
121         public static $toolboxes = array();
122
123         /**
124          * Internal Query function, executes the desired query. Used by
125          * all facade query functions. This keeps things DRY.
126          *
127          * @param string $method   desired query method (i.e. 'cell', 'col', 'exec' etc..)
128          * @param string $sql      the sql you want to execute
129          * @param array  $bindings array of values to be bound to query statement
130          *
131          * @return array
132          */
133         private static function query( $method, $sql, $bindings )
134         {
135                 if ( !self::$redbean->isFrozen() ) {
136                         try {
137                                 $rs = Facade::$adapter->$method( $sql, $bindings );
138                         } catch ( SQLException $exception ) {
139                                 if ( self::$writer->sqlStateIn( $exception->getSQLState(),
140                                         array(
141                                                 QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
142                                                 QueryWriter::C_SQLSTATE_NO_SUCH_TABLE )
143                                         )
144                                 ) {
145                                         return ( $method === 'getCell' ) ? NULL : array();
146                                 } else {
147                                         throw $exception;
148                                 }
149                         }
150
151                         return $rs;
152                 } else {
153                         return Facade::$adapter->$method( $sql, $bindings );
154                 }
155         }
156
157         /**
158          * Returns the RedBeanPHP version string.
159          * The RedBeanPHP version string always has the same format "X.Y"
160          * where X is the major version number and Y is the minor version number.
161          * Point releases are not mentioned in the version string.
162          *
163          * @return string
164          */
165         public static function getVersion()
166         {
167                 return self::C_REDBEANPHP_VERSION;
168         }
169
170         /**
171          * Tests the connection.
172          * Returns TRUE if connection has been established and
173          * FALSE otherwise.
174          *
175          * @return boolean
176          */
177         public static function testConnection()
178         {
179                 if ( !isset( self::$adapter ) ) return FALSE;
180
181                 $database = self::$adapter->getDatabase();
182                 try {
183                         @$database->connect();
184                 } catch ( \Exception $e ) {}
185                 return $database->isConnected();
186         }
187
188         /**
189          * Kickstarts redbean for you. This method should be called before you start using
190          * RedBean. The Setup() method can be called without any arguments, in this case it will
191          * try to create a SQLite database in /tmp called red.db (this only works on UNIX-like systems).
192          *
193          * @param string  $dsn      Database connection string
194          * @param string  $username Username for database
195          * @param string  $password Password for database
196          * @param boolean $frozen   TRUE if you want to setup in frozen mode
197          *
198          * @return ToolBox
199          */
200         public static function setup( $dsn = NULL, $username = NULL, $password = NULL, $frozen = FALSE )
201         {
202                 if ( is_null( $dsn ) ) {
203                         $dsn = 'sqlite:/' . sys_get_temp_dir() . '/red.db';
204                 }
205
206                 self::addDatabase( 'default', $dsn, $username, $password, $frozen );
207                 self::selectDatabase( 'default' );
208
209                 return self::$toolbox;
210         }
211
212         /**
213          * Toggles Narrow Field Mode.
214          * See documentation in QueryWriter.
215          *
216          * @param boolean $mode TRUE = Narrow Field Mode
217          *
218          * @return void
219          */
220         public static function setNarrowFieldMode( $mode )
221         {
222                 AQueryWriter::setNarrowFieldMode( $mode );
223         }
224
225         /**
226          * Wraps a transaction around a closure or string callback.
227          * If an Exception is thrown inside, the operation is automatically rolled back.
228          * If no Exception happens, it commits automatically.
229          * It also supports (simulated) nested transactions (that is useful when
230          * you have many methods that needs transactions but are unaware of
231          * each other).
232          *
233          * Example:
234          *
235          * <code>
236          * $from = 1;
237          * $to = 2;
238          * $amount = 300;
239          *
240          * R::transaction(function() use($from, $to, $amount)
241          * {
242          *   $accountFrom = R::load('account', $from);
243          *   $accountTo = R::load('account', $to);
244          *   $accountFrom->money -= $amount;
245          *   $accountTo->money += $amount;
246          *   R::store($accountFrom);
247          *   R::store($accountTo);
248          * });
249          * </code>
250          *
251          * @param callable $callback Closure (or other callable) with the transaction logic
252          *
253          * @return mixed
254          */
255         public static function transaction( $callback )
256         {
257                 return Transaction::transaction( self::$adapter, $callback );
258         }
259
260         /**
261          * Adds a database to the facade, afterwards you can select the database using
262          * selectDatabase($key), where $key is the name you assigned to this database.
263          *
264          * Usage:
265          *
266          * <code>
267          * R::addDatabase( 'database-1', 'sqlite:/tmp/db1.txt' );
268          * R::selectDatabase( 'database-1' ); //to select database again
269          * </code>
270          *
271          * This method allows you to dynamically add (and select) new databases
272          * to the facade. Adding a database with the same key will cause an exception.
273          *
274          * @param string      $key    ID for the database
275          * @param string      $dsn    DSN for the database
276          * @param string      $user   user for connection
277          * @param NULL|string $pass   password for connection
278          * @param bool        $frozen whether this database is frozen or not
279          *
280          * @return void
281          */
282         public static function addDatabase( $key, $dsn, $user = NULL, $pass = NULL, $frozen = FALSE )
283         {
284                 if ( isset( self::$toolboxes[$key] ) ) {
285                         throw new RedException( 'A database has already been specified for this key.' );
286                 }
287
288                 if ( is_object($dsn) ) {
289                         $db  = new RPDO( $dsn );
290                         $dbType = $db->getDatabaseType();
291                 } else {
292                         $db = new RPDO( $dsn, $user, $pass, TRUE );
293                         $dbType = substr( $dsn, 0, strpos( $dsn, ':' ) );
294                 }
295
296                 $adapter = new DBAdapter( $db );
297
298                 $writers = array(
299                         'pgsql'  => 'PostgreSQL',
300                         'sqlite' => 'SQLiteT',
301                         'cubrid' => 'CUBRID',
302                         'mysql'  => 'MySQL',
303                         'sqlsrv' => 'SQLServer',
304                 );
305
306                 $wkey = trim( strtolower( $dbType ) );
307                 if ( !isset( $writers[$wkey] ) ) {
308                         $wkey = preg_replace( '/\W/', '' , $wkey );
309                         throw new RedException( 'Unsupported database ('.$wkey.').' );
310                 }
311                 $writerClass = '\\RedBeanPHP\\QueryWriter\\'.$writers[$wkey];
312                 $writer      = new $writerClass( $adapter );
313                 $redbean     = new OODB( $writer, $frozen );
314
315                 self::$toolboxes[$key] = new ToolBox( $redbean, $adapter, $writer );
316         }
317
318         /**
319          * Determines whether a database identified with the specified key has
320          * already been added to the facade. This function will return TRUE
321          * if the database indicated by the key is available and FALSE otherwise.
322          *
323          * @param string $key the key/name of the database to check for
324          *
325          * @return boolean
326          */
327         public static function hasDatabase( $key )
328         {
329                 return ( isset( self::$toolboxes[$key] ) );
330         }
331
332         /**
333          * Selects a different database for the Facade to work with.
334          * If you use the R::setup() you don't need this method. This method is meant
335          * for multiple database setups. This method selects the database identified by the
336          * database ID ($key). Use addDatabase() to add a new database, which in turn
337          * can be selected using selectDatabase(). If you use R::setup(), the resulting
338          * database will be stored under key 'default', to switch (back) to this database
339          * use R::selectDatabase( 'default' ). This method returns TRUE if the database has been
340          * switched and FALSE otherwise (for instance if you already using the specified database).
341          *
342          * @param  string $key Key of the database to select
343          *
344          * @return boolean
345          */
346         public static function selectDatabase( $key )
347         {
348                 if ( self::$currentDB === $key ) {
349                         return FALSE;
350                 }
351
352                 if ( !isset( self::$toolboxes[$key] ) ) {
353                         throw new RedException( 'Database not found in registry. Add database using R::addDatabase().' );
354                 }
355
356                 self::configureFacadeWithToolbox( self::$toolboxes[$key] );
357                 self::$currentDB = $key;
358
359                 return TRUE;
360         }
361
362         /**
363          * Toggles DEBUG mode.
364          * In Debug mode all SQL that happens under the hood will
365          * be printed to the screen and/or logged.
366          * If no database connection has been configured using R::setup() or
367          * R::selectDatabase() this method will throw an exception.
368          *
369          * There are 2 debug styles:
370          *
371          * Classic: separate parameter bindings, explicit and complete but less readable
372          * Fancy:   interpersed bindings, truncates large strings, highlighted schema changes
373          *
374          * Fancy style is more readable but sometimes incomplete.
375          *
376          * The first parameter turns debugging ON or OFF.
377          * The second parameter indicates the mode of operation:
378          *
379          * 0 Log and write to STDOUT classic style (default)
380          * 1 Log only, class style
381          * 2 Log and write to STDOUT fancy style
382          * 3 Log only, fancy style
383          *
384          * This function always returns the logger instance created to generate the
385          * debug messages.
386          *
387          * @param boolean $tf   debug mode (TRUE or FALSE)
388          * @param integer $mode mode of operation
389          *
390          * @return RDefault
391          * @throws RedException
392          */
393         public static function debug( $tf = TRUE, $mode = 0 )
394         {
395                 if ($mode > 1) {
396                         $mode -= 2;
397                         $logger = new Debug;
398                 } else {
399                         $logger = new RDefault;
400                 }
401
402                 if ( !isset( self::$adapter ) ) {
403                         throw new RedException( 'Use R::setup() first.' );
404                 }
405                 $logger->setMode($mode);
406                 self::$adapter->getDatabase()->setDebugMode( $tf, $logger );
407
408                 return $logger;
409         }
410
411         /**
412          * Turns on the fancy debugger.
413          * In 'fancy' mode the debugger will output queries with bound
414          * parameters inside the SQL itself. This method has been added to
415          * offer a convenient way to activate the fancy debugger system
416          * in one call.
417          *
418          * @param boolean $toggle TRUE to activate debugger and select 'fancy' mode
419          *
420          * @return void
421          */
422         public static function fancyDebug( $toggle = TRUE )
423         {
424                 self::debug( $toggle, 2 );
425         }
426
427         /**
428         * Inspects the database schema. If you pass the type of a bean this
429         * method will return the fields of its table in the database.
430         * The keys of this array will be the field names and the values will be
431         * the column types used to store their values.
432         * If no type is passed, this method returns a list of all tables in the database.
433         *
434         * @param string $type Type of bean (i.e. table) you want to inspect
435         *
436         * @return array
437         */
438         public static function inspect( $type = NULL )
439         {
440                 return ($type === NULL) ? self::$writer->getTables() : self::$writer->getColumns( $type );
441         }
442
443         /**
444          * Stores a bean in the database. This method takes a
445          * OODBBean Bean Object $bean and stores it
446          * in the database. If the database schema is not compatible
447          * with this bean and RedBean runs in fluid mode the schema
448          * will be altered to store the bean correctly.
449          * If the database schema is not compatible with this bean and
450          * RedBean runs in frozen mode it will throw an exception.
451          * This function returns the primary key ID of the inserted
452          * bean.
453          *
454          * The return value is an integer if possible. If it is not possible to
455          * represent the value as an integer a string will be returned.
456          *
457          * @param OODBBean|SimpleModel $bean bean to store
458          *
459          * @return integer|string
460          */
461         public static function store( $bean )
462         {
463                 return self::$redbean->store( $bean );
464         }
465
466         /**
467          * Toggles fluid or frozen mode. In fluid mode the database
468          * structure is adjusted to accomodate your objects. In frozen mode
469          * this is not the case.
470          *
471          * You can also pass an array containing a selection of frozen types.
472          * Let's call this chilly mode, it's just like fluid mode except that
473          * certain types (i.e. tables) aren't touched.
474          *
475          * @param boolean|array $trueFalse
476          */
477         public static function freeze( $tf = TRUE )
478         {
479                 self::$redbean->freeze( $tf );
480         }
481
482         /**
483          * Loads multiple types of beans with the same ID.
484          * This might look like a strange method, however it can be useful
485          * for loading a one-to-one relation.
486          *
487          * Usage:
488          * list( $author, $bio ) = R::loadMulti( 'author, bio', $id );
489          *
490          * @param string|array $types the set of types to load at once
491          * @param mixed        $id    the common ID
492          *
493          * @return OODBBean
494          */
495         public static function loadMulti( $types, $id )
496         {
497                 return MultiLoader::load( self::$redbean, $types, $id );
498         }
499
500         /**
501          * Loads a bean from the object database.
502          * It searches for a OODBBean Bean Object in the
503          * database. It does not matter how this bean has been stored.
504          * RedBean uses the primary key ID $id and the string $type
505          * to find the bean. The $type specifies what kind of bean you
506          * are looking for; this is the same type as used with the
507          * dispense() function. If RedBean finds the bean it will return
508          * the OODB Bean object; if it cannot find the bean
509          * RedBean will return a new bean of type $type and with
510          * primary key ID 0. In the latter case it acts basically the
511          * same as dispense().
512          *
513          * Important note:
514          * If the bean cannot be found in the database a new bean of
515          * the specified type will be generated and returned.
516          *
517          * @param string  $type type of bean you want to load
518          * @param integer $id   ID of the bean you want to load
519          *
520          * @return OODBBean
521          */
522         public static function load( $type, $id )
523         {
524                 return self::$redbean->load( $type, $id );
525         }
526
527         /**
528          * Removes a bean from the database.
529          * This function will remove the specified OODBBean
530          * Bean Object from the database.
531          *
532          * This facade method also accepts a type-id combination,
533          * in the latter case this method will attempt to load the specified bean
534          * and THEN trash it.
535          *
536          * @param string|OODBBean|SimpleModel $bean bean you want to remove from database
537          * @param integer                     $id   ID if the bean to trash (optional, type-id variant only)
538          *
539          * @return void
540          */
541         public static function trash( $beanOrType, $id = NULL )
542         {
543                 if ( is_string( $beanOrType ) ) return self::trash( self::load( $beanOrType, $id ) );
544                 return self::$redbean->trash( $beanOrType );
545         }
546
547         /**
548          * Dispenses a new RedBean OODB Bean for use with
549          * the rest of the methods.
550          *
551          * @param string|array $typeOrBeanArray   type or bean array to import
552          * @param integer      $number            number of beans to dispense
553          * @param boolean      $alwaysReturnArray if TRUE always returns the result as an array
554          *
555          * @return array|OODBBean
556          */
557         public static function dispense( $typeOrBeanArray, $num = 1, $alwaysReturnArray = FALSE )
558         {
559                 return DispenseHelper::dispense( self::$redbean, $typeOrBeanArray, $num, $alwaysReturnArray );
560         }
561
562         /**
563          * Takes a comma separated list of bean types
564          * and dispenses these beans. For each type in the list
565          * you can specify the number of beans to be dispensed.
566          *
567          * Usage:
568          *
569          * <code>
570          * list( $book, $page, $text ) = R::dispenseAll( 'book,page,text' );
571          * </code>
572          *
573          * This will dispense a book, a page and a text. This way you can
574          * quickly dispense beans of various types in just one line of code.
575          *
576          * Usage:
577          *
578          * <code>
579          * list($book, $pages) = R::dispenseAll('book,page*100');
580          * </code>
581          *
582          * This returns an array with a book bean and then another array
583          * containing 100 page beans.
584          *
585          * @param string  $order      a description of the desired dispense order using the syntax above
586          * @param boolean $onlyArrays return only arrays even if amount < 2
587          *
588          * @return array
589          */
590         public static function dispenseAll( $order, $onlyArrays = FALSE )
591         {
592                 return DispenseHelper::dispenseAll( self::$redbean, $order, $onlyArrays );
593         }
594
595         /**
596          * Convience method. Tries to find beans of a certain type,
597          * if no beans are found, it dispenses a bean of that type.
598          * Note that this function always returns an array.
599          *
600          * @param  string $type     type of bean you are looking for
601          * @param  string $sql      SQL code for finding the bean
602          * @param  array  $bindings parameters to bind to SQL
603          *
604          * @return array
605          */
606         public static function findOrDispense( $type, $sql = NULL, $bindings = array() )
607         {
608                 return self::$finder->findOrDispense( $type, $sql, $bindings );
609         }
610
611         /**
612          * Same as findOrDispense but returns just one element.
613          *
614          * @param  string $type     type of bean you are looking for
615          * @param  string $sql      SQL code for finding the bean
616          * @param  array  $bindings parameters to bind to SQL
617          *
618          * @return OODBBean
619          */
620         public static function findOneOrDispense( $type, $sql = NULL, $bindings = array() )
621         {
622                 return reset( self::findOrDispense( $type, $sql, $bindings ) );
623         }
624
625         /**
626          * Finds a bean using a type and a where clause (SQL).
627          * As with most Query tools in RedBean you can provide values to
628          * be inserted in the SQL statement by populating the value
629          * array parameter; you can either use the question mark notation
630          * or the slot-notation (:keyname).
631          *
632          * @param string $type     the type of bean you are looking for
633          * @param string $sql      SQL query to find the desired bean, starting right after WHERE clause
634          * @param array  $bindings array of values to be bound to parameters in query
635          *
636          * @return array
637          */
638         public static function find( $type, $sql = NULL, $bindings = array() )
639         {
640                 return self::$finder->find( $type, $sql, $bindings );
641         }
642
643         /**
644          * @see Facade::find
645          *      The findAll() method differs from the find() method in that it does
646          *      not assume a WHERE-clause, so this is valid:
647          *
648          * R::findAll('person',' ORDER BY name DESC ');
649          *
650          * Your SQL does not have to start with a valid WHERE-clause condition.
651          *
652          * @param string $type     the type of bean you are looking for
653          * @param string $sql      SQL query to find the desired bean, starting right after WHERE clause
654          * @param array  $bindings array of values to be bound to parameters in query
655          *
656          * @return array
657          */
658         public static function findAll( $type, $sql = NULL, $bindings = array() )
659         {
660                 return self::$finder->find( $type, $sql, $bindings );
661         }
662
663         /**
664          * @see Facade::find
665          * The variation also exports the beans (i.e. it returns arrays).
666          *
667          * @param string $type     the type of bean you are looking for
668          * @param string $sql      SQL query to find the desired bean, starting right after WHERE clause
669          * @param array  $bindings array of values to be bound to parameters in query
670          *
671          * @return array
672          */
673         public static function findAndExport( $type, $sql = NULL, $bindings = array() )
674         {
675                 return self::$finder->findAndExport( $type, $sql, $bindings );
676         }
677
678         /**
679          * @see Facade::find
680          * This variation returns the first bean only.
681          *
682          * @param string $type     the type of bean you are looking for
683          * @param string $sql      SQL query to find the desired bean, starting right after WHERE clause
684          * @param array  $bindings array of values to be bound to parameters in query
685          *
686          * @return OODBBean
687          */
688         public static function findOne( $type, $sql = NULL, $bindings = array() )
689         {
690                 return self::$finder->findOne( $type, $sql, $bindings );
691         }
692
693         /**
694          * @see Facade::find
695          * This variation returns the last bean only.
696          *
697          * @param string $type     the type of bean you are looking for
698          * @param string $sql      SQL query to find the desired bean, starting right after WHERE clause
699          * @param array  $bindings array of values to be bound to parameters in query
700          *
701          * @return OODBBean
702          */
703         public static function findLast( $type, $sql = NULL, $bindings = array() )
704         {
705                 return self::$finder->findLast( $type, $sql, $bindings );
706         }
707
708         /**
709          * Finds a bean collection.
710          * Use this for large datasets.
711          *
712          * @param string $type     the type of bean you are looking for
713          * @param string $sql      SQL query to find the desired bean, starting right after WHERE clause
714          * @param array  $bindings array of values to be bound to parameters in query
715          *
716          * @return BeanCollection
717          */
718         public static function findCollection( $type, $sql = NULL, $bindings = array() )
719         {
720                 return self::$finder->findCollection( $type, $sql, $bindings );
721         }
722
723         /**
724          * Finds multiple types of beans at once and offers additional
725          * remapping functionality. This is a very powerful yet complex function.
726          * For details see Finder::findMulti().
727          *
728          * @see Finder::findMulti()
729          *
730          * @param array|string $types      a list of bean types to find
731          * @param string|array $sqlOrArr   SQL query string or result set array
732          * @param array        $bindings   SQL bindings
733          * @param array        $remappings an array of remapping arrays containing closures
734          *
735          * @return array
736          */
737         public static function findMulti( $types, $sql, $bindings = array(), $remappings = array() )
738         {
739                 return self::$finder->findMulti( $types, $sql, $bindings, $remappings );
740         }
741
742         /**
743          * Returns an array of beans. Pass a type and a series of ids and
744          * this method will bring you the corresponding beans.
745          *
746          * important note: Because this method loads beans using the load()
747          * function (but faster) it will return empty beans with ID 0 for
748          * every bean that could not be located. The resulting beans will have the
749          * passed IDs as their keys.
750          *
751          * @param string $type type of beans
752          * @param array  $ids  ids to load
753          *
754          * @return array
755          */
756         public static function batch( $type, $ids )
757         {
758                 return self::$redbean->batch( $type, $ids );
759         }
760
761         /**
762          * @see Facade::batch
763          *
764          * Alias for batch(). Batch method is older but since we added so-called *All
765          * methods like storeAll, trashAll, dispenseAll and findAll it seemed logical to
766          * improve the consistency of the Facade API and also add an alias for batch() called
767          * loadAll.
768          *
769          * @param string $type type of beans
770          * @param array  $ids  ids to load
771          *
772          * @return array
773          */
774         public static function loadAll( $type, $ids )
775         {
776                 return self::$redbean->batch( $type, $ids );
777         }
778
779         /**
780          * Convenience function to execute Queries directly.
781          * Executes SQL.
782          *
783          * @param string $sql       SQL query to execute
784          * @param array  $bindings  a list of values to be bound to query parameters
785          *
786          * @return integer
787          */
788         public static function exec( $sql, $bindings = array() )
789         {
790                 return self::query( 'exec', $sql, $bindings );
791         }
792
793         /**
794          * Convenience function to execute Queries directly.
795          * Executes SQL.
796          *
797          * @param string $sql      SQL query to execute
798          * @param array  $bindings a list of values to be bound to query parameters
799          *
800          * @return array
801          */
802         public static function getAll( $sql, $bindings = array() )
803         {
804                 return self::query( 'get', $sql, $bindings );
805         }
806
807         /**
808          * Convenience function to execute Queries directly.
809          * Executes SQL.
810          *
811          * @param string $sql      SQL query to execute
812          * @param array  $bindings a list of values to be bound to query parameters
813          *
814          * @return string
815          */
816         public static function getCell( $sql, $bindings = array() )
817         {
818                 return self::query( 'getCell', $sql, $bindings );
819         }
820
821         /**
822          * Convenience function to execute Queries directly.
823          * Executes SQL.
824          *
825          * @param string $sql      SQL query to execute
826          * @param array  $bindings a list of values to be bound to query parameters
827          *
828          * @return array
829          */
830         public static function getRow( $sql, $bindings = array() )
831         {
832                 return self::query( 'getRow', $sql, $bindings );
833         }
834
835         /**
836          * Convenience function to execute Queries directly.
837          * Executes SQL.
838          *
839          * @param string $sql      SQL query to execute
840          * @param array  $bindings a list of values to be bound to query parameters
841          *
842          * @return array
843          */
844         public static function getCol( $sql, $bindings = array() )
845         {
846                 return self::query( 'getCol', $sql, $bindings );
847         }
848
849         /**
850          * Convenience function to execute Queries directly.
851          * Executes SQL.
852          * Results will be returned as an associative array. The first
853          * column in the select clause will be used for the keys in this array and
854          * the second column will be used for the values. If only one column is
855          * selected in the query, both key and value of the array will have the
856          * value of this field for each row.
857          *
858          * @param string $sql      SQL query to execute
859          * @param array  $bindings a list of values to be bound to query parameters
860          *
861          * @return array
862          */
863         public static function getAssoc( $sql, $bindings = array() )
864         {
865                 return self::query( 'getAssoc', $sql, $bindings );
866         }
867
868         /**
869          * Convenience function to execute Queries directly.
870          * Executes SQL.
871          * Results will be returned as an associative array indexed by the first
872          * column in the select.
873          *
874          * @param string $sql      SQL query to execute
875          * @param array  $bindings a list of values to be bound to query parameters
876          *
877          * @return array
878          */
879         public static function getAssocRow( $sql, $bindings = array() )
880         {
881                 return self::query( 'getAssocRow', $sql, $bindings );
882         }
883
884         /**
885          * Returns the insert ID for databases that support/require this
886          * functionality. Alias for R::getAdapter()->getInsertID().
887          *
888          * @return mixed
889          */
890         public static function getInsertID()
891         {
892                 return self::$adapter->getInsertID();
893         }
894
895         /**
896          * Makes a copy of a bean. This method makes a deep copy
897          * of the bean.The copy will have the following features.
898          * - All beans in own-lists will be duplicated as well
899          * - All references to shared beans will be copied but not the shared beans themselves
900          * - All references to parent objects (_id fields) will be copied but not the parents themselves
901          * In most cases this is the desired scenario for copying beans.
902          * This function uses a trail-array to prevent infinite recursion, if a recursive bean is found
903          * (i.e. one that already has been processed) the ID of the bean will be returned.
904          * This should not happen though.
905          *
906          * Note:
907          * This function does a reflectional database query so it may be slow.
908          *
909          * @deprecated
910          * This function is deprecated in favour of R::duplicate().
911          * This function has a confusing method signature, the R::duplicate() function
912          * only accepts two arguments: bean and filters.
913          *
914          * @param OODBBean $bean  bean to be copied
915          * @param array    $trail for internal usage, pass array()
916          * @param boolean  $pid   for internal usage
917          * @param array    $white white list filter with bean types to duplicate
918          *
919          * @return array
920          */
921         public static function dup( $bean, $trail = array(), $pid = FALSE, $filters = array() )
922         {
923                 self::$duplicationManager->setFilters( $filters );
924                 return self::$duplicationManager->dup( $bean, $trail, $pid );
925         }
926
927         /**
928          * Makes a deep copy of a bean. This method makes a deep copy
929          * of the bean.The copy will have the following:
930          *
931          * * All beans in own-lists will be duplicated as well
932          * * All references to shared beans will be copied but not the shared beans themselves
933          * * All references to parent objects (_id fields) will be copied but not the parents themselves
934          *
935          * In most cases this is the desired scenario for copying beans.
936          * This function uses a trail-array to prevent infinite recursion, if a recursive bean is found
937          * (i.e. one that already has been processed) the ID of the bean will be returned.
938          * This should not happen though.
939          *
940          * Note:
941          * This function does a reflectional database query so it may be slow.
942          *
943          * Note:
944          * This is a simplified version of the deprecated R::dup() function.
945          *
946          * @param OODBBean $bean  bean to be copied
947          * @param array    $white white list filter with bean types to duplicate
948          *
949          * @return array
950          */
951         public static function duplicate( $bean, $filters = array() )
952         {
953                 return self::dup( $bean, array(), FALSE, $filters );
954         }
955
956         /**
957          * Exports a collection of beans. Handy for XML/JSON exports with a
958          * Javascript framework like Dojo or ExtJS.
959          * What will be exported:
960          *
961          * * contents of the bean
962          * * all own bean lists (recursively)
963          * * all shared beans (not THEIR own lists)
964          *
965          * @param    array|OODBBean $beans   beans to be exported
966          * @param    boolean        $parents whether you want parent beans to be exported
967          * @param    array          $filters whitelist of types
968          *
969          * @return array
970          */
971         public static function exportAll( $beans, $parents = FALSE, $filters = array())
972         {
973                 return self::$duplicationManager->exportAll( $beans, $parents, $filters, self::$exportCaseStyle );
974         }
975
976         /**
977          * Selects case style for export.
978          * This will determine the case style for the keys of exported beans (see exportAll).
979          * The following options are accepted:
980          *
981          * * 'default' RedBeanPHP by default enforces Snake Case (i.e. book_id is_valid )
982          * * 'camel'   Camel Case   (i.e. bookId isValid   )
983          * * 'dolphin' Dolphin Case (i.e. bookID isValid   ) Like CamelCase but ID is written all uppercase
984          *
985          * @warning RedBeanPHP transforms camelCase to snake_case using a slightly different
986          * algorithm, it also converts isACL to is_acl (not is_a_c_l) and bookID to book_id.
987          * Due to information loss this cannot be corrected. However if you might try
988          * DolphinCase for IDs it takes into account the exception concerning IDs.
989          *
990          * @param string $caseStyle case style identifier
991          *
992          * @return void
993          */
994         public static function useExportCase( $caseStyle = 'default' )
995         {
996                 if ( !in_array( $caseStyle, array( 'default', 'camel', 'dolphin' ) ) ) throw new RedException( 'Invalid case selected.' );
997                 self::$exportCaseStyle = $caseStyle;
998         }
999
1000         /**
1001          * Converts a series of rows to beans.
1002          * This method converts a series of rows to beans.
1003          * The type of the desired output beans can be specified in the
1004          * first parameter. The second parameter is meant for the database
1005          * result rows.
1006          *
1007          * Usage:
1008          *
1009          * <code>
1010          * $rows = R::getAll( 'SELECT * FROM ...' )
1011          * $beans = R::convertToBeans( $rows );
1012          * </code>
1013          *
1014          * As of version 4.3.2 you can specify a meta-mask.
1015          * Data from columns with names starting with the value specified in the mask
1016          * will be transferred to the meta section of a bean (under data.bundle).
1017          *
1018          * <code>
1019          * $rows = R::getAll( 'SELECT FROM... COUNT(*) AS extra_count ...' );
1020          * $beans = R::convertToBeans( $rows );
1021          * $bean = reset( $beans );
1022          * $data = $bean->getMeta( 'data.bundle' );
1023          * $extra_count = $data['extra_count'];
1024          * </code>
1025          *
1026          * @param string $type type of beans to produce
1027          * @param array  $rows must contain an array of array
1028          *
1029          * @return array
1030          */
1031         public static function convertToBeans( $type, $rows, $metamask = NULL )
1032         {
1033                 return self::$redbean->convertToBeans( $type, $rows, $metamask );
1034         }
1035
1036         /**
1037          * Just like converToBeans, but for one bean.
1038          * @see convertToBeans for more details.
1039          *
1040          * @param string $type type of beans to produce
1041          * @param array  $row  one row from the database
1042          *
1043          * @return array
1044          */
1045         public static function convertToBean( $type, $row, $metamask = NULL )
1046         {
1047                 $beans = self::$redbean->convertToBeans( $type, array( $row ), $metamask );
1048                 $bean  = reset( $beans );
1049                 return $bean;
1050         }
1051
1052         /**
1053          * Part of RedBeanPHP Tagging API.
1054          * Tests whether a bean has been associated with one ore more
1055          * of the listed tags. If the third parameter is TRUE this method
1056          * will return TRUE only if all tags that have been specified are indeed
1057          * associated with the given bean, otherwise FALSE.
1058          * If the third parameter is FALSE this
1059          * method will return TRUE if one of the tags matches, FALSE if none
1060          * match.
1061          *
1062          * @param  OODBBean $bean bean to check for tags
1063          * @param  array    $tags list of tags
1064          * @param  boolean  $all  whether they must all match or just some
1065          *
1066          * @return boolean
1067          */
1068         public static function hasTag( $bean, $tags, $all = FALSE )
1069         {
1070                 return self::$tagManager->hasTag( $bean, $tags, $all );
1071         }
1072
1073         /**
1074          * Part of RedBeanPHP Tagging API.
1075          * Removes all specified tags from the bean. The tags specified in
1076          * the second parameter will no longer be associated with the bean.
1077          *
1078          * @param  OODBBean $bean    tagged bean
1079          * @param  array    $tagList list of tags (names)
1080          *
1081          * @return void
1082          */
1083         public static function untag( $bean, $tagList )
1084         {
1085                 self::$tagManager->untag( $bean, $tagList );
1086         }
1087
1088         /**
1089          * Part of RedBeanPHP Tagging API.
1090          * Tags a bean or returns tags associated with a bean.
1091          * If $tagList is NULL or omitted this method will return a
1092          * comma separated list of tags associated with the bean provided.
1093          * If $tagList is a comma separated list (string) of tags all tags will
1094          * be associated with the bean.
1095          * You may also pass an array instead of a string.
1096          *
1097          * @param OODBBean $bean    bean to tag
1098          * @param mixed    $tagList tags to attach to the specified bean
1099          *
1100          * @return string
1101          */
1102         public static function tag( OODBBean $bean, $tagList = NULL )
1103         {
1104                 return self::$tagManager->tag( $bean, $tagList );
1105         }
1106
1107         /**
1108          * Part of RedBeanPHP Tagging API.
1109          * Adds tags to a bean.
1110          * If $tagList is a comma separated list of tags all tags will
1111          * be associated with the bean.
1112          * You may also pass an array instead of a string.
1113          *
1114          * @param OODBBean $bean    bean to tag
1115          * @param array    $tagList list of tags to add to bean
1116          *
1117          * @return void
1118          */
1119         public static function addTags( OODBBean $bean, $tagList )
1120         {
1121                 self::$tagManager->addTags( $bean, $tagList );
1122         }
1123
1124         /**
1125          * Part of RedBeanPHP Tagging API.
1126          * Returns all beans that have been tagged with one of the tags given.
1127          *
1128          * @param string $beanType type of bean you are looking for
1129          * @param array  $tagList  list of tags to match
1130          * @param string $sql      additional SQL query snippet
1131          * @param array  $bindings a list of values to bind to the query parameters
1132          *
1133          * @return array
1134          */
1135         public static function tagged( $beanType, $tagList, $sql = '', $bindings = array() )
1136         {
1137                 return self::$tagManager->tagged( $beanType, $tagList, $sql, $bindings );
1138         }
1139
1140         /**
1141          * Part of RedBeanPHP Tagging API.
1142          * Returns all beans that have been tagged with ALL of the tags given.
1143          *
1144          * @param string $beanType type of bean you are looking for
1145          * @param array  $tagList  list of tags to match
1146          * @param string $sql      additional SQL query snippet
1147          * @param array  $bindings a list of values to bind to the query parameters
1148          *
1149          * @return array
1150          */
1151         public static function taggedAll( $beanType, $tagList, $sql = '', $bindings = array() )
1152         {
1153                 return self::$tagManager->taggedAll( $beanType, $tagList, $sql, $bindings );
1154         }
1155
1156         /**
1157          * Wipes all beans of type $beanType.
1158          *
1159          * @param string $beanType type of bean you want to destroy entirely
1160          *
1161          * @return boolean
1162          */
1163         public static function wipe( $beanType )
1164         {
1165                 return Facade::$redbean->wipe( $beanType );
1166         }
1167
1168         /**
1169          * Counts the number of beans of type $type.
1170          * This method accepts a second argument to modify the count-query.
1171          * A third argument can be used to provide bindings for the SQL snippet.
1172          *
1173          * @param string $type     type of bean we are looking for
1174          * @param string $addSQL   additional SQL snippet
1175          * @param array  $bindings parameters to bind to SQL
1176          *
1177          * @return integer
1178          */
1179         public static function count( $type, $addSQL = '', $bindings = array() )
1180         {
1181                 return Facade::$redbean->count( $type, $addSQL, $bindings );
1182         }
1183
1184         /**
1185          * Configures the facade, want to have a new Writer? A new Object Database or a new
1186          * Adapter and you want it on-the-fly? Use this method to hot-swap your facade with a new
1187          * toolbox.
1188          *
1189          * @param ToolBox $tb toolbox to configure facade with
1190          *
1191          * @return ToolBox
1192          */
1193         public static function configureFacadeWithToolbox( ToolBox $tb )
1194         {
1195                 $oldTools                 = self::$toolbox;
1196                 self::$toolbox            = $tb;
1197                 self::$writer             = self::$toolbox->getWriter();
1198                 self::$adapter            = self::$toolbox->getDatabaseAdapter();
1199                 self::$redbean            = self::$toolbox->getRedBean();
1200                 self::$finder             = new Finder( self::$toolbox );
1201                 self::$associationManager = new AssociationManager( self::$toolbox );
1202                 self::$redbean->setAssociationManager( self::$associationManager );
1203                 self::$labelMaker         = new LabelMaker( self::$toolbox );
1204                 $helper                   = new SimpleModelHelper();
1205                 $helper->attachEventListeners( self::$redbean );
1206                 self::$redbean->setBeanHelper( new SimpleFacadeBeanHelper );
1207                 self::$duplicationManager = new DuplicationManager( self::$toolbox );
1208                 self::$tagManager         = new TagManager( self::$toolbox );
1209                 return $oldTools;
1210         }
1211
1212         /**
1213          * Facade Convience method for adapter transaction system.
1214          * Begins a transaction.
1215          *
1216          * @return bool
1217          */
1218         public static function begin()
1219         {
1220                 if ( !self::$redbean->isFrozen() ) return FALSE;
1221                 self::$adapter->startTransaction();
1222                 return TRUE;
1223         }
1224
1225         /**
1226          * Facade Convience method for adapter transaction system.
1227          * Commits a transaction.
1228          *
1229          * @return bool
1230          */
1231         public static function commit()
1232         {
1233                 if ( !self::$redbean->isFrozen() ) return FALSE;
1234                 self::$adapter->commit();
1235                 return TRUE;
1236         }
1237
1238         /**
1239          * Facade Convience method for adapter transaction system.
1240          * Rolls back a transaction.
1241          *
1242          * @return bool
1243          */
1244         public static function rollback()
1245         {
1246                 if ( !self::$redbean->isFrozen() ) return FALSE;
1247                 self::$adapter->rollback();
1248                 return TRUE;
1249         }
1250
1251         /**
1252          * Returns a list of columns. Format of this array:
1253          * array( fieldname => type )
1254          * Note that this method only works in fluid mode because it might be
1255          * quite heavy on production servers!
1256          *
1257          * @param  string $table name of the table (not type) you want to get columns of
1258          *
1259          * @return array
1260          */
1261         public static function getColumns( $table )
1262         {
1263                 return self::$writer->getColumns( $table );
1264         }
1265
1266         /**
1267          * Generates question mark slots for an array of values.
1268          *
1269          * @param array  $array array to generate question mark slots for
1270          *
1271          * @return string
1272          */
1273         public static function genSlots( $array, $template = NULL )
1274         {
1275                 return ArrayTool::genSlots( $array, $template );
1276         }
1277
1278         /**
1279          * Flattens a multi dimensional bindings array for use with genSlots().
1280          *
1281          * @param array $array array to flatten
1282          *
1283          * @return array
1284          */
1285         public static function flat( $array, $result = array() )
1286         {
1287                 return ArrayTool::flat( $array, $result );
1288         }
1289
1290         /**
1291          * Nukes the entire database.
1292          * This will remove all schema structures from the database.
1293          * Only works in fluid mode. Be careful with this method.
1294          *
1295          * @warning dangerous method, will remove all tables, columns etc.
1296          *
1297          * @return void
1298          */
1299         public static function nuke()
1300         {
1301                 if ( !self::$redbean->isFrozen() ) {
1302                         self::$writer->wipeAll();
1303                 }
1304         }
1305
1306         /**
1307          * Short hand function to store a set of beans at once, IDs will be
1308          * returned as an array. For information please consult the R::store()
1309          * function.
1310          * A loop saver.
1311          *
1312          * @param array $beans list of beans to be stored
1313          *
1314          * @return array
1315          */
1316         public static function storeAll( $beans )
1317         {
1318                 $ids = array();
1319                 foreach ( $beans as $bean ) {
1320                         $ids[] = self::store( $bean );
1321                 }
1322                 return $ids;
1323         }
1324
1325         /**
1326          * Short hand function to trash a set of beans at once.
1327          * For information please consult the R::trash() function.
1328          * A loop saver.
1329          *
1330          * @param array $beans list of beans to be trashed
1331          *
1332          * @return void
1333          */
1334         public static function trashAll( $beans )
1335         {
1336                 foreach ( $beans as $bean ) {
1337                         self::trash( $bean );
1338                 }
1339         }
1340
1341         /**
1342          * Toggles Writer Cache.
1343          * Turns the Writer Cache on or off. The Writer Cache is a simple
1344          * query based caching system that may improve performance without the need
1345          * for cache management. This caching system will cache non-modifying queries
1346          * that are marked with special SQL comments. As soon as a non-marked query
1347          * gets executed the cache will be flushed. Only non-modifying select queries
1348          * have been marked therefore this mechanism is a rather safe way of caching, requiring
1349          * no explicit flushes or reloads. Of course this does not apply if you intend to test
1350          * or simulate concurrent querying.
1351          *
1352          * @param boolean $yesNo TRUE to enable cache, FALSE to disable cache
1353          *
1354          * @return void
1355          */
1356         public static function useWriterCache( $yesNo )
1357         {
1358                 self::getWriter()->setUseCache( $yesNo );
1359         }
1360
1361         /**
1362          * A label is a bean with only an id, type and name property.
1363          * This function will dispense beans for all entries in the array. The
1364          * values of the array will be assigned to the name property of each
1365          * individual bean.
1366          *
1367          * @param string $type   type of beans you would like to have
1368          * @param array  $labels list of labels, names for each bean
1369          *
1370          * @return array
1371          */
1372         public static function dispenseLabels( $type, $labels )
1373         {
1374                 return self::$labelMaker->dispenseLabels( $type, $labels );
1375         }
1376
1377         /**
1378          * Generates and returns an ENUM value. This is how RedBeanPHP handles ENUMs.
1379          * Either returns a (newly created) bean respresenting the desired ENUM
1380          * value or returns a list of all enums for the type.
1381          *
1382          * To obtain (and add if necessary) an ENUM value:
1383          *
1384          * <code>
1385          * $tea->flavour = R::enum( 'flavour:apple' );
1386          * </code>
1387          *
1388          * Returns a bean of type 'flavour' with  name = apple.
1389          * This will add a bean with property name (set to APPLE) to the database
1390          * if it does not exist yet.
1391          *
1392          * To obtain all flavours:
1393          *
1394          * <code>
1395          * R::enum('flavour');
1396          * </code>
1397          *
1398          * To get a list of all flavour names:
1399          *
1400          * <code>
1401          * R::gatherLabels( R::enum( 'flavour' ) );
1402          * </code>
1403          *
1404          * @param string $enum either type or type-value
1405          *
1406          * @return array|OODBBean
1407          */
1408         public static function enum( $enum )
1409         {
1410                 return self::$labelMaker->enum( $enum );
1411         }
1412
1413         /**
1414          * Gathers labels from beans. This function loops through the beans,
1415          * collects the values of the name properties of each individual bean
1416          * and stores the names in a new array. The array then gets sorted using the
1417          * default sort function of PHP (sort).
1418          *
1419          * @param array $beans list of beans to loop
1420          *
1421          * @return array
1422          */
1423         public static function gatherLabels( $beans )
1424         {
1425                 return self::$labelMaker->gatherLabels( $beans );
1426         }
1427
1428         /**
1429          * Closes the database connection.
1430          *
1431          * @return void
1432          */
1433         public static function close()
1434         {
1435                 if ( isset( self::$adapter ) ) {
1436                         self::$adapter->close();
1437                 }
1438         }
1439
1440         /**
1441          * Simple convenience function, returns ISO date formatted representation
1442          * of $time.
1443          *
1444          * @param mixed $time UNIX timestamp
1445          *
1446          * @return string
1447          */
1448         public static function isoDate( $time = NULL )
1449         {
1450                 if ( !$time ) {
1451                         $time = time();
1452                 }
1453
1454                 return @date( 'Y-m-d', $time );
1455         }
1456
1457         /**
1458          * Simple convenience function, returns ISO date time
1459          * formatted representation
1460          * of $time.
1461          *
1462          * @param mixed $time UNIX timestamp
1463          *
1464          * @return string
1465          */
1466         public static function isoDateTime( $time = NULL )
1467         {
1468                 if ( !$time ) $time = time();
1469                 return @date( 'Y-m-d H:i:s', $time );
1470         }
1471
1472         /**
1473          * Optional accessor for neat code.
1474          * Sets the database adapter you want to use.
1475          *
1476          * @param Adapter $adapter Database Adapter for facade to use
1477          *
1478          * @return void
1479          */
1480         public static function setDatabaseAdapter( Adapter $adapter )
1481         {
1482                 self::$adapter = $adapter;
1483         }
1484
1485         /**
1486          * Optional accessor for neat code.
1487          * Sets the database adapter you want to use.
1488          *
1489          * @param QueryWriter $writer Query Writer instance for facade to use
1490          *
1491          * @return void
1492          */
1493         public static function setWriter( QueryWriter $writer )
1494         {
1495                 self::$writer = $writer;
1496         }
1497
1498         /**
1499          * Optional accessor for neat code.
1500          * Sets the database adapter you want to use.
1501          *
1502          * @param OODB $redbean Object Database for facade to use
1503          */
1504         public static function setRedBean( OODB $redbean )
1505         {
1506                 self::$redbean = $redbean;
1507         }
1508
1509         /**
1510          * Optional accessor for neat code.
1511          * Sets the database adapter you want to use.
1512          *
1513          * @return DBAdapter
1514          */
1515         public static function getDatabaseAdapter()
1516         {
1517                 return self::$adapter;
1518         }
1519
1520         /**
1521          * In case you use PDO (which is recommended and the default but not mandatory, hence
1522          * the database adapter), you can use this method to obtain the PDO object directly.
1523          * This is a convenience method, it will do the same as:
1524          *
1525          * <code>
1526          * R::getDatabaseAdapter()->getDatabase()->getPDO();
1527          * </code>
1528          *
1529          * If the PDO object could not be found, for whatever reason, this method
1530          * will return NULL instead.
1531          *
1532          * @return NULL|PDO
1533          */
1534         public static function getPDO()
1535         {
1536                 $databaseAdapter = self::getDatabaseAdapter();
1537                 if ( is_null( $databaseAdapter ) ) return NULL;
1538                 $database = $databaseAdapter->getDatabase();
1539                 if ( is_null( $database ) ) return NULL;
1540                 if ( !method_exists( $database, 'getPDO' ) ) return NULL;
1541                 return $database->getPDO();
1542         }
1543
1544         /**
1545          * Returns the current duplication manager instance.
1546          *
1547          * @return DuplicationManager
1548          */
1549         public static function getDuplicationManager()
1550         {
1551                 return self::$duplicationManager;
1552         }
1553
1554         /**
1555          * Optional accessor for neat code.
1556          * Sets the database adapter you want to use.
1557          *
1558          * @return QueryWriter
1559          */
1560         public static function getWriter()
1561         {
1562                 return self::$writer;
1563         }
1564
1565         /**
1566          * Optional accessor for neat code.
1567          * Sets the database adapter you want to use.
1568          *
1569          * @return OODB
1570          */
1571         public static function getRedBean()
1572         {
1573                 return self::$redbean;
1574         }
1575
1576         /**
1577          * Returns the toolbox currently used by the facade.
1578          * To set the toolbox use R::setup() or R::configureFacadeWithToolbox().
1579          * To create a toolbox use Setup::kickstart(). Or create a manual
1580          * toolbox using the ToolBox class.
1581          *
1582          * @return ToolBox
1583          */
1584         public static function getToolBox()
1585         {
1586                 return self::$toolbox;
1587         }
1588
1589         /**
1590          * Mostly for internal use, but might be handy
1591          * for some users.
1592          * This returns all the components of the currently
1593          * selected toolbox.
1594          *
1595          * Returns the components in the following order:
1596          *
1597          * # OODB instance (getRedBean())
1598          * # Database Adapter
1599          * # Query Writer
1600          * # Toolbox itself
1601          *
1602          * @return array
1603          */
1604         public static function getExtractedToolbox()
1605         {
1606                 return array( self::$redbean, self::$adapter, self::$writer, self::$toolbox );
1607         }
1608
1609         /**
1610          * Facade method for AQueryWriter::renameAssociation()
1611          *
1612          * @param string|array $from
1613          * @param string       $to
1614          *
1615          * @return void
1616          */
1617         public static function renameAssociation( $from, $to = NULL )
1618         {
1619                 AQueryWriter::renameAssociation( $from, $to );
1620         }
1621
1622         /**
1623          * Little helper method for Resty Bean Can server and others.
1624          * Takes an array of beans and exports each bean.
1625          * Unlike exportAll this method does not recurse into own lists
1626          * and shared lists, the beans are exported as-is, only loaded lists
1627          * are exported.
1628          *
1629          * @param array $beans beans
1630          *
1631          * @return array
1632          */
1633         public static function beansToArray( $beans )
1634         {
1635                 $list = array();
1636                 foreach( $beans as $bean ) $list[] = $bean->export();
1637                 return $list;
1638         }
1639
1640         /**
1641          * Sets the error mode for FUSE.
1642          * What to do if a FUSE model method does not exist?
1643          * You can set the following options:
1644          *
1645          * * OODBBean::C_ERR_IGNORE (default), ignores the call, returns NULL
1646          * * OODBBean::C_ERR_LOG, logs the incident using error_log
1647          * * OODBBean::C_ERR_NOTICE, triggers a E_USER_NOTICE
1648          * * OODBBean::C_ERR_WARN, triggers a E_USER_WARNING
1649          * * OODBBean::C_ERR_EXCEPTION, throws an exception
1650          * * OODBBean::C_ERR_FUNC, allows you to specify a custom handler (function)
1651          * * OODBBean::C_ERR_FATAL, triggers a E_USER_ERROR
1652          *
1653          * <code>
1654          * Custom handler method signature: handler( array (
1655          *      'message' => string
1656          *      'bean' => OODBBean
1657          *      'method' => string
1658          * ) )
1659          * </code>
1660          *
1661          * This method returns the old mode and handler as an array.
1662          *
1663          * @param integer       $mode mode, determines how to handle errors
1664          * @param callable|NULL $func custom handler (if applicable)
1665          *
1666          * @return array
1667          */
1668         public static function setErrorHandlingFUSE( $mode, $func = NULL )
1669         {
1670                 return OODBBean::setErrorHandlingFUSE( $mode, $func );
1671         }
1672
1673         /**
1674          * Simple but effective debug function.
1675          * Given a one or more beans this method will
1676          * return an array containing first part of the string
1677          * representation of each item in the array.
1678          *
1679          * @param OODBBean|array $data either a bean or an array of beans
1680          *
1681          * @return array
1682          */
1683         public static function dump( $data )
1684         {
1685                 return Dump::dump( $data );
1686         }
1687
1688         /**
1689          * Binds an SQL function to a column.
1690          * This method can be used to setup a decode/encode scheme or
1691          * perform UUID insertion. This method is especially useful for handling
1692          * MySQL spatial columns, because they need to be processed first using
1693          * the asText/GeomFromText functions.
1694          *
1695          * Example:
1696          *
1697          * <code>
1698          * R::bindFunc( 'read', 'location.point', 'asText' );
1699          * R::bindFunc( 'write', 'location.point', 'GeomFromText' );
1700          * </code>
1701          *
1702          * Passing NULL as the function will reset (clear) the function
1703          * for this column/mode.
1704          *
1705          * @param string $mode     mode for function: i.e. read or write
1706          * @param string $field    field (table.column) to bind function to
1707          * @param string $function SQL function to bind to specified column
1708          *
1709          * @return void
1710          */
1711         public static function bindFunc( $mode, $field, $function )
1712         {
1713                 self::$redbean->bindFunc( $mode, $field, $function );
1714         }
1715
1716         /**
1717          * Sets global aliases.
1718          * Registers a batch of aliases in one go. This works the same as
1719          * fetchAs and setAutoResolve but explicitly. For instance if you register
1720          * the alias 'cover' for 'page' a property containing a reference to a
1721          * page bean called 'cover' will correctly return the page bean and not
1722          * a (non-existant) cover bean.
1723          *
1724          * <code>
1725          * R::aliases( array( 'cover' => 'page' ) );
1726          * $book = R::dispense( 'book' );
1727          * $page = R::dispense( 'page' );
1728          * $book->cover = $page;
1729          * R::store( $book );
1730          * $book = $book->fresh();
1731          * $cover = $book->cover;
1732          * echo $cover->getMeta( 'type' ); //page
1733          * </code>
1734          *
1735          * The format of the aliases registration array is:
1736          *
1737          * {alias} => {actual type}
1738          *
1739          * In the example above we use:
1740          *
1741          * cover => page
1742          *
1743          * From that point on, every bean reference to a cover
1744          * will return a 'page' bean. Note that with autoResolve this
1745          * feature along with fetchAs() is no longer very important, although
1746          * relying on explicit aliases can be a bit faster.
1747          *
1748          * @param array $list list of global aliases to use
1749          *
1750          * @return void
1751          */
1752         public static function aliases( $list )
1753         {
1754                 OODBBean::aliases( $list );
1755         }
1756
1757         /**
1758          * Tries to find a bean matching a certain type and
1759          * criteria set. If no beans are found a new bean
1760          * will be created, the criteria will be imported into this
1761          * bean and the bean will be stored and returned.
1762          * If multiple beans match the criteria only the first one
1763          * will be returned.
1764          *
1765          * @param string $type type of bean to search for
1766          * @param array  $like criteria set describing the bean to search for
1767          *
1768          * @return OODBBean
1769          */
1770         public static function findOrCreate( $type, $like = array() )
1771         {
1772                 return self::$finder->findOrCreate( $type, $like );
1773         }
1774
1775         /**
1776          * Tries to find beans matching the specified type and
1777          * criteria set.
1778          *
1779          * If the optional additional SQL snippet is a condition, it will
1780          * be glued to the rest of the query using the AND operator.
1781          *
1782          * @param string $type type of bean to search for
1783          * @param array  $like optional criteria set describing the bean to search for
1784          * @param string $sql  optional additional SQL for sorting
1785          *
1786          * @return array
1787          */
1788         public static function findLike( $type, $like = array(), $sql = '' )
1789         {
1790                 return self::$finder->findLike( $type, $like, $sql );
1791         }
1792
1793         /**
1794          * Starts logging queries.
1795          * Use this method to start logging SQL queries being
1796          * executed by the adapter.
1797          *
1798          * @note you cannot use R::debug and R::startLogging
1799          * at the same time because R::debug is essentially a
1800          * special kind of logging.
1801          *
1802          * @return void
1803          */
1804         public static function startLogging()
1805         {
1806                 self::debug( TRUE, RDefault::C_LOGGER_ARRAY );
1807         }
1808
1809         /**
1810          * Stops logging, comfortable method to stop logging of queries.
1811          *
1812          * @return void
1813          */
1814         public static function stopLogging()
1815         {
1816                 self::debug( FALSE );
1817         }
1818
1819         /**
1820          * Returns the log entries written after the startLogging.
1821          *
1822          * @return array
1823          */
1824         public static function getLogs()
1825         {
1826                 return self::getLogger()->getLogs();
1827         }
1828
1829         /**
1830          * Resets the Query counter.
1831          *
1832          * @return integer
1833          */
1834         public static function resetQueryCount()
1835         {
1836                 self::$adapter->getDatabase()->resetCounter();
1837         }
1838
1839         /**
1840          * Returns the number of SQL queries processed.
1841          *
1842          * @return integer
1843          */
1844         public static function getQueryCount()
1845         {
1846                 return self::$adapter->getDatabase()->getQueryCount();
1847         }
1848
1849         /**
1850          * Returns the current logger instance being used by the
1851          * database object.
1852          *
1853          * @return Logger
1854          */
1855         public static function getLogger()
1856         {
1857                 return self::$adapter->getDatabase()->getLogger();
1858         }
1859
1860         /**
1861          * Alias for setAutoResolve() method on OODBBean.
1862          * Enables or disables auto-resolving fetch types.
1863          * Auto-resolving aliased parent beans is convenient but can
1864          * be slower and can create infinite recursion if you
1865          * used aliases to break cyclic relations in your domain.
1866          *
1867          * @param boolean $automatic TRUE to enable automatic resolving aliased parents
1868          *
1869          * @return void
1870          */
1871         public static function setAutoResolve( $automatic = TRUE )
1872         {
1873                 OODBBean::setAutoResolve( (boolean) $automatic );
1874         }
1875
1876         /**
1877          * Dynamically extends the facade with a plugin.
1878          * Using this method you can register your plugin with the facade and then
1879          * use the plugin by invoking the name specified plugin name as a method on
1880          * the facade.
1881          *
1882          * Usage:
1883          *
1884          * <code>
1885          * R::ext( 'makeTea', function() { ... }  );
1886          * </code>
1887          *
1888          * Now you can use your makeTea plugin like this:
1889          *
1890          * <code>
1891          * R::makeTea();
1892          * </code>
1893          *
1894          * @param string   $pluginName name of the method to call the plugin
1895          * @param callable $callable   a PHP callable
1896          *
1897          * @return void
1898          */
1899         public static function ext( $pluginName, $callable )
1900         {
1901                 if ( !ctype_alnum( $pluginName ) ) {
1902                         throw new RedException( 'Plugin name may only contain alphanumeric characters.' );
1903                 }
1904                 self::$plugins[$pluginName] = $callable;
1905         }
1906
1907         /**
1908          * Call static for use with dynamic plugins. This magic method will
1909          * intercept static calls and route them to the specified plugin.
1910          *
1911          * @param string $pluginName name of the plugin
1912          * @param array  $params     list of arguments to pass to plugin method
1913          *
1914          * @return mixed
1915          */
1916         public static function __callStatic( $pluginName, $params )
1917         {
1918                 if ( !ctype_alnum( $pluginName) ) {
1919                         throw new RedException( 'Plugin name may only contain alphanumeric characters.' );
1920                 }
1921                 if ( !isset( self::$plugins[$pluginName] ) ) {
1922                         throw new RedException( 'Plugin \''.$pluginName.'\' does not exist, add this plugin using: R::ext(\''.$pluginName.'\')' );
1923                 }
1924                 return call_user_func_array( self::$plugins[$pluginName], $params );
1925         }
1926 }
1927