MeekroDB Quick Start Docs ORM Docs FAQ
Download GitHub

Introduction to Object-Relational Mappers (ORMs)

If you've used MeekroDB (or even something like PDO), you know how traditional database access works. You have four operations available to you: SELECT, INSERT, UPDATE, and DELETE. Libraries like MeekroDB simplify these four operations, but they are still basically the same. SELECT returns a single hash representing a row, or an array of hashes representing many rows. INSERT adds a hash as a new row. UPDATE changes rows that match search criteria, and DELETE removes rows that match.

ORMs come at it differently: the idea now is that for each table, you create a class. When you create or retrieve a row from the table, you will interact with an object of that class.

A simple example

This should make more sense once we consider an example. Let's start with a basic table that will hold login information for your web app. Before we can do anything, though, we need to make sure that we have a database connection. MeekroORM relies on MeekroDB's default connection, so let's set that up at the top of your program:

DB::$dsn = 'mysql:host=localhost;dbname=mydb';
DB::$user = 'my_database_user';
DB::$password = 'my_database_password';

If you've already been using MeekroDB (or PDO, or anything else) then you probably have something like this in your program's init.php or whatever. Anyway, let's create a table to hold our login information:

CREATE TABLE accounts (
  `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `email` varchar(255) NOT NULL DEFAULT '',
  `password` varchar(255) NOT NULL DEFAULT ''
)

We probably want more data than that, but it's good enough for now. Before we can start interacting with the table, we need a corresponding class in our PHP app. Let's make one:

 class Account extends MeekroORM {}

Yeah, that's really all we need.

Let's add our first user

$Account = new Account();
$Account->email = '[email protected]';
$Account->password = 'kickme123';
$Account->Save();
echo "We just saved a new user with id {$Account->id}!\n";

.. see what we did there? We just set all of the various pieces of data, and ran Save(). The ORM automatically scanned our table to figure out its structure and added a new row. If you're a MeekroDB user and familiar with how it works, you can actually set DB::debugMode() at the top and watch your data get INSERTed.

Retrieving the user by primary key

The simplest way to retrieve the user is by the id PRIMARY KEY:

$Account = Account::Load(1);
echo "Email: {$Account->email}\n";

Simple, right? But usually we'll want to lookup the account by email, and verify the user's password to see if they can log in.

Retrieving the user by any field

With Search(), we can retrieve our account by any field. Let's find it by email and verify the password.

$Account = Account::Search(['email' => $_POST['email']]);
if ($Account->password == $_POST['password']) {
  echo "You signed in!\n";
} else {
  echo "Wrong password!\n";
}

Altering and saving the user

We can even change the user.. maybe give them a better password?

$Account = Account::Search(['email' => $_POST['email']]);
$Account->password = 'kickme123!'; // new password
$Account->xxyxz = 'abcde'; // this isn't a database column, so won't be saved
$Account->Save();

If you use DB::debugMode() watch what it does, you'll see that it runs an UPDATE and changes only the password, leaving everything else alone.

Also, we set an extra random field called xxyxz. That field isn't in the database, and so won't be saved. You can still access it from the object, though.

Deleting the user

Let's get rid of the user called [email protected], if it exists.

$Account = Account::Search(['email' => '[email protected]');
if ($Account) {
  $Account->Destroy();
} else {
  echo "Couldn't find an account with that email!\n";
}

It's that simple-- the row is gone!

Let's add more stuff

First, we'll need a better table:

CREATE TABLE accounts (
  `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `email` varchar(255) NOT NULL DEFAULT '',
  `password_hash` varchar(255) NOT NULL DEFAULT '',
  `is_admin` tinyint(1) NOT NULL DEFAULT 0,
  `last_login_at` timestamp NULL DEFAULT NULL
)

The password field will now be encrypted. We've got a few new columns, too: we're giving the user an admin status, and a timestamp field to track when they last logged in. We'll also fancy up the class from before.

class Account extends MeekroORM {
  static $_columns = [
    'is_admin' => ['type' => 'bool'],
  ];

  function set_password($newpass) {
    $this->password_hash = password_hash($newpass);
  }
  function check_login($password) {
    if (password_verify($password, $this->password_hash)) {
      $this->last_login_at = new DateTime('now');
      $this->Save();
      return true;
    }
    return false;
  }
  static function reset_all_passwords() {
    DB::query("UPDATE accounts SET password_hash=''");
  }
}

Let's break that down. The $_columns hash is a way of specifying extra data about how we should treat certain database columns. It can figure out basic stuff like strings, numbers, dates, etc by reading your table structure, but since MySQL doesn't have a bool type, we're using tinyint(1) to simulate it. MeekroORM has no way of knowing that we want this to be a bool and not a number, though, so we have to tell it.

Apart from that, we have two self-explanatory functions. Let's see how you would use them, and make the user an admin too:

$Account = Account::Search(['email' => '[email protected]');
$Account->is_admin = true;
$Account->set_password('kickme123!');
$Account->Save();

Now that we've set an encrypted password, we can verify it:

$Account = Account::Search(['email' => '[email protected]');
if ($Account->check_login($_POST['password']) {
  echo "Logged in!\n";
}

Also, did you notice the reset_all_passwords() static function? We put it there to illustrate that you can mix MeekroDB queries into MeekroORM. Sometimes a single UPDATE command is much faster than loading, altering, and saving lots of records one by one.

Retrieving many users at once

What if we do want to load, alter, and save many records one by one? You could run out of memory if you have millions of records, but for small tables you could get away with this.

// no search params to SearchMany() means get all records
$Accounts = Account::SearchMany();
foreach ($Accounts as $Account) {
    // reset everyone's password
    $Account->password_hash = '';
    $Account->Save();
}

Conclusion

Using ORMs works well for a lot of situations. The Account class above is a natural way to structure your program, since it can contain all of your methods for interacting with account data. There's a lot more you can do with MeekroORM, but these examples should be enough to get you started.