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: 
  6: /**
  7:  * RedBeanPHP Finder.
  8:  * Service class to find beans. For the most part this class
  9:  * offers user friendly utility methods for interacting with the
 10:  * OODB::find() method, which is rather complex. This class can be
 11:  * used to find beans using plain old SQL queries.
 12:  *
 13:  * @file    RedBeanPHP/Finder.php
 14:  * @author  Gabor de Mooij and the RedBeanPHP Community
 15:  * @license BSD/GPLv2
 16:  *
 17:  * @copyright
 18:  * copyright (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community
 19:  * This source file is subject to the BSD/GPLv2 License that is bundled
 20:  * with this source code in the file license.txt.
 21:  */
 22: class Finder
 23: {
 24:     /**
 25:      * @var ToolBox
 26:      */
 27:     protected $toolbox;
 28: 
 29:     /**
 30:      * @var OODB
 31:      */
 32:     protected $redbean;
 33: 
 34:     /**
 35:      * Constructor.
 36:      * The Finder requires a toolbox.
 37:      *
 38:      * @param ToolBox $toolbox
 39:      */
 40:     public function __construct( ToolBox $toolbox )
 41:     {
 42:         $this->toolbox = $toolbox;
 43:         $this->redbean = $toolbox->getRedBean();
 44:     }
 45: 
 46:     /**
 47:      * Finds a bean using a type and a where clause (SQL).
 48:      * As with most Query tools in RedBean you can provide values to
 49:      * be inserted in the SQL statement by populating the value
 50:      * array parameter; you can either use the question mark notation
 51:      * or the slot-notation (:keyname).
 52:      *
 53:      * @param string $type     type   the type of bean you are looking for
 54:      * @param string $sql      sql    SQL query to find the desired bean, starting right after WHERE clause
 55:      * @param array  $bindings values array of values to be bound to parameters in query
 56:      *
 57:      * @return array
 58:      */
 59:     public function find( $type, $sql = NULL, $bindings = array() )
 60:     {
 61:         if ( !is_array( $bindings ) ) {
 62:             throw new RedException(
 63:                 'Expected array, ' . gettype( $bindings ) . ' given.'
 64:             );
 65:         }
 66: 
 67:         return $this->redbean->find( $type, array(), $sql, $bindings );
 68:     }
 69: 
 70:     /**
 71:      * Like find() but also exports the beans as an array.
 72:      * This method will perform a find-operation. For every bean
 73:      * in the result collection this method will call the export() method.
 74:      * This method returns an array containing the array representations
 75:      * of every bean in the result set.
 76:      *
 77:      * @see Finder::find
 78:      *
 79:      * @param string $type     type   the type of bean you are looking for
 80:      * @param string $sql      sql    SQL query to find the desired bean, starting right after WHERE clause
 81:      * @param array  $bindings values array of values to be bound to parameters in query
 82:      *
 83:      * @return array
 84:      */
 85:     public function findAndExport( $type, $sql = NULL, $bindings = array() )
 86:     {
 87:         $arr = array();
 88:         foreach ( $this->find( $type, $sql, $bindings ) as $key => $item ) {
 89:             $arr[] = $item->export();
 90:         }
 91: 
 92:         return $arr;
 93:     }
 94: 
 95:     /**
 96:      * Like find() but returns just one bean instead of an array of beans.
 97:      * This method will return only the first bean of the array.
 98:      * If no beans are found, this method will return NULL.
 99:      *
100:      * @see Finder::find
101:      *
102:      * @param string $type     type   the type of bean you are looking for
103:      * @param string $sql      sql    SQL query to find the desired bean, starting right after WHERE clause
104:      * @param array  $bindings values array of values to be bound to parameters in query
105:      *
106:      * @return OODBBean
107:      */
108:     public function findOne( $type, $sql = NULL, $bindings = array() )
109:     {
110:         $sql = $this->toolbox->getWriter()->glueLimitOne( $sql );
111: 
112:         $items = $this->find( $type, $sql, $bindings );
113: 
114:         if ( empty($items) ) {
115:             return NULL;
116:         }
117: 
118:         return reset( $items );
119:     }
120: 
121:     /**
122:      * Like find() but returns the last bean of the result array.
123:      * Opposite of Finder::findLast().
124:      * If no beans are found, this method will return NULL.
125:      *
126:      * @see Finder::find
127:      *
128:      * @param string $type     the type of bean you are looking for
129:      * @param string $sql      SQL query to find the desired bean, starting right after WHERE clause
130:      * @param array  $bindings values array of values to be bound to parameters in query
131:      *
132:      * @return OODBBean
133:      */
134:     public function findLast( $type, $sql = NULL, $bindings = array() )
135:     {
136:         $items = $this->find( $type, $sql, $bindings );
137: 
138:         if ( empty($items) ) {
139:             return NULL;
140:         }
141: 
142:         return end( $items );
143:     }
144: 
145:     /**
146:      * Tries to find beans of a certain type,
147:      * if no beans are found, it dispenses a bean of that type.
148:      *
149:      * @see Finder::find
150:      *
151:      * @param  string $type     the type of bean you are looking for
152:      * @param  string $sql      SQL query to find the desired bean, starting right after WHERE clause
153:      * @param  array  $bindings values array of values to be bound to parameters in query
154:      *
155:      * @return array
156:      */
157:     public function findOrDispense( $type, $sql = NULL, $bindings = array() )
158:     {
159:         $foundBeans = $this->find( $type, $sql, $bindings );
160: 
161:         if ( empty( $foundBeans ) ) {
162:             return array( $this->redbean->dispense( $type ) );
163:         } else {
164:             return $foundBeans;
165:         }
166:     }
167: 
168:     /**
169:      * Finds a BeanCollection using the repository.
170:      * A bean collection can be used to retrieve one bean at a time using
171:      * cursors - this is useful for processing large datasets. A bean collection
172:      * will not load all beans into memory all at once, just one at a time.
173:      *
174:      * @param  string $type     the type of bean you are looking for
175:      * @param  string $sql      SQL query to find the desired bean, starting right after WHERE clause
176:      * @param  array  $bindings values array of values to be bound to parameters in query
177:      *
178:      * @return BeanCollection
179:      */
180:     public function findCollection( $type, $sql, $bindings = array() )
181:     {
182:         return $this->redbean->findCollection( $type, $sql, $bindings );
183:     }
184: 
185:     /**
186:      * Finds or creates a bean.
187:      * Tries to find a bean with certain properties specified in the second
188:      * parameter ($like). If the bean is found, it will be returned.
189:      * If multiple beans are found, only the first will be returned.
190:      * If no beans match the criteria, a new bean will be dispensed,
191:      * the criteria will be imported as properties and this new bean
192:      * will be stored and returned.
193:      *
194:      * Format of criteria set: property => value
195:      * The criteria set also supports OR-conditions: property => array( value1, orValue2 )
196:      *
197:      * @param string $type type of bean to search for
198:      * @param array  $like criteria set describing bean to search for
199:      *
200:      * @return OODBBean
201:      */
202:     public function findOrCreate( $type, $like = array() )
203:     {
204:             $beans = $this->findLike( $type, $like );
205:             if ( count( $beans ) ) {
206:                 $bean = reset( $beans );
207:                 return $bean;
208:             }
209: 
210:             $bean = $this->redbean->dispense( $type );
211:             $bean->import( $like );
212:             $this->redbean->store( $bean );
213:             return $bean;
214:     }
215: 
216:     /**
217:      * Finds beans by its type and a certain criteria set.
218:      *
219:      * Format of criteria set: property => value
220:      * The criteria set also supports OR-conditions: property => array( value1, orValue2 )
221:      *
222:      * If the additional SQL is a condition, this condition will be glued to the rest
223:      * of the query using an AND operator. Note that this is as far as this method
224:      * can go, there is no way to glue additional SQL using an OR-condition.
225:      * This method provides access to an underlying mechanism in the RedBeanPHP architecture
226:      * to find beans using criteria sets. However, please do not use this method
227:      * for complex queries, use plain SQL instead ( the regular find method ) as it is
228:      * more suitable for the job. This method is
229:      * meant for basic search-by-example operations.
230:      *
231:      * @param string $type       type of bean to search for
232:      * @param array  $conditions criteria set describing the bean to search for
233:      * @param string $sql        additional SQL (for sorting)
234:      *
235:      * @return array
236:      */
237:     public function findLike( $type, $conditions = array(), $sql = '' )
238:     {
239:         if ( count( $conditions ) > 0 ) {
240:             foreach( $conditions as $key => $condition ) {
241:                 if ( !count( $condition ) ) unset( $conditions[$key] );
242:             }
243:         }
244: 
245:         return $this->redbean->find( $type, $conditions, $sql );
246:     }
247: 
248:     /**
249:      * Returns a hashmap with bean arrays keyed by type using an SQL
250:      * query as its resource. Given an SQL query like 'SELECT movie.*, review.* FROM movie... JOIN review'
251:      * this method will return movie and review beans.
252:      *
253:      * Example:
254:      *
255:      * <code>
256:      * $stuff = $finder->findMulti('movie,review', '
257:      *          SELECT movie.*, review.* FROM movie
258:      *          LEFT JOIN review ON review.movie_id = movie.id');
259:      * </code>
260:      *
261:      * After this operation, $stuff will contain an entry 'movie' containing all
262:      * movies and an entry named 'review' containing all reviews (all beans).
263:      * You can also pass bindings.
264:      *
265:      * If you want to re-map your beans, so you can use $movie->ownReviewList without
266:      * having RedBeanPHP executing an SQL query you can use the fourth parameter to
267:      * define a selection of remapping closures.
268:      *
269:      * The remapping argument (optional) should contain an array of arrays.
270:      * Each array in the remapping array should contain the following entries:
271:      *
272:      * <code>
273:      * array(
274:      *  'a'       => TYPE A
275:      *    'b'       => TYPE B
276:      *    'matcher' => MATCHING FUNCTION ACCEPTING A, B and ALL BEANS
277:      *    'do'      => OPERATION FUNCTION ACCEPTING A, B, ALL BEANS, ALL REMAPPINGS
278:      * )
279:      * </code>
280:      *
281:      * Using this mechanism you can build your own 'preloader' with tiny function
282:      * snippets (and those can be re-used and shared online of course).
283:      *
284:      * Example:
285:      *
286:      * <code>
287:      * array(
288:      *  'a'       => 'movie'     //define A as movie
289:      *    'b'       => 'review'    //define B as review
290:      *    'matcher' => function( $a, $b ) {
291:      *       return ( $b->movie_id == $a->id );  //Perform action if review.movie_id equals movie.id
292:      *    }
293:      *    'do'      => function( $a, $b ) {
294:      *       $a->noLoad()->ownReviewList[] = $b; //Add the review to the movie
295:      *       $a->clearHistory();                 //optional, act 'as if these beans have been loaded through ownReviewList'.
296:      *    }
297:      * )
298:      * </code>
299:      *
300:      * The Query Template parameter is optional as well but can be used to
301:      * set a different SQL template (sprintf-style) for processing the original query.
302:      *
303:      * @note the SQL query provided IS NOT THE ONE used internally by this function,
304:      * this function will pre-process the query to get all the data required to find the beans.
305:      *
306:      * @note if you use the 'book.*' notation make SURE you're
307:      * selector starts with a SPACE. ' book.*' NOT ',book.*'. This is because
308:      * it's actually an SQL-like template SLOT, not real SQL.
309:      *
310:      * @note instead of an SQL query you can pass a result array as well.
311:      *
312:      * @param string|array $types         a list of types (either array or comma separated string)
313:      * @param string|array $sqlOrArr      an SQL query or an array of prefetched records
314:      * @param array        $bindings      optional, bindings for SQL query
315:      * @param array        $remappings    optional, an array of remapping arrays
316:      * @param string       $queryTemplate optional, query template
317:      *
318:      * @return array
319:      */
320:     public function findMulti( $types, $sql, $bindings = array(), $remappings = array(), $queryTemplate = ' %s.%s AS %s__%s' )
321:     {
322:         if ( !is_array( $types ) ) $types = explode( ',', $types );
323:         if ( !is_array( $sql ) ) {
324:             $writer = $this->toolbox->getWriter();
325:             $adapter = $this->toolbox->getDatabaseAdapter();
326: 
327:             //Repair the query, replace book.* with book.id AS book_id etc..
328:             foreach( $types as $type ) {
329:                 $pattern = " {$type}.*";
330:                 if ( strpos( $sql, $pattern ) !== FALSE ) {
331:                     $newSelectorArray = array();
332:                     $columns = $writer->getColumns( $type );
333:                     foreach( $columns as $column => $definition ) {
334:                         $newSelectorArray[] = sprintf( $queryTemplate, $type, $column, $type, $column );
335:                     }
336:                     $newSelector = implode( ',', $newSelectorArray );
337:                     $sql = str_replace( $pattern, $newSelector, $sql );
338:                 }
339:             }
340: 
341:             $rows = $adapter->get( $sql, $bindings );
342:         } else {
343:             $rows = $sql;
344:         }
345: 
346:         //Gather the bean data from the query results using the prefix
347:         $wannaBeans = array();
348:         foreach( $types as $type ) {
349:             $wannaBeans[$type] = array();
350:             $prefix            = "{$type}__";
351:             foreach( $rows as $rowkey=>$row ) {
352:                 $wannaBean = array();
353:                 foreach( $row as $cell => $value ) {
354:                     if ( strpos( $cell, $prefix ) === 0 ) {
355:                         $property = substr( $cell, strlen( $prefix ) );
356:                         unset( $rows[$rowkey][$cell] );
357:                         $wannaBean[$property] = $value;
358:                     }
359:                 }
360:                 if ( !isset( $wannaBean['id'] ) ) continue;
361:                 if ( is_null( $wannaBean['id'] ) ) continue;
362:                 $wannaBeans[$type][$wannaBean['id']] = $wannaBean;
363:             }
364:         }
365: 
366:         //Turn the rows into beans
367:         $beans = array();
368:         foreach( $wannaBeans as $type => $wannabees ) {
369:             $beans[$type] = $this->redbean->convertToBeans( $type, $wannabees );
370:         }
371: 
372:         //Apply additional re-mappings
373:         foreach($remappings as $remapping) {
374:             $a       = $remapping['a'];
375:             $b       = $remapping['b'];
376:             $matcher = $remapping['matcher'];
377:             $do      = $remapping['do'];
378:             foreach( $beans[$a] as $bean ) {
379:                 foreach( $beans[$b] as $putBean ) {
380:                     if ( $matcher( $bean, $putBean, $beans ) ) $do( $bean, $putBean, $beans, $remapping );
381:                 }
382:             }
383:         }
384:         return $beans;
385:     }
386: }
387: 
API documentation generated by ApiGen