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;
26 * RedBean Version @version 4.3
28 * This class hides the object landscape of
29 * RedBeanPHP behind a single letter class providing
30 * almost all functionality with simple static calls.
32 * @file RedBeanPHP/Facade.php
33 * @author Gabor de Mooij and the RedBeanPHP Community
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.
44 * RedBeanPHP version constant.
46 const C_REDBEANPHP_VERSION = '4.3';
51 public static $toolbox;
56 private static $redbean;
61 private static $writer;
66 private static $adapter;
69 * @var AssociationManager
71 private static $associationManager;
76 private static $tagManager;
79 * @var DuplicationManager
81 private static $duplicationManager;
86 private static $labelMaker;
91 private static $finder;
96 private static $logger;
101 private static $plugins = array();
106 private static $exportCaseStyle = 'default';
109 * Not in use (backward compatibility SQLHelper)
116 public static $currentDB = '';
121 public static $toolboxes = array();
124 * Internal Query function, executes the desired query. Used by
125 * all facade query functions. This keeps things DRY.
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
133 private static function query( $method, $sql, $bindings )
135 if ( !self::$redbean->isFrozen() ) {
137 $rs = Facade::$adapter->$method( $sql, $bindings );
138 } catch ( SQLException $exception ) {
139 if ( self::$writer->sqlStateIn( $exception->getSQLState(),
141 QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
142 QueryWriter::C_SQLSTATE_NO_SUCH_TABLE )
145 return ( $method === 'getCell' ) ? NULL : array();
153 return Facade::$adapter->$method( $sql, $bindings );
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.
165 public static function getVersion()
167 return self::C_REDBEANPHP_VERSION;
171 * Tests the connection.
172 * Returns TRUE if connection has been established and
177 public static function testConnection()
179 if ( !isset( self::$adapter ) ) return FALSE;
181 $database = self::$adapter->getDatabase();
183 @$database->connect();
184 } catch ( \Exception $e ) {}
185 return $database->isConnected();
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).
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
200 public static function setup( $dsn = NULL, $username = NULL, $password = NULL, $frozen = FALSE )
202 if ( is_null( $dsn ) ) {
203 $dsn = 'sqlite:/' . sys_get_temp_dir() . '/red.db';
206 self::addDatabase( 'default', $dsn, $username, $password, $frozen );
207 self::selectDatabase( 'default' );
209 return self::$toolbox;
213 * Toggles Narrow Field Mode.
214 * See documentation in QueryWriter.
216 * @param boolean $mode TRUE = Narrow Field Mode
220 public static function setNarrowFieldMode( $mode )
222 AQueryWriter::setNarrowFieldMode( $mode );
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
240 * R::transaction(function() use($from, $to, $amount)
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);
251 * @param callable $callback Closure (or other callable) with the transaction logic
255 public static function transaction( $callback )
257 return Transaction::transaction( self::$adapter, $callback );
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.
267 * R::addDatabase( 'database-1', 'sqlite:/tmp/db1.txt' );
268 * R::selectDatabase( 'database-1' ); //to select database again
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.
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
282 public static function addDatabase( $key, $dsn, $user = NULL, $pass = NULL, $frozen = FALSE )
284 if ( isset( self::$toolboxes[$key] ) ) {
285 throw new RedException( 'A database has already been specified for this key.' );
288 if ( is_object($dsn) ) {
289 $db = new RPDO( $dsn );
290 $dbType = $db->getDatabaseType();
292 $db = new RPDO( $dsn, $user, $pass, TRUE );
293 $dbType = substr( $dsn, 0, strpos( $dsn, ':' ) );
296 $adapter = new DBAdapter( $db );
299 'pgsql' => 'PostgreSQL',
300 'sqlite' => 'SQLiteT',
301 'cubrid' => 'CUBRID',
303 'sqlsrv' => 'SQLServer',
306 $wkey = trim( strtolower( $dbType ) );
307 if ( !isset( $writers[$wkey] ) ) {
308 $wkey = preg_replace( '/\W/', '' , $wkey );
309 throw new RedException( 'Unsupported database ('.$wkey.').' );
311 $writerClass = '\\RedBeanPHP\\QueryWriter\\'.$writers[$wkey];
312 $writer = new $writerClass( $adapter );
313 $redbean = new OODB( $writer, $frozen );
315 self::$toolboxes[$key] = new ToolBox( $redbean, $adapter, $writer );
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.
323 * @param string $key the key/name of the database to check for
327 public static function hasDatabase( $key )
329 return ( isset( self::$toolboxes[$key] ) );
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).
342 * @param string $key Key of the database to select
346 public static function selectDatabase( $key )
348 if ( self::$currentDB === $key ) {
352 if ( !isset( self::$toolboxes[$key] ) ) {
353 throw new RedException( 'Database not found in registry. Add database using R::addDatabase().' );
356 self::configureFacadeWithToolbox( self::$toolboxes[$key] );
357 self::$currentDB = $key;
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.
369 * There are 2 debug styles:
371 * Classic: separate parameter bindings, explicit and complete but less readable
372 * Fancy: interpersed bindings, truncates large strings, highlighted schema changes
374 * Fancy style is more readable but sometimes incomplete.
376 * The first parameter turns debugging ON or OFF.
377 * The second parameter indicates the mode of operation:
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
384 * This function always returns the logger instance created to generate the
387 * @param boolean $tf debug mode (TRUE or FALSE)
388 * @param integer $mode mode of operation
391 * @throws RedException
393 public static function debug( $tf = TRUE, $mode = 0 )
399 $logger = new RDefault;
402 if ( !isset( self::$adapter ) ) {
403 throw new RedException( 'Use R::setup() first.' );
405 $logger->setMode($mode);
406 self::$adapter->getDatabase()->setDebugMode( $tf, $logger );
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
418 * @param boolean $toggle TRUE to activate debugger and select 'fancy' mode
422 public static function fancyDebug( $toggle = TRUE )
424 self::debug( $toggle, 2 );
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.
434 * @param string $type Type of bean (i.e. table) you want to inspect
438 public static function inspect( $type = NULL )
440 return ($type === NULL) ? self::$writer->getTables() : self::$writer->getColumns( $type );
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
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.
457 * @param OODBBean|SimpleModel $bean bean to store
459 * @return integer|string
461 public static function store( $bean )
463 return self::$redbean->store( $bean );
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.
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.
475 * @param boolean|array $trueFalse
477 public static function freeze( $tf = TRUE )
479 self::$redbean->freeze( $tf );
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.
488 * list( $author, $bio ) = R::loadMulti( 'author, bio', $id );
490 * @param string|array $types the set of types to load at once
491 * @param mixed $id the common ID
495 public static function loadMulti( $types, $id )
497 return MultiLoader::load( self::$redbean, $types, $id );
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().
514 * If the bean cannot be found in the database a new bean of
515 * the specified type will be generated and returned.
517 * @param string $type type of bean you want to load
518 * @param integer $id ID of the bean you want to load
522 public static function load( $type, $id )
524 return self::$redbean->load( $type, $id );
528 * Removes a bean from the database.
529 * This function will remove the specified OODBBean
530 * Bean Object from the database.
532 * This facade method also accepts a type-id combination,
533 * in the latter case this method will attempt to load the specified bean
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)
541 public static function trash( $beanOrType, $id = NULL )
543 if ( is_string( $beanOrType ) ) return self::trash( self::load( $beanOrType, $id ) );
544 return self::$redbean->trash( $beanOrType );
548 * Dispenses a new RedBean OODB Bean for use with
549 * the rest of the methods.
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
555 * @return array|OODBBean
557 public static function dispense( $typeOrBeanArray, $num = 1, $alwaysReturnArray = FALSE )
559 return DispenseHelper::dispense( self::$redbean, $typeOrBeanArray, $num, $alwaysReturnArray );
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.
570 * list( $book, $page, $text ) = R::dispenseAll( 'book,page,text' );
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.
579 * list($book, $pages) = R::dispenseAll('book,page*100');
582 * This returns an array with a book bean and then another array
583 * containing 100 page beans.
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
590 public static function dispenseAll( $order, $onlyArrays = FALSE )
592 return DispenseHelper::dispenseAll( self::$redbean, $order, $onlyArrays );
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.
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
606 public static function findOrDispense( $type, $sql = NULL, $bindings = array() )
608 return self::$finder->findOrDispense( $type, $sql, $bindings );
612 * Same as findOrDispense but returns just one element.
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
620 public static function findOneOrDispense( $type, $sql = NULL, $bindings = array() )
622 return reset( self::findOrDispense( $type, $sql, $bindings ) );
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).
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
638 public static function find( $type, $sql = NULL, $bindings = array() )
640 return self::$finder->find( $type, $sql, $bindings );
645 * The findAll() method differs from the find() method in that it does
646 * not assume a WHERE-clause, so this is valid:
648 * R::findAll('person',' ORDER BY name DESC ');
650 * Your SQL does not have to start with a valid WHERE-clause condition.
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
658 public static function findAll( $type, $sql = NULL, $bindings = array() )
660 return self::$finder->find( $type, $sql, $bindings );
665 * The variation also exports the beans (i.e. it returns arrays).
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
673 public static function findAndExport( $type, $sql = NULL, $bindings = array() )
675 return self::$finder->findAndExport( $type, $sql, $bindings );
680 * This variation returns the first bean only.
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
688 public static function findOne( $type, $sql = NULL, $bindings = array() )
690 return self::$finder->findOne( $type, $sql, $bindings );
695 * This variation returns the last bean only.
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
703 public static function findLast( $type, $sql = NULL, $bindings = array() )
705 return self::$finder->findLast( $type, $sql, $bindings );
709 * Finds a bean collection.
710 * Use this for large datasets.
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
716 * @return BeanCollection
718 public static function findCollection( $type, $sql = NULL, $bindings = array() )
720 return self::$finder->findCollection( $type, $sql, $bindings );
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().
728 * @see Finder::findMulti()
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
737 public static function findMulti( $types, $sql, $bindings = array(), $remappings = array() )
739 return self::$finder->findMulti( $types, $sql, $bindings, $remappings );
743 * Returns an array of beans. Pass a type and a series of ids and
744 * this method will bring you the corresponding beans.
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.
751 * @param string $type type of beans
752 * @param array $ids ids to load
756 public static function batch( $type, $ids )
758 return self::$redbean->batch( $type, $ids );
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
769 * @param string $type type of beans
770 * @param array $ids ids to load
774 public static function loadAll( $type, $ids )
776 return self::$redbean->batch( $type, $ids );
780 * Convenience function to execute Queries directly.
783 * @param string $sql SQL query to execute
784 * @param array $bindings a list of values to be bound to query parameters
788 public static function exec( $sql, $bindings = array() )
790 return self::query( 'exec', $sql, $bindings );
794 * Convenience function to execute Queries directly.
797 * @param string $sql SQL query to execute
798 * @param array $bindings a list of values to be bound to query parameters
802 public static function getAll( $sql, $bindings = array() )
804 return self::query( 'get', $sql, $bindings );
808 * Convenience function to execute Queries directly.
811 * @param string $sql SQL query to execute
812 * @param array $bindings a list of values to be bound to query parameters
816 public static function getCell( $sql, $bindings = array() )
818 return self::query( 'getCell', $sql, $bindings );
822 * Convenience function to execute Queries directly.
825 * @param string $sql SQL query to execute
826 * @param array $bindings a list of values to be bound to query parameters
830 public static function getRow( $sql, $bindings = array() )
832 return self::query( 'getRow', $sql, $bindings );
836 * Convenience function to execute Queries directly.
839 * @param string $sql SQL query to execute
840 * @param array $bindings a list of values to be bound to query parameters
844 public static function getCol( $sql, $bindings = array() )
846 return self::query( 'getCol', $sql, $bindings );
850 * Convenience function to execute Queries directly.
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.
858 * @param string $sql SQL query to execute
859 * @param array $bindings a list of values to be bound to query parameters
863 public static function getAssoc( $sql, $bindings = array() )
865 return self::query( 'getAssoc', $sql, $bindings );
869 * Convenience function to execute Queries directly.
871 * Results will be returned as an associative array indexed by the first
872 * column in the select.
874 * @param string $sql SQL query to execute
875 * @param array $bindings a list of values to be bound to query parameters
879 public static function getAssocRow( $sql, $bindings = array() )
881 return self::query( 'getAssocRow', $sql, $bindings );
885 * Returns the insert ID for databases that support/require this
886 * functionality. Alias for R::getAdapter()->getInsertID().
890 public static function getInsertID()
892 return self::$adapter->getInsertID();
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.
907 * This function does a reflectional database query so it may be slow.
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.
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
921 public static function dup( $bean, $trail = array(), $pid = FALSE, $filters = array() )
923 self::$duplicationManager->setFilters( $filters );
924 return self::$duplicationManager->dup( $bean, $trail, $pid );
928 * Makes a deep copy of a bean. This method makes a deep copy
929 * of the bean.The copy will have the following:
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
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.
941 * This function does a reflectional database query so it may be slow.
944 * This is a simplified version of the deprecated R::dup() function.
946 * @param OODBBean $bean bean to be copied
947 * @param array $white white list filter with bean types to duplicate
951 public static function duplicate( $bean, $filters = array() )
953 return self::dup( $bean, array(), FALSE, $filters );
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:
961 * * contents of the bean
962 * * all own bean lists (recursively)
963 * * all shared beans (not THEIR own lists)
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
971 public static function exportAll( $beans, $parents = FALSE, $filters = array())
973 return self::$duplicationManager->exportAll( $beans, $parents, $filters, self::$exportCaseStyle );
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:
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
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.
990 * @param string $caseStyle case style identifier
994 public static function useExportCase( $caseStyle = 'default' )
996 if ( !in_array( $caseStyle, array( 'default', 'camel', 'dolphin' ) ) ) throw new RedException( 'Invalid case selected.' );
997 self::$exportCaseStyle = $caseStyle;
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
1010 * $rows = R::getAll( 'SELECT * FROM ...' )
1011 * $beans = R::convertToBeans( $rows );
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).
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'];
1026 * @param string $type type of beans to produce
1027 * @param array $rows must contain an array of array
1031 public static function convertToBeans( $type, $rows, $metamask = NULL )
1033 return self::$redbean->convertToBeans( $type, $rows, $metamask );
1037 * Just like converToBeans, but for one bean.
1038 * @see convertToBeans for more details.
1040 * @param string $type type of beans to produce
1041 * @param array $row one row from the database
1045 public static function convertToBean( $type, $row, $metamask = NULL )
1047 $beans = self::$redbean->convertToBeans( $type, array( $row ), $metamask );
1048 $bean = reset( $beans );
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
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
1068 public static function hasTag( $bean, $tags, $all = FALSE )
1070 return self::$tagManager->hasTag( $bean, $tags, $all );
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.
1078 * @param OODBBean $bean tagged bean
1079 * @param array $tagList list of tags (names)
1083 public static function untag( $bean, $tagList )
1085 self::$tagManager->untag( $bean, $tagList );
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.
1097 * @param OODBBean $bean bean to tag
1098 * @param mixed $tagList tags to attach to the specified bean
1102 public static function tag( OODBBean $bean, $tagList = NULL )
1104 return self::$tagManager->tag( $bean, $tagList );
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.
1114 * @param OODBBean $bean bean to tag
1115 * @param array $tagList list of tags to add to bean
1119 public static function addTags( OODBBean $bean, $tagList )
1121 self::$tagManager->addTags( $bean, $tagList );
1125 * Part of RedBeanPHP Tagging API.
1126 * Returns all beans that have been tagged with one of the tags given.
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
1135 public static function tagged( $beanType, $tagList, $sql = '', $bindings = array() )
1137 return self::$tagManager->tagged( $beanType, $tagList, $sql, $bindings );
1141 * Part of RedBeanPHP Tagging API.
1142 * Returns all beans that have been tagged with ALL of the tags given.
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
1151 public static function taggedAll( $beanType, $tagList, $sql = '', $bindings = array() )
1153 return self::$tagManager->taggedAll( $beanType, $tagList, $sql, $bindings );
1157 * Wipes all beans of type $beanType.
1159 * @param string $beanType type of bean you want to destroy entirely
1163 public static function wipe( $beanType )
1165 return Facade::$redbean->wipe( $beanType );
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.
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
1179 public static function count( $type, $addSQL = '', $bindings = array() )
1181 return Facade::$redbean->count( $type, $addSQL, $bindings );
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
1189 * @param ToolBox $tb toolbox to configure facade with
1193 public static function configureFacadeWithToolbox( ToolBox $tb )
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 );
1213 * Facade Convience method for adapter transaction system.
1214 * Begins a transaction.
1218 public static function begin()
1220 if ( !self::$redbean->isFrozen() ) return FALSE;
1221 self::$adapter->startTransaction();
1226 * Facade Convience method for adapter transaction system.
1227 * Commits a transaction.
1231 public static function commit()
1233 if ( !self::$redbean->isFrozen() ) return FALSE;
1234 self::$adapter->commit();
1239 * Facade Convience method for adapter transaction system.
1240 * Rolls back a transaction.
1244 public static function rollback()
1246 if ( !self::$redbean->isFrozen() ) return FALSE;
1247 self::$adapter->rollback();
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!
1257 * @param string $table name of the table (not type) you want to get columns of
1261 public static function getColumns( $table )
1263 return self::$writer->getColumns( $table );
1267 * Generates question mark slots for an array of values.
1269 * @param array $array array to generate question mark slots for
1273 public static function genSlots( $array, $template = NULL )
1275 return ArrayTool::genSlots( $array, $template );
1279 * Flattens a multi dimensional bindings array for use with genSlots().
1281 * @param array $array array to flatten
1285 public static function flat( $array, $result = array() )
1287 return ArrayTool::flat( $array, $result );
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.
1295 * @warning dangerous method, will remove all tables, columns etc.
1299 public static function nuke()
1301 if ( !self::$redbean->isFrozen() ) {
1302 self::$writer->wipeAll();
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()
1312 * @param array $beans list of beans to be stored
1316 public static function storeAll( $beans )
1319 foreach ( $beans as $bean ) {
1320 $ids[] = self::store( $bean );
1326 * Short hand function to trash a set of beans at once.
1327 * For information please consult the R::trash() function.
1330 * @param array $beans list of beans to be trashed
1334 public static function trashAll( $beans )
1336 foreach ( $beans as $bean ) {
1337 self::trash( $bean );
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.
1352 * @param boolean $yesNo TRUE to enable cache, FALSE to disable cache
1356 public static function useWriterCache( $yesNo )
1358 self::getWriter()->setUseCache( $yesNo );
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
1367 * @param string $type type of beans you would like to have
1368 * @param array $labels list of labels, names for each bean
1372 public static function dispenseLabels( $type, $labels )
1374 return self::$labelMaker->dispenseLabels( $type, $labels );
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.
1382 * To obtain (and add if necessary) an ENUM value:
1385 * $tea->flavour = R::enum( 'flavour:apple' );
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.
1392 * To obtain all flavours:
1395 * R::enum('flavour');
1398 * To get a list of all flavour names:
1401 * R::gatherLabels( R::enum( 'flavour' ) );
1404 * @param string $enum either type or type-value
1406 * @return array|OODBBean
1408 public static function enum( $enum )
1410 return self::$labelMaker->enum( $enum );
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).
1419 * @param array $beans list of beans to loop
1423 public static function gatherLabels( $beans )
1425 return self::$labelMaker->gatherLabels( $beans );
1429 * Closes the database connection.
1433 public static function close()
1435 if ( isset( self::$adapter ) ) {
1436 self::$adapter->close();
1441 * Simple convenience function, returns ISO date formatted representation
1444 * @param mixed $time UNIX timestamp
1448 public static function isoDate( $time = NULL )
1454 return @date( 'Y-m-d', $time );
1458 * Simple convenience function, returns ISO date time
1459 * formatted representation
1462 * @param mixed $time UNIX timestamp
1466 public static function isoDateTime( $time = NULL )
1468 if ( !$time ) $time = time();
1469 return @date( 'Y-m-d H:i:s', $time );
1473 * Optional accessor for neat code.
1474 * Sets the database adapter you want to use.
1476 * @param Adapter $adapter Database Adapter for facade to use
1480 public static function setDatabaseAdapter( Adapter $adapter )
1482 self::$adapter = $adapter;
1486 * Optional accessor for neat code.
1487 * Sets the database adapter you want to use.
1489 * @param QueryWriter $writer Query Writer instance for facade to use
1493 public static function setWriter( QueryWriter $writer )
1495 self::$writer = $writer;
1499 * Optional accessor for neat code.
1500 * Sets the database adapter you want to use.
1502 * @param OODB $redbean Object Database for facade to use
1504 public static function setRedBean( OODB $redbean )
1506 self::$redbean = $redbean;
1510 * Optional accessor for neat code.
1511 * Sets the database adapter you want to use.
1515 public static function getDatabaseAdapter()
1517 return self::$adapter;
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:
1526 * R::getDatabaseAdapter()->getDatabase()->getPDO();
1529 * If the PDO object could not be found, for whatever reason, this method
1530 * will return NULL instead.
1534 public static function getPDO()
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();
1545 * Returns the current duplication manager instance.
1547 * @return DuplicationManager
1549 public static function getDuplicationManager()
1551 return self::$duplicationManager;
1555 * Optional accessor for neat code.
1556 * Sets the database adapter you want to use.
1558 * @return QueryWriter
1560 public static function getWriter()
1562 return self::$writer;
1566 * Optional accessor for neat code.
1567 * Sets the database adapter you want to use.
1571 public static function getRedBean()
1573 return self::$redbean;
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.
1584 public static function getToolBox()
1586 return self::$toolbox;
1590 * Mostly for internal use, but might be handy
1592 * This returns all the components of the currently
1595 * Returns the components in the following order:
1597 * # OODB instance (getRedBean())
1598 * # Database Adapter
1604 public static function getExtractedToolbox()
1606 return array( self::$redbean, self::$adapter, self::$writer, self::$toolbox );
1610 * Facade method for AQueryWriter::renameAssociation()
1612 * @param string|array $from
1617 public static function renameAssociation( $from, $to = NULL )
1619 AQueryWriter::renameAssociation( $from, $to );
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
1629 * @param array $beans beans
1633 public static function beansToArray( $beans )
1636 foreach( $beans as $bean ) $list[] = $bean->export();
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:
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
1654 * Custom handler method signature: handler( array (
1655 * 'message' => string
1656 * 'bean' => OODBBean
1657 * 'method' => string
1661 * This method returns the old mode and handler as an array.
1663 * @param integer $mode mode, determines how to handle errors
1664 * @param callable|NULL $func custom handler (if applicable)
1668 public static function setErrorHandlingFUSE( $mode, $func = NULL )
1670 return OODBBean::setErrorHandlingFUSE( $mode, $func );
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.
1679 * @param OODBBean|array $data either a bean or an array of beans
1683 public static function dump( $data )
1685 return Dump::dump( $data );
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.
1698 * R::bindFunc( 'read', 'location.point', 'asText' );
1699 * R::bindFunc( 'write', 'location.point', 'GeomFromText' );
1702 * Passing NULL as the function will reset (clear) the function
1703 * for this column/mode.
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
1711 public static function bindFunc( $mode, $field, $function )
1713 self::$redbean->bindFunc( $mode, $field, $function );
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.
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
1735 * The format of the aliases registration array is:
1737 * {alias} => {actual type}
1739 * In the example above we use:
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.
1748 * @param array $list list of global aliases to use
1752 public static function aliases( $list )
1754 OODBBean::aliases( $list );
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
1765 * @param string $type type of bean to search for
1766 * @param array $like criteria set describing the bean to search for
1770 public static function findOrCreate( $type, $like = array() )
1772 return self::$finder->findOrCreate( $type, $like );
1776 * Tries to find beans matching the specified type and
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.
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
1788 public static function findLike( $type, $like = array(), $sql = '' )
1790 return self::$finder->findLike( $type, $like, $sql );
1794 * Starts logging queries.
1795 * Use this method to start logging SQL queries being
1796 * executed by the adapter.
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.
1804 public static function startLogging()
1806 self::debug( TRUE, RDefault::C_LOGGER_ARRAY );
1810 * Stops logging, comfortable method to stop logging of queries.
1814 public static function stopLogging()
1816 self::debug( FALSE );
1820 * Returns the log entries written after the startLogging.
1824 public static function getLogs()
1826 return self::getLogger()->getLogs();
1830 * Resets the Query counter.
1834 public static function resetQueryCount()
1836 self::$adapter->getDatabase()->resetCounter();
1840 * Returns the number of SQL queries processed.
1844 public static function getQueryCount()
1846 return self::$adapter->getDatabase()->getQueryCount();
1850 * Returns the current logger instance being used by the
1855 public static function getLogger()
1857 return self::$adapter->getDatabase()->getLogger();
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.
1867 * @param boolean $automatic TRUE to enable automatic resolving aliased parents
1871 public static function setAutoResolve( $automatic = TRUE )
1873 OODBBean::setAutoResolve( (boolean) $automatic );
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
1885 * R::ext( 'makeTea', function() { ... } );
1888 * Now you can use your makeTea plugin like this:
1894 * @param string $pluginName name of the method to call the plugin
1895 * @param callable $callable a PHP callable
1899 public static function ext( $pluginName, $callable )
1901 if ( !ctype_alnum( $pluginName ) ) {
1902 throw new RedException( 'Plugin name may only contain alphanumeric characters.' );
1904 self::$plugins[$pluginName] = $callable;
1908 * Call static for use with dynamic plugins. This magic method will
1909 * intercept static calls and route them to the specified plugin.
1911 * @param string $pluginName name of the plugin
1912 * @param array $params list of arguments to pass to plugin method
1916 public static function __callStatic( $pluginName, $params )
1918 if ( !ctype_alnum( $pluginName) ) {
1919 throw new RedException( 'Plugin name may only contain alphanumeric characters.' );
1921 if ( !isset( self::$plugins[$pluginName] ) ) {
1922 throw new RedException( 'Plugin \''.$pluginName.'\' does not exist, add this plugin using: R::ext(\''.$pluginName.'\')' );
1924 return call_user_func_array( self::$plugins[$pluginName], $params );