All Projects → paragonie → Easydb

paragonie / Easydb

Licence: mit
Easy-to-use PDO wrapper for PHP projects.

Projects that are alternatives of or similar to Easydb

Dibi
Dibi - smart database abstraction layer
Stars: ✭ 373 (-40.22%)
Mutual labels:  pdo, database, mysql, postgresql, sqlite
Db
Data access layer for PostgreSQL, CockroachDB, MySQL, SQLite and MongoDB with ORM-like features.
Stars: ✭ 2,832 (+353.85%)
Mutual labels:  database, mysql, postgresql, sqlite
Typeorm
ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.
Stars: ✭ 26,559 (+4156.25%)
Mutual labels:  database, mysql, postgresql, sqlite
Mikro Orm
TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite databases.
Stars: ✭ 3,874 (+520.83%)
Mutual labels:  database, mysql, postgresql, sqlite
Migrate
Database migrations. CLI and Golang library.
Stars: ✭ 2,315 (+270.99%)
Mutual labels:  database, mysql, sqlite, databases
Endb
Key-value storage for multiple databases. Supports MongoDB, MySQL, Postgres, Redis, and SQLite.
Stars: ✭ 208 (-66.67%)
Mutual labels:  database, mysql, postgresql, sqlite
Phpmyfaq
phpMyFAQ - Open Source FAQ web application for PHP and MySQL, PostgreSQL and other databases
Stars: ✭ 494 (-20.83%)
Mutual labels:  database, mysql, postgresql, sqlite
Sql Fundamentals
👨‍🏫 Mike's SQL Fundamentals and Professional SQL Courses
Stars: ✭ 140 (-77.56%)
Mutual labels:  database, mysql, postgresql, sqlite
Pgloader
Migrate to PostgreSQL in a single command!
Stars: ✭ 3,754 (+501.6%)
Mutual labels:  database, mysql, postgresql, sqlite
Beekeeper Studio
Modern and easy to use SQL client for MySQL, Postgres, SQLite, SQL Server, and more. Linux, MacOS, and Windows.
Stars: ✭ 8,053 (+1190.54%)
Mutual labels:  database, mysql, postgresql, sqlite
Go Sqlbuilder
A flexible and powerful SQL string builder library plus a zero-config ORM.
Stars: ✭ 539 (-13.62%)
Mutual labels:  database, mysql, postgresql, sqlite
Denodb
MySQL, SQLite, MariaDB, PostgreSQL and MongoDB ORM for Deno
Stars: ✭ 498 (-20.19%)
Mutual labels:  database, mysql, postgresql, sqlite
Nut
Advanced, Powerful and easy to use ORM for Qt
Stars: ✭ 181 (-70.99%)
Mutual labels:  database, mysql, postgresql, sqlite
Evolve
Database migration tool for .NET and .NET Core projects. Inspired by Flyway.
Stars: ✭ 477 (-23.56%)
Mutual labels:  database, mysql, postgresql, sqlite
Linq2db
Linq to database provider.
Stars: ✭ 2,211 (+254.33%)
Mutual labels:  database, mysql, postgresql, sqlite
Php Crud Api
Single file PHP script that adds a REST API to a SQL database
Stars: ✭ 2,904 (+365.38%)
Mutual labels:  database, mysql, postgresql, sqlite
Directus
Open-Source Data Platform 🐰 — Directus wraps any SQL database with a real-time GraphQL+REST API and an intuitive app for non-technical users.
Stars: ✭ 13,190 (+2013.78%)
Mutual labels:  database, mysql, postgresql, sqlite
Kangaroo
SQL client and admin tool for popular databases
Stars: ✭ 127 (-79.65%)
Mutual labels:  database, mysql, postgresql, sqlite
Node Orm2
Object Relational Mapping
Stars: ✭ 3,063 (+390.87%)
Mutual labels:  database, mysql, postgresql, sqlite
Dbeaver
Free universal database tool and SQL client
Stars: ✭ 23,752 (+3706.41%)
Mutual labels:  database, mysql, postgresql, sqlite

EasyDB - Simple Database Abstraction Layer

Build Status Latest Stable Version Latest Unstable Version License Downloads

PDO lacks brevity and simplicity; EasyDB makes separating data from instructions easy (and aesthetically pleasing).

EasyDB was created by Paragon Initiative Enterprises as part of our effort to encourage better application security practices.

Check out our other open source projects too.

If you're looking for a full-fledged query builder, check out Latitude and Aura.SqlQuery, which can be used with EasyDB.

If you'd like to use EasyDB but cache prepared statements in memory for multiple queries (i.e. to reduce database round-trips), check out our EasyDB-Cache wrapper class.

Installing EasyDB

First, get Composer, if you don't already use it.

Next, run the following command:

/path/to/your/local/composer.phar require paragonie/easydb:^2

If you've installed Composer in /usr/bin, you can replace /path/to/your/local/composer.phar with just composer.

Why Use EasyDB? Because it's cleaner!

Let's refactor a dangerous PHP snippet that previously used string concatenation to pass user input instead of prepared statements. For example, imagine something that just dropped {$_GET['blogpostid']} into the middle of a mysql_query() statement. Let's make it secure.

The PDO Way

$db = new \PDO(
    'mysql:host=localhost;dbname=something',
    'username',
    'putastrongpasswordhere'
);

$statement = $db->prepare('SELECT * FROM comments WHERE blogpostid = ? ORDER BY created ASC');
$exec = $statement->execute([$_GET['blogpostid']]);
$rows = $statement->fetchAll(\PDO::FETCH_ASSOC);
foreach ($rows as $row) {
    $template_engine->render('comment', $row);
}

That's a little wordy for such a simple task. If we do this in multiple places, we end up repeating ourselves a lot.

The EasyDB Solution

$db = \ParagonIE\EasyDB\Factory::fromArray([
    'mysql:host=localhost;dbname=something',
    'username',
    'putastrongpasswordhere'
]);

$rows = $db->run('SELECT * FROM comments WHERE blogpostid = ? ORDER BY created ASC', $_GET['blogpostid']);
foreach ($rows as $row) {
    $template_engine->render('comment', $row);
}

We made it a one-liner.

What else can EasyDB do quickly?

Insert a row into a database table

$db->insert('comments', [
    'blogpostid' => $_POST['blogpost'],
    'userid' => $_SESSION['user'],
    'comment' => $_POST['body'],
    'parent' => isset($_POST['replyTo']) ? $_POST['replyTo'] : null
]);

This is equivalent to the following SQL query (assuming $_POST['blogpostid'] is equal to 123, $_SESSION['user'] is equal to 234, $_POST['body'] is equal to test, and $_POST['replyTo'] is equal to 3456):

INSERT INTO comments (blogpostid, userid, comment, parent) VALUES (
    123,
    234,
    'test',
    3456
);

Build an insert without executing

$sql = $db->buildInsertQuery('comments', [
    'blogpostid',
    'userid',
    'comment'
]);

// INSERT INTO comments (blogpostid, userid, comment) VALUES (?, ?, ?)

$result = $db->q(
    $sql,
    $values,
    \PDO::FETCH_BOTH,
    true
);

Update a row from a database table

$db->update('comments', [
    'column' => 'foo',
    'otherColumn' => 123456,
    'approved' => true
], [
    'commentid' => $_POST['comment']
]);

This is equivalent to the following SQL query (assuming $_POST['comment'] is equal to 789):

UPDATE comments
SET 
  column = 'foo',
  otherColumn = 123456,
  approved = TRUE
WHERE commentid = 789

Delete a row from a database table

// Delete all of this user's comments
$db->delete('comments', [
    'userid' => 3
]);

This is equivalent to the following SQL query:

DELETE FROM comments WHERE userid = 3

Fetch a single row from a table

$userData = $db->row(
    "SELECT * FROM users WHERE userid = ?",
    $_GET['userid']
);

Note: This expects a variadic list of arguments, not an array. If you have multiple parameters, stack them like this:

$userData = $db->row(
    "SELECT * FROM users WHERE userid = ? AND other = ?",
    $_GET['userid'],
    $_GET['other']
);

This is wrong:

$userData = $db->row(
    "SELECT * FROM users WHERE userid = ? AND other = ?",
    array($userid, $other) // WRONG, should not be in an array
);

Fetch a single column from a single row from a table

$exists = $db->cell(
    "SELECT count(id) FROM users WHERE email = ?",
    $_POST['email']
);

/* OR YOU CAN CALL IT THIS WAY: */
$exists = $db->single(
    "SELECT count(id) FROM users WHERE email = ?",
    array(
        $_POST['email']
    )
);

Note: cell() expects a variadic list of arguments, not an array. If you have multiple parameters, stack them like this:

$exists = $db->cell(
    "SELECT count(id) FROM users WHERE email = ? AND username = ?",
    $_POST['email'],
    $_POST['usenrame']
);

This is wrong:

$exists = $db->cell(
    "SELECT count(id) FROM users WHERE email = ? AND username = ?",
    array($email, $username) // WRONG, should not be in an array
);

Alternatively, you can use single() instead of cell() if you really want to pass an array.

Try to perform a transaction

$save = function (EasyDB $db) use ($userData, $query) : int {
    $db->safeQuery($query, [$userData['userId']]);
    return \Some\Other\Package::CleanUpTable($db);
};
// auto starts, commits and rolls back a transaction as necessary
$returnedInt = $db->tryFlatTransaction($save);

Generate dynamic query conditions

$statement = EasyStatement::open()
    ->with('last_login IS NOT NULL');

if (strpos($_POST['search'], '@') !== false) {
    // Perform a username search
    $statement->orWith('username LIKE ?', '%' . $db->escapeLikeValue($_POST['search']) . '%');
} else {
    // Perform an email search
    $statement->orWith('email = ?', $_POST['search']);
}

// The statement can compile itself to a string with placeholders:
echo $statement; /* last_login IS NOT NULL OR username LIKE ? */

// All the values passed to the statement are captured and can be used for querying:
$user = $db->single("SELECT * FROM users WHERE $statement", $statement->values());

Note: Passing values with conditions is entirely optional but recommended.

Variable number of "IN" arguments

// Statements also handle translation for IN conditions with variable arguments,
// using a special ?* placeholder:
$roles = [1];
if ($_GET['with_managers']) {
    $roles[] = 2;
}

$statement = EasyStatement::open()->in('role IN (?*)', $roles);

// The ?* placeholder is replaced by the correct number of ? placeholders:
echo $statement; /* role IN (?, ?) */

// And the values will be unpacked accordingly:
print_r($statement->values()); /* [1, 2] */

Grouping of conditions

// Statements can also be grouped when necessary:
$statement = EasyStatement::open()
    ->group()
        ->with('subtotal > ?')
        ->andWith('taxes > ?')
    ->end()
    ->orGroup()
        ->with('cost > ?')
        ->andWith('cancelled = 1')
    ->end();

echo $statement; /* (subtotal > ? AND taxes > ?) OR (cost > ? AND cancelled = 1) */

What if I need PDO for something specific?

$pdo = $db->getPdo();

Can I create an EasyDB wrapper for an existing PDO instance?

Yes! It's as simple as doing this:

$easy = new \ParagonIE\EasyDB\EasyDB($pdo, 'mysql');

How do I run tests ?

vendor/bin/phpunit

Troubleshooting Common Issues

Only one-dimensional arrays are allowed

This comes up a lot when trying to pass an array of parameters to run().

EasyDB::run() expects a query string, then any number of optional parameters. It does NOT expect an array of all the parameters.

If you want to use an API that looks like $obj->method($string, $array), use safeQuery() instead of run().

<?php
/**
 * @var EasyDB $db
 * @var string $query
 * @var array $params 
 */
- $rows = $db->run($query, $params);
+ $rows = $db->safeQuery($query, $params);

Alternatively, you can flatten your array with the splat operator:

<?php
/**
 * @var EasyDB $db
 * @var string $query
 * @var array $params 
 */
- $rows = $db->run($query, $params);
+ $rows = $db->run($query, ...$params);

EasyDB's run() method is a variadic wrapper for safeQuery(), so either solution is correct.

Support Contracts

If your company uses this library in their products or services, you may be interested in purchasing a support contract from Paragon Initiative Enterprises.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].