Querying


    The framework protects against injection attacks by quoting
    condition values. Other options i.e. ‘fields’ are
    however not automatically quoted. Read more about the topic
    and potential countermeasures in the Security chapter.

    find() utilizes finders to do most of its work. The first parameter to find()
    selects the type of finder you want to use. The second parameter provides options to the
    finder.

    There are four built-in finders. The most commonly used ones are 'all' and 'first'.


    You can also create your own custom finders via finder().
    • 'all': Returns a collection of records matching the conditions.
    • 'first': Returns the first record matching the conditions.
    • 'count': Returns an integer count of all records matching the conditions.
    • 'list': Returns a one dimensional array, where the key is the primary
      key and the value the title of the record (a 'title' field is required
      for this). A result may look like: array(1 => 'Foo', 2 => 'Bar').

    All bultin-in finders take the same set of options to control which and
    how many records they return.

    Using Conditions

    The 'conditions' option allows you to provide conditions for the query
    i.e. 'array('is_published' => true). The following example finds all
    posts author name is michael.

    1. $posts = Posts::find('all', [
    2. 'conditions' => ['author' => 'michael']
    3. ]);

    By default the conditions are AND’ed together so the following
    example would require each post to be published and authored
    by michael.

    1. $posts = Posts::find('all', [
    2. 'conditions' => [
    3. 'author' => 'michael',
    4. 'is_published' => true
    5. ]
    6. ]);

    To OR conditions together use the following syntax.

    1. $posts = Posts::find('all', [
    2. 'conditions' => [
    3. 'or' => [
    4. 'author' => 'michael',
    5. 'is_published' => true
    6. ]
    7. ]
    8. ]);

    To find all records from a set of authors use the array
    syntax.

    1. $posts = Posts::find('all', [
    2. 'conditions' => [
    3. 'author' => ['michael', 'nate']
    4. ]
    5. ]);

    Ordering

    The following are equal groups:

    1. Posts::find('all', ['order' => 'title']);
    2. Posts::find('all', ['order' => 'title ASC']);
    3. Posts::find('all', ['order' => ['title']]);
    4. Posts::find('all', ['order' => ['title' => 'ASC']]);
    5. Posts::find('all', ['order' => ['title', 'id']]);

    The option allows to specify the fields that should be retrieved. By default
    all fields are retrieved. To optimize query performance, limit to just the ones actually
    needed.

    Limiting Number of Records

    The 'limit' option allows to limit the set of returned records to a maximum number.

    1. Posts::find('all', [
    2. 'limit' => 10
    3. ]);

    Pagination

    The 'page' option allows to paginate data sets. It specifies the page of the set
    together with the limit option specifying the number of records per page. The first
    page starts at 1.

    1. $page1 = Posts::find('all', [
    2. 'page' => 1,
    3. 'limit' => 10
    4. ]);
    5. $page2 = Posts::find('all', [
    6. 'page' => 2,
    7. 'limit' => 10
    8. ]);

    li3 also provides some additional basic methods around the find() method which
    make your code less verbose and easier to read:

    1. // Shorthand for find first by primary key.
    2. Posts::find(23);
    3. Posts::all();

    Note list is a keyword in PHP and so cannot be called magically like other finders.

    The example below shows two different approaches to finding all the posts related to the
    username “Michael”. The first bare approach shows how to use find() directly. The second
    example uses camelCase convention to tell li3 to filter by a specific field name and
    value.

    1. $posts = Posts::findAllByUsername('michael');
    2. // ... is functionally equal to ...
    3. $posts = Posts::find('all', [
    4. 'conditions' => ['username' => 'michael']
    5. ]);

    Custom Finders

    The basic finders are nice, but the framework also provides you with a set of highly
    dynamic methods that match against your dataset. It allows you to build
    custom finders to extend functionality.

    1. $recentComments = Comments::find('all', [
    2. 'conditions' => [
    3. 'created' => [
    4. '>=' => date('Y-m-d H:i:s', time() - (86400 * 3))
    5. ]
    6. ]
    7. ]);

    You could create a custom finder method that packages the specified conditions into a one-liner:

    At a basic level, this is done by utilizing the finder() method of the model.
    You call finder() and supply the name of the finder, along with a definition
    so li3 knows how to form the query. The definition in this simple case looks
    just like the query array we supplied to find() earlier:

    1. Comments::finder('recent', [
    2. 'conditions' => [
    3. 'created' => [
    4. '>=' => date('Y-m-d H:i:s', time() - (86400 * 3))
    5. ]
    6. ]
    7. ]);

    Some finder implementations might require a little processing in addition to a default set
    of conditions. In that case, you can define a finder using a closure that will be called
    as part of find chaining. In this use case, you supply the name of the finder along with a
    closure that looks much like a filter definition:


    The syntax for filter and thus for finders has changed in 1.1.
    Below you find the new syntax. The old one receives 3 parameters
    ($self, $params, $chain).
    1. Comments::finder('recentCategories', function($params, $next){
    2. // Set up default conditions
    3. $defaults = [
    4. '>=' => date('Y-m-d H:i:s', time() - (86400 * 3))
    5. ]
    6. ];
    7. $params['options']['conditions'] = $defaults + (array) $params['options']['conditions'];
    8. // Do a bit of reformatting
    9. $results = [];
    10. foreach ($next($params) as $entity) {
    11. $results[] = $entity->categoryName;
    12. }
    13. // Returns an array of recent categories given the supplied query params.
    14. return $results;
    15. });

    Rich Returned Values

    The response from a model method is not just a plain array but actually an
    entity object (or a collection of them). This means that you can perform a
    variety of actions on them if you need to. Here are a few examples:

    1. // Find all Posts
    2. $posts = Posts::all();
    3. // Get the first and last post of the collection
    4. $first = $posts->first();
    5. $last = $posts->last();
    6. // Iterate over all posts and print out the title
    7. foreach ($posts as $post) {
    8. echo $post->title;
    9. }

    Entities can be easily converted into other formats.

    1. Posts::find('all')->data();
    2. Posts::find('all')->to('array');

    In cases where you always want finders results constrained to i.e. certain conditions,
    default query options can be used. Default options may be defined by using the query()
    method or alternatively by defining the $_query property on the model class.

    Specific query options overwrite default ones. As both are merged by simply using the +
    operator for arrays. Note that this can also be a common pitfall.

    1. Posts::query([
    2. 'conditions' => ['is_published' => true],
    3. 'limit' => 4
    4. ]);
    5. // Will retrieve maximum of 4 results which are published.
    6. Posts::find('all');
    7. // Potential pitfall: will retrieve results published or not
    8. // for author michael. Limited to 4 results maximum.
    9. Posts::find('all', [
    10. 'conditions' => ['author' => 'michael']
    11. ]);
    12. // Will retrieve only published results for author michael.
    13. // Limited to 4 results.
    14. Posts::find('all', [