finesse/micro-db

A simple database connector for using pure men's SQL with bindings 💪

v0.2.3 2018-03-13 04:56 UTC

This package is auto-updated.

Last update: 2021-05-29 01:11:29 UTC


README

Latest Stable Version Total Downloads PHP from Packagist Test Status Maintainability Test Coverage

Like to use pure SQL but don't like to suffer from PDO, mysqli or etc.? Try this.

$database = Connection::create('mysql:host=localhost;dbname=my_database', 'user', 'pass');
$items = $database->select('SELECT * FROM items WHERE category_id = ?', [3]);

Key features:

  • No silly query builder, only a good old SQL.
  • Very light, no external dependencies. It required only the PDO extension which is available by default in most of servers.
  • Database object is delivered explicitly, not through a static class.
  • Exceptions on errors.

You can combine it with a third-party SQL query builder to rock the database. Examples of suitable query builders: Query Scribe, Nilportugues SQL Query Builder, Aura.SqlQuery, Latitude, Koine Query Builder, Phossa2 Query, Hydrahon.

Installation

Using Composer

Run in a console

composer require finesse/micro-db

Reference

Create a Connection instance

To create a new Connection instance call the create method passing PDO constructor arguments.

use Finesse\MicroDB\Connection;

$database = Connection::create('dsn:string', 'username', 'password, ['options']);

Or pass a PDO instance to the constructor. But be careful: Connection changes the given PDO object and you must not change the given object, otherwise something unexpected will happen.

use Finesse\MicroDB\Connection;

$pdo = new PDO(/* ... */);
$database = new Connection($pdo);

Select

Select many rows:

$rows = $database->select('SELECT * FROM table'); // [['id' => 1, 'name' => 'Bill'], ['id' => 2, 'name' => 'John']]

Select one row:

$row = $database->selectFirst('SELECT * FROM table'); // ['id' => 1, 'name' => 'Bill']

The cell values are returned as they are returned by PDO. They are not casted automatically because casting can cause data loss.

Insert

Insert and get the number of the inserted rows:

$insertedCount = $database->insert('INSERT INTO table (id, price) VALUES (1, 45), (2, 98)'); // 2

Insert and get the identifier of the last inserted row:

$id = $database->insertGetId('INSERT INTO table (weight, price) VALUES (12.3, 45)'); // 3

Update

Update rows and get the number of the updated rows:

$updatedCount = $database->update('UPDATE table SET status = 1 WHERE price < 1000');

Delete

Delete rows and get the number of the deleted rows:

$deletedCount = $database->delete('DELETE FROM table WHERE price > 1000');

Other queries

Perform any other statement:

$database->statement('CREATE TABLE table(id INTEGER PRIMARY KEY ASC, name TEXT, price NUMERIC)');

If the query contains multiple statements separated by a semicolon, only the first statement will be executed. You can execute multiple statements using the other method:

$database->statements("
    CREATE TABLE table(id INTEGER PRIMARY KEY ASC, name TEXT, price NUMERIC);
    INSERT INTO table (name, price) VALUES ('Donald', 1000000);
");

The lack of this method is that it doesn't take values to bind.

Execute a file

Execute the query from an SQL file:

$database->import('path/to/file.sql');

Or from a resource:

$stream = fopen('path/to/file.sql', 'r');
$database->import($stream);

Binding values

You should not insert values right to an SQL query because it can cause SQL injections. Instead use the binding:

// WRONG! Don't do it or you will be fired
$rows = $database->select("SELECT * FROM table WHERE name = '$name' LIMIT $limit");

// Good
$rows = $database->select('SELECT * FROM table WHERE name = ? LIMIT ?', [$name, $limit]);

Database server replaces the placeholders (?s) safely with the given values. Almost all the above methods accepts the list of the bound values as the second argument.

You can also use named parameters:

$rows = $database->select('SELECT * FROM table WHERE name = :name LIMIT :limit', [':name' => $name, ':limit' => $limit]);

You can even pass named and anonymous parameters in the same array but it works only when the array of values has the same order as the placeholders in the query text.

All the scalar types of values are supported: string, integer, float, boolean and null.

Error handling

The Finesse\MicroDB\Exceptions\PDOException is thrown in case of every database query error. If an error is caused by an SQL query, the exception has the query text and bound values in the message. They are also available through the methods:

$sql = $exception->getQuery();
$bindings = $exception->getValues();

The Finesse\MicroDB\Exceptions\InvalidArgumentException is thrown when the method arguments have a wrong format.

The Finesse\MicroDB\Exceptions\FileException is thrown on a file read error.

All the exceptions implement Finesse\MicroDB\IException.

Retrieve the underlying PDO object

$pdo = $database->getPDO();

You must not change the retrieved object, otherwise something unexpected will happen.

Known problems

  • insertGetId doesn't return the inserted row identifier for SQL Server and PostgreSQL.
  • statements and import don't throw an exception if the second or a next statement of the query has an error. This is a PDO bug.

Make a pull request or an issue if you need a problem to be fixed.

Versions compatibility

The project follows the Semantic Versioning.

License

MIT. See the LICENSE file for details.