Skip to content
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
2 changes: 2 additions & 0 deletions src/Adapter/Driver/Pdo/AbstractPdo.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ public function getProfiler(): ?ProfilerInterface
public function checkEnvironment(): bool
{
if (! extension_loaded('PDO')) {
// @codeCoverageIgnoreStart
throw new Exception\RuntimeException(
'The PDO extension is required for this adapter but the extension is not loaded'
);
// @codeCoverageIgnoreEnd
}
return true;
}
Expand Down
21 changes: 4 additions & 17 deletions src/ResultSet/AbstractResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use function gettype;
use function is_array;
use function is_object;
use function key;
use function method_exists;
use function reset;

Expand Down Expand Up @@ -80,12 +79,9 @@ public function initialize(iterable $dataSource): ResultSetInterface
} elseif ($dataSource instanceof IteratorAggregate) {
/** @phpstan-ignore assign.propertyType */
$this->dataSource = $dataSource->getIterator();
} elseif ($dataSource instanceof Iterator) {
$this->dataSource = $dataSource;
} else {
throw new InvalidArgumentException(
'DataSource provided is not an array, nor does it implement Iterator or IteratorAggregate'
);
/** @phpstan-ignore assign.propertyType */
$this->dataSource = $dataSource;
}

return $this;
Expand Down Expand Up @@ -214,12 +210,7 @@ public function valid(): bool
return true;
}

if ($this->dataSource instanceof Iterator) {
return $this->dataSource->valid();
} else {
$key = key($this->dataSource);
return $key !== null;
}
return $this->dataSource->valid();
}

/**
Expand All @@ -229,11 +220,7 @@ public function valid(): bool
public function rewind(): void
{
if (! is_array($this->buffer)) {
if ($this->dataSource instanceof Iterator) {
$this->dataSource->rewind();
} else {
reset($this->dataSource);
}
$this->dataSource->rewind();
}

$this->position = 0;
Expand Down
51 changes: 1 addition & 50 deletions src/Sql/AbstractSql.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,8 @@
use function count;
use function current;
use function get_object_vars;
use function gettype;
use function implode;
use function is_array;
use function is_callable;
use function is_object;
use function is_string;
use function key;
use function rtrim;
Expand Down Expand Up @@ -151,14 +148,6 @@ protected function processExpression(
: $platform->quoteValue((string) $argument->getValue()),
$argument instanceof Identifier => $platform->quoteIdentifierInFragment($argument->getValue()),
$argument instanceof Literal => $argument->getValue(),
$argument instanceof Values => $this->processValuesArgument(
$argument,
$expressionParamIndex,
$namedParameterPrefix,
$platform,
$driver,
$parameterContainer
),
$argument instanceof Identifiers => $this->processIdentifiersArgument($argument, $platform),
$argument instanceof SelectArgument => $this->processExpressionOrSelect(
$argument,
Expand Down Expand Up @@ -234,36 +223,6 @@ protected function processExpressionOrSelect(
};
}

protected function processValuesArgument(
ArgumentInterface $argument,
int &$expressionParamIndex,
string $namedParameterPrefix,
PlatformInterface $platform,
?DriverInterface $driver = null,
?ParameterContainer $parameterContainer = null
): string {
$values = $argument->getValue();
$processedValues = [];

if ($parameterContainer instanceof ParameterContainer) {
foreach ($values as $value) {
$processedValues[] = $this->processExpressionParameterName(
$value,
$namedParameterPrefix,
$expressionParamIndex,
$driver,
$parameterContainer
);
}
} else {
foreach ($values as $value) {
$processedValues[] = $platform->quoteValue((string) $value);
}
}

return implode(', ', $processedValues);
}

protected function processIdentifiersArgument(
ArgumentInterface $argument,
PlatformInterface $platform
Expand Down Expand Up @@ -419,13 +378,8 @@ protected function processJoin(
: '') . $platform->quoteIdentifier($joinName[0]);
} elseif ($joinName instanceof Select) {
$joinName = '(' . $this->processSubSelect($joinName, $platform, $driver, $parameterContainer) . ')';
} elseif (is_string($joinName) || (is_object($joinName) && is_callable([$joinName, '__toString']))) {
$joinName = $platform->quoteIdentifier($joinName);
} else {
throw new Exception\InvalidArgumentException(sprintf(
'Join name expected to be Expression|TableIdentifier|Select|string, "%s" given',
gettype($joinName)
));
$joinName = $platform->quoteIdentifier($joinName);
}

$joinSpecArgArray[$j] = [
Expand Down Expand Up @@ -511,9 +465,6 @@ protected function resolveTable(
return $table;
}

/**
* Copy variables from the subject into the local properties
*/
protected function localizeVariables(): void
{
if (! $this instanceof PlatformDecoratorInterface) {
Expand Down
19 changes: 7 additions & 12 deletions test/unit/Adapter/AdapterAwareTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,21 @@

use PhpDb\Adapter\Adapter;
use PhpDb\Adapter\AdapterAwareTrait;
use PhpDb\Adapter\AdapterInterface;
use PhpDb\Adapter\Driver\DriverInterface;
use PhpDb\Adapter\Platform\PlatformInterface;
use PhpDbTest\Adapter\TestAsset\ConcreteAdapterAwareObject;
use PHPUnit\Framework\Attributes\CoversMethod;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use ReflectionProperty;

#[CoversMethod(AdapterAwareTrait::class, 'setDbAdapter')]
#[Group('unit')]
class AdapterAwareTraitTest extends TestCase
{
public function testSetDbAdapter(): void
{
$object = new class {
use AdapterAwareTrait;

public function getAdapter(): ?AdapterInterface
{
return $this->adapter ?? null;
}
};
$object = new ConcreteAdapterAwareObject();

self::assertNull($object->getAdapter());

Expand All @@ -39,9 +36,7 @@ public function getAdapter(): ?AdapterInterface

public function testSetDbAdapterSetsProperty(): void
{
$object = new class {
use AdapterAwareTrait;
};
$object = new ConcreteAdapterAwareObject();

$driver = $this->createMock(DriverInterface::class);
$platform = $this->createMock(PlatformInterface::class);
Expand Down
114 changes: 102 additions & 12 deletions test/unit/Adapter/AdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use PhpDb\Adapter\Driver\DriverInterface;
use PhpDb\Adapter\Driver\ResultInterface;
use PhpDb\Adapter\Driver\StatementInterface;
use PhpDb\Adapter\Exception\InvalidArgumentException;
use PhpDb\Adapter\Exception\VunerablePlatformQuoteException;
use PhpDb\Adapter\ParameterContainer;
use PhpDb\Adapter\Platform\PlatformInterface;
use PhpDb\Adapter\Profiler;
Expand All @@ -26,15 +28,16 @@

#[CoversMethod(Adapter::class, 'setProfiler')]
#[CoversMethod(Adapter::class, 'getProfiler')]
#[CoversMethod(Adapter::class, 'createDriver')]
#[CoversMethod(Adapter::class, 'createPlatform')]
#[CoversMethod(Adapter::class, 'getDriver')]
#[CoversMethod(Adapter::class, 'getPlatform')]
#[CoversMethod(Adapter::class, 'getQueryResultSetPrototype')]
#[CoversMethod(Adapter::class, 'getCurrentSchema')]
#[CoversMethod(Adapter::class, 'query')]
#[CoversMethod(Adapter::class, 'createStatement')]
#[CoversMethod(Adapter::class, '__get')]
#[CoversMethod(Adapter::class, '__construct')]
#[CoversMethod(Adapter::class, 'getHelpers')]
#[Group('unit')]
final class AdapterTest extends TestCase
{
protected DriverInterface&MockObject $mockDriver;
Expand Down Expand Up @@ -67,14 +70,14 @@ protected function setUp(): void
}

#[TestDox('unit test: Test setProfiler() will store profiler')]
public function testSetProfiler(): void
public function testFluentSetProfiler(): void
{
$ret = $this->adapter->setProfiler(new Profiler\Profiler());
self::assertSame($this->adapter, $ret);
}

#[TestDox('unit test: Test getProfiler() will store profiler')]
public function testGetProfiler(): void
public function testGetProfilerReturnsProfiler(): void
{
$this->adapter->setProfiler($profiler = new Profiler\Profiler());
self::assertSame($profiler, $this->adapter->getProfiler());
Expand All @@ -88,25 +91,25 @@ public function testGetProfiler(): void
}

#[TestDox('unit test: Test getDriver() will return driver object')]
public function testGetDriver(): void
public function testGetDriverReturnsDriver(): void
{
self::assertSame($this->mockDriver, $this->adapter->getDriver());
}

#[TestDox('unit test: Test getPlatform() returns platform object')]
public function testGetPlatform(): void
public function testGetPlatformReturnsPlatform(): void
{
self::assertSame($this->mockPlatform, $this->adapter->getPlatform());
}

#[TestDox('unit test: Test getPlatform() returns platform object')]
public function testGetQueryResultSetPrototype(): void
public function testGetQueryResultSetPrototypeReturnsResultSet(): void
{
self::assertInstanceOf(ResultSetInterface::class, $this->adapter->getQueryResultSetPrototype());
}

#[TestDox('unit test: Test getCurrentSchema() returns current schema from connection object')]
public function testGetCurrentSchema(): void
public function testGetCurrentSchemaDelegatesToConnection(): void
{
$this->mockConnection->expects($this->any())->method('getCurrentSchema')->willReturn('FooSchema');
self::assertEquals('FooSchema', $this->adapter->getCurrentSchema());
Expand Down Expand Up @@ -215,15 +218,13 @@ public function testQueryWhenExecutedProducesAResultSetObjectWhenResultIsQuery()
}

#[TestDox('unit test: Test createStatement() produces a statement object')]
public function testCreateStatement(): void
public function testCreateStatementDelegatesToDriver(): void
{
self::assertSame($this->mockStatement, $this->adapter->createStatement());
}

// @codingStandardsIgnoreStart
public function test__get(): void
public function testMagicGetReturnsDriverAndPlatformCaseInsensitively(): void
{
// @codingStandardsIgnoreEnd
self::assertSame($this->mockDriver, $this->adapter->driver);
/** @phpstan-ignore property.notFound */
self::assertSame($this->mockDriver, $this->adapter->DrivER);
Expand All @@ -236,4 +237,93 @@ public function test__get(): void
/** @phpstan-ignore property.notFound, expr.resultUnused */
$this->adapter->foo;
}

public function testGetHelpersReturnsQuoteIdentifierFunction(): void
{
$functions = $this->adapter->getHelpers(Adapter::FUNCTION_QUOTE_IDENTIFIER);

self::assertCount(1, $functions);
self::assertIsCallable($functions[0]);
}

public function testGetHelpersReturnsQuoteValueFunction(): void
{
$functions = $this->adapter->getHelpers(Adapter::FUNCTION_QUOTE_VALUE);

self::assertCount(1, $functions);
self::assertIsCallable($functions[0]);
}

public function testGetHelpersReturnsBothFunctions(): void
{
$functions = $this->adapter->getHelpers(
Adapter::FUNCTION_QUOTE_IDENTIFIER,
Adapter::FUNCTION_QUOTE_VALUE
);

self::assertCount(2, $functions);
self::assertIsCallable($functions[0]);
self::assertIsCallable($functions[1]);
}

public function testConstructorWithProfilerDelegatesToSetProfiler(): void
{
$profilerMock = $this->createMock(Profiler\ProfilerInterface::class);
$driverMock = $this->createMock(DriverInterface::class);
$platformMock = $this->createMock(PlatformInterface::class);

$adapter = new Adapter(
driver: $driverMock,
platform: $platformMock,
profiler: $profilerMock,
);

self::assertSame($profilerMock, $adapter->getProfiler());
}

public function testQueryThrowsOnInvalidParameterType(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Parameter 2 to this method must be a flag, an array, or ParameterContainer');

$this->adapter->query('SELECT 1', 'invalid_mode');
}

public function testSetProfilerDelegatesToDriverWhenProfilerAware(): void
{
$profiler = $this->createMock(Profiler\ProfilerInterface::class);
$driver = $this->createMockForIntersectionOfInterfaces(
[DriverInterface::class, Profiler\ProfilerAwareInterface::class]
);
$driver->expects($this->once())->method('setProfiler')->with($profiler);

$platform = $this->createMock(PlatformInterface::class);
$adapter = new Adapter(driver: $driver, platform: $platform);

$adapter->setProfiler($profiler);
}

public function testGetHelpersQuoteIdentifierClosureCallsPlatform(): void
{
$this->mockPlatform->method('quoteIdentifier')
->with('test')
->willReturn('"test"');

$functions = $this->adapter->getHelpers(Adapter::FUNCTION_QUOTE_IDENTIFIER);
$result = $functions[0]('test');

self::assertSame('"test"', $result);
}

public function testGetHelpersQuoteValueClosureCallsPlatform(): void
{
$this->mockPlatform->method('quoteValue')
->with('test')
->willThrowException(VunerablePlatformQuoteException::forPlatformAndMethod('test', 'test'));

$functions = $this->adapter->getHelpers(Adapter::FUNCTION_QUOTE_VALUE);

$this->expectException(VunerablePlatformQuoteException::class);
$functions[0]('test');
}
}
Loading