Custom wrapper / Composition
decMuc\PDOdb\PDOdb is intentionally declared as
final and is not meant to be subclassed.
The old example that showed class MyDatabase extends PDOdb
was from the very early days and is no longer valid.
The recommended way is to use composition
(a wrapper / base class that contains a PDOdb instance), not inheritance.
In real-world applications you usually want a central place where you configure
your database connection(s) and expose a convenient API to the rest of your code.
Instead of extending PDOdb directly, create your own base class that
holds a PDOdb instance and provides a method like getDb().
Base model with a core database connection
A common pattern is to have an abstract base model or service class that owns a
default (core/system) PDOdb instance. All other models extend this base class
and use getDb() to access the core database.
use decMuc\PDOdb\PDOdb;
abstract class BaseModel
{
/**
* Core/system database connection for the application.
* This is where global EMS data, configuration, etc. is stored.
*/
private PDOdb $coreDb;
public function __construct()
{
// default/shared instance
$this->coreDb = PDOdb::getInstance();
}
/**
* Always returns the core/system database connection.
*/
protected function getCoreDb(): PDOdb
{
return $this->coreDb;
}
}
The important part here is: getCoreDb() is the single, safe access
to your core/system database. Child classes cannot accidentally overwrite this
property because it is declared as private in the base class.
Usage in a simple model
A simple model or repository just uses the core database:
final class UserRepository extends BaseModel
{
public function getActiveUsers(): array
{
return $this->getCoreDb()
->where('status', 'active')
->get('users');
}
}
This keeps your application code independent from PDOdb internals while still
exposing the full query API via getCoreDb().
Advanced: working with a second (customer/tenant) database
Many EMS-style applications work with more than one database:
a core/system database and one or more customer/tenant databases.
PDOdb supports this via the instance mechanism. A child model
can keep an additional connection that is separate from the core DB.
use decMuc\PDOdb\PDOdb;
final class MediaRepository extends BaseModel
{
/**
* Customer/tenant-specific database connection.
* This is intentionally separate from the core DB.
*/
protected PDOdb $tenantDb;
public function __construct(string $dbHost, string $dbUser, string $dbPass, string $dbName)
{
parent::__construct(); // initializes the core DB
$instance = $dbName; // used as instance key
$existing = PDOdb::getInstance($instance);
if ($existing instanceof PDOdb) {
$this->tenantDb = $existing;
} else {
$this->tenantDb = new PDOdb([
'host' => $dbHost,
'username' => $dbUser,
'password' => $dbPass,
'db' => $dbName,
'instance' => $instance,
]);
}
}
public function insertMediaForCustomer(array $data): int
{
// write to the customer/tenant DB
return $this->tenantDb
->insert('cust_media_files', $data);
}
public function logToCoreDb(array $data): int
{
// write to the core/system DB
return $this->getCoreDb()
->insert('media_log', $data);
}
}
The idea here is very explicit:
– getCoreDb() → always the core/system database
– $this->tenantDb → customer/tenant database for this model
getDb() for the core DB, while certain child models define their
own protected $db property for the tenant DB. This works in PHP
because a private property in the parent class does not conflict
with a protected property of the same name in the child class.
The important semantic idea is the same as in the example above: one connection is reserved for the core/system database (accessed via a getter), and another connection is used for tenant-specific data in the child model.