Skip to content

Driver feature interface poc #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions src/Adapter/Driver/Feature/AbstractFeature.php
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
<?php

declare(strict_types=1);

namespace Laminas\Db\Adapter\Driver\Feature;

use Laminas\Db\Adapter\Driver\DriverInterface;

abstract class AbstractFeature
abstract class AbstractFeature implements DriverFeatureInterface
{
/** @var DriverInterface */
protected $driver;
protected DriverInterface $driver;

/**
* Set driver
*
* @return void
*/
public function setDriver(DriverInterface $driver)
public function setDriver(DriverInterface $driver): DriverFeatureInterface
{
$this->driver = $driver;
return $this;
}

/**
* Get name
*
* @return string
*/
abstract public function getName();
}
24 changes: 4 additions & 20 deletions src/Adapter/Driver/Feature/DriverFeatureInterface.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
<?php

namespace Laminas\Db\Adapter\Driver\Feature;
declare(strict_types=1);

interface DriverFeatureInterface
{
/**
* Setup the default features for Pdo
*/
public function setupDefaultFeatures(): DriverFeatureInterface;
namespace Laminas\Db\Adapter\Driver\Feature;

/**
* Add feature
*
* todo: narrow down the type of $feature
*/
public function addFeature(string $name, mixed $feature): DriverFeatureInterface;
use Laminas\Db\Adapter\Driver\DriverAwareInterface;

/**
* Get feature
*
* todo: narrow return type if possible
*/
public function getFeature(string $name): mixed;
}
interface DriverFeatureInterface extends DriverAwareInterface {}
26 changes: 26 additions & 0 deletions src/Adapter/Driver/Feature/DriverFeatureProviderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Laminas\Db\Adapter\Driver\Feature;

use Laminas\Db\Adapter\Driver\DriverInterface;

/**
*
* @property array<class-string, DriverInterface> $features
*/
interface DriverFeatureProviderInterface
{
/** @param DriverFeatureInterface[] $features */
public function addFeatures(array $features): DriverFeatureProviderInterface;

public function addFeature(DriverFeatureInterface $feature): DriverFeatureProviderInterface;

/**
* Get feature
*
* todo: narrow to DriverFeatureInterface|false once PHP 8.2 is the minimum version
*/
public function getFeature(string $name): DriverFeatureInterface|bool;
}
51 changes: 51 additions & 0 deletions src/Adapter/Driver/Feature/DriverFeatureProviderTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace Laminas\Db\Adapter\Driver\Feature;

use Laminas\Db\Adapter\Driver\DriverInterface;
use Laminas\Db\Adapter\Exception\RuntimeException;

/**
* Trait implementation of DriverFeatureProviderInterface.
*
* This trait can be used in any driver that needs to support features.
* Primarily used in the Pdo driver, but can be adapted for others.
*/
trait DriverFeatureProviderTrait
{
/**
*
* @var array<class-string, DriverFeatureInterface>
*/
protected array $features = [];

public function addFeature(DriverFeatureInterface $feature): DriverFeatureProviderInterface
{
if (! $this instanceof DriverInterface) {
throw new RuntimeException(sprintf(
'%s can only be composed into %s',
__TRAIT__,
DriverInterface::class
));
}

$feature->setDriver($this);
$this->features[$feature::class] = $feature;
return $this;
}

public function addFeatures(array $features): DriverFeatureProviderInterface
{
foreach ($features as $feature) {
$this->addFeature($feature);
}
return $this;
}

public function getFeature(string $name): DriverFeatureInterface|bool
{
return $this->features[$name] ?? false;
}
}
8 changes: 0 additions & 8 deletions src/Adapter/Driver/Oci8/Feature/RowCounter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,6 @@
*/
class RowCounter extends AbstractFeature
{
/**
* @return string
*/
public function getName()
{
return 'RowCounter';
}

/**
* @return null|int
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Adapter/Driver/Oci8/Oci8.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function __construct(
?Statement $statementPrototype = null,
?Result $resultPrototype = null,
array $options = [],
$features = self::FEATURES_DEFAULT
$features = [new Feature\RowCounter()]
) {
if (! $connection instanceof Connection) {
$connection = new Connection($connection);
Expand Down
73 changes: 5 additions & 68 deletions src/Adapter/Driver/Pdo/AbstractPdo.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@

use Laminas\Db\Adapter\Driver\ConnectionInterface;
use Laminas\Db\Adapter\Driver\DriverAwareInterface;
use Laminas\Db\Adapter\Driver\Feature\AbstractFeature;
use Laminas\Db\Adapter\Driver\Feature\DriverFeatureInterface;
use Laminas\Db\Adapter\Driver\Feature\DriverFeatureProviderInterface;
use Laminas\Db\Adapter\Driver\PdoDriverAwareInterface;
use Laminas\Db\Adapter\Driver\PdoDriverInterface;
use Laminas\Db\Adapter\Driver\ResultInterface;
Expand All @@ -25,18 +24,16 @@
use function preg_match;
use function sprintf;

abstract class AbstractPdo implements PdoDriverInterface, DriverFeatureInterface, ProfilerAwareInterface
abstract class AbstractPdo implements PdoDriverInterface, ProfilerAwareInterface
{
public const FEATURES_DEFAULT = 'default';

/** @internal */
public ?ProfilerInterface $profiler;

public function __construct(
protected readonly AbstractPdoConnection|\PDO $connection,
protected readonly StatementInterface&PdoDriverAwareInterface $statementPrototype,
protected readonly ResultInterface $resultPrototype,
protected array|string $features = self::FEATURES_DEFAULT
array $features = [],
) {

if ($this->connection instanceof DriverAwareInterface) {
Expand All @@ -47,14 +44,8 @@ public function __construct(
$this->statementPrototype->setDriver($this);
}

if (is_array($features)) {
foreach ($features as $name => $feature) {
$this->addFeature($name, $feature);
}
} elseif ($features instanceof AbstractFeature) {
$this->addFeature($features->getName(), $features);
} elseif ($features === self::FEATURES_DEFAULT) {
$this->setupDefaultFeatures();
if ($features !== [] && $this instanceof DriverFeatureProviderInterface) {
$this->addFeatures($features);
}
}

Expand Down Expand Up @@ -96,60 +87,6 @@ public function registerResultPrototype(ResultInterface $resultPrototype)
$this->resultPrototype = $resultPrototype;
}

/**
* Add feature
*
* todo: needs improvement
*
* @param string $name
* @param AbstractFeature $feature
* @return $this Provides a fluent interface
*/
public function addFeature($name, $feature)
{
if ($feature instanceof AbstractFeature) {
$name = $feature->getName(); // overwrite the name, just in case
$feature->setDriver($this);
}
$this->features[$name] = $feature;
return $this;
}

/**
* Setup the default features for Pdo
*
* @return $this Provides a fluent interface
*/
// public function setupDefaultFeatures()
// {
// $driverName = $this->connection->getDriverName();
// if ($driverName === 'sqlite') {
// $this->addFeature(null, new Feature\SqliteRowCounter());
// return $this;
// }

// if ($driverName === 'oci') {
// $this->addFeature(null, new Feature\OracleRowCounter());
// return $this;
// }

// return $this;
// }

/**
* Get feature
*
* @param string $name
* @return AbstractFeature|false
*/
public function getFeature($name)
{
if (isset($this->features[$name])) {
return $this->features[$name];
}
return false;
}

/**
* Get database platform name
*
Expand Down
Loading