Skip to content

Commit 555d6a9

Browse files
committed
create empty resultIterator
1 parent 42e2f4f commit 555d6a9

File tree

6 files changed

+129
-30
lines changed

6 files changed

+129
-30
lines changed

src/InnerResultArray.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class InnerResultArray extends InnerResultIterator
5353
*/
5454
public function offsetExists($offset)
5555
{
56+
if ($this->count === 0) {
57+
return false;
58+
}
5659
try {
5760
$this->toIndex($offset);
5861
} catch (TDBMInvalidOffsetException $e) {
@@ -122,6 +125,9 @@ public function next()
122125
*/
123126
public function rewind()
124127
{
128+
if ($this->count === 0) {
129+
return;
130+
}
125131
if (!$this->fetchStarted) {
126132
$this->executeQuery();
127133
}

src/InnerResultIterator.php

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\DBAL\Statement;
88
use Mouf\Database\MagicQuery;
99
use Psr\Log\LoggerInterface;
10+
use Psr\Log\NullLogger;
1011
use TheCodingMachine\TDBM\Utils\DbalUtils;
1112

1213
/*
@@ -65,23 +66,29 @@ class InnerResultIterator implements \Iterator, \Countable, \ArrayAccess
6566
*/
6667
private $logger;
6768

69+
protected $count = null;
70+
6871
/**
6972
* @param mixed[] $parameters
7073
* @param array[] $columnDescriptors
7174
*/
72-
public function __construct(string $magicSql, array $parameters, ?int $limit, ?int $offset, array $columnDescriptors, ObjectStorageInterface $objectStorage, ?string $className, TDBMService $tdbmService, MagicQuery $magicQuery, LoggerInterface $logger)
75+
public function __construct(?string $magicSql, ?array $parameters, ?int $limit, ?int $offset, ?array $columnDescriptors, ?ObjectStorageInterface $objectStorage, ?string $className, ?TDBMService $tdbmService, ?MagicQuery $magicQuery, ?LoggerInterface $logger)
7376
{
74-
$this->magicSql = $magicSql;
75-
$this->objectStorage = $objectStorage;
76-
$this->className = $className;
77-
$this->tdbmService = $tdbmService;
78-
$this->parameters = $parameters;
79-
$this->limit = $limit;
80-
$this->offset = $offset;
81-
$this->columnDescriptors = $columnDescriptors;
82-
$this->magicQuery = $magicQuery;
83-
$this->databasePlatform = $this->tdbmService->getConnection()->getDatabasePlatform();
84-
$this->logger = $logger;
77+
if (!$magicSql) {
78+
$this->count = 0;
79+
} else {
80+
$this->magicSql = $magicSql;
81+
$this->objectStorage = $objectStorage;
82+
$this->className = $className;
83+
$this->tdbmService = $tdbmService;
84+
$this->parameters = $parameters;
85+
$this->limit = $limit;
86+
$this->offset = $offset;
87+
$this->columnDescriptors = $columnDescriptors;
88+
$this->magicQuery = $magicQuery;
89+
$this->databasePlatform = $this->tdbmService ? $this->tdbmService->getConnection()->getDatabasePlatform() : null;
90+
}
91+
$this->logger = $logger ?? new NullLogger();
8592
}
8693

8794
private function getQuery(): string
@@ -102,7 +109,6 @@ protected function executeQuery(): void
102109
$this->fetchStarted = true;
103110
}
104111

105-
private $count = null;
106112
/**
107113
* Counts found records (this is the number of records fetched, taking into account the LIMIT and OFFSET settings).
108114
*
@@ -242,6 +248,9 @@ public function next()
242248
*/
243249
public function rewind()
244250
{
251+
if ($this->count === 0) {
252+
return;
253+
}
245254
$this->executeQuery();
246255
$this->key = -1;
247256
$this->next();
@@ -253,6 +262,9 @@ public function rewind()
253262
*/
254263
public function valid()
255264
{
265+
if ($this->count === 0) {
266+
return false;
267+
}
256268
return $this->current !== null;
257269
}
258270

@@ -311,7 +323,7 @@ public function offsetGet($offset)
311323
*/
312324
public function offsetSet($offset, $value)
313325
{
314-
throw new TDBMInvalidOperationException('You can set values in a TDBM result set.');
326+
throw new TDBMInvalidOperationException('You cannot set values in a TDBM result set.');
315327
}
316328

317329
/**
@@ -327,6 +339,6 @@ public function offsetSet($offset, $value)
327339
*/
328340
public function offsetUnset($offset)
329341
{
330-
throw new TDBMInvalidOperationException('You can unset values in a TDBM result set.');
342+
throw new TDBMInvalidOperationException('You cannot unset values in a TDBM result set.');
331343
}
332344
}

src/MapIterator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function __construct($iterator, callable $callable)
5555
* Alters the current item with $this->callable and returns a new item.
5656
* Be careful with your types as we can't do static type checking here!
5757
*
58-
* @return mixed
58+
* @return mixed|null
5959
*/
6060
public function current()
6161
{

src/PageIterator.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Mouf\Database\MagicQuery;
88
use Porpaginas\Page;
99
use Psr\Log\LoggerInterface;
10+
use Psr\Log\NullLogger;
1011

1112
/*
1213
Copyright (C) 2006-2017 David Négrier - THE CODING MACHINE
@@ -71,7 +72,7 @@ class PageIterator implements Page, \ArrayAccess, \JsonSerializable
7172
* @param mixed[] $parameters
7273
* @param array[] $columnDescriptors
7374
*/
74-
public function __construct(ResultIterator $parentResult, string $magicSql, array $parameters, int $limit, int $offset, array $columnDescriptors, ObjectStorageInterface $objectStorage, ?string $className, TDBMService $tdbmService, MagicQuery $magicQuery, int $mode, LoggerInterface $logger)
75+
public function __construct(ResultIterator $parentResult, ?string $magicSql, array $parameters, ?int $limit, ?int $offset, ?array $columnDescriptors, ?ObjectStorageInterface $objectStorage, ?string $className, ?TDBMService $tdbmService, ?MagicQuery $magicQuery, ?int $mode, ?LoggerInterface $logger)
7576
{
7677
$this->parentResult = $parentResult;
7778
$this->magicSql = $magicSql;
@@ -84,7 +85,7 @@ public function __construct(ResultIterator $parentResult, string $magicSql, arra
8485
$this->columnDescriptors = $columnDescriptors;
8586
$this->magicQuery = $magicQuery;
8687
$this->mode = $mode;
87-
$this->logger = $logger;
88+
$this->logger = $logger ?? new NullLogger();
8889
}
8990

9091
/**
@@ -100,7 +101,9 @@ public function __construct(ResultIterator $parentResult, string $magicSql, arra
100101
public function getIterator()
101102
{
102103
if ($this->innerResultIterator === null) {
103-
if ($this->mode === TDBMService::MODE_CURSOR) {
104+
if ($this->parentResult->count() === 0) {
105+
$this->innerResultIterator = new InnerResultIterator(null, null, null, null, null, null, null, null, null, null);
106+
} elseif ($this->mode === TDBMService::MODE_CURSOR) {
104107
$this->innerResultIterator = new InnerResultIterator($this->magicSql, $this->parameters, $this->limit, $this->offset, $this->columnDescriptors, $this->objectStorage, $this->className, $this->tdbmService, $this->magicQuery, $this->logger);
105108
} else {
106109
$this->innerResultIterator = new InnerResultArray($this->magicSql, $this->parameters, $this->limit, $this->offset, $this->columnDescriptors, $this->objectStorage, $this->className, $this->tdbmService, $this->magicQuery, $this->logger);
@@ -173,6 +176,9 @@ public function toArray(): array
173176
*/
174177
public function map(callable $callable): MapIterator
175178
{
179+
if ($this->count() === 0) {
180+
return new MapIterator([], $callable);
181+
}
176182
return new MapIterator($this->getIterator(), $callable);
177183
}
178184

src/ResultIterator.php

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace TheCodingMachine\TDBM;
55

6+
use Psr\Log\NullLogger;
67
use function array_map;
78
use Doctrine\DBAL\Connection;
89
use Doctrine\DBAL\Statement;
@@ -69,20 +70,29 @@ class ResultIterator implements Result, \ArrayAccess, \JsonSerializable
6970
/**
7071
* @param mixed[] $parameters
7172
*/
72-
public function __construct(QueryFactory $queryFactory, array $parameters, ObjectStorageInterface $objectStorage, ?string $className, TDBMService $tdbmService, MagicQuery $magicQuery, int $mode, LoggerInterface $logger)
73+
public function __construct(?QueryFactory $queryFactory, ?array $parameters, ?ObjectStorageInterface $objectStorage, ?string $className, ?TDBMService $tdbmService, ?MagicQuery $magicQuery, int $mode, ?LoggerInterface $logger)
7374
{
7475
if ($mode !== TDBMService::MODE_CURSOR && $mode !== TDBMService::MODE_ARRAY) {
7576
throw new TDBMException("Unknown fetch mode: '".$mode."'");
7677
}
7778

78-
$this->queryFactory = $queryFactory;
79-
$this->objectStorage = $objectStorage;
80-
$this->className = $className;
81-
$this->tdbmService = $tdbmService;
82-
$this->parameters = $parameters;
83-
$this->magicQuery = $magicQuery;
84-
$this->mode = $mode;
85-
$this->logger = $logger;
79+
if (!$queryFactory) {
80+
$this->totalCount = 0;
81+
} else {
82+
$this->queryFactory = $queryFactory;
83+
$this->objectStorage = $objectStorage;
84+
$this->className = $className;
85+
$this->tdbmService = $tdbmService;
86+
$this->parameters = $parameters;
87+
$this->magicQuery = $magicQuery;
88+
$this->mode = $mode;
89+
}
90+
$this->logger = $logger ?? new NullLogger();
91+
}
92+
93+
public static function createEmpyIterator(): self
94+
{
95+
return new self(null, null, null, null, null, null, TDBMService::MODE_ARRAY, null);
8696
}
8797

8898
protected function executeCountQuery(): void
@@ -113,6 +123,9 @@ public function count(): int
113123
*/
114124
public function toArray(): array
115125
{
126+
if ($this->totalCount === 0) {
127+
return [];
128+
}
116129
return iterator_to_array($this->getIterator());
117130
}
118131

@@ -125,6 +138,9 @@ public function toArray(): array
125138
*/
126139
public function map(callable $callable): MapIterator
127140
{
141+
if ($this->totalCount === 0) {
142+
return new MapIterator([], $callable);
143+
}
128144
return new MapIterator($this->getIterator(), $callable);
129145
}
130146

@@ -141,7 +157,9 @@ public function map(callable $callable): MapIterator
141157
public function getIterator()
142158
{
143159
if ($this->innerResultIterator === null) {
144-
if ($this->mode === TDBMService::MODE_CURSOR) {
160+
if ($this->totalCount === 0) {
161+
$this->innerResultIterator = new InnerResultArray(null, null, null, null, null, null, null, null, null, null);
162+
} elseif ($this->mode === TDBMService::MODE_CURSOR) {
145163
$this->innerResultIterator = new InnerResultIterator($this->queryFactory->getMagicSql(), $this->parameters, null, null, $this->queryFactory->getColumnDescriptors(), $this->objectStorage, $this->className, $this->tdbmService, $this->magicQuery, $this->logger);
146164
} else {
147165
$this->innerResultIterator = new InnerResultArray($this->queryFactory->getMagicSql(), $this->parameters, null, null, $this->queryFactory->getColumnDescriptors(), $this->objectStorage, $this->className, $this->tdbmService, $this->magicQuery, $this->logger);
@@ -159,6 +177,9 @@ public function getIterator()
159177
*/
160178
public function take($offset, $limit)
161179
{
180+
if ($this->totalCount === 0) {
181+
return new PageIterator($this, null, [], null, null, null, null, null, null, null, null, null);
182+
}
162183
return new PageIterator($this, $this->queryFactory->getMagicSql(), $this->parameters, $limit, $offset, $this->queryFactory->getColumnDescriptors(), $this->objectStorage, $this->className, $this->tdbmService, $this->magicQuery, $this->mode, $this->logger);
163184
}
164185

@@ -265,12 +286,15 @@ public function jsonSerialize($stopRecursion = false)
265286
*/
266287
public function first()
267288
{
289+
if ($this->totalCount === 0) {
290+
return null;
291+
}
268292
$page = $this->take(0, 1);
269293
foreach ($page as $bean) {
270294
return $bean;
271295
}
272296

273-
return;
297+
return null;
274298
}
275299

276300
/**
@@ -292,6 +316,9 @@ public function first()
292316
public function withOrder($orderBy) : ResultIterator
293317
{
294318
$clone = clone $this;
319+
if ($this->totalCount === 0) {
320+
return $clone;
321+
}
295322
$clone->queryFactory = clone $this->queryFactory;
296323
$clone->queryFactory->sort($orderBy);
297324
$clone->innerResultIterator = null;
@@ -313,6 +340,9 @@ public function withOrder($orderBy) : ResultIterator
313340
public function withParameters(array $parameters) : ResultIterator
314341
{
315342
$clone = clone $this;
343+
if ($this->totalCount === 0) {
344+
return $clone;
345+
}
316346
$clone->parameters = $parameters;
317347
$clone->innerResultIterator = null;
318348
$clone->totalCount = null;

tests/AbstractTDBMObjectTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace TheCodingMachine\TDBM;
44

55
use PHPUnit\Framework\TestCase;
6+
use function foo\func;
67

78
class AbstractTDBMObjectTest extends TestCase
89
{
@@ -13,4 +14,48 @@ public function testGetManyToManyRelationshipDescriptor()
1314
$this->expectExceptionMessage('Could not find many to many relationship descriptor key for "foo"');
1415
$object->_getManyToManyRelationshipDescriptor('foo');
1516
}
17+
18+
public function testEmptyResultIterator()
19+
{
20+
$a = ResultIterator::createEmpyIterator();
21+
foreach ($a as $empty) {
22+
throw new \LogicException("Not supposed to iterate on an empty iterator.");
23+
}
24+
$this->assertEquals(0, $a->count());
25+
$this->assertEquals(null, $a->first());
26+
$this->assertEquals(null, isset($a[0])); //an empty resultIterator must implement arrayAccess
27+
$this->assertEquals([], $a->toArray());
28+
foreach ($a->map(function ($foo) {
29+
}) as $empty) {
30+
throw new \LogicException("Not supposed to iterate on an empty iterator.");
31+
}
32+
$c = $a->withOrder("who cares");
33+
foreach ($c as $empty) {
34+
throw new \LogicException("Not supposed to iterate on an empty iterator.");
35+
}
36+
$this->assertEquals(0, $c->count());
37+
$d = $a->withParameters(["who cares"]);
38+
foreach ($d as $empty) {
39+
throw new \LogicException("Not supposed to iterate on an empty iterator.");
40+
}
41+
$this->assertEquals(0, $d->count());
42+
}
43+
44+
public function testEmptyPageIterator()
45+
{
46+
$a = ResultIterator::createEmpyIterator();
47+
$b = $a->take(0, 10);
48+
foreach ($b as $empty) {
49+
throw new \LogicException("Not supposed to iterate on an empty page iterator.");
50+
}
51+
$this->assertEquals(0, $b->count());
52+
$this->assertEquals([], $b->toArray());
53+
$this->assertEquals(0, $b->totalCount());
54+
$c = $b->map(function ($foo) {
55+
});
56+
foreach ($c as $empty) {
57+
throw new \LogicException("Not supposed to iterate on an empty iterator.");
58+
}
59+
$this->assertEquals([], $c->toArray());
60+
}
1661
}

0 commit comments

Comments
 (0)