composer require pomm-project/foundation
config/pomm.php file (or extend Laravel’s config/database.php):
'pomm' => [
'connections' => [
'default' => [
'dsn' => 'pgsql:host=localhost;dbname=your_db',
'user' => 'your_user',
'password' => 'your_password',
'timezone' => 'UTC', // Critical for time consistency
],
],
],
use PommProject\Foundation\ConnectionManager;
use PommProject\Foundation\QueryManager;
$connManager = new ConnectionManager('default');
$session = $connManager->getSession();
$queryManager = new QueryManager($session);
// Execute a simple query
$result = $queryManager->query('SELECT * FROM users WHERE id = $1', [1]);
foreach ($result as $row) {
print_r($row);
}
Replace Laravel’s DB::select() with Foundation’s QueryManager for PostgreSQL-specific queries:
$queryManager->query(
'SELECT id, name, data->>\'key\' as custom_data
FROM users
WHERE created_at > $1
ORDER BY id LIMIT $2',
[new \DateTime('2023-01-01'), 10]
);
ConnectionManager:
$connManager = new ConnectionManager('default', [
'pool' => [
'min_connections' => 5,
'max_connections' => 20,
'lifetime' => 3600, // 1 hour
],
]);
$this->app->singleton('pomm.conn', function ($app) {
return new ConnectionManager($app['config']['pomm.connections.default']);
});
$queryManager->query('INSERT INTO logs (message, level) VALUES ($1, $2)', [
'User logged in',
'info'
]);
$iterator = $queryManager->query('SELECT * FROM large_table');
foreach ($iterator as $row) {
// Process row-by-row (memory efficient)
}
$session->listen('user_events');
$session->onNotify(function ($payload, $channel) {
Log::info("Received $channel: $payload");
});
BEGIN, COMMIT, and ROLLBACK:
$session->beginTransaction();
try {
$queryManager->query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [100, 1]);
$queryManager->query('UPDATE accounts SET balance = balance + $1 WHERE id = $3', [100, 2]);
$session->commit();
} catch (\Exception $e) {
$session->rollback();
throw $e;
}
Create app/Providers/PommServiceProvider.php:
public function register()
{
$this->app->singleton('pomm', function ($app) {
$config = $app['config']['pomm.connections.default'];
return new ConnectionManager($config['dsn'], $config['user'], $config['password']);
});
$this->app->bind('pomm.query', function ($app) {
return new QueryManager($app['pomm']->getSession());
});
}
Create app/Facades/Pomm.php:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Pomm extends Facade
{
protected static function getFacadeAccessor()
{
return 'pomm.query';
}
}
Usage:
Pomm::query('SELECT * FROM users')->fetchAll();
Extend Laravel’s Builder to use Foundation:
namespace App\Database;
use PommProject\Foundation\QueryManager;
use Illuminate\Database\Query\Builder as LaravelBuilder;
class PommBuilder extends LaravelBuilder
{
protected $queryManager;
public function __construct(QueryManager $queryManager)
{
$this->queryManager = $queryManager;
}
public function run()
{
$sql = $this->toSql();
$bindings = $this->getBindings();
return $this->queryManager->query($sql, $bindings);
}
}
Timezone Mismatches:
timestamp conversion errors.'timezone' => 'America/New_York', // PHP
And in PostgreSQL:
SET TIME ZONE 'America/New_York';
Composite Types in Non-Public Schemas:
public.$session->getConverterManager()->registerConverter(
'my_schema.my_composite_type',
new \PommProject\Foundation\Converter\CompositeTypeConverter(
$session,
'my_schema.my_composite_type'
)
);
Transaction Isolation:
$session->beginTransaction('SERIALIZABLE');
Memory Leaks with Iterators:
foreach) instead of fetchAll():
// Bad: Loads all rows into memory
$rows = $queryManager->query('SELECT * FROM huge_table')->fetchAll();
// Good: Processes row-by-row
foreach ($queryManager->query('SELECT * FROM huge_table') as $row) {
// Process
}
LISTEN/NOTIFY Persistence:
Enable Query Logging:
$session->getLogger()->setLevel(\Psr\Log\LogLevel::DEBUG);
Logs will show executed queries and parameters.
Check Connection Health:
if (!$session->isActive()) {
$session->reconnect();
}
Handle PostgreSQL Errors:
Foundation throws \PommProject\Foundation\Exception\RuntimeException. Catch and translate to Laravel’s QueryException:
try {
$queryManager->query('INVALID SQL');
} catch (\PommProject\Foundation\Exception\RuntimeException $e) {
throw new \Illuminate\Database\QueryException(
$e->getMessage(),
$e->getCode(),
$e
);
}
Custom Converters:
Extend \PommProject\Foundation\Converter\AbstractConverter for unsupported types (e.g., custom JSON structures):
class CustomJsonConverter extends AbstractConverter
{
public function convertToPHP($value, $type)
{
return json_decode($value, true);
}
public function convertToPostgreSQL($value, $type)
{
return json_encode($value);
}
}
Register with:
$session->getConverterManager()->registerConverter('jsonb', new CustomJsonConverter());
Query Hooks:
Subclass QueryManager to intercept queries:
class LoggingQueryManager extends QueryManager
{
public function query($sql, $params = [])
{
Log::debug("Executing: $sql", ['params' => $params]);
return parent::query($sql, $params);
}
}
Session Events: Listen for session events (e.g., connection drops):
$session->onConnect(function () {
Log::info('Connected to PostgreSQL');
});
$session->onDisconnect(function () {
Log::warning('Disconnected from
How can I help you explore Laravel packages today?