/** * Find records in the database. * * Finding by the primary key: * * <code> * # queries for the model with id=123 * YourModel::find(123); * * # queries for model with id in(1,2,3) * YourModel::find(1,2,3); * * # finding by pk accepts an options array * YourModel::find(123,array('order' => 'name desc')); * </code> * * Finding by using a conditions array: * * <code> * YourModel::find('first', array('conditions' => array('name=?','Tito'), * 'order' => 'name asc')) * YourModel::find('all', array('conditions' => 'amount > 3.14159265')); * YourModel::find('all', array('conditions' => array('id in(?)', array(1,2,3)))); * </code> * * Finding by using a hash: * * <code> * YourModel::find(array('name' => 'Tito', 'id' => 1)); * YourModel::find('first',array('name' => 'Tito', 'id' => 1)); * YourModel::find('all',array('name' => 'Tito', 'id' => 1)); * </code> * * An options array can take the following parameters: * * <ul> * <li><b>select:</b> A SQL fragment for what fields to return such as: '*', 'people.*', 'first_name, last_name, id'</li> * <li><b>joins:</b> A SQL join fragment such as: 'JOIN roles ON(roles.user_id=user.id)' or a named association on the model</li> * <li><b>include:</b> TODO not implemented yet</li> * <li><b>conditions:</b> A SQL fragment such as: 'id=1', array('id=1'), array('name=? and id=?','Tito',1), array('name IN(?)', array('Tito','Bob')), * array('name' => 'Tito', 'id' => 1)</li> * <li><b>limit:</b> Number of records to limit the query to</li> * <li><b>offset:</b> The row offset to return results from for the query</li> * <li><b>order:</b> A SQL fragment for order such as: 'name asc', 'name asc, id desc'</li> * <li><b>readonly:</b> Return all the models in readonly mode</li> * <li><b>group:</b> A SQL group by fragment</li> * </ul> * * @throws {@link RecordNotFound} if no options are passed or finding by pk and no records matched * @return mixed An array of records found if doing a find_all otherwise a * single Model object or null if it wasn't found. NULL is only return when * doing a first/last find. If doing an all find and no records matched this * will return an empty array. */ public static function find() { $class = get_called_class(); if (func_num_args() <= 0) { throw new RecordNotFound("Couldn't find {$class} without an ID"); } $args = func_get_args(); $options = static::extractAndValidateOptions($args); $numArgs = count($args); $single = true; if ($numArgs > 0 && ($args[0] === 'all' || $args[0] === 'first' || $args[0] === 'last')) { switch ($args[0]) { case 'all': $single = false; break; case 'last': if (!array_key_exists('order', $options)) { $options['order'] = join(' DESC, ', static::table()->pk) . ' DESC'; } else { $options['order'] = SQLBuilder::reverseOrder($options['order']); } // fall thru // fall thru case 'first': $options['limit'] = 1; $options['offset'] = 0; break; } $args = array_slice($args, 1); $numArgs--; } elseif (1 === count($args) && 1 == $numArgs) { $args = $args[0]; } // anything left in $args is a find by pk if ($numArgs > 0 && !isset($options['conditions'])) { return static::findByPk($args, $options); } $options['mapped_names'] = static::$aliasAttribute; $list = static::table()->find($options); return $single ? !empty($list) ? $list[0] : null : $list; }