3 minutes
Use Dotenv to Configure a Laminas or Mezzio Application
In 2019, I wrote an article about using Dotenv to configure a Zend Expressive application. Since then, the project has been renamed to Laminas and the microframework to Mezzio. Plus, vlucas/phpdotenv
has been updated and the recommended way to use it has changed. Time for an update.
Starting point
Any laminas or mezzio application serves as a starting point. For this article, a minimal setup is used with a container.php
and container.php
as it is provided by mezzio-skeleton
.
In this example, the .env
file is used to configure the database connection. The database connection is created using PDO. The database connection is created in a factory and the factory is registered in the container.
Install phpdotenv
composer require vlucas/phpdotenv
Create a dotenv file
.env
DB_DSN=sqlite::memory:
DB_USERNAME=null
DB_PASSWORD=null
Connect dotenv to the application
To make the .env
file available to the application, the following code is added to container.php
. It also ensures that the required environment variables are set.
config/container.php
use Dotenv\Dotenv;
$dotenv = Dotenv::createImmutable(dirname(__DIR__));
$dotenv->load();
$dotenv->required(['DB_DSN', 'DB_USERNAME', 'DB_PASSWORD']);
Application configuration
As the .env
file is environment-specific, and the application configuration is making usage of it, the configuration file can be global.
config/autoload/db.global.php
<?php
declare(strict_types=1);
return [
'db' => [
'dsn' => $_ENV['DB_DSN'],
'username' => $_ENV['DB_USERNAME'],
'password' => $_ENV['DB_PASSWORD'],
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
],
],
];
Factory
The PDO instance is created in a factory.
src/LaminasDotEnv/PdoFactory.php
<?php
declare(strict_types=1);
namespace LaminasDotEnv;
use PDO;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
final class PdoFactory
{
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function __invoke(ContainerInterface $container): PDO
{
$config = $container->get('config');
return new PDO(
$config['db']['dsn'],
$config['db']['username'],
$config['db']['password'],
);
}
}
Add a service definition as you wish. The PDO instance can then be retrieved from the container.
bin/db.php
<?php
declare(strict_types=1);
use Psr\Container\ContainerInterface;
require_once dirname(__DIR__) . '/vendor/autoload.php';
(static function (): void {
$container = require dirname(__DIR__) . '/config/container.php';
assert($container instanceof ContainerInterface);
$pdo = $container->get(PDO::class);
assert($pdo instanceof PDO);
echo 'Create table' . PHP_EOL;
$pdo->exec('CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
echo 'Insert data' . PHP_EOL;
$pdo->exec('INSERT INTO test (name) VALUES ("Hello, World!")');
echo 'Fetch data' . PHP_EOL;
$stmt = $pdo->query('SELECT * FROM test');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo 'Data: ';
echo $row['name'] . PHP_EOL;
echo 'Done' . PHP_EOL;
})();
Run the application
C:\source\laminas-dot-env [main ≡]> php bin/db.php
Create table
Insert data
Fetch data
Data: Hello, World!
Done
Conclusion
Using Dotenv to configure a Laminas or Mezzio application is straightforward. The .env
file is loaded in the container configuration and the required environment variables are checked. The PDO instance is created using the configuration via a factory registered to the container. The PDO instance is retrieved from the container.