Skip to content

Commit

Permalink
PHP_CodeSniffer fixes and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zoilomora committed Nov 25, 2020
1 parent ae819d9 commit 02c858b
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 61 deletions.
31 changes: 17 additions & 14 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
<?xml version="1.0" ?>
<ruleset name="Project rules">
<file>src</file>
<file>tests</file>
<rule ref="vendor/pccomponentes/coding-standard/src/ruleset.xml">
<exclude name="PSR2.Methods.MethodDeclaration.Underscore" />
<exclude name="SlevomatCodingStandard.PHP.DisallowReference.DisallowedPassingByReference" />
<exclude name="SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing.IncorrectLinesCountAfterControlStructure" />
<exclude name="SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing.IncorrectLinesCountBeforeControlStructure" />
</rule>
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
<exclude-pattern>tests/*</exclude-pattern>
</rule>
</ruleset>
<?xml version="1.0" ?>
<ruleset name="Project rules">
<file>src</file>
<file>tests</file>
<rule ref="vendor/pccomponentes/coding-standard/src/ruleset.xml">
<exclude name="PSR2.Methods.MethodDeclaration.Underscore" />
<exclude name="SlevomatCodingStandard.PHP.DisallowReference.DisallowedPassingByReference" />
<exclude name="SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing.IncorrectLinesCountAfterControlStructure" />
<exclude name="SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing.IncorrectLinesCountBeforeControlStructure" />
</rule>
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
<exclude-pattern>tests/*</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.Operators.RequireOnlyStandaloneIncrementAndDecrementOperators.PostDecrementOperatorNotUsedStandalone">
<exclude-pattern>src/Doctrine/DBAL/Platforms/MicrosoftAccessPlatform.php</exclude-pattern>
</rule>
</ruleset>
77 changes: 30 additions & 47 deletions src/Doctrine/DBAL/Platforms/MicrosoftAccessPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

final class MicrosoftAccessPlatform extends SQLServer2012Platform
{
/**
* {@inheritDoc}
*/
public function getName(): string
{
return 'msaccess';
Expand Down Expand Up @@ -77,9 +74,6 @@ protected function initializeDoctrineTypeMappings()
];
}

/**
* {@inheritDoc}
*/
protected function getReservedKeywordsClass(): string
{
return MicrosoftAccessKeywords::class;
Expand All @@ -88,73 +82,66 @@ protected function getReservedKeywordsClass(): string
/**
* {@inheritDoc}
*
* @see https://github.com/doctrine/dbal/blob/2.12.x/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php#L1285
* @see \Doctrine\DBAL\Platforms\SQLServerPlatform::doModifyLimitQuery
*/
protected function doModifyLimitQuery($query, $limit, $offset = null)
{
$where = [];

if ($offset > 0) {
$where[] = sprintf('doctrine_rownum >= %d', $offset + 1);
$where[] = \sprintf('doctrine_rownum >= %d', $offset + 1);
}

if ($limit !== null) {
$where[] = sprintf('doctrine_rownum <= %d', $offset + $limit);
$top = sprintf('TOP %d', $offset + $limit);
if (null !== $limit) {
$where[] = \sprintf('doctrine_rownum <= %d', $offset + $limit);
$top = \sprintf('TOP %d', $offset + $limit);
} else {
$top = 'TOP 9223372036854775807';
}

if (empty($where)) {
if (0 === \count($where)) {
return $query;
}

// We'll find a SELECT or SELECT distinct and prepend TOP n to it
// Even if the TOP n is very large, the use of a CTE will
// allow the SQL Server query planner to optimize it so it doesn't
// actually scan the entire range covered by the TOP clause.
if (!preg_match('/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/is', $query, $matches)) {
if (!\preg_match('/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/is', $query, $matches)) {
return $query;
}

$query = $matches[1] . $top . ' ' . $matches[2];

if (stristr($query, 'ORDER BY')) {
// Inner order by is not valid in SQL Server for our purposes
// unless it's in a TOP N subquery.
if (\stristr($query, 'ORDER BY')) {
$query = $this->scrubInnerOrderBy($query);
}

return $query;
}

/**
* Remove ORDER BY clauses in sub queries - they're not supported by MS Access.
* Caveat: will leave ORDER BY in TOP N sub queries.
*
* @param string $query
* {@inheritDoc}
*
* @return string
* @see \Doctrine\DBAL\Platforms\SQLServerPlatform::scrubInnerOrderBy
*/
private function scrubInnerOrderBy(string $query)
private function scrubInnerOrderBy(string $query): string
{
$count = substr_count(strtoupper($query), 'ORDER BY');
$count = \substr_count(\strtoupper($query), 'ORDER BY');
$offset = 0;

while ($count-- > 0) {
$orderByPos = stripos($query, ' ORDER BY', $offset);
if ($orderByPos === false) {
$orderByPos = \stripos($query, ' ORDER BY', $offset);
if (false === $orderByPos) {
break;
}

$qLen = strlen($query);
$qLen = \strlen($query);
$parenCount = 0;
$currentPosition = $orderByPos;

while ($parenCount >= 0 && $currentPosition < $qLen) {
if ($query[$currentPosition] === '(') {
if ('(' === $query[$currentPosition]) {
$parenCount++;
} elseif ($query[$currentPosition] === ')') {
}

if (')' === $query[$currentPosition]) {
$parenCount--;
}

Expand All @@ -165,49 +152,45 @@ private function scrubInnerOrderBy(string $query)
// If the order by clause is in a TOP N subquery, do not remove
// it and continue iteration from the current position.
$offset = $currentPosition;

continue;
}

if ($currentPosition >= $qLen - 1) {
continue;
}

$query = substr($query, 0, $orderByPos) . substr($query, $currentPosition - 1);
$query = \substr($query, 0, $orderByPos) . \substr($query, $currentPosition - 1);
$offset = $orderByPos;
}

return $query;
}

/**
* Check an ORDER BY clause to see if it is in a TOP N query or sub query.
*
* @param string $query The query
* @param int $currentPosition Start position of ORDER BY clause
* {@inheritDoc}
*
* @return bool true if ORDER BY is in a TOP N query, false otherwise
* @see \Doctrine\DBAL\Platforms\SQLServerPlatform::isOrderByInTopNSubquery
*/
private function isOrderByInTopNSubquery(string $query, int $currentPosition)
private function isOrderByInTopNSubquery(string $query, int $currentPosition): bool
{
// Grab query text on the same nesting level as the ORDER BY clause we're examining.
$subQueryBuffer = '';
$parenCount = 0;

// If $parenCount goes negative, we've exited the subquery we're examining.
// If $currentPosition goes negative, we've reached the beginning of the query.
while ($parenCount >= 0 && $currentPosition >= 0) {
if ($query[$currentPosition] === '(') {
if ('(' === $query[$currentPosition]) {
$parenCount--;
} elseif ($query[$currentPosition] === ')') {
}

if (')' === $query[$currentPosition]) {
$parenCount++;
}

// Only yank query text on the same nesting level as the ORDER BY clause.
$subQueryBuffer = ($parenCount === 0 ? $query[$currentPosition] : ' ') . $subQueryBuffer;
$subQueryBuffer = (0 === $parenCount ? $query[$currentPosition] : ' ') . $subQueryBuffer;

$currentPosition--;
}

return (bool)preg_match('/SELECT\s+(DISTINCT\s+)?TOP\s/i', $subQueryBuffer);
return (bool)\preg_match('/SELECT\s+(DISTINCT\s+)?TOP\s/i', $subQueryBuffer);
}
}
30 changes: 30 additions & 0 deletions tests/Doctrine/DBAL/Platforms/MicrosoftAccessPlatformTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

namespace ZoiloMora\Tests\Doctrine\DBAL\Platforms;

use Doctrine\DBAL\Connection;
use ZoiloMora\Tests\BaseTest;

class MicrosoftAccessPlatformTest extends BaseTest
{
private const TABLE_NAME = 'Table1';

/**
* @test
* @dataProvider connections
*/
public function given_an_connection_when_get_the_first_two_rows_then_returns_array_with_two_rows(Connection $connection)
{
$result = $connection->createQueryBuilder()
->select('*')
->from(self::TABLE_NAME)
->setMaxResults(2)
->execute();

$rows = $result->fetchAllAssociative();

$this->assertIsArray($rows);
$this->assertCount(2, $rows);
}
}

0 comments on commit 02c858b

Please sign in to comment.