diff --git a/composer.json b/composer.json
index ad91758..8620c9d 100644
--- a/composer.json
+++ b/composer.json
@@ -37,7 +37,8 @@
},
"autoload-dev": {
"psr-4": {
- "Respect\\Relational\\": "tests/"
+ "Respect\\Relational\\": ["tests/", "tests/Stubs/"],
+ "Respect\\Relational\\OtherEntity\\": "tests/Stubs/OtherEntity/"
}
},
"scripts": {
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index aecc899..d0a519e 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -14,14 +14,9 @@
src/
tests/
-
-
-
-
-
-
+
-
+
tests/
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index a79c04a..334cef8 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -9,7 +9,6 @@ parameters:
- message: '/Access to an undefined property Respect\\Relational\\Mapper::\$\w+\./'
- message: '/Unsafe usage of new static\(\)\./'
- message: '/Cannot unset property .+ because it might have hooks in a subclass\./'
- - message: '/Array has \d+ duplicate keys/'
-
message: '/Parameter #1 .+ of class Respect\\Relational\\Mapper constructor expects .+, string given\./'
path: tests/MapperTest.php
diff --git a/src/Mapper.php b/src/Mapper.php
index 62e611d..e64cb05 100644
--- a/src/Mapper.php
+++ b/src/Mapper.php
@@ -61,6 +61,30 @@ public function getDb(): Db
return $this->db;
}
+ public function fetch(Collection $collection, mixed $extra = null): mixed
+ {
+ $statement = $this->createStatement($collection, $extra);
+ $hydrated = $this->fetchHydrated($collection, $statement);
+ if (!$hydrated) {
+ return false;
+ }
+
+ return $this->parseHydrated($hydrated);
+ }
+
+ /** @return array */
+ public function fetchAll(Collection $collection, mixed $extra = null): array
+ {
+ $statement = $this->createStatement($collection, $extra);
+ $entities = [];
+
+ while ($hydrated = $this->fetchHydrated($collection, $statement)) {
+ $entities[] = $this->parseHydrated($hydrated);
+ }
+
+ return $entities;
+ }
+
public function persist(object $object, Collection $onCollection): bool
{
$next = $onCollection->getNext();
@@ -268,22 +292,6 @@ protected function checkNewIdentity(object $entity, Collection $collection): boo
return true;
}
- protected function createStatement(
- Collection $collection,
- mixed $withExtra = null,
- ): PDOStatement {
- $query = $this->generateQuery($collection);
-
- if ($withExtra instanceof Sql) {
- $query->appendQuery($withExtra);
- }
-
- $statement = $this->db->prepare((string) $query, PDO::FETCH_NUM);
- $statement->execute($query->getParams());
-
- return $statement;
- }
-
protected function generateQuery(Collection $collection): Sql
{
$collections = iterator_to_array(
@@ -499,28 +507,6 @@ protected function hasComposition(string $entity, string|null $next, string|null
|| $entity === $s->composed($next, $parent);
}
- protected function fetchSingle(
- Collection $collection,
- PDOStatement $statement,
- ): SplObjectStorage|false {
- $name = $collection->getName();
- $entityName = $name;
- $row = $statement->fetch(PDO::FETCH_OBJ);
-
- if (!$row) {
- return false;
- }
-
- if ($this->typable($collection)) {
- $entityName = $this->inferGet($row, $this->getType($collection));
- }
-
- $entities = new SplObjectStorage();
- $entities[$this->transformSingleRow($row, $entityName)] = $collection;
-
- return $entities;
- }
-
protected function getNewEntityByName(string $entityName): object
{
$entityName = $this->getStyle()->styledName($entityName);
@@ -571,24 +557,6 @@ protected function inferGet(object &$object, string $prop): mixed
}
}
- protected function fetchMulti(
- Collection $collection,
- PDOStatement $statement,
- ): SplObjectStorage|false {
- $entities = [];
- $row = $statement->fetch(PDO::FETCH_NUM);
-
- if (!$row) {
- return false;
- }
-
- $this->postHydrate(
- $entities = $this->createEntities($row, $statement, $collection),
- );
-
- return $entities;
- }
-
/** @param array $row */
protected function createEntities(
array $row,
@@ -709,4 +677,77 @@ protected function getAllProperties(object $object): array
return $cols;
}
+
+ private function parseHydrated(SplObjectStorage $hydrated): mixed
+ {
+ $this->tracked->addAll($hydrated);
+ $hydrated->rewind();
+
+ return $hydrated->current();
+ }
+
+ private function fetchHydrated(Collection $collection, PDOStatement $statement): SplObjectStorage|false
+ {
+ if (!$collection->hasMore()) {
+ return $this->fetchSingle($collection, $statement);
+ }
+
+ return $this->fetchMulti($collection, $statement);
+ }
+
+ private function createStatement(
+ Collection $collection,
+ mixed $withExtra = null,
+ ): PDOStatement {
+ $query = $this->generateQuery($collection);
+
+ if ($withExtra instanceof Sql) {
+ $query->appendQuery($withExtra);
+ }
+
+ $statement = $this->db->prepare((string) $query, PDO::FETCH_NUM);
+ $statement->execute($query->getParams());
+
+ return $statement;
+ }
+
+ private function fetchSingle(
+ Collection $collection,
+ PDOStatement $statement,
+ ): SplObjectStorage|false {
+ $name = $collection->getName();
+ $entityName = $name;
+ $row = $statement->fetch(PDO::FETCH_OBJ);
+
+ if (!$row) {
+ return false;
+ }
+
+ if ($this->typable($collection)) {
+ $entityName = $this->inferGet($row, $this->getType($collection));
+ }
+
+ $entities = new SplObjectStorage();
+ $entities[$this->transformSingleRow($row, $entityName)] = $collection;
+
+ return $entities;
+ }
+
+ private function fetchMulti(
+ Collection $collection,
+ PDOStatement $statement,
+ ): SplObjectStorage|false {
+ $entities = [];
+ $row = $statement->fetch(PDO::FETCH_NUM);
+
+ if (!$row) {
+ return false;
+ }
+
+ $this->postHydrate(
+ $entities = $this->createEntities($row, $statement, $collection),
+ );
+
+ return $entities;
+ }
}
diff --git a/tests/DbTest.php b/tests/DbTest.php
index 53c0581..4e3133f 100644
--- a/tests/DbTest.php
+++ b/tests/DbTest.php
@@ -123,28 +123,3 @@ protected function tearDown(): void
unset($this->object);
}
}
-
-class TestFetchingClass
-{
- public int|null $testa = null;
-
- public string|null $testb = null;
-
- public int|null $testez = null;
-}
-
-class TestFetchingInto
-{
- public int|null $testa = null;
-
- public string|null $testb = null;
-
- public int|null $testez = null;
-}
-
-class TestFetchingClassArgs
-{
- public function __construct(public string|null $testd = null)
- {
- }
-}
diff --git a/tests/MapperTest.php b/tests/MapperTest.php
index 5512b15..d0f29f0 100644
--- a/tests/MapperTest.php
+++ b/tests/MapperTest.php
@@ -1145,170 +1145,3 @@ public function testShouldNotExecuteEntityConstructorWhenDisabled(): void
);
}
}
-
-class Postcomment
-{
- public int|null $id = null;
-}
-
-class Bug
-{
- public int|null $id = null;
-
- public string|null $title = null;
-
- public string|null $type = null;
-}
-
-class Improvement
-{
- public int|null $id = null;
-
- public string|null $title = null;
-
- public string|null $type = null;
-}
-
-class Comment
-{
- public mixed $id = null;
-
- public mixed $post_id = null;
-
- public string|null $text = null;
-
- private string|null $datetime = null;
-
- public function setDatetime(Datetime $datetime): void
- {
- $this->datetime = $datetime->format('Y-m-d H:i:s');
- }
-
- public function getDatetime(): Datetime
- {
- return new Datetime($this->datetime);
- }
-}
-
-class Post
-{
- public mixed $id = null;
-
- public mixed $author_id = null;
-
- public string|null $text = null;
-
- public string|null $title = null;
-
- /** @Relational\isNotColumn -> annotation because generate a sql error case column not exists in db. */
- private string $datetime = '';
-
- public function setDatetime(Datetime $datetime): void
- {
- $this->datetime = $datetime->format('Y-m-d H:i:s');
- }
-
- public function getDatetime(): Datetime
- {
- return new Datetime($this->datetime);
- }
-}
-
-namespace Respect\Relational\OtherEntity;
-
-use DomainException;
-
-class Post
-{
- private mixed $id = null;
-
- private mixed $author_id = null;
-
- private mixed $title = null;
-
- private mixed $text = null;
-
- public function getTitle(): mixed
- {
- return $this->title;
- }
-
- public function setTitle(mixed $title): void
- {
- $this->title = $title;
- }
-
- public function getId(): mixed
- {
- return $this->id;
- }
-
- public function getAuthor(): mixed
- {
- return $this->author_id;
- }
-
- public function getText(): mixed
- {
- return $this->text;
- }
-
- public function setId(mixed $id): void
- {
- $this->id = $id;
- }
-
- public function setAuthor(Author $author): void
- {
- $this->author_id = $author;
- }
-
- public function setText(mixed $text): void
- {
- $this->text = $text;
- }
-}
-
-class Author
-{
- private mixed $id = null;
-
- private mixed $name = null;
-
- public function getId(): mixed
- {
- return $this->id;
- }
-
- public function getName(): mixed
- {
- return $this->name;
- }
-
- public function setId(mixed $id): void
- {
- $this->id = $id;
- }
-
- public function setName(mixed $name): void
- {
- $this->name = $name;
- }
-}
-
-
-class Comment
-{
- public int|null $id = null;
-
- public int|null $post_id = null;
-
- public string|null $text = null;
-
- public string|null $datetime = null;
-
- public function __construct()
- {
- throw new DomainException('Exception from __construct');
- }
-}
diff --git a/tests/Stubs/Bug.php b/tests/Stubs/Bug.php
new file mode 100644
index 0000000..a9d6f3c
--- /dev/null
+++ b/tests/Stubs/Bug.php
@@ -0,0 +1,14 @@
+datetime = $datetime->format('Y-m-d H:i:s');
+ }
+
+ public function getDatetime(): Datetime
+ {
+ return new Datetime($this->datetime);
+ }
+}
diff --git a/tests/Stubs/Improvement.php b/tests/Stubs/Improvement.php
new file mode 100644
index 0000000..10f5978
--- /dev/null
+++ b/tests/Stubs/Improvement.php
@@ -0,0 +1,14 @@
+id;
+ }
+
+ public function getName(): mixed
+ {
+ return $this->name;
+ }
+
+ public function setId(mixed $id): void
+ {
+ $this->id = $id;
+ }
+
+ public function setName(mixed $name): void
+ {
+ $this->name = $name;
+ }
+}
diff --git a/tests/Stubs/OtherEntity/Comment.php b/tests/Stubs/OtherEntity/Comment.php
new file mode 100644
index 0000000..5d96334
--- /dev/null
+++ b/tests/Stubs/OtherEntity/Comment.php
@@ -0,0 +1,23 @@
+title;
+ }
+
+ public function setTitle(mixed $title): void
+ {
+ $this->title = $title;
+ }
+
+ public function getId(): mixed
+ {
+ return $this->id;
+ }
+
+ public function getAuthor(): mixed
+ {
+ return $this->author_id;
+ }
+
+ public function getText(): mixed
+ {
+ return $this->text;
+ }
+
+ public function setId(mixed $id): void
+ {
+ $this->id = $id;
+ }
+
+ public function setAuthor(Author $author): void
+ {
+ $this->author_id = $author;
+ }
+
+ public function setText(mixed $text): void
+ {
+ $this->text = $text;
+ }
+}
diff --git a/tests/Stubs/Post.php b/tests/Stubs/Post.php
new file mode 100644
index 0000000..9039092
--- /dev/null
+++ b/tests/Stubs/Post.php
@@ -0,0 +1,31 @@
+ annotation because generate a sql error case column not exists in db. */
+ private string $datetime = '';
+
+ public function setDatetime(Datetime $datetime): void
+ {
+ $this->datetime = $datetime->format('Y-m-d H:i:s');
+ }
+
+ public function getDatetime(): Datetime
+ {
+ return new Datetime($this->datetime);
+ }
+}
diff --git a/tests/Stubs/Postcomment.php b/tests/Stubs/Postcomment.php
new file mode 100644
index 0000000..812825f
--- /dev/null
+++ b/tests/Stubs/Postcomment.php
@@ -0,0 +1,10 @@
+style = new class extends AbstractStyle {
- public function styledProperty(string $name): string
- {
- return $name;
- }
-
- public function realName(string $name): string
- {
- return $name;
- }
-
- public function realProperty(string $name): string
- {
- return $name;
- }
-
- public function styledName(string $name): string
- {
- return $name;
- }
-
- public function identifier(string $name): string
- {
- return 'id';
- }
-
- public function remoteIdentifier(string $name): string
- {
- return $name . '_id';
- }
-
- public function composed(string $left, string $right): string
- {
- return $left . '_' . $right;
- }
-
- public function isRemoteIdentifier(string $name): bool
- {
- return false;
- }
-
- public function remoteFromIdentifier(string $name): string|null
- {
- return null;
- }
- };
- }
-
- /** @return array */
- public static function singularPluralProvider(): array
- {
- return [
- ['post', 'posts'],
- ['comment', 'comments'],
- ['category', 'categories'],
- ['tag', 'tags'],
- ['entity', 'entities'],
- ];
- }
-
- /** @return array */
- public static function camelCaseToSeparatorProvider(): array
- {
- return [
- ['-', 'HenriqueMoody', 'Henrique-Moody'],
- [' ', 'AlexandreGaigalas', 'Alexandre Gaigalas'],
- ['_', 'AugustoPascutti', 'Augusto_Pascutti'],
- ];
- }
-
- #[DataProvider('singularPluralProvider')]
- public function testPluralToSingularAndViceVersa(string $singular, string $plural): void
- {
- $pluralToSingular = new ReflectionMethod($this->style, 'pluralToSingular');
- $this->assertEquals($singular, $pluralToSingular->invoke($this->style, $plural));
-
- $singularToPlural = new ReflectionMethod($this->style, 'singularToPlural');
- $this->assertEquals($plural, $singularToPlural->invoke($this->style, $singular));
- }
-
- #[DataProvider('camelCaseToSeparatorProvider')]
- public function testCamelCaseToSeparatorAndViceVersa(
- string $separator,
- string $camelCase,
- string $separated,
- ): void {
- $camelCaseToSeparatorMethod = new ReflectionMethod($this->style, 'camelCaseToSeparator');
- $this->assertEquals(
- $separated,
- $camelCaseToSeparatorMethod->invoke($this->style, $camelCase, $separator),
- );
-
- $separatorToCamelCaseMethod = new ReflectionMethod($this->style, 'separatorToCamelCase');
- $this->assertEquals(
- $camelCase,
- $separatorToCamelCaseMethod->invoke($this->style, $separated, $separator),
- );
- }
-}
diff --git a/tests/Styles/CakePHPTest.php b/tests/Styles/CakePHPTest.php
deleted file mode 100644
index 4b20acf..0000000
--- a/tests/Styles/CakePHPTest.php
+++ /dev/null
@@ -1,346 +0,0 @@
- */
- private array $posts;
-
- /** @var list