Repository: JsonMapper/JsonMapper (php)

Issue:
Starting with v2.15.0 constructor for nested array of objects is not called
**Describe the bug**
Starting with v2.15.0 constructor for nested array of objects is not called.

**To Reproduce**
Steps to reproduce the behaviour:
I have a case like this:
```
class Article
{
    /** @var Tag[] */
    public array $tags;
}

class Tag
{
    private $configuration;

    public function __construct()
    {
        $this->configuration = Config::get('myconfiguration');
    }
}

// Usage
$mapper = (new JsonMapperFactory())->bestFit();
$result = $mapper->mapArray($jsonData, new Article());
```
Up until v2.14.4 everything works as expected - the constructor is called.
Starting with v2.15.0 the constructor is not called anymore and I get an issue because of the non-initialised/empty `$configuration`.

Here is a comparison between the two versions: https://github.com/JsonMapper/JsonMapper/compare/2.14.4...2.15.0

**Expected behavior**
The constructor for the `Tag` gets called.

**Environment (please complete the following information):**
 - PHP: 8.2.5
 
**Additional context**
Add any other context about the problem here.

**UPDATE**
I have prepared a test case and example with results.

```
class TestArticle
{
    public int $id;
    public string $title;

    /** @var TestTag[] */
    public array $tags;
}

class TestTag
{
    private string $configuration;

    public int $id;
    public string $name;

    public function __construct()
    {
        $this->configuration = "Works?";
    }
}

class Test
{
    public function test()
    {
        $data = json_decode('[{"id":1,"title":"Article 1","tags":[{"id":1,"name":"Tag 1"},{"id":2,"name":"Tag 2"}]},{"id":2,"title":"Article 2","tags":[{"id":1,"name":"Tag 1"},{"id":3,"name":"Tag 3"}]}]');
        $mapper = (new JsonMapperFactory())->bestFit();
        return $mapper->mapArray($data, new TestArticle());
    }
}

$test = new Test();
dd($test->test());
```

Here is a comparison of the results with v2.14.4 and v2.15.0.
| 2.14.4  | 2.15.0 |
| ------------- | ------------- |
| <img width="341" alt="Screenshot 2023-05-25 at 13 04 42" src="https://github.com/JsonMapper/JsonMapper/assets/934385/e599595f-c407-4aa3-8af7-65abbecdc225">  | <img width="292" alt="Screenshot 2023-05-25 at 13 05 16" src="https://github.com/JsonMapper/JsonMapper/assets/934385/7c641dc0-b542-40bd-b54f-0a52088ae89e">  |

As seen in the screenshots the `configuration` parameter is completely missing in the second screenshot.

Pull request description:
fix: Fix constructor not being called on nested array of objects
Fixes #162 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a089d0..4349ef4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
+### Fixed
+- Fix constructor not being called on nested array of objects [PR#162](https://github.com/JsonMapper/JsonMapper/pull/163). Thanks to [o15a3d4l11s2](https://github.com/o15a3d4l11s2) for reporting the issue.
 
 ## [2.18.0] - 2023-05-12
 ### Fixed 
diff --git a/src/Wrapper/ObjectWrapper.php b/src/Wrapper/ObjectWrapper.php
index 7782620..b2024ab 100644
--- a/src/Wrapper/ObjectWrapper.php
+++ b/src/Wrapper/ObjectWrapper.php
@@ -49,8 +49,14 @@ class ObjectWrapper
     public function getObject()
     {
         if (\is_null($this->object)) {
-            $this->object = $this->getReflectedObject()->newInstanceWithoutConstructor();
+            $constructor = $this->getReflectedObject()->getConstructor();
+            if (\is_null($constructor) || $constructor->getNumberOfParameters() === 0) {
+                $this->object = $this->getReflectedObject()->newInstance();
+            } else {
+                $this->object = $this->getReflectedObject()->newInstanceWithoutConstructor();
+            }
         }
+
         return $this->object;
     }
 


Test patch:
diff --git a/tests/Implementation/Php74/Article/Article.php b/tests/Implementation/Php74/Article/Article.php
new file mode 100644
index 0000000..3ba6e04
--- /dev/null
+++ b/tests/Implementation/Php74/Article/Article.php
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace JsonMapper\Tests\Implementation\Php74\Article;
+
+use JsonMapper\Tests\Implementation\Article\TestTag;
+
+class Article
+{
+    public int $id;
+    public string $title;
+
+    /** @var Tag[] */
+    public array $tags;
+}
diff --git a/tests/Implementation/Php74/Article/Tag.php b/tests/Implementation/Php74/Article/Tag.php
new file mode 100644
index 0000000..ed84d04
--- /dev/null
+++ b/tests/Implementation/Php74/Article/Tag.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace JsonMapper\Tests\Implementation\Php74\Article;
+
+class Tag
+{
+    private string $configuration = 'Doesnt work';
+
+    public int $id;
+    public string $name;
+
+    public function __construct()
+    {
+        $this->configuration = "Works?";
+    }
+
+    public function getConfiguration(): string
+    {
+        return $this->configuration;
+    }
+}
diff --git a/tests/Integration/Regression/Bug162RegressionTest.php b/tests/Integration/Regression/Bug162RegressionTest.php
new file mode 100644
index 0000000..3d2ac70
--- /dev/null
+++ b/tests/Integration/Regression/Bug162RegressionTest.php
@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+namespace JsonMapper\Tests\Integration\Regression;
+
+use JsonMapper\Cache\NullCache;
+use JsonMapper\JsonMapperFactory;
+use JsonMapper\JsonMapperInterface;
+use JsonMapper\Tests\Implementation\Php74\Article\Article;
+use JsonMapper\Tests\Implementation\Php74\Article\Tag;
+use JsonMapper\ValueObjects;
+use JsonMapper\Wrapper\ObjectWrapper;
+use PHPUnit\Framework\TestCase;
+use JsonMapper\Middleware;
+use JsonMapper\Middleware as MiddlewareUsingAnAlias;
+
+class Bug162RegressionTest extends TestCase
+{
+    /**
+     * @test
+     * @coversNothing
+     * @requires PHP >= 7.4
+     */
+    public function testConstructorIsCalledWhenAvailable()
+    {
+        $data = [
+            (object) [
+                'id' => 1,
+                'title' => 'Article 1',
+                'tags' => [(object) ['id' => 1, 'name' => 'Tag 1'], (object) ['id' => 2, 'name' => 'Tag 2']]
+            ],
+            (object) [
+                'id' => 2,
+                'title' => 'Article 2',
+                'tags' => [(object) ['id' => 1, 'name' => 'Tag 1'], (object) ['id' => 3, 'name' => 'Tag 3']]
+            ]
+        ];
+        $mapper = (new JsonMapperFactory())->bestFit();
+
+        $result = $mapper->mapArray($data, new Article());
+
+        self::assertEquals((new Tag())->getConfiguration(), $result[0]->tags[0]->getConfiguration());
+        self::assertEquals((new Tag())->getConfiguration(), $result[0]->tags[1]->getConfiguration());
+        self::assertEquals((new Tag())->getConfiguration(), $result[1]->tags[0]->getConfiguration());
+        self::assertEquals((new Tag())->getConfiguration(), $result[1]->tags[1]->getConfiguration());
+    }
+}