Yaffs site version 1.1
[yaffs-website] / vendor / gabordemooij / redbean / RedBeanPHP / OODB.php
1 <?php
2
3 namespace RedBeanPHP;
4
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;
12
13 /**
14  * RedBean Object Oriented DataBase.
15  *
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
19  * object database.
20  *
21  * @file    RedBeanPHP/OODB.php
22  * @author  Gabor de Mooij and the RedBeanPHP community
23  * @license BSD/GPLv2
24  *
25  * @copyright
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.
29  */
30 class OODB extends Observable
31 {
32         /**
33          * @var array
34          */
35         private static $sqlFilters = array();
36
37         /**
38          * @var array
39          */
40         protected $chillList = array();
41
42         /**
43          * @var array
44          */
45         protected $stash = NULL;
46
47         /*
48          * @var integer
49          */
50         protected $nesting = 0;
51
52         /**
53          * @var DBAdapter
54          */
55         protected $writer;
56
57         /**
58          * @var boolean
59          */
60         protected $isFrozen = FALSE;
61
62         /**
63          * @var FacadeBeanHelper
64          */
65         protected $beanhelper = NULL;
66
67         /**
68          * @var AssociationManager
69          */
70         protected $assocManager = NULL;
71
72         /**
73          * @var Repository
74          */
75         protected $repository = NULL;
76
77         /**
78          * @var FrozenRepo
79          */
80         protected $frozenRepository = NULL;
81
82         /**
83          * @var FluidRepo
84          */
85         protected $fluidRepository = NULL;
86
87         /**
88          * @var boolean
89          */
90         protected static $autoClearHistoryAfterStore = FALSE;
91
92         /**
93          * If set to TRUE, this method will call clearHistory every time
94          * the bean gets stored.
95          *
96          * @param boolean $autoClear auto clear option
97          *
98          * @return void
99          */
100         public static function autoClearHistoryAfterStore( $autoClear = TRUE )
101         {
102                 self::$autoClearHistoryAfterStore = (boolean) $autoClear;
103         }
104
105         /**
106          * Unboxes a bean from a FUSE model if needed and checks whether the bean is
107          * an instance of OODBBean.
108          *
109          * @param OODBBean $bean bean you wish to unbox
110          *
111          * @return OODBBean
112          */
113         protected function unboxIfNeeded( $bean )
114         {
115                 if ( $bean instanceof SimpleModel ) {
116                         $bean = $bean->unbox();
117                 }
118                 if ( !( $bean instanceof OODBBean ) ) {
119                         throw new RedException( 'OODB Store requires a bean, got: ' . gettype( $bean ) );
120                 }
121
122                 return $bean;
123         }
124
125         /**
126          * Constructor, requires a query writer.
127          *
128          * @param QueryWriter   $writer writer
129          * @param array|boolean $frozen mode of operation: TRUE (frozen), FALSE (default, fluid) or ARRAY (chilled)
130          */
131         public function __construct( QueryWriter $writer, $frozen = FALSE )
132         {
133                 if ( $writer instanceof QueryWriter ) {
134                         $this->writer = $writer;
135                 }
136
137                 $this->freeze( $frozen );
138         }
139
140         /**
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.
144          *
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.
148          *
149          * @param boolean|array $toggle TRUE if you want to use OODB instance in frozen mode
150          *
151          * @return void
152          */
153         public function freeze( $toggle )
154         {
155                 if ( is_array( $toggle ) ) {
156                         $this->chillList = $toggle;
157                         $this->isFrozen  = FALSE;
158                 } else {
159                         $this->isFrozen = (boolean) $toggle;
160                 }
161
162                 if ( $this->isFrozen ) {
163                         if ( !$this->frozenRepository ) {
164                                 $this->frozenRepository = new FrozenRepo( $this, $this->writer );
165                         }
166
167                         $this->repository = $this->frozenRepository;
168
169                 } else {
170                         if ( !$this->fluidRepository ) {
171                                 $this->fluidRepository = new FluidRepo( $this, $this->writer );
172                         }
173
174                         $this->repository = $this->fluidRepository;
175                 }
176
177                 if ( count( self::$sqlFilters ) ) {
178                         AQueryWriter::setSQLFilters( self::$sqlFilters, ( !$this->isFrozen ) );
179                 }
180
181         }
182
183         /**
184          * Returns the current mode of operation of RedBean.
185          * In fluid mode the database
186          * structure is adjusted to accomodate your objects.
187          * In frozen mode
188          * this is not the case.
189          *
190          * @return boolean
191          */
192         public function isFrozen()
193         {
194                 return (bool) $this->isFrozen;
195         }
196
197         /**
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.
203          *
204          * @param string $type the type you wish to check
205          *
206          * @return boolean
207          */
208         public function isChilled( $type )
209         {
210                 return (boolean) ( in_array( $type, $this->chillList ) );
211         }
212
213         /**
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.
221          *
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
225          *
226          * @return OODBBean
227          */
228         public function dispense( $type, $number = 1, $alwaysReturnArray = FALSE )
229         {
230                 if ( $number < 1 ) {
231                         if ( $alwaysReturnArray ) return array();
232                         return NULL;
233                 }
234
235                 return $this->repository->dispense( $type, $number, $alwaysReturnArray );
236         }
237
238         /**
239          * Sets bean helper to be given to beans.
240          * Bean helpers assist beans in getting a reference to a toolbox.
241          *
242          * @param BeanHelper $beanhelper helper
243          *
244          * @return void
245          */
246         public function setBeanHelper( BeanHelper $beanhelper )
247         {
248                 $this->beanhelper = $beanhelper;
249         }
250
251         /**
252          * Returns the current bean helper.
253          * Bean helpers assist beans in getting a reference to a toolbox.
254          *
255          * @return BeanHelper
256          */
257         public function getBeanHelper()
258         {
259                 return $this->beanhelper;
260         }
261
262         /**
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.
266          *
267          * @param OODBBean $bean the bean that needs to be checked
268          *
269          * @return void
270          */
271         public function check( OODBBean $bean )
272         {
273                 $this->repository->check( $bean );
274         }
275
276         /**
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.
279          *
280          * Conditions need to take form:
281          *
282          * <code>
283          * array(
284          *    'PROPERTY' => array( POSSIBLE VALUES... 'John', 'Steve' )
285          *    'PROPERTY' => array( POSSIBLE VALUES... )
286          * );
287          * </code>
288          *
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.
291          *
292          * Note that you can use property names; the columns will be extracted using the
293          * appropriate bean formatter.
294          *
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
299          *
300          * @return array
301          */
302         public function find( $type, $conditions = array(), $sql = NULL, $bindings = array() )
303         {
304                 return $this->repository->find( $type, $conditions, $sql, $bindings );
305         }
306
307         /**
308          * Same as find() but returns a BeanCollection.
309          *
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
313          *
314          * @return array
315          */
316         public function findCollection(  $type, $sql = NULL, $bindings = array() )
317         {
318                 return $this->repository->findCollection( $type, $sql, $bindings );
319         }
320
321         /**
322          * Checks whether the specified table already exists in the database.
323          * Not part of the Object Database interface!
324          *
325          * @deprecated Use AQueryWriter::typeExists() instead.
326          *
327          * @param string $table table name
328          *
329          * @return boolean
330          */
331         public function tableExists( $table )
332         {
333                 return $this->repository->tableExists( $table );
334         }
335
336         /**
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
345          * bean.
346          *
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).
351          *
352          * @param OODBBean|SimpleModel $bean bean to store
353          *
354          * @return integer|string
355          */
356         public function store( $bean )
357         {
358                 $bean = $this->unboxIfNeeded( $bean );
359                 $id = $this->repository->store( $bean );
360                 if ( self::$autoClearHistoryAfterStore ) {
361                                 $bean->clearHistory();
362                 }
363                 return $id;
364         }
365
366         /**
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().
378          *
379          * Important note:
380          * If the bean cannot be found in the database a new bean of
381          * the specified type will be generated and returned.
382          *
383          * @param string  $type type of bean you want to load
384          * @param integer $id   ID of the bean you want to load
385          *
386          * @return OODBBean
387          */
388         public function load( $type, $id )
389         {
390                 return $this->repository->load( $type, $id );
391         }
392
393         /**
394          * Removes a bean from the database.
395          * This function will remove the specified OODBBean
396          * Bean Object from the database.
397          *
398          * @param OODBBean|SimpleModel $bean bean you want to remove from database
399          *
400          * @return void
401          */
402         public function trash( $bean )
403         {
404                 $bean = $this->unboxIfNeeded( $bean );
405                 return $this->repository->trash( $bean );
406         }
407
408         /**
409          * Returns an array of beans. Pass a type and a series of ids and
410          * this method will bring you the corresponding beans.
411          *
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.
416          *
417          * @param string $type type of beans
418          * @param array  $ids  ids to load
419          *
420          * @return array
421          */
422         public function batch( $type, $ids )
423         {
424                 return $this->repository->batch( $type, $ids );
425         }
426
427         /**
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.
432          *
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
436          *
437          * @return array
438          */
439         public function convertToBeans( $type, $rows, $mask = NULL )
440         {
441                 return $this->repository->convertToBeans( $type, $rows, $mask );
442         }
443
444         /**
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.
448          *
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
452          *
453          * @return integer
454          */
455         public function count( $type, $addSQL = '', $bindings = array() )
456         {
457                 return $this->repository->count( $type, $addSQL, $bindings );
458         }
459
460         /**
461          * Trash all beans of a given type. Wipes an entire type of bean.
462          *
463          * @param string $type type of bean you wish to delete all instances of
464          *
465          * @return boolean
466          */
467         public function wipe( $type )
468         {
469                 return $this->repository->wipe( $type );
470         }
471
472         /**
473          * Returns an Association Manager for use with OODB.
474          * A simple getter function to obtain a reference to the association manager used for
475          * storage and more.
476          *
477          * @return AssociationManager
478          */
479         public function getAssociationManager()
480         {
481                 if ( !isset( $this->assocManager ) ) {
482                         throw new RedException( 'No association manager available.' );
483                 }
484
485                 return $this->assocManager;
486         }
487
488         /**
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
491          * more.
492          *
493          * @param AssociationManager $assoc sets the association manager to be used
494          *
495          * @return void
496          */
497         public function setAssociationManager( AssociationManager $assocManager )
498         {
499                 $this->assocManager = $assocManager;
500         }
501
502         /**
503          * Returns the currently used repository instance.
504          * For testing purposes only.
505          *
506          * @return Repository
507          */
508         public function getCurrentRepository()
509         {
510                 return $this->repository;
511         }
512
513         /**
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.
519          *
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
523          *
524          * @return void
525          */
526         public function bindFunc( $mode, $field, $function )
527         {
528                 list( $type, $property ) = explode( '.', $field );
529                 $mode = ($mode === 'write') ? QueryWriter::C_SQLFILTER_WRITE : QueryWriter::C_SQLFILTER_READ;
530
531                 if ( !isset( self::$sqlFilters[$mode] ) ) self::$sqlFilters[$mode] = array();
532                 if ( !isset( self::$sqlFilters[$mode][$type] ) ) self::$sqlFilters[$mode][$type] = array();
533
534                 if ( is_null( $function ) ) {
535                         unset( self::$sqlFilters[$mode][$type][$property] );
536                 } else {
537                         if ($mode === QueryWriter::C_SQLFILTER_WRITE) {
538                                 self::$sqlFilters[$mode][$type][$property] = $function.'(?)';
539                         } else {
540                                 self::$sqlFilters[$mode][$type][$property] = $function."($field)";
541                         }
542                 }
543
544                 AQueryWriter::setSQLFilters( self::$sqlFilters, ( !$this->isFrozen ) );
545         }
546 }