Tiny database layer for PHP

Documentation – Mastering Neevo

Type detection

Neevo is able to automatically detect data type of database fields and then convert fetched values to corresponding PHP equivalents. You can also set your own types for fields. Let's take a look at example.

Assume we have database table like this:

CREATE TABLE `users` (
  `id` int PRIMARY KEY,
  `name` varchar,
  `mail` varchar,
  `registered` datetime

Now we can automatically detect that types with detectTypes() method:

$row = $neevo->select('users')

Now, $row properties will be of following types:

field PHP type
id int
name string
mail string
registered instance of DateTime

Now, we want to set our own types. OK, Let's do it with setTypes() method:

$types = array(
    'id' => Neevo\Manager::TEXT,
    'name' => Neevo\Manager::TEXT,
    'mail' => Neevo\Manager::TEXT,
    'registered' => Neevo\Manager::DATETIME

$row = $neevo->select('users')->setTypes($types)->fetch();

Available types are:

  • Neevo\Manager::TEXT – Textual content
  • Neevo\Manager::BOOL – Boolean value – TRUE or FALSE
  • Neevo\Manager::INT – Integer number
  • Neevo\Manager::FLOAT – Number with floating point
  • Neevo\Manager::BINARY – Binary data
  • Neevo\Manager::DATETIME – Date or time value

Conditional statements

Sometimes, you need to adjust SQL query based on some conditions. In those cases, you can use Neevo conditional statements. Take a look at the example code:

$result = $neevo->select('users')
       ->where('role', 'admin')
       ->or('role', 'webmaster')
       ->where('role', 'editor')
     ->order('id', Neevo\Manager::DESC);

You can of course go deeper and use conditions inside conditions etc. And you can omit the last end(), if there are no „clause-methods“ after it.


Another useful feature. You can easily create subqueries with Neevo. Example first:

// SELECT * FROM `users` WHERE (`role` = 'admin')
$subquery = $neevo->select('users')->where('role', 'admin');

// SELECT `id`, `name` FROM (SELECT * FROM `users` WHERE (`role` = 'admin')) `admins`
$neevo->select('id, name', $subquery->as('admins'));

// SELECT * FROM `posts`
// LEFT JOIN ( SELECT * FROM `users` WHERE (`role` = 'admin')) `admins`
// ON `posts`.`user_id` = `users`.`id`
      ->leftJoin($subquery, ':posts.user_id =');
// SELECT `id` FROM `users` WHERE (`role` = 'admin')
$subquery = $neevo->select('id', 'users')->where('role', 'admin');

// SELECT * FROM `posts`
// WHERE (`user_id` IN (SELECT `id` FROM `users` WHERE (`role` = 'admin')))
      ->where('user_id', $subquery);

You can use subqueries as a SELECT source (first example), JOIN source (second example) and also in WHERE conditions.

When using as a SELECT or JOIN source, you have to specify an alias for subquery. There is a as() method for this, and also less magic setAlias(). If you don't specify any alias, it will be automaticaly generated.


Neevo\Row in not just an object container for retrieved database rows. It can also modify those data and reflect changes back to the database. Consider following example:

// SELECT * FROM `users`
$user = $neevo->select('users')->fetch() // We get the first row.

$user->name = 'John Doe';

// UPDATE `users` SET `name` = 'John Doe' WHERE (`id` = 1);

We fetch the first row from the database, then change the value in name column and call update(). This method automatically discovers PRIMARY KEY column for the table and it's value in the current row and then executes the appropriate UPDATE query.

You can also remove the row the same way using delete().

$user = $neevo->select('users')->fetch();

// DELETE FROM `users` WHERE (`id` = 1);

If PRIMARY KEY cannot be discovered or the corresponsing column is not present in the fetched row, these features are disabled and a Neevo\Exception is thrown when you try to call it.

Neevo Cache

Neevo has it's own internal mechanism for caching some expensive tasks, like column type detection, primary key discovery etc. By default, it uses Neevo\Cache\Me­moryStorage cache implementation, which stores the data for the time of a request.

However, you can pass a cache instance when connecting to database as a second parameter for Neevo\Manager constructor. It must be an object implementing Neevo\Cache interface.

Neevo comes with few implementations of this interface:

Profiling Neevo

Profiling in Neevo is implemented using the Observer design pattern. Objects that can be observed implement Neevo\Observer\Sub­ject interface and have a list of their observers – objects implementing Neevo\Observer\Ob­server. When a state of observable object changes, it notifies all attached observers passing them an instance of itself and the event ID.

You can attach observers individually for observables you choose using their attachObserver() method, but you can also attach observers to all Neevo observables by attaching them to Neevo\Manager object. attachObserver() also accepts bitmask of events in which is observer interested.

Custom database drivers

Currently, Neevo supports 3 database systems and 5 PHP database implementations:

But you can easily support any other database. You just need to create a Neevo driver for it.

Neevo driver is a class which implements Neevo\Driver interface. If your driver needs to rewrite some default SQL output of Neevo, it can extend Neevo\Parser class and override some methods.

Driver classes have to match naming convention „Neevo\Drivers\NameDriver“, where „Name“ is a driver name, for example „PgSQL“. You can then use this name when connecting to database:

$neevo = new Neevo\Manager(array(
    'driver' => 'pgsql'

To properly load the driver, it should be located in the „name.php“ file in the Neevo/Drivers directory.

That's all. Now, you are ready to use Neevo and all it's features.

« Data retrieval

Fork me on GitHub