Oihana PHP

PDOModel extends Model uses PDOTrait

A ready-to-use, PDO-backed model that turns SQL queries into objects, schema instances or scalars.

PDOModel extends Model (DI container + debug + logger) and mixes in PDOTrait, which supplies all the database plumbing: prepared-statement execution, named-parameter binding, the various fetch* helpers, schema-based result mapping and generator-based streaming.

Everything is configured through the constructor $init array, including the PDO instance itself which may be passed directly or referenced by its container service id:

  • alters : a map of property alterations applied to each fetched row (see AlterDocumentTrait).
  • binds : default named-parameter bindings reused across queries (see BindsTrait).
  • deferAssignment : when a schema is set, hydrate via FETCH_PROPS_LATE (constructor runs first).
  • schema : a class name; rows are then returned as instances of that class instead of stdClass.
  • pdo : a PDO instance, or the container id of one to resolve.
Tags
example
use DI\Container;
use oihana\models\pdo\PDOModel;

$container = new Container();

// Configuration array with optional parameters
$config =
[
    'deferAssignment' => true,
    'pdo'             => 'my_pdo_service', // a PDO instance, or its container service id
    'schema'          => MyEntity::class,  // rows are hydrated into MyEntity instances
];

// Instantiate the model with the container and configuration
$model = new PDOModel( $container , $config ) ;

// Fetch a single record (returned as a MyEntity instance thanks to the schema)
$record = $model->fetch( 'SELECT * FROM users WHERE id = :id' , [ 'id' => 123 ] );

// Fetch all records
$records = $model->fetchAll( 'SELECT * FROM users' );

// Stream a large result set without loading it all in memory
foreach ( $model->fetchAllAsGenerator( 'SELECT * FROM logs' ) as $row )
{
    // process $row
}
author

Marc Alcaraz (ekameleon)

since
1.0.0

Table of Contents

Properties

$container  : Container
The PHP-DI container reference, used to resolve services by name throughout the model.
$deferAssignment  : bool|null
Whether schema hydration should run the constructor *before* assigning fetched columns.
$pdo  : PDO|null
The PDO connection used to prepare and execute statements, or `null` when none is configured.

Methods

__construct()  : mixed
Creates a new PDOModel instance.
bindValues()  : void
Binds named parameters onto an already-prepared PDO statement.
fetch()  : mixed
Executes a SELECT query and returns its first row.
fetchAll()  : array<string|int, mixed>
Executes a query and returns all of its rows at once.
fetchAllAsGenerator()  : Generator<string|int, object>
Executes a SELECT query and streams its rows one by one through a generator.
fetchColumn()  : mixed
Executes a query and returns the value of a single column from its first row.
fetchColumnArray()  : array<int, string>
Executes a query and returns the first column of every row as a flat list.
initializeDefaultFetchMode()  : void
Configures the fetch mode of a statement just before rows are read.
initializeDeferAssignment()  : static
Initializes the `$deferAssignment` property from an options array.
initializePDO()  : static
Initializes the `$pdo` connection from an options array or the DI container.
isConnected()  : bool
Indicates whether a live PDO connection is currently available.

Properties

$container

The PHP-DI container reference, used to resolve services by name throughout the model.

public Container $container

$deferAssignment

Whether schema hydration should run the constructor *before* assigning fetched columns.

public bool|null $deferAssignment = false

Only meaningful when a $schema class is defined: when true, the fetch mode is combined with PDO::FETCH_PROPS_LATE so the object's constructor runs first and the row values then overwrite the defaults it set.

$pdo

The PDO connection used to prepare and execute statements, or `null` when none is configured.

public PDO|null $pdo = null

Methods

__construct()

Creates a new PDOModel instance.

public __construct(Container $container[, PDO|string|null} $init = [] ]) : mixed

Runs the parent Model initializers (debug, logger, mock), then configures the PDO-specific behaviour from the same $init array, in this order: alterations, default binds, deferred assignment, schema, throwable flag and finally the PDO instance (resolved from the container when given as a string id).

Parameters
$container : Container

The DI container used to resolve services such as the PDO instance and the logger.

$init : PDO|string|null} = []

Optional initialization array with keys:

  • alters (ModelParam::ALTERS) : map of property alterations applied to each fetched row.
  • binds (ModelParam::BINDS) : default named-parameter bindings reused across queries.
  • deferAssignment (ModelParam::DEFER_ASSIGNMENT) : when true and a schema is set, hydrate with FETCH_PROPS_LATE.
  • schema (ModelParam::SCHEMA) : class name used as the fetch target instead of stdClass.
  • pdo (ModelParam::PDO) : a PDO instance, or the container service id of one to resolve.
Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

example
$model = new PDOModel( $container ,
[
    'pdo'    => 'db.pdo' ,          // resolved from the container
    'schema' => User::class ,       // rows hydrated as User instances
    'binds'  => [ 'tenant' => 1 ] , // default bindings
] );

bindValues()

Binds named parameters onto an already-prepared PDO statement.

public bindValues(PDOStatement $statement[, array<string|int, mixed> $bindVars = [] ]) : void

Each key of $bindVars is bound to the matching :key placeholder (the leading colon is prepended automatically). A scalar value is bound with PDO's default type inference; an array value is treated as a [value, type] pair, letting you force a PDO type such as PDO::PARAM_INT or PDO::PARAM_BOOL. An empty $bindVars is a no-op.

Parameters
$statement : PDOStatement

The prepared statement to bind the values onto.

$bindVars : array<string|int, mixed> = []

Associative array of bindings, keyed by placeholder name. Supports:

  • ['id' => 5] — bound with default type inference.
  • ['id' => [5, PDO::PARAM_INT]] — bound with an explicit PDO type.
Tags
example
$statement = $pdo->prepare( 'SELECT * FROM users WHERE id = :id AND active = :active' );
$this->bindValues( $statement , [ 'id' => [ 42 , PDO::PARAM_INT ] , 'active' => true ] );
$statement->execute();

fetch()

Executes a SELECT query and returns its first row.

public fetch(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : mixed

The row is mapped according to the configured fetch mode: a schema instance when a $schema class is set, otherwise a stdClass object built from the associative row. The result is then passed through AlterDocumentTrait::alter() before being returned.

When the statement cannot be prepared, fails to execute or returns no row, null is returned. On error the exception is caught and logged (or printed in CLI), unless $throwable is true in which case it is rethrown. The statement cursor is always closed in the finally block.

Parameters
$query : string

The SQL SELECT query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query. Supports:

  • ['id' => 5]
  • ['id' => [5, PDO::PARAM_INT]]
$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
$user = $model->fetch( 'SELECT * FROM users WHERE id = :id' , [ 'id' => 123 ] );

if ( $user !== null )
{
    echo $user->email;
}
Return values
mixed

The altered result object/schema instance, or null if no row is found or the query fails.

fetchAll()

Executes a query and returns all of its rows at once.

public fetchAll(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : array<string|int, mixed>

Depending on the configured fetch mode, rows are returned as schema instances (when a $schema class is set) or as associative arrays. The non-empty result set is passed as a whole through AlterDocumentTrait::alter() so registered alterations apply to every element.

An empty array is returned when the statement cannot be prepared, fails to execute or yields no rows. Errors are caught and logged unless $throwable is true. The cursor is always closed.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query. Supports:

  • ['id' => 5]
  • ['id' => [5, PDO::PARAM_INT]]
$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
$admins = $model->fetchAll(
    'SELECT * FROM users WHERE role = :role' ,
    [ 'role' => 'admin' ]
);

foreach ( $admins as $admin )
{
    // ...
}
Return values
array<string|int, mixed>

The altered list of results, or an empty array if the query yields nothing or fails while $throwable is false.

fetchAllAsGenerator()

Executes a SELECT query and streams its rows one by one through a generator.

public fetchAllAsGenerator(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : Generator<string|int, object>

This is the memory-efficient counterpart of PDOTrait::fetchAll(): rows are never accumulated in an array. Each row is cast to an object (or hydrated into a schema instance via the configured fetch mode), passed through AlterDocumentTrait::alter() and yielded immediately. The cursor is closed once iteration completes or the generator is discarded.

If the statement cannot be prepared or fails to execute, the generator simply yields nothing. Errors raised during iteration are logged unless $throwable is true.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query (see PDOTrait::bindValues()).

$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
// Iterate over a million rows without exhausting memory
foreach ( $model->fetchAllAsGenerator( 'SELECT * FROM events' ) as $event )
{
    $this->process( $event );
}
Return values
Generator<string|int, object>

A generator yielding the altered rows one at a time.

fetchColumn()

Executes a query and returns the value of a single column from its first row.

public fetchColumn(string $query[, array<string|int, mixed> $bindVars = [] ][, int $column = 0 ][, bool $throwable = false ]) : mixed

Unlike the other fetch* helpers this one does not apply schema mapping nor alterations — it returns the raw scalar produced by PDOStatement::fetchColumn(). Handy for COUNT(*), MAX(...), an existence check or fetching one field.

Returns null when the statement cannot be prepared, fails to execute or has no row. Errors are logged and swallowed unless $throwable is true. The cursor is always closed.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query (see PDOTrait::bindValues()).

$column : int = 0

Zero-based index of the column to return from the first row (default 0).

$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
Exception

If the SQL statement fails to prepare or execute and $throwable is true.

example
$total = (int) $model->fetchColumn(
    'SELECT COUNT(*) FROM users WHERE active = :active' ,
    [ 'active' => true ]
);
Return values
mixed

The column value, or null if no row is found or the query fails.

fetchColumnArray()

Executes a query and returns the first column of every row as a flat list.

public fetchColumnArray(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : array<int, string>

Uses PDO::FETCH_COLUMN, so a single-column SELECT yields a simple list of scalar values. Like PDOTrait::fetchColumn() it applies neither schema mapping nor alterations.

Returns an empty array when the statement cannot be prepared, fails to execute or has no rows. Errors are logged and swallowed unless $throwable is true. The cursor is always closed.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query (see PDOTrait::bindValues()).

$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
Exception

If the SQL statement fails to prepare or execute and $throwable is true.

example
$emails = $model->fetchColumnArray( 'SELECT email FROM users WHERE active = 1' );
// [ 'a@example.com' , 'b@example.com' , ... ]
Return values
array<int, string>

The list of first-column values, or an empty array on failure.

initializeDefaultFetchMode()

Configures the fetch mode of a statement just before rows are read.

public initializeDefaultFetchMode(PDOStatement $statement) : void

When $schema names an existing class, rows are hydrated into instances of it via PDO::FETCH_CLASS, combined with PDO::FETCH_PROPS_LATE when $deferAssignment is true (so the constructor runs before columns are assigned). Otherwise the statement falls back to PDO::FETCH_ASSOC. Called internally by every fetch* helper.

Parameters
$statement : PDOStatement

The prepared, executed statement to configure.

initializeDeferAssignment()

Initializes the `$deferAssignment` property from an options array.

public initializeDeferAssignment([array<string|int, mixed> $init = [] ]) : static

Reads the ModelParam::DEFER_ASSIGNMENT key when present, falling back to false.

Parameters
$init : array<string|int, mixed> = []

Initialization options; the deferAssignment boolean key sets the property.

Return values
static

The current instance, i.e. $this, for fluent chaining.

initializePDO()

Initializes the `$pdo` connection from an options array or the DI container.

public initializePDO([array<string|int, mixed> $init = [] ][, Container|null $container = null ]) : static

The ModelParam::PDO key may hold a PDO instance directly, or a string service id. When it is a string and the given container declares that id, the service is resolved from it. Any value that is not ultimately a PDO instance leaves $pdo set to null.

Parameters
$init : array<string|int, mixed> = []

Configuration array; the pdo key holds a PDO instance or a container id.

$container : Container|null = null

Optional DI container used to resolve a string PDO service id.

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

Return values
static

The current instance, i.e. $this, for fluent chaining.

isConnected()

Indicates whether a live PDO connection is currently available.

public isConnected() : bool

Returns false when no PDO instance is configured. Otherwise it queries PDO::ATTR_CONNECTION_STATUS; a non-null status means the connection is up. Any PDOException raised while reading the attribute is treated as "not connected".

Return values
bool

true if a PDO instance is set and reports a connection status, false otherwise.

On this page

Search results