anax / database
Anax Database module, to work with databases.
Installs: 14 578
Dependents: 23
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 9
Open Issues: 2
Requires
- php: >=7.2
Requires (Dev)
- phpunit/phpunit: ^8
README
Anax Database module as a database abstraction layer (DBA) for wrapping PHP PDO with an additional layer of utilities and ease of use together with ability to use configuration file and attach into an Anax installation as a servide in $di.
The module is tested using MySQL and SQLite.
There are separate modules for a Database Query Builder in anax\database-query-builder
and a Database Active Record in anax\database-active-record
.
Table of content
- Install
- Development
- Class, interface, trait
- Exceptions
- Configuration file
- DI service
- Access as framework service
- Create a connection
- Perform a SELECT query
- Fetch versus FetchAll
- FetchClass
- FetchInto
- Perform an INSERT, UPDATE, DELETE query
- Last insert id
- Row count, affected rows
- Throw exception on failure
- Dependency
- License
Install
You can install the module from anax/database
on Packagist using composer.
composer require anax/database
You can then copy the default configuration files as a start.
# In the root of your Anax installation
rsync -av vendor/anax/database/config .
Development
To work as a developer you clone the repo and install the local environment through make. Then you can run the unit tests.
make install
make test
Class, interface, trait
The following classes exists.
Exceptions
All exceptions are in the namespace Anax\Database\Exception\
. The following exceptions exists and may be thrown.
Configuration file
This is a sample configuration file. It is usually stored in config/database.php
when used together with Anax.
/** * Config file for Database. * * Example for MySQL. * "dsn" => "mysql:host=localhost;dbname=test;", * "username" => "test", * "password" => "test", * "driver_options" => [ * \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'" * ], * * Example for SQLite. * "dsn" => "sqlite::memory:", * "dsn" => "sqlite:$path", * */ return [ "dsn" => null, "username" => null, "password" => null, "driver_options" => null, "fetch_mode" => \PDO::FETCH_OBJ, "table_prefix" => null, "session_key" => "Anax\Database", "emulate_prepares" => false, // True to be very verbose during development "verbose" => null, // True to be verbose on connection failed "debug_connect" => false, ];
You can use if-statements within the configuration file to serve different configurations for local development environment, staging and or production environment.
DI service
The database is created as a framework service within $di
. The following is a sample on how the database service is created through config/di/db.php
.
/** * Configuration file for database service. */ return [ // Services to add to the container. "services" => [ "db" => [ "shared" => true, "callback" => function () { $db = new \Anax\Database\Database(); // Load the configuration files $cfg = $this->get("configuration"); $config = $cfg->load("database"); // Set the database configuration $connection = $config["config"] ?? []; $db->setOptions($connection); return $db; } ], ], ];
The setup callback works like this.
- The database object is created.
- The configuration file is read.
- The configuration is applied.
Access as framework service
You can access the database module as a framework service.
$sql = "SELECT * FROM movie;"; # $app style $app->db->connect(); $res = $app->db->executeFetchAll($sql); # $di style $db = $di->get("db"); $db->connect(); $res = $db->executeFetchAll($sql);
Create a connection
You must connect to the database before using it.
You may call $db->connect()
many times, the connection is however only made once, the first time, so it is safe to call the method several times.
# $app style $app->db->connect(); # $di style $di->get("db")->connect();
Perform a SELECT query
You connect and perform the query which returns a resultset.
$sql = "SELECT * FROM movie;"; # $app style $app->db->connect(); $res = $app->db->executeFetchAll($sql); # $di style $db = $di->get("db"); $db->connect(); $res = $db->executeFetchAll($sql);
The contents of $res
is depending on the configuration key which default is set to "fetch_mode" => \PDO::FETCH_OBJ,
.
You can also separate executeFetchAll()
into two separate commands execute()
and fetchAll()
.
$sql = "SELECT * FROM movie;"; # $app style $app->db->connect(); $res = $app->db->execute($sql)->fetchAll(); # $di style $db = $di->get("db"); $db->connect(); $res = $db->execute($sql)->fetchAll();
Fetch versus FetchAll
With fetchAll()
you fetch all matching rows in an array. When no matching rows are found you get en ampty array.
With fetch()
you get the first item in the resultset. You may use this when your resultset only contain one row.
$sql = "SELECT * FROM movie WHERE id = 1;"; # $app style $app->db->connect(); $res = $app->db->executeFetch($sql); # $di style $db = $di->get("db"); $db->connect(); $res = $db->executeFetch($sql);
The content of $res
is now an object of type \StdClass
and you access the resultset columns by their name, for example $res->id
.
FetchClass
You can fetch the resultset into an object instantiated from a specified class.
$sql = "SELECT * FROM movie WHERE id = ?;"; # $app style $app->db->connect(); $res = $app->db->executeFetchClass($sql, [1], "\Anax\SomeClass"); # $di style $db = $di->get("db"); $db->connect(); $res = $db->executeFetchClass($sql, [1], "\Anax\SomeClass");
The resultset is inserted into a new object of the class "\Anax\SomeClass"
.
There is also executeFetchAllClass()
which fetches an array of all matching rows as new objects of the class.
FetchInto
You can fetch the resultset into an existing object as public properties.
$sql = "SELECT * FROM movie WHERE id = ?;"; $obj = new SomeClass(); # $app style $app->db->connect(); $res = $app->db->executeFetchInto($sql, [1], $obj); # $di style $db = $di->get("db"); $db->connect(); $res = $db->executeFetchClass($sql, [1], $obj);
The resultset is inserted into the object $obj
.
Perform an INSERT, UPDATE, DELETE query
These queries, that updates the database, uses $db->execute()
and does not return a resultset.
$sql = "UPDATE movie SET title = ? WHERE id = ?;"; # $app style $app->db->connect(); $app->db->execute($sql, ["Some title", 1]); # $di style $db = $di->get("db"); $db->connect(); $db->execute($sql, ["Some title", 1]);
Last insert id
You can check the last inserted id when doing INSERT where the primary key is auto generated.
$sql = "INSERT INTO movie (title) VALUES (?);"; # $app style $app->db->connect(); $app->db->execute($sql, ["Some title"]); $id = $app->lastInsertId(); # $di style $db = $di->get("db"); $db->connect(); $db->execute($sql, ["Some title"]); $id = $db->lastInsertId();
Row count, affected rows
You can check how many rows that are affected by the last INSERT, UPDATE, DELETE statement.
$sql = "DELETE FROM movie;"; # $app style $app->db->connect(); $app->db->execute($sql); $num = $app->rowCount(); # $di style $db = $di->get("db"); $db->connect(); $db->execute($sql); $num = $db->rowCount();
Throw exception on failure
Exception are in general thrown as soon as something fails.
The exception is module specific Anax\Database\Exception\Exception
and contains details from the error message from the PDO layer, either from the statement or from the PDO-object, depending on what type of error happens.
Dependency
No particular dependencies. The module is usually used within an Anax installation but can also be used without Anax.
License
This software carries a MIT license. See LICENSE.txt for details.
.
..: Copyright (c) 2013 - 2018 Mikael Roos, mos@dbwebb.se