5 use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
6 use RedBeanPHP\QueryWriter as QueryWriter;
7 use RedBeanPHP\BeanHelper as BeanHelper;
8 use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
9 use RedBeanPHP\Repository as Repository;
10 use RedBeanPHP\Repository\Fluid as FluidRepo;
11 use RedBeanPHP\Repository\Frozen as FrozenRepo;
14 * RedBean Object Oriented DataBase.
16 * The RedBean OODB Class is the main class of RedBeanPHP.
17 * It takes OODBBean objects and stores them to and loads them from the
18 * database as well as providing other CRUD functions. This class acts as a
21 * @file RedBeanPHP/OODB.php
22 * @author Gabor de Mooij and the RedBeanPHP community
26 * copyright (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community
27 * This source file is subject to the BSD/GPLv2 License that is bundled
28 * with this source code in the file license.txt.
30 class OODB extends Observable
35 private static $sqlFilters = array();
40 protected $chillList = array();
45 protected $stash = NULL;
50 protected $nesting = 0;
60 protected $isFrozen = FALSE;
63 * @var FacadeBeanHelper
65 protected $beanhelper = NULL;
68 * @var AssociationManager
70 protected $assocManager = NULL;
75 protected $repository = NULL;
80 protected $frozenRepository = NULL;
85 protected $fluidRepository = NULL;
90 protected static $autoClearHistoryAfterStore = FALSE;
93 * If set to TRUE, this method will call clearHistory every time
94 * the bean gets stored.
96 * @param boolean $autoClear auto clear option
100 public static function autoClearHistoryAfterStore( $autoClear = TRUE )
102 self::$autoClearHistoryAfterStore = (boolean) $autoClear;
106 * Unboxes a bean from a FUSE model if needed and checks whether the bean is
107 * an instance of OODBBean.
109 * @param OODBBean $bean bean you wish to unbox
113 protected function unboxIfNeeded( $bean )
115 if ( $bean instanceof SimpleModel ) {
116 $bean = $bean->unbox();
118 if ( !( $bean instanceof OODBBean ) ) {
119 throw new RedException( 'OODB Store requires a bean, got: ' . gettype( $bean ) );
126 * Constructor, requires a query writer.
128 * @param QueryWriter $writer writer
129 * @param array|boolean $frozen mode of operation: TRUE (frozen), FALSE (default, fluid) or ARRAY (chilled)
131 public function __construct( QueryWriter $writer, $frozen = FALSE )
133 if ( $writer instanceof QueryWriter ) {
134 $this->writer = $writer;
137 $this->freeze( $frozen );
141 * Toggles fluid or frozen mode. In fluid mode the database
142 * structure is adjusted to accomodate your objects. In frozen mode
143 * this is not the case.
145 * You can also pass an array containing a selection of frozen types.
146 * Let's call this chilly mode, it's just like fluid mode except that
147 * certain types (i.e. tables) aren't touched.
149 * @param boolean|array $toggle TRUE if you want to use OODB instance in frozen mode
153 public function freeze( $toggle )
155 if ( is_array( $toggle ) ) {
156 $this->chillList = $toggle;
157 $this->isFrozen = FALSE;
159 $this->isFrozen = (boolean) $toggle;
162 if ( $this->isFrozen ) {
163 if ( !$this->frozenRepository ) {
164 $this->frozenRepository = new FrozenRepo( $this, $this->writer );
167 $this->repository = $this->frozenRepository;
170 if ( !$this->fluidRepository ) {
171 $this->fluidRepository = new FluidRepo( $this, $this->writer );
174 $this->repository = $this->fluidRepository;
177 if ( count( self::$sqlFilters ) ) {
178 AQueryWriter::setSQLFilters( self::$sqlFilters, ( !$this->isFrozen ) );
184 * Returns the current mode of operation of RedBean.
185 * In fluid mode the database
186 * structure is adjusted to accomodate your objects.
188 * this is not the case.
192 public function isFrozen()
194 return (bool) $this->isFrozen;
198 * Determines whether a type is in the chill list.
199 * If a type is 'chilled' it's frozen, so its schema cannot be
200 * changed anymore. However other bean types may still be modified.
201 * This method is a convenience method for other objects to check if
202 * the schema of a certain type is locked for modification.
204 * @param string $type the type you wish to check
208 public function isChilled( $type )
210 return (boolean) ( in_array( $type, $this->chillList ) );
214 * Dispenses a new bean (a OODBBean Bean Object)
215 * of the specified type. Always
216 * use this function to get an empty bean object. Never
217 * instantiate a OODBBean yourself because it needs
218 * to be configured before you can use it with RedBean. This
219 * function applies the appropriate initialization /
220 * configuration for you.
222 * @param string $type type of bean you want to dispense
223 * @param string $number number of beans you would like to get
224 * @param boolean $alwaysReturnArray if TRUE always returns the result as an array
228 public function dispense( $type, $number = 1, $alwaysReturnArray = FALSE )
231 if ( $alwaysReturnArray ) return array();
235 return $this->repository->dispense( $type, $number, $alwaysReturnArray );
239 * Sets bean helper to be given to beans.
240 * Bean helpers assist beans in getting a reference to a toolbox.
242 * @param BeanHelper $beanhelper helper
246 public function setBeanHelper( BeanHelper $beanhelper )
248 $this->beanhelper = $beanhelper;
252 * Returns the current bean helper.
253 * Bean helpers assist beans in getting a reference to a toolbox.
257 public function getBeanHelper()
259 return $this->beanhelper;
263 * Checks whether a OODBBean bean is valid.
264 * If the type is not valid or the ID is not valid it will
265 * throw an exception: Security.
267 * @param OODBBean $bean the bean that needs to be checked
271 public function check( OODBBean $bean )
273 $this->repository->check( $bean );
277 * Searches the database for a bean that matches conditions $conditions and sql $addSQL
278 * and returns an array containing all the beans that have been found.
280 * Conditions need to take form:
284 * 'PROPERTY' => array( POSSIBLE VALUES... 'John', 'Steve' )
285 * 'PROPERTY' => array( POSSIBLE VALUES... )
289 * All conditions are glued together using the AND-operator, while all value lists
290 * are glued using IN-operators thus acting as OR-conditions.
292 * Note that you can use property names; the columns will be extracted using the
293 * appropriate bean formatter.
295 * @param string $type type of beans you are looking for
296 * @param array $conditions list of conditions
297 * @param string $addSQL SQL to be used in query
298 * @param array $bindings a list of values to bind to query parameters
302 public function find( $type, $conditions = array(), $sql = NULL, $bindings = array() )
304 return $this->repository->find( $type, $conditions, $sql, $bindings );
308 * Same as find() but returns a BeanCollection.
310 * @param string $type type of beans you are looking for
311 * @param string $addSQL SQL to be used in query
312 * @param array $bindings a list of values to bind to query parameters
316 public function findCollection( $type, $sql = NULL, $bindings = array() )
318 return $this->repository->findCollection( $type, $sql, $bindings );
322 * Checks whether the specified table already exists in the database.
323 * Not part of the Object Database interface!
325 * @deprecated Use AQueryWriter::typeExists() instead.
327 * @param string $table table name
331 public function tableExists( $table )
333 return $this->repository->tableExists( $table );
337 * Stores a bean in the database. This method takes a
338 * OODBBean Bean Object $bean and stores it
339 * in the database. If the database schema is not compatible
340 * with this bean and RedBean runs in fluid mode the schema
341 * will be altered to store the bean correctly.
342 * If the database schema is not compatible with this bean and
343 * RedBean runs in frozen mode it will throw an exception.
344 * This function returns the primary key ID of the inserted
347 * The return value is an integer if possible. If it is not possible to
348 * represent the value as an integer a string will be returned. We use
349 * explicit casts instead of functions to preserve performance
350 * (0.13 vs 0.28 for 10000 iterations on Core i3).
352 * @param OODBBean|SimpleModel $bean bean to store
354 * @return integer|string
356 public function store( $bean )
358 $bean = $this->unboxIfNeeded( $bean );
359 $id = $this->repository->store( $bean );
360 if ( self::$autoClearHistoryAfterStore ) {
361 $bean->clearHistory();
367 * Loads a bean from the object database.
368 * It searches for a OODBBean Bean Object in the
369 * database. It does not matter how this bean has been stored.
370 * RedBean uses the primary key ID $id and the string $type
371 * to find the bean. The $type specifies what kind of bean you
372 * are looking for; this is the same type as used with the
373 * dispense() function. If RedBean finds the bean it will return
374 * the OODB Bean object; if it cannot find the bean
375 * RedBean will return a new bean of type $type and with
376 * primary key ID 0. In the latter case it acts basically the
377 * same as dispense().
380 * If the bean cannot be found in the database a new bean of
381 * the specified type will be generated and returned.
383 * @param string $type type of bean you want to load
384 * @param integer $id ID of the bean you want to load
388 public function load( $type, $id )
390 return $this->repository->load( $type, $id );
394 * Removes a bean from the database.
395 * This function will remove the specified OODBBean
396 * Bean Object from the database.
398 * @param OODBBean|SimpleModel $bean bean you want to remove from database
402 public function trash( $bean )
404 $bean = $this->unboxIfNeeded( $bean );
405 return $this->repository->trash( $bean );
409 * Returns an array of beans. Pass a type and a series of ids and
410 * this method will bring you the corresponding beans.
412 * important note: Because this method loads beans using the load()
413 * function (but faster) it will return empty beans with ID 0 for
414 * every bean that could not be located. The resulting beans will have the
415 * passed IDs as their keys.
417 * @param string $type type of beans
418 * @param array $ids ids to load
422 public function batch( $type, $ids )
424 return $this->repository->batch( $type, $ids );
428 * This is a convenience method; it converts database rows
429 * (arrays) into beans. Given a type and a set of rows this method
430 * will return an array of beans of the specified type loaded with
431 * the data fields provided by the result set from the database.
433 * @param string $type type of beans you would like to have
434 * @param array $rows rows from the database result
435 * @param string $mask mask to apply for meta data
439 public function convertToBeans( $type, $rows, $mask = NULL )
441 return $this->repository->convertToBeans( $type, $rows, $mask );
445 * Counts the number of beans of type $type.
446 * This method accepts a second argument to modify the count-query.
447 * A third argument can be used to provide bindings for the SQL snippet.
449 * @param string $type type of bean we are looking for
450 * @param string $addSQL additional SQL snippet
451 * @param array $bindings parameters to bind to SQL
455 public function count( $type, $addSQL = '', $bindings = array() )
457 return $this->repository->count( $type, $addSQL, $bindings );
461 * Trash all beans of a given type. Wipes an entire type of bean.
463 * @param string $type type of bean you wish to delete all instances of
467 public function wipe( $type )
469 return $this->repository->wipe( $type );
473 * Returns an Association Manager for use with OODB.
474 * A simple getter function to obtain a reference to the association manager used for
477 * @return AssociationManager
479 public function getAssociationManager()
481 if ( !isset( $this->assocManager ) ) {
482 throw new RedException( 'No association manager available.' );
485 return $this->assocManager;
489 * Sets the association manager instance to be used by this OODB.
490 * A simple setter function to set the association manager to be used for storage and
493 * @param AssociationManager $assoc sets the association manager to be used
497 public function setAssociationManager( AssociationManager $assocManager )
499 $this->assocManager = $assocManager;
503 * Returns the currently used repository instance.
504 * For testing purposes only.
508 public function getCurrentRepository()
510 return $this->repository;
514 * Binds an SQL function to a column.
515 * This method can be used to setup a decode/encode scheme or
516 * perform UUID insertion. This method is especially useful for handling
517 * MySQL spatial columns, because they need to be processed first using
518 * the asText/GeomFromText functions.
520 * @param string $mode mode to set function for, i.e. read or write
521 * @param string $field field (table.column) to bind SQL function to
522 * @param string $function SQL function to bind to field
526 public function bindFunc( $mode, $field, $function )
528 list( $type, $property ) = explode( '.', $field );
529 $mode = ($mode === 'write') ? QueryWriter::C_SQLFILTER_WRITE : QueryWriter::C_SQLFILTER_READ;
531 if ( !isset( self::$sqlFilters[$mode] ) ) self::$sqlFilters[$mode] = array();
532 if ( !isset( self::$sqlFilters[$mode][$type] ) ) self::$sqlFilters[$mode][$type] = array();
534 if ( is_null( $function ) ) {
535 unset( self::$sqlFilters[$mode][$type][$property] );
537 if ($mode === QueryWriter::C_SQLFILTER_WRITE) {
538 self::$sqlFilters[$mode][$type][$property] = $function.'(?)';
540 self::$sqlFilters[$mode][$type][$property] = $function."($field)";
544 AQueryWriter::setSQLFilters( self::$sqlFilters, ( !$this->isFrozen ) );