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;
  4: 
  5: use RedBeanPHP\ToolBox as ToolBox;
  6: use RedBeanPHP\AssociationManager as AssociationManager;
  7: use RedBeanPHP\OODB as OODB;
  8: use RedBeanPHP\OODBBean as OODBBean;
  9: use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
 10: 
 11: /**
 12:  * Duplication Manager.
 13:  * Creates deep copies of beans.
 14:  *
 15:  * @file    RedBeanPHP/DuplicationManager.php
 16:  * @author  Gabor de Mooij and the RedBeanPHP Community
 17:  * @license BSD/GPLv2
 18:  *
 19:  * @copyright
 20:  * copyright (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community
 21:  * This source file is subject to the BSD/GPLv2 License that is bundled
 22:  * with this source code in the file license.txt.
 23:  */
 24: class DuplicationManager
 25: {
 26:     /**
 27:      * @var ToolBox
 28:      */
 29:     protected $toolbox;
 30: 
 31:     /**
 32:      * @var AssociationManager
 33:      */
 34:     protected $associationManager;
 35: 
 36:     /**
 37:      * @var OODB
 38:      */
 39:     protected $redbean;
 40: 
 41:     /**
 42:      * @var array
 43:      */
 44:     protected $tables = array();
 45: 
 46:     /**
 47:      * @var array
 48:      */
 49:     protected $columns = array();
 50: 
 51:     /**
 52:      * @var array
 53:      */
 54:     protected $filters = array();
 55: 
 56:     /**
 57:      * @var array
 58:      */
 59:     protected $cacheTables = FALSE;
 60: 
 61:     /**
 62:      * Copies the shared beans in a bean, i.e. all the sharedBean-lists.
 63:      *
 64:      * @param OODBBean $copy   target bean to copy lists to
 65:      * @param string   $shared name of the shared list
 66:      * @param array    $beans  array with shared beans to copy
 67:      *
 68:      * @return void
 69:      */
 70:     private function copySharedBeans( OODBBean $copy, $shared, $beans )
 71:     {
 72:         $copy->$shared = array();
 73: 
 74:         foreach ( $beans as $subBean ) {
 75:             array_push( $copy->$shared, $subBean );
 76:         }
 77:     }
 78: 
 79:     /**
 80:      * Copies the own beans in a bean, i.e. all the ownBean-lists.
 81:      * Each bean in the own-list belongs exclusively to its owner so
 82:      * we need to invoke the duplicate method again to duplicate each bean here.
 83:      *
 84:      * @param OODBBean $copy        target bean to copy lists to
 85:      * @param string   $owned       name of the own list
 86:      * @param array    $beans       array with shared beans to copy
 87:      * @param array    $trail       array with former beans to detect recursion
 88:      * @param boolean  $preserveIDs TRUE means preserve IDs, for export only
 89:      *
 90:      * @return void
 91:      */
 92:     private function copyOwnBeans( OODBBean $copy, $owned, $beans, $trail, $preserveIDs )
 93:     {
 94:         $copy->$owned = array();
 95:         foreach ( $beans as $subBean ) {
 96:             array_push( $copy->$owned, $this->duplicate( $subBean, $trail, $preserveIDs ) );
 97:         }
 98:     }
 99: 
100:     /**
101:      * Creates a copy of bean $bean and copies all primitive properties (not lists)
102:      * and the parents beans to the newly created bean. Also sets the ID of the bean
103:      * to 0.
104:      *
105:      * @param OODBBean $bean bean to copy
106:      *
107:      * @return OODBBean
108:      */
109:     private function createCopy( OODBBean $bean )
110:     {
111:         $type = $bean->getMeta( 'type' );
112: 
113:         $copy = $this->redbean->dispense( $type );
114:         $copy->setMeta( 'sys.dup-from-id', $bean->id );
115:         $copy->setMeta( 'sys.old-id', $bean->id );
116:         $copy->importFrom( $bean );
117:         $copy->id = 0;
118: 
119:         return $copy;
120:     }
121: 
122:     /**
123:      * Generates a key from the bean type and its ID and determines if the bean
124:      * occurs in the trail, if not the bean will be added to the trail.
125:      * Returns TRUE if the bean occurs in the trail and FALSE otherwise.
126:      *
127:      * @param array    $trail list of former beans
128:      * @param OODBBean $bean  currently selected bean
129:      *
130:      * @return boolean
131:      */
132:     private function inTrailOrAdd( &$trail, OODBBean $bean )
133:     {
134:         $type = $bean->getMeta( 'type' );
135:         $key  = $type . $bean->getID();
136: 
137:         if ( isset( $trail[$key] ) ) {
138:             return TRUE;
139:         }
140: 
141:         $trail[$key] = $bean;
142: 
143:         return FALSE;
144:     }
145: 
146:     /**
147:      * Given the type name of a bean this method returns the canonical names
148:      * of the own-list and the shared-list properties respectively.
149:      * Returns a list with two elements: name of the own-list, and name
150:      * of the shared list.
151:      *
152:      * @param string $typeName bean type name
153:      *
154:      * @return array
155:      */
156:     private function getListNames( $typeName )
157:     {
158:         $owned  = 'own' . ucfirst( $typeName );
159:         $shared = 'shared' . ucfirst( $typeName );
160: 
161:         return array( $owned, $shared );
162:     }
163: 
164:     /**
165:      * Determines whether the bean has an own list based on
166:      * schema inspection from realtime schema or cache.
167:      *
168:      * @param string $type   bean type to get list for
169:      * @param string $target type of list you want to detect
170:      *
171:      * @return boolean
172:      */
173:     protected function hasOwnList( $type, $target )
174:     {
175:         return isset( $this->columns[$target][$type . '_id'] );
176:     }
177: 
178:     /**
179:      * Determines whether the bea has a shared list based on
180:      * schema inspection from realtime schema or cache.
181:      *
182:      * @param string $type   bean type to get list for
183:      * @param string $target type of list you are looking for
184:      *
185:      * @return boolean
186:      */
187:     protected function hasSharedList( $type, $target )
188:     {
189:         return in_array( AQueryWriter::getAssocTableFormat( array( $type, $target ) ), $this->tables );
190:     }
191: 
192:     /**
193:      * @see DuplicationManager::dup
194:      *
195:      * @param OODBBean $bean        bean to be copied
196:      * @param array    $trail       trail to prevent infinite loops
197:      * @param boolean  $preserveIDs preserve IDs
198:      *
199:      * @return OODBBean
200:      */
201:     protected function duplicate( OODBBean $bean, $trail = array(), $preserveIDs = FALSE )
202:     {
203:         if ( $this->inTrailOrAdd( $trail, $bean ) ) return $bean;
204: 
205:         $type = $bean->getMeta( 'type' );
206: 
207:         $copy = $this->createCopy( $bean );
208:         foreach ( $this->tables as $table ) {
209: 
210:             if ( !empty( $this->filters ) ) {
211:                 if ( !in_array( $table, $this->filters ) ) continue;
212:             }
213: 
214:             list( $owned, $shared ) = $this->getListNames( $table );
215: 
216:             if ( $this->hasSharedList( $type, $table ) ) {
217:                 if ( $beans = $bean->$shared ) {
218:                     $this->copySharedBeans( $copy, $shared, $beans );
219:                 }
220:             } elseif ( $this->hasOwnList( $type, $table ) ) {
221:                 if ( $beans = $bean->$owned ) {
222:                     $this->copyOwnBeans( $copy, $owned, $beans, $trail, $preserveIDs );
223:                 }
224: 
225:                 $copy->setMeta( 'sys.shadow.' . $owned, NULL );
226:             }
227: 
228:             $copy->setMeta( 'sys.shadow.' . $shared, NULL );
229:         }
230: 
231:         $copy->id = ( $preserveIDs ) ? $bean->id : $copy->id;
232: 
233:         return $copy;
234:     }
235: 
236:     /**
237:      * Constructor,
238:      * creates a new instance of DupManager.
239:      *
240:      * @param ToolBox $toolbox
241:      */
242:     public function __construct( ToolBox $toolbox )
243:     {
244:         $this->toolbox            = $toolbox;
245:         $this->redbean            = $toolbox->getRedBean();
246:         $this->associationManager = $this->redbean->getAssociationManager();
247:     }
248: 
249:     /**
250:      * Recursively turns the keys of an array into
251:      * camelCase.
252:      *
253:      * @param array   $array       array to camelize
254:      * @param boolean $dolphinMode whether you want the exception for IDs.
255:      *
256:      * @return array
257:      */
258:     public function camelfy( $array, $dolphinMode = false ) {
259:         $newArray = array();
260:         foreach( $array as $key => $element ) {
261:             $newKey = preg_replace_callback( '/_(\w)/', function( &$matches ){
262:                 return strtoupper( $matches[1] );
263:             }, $key);
264: 
265:             if ( $dolphinMode ) {
266:                 $newKey = preg_replace( '/(\w)Id$/', '$1ID', $newKey );
267:             }
268: 
269:             $newArray[$newKey] = ( is_array($element) ) ? $this->camelfy( $element, $dolphinMode ) : $element;
270:         }
271:         return $newArray;
272:     }
273: 
274:     /**
275:      * For better performance you can pass the tables in an array to this method.
276:      * If the tables are available the duplication manager will not query them so
277:      * this might be beneficial for performance.
278:      *
279:      * This method allows two array formats:
280:      *
281:      * <code>
282:      * array( TABLE1, TABLE2 ... )
283:      * </code>
284:      *
285:      * or
286:      *
287:      * <code>
288:      * array( TABLE1 => array( COLUMN1, COLUMN2 ... ) ... )
289:      * </code>
290:      *
291:      * @param array $tables a table cache array
292:      *
293:      * @return void
294:      */
295:     public function setTables( $tables )
296:     {
297:         foreach ( $tables as $key => $value ) {
298:             if ( is_numeric( $key ) ) {
299:                 $this->tables[] = $value;
300:             } else {
301:                 $this->tables[]      = $key;
302:                 $this->columns[$key] = $value;
303:             }
304:         }
305: 
306:         $this->cacheTables = TRUE;
307:     }
308: 
309:     /**
310:      * Returns a schema array for cache.
311:      * You can use the return value of this method as a cache,
312:      * store it in RAM or on disk and pass it to setTables later.
313:      *
314:      * @return array
315:      */
316:     public function getSchema()
317:     {
318:         return $this->columns;
319:     }
320: 
321:     /**
322:      * Indicates whether you want the duplication manager to cache the database schema.
323:      * If this flag is set to TRUE the duplication manager will query the database schema
324:      * only once. Otherwise the duplicationmanager will, by default, query the schema
325:      * every time a duplication action is performed (dup()).
326:      *
327:      * @param boolean $yesNo TRUE to use caching, FALSE otherwise
328:      */
329:     public function setCacheTables( $yesNo )
330:     {
331:         $this->cacheTables = $yesNo;
332:     }
333: 
334:     /**
335:      * A filter array is an array with table names.
336:      * By setting a table filter you can make the duplication manager only take into account
337:      * certain bean types. Other bean types will be ignored when exporting or making a
338:      * deep copy. If no filters are set all types will be taking into account, this is
339:      * the default behavior.
340:      *
341:      * @param array $filters list of tables to be filtered
342:      *
343:      * @return void
344:      */
345:     public function setFilters( $filters )
346:     {
347:         if ( !is_array( $filters ) ) {
348:             $filters = array( $filters );
349:         }
350: 
351:         $this->filters = $filters;
352:     }
353: 
354:     /**
355:      * Makes a copy of a bean. This method makes a deep copy
356:      * of the bean.The copy will have the following features.
357:      * - All beans in own-lists will be duplicated as well
358:      * - All references to shared beans will be copied but not the shared beans themselves
359:      * - All references to parent objects (_id fields) will be copied but not the parents themselves
360:      * In most cases this is the desired scenario for copying beans.
361:      * This function uses a trail-array to prevent infinite recursion, if a recursive bean is found
362:      * (i.e. one that already has been processed) the ID of the bean will be returned.
363:      * This should not happen though.
364:      *
365:      * Note:
366:      * This function does a reflectional database query so it may be slow.
367:      *
368:      * Note:
369:      * this function actually passes the arguments to a protected function called
370:      * duplicate() that does all the work. This method takes care of creating a clone
371:      * of the bean to avoid the bean getting tainted (triggering saving when storing it).
372:      *
373:      * @param OODBBean $bean        bean to be copied
374:      * @param array    $trail       for internal usage, pass array()
375:      * @param boolean  $preserveIDs for internal usage
376:      *
377:      * @return OODBBean
378:      */
379:     public function dup( OODBBean $bean, $trail = array(), $preserveIDs = FALSE )
380:     {
381:         if ( !count( $this->tables ) ) {
382:             $this->tables = $this->toolbox->getWriter()->getTables();
383:         }
384: 
385:         if ( !count( $this->columns ) ) {
386:             foreach ( $this->tables as $table ) {
387:                 $this->columns[$table] = $this->toolbox->getWriter()->getColumns( $table );
388:             }
389:         }
390: 
391:         $rs = $this->duplicate( ( clone $bean ), $trail, $preserveIDs );
392: 
393:         if ( !$this->cacheTables ) {
394:             $this->tables  = array();
395:             $this->columns = array();
396:         }
397: 
398:         return $rs;
399:     }
400: 
401:     /**
402:      * Exports a collection of beans recursively.
403:      * This method will export an array of beans in the first argument to a
404:      * set of arrays. This can be used to send JSON or XML representations
405:      * of bean hierarchies to the client.
406:      *
407:      * For every bean in the array this method will export:
408:      *
409:      * - contents of the bean
410:      * - all own bean lists (recursively)
411:      * - all shared beans (but not THEIR own lists)
412:      *
413:      * If the second parameter is set to TRUE the parents of the beans in the
414:      * array will be exported as well (but not THEIR parents).
415:      *
416:      * The third parameter can be used to provide a white-list array
417:      * for filtering. This is an array of strings representing type names,
418:      * only the type names in the filter list will be exported.
419:      *
420:      * The fourth parameter can be used to change the keys of the resulting
421:      * export arrays. The default mode is 'snake case' but this leaves the
422:      * keys as-is, because 'snake' is the default case style used by
423:      * RedBeanPHP in the database. You can set this to 'camel' for
424:      * camel cased keys or 'dolphin' (same as camelcase but id will be
425:      * converted to ID instead of Id).
426:      *
427:      * @param array|OODBBean $beans     beans to be exported
428:      * @param boolean        $parents   also export parents
429:      * @param array          $filters   only these types (whitelist)
430:      * @param string         $caseStyle case style identifier
431:      *
432:      * @return array
433:      */
434:     public function exportAll( $beans, $parents = FALSE, $filters = array(), $caseStyle = 'snake')
435:     {
436:         $array = array();
437: 
438:         if ( !is_array( $beans ) ) {
439:             $beans = array( $beans );
440:         }
441: 
442:         foreach ( $beans as $bean ) {
443:             $this->setFilters( $filters );
444: 
445:             $duplicate = $this->dup( $bean, array(), TRUE );
446: 
447:             $array[]   = $duplicate->export( FALSE, $parents, FALSE, $filters );
448:         }
449: 
450:         if ( $caseStyle === 'camel' ) $array = $this->camelfy( $array );
451:         if ( $caseStyle === 'dolphin' ) $array = $this->camelfy( $array, true );
452: 
453:         return $array;
454:     }
455: }
456: 
API documentation generated by ApiGen