Skip to content
18 changes: 9 additions & 9 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
tools: "cs2pr"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
tools: "cs2pr"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -109,7 +109,7 @@ jobs:
tools: "cs2pr"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -161,7 +161,7 @@ jobs:
coverage: "pcov"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -208,7 +208,7 @@ jobs:
coverage: "pcov"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -254,7 +254,7 @@ jobs:
coverage: "pcov"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -305,7 +305,7 @@ jobs:
coverage: "pcov"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -352,7 +352,7 @@ jobs:
coverage: "pcov"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down Expand Up @@ -403,7 +403,7 @@ jobs:
coverage: "pcov"

- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
uses: "actions/cache@v4"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down
5 changes: 1 addition & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"doctrine/annotations": "^1.10",
"laminas/laminas-code": "^4.7",
"psr/container": "^1 || ^2",
"brain-diminished/schema-version-control": "dev-master",
"brain-diminished/schema-version-control": "^1.0.5",
"ext-PDO": "*",
"ext-json": "*",
"ext-hash": "*",
Expand All @@ -54,9 +54,6 @@
"bamarni/composer-bin-plugin": "^1.4.1",
"phpbench/phpbench": "^1.1"
},
"conflict": {
"mouf/database.tdbm": "~5.0.0"
},
"autoload" : {
"psr-4" : {
"TheCodingMachine\\TDBM\\" : "src/"
Expand Down
7 changes: 7 additions & 0 deletions src/EmptyResultIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace TheCodingMachine\TDBM;

class EmptyResultIterator extends ResultIterator
{
}
6 changes: 5 additions & 1 deletion src/InnerResultIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace TheCodingMachine\TDBM;

use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\ForwardCompatibility\Result;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Statement;
Expand Down Expand Up @@ -135,7 +136,7 @@ public function count()

if ($this->fetchStarted && $this->tdbmService->getConnection()->getDatabasePlatform() instanceof MySqlPlatform) {
// Optimisation: we don't need a separate "count" SQL request in MySQL.
assert($this->statement instanceof Statement);
assert($this->statement instanceof Statement || $this->statement instanceof Result);
$this->count = (int)$this->statement->rowCount();
return $this->count;
}
Expand Down Expand Up @@ -243,6 +244,9 @@ public function next(): void
$dbRow = $this->objectStorage->get($mainBeanTableName, $hash);
if ($dbRow !== null) {
$bean = $dbRow->getTDBMObject();
if ($bean->_getStatus() === TDBMObjectStateEnum::STATE_NOT_LOADED) {
$bean->_constructFromData($beanData, $this->tdbmService);
}
} else {
// Let's construct the bean
if (!isset($reflectionClassCache[$actualClassName])) {
Expand Down
8 changes: 8 additions & 0 deletions src/NativeWeakrefObjectStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ public function remove(string $tableName, $id): void
unset($this->objects[$tableName][$id]);
}

/**
* Removes all objects from the storage.
*/
public function clear(): void
{
$this->objects = array();
}

private function cleanupDanglingWeakRefs(): void
{
foreach ($this->objects as $tableName => $table) {
Expand Down
5 changes: 5 additions & 0 deletions src/ObjectStorageInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ public function get(string $tableName, $id): ?DbRow;
* @param string|int $id
*/
public function remove(string $tableName, $id): void;

/**
* Removes all objects from the storage.
*/
public function clear(): void;
}
2 changes: 1 addition & 1 deletion src/PageIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public static function createEmpyIterator(ResultIterator $parentResult): self
public function getIterator()
{
if ($this->innerResultIterator === null) {
if ($this->parentResult->count() === 0) {
if ($this->parentResult instanceof EmptyResultIterator) {
$this->innerResultIterator = new EmptyInnerResultIterator();
} elseif ($this->mode === TDBMService::MODE_CURSOR) {
$this->innerResultIterator = InnerResultIterator::createInnerResultIterator($this->magicSql, $this->parameters, $this->limit, $this->offset, $this->columnDescriptors, $this->objectStorage, $this->className, $this->tdbmService, $this->magicQuery, $this->logger);
Expand Down
31 changes: 26 additions & 5 deletions src/QueryFactory/FindObjectsFromRawSqlQueryFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Schema\Schema;
use PHPSQLParser\builders\OrderByBuilder;
use PHPSQLParser\builders\SelectStatementBuilder;
use TheCodingMachine\TDBM\TDBMException;
use TheCodingMachine\TDBM\TDBMService;
use PHPSQLParser\PHPSQLCreator;
Expand Down Expand Up @@ -106,7 +108,7 @@ private function compute(string $sql, ?string $sqlCount): array
* @param mixed[] $parsedSql
* @param null|string $sqlCount
* @return mixed[] An array of 3 elements: [$processedSql, $processedSqlCount, $columnDescriptors]
* @throws \PHPSQLParser\exceptions\UnsupportedFeatureException
* @throws \PHPSQLParser\exceptions\UnsupportedFeatureException|\PHPSQLParser\exceptions\UnableToCreateSQLException
*/
private function processParsedUnionQuery(array $parsedSql, ?string $sqlCount): array
{
Expand All @@ -120,9 +122,9 @@ private function processParsedUnionQuery(array $parsedSql, ?string $sqlCount): a

// Let's reparse the returned SQL (not the most efficient way of doing things)
$parser = new PHPSQLParser();
$parsedSql = $parser->parse($selectProcessedSql);
$parsedSelectSql = $parser->parse($selectProcessedSql);

$parsedSqlList[] = $parsedSql;
$parsedSqlList[] = $parsedSelectSql;
}

// Let's rebuild the UNION query
Expand All @@ -133,12 +135,31 @@ private function processParsedUnionQuery(array $parsedSql, ?string $sqlCount): a

$generator = new PHPSQLCreator();

$processedSql = $generator->create($query);
// Replaced the default generator by our own to add parenthesis around each SELECT
$processedSql = $this->buildUnion($query);
$processedSqlCount = $generator->create($countQuery);

// Let's add the ORDER BY if any
if (isset($parsedSql['0']['ORDER'])) {
$orderByBuilder = new OrderByBuilder();
$processedSql .= " " . $orderByBuilder->build($parsedSql['0']['ORDER']);
}

return [$processedSql, $sqlCount ?? $processedSqlCount, $columnDescriptors];
}

/**
* @param mixed[] $parsed
*/
private function buildUnion(array $parsed): string
{
$selectBuilder = new SelectStatementBuilder();

return implode(' UNION ', array_map(function ($clause) use ($selectBuilder) {
return '(' . $selectBuilder->build($clause) . ')';
}, $parsed['UNION']));
}

/**
* @param mixed[] $parsedSql
* @param null|string $sqlCount
Expand Down Expand Up @@ -382,7 +403,7 @@ private function generateGroupedSqlCount(array $parsedSql): array
$item['delim'] = ',';
$innerColumns[] = $item;
}
$innerColumns[count($innerColumns)-1]['delim'] = false;
$innerColumns[count($innerColumns) - 1]['delim'] = false;
$parsedSql['SELECT'] = $innerColumns;

$parsedSql = [
Expand Down
2 changes: 1 addition & 1 deletion src/ResultIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public function getIterator()
*/
public function take($offset, $limit)
{
if ($this->totalCount === 0) {
if ($this instanceof EmptyResultIterator) {
return PageIterator::createEmpyIterator($this);
}
return PageIterator::createResultIterator($this, $this->queryFactory->getMagicSql(), $this->parameters, $limit, $offset, $this->queryFactory->getColumnDescriptors(), $this->objectStorage, $this->className, $this->tdbmService, $this->magicQuery, $this->mode, $this->logger);
Expand Down
10 changes: 10 additions & 0 deletions src/TDBMService.php
Original file line number Diff line number Diff line change
Expand Up @@ -1559,4 +1559,14 @@ public function setLogLevel(string $level): void
{
$this->logger = new LevelFilter($this->rootLogger, $level);
}

/**
* Clear TDBM's bean cache
*
* This can be used in long-running processes to cleanup everything.
*/
public function clearBeanCache(): void
{
$this->objectStorage->clear();
}
}
4 changes: 2 additions & 2 deletions src/Utils/BeanDescriptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -1333,7 +1333,7 @@ private function generateFindByDaoCodeForIndex(Index $index, string $beanNamespa
$parameter = new ParameterGenerator(ltrim($element->getSafeVariableName(), '$'));
if (!$first && !($element->isCompulsory() && $index->isUnique())) {
$parameterType = '?';
//$functionParameter = '?';
//$functionParameter = '?';
} else {
$parameterType = '';
//$functionParameter = '';
Expand Down Expand Up @@ -1765,7 +1765,7 @@ private function generateGetForeignKeys(array $fks): MethodGenerator
* @param string $indent
* @return string
*/
private function psr2VarExport($var, string $indent=''): string
private function psr2VarExport($var, string $indent = ''): string
{
if (is_array($var)) {
$indexed = array_keys($var) === range(0, count($var) - 1);
Expand Down
2 changes: 2 additions & 0 deletions src/Utils/DbalUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public static function generateTypes(array $parameters): array
$types[$key] = Connection::PARAM_INT_ARRAY;
} elseif (is_int($value)) {
$types[$key] = ParameterType::INTEGER;
} elseif (is_bool($value)) {
$types[$key] = ParameterType::BOOLEAN;
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/AbstractTDBMObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function testEmptyResultIterator()

public function testEmptyPageIterator()
{
$a = ResultIterator::createEmpyIterator();
$a = EmptyResultIterator::createEmpyIterator();
$b = $a->take(0, 10);
foreach ($b as $empty) {
throw new \LogicException("Not supposed to iterate on an empty page iterator.");
Expand Down
8 changes: 8 additions & 0 deletions tests/Dao/TestCountryDao.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,12 @@ public function getCountriesUsingDistinctQuery()

return $this->findFromRawSql($sql);
}

/**
* @return CountryBean[]|Result
*/
public function findByIds(array $ids)
{
return $this->find('id IN (:ids)', ['ids' => $ids]);
}
}
1 change: 1 addition & 0 deletions tests/Dao/TestPersonDao.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
* This file has been automatically generated by TDBM.
* You can edit this file as it will not be overwritten.
Expand Down
2 changes: 1 addition & 1 deletion tests/NativeWeakrefObjectStorageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function testDanglingPointers(): void
$objectStorage = new NativeWeakrefObjectStorage();
$dbRow = $this->createMock(DbRow::class);

for ($i=0; $i<10001; $i++) {
for ($i = 0; $i < 10001; $i++) {
$objectStorage->set('foo', $i, clone $dbRow);
}
$this->assertNull($objectStorage->get('foo', 42));
Expand Down
6 changes: 3 additions & 3 deletions tests/Performance/ManyToOneBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,18 @@ private static function initSchema(Connection $connection): void
$connection->exec($sqlStmt);
}

for ($i = 1; $i<200; $i++) {
for ($i = 1; $i < 200; $i++) {
TDBMAbstractServiceTest::insert($connection, 'countries', [
'id' => $i,
'label' => 'Country '.$i,
]);
}

for ($i = 1; $i<1000; $i++) {
for ($i = 1; $i < 1000; $i++) {
TDBMAbstractServiceTest::insert($connection, 'users', [
'id' => $i,
'name' => 'User '.$i,
'country_id' => ($i%199) +1,
'country_id' => ($i % 199) + 1,
]);
}
}
Expand Down
8 changes: 4 additions & 4 deletions tests/TDBMAbstractServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ private static function initSchema(Connection $connection): void
->column('manager_id')->references('contact')->null();

$db->table('users')
->addAnnotation('AddTrait', ['name'=>TestUserTrait::class], false)
->addAnnotation('AddTrait', ['name'=>TestOtherUserTrait::class, 'modifiers'=>['\\'.TestOtherUserTrait::class.'::method1 insteadof \\'.TestUserTrait::class, '\\'.TestUserTrait::class.'::method1 as method1renamed']], false)
->addAnnotation('AddTraitOnDao', ['name'=>TestUserDaoTrait::class], false)
->addAnnotation('AddTrait', ['name' => TestUserTrait::class], false)
->addAnnotation('AddTrait', ['name' => TestOtherUserTrait::class, 'modifiers' => ['\\'.TestOtherUserTrait::class.'::method1 insteadof \\'.TestUserTrait::class, '\\'.TestUserTrait::class.'::method1 as method1renamed']], false)
->addAnnotation('AddTraitOnDao', ['name' => TestUserDaoTrait::class], false)
->implementsInterface(TestUserInterface::class)
->implementsInterfaceOnDao(TestUserDaoInterface::class)
->extends('contact')
Expand Down Expand Up @@ -721,7 +721,7 @@ private static function initSchema(Connection $connection): void

self::insert($connection, 'tracks', [
'album_id' => 1,
'title' =>'Pigs on the Wing 1',
'title' => 'Pigs on the Wing 1',
// Note: Oracle does not have a TIME column type
'duration' => $timeType->convertToDatabaseValue(new DateTimeImmutable('1970-01-01 00:01:25'), $connection->getDatabasePlatform()),
]);
Expand Down
Loading