Overview

Namespaces

  • None
  • RedBeanPHP
    • Adapter
    • BeanHelper
    • Cursor
    • Driver
    • Logger
      • RDefault
    • QueryWriter
    • RedException
    • Repository
    • Util

Classes

  • R
  • RedBean_SimpleModel
  • RedBeanPHP\Adapter\DBAdapter
  • RedBeanPHP\AssociationManager
  • RedBeanPHP\BeanCollection
  • RedBeanPHP\BeanHelper\SimpleFacadeBeanHelper
  • RedBeanPHP\Cursor\NullCursor
  • RedBeanPHP\Cursor\PDOCursor
  • RedBeanPHP\Driver\RPDO
  • RedBeanPHP\DuplicationManager
  • RedBeanPHP\Facade
  • RedBeanPHP\Finder
  • RedBeanPHP\Jsonable
  • RedBeanPHP\LabelMaker
  • RedBeanPHP\Logger\RDefault
  • RedBeanPHP\Logger\RDefault\Debug
  • RedBeanPHP\Observable
  • RedBeanPHP\OODB
  • RedBeanPHP\OODBBean
  • RedBeanPHP\QueryWriter\AQueryWriter
  • RedBeanPHP\QueryWriter\CUBRID
  • RedBeanPHP\QueryWriter\MySQL
  • RedBeanPHP\QueryWriter\PostgreSQL
  • RedBeanPHP\QueryWriter\SQLiteT
  • RedBeanPHP\R
  • RedBeanPHP\Repository
  • RedBeanPHP\Repository\Fluid
  • RedBeanPHP\Repository\Frozen
  • RedBeanPHP\SimpleModel
  • RedBeanPHP\SimpleModelHelper
  • RedBeanPHP\TagManager
  • RedBeanPHP\ToolBox
  • RedBeanPHP\Util\ArrayTool
  • RedBeanPHP\Util\DispenseHelper
  • RedBeanPHP\Util\Dump
  • RedBeanPHP\Util\MultiLoader
  • RedBeanPHP\Util\Transaction

Interfaces

  • RedBeanPHP\Adapter
  • RedBeanPHP\BeanHelper
  • RedBeanPHP\Cursor
  • RedBeanPHP\Driver
  • RedBeanPHP\Logger
  • RedBeanPHP\Observer
  • RedBeanPHP\Plugin
  • RedBeanPHP\QueryWriter

Exceptions

  • RedBeanPHP\RedException
  • RedBeanPHP\RedException\SQL

Functions

  • array_flatten
  • dmp
  • EID
  • genslots
  • Overview
  • Namespace
  • Class
  1: <?php
  2: 
  3: namespace RedBeanPHP\Repository;
  4: 
  5: use RedBeanPHP\OODBBean as OODBBean;
  6: use RedBeanPHP\QueryWriter as QueryWriter;
  7: use RedBeanPHP\RedException as RedException;
  8: use RedBeanPHP\BeanHelper as BeanHelper;
  9: use RedBeanPHP\RedException\SQL as SQLException;
 10: use RedBeanPHP\Repository as Repository;
 11: 
 12: /**
 13:  * Fluid Repository.
 14:  * OODB manages two repositories, a fluid one that
 15:  * adjust the database schema on-the-fly to accomodate for
 16:  * new bean types (tables) and new properties (columns) and
 17:  * a frozen one for use in a production environment. OODB
 18:  * allows you to swap the repository instances using the freeze()
 19:  * method.
 20:  *
 21:  * @file    RedBeanPHP/Repository/Fluid.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 Fluid extends Repository
 31: {
 32:     /**
 33:      * Figures out the desired type given the cast string ID.
 34:      *
 35:      * @param string $cast cast identifier
 36:      *
 37:      * @return integer
 38:      */
 39:     private function getTypeFromCast( $cast )
 40:     {
 41:         if ( $cast == 'string' ) {
 42:             $typeno = $this->writer->scanType( 'STRING' );
 43:         } elseif ( $cast == 'id' ) {
 44:             $typeno = $this->writer->getTypeForID();
 45:         } elseif ( isset( $this->writer->sqltype_typeno[$cast] ) ) {
 46:             $typeno = $this->writer->sqltype_typeno[$cast];
 47:         } else {
 48:             throw new RedException( 'Invalid Cast' );
 49:         }
 50: 
 51:         return $typeno;
 52:     }
 53: 
 54:     /**
 55:      * Orders the Query Writer to create a table if it does not exist already and
 56:      * adds a note in the build report about the creation.
 57:      *
 58:      * @param OODBBean $bean bean to update report of
 59:      * @param string         $table table to check and create if not exists
 60:      *
 61:      * @return void
 62:      */
 63:     private function createTableIfNotExists( OODBBean $bean, $table )
 64:     {
 65:         //Does table exist? If not, create
 66:         if ( !$this->tableExists( $this->writer->esc( $table, TRUE ) ) ) {
 67:             $this->writer->createTable( $table );
 68:             $bean->setMeta( 'buildreport.flags.created', TRUE );
 69:         }
 70:     }
 71: 
 72:     /**
 73:      * Modifies the table to fit the bean data.
 74:      * Given a property and a value and the bean, this method will
 75:      * adjust the table structure to fit the requirements of the property and value.
 76:      * This may include adding a new column or widening an existing column to hold a larger
 77:      * or different kind of value. This method employs the writer to adjust the table
 78:      * structure in the database. Schema updates are recorded in meta properties of the bean.
 79:      *
 80:      * This method will also apply indexes, unique constraints and foreign keys.
 81:      *
 82:      * @param OODBBean $bean     bean to get cast data from and store meta in
 83:      * @param string   $property property to store
 84:      * @param mixed    $value    value to store
 85:      *
 86:      * @return void
 87:      */
 88:     private function modifySchema( OODBBean $bean, $property, $value )
 89:     {
 90:         $doFKStuff = FALSE;
 91:         $table   = $bean->getMeta( 'type' );
 92:         $columns = $this->writer->getColumns( $table );
 93:         $columnNoQ = $this->writer->esc( $property, TRUE );
 94:         if ( !$this->oodb->isChilled( $bean->getMeta( 'type' ) ) ) {
 95:             if ( $bean->getMeta( "cast.$property", -1 ) !== -1 ) { //check for explicitly specified types
 96:                 $cast   = $bean->getMeta( "cast.$property" );
 97:                 $typeno = $this->getTypeFromCast( $cast );
 98:             } else {
 99:                 $cast   = FALSE;
100:                 $typeno = $this->writer->scanType( $value, TRUE );
101:             }
102:             if ( isset( $columns[$this->writer->esc( $property, TRUE )] ) ) { //Is this property represented in the table ?
103:                 if ( !$cast ) { //rescan without taking into account special types >80
104:                     $typeno = $this->writer->scanType( $value, FALSE );
105:                 }
106:                 $sqlt = $this->writer->code( $columns[$this->writer->esc( $property, TRUE )] );
107:                 if ( $typeno > $sqlt ) { //no, we have to widen the database column type
108:                     $this->writer->widenColumn( $table, $property, $typeno );
109:                     $bean->setMeta( 'buildreport.flags.widen', TRUE );
110:                     $doFKStuff = TRUE;
111:                 }
112:             } else {
113:                 $this->writer->addColumn( $table, $property, $typeno );
114:                 $bean->setMeta( 'buildreport.flags.addcolumn', TRUE );
115:                 $doFKStuff = TRUE;
116:             }
117:             if ($doFKStuff) {
118:                 if (strrpos($columnNoQ, '_id')===(strlen($columnNoQ)-3)) {
119:                     $destinationColumnNoQ = substr($columnNoQ, 0, strlen($columnNoQ)-3);
120:                     $indexName = "index_foreignkey_{$table}_{$destinationColumnNoQ}";
121:                     $this->writer->addIndex($table, $indexName, $columnNoQ);
122:                     $typeof = $bean->getMeta("sys.typeof.{$destinationColumnNoQ}", $destinationColumnNoQ);
123:                     $isLink = $bean->getMeta( 'sys.buildcommand.unique', FALSE );
124:                     //Make FK CASCADING if part of exclusive list (dependson=typeof) or if link bean
125:                     $isDep = ( $bean->moveMeta( 'sys.buildcommand.fkdependson' ) === $typeof || is_array( $isLink ) );
126:                     $result = $this->writer->addFK( $table, $typeof, $columnNoQ, 'id', $isDep );
127:                     //If this is a link bean and all unique columns have been added already, then apply unique constraint
128:                     if ( is_array( $isLink ) && !count( array_diff( $isLink, array_keys( $this->writer->getColumns( $table ) ) ) ) ) {
129:                         $this->writer->addUniqueConstraint( $table, $bean->moveMeta('sys.buildcommand.unique') );
130:                         $bean->setMeta("sys.typeof.{$destinationColumnNoQ}", NULL);
131:                     }
132:                 }
133:             }
134:         }
135:     }
136: 
137:     /**
138:      * Part of the store() functionality.
139:      * Handles all new additions after the bean has been saved.
140:      * Stores addition bean in own-list, extracts the id and
141:      * adds a foreign key. Also adds a constraint in case the type is
142:      * in the dependent list.
143:      *
144:      * Note that this method raises a custom exception if the bean
145:      * is not an instance of OODBBean. Therefore it does not use
146:      * a type hint. This allows the user to take action in case
147:      * invalid objects are passed in the list.
148:      *
149:      * @param OODBBean $bean         bean to process
150:      * @param array    $ownAdditions list of addition beans in own-list
151:      *
152:      * @return void
153:      */
154:     protected function processAdditions( $bean, $ownAdditions )
155:     {
156:         $beanType = $bean->getMeta( 'type' );
157: 
158:         foreach ( $ownAdditions as $addition ) {
159:             if ( $addition instanceof OODBBean ) {
160: 
161:                 $myFieldLink = $beanType . '_id';
162:                 $alias = $bean->getMeta( 'sys.alias.' . $addition->getMeta( 'type' ) );
163:                 if ( $alias ) $myFieldLink = $alias . '_id';
164: 
165:                 $addition->$myFieldLink = $bean->id;
166:                 $addition->setMeta( 'cast.' . $myFieldLink, 'id' );
167: 
168:                 if ($alias) {
169:                     $addition->setMeta( "sys.typeof.{$alias}", $beanType );
170:                 } else {
171:                     $addition->setMeta( "sys.typeof.{$beanType}", $beanType );
172:                 }
173: 
174:                 $this->store( $addition );
175:             } else {
176:                 throw new RedException( 'Array may only contain OODBBeans' );
177:             }
178:         }
179:     }
180: 
181:     /**
182:      * Stores a cleaned bean; i.e. only scalar values. This is the core of the store()
183:      * method. When all lists and embedded beans (parent objects) have been processed and
184:      * removed from the original bean the bean is passed to this method to be stored
185:      * in the database.
186:      *
187:      * @param OODBBean $bean the clean bean
188:      *
189:      * @return void
190:      */
191:     protected function storeBean( OODBBean $bean )
192:     {
193:         if ( $bean->getMeta( 'changed' ) ) {
194:             $this->check( $bean );
195:             $table = $bean->getMeta( 'type' );
196:             $this->createTableIfNotExists( $bean, $table );
197: 
198:             $updateValues = array();
199:             foreach ( $bean as $property => $value ) {
200:                 if ( $property !== 'id' ) {
201:                     $this->modifySchema( $bean, $property, $value );
202:                 }
203:                 if ( $property !== 'id' ) {
204:                     $updateValues[] = array( 'property' => $property, 'value' => $value );
205:                 }
206:             }
207: 
208:             $bean->id = $this->writer->updateRecord( $table, $updateValues, $bean->id );
209:             $bean->setMeta( 'changed', FALSE );
210:         }
211:         $bean->setMeta( 'tainted', FALSE );
212:     }
213: 
214:     /**
215:      * Handles exceptions. Suppresses exceptions caused by missing structures.
216:      *
217:      * @param Exception $exception exception
218:      *
219:      * @return void
220:      */
221:     protected function handleException( \Exception $exception )
222:     {
223:         if ( !$this->writer->sqlStateIn( $exception->getSQLState(),
224:             array(
225:                 QueryWriter::C_SQLSTATE_NO_SUCH_TABLE,
226:                 QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN ) )
227:         ) {
228:             throw $exception;
229:         }
230:     }
231: 
232:     /**
233:      * Dispenses a new bean (a OODBBean Bean Object)
234:      * of the specified type. Always
235:      * use this function to get an empty bean object. Never
236:      * instantiate a OODBBean yourself because it needs
237:      * to be configured before you can use it with RedBean. This
238:      * function applies the appropriate initialization /
239:      * configuration for you.
240:      *
241:      * @param string  $type              type of bean you want to dispense
242:      * @param string  $number            number of beans you would like to get
243:      * @param boolean $alwaysReturnArray if TRUE always returns the result as an array
244:      *
245:      * @return OODBBean
246:      */
247:     public function dispense( $type, $number = 1, $alwaysReturnArray = FALSE )
248:     {
249:         $OODBBEAN = defined( 'REDBEAN_OODBBEAN_CLASS' ) ? REDBEAN_OODBBEAN_CLASS : '\RedBeanPHP\OODBBean';
250:         $beans = array();
251:         for ( $i = 0; $i < $number; $i++ ) {
252:             $bean = new $OODBBEAN;
253:             $bean->initializeForDispense( $type, $this->oodb->getBeanHelper() );
254:             $this->check( $bean );
255:             $this->oodb->signal( 'dispense', $bean );
256:             $beans[] = $bean;
257:         }
258: 
259:         return ( count( $beans ) === 1 && !$alwaysReturnArray ) ? array_pop( $beans ) : $beans;
260:     }
261: 
262:     /**
263:      * Loads a bean from the object database.
264:      * It searches for a OODBBean Bean Object in the
265:      * database. It does not matter how this bean has been stored.
266:      * RedBean uses the primary key ID $id and the string $type
267:      * to find the bean. The $type specifies what kind of bean you
268:      * are looking for; this is the same type as used with the
269:      * dispense() function. If RedBean finds the bean it will return
270:      * the OODB Bean object; if it cannot find the bean
271:      * RedBean will return a new bean of type $type and with
272:      * primary key ID 0. In the latter case it acts basically the
273:      * same as dispense().
274:      *
275:      * Important note:
276:      * If the bean cannot be found in the database a new bean of
277:      * the specified type will be generated and returned.
278:      *
279:      * @param string  $type type of bean you want to load
280:      * @param integer $id   ID of the bean you want to load
281:      *
282:      * @return OODBBean
283:      */
284:     public function load( $type, $id )
285:     {
286:         $bean = $this->dispense( $type );
287:         if ( isset( $this->stash[$this->nesting][$id] ) ) {
288:             $row = $this->stash[$this->nesting][$id];
289:         } else {
290:             try {
291:                 $rows = $this->writer->queryRecord( $type, array( 'id' => array( $id ) ) );
292:             } catch ( SQLException $exception ) {
293:                 if ( $this->writer->sqlStateIn( $exception->getSQLState(),
294:                     array(
295:                         QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
296:                         QueryWriter::C_SQLSTATE_NO_SUCH_TABLE )
297:                 )
298:                 ) {
299:                     $rows = 0;
300:                 }
301:             }
302:             if ( empty( $rows ) ) {
303:                 return $bean;
304:             }
305:             $row = array_pop( $rows );
306:         }
307:         $bean->importRow( $row );
308:         $this->nesting++;
309:         $this->oodb->signal( 'open', $bean );
310:         $this->nesting--;
311: 
312:         return $bean->setMeta( 'tainted', FALSE );
313:     }
314: }
315: 
API documentation generated by ApiGen