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\Adapter\DBAdapter as DBAdapter;
  6: use RedBeanPHP\QueryWriter as QueryWriter;
  7: use RedBeanPHP\RedException as RedException;
  8: use RedBeanPHP\RedException\SQL as SQLException;
  9: 
 10: /**
 11:  * Association Manager.
 12:  * Manages simple bean associations.
 13:  *
 14:  * @file    RedBeanPHP/AssociationManager.php
 15:  * @author  Gabor de Mooij and the RedBeanPHP Community
 16:  * @license BSD/GPLv2
 17:  *
 18:  * @copyright
 19:  * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
 20:  * This source file is subject to the BSD/GPLv2 License that is bundled
 21:  * with this source code in the file license.txt.
 22:  */
 23: class AssociationManager extends Observable
 24: {
 25:     /**
 26:      * @var OODB
 27:      */
 28:     protected $oodb;
 29: 
 30:     /**
 31:      * @var DBAdapter
 32:      */
 33:     protected $adapter;
 34: 
 35:     /**
 36:      * @var QueryWriter
 37:      */
 38:     protected $writer;
 39: 
 40:     /**
 41:      * Handles exceptions. Suppresses exceptions caused by missing structures.
 42:      *
 43:      * @param Exception $exception exception to handle
 44:      *
 45:      * @return void
 46:      */
 47:     private function handleException( \Exception $exception )
 48:     {
 49:         if ( $this->oodb->isFrozen() || !$this->writer->sqlStateIn( $exception->getSQLState(),
 50:             array(
 51:                 QueryWriter::C_SQLSTATE_NO_SUCH_TABLE,
 52:                 QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN )
 53:             )
 54:         ) {
 55:             throw $exception;
 56:         }
 57:     }
 58: 
 59:     /**
 60:      * Internal method.
 61:      * Returns the many-to-many related rows of table $type for bean $bean using additional SQL in $sql and
 62:      * $bindings bindings. If $getLinks is TRUE, link rows are returned instead.
 63:      *
 64:      * @param OODBBean $bean     reference bean instance
 65:      * @param string   $type     target bean type
 66:      * @param string   $sql      additional SQL snippet
 67:      * @param array    $bindings bindings for query
 68:      *
 69:      * @return array
 70:      */
 71:     private function relatedRows( $bean, $type, $sql = '', $bindings = array() )
 72:     {
 73:         $ids = array( $bean->id );
 74:         $sourceType = $bean->getMeta( 'type' );
 75:         try {
 76:             return $this->writer->queryRecordRelated( $sourceType, $type, $ids, $sql, $bindings );
 77:         } catch ( SQLException $exception ) {
 78:             $this->handleException( $exception );
 79:             return array();
 80:         }
 81:     }
 82: 
 83:     /**
 84:      * Associates a pair of beans. This method associates two beans, no matter
 85:      * what types. Accepts a base bean that contains data for the linking record.
 86:      * This method is used by associate. This method also accepts a base bean to be used
 87:      * as the template for the link record in the database.
 88:      *
 89:      * @param OODBBean $bean1 first bean
 90:      * @param OODBBean $bean2 second bean
 91:      * @param OODBBean $bean  base bean (association record)
 92:      *
 93:      * @return mixed
 94:      */
 95:     protected function associateBeans( OODBBean $bean1, OODBBean $bean2, OODBBean $bean )
 96:     {
 97:         $type      = $bean->getMeta( 'type' );
 98:         $property1 = $bean1->getMeta( 'type' ) . '_id';
 99:         $property2 = $bean2->getMeta( 'type' ) . '_id';
100: 
101:         if ( $property1 == $property2 ) {
102:             $property2 = $bean2->getMeta( 'type' ) . '2_id';
103:         }
104: 
105:         $this->oodb->store( $bean1 );
106:         $this->oodb->store( $bean2 );
107: 
108:         $bean->setMeta( "cast.$property1", "id" );
109:         $bean->setMeta( "cast.$property2", "id" );
110:         $bean->setMeta( 'sys.buildcommand.unique', array( $property1, $property2 ) );
111: 
112:         $bean->$property1 = $bean1->id;
113:         $bean->$property2 = $bean2->id;
114: 
115:         $results   = array();
116: 
117:         try {
118:             $id = $this->oodb->store( $bean );
119:             $results[] = $id;
120:         } catch ( SQLException $exception ) {
121:             if ( !$this->writer->sqlStateIn( $exception->getSQLState(),
122:                 array( QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION ) )
123:             ) {
124:                 throw $exception;
125:             }
126:         }
127: 
128:         return $results;
129:     }
130: 
131:     /**
132:      * Constructor
133:      *
134:      * @param ToolBox $tools toolbox
135:      */
136:     public function __construct( ToolBox $tools )
137:     {
138:         $this->oodb    = $tools->getRedBean();
139:         $this->adapter = $tools->getDatabaseAdapter();
140:         $this->writer  = $tools->getWriter();
141:         $this->toolbox = $tools;
142:     }
143: 
144:     /**
145:      * Creates a table name based on a types array.
146:      * Manages the get the correct name for the linking table for the
147:      * types provided.
148:      *
149:      * @todo find a nice way to decouple this class from QueryWriter?
150:      *
151:      * @param array $types 2 types as strings
152:      *
153:      * @return string
154:      */
155:     public function getTable( $types )
156:     {
157:         return $this->writer->getAssocTable( $types );
158:     }
159: 
160:     /**
161:      * Associates two beans in a many-to-many relation.
162:      * This method will associate two beans and store the connection between the
163:      * two in a link table. Instead of two single beans this method also accepts
164:      * two sets of beans. Returns the ID or the IDs of the linking beans.
165:      *
166:      * @param OODBBean|array $beans1 one or more beans to form the association
167:      * @param OODBBean|array $beans2 one or more beans to form the association
168:      *
169:      * @return array
170:      */
171:     public function associate( $beans1, $beans2 )
172:     {
173:         if ( !is_array( $beans1 ) ) {
174:             $beans1 = array( $beans1 );
175:         }
176: 
177:         if ( !is_array( $beans2 ) ) {
178:             $beans2 = array( $beans2 );
179:         }
180: 
181:         $results = array();
182:         foreach ( $beans1 as $bean1 ) {
183:             foreach ( $beans2 as $bean2 ) {
184:                 $table     = $this->getTable( array( $bean1->getMeta( 'type' ), $bean2->getMeta( 'type' ) ) );
185:                 $bean      = $this->oodb->dispense( $table );
186:                 $results[] = $this->associateBeans( $bean1, $bean2, $bean );
187:             }
188:         }
189: 
190:         return ( count( $results ) > 1 ) ? $results : reset( $results );
191:     }
192: 
193:     /**
194:      * Counts the number of related beans in an N-M relation.
195:      * This method returns the number of beans of type $type associated
196:      * with reference bean(s) $bean. The query can be tuned using an
197:      * SQL snippet for additional filtering.
198:      *
199:      * @param OODBBean|array $bean     a bean object or an array of beans
200:      * @param string         $type     type of bean you're interested in
201:      * @param string         $sql      SQL snippet (optional)
202:      * @param array          $bindings bindings for your SQL string
203:      *
204:      * @return integer
205:      */
206:     public function relatedCount( $bean, $type, $sql = NULL, $bindings = array() )
207:     {
208:         if ( !( $bean instanceof OODBBean ) ) {
209:             throw new RedException(
210:                 'Expected array or OODBBean but got:' . gettype( $bean )
211:             );
212:         }
213: 
214:         if ( !$bean->id ) {
215:             return 0;
216:         }
217: 
218:         $beanType = $bean->getMeta( 'type' );
219: 
220:         try {
221:             return $this->writer->queryRecordCountRelated( $beanType, $type, $bean->id, $sql, $bindings );
222:         } catch ( SQLException $exception ) {
223:             $this->handleException( $exception );
224: 
225:             return 0;
226:         }
227:     }
228: 
229:     /**
230:      * Breaks the association between two beans. This method unassociates two beans. If the
231:      * method succeeds the beans will no longer form an association. In the database
232:      * this means that the association record will be removed. This method uses the
233:      * OODB trash() method to remove the association links, thus giving FUSE models the
234:      * opportunity to hook-in additional business logic. If the $fast parameter is
235:      * set to boolean TRUE this method will remove the beans without their consent,
236:      * bypassing FUSE. This can be used to improve performance.
237:      *
238:      * @param OODBBean $bean1 first bean in target association
239:      * @param OODBBean $bean2 second bean in target association
240:      * @param boolean  $fast  if TRUE, removes the entries by query without FUSE
241:      *
242:      * @return void
243:      */
244:     public function unassociate( $beans1, $beans2, $fast = NULL )
245:     {
246:         $beans1 = ( !is_array( $beans1 ) ) ? array( $beans1 ) : $beans1;
247:         $beans2 = ( !is_array( $beans2 ) ) ? array( $beans2 ) : $beans2;
248: 
249:         foreach ( $beans1 as $bean1 ) {
250:             foreach ( $beans2 as $bean2 ) {
251:                 try {
252:                     $this->oodb->store( $bean1 );
253:                     $this->oodb->store( $bean2 );
254: 
255:                     $type1 = $bean1->getMeta( 'type' );
256:                     $type2 = $bean2->getMeta( 'type' );
257: 
258:                     $row      = $this->writer->queryRecordLink( $type1, $type2, $bean1->id, $bean2->id );
259:                     $linkType = $this->getTable( array( $type1, $type2 ) );
260: 
261:                     if ( $fast ) {
262:                         $this->writer->deleteRecord( $linkType, array( 'id' => $row['id'] ) );
263: 
264:                         return;
265:                     }
266: 
267:                     $beans = $this->oodb->convertToBeans( $linkType, array( $row ) );
268: 
269:                     if ( count( $beans ) > 0 ) {
270:                         $bean = reset( $beans );
271:                         $this->oodb->trash( $bean );
272:                     }
273:                 } catch ( SQLException $exception ) {
274:                     $this->handleException( $exception );
275:                 }
276:             }
277:         }
278:     }
279: 
280:     /**
281:      * Removes all relations for a bean. This method breaks every connection between
282:      * a certain bean $bean and every other bean of type $type. Warning: this method
283:      * is really fast because it uses a direct SQL query however it does not inform the
284:      * models about this. If you want to notify FUSE models about deletion use a foreach-loop
285:      * with unassociate() instead. (that might be slower though)
286:      *
287:      * @param OODBBean $bean reference bean
288:      * @param string   $type type of beans that need to be unassociated
289:      *
290:      * @return void
291:      */
292:     public function clearRelations( OODBBean $bean, $type )
293:     {
294:         $this->oodb->store( $bean );
295:         try {
296:             $this->writer->deleteRelations( $bean->getMeta( 'type' ), $type, $bean->id );
297:         } catch ( SQLException $exception ) {
298:             $this->handleException( $exception );
299:         }
300:     }
301: 
302:     /**
303:      * Returns all the beans associated with $bean.
304:      * This method will return an array containing all the beans that have
305:      * been associated once with the associate() function and are still
306:      * associated with the bean specified. The type parameter indicates the
307:      * type of beans you are looking for. You can also pass some extra SQL and
308:      * values for that SQL to filter your results after fetching the
309:      * related beans.
310:      *
311:      * Don't try to make use of subqueries, a subquery using IN() seems to
312:      * be slower than two queries!
313:      *
314:      * Since 3.2, you can now also pass an array of beans instead just one
315:      * bean as the first parameter.
316:      *
317:      * @param OODBBean|array $bean the bean you have
318:      * @param string         $type      the type of beans you want
319:      * @param string         $sql       SQL snippet for extra filtering
320:      * @param array          $bindings  values to be inserted in SQL slots
321:      *
322:      * @return array
323:      */
324:     public function related( $bean, $type, $sql = '', $bindings = array() )
325:     {
326:         $sql   = $this->writer->glueSQLCondition( $sql );
327:         $rows  = $this->relatedRows( $bean, $type, $sql, $bindings );
328:         $links = array();
329: 
330:         foreach ( $rows as $key => $row ) {
331:             if ( !isset( $links[$row['id']] ) ) $links[$row['id']] = array();
332:             $links[$row['id']][] = $row['linked_by'];
333:             unset( $rows[$key]['linked_by'] );
334:         }
335: 
336:         $beans = $this->oodb->convertToBeans( $type, $rows );
337:         foreach ( $beans as $bean ) $bean->setMeta( 'sys.belongs-to', $links[$bean->id] );
338: 
339:         return $beans;
340:     }
341: }
342: 
API documentation generated by ApiGen