MeekroDB Quick Start Docs ORM Docs FAQ
Download GitHub

Scopes

Scopes are a convenient way to do simple database searches. You can combine them to quickly grab the set of records you're looking for.

class Account extends MeekroORM {
  static function _scopes() {
    return [
      'uses_gmail' => fn() => return self::where("email LIKE '%@gmail.com'");
      'recent' => fn($days) => return self::where('created_at > DATE_SUB(NOW(), INTERVAL %i DAY)', $days);
    ];
  }
}

// accounts that use gmail
$Accounts = Account::scope('uses_gmail');
foreach ($Accounts as $Account) {
  echo $Account->email . "\n";
}

As you can see, you create a static function called _scopes() that returns a hash of your scopes. Each row in the hash is one scope, maping its name to an anonymous function that returns a self::where().

Starting a scope with scope()

As you saw above, you start a scope by running ::scope() on the Account class. If the scope requires arguments, you can pass them:

// accounts created in the last 7 days
$Scope = Account::scope('recent', 7);

Starting a scope with where()

You can think of this as creating a temporary scope on-the-fly, without having to define it first. Note the MeekroDB style syntax.

$Scope = Account::where('id > %i', 5);

Starting an unlimited scope with all()

If you run all(), you'll get a scope without any WHERE restrictions, meaning it'll match every row in the table if executed. However, you can still narrow it as shown below.

$All = Account::all();
foreach ($All as $Account) { ... }

Narrowing the scope with scope() and where()

Once you have a scope, you can narrow it further by adding additional scopes or wheres to it. When the query executes, it will join all of the WHERE pieces with AND to produce a result set that matches all of the requirements.

// only accounts created in the last 7 days
$Scope = Account::scope('recent', 7);

// narrow the scope to only gmail users
$Scope->scope('uses_gmail');

// narrow the scope to exclude the first 50 accounts
$Scope->where("id > %i", 50);

// accounts created in the last 7 days, using gmail, and with id > 50
foreach ($Scope as $Account) {
  ...
}

Ordering the result set

You can run order_by() on the scope to add an ORDER BY to the resultant SQL query. If you use order_by() more than once, only the most recent one will apply.

// add a sort order
// you probably just want one of these lines, but we give several exmaples
$Scope->order_by('id');
$Scope->order_by('id', 'email');
$Scope->order_by(['id' => 'desc', 'email' => 'asc']);

Limiting the result set

Similar to order_by() above, you can add a limit to your scope like this:

// add a limit
// you probably just want one of these, we give a couple examples
$Scope->limit(5); // only first 5 rows
$Scope->limit(1, 5); // skip the first row, then return the next 5

Accessing the results

You can access the scope's results with count(), foreach, first(), last(), toArray() and array access as shown above. When you do, the MySQL query will be executed and you'll get the results. You can still keep narrowing the scope after retrieving results, which will cause the query to be re-run.

// once your access the results in the scope, it actually runs your query
// even after it runs, you can always narrow the scope further and force it
// to re-run a new query
$count = count($Scope); // number of results
$Account = $Scope[1]; // access results as array
$Account = $Scope->first(); // access first result
$Account = $Scope->last(); // access last result

// array_map() expects a true array, not an ArrayAccess/Traversable object
$ids = array_map(fn($Account) => $Account->id, $Scope->toArray());

// access results as foreach
foreach ($Scope as $Account) { ... }