Skip to content

Commit

Permalink
Merge branch 'hotfix/typed-properties'
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-gerarts committed May 1, 2020
2 parents d3fc010 + a273e3a commit e280caf
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 29 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -3,5 +3,6 @@ php:
- '7.1'
- '7.2'
- '7.3'
- '7.4'
install:
- composer install
4 changes: 2 additions & 2 deletions composer.json
Expand Up @@ -27,7 +27,7 @@
"require-dev": {
"symfony/var-dumper": "^3.3",
"symfony/debug": "^3.3",
"phpunit/phpunit": "^6.4",
"mark-gerarts/phpstan-automapper-plus": "^0.1.0"
"mark-gerarts/phpstan-automapper-plus": "^0.1.0",
"phpunit/phpunit": "^7.0"
}
}
62 changes: 35 additions & 27 deletions src/PropertyAccessor/PropertyAccessor.php
Expand Up @@ -59,12 +59,12 @@ public function setProperty($object, string $propertyName, $value): void
*/
public function getPropertyNames($object): array
{
$propertyNames = [];
foreach ((array) $object as $propertyPath => $value) {
$propertyNames[] = $this->getRealName($propertyPath);
$names = [];
foreach ($this->getReflectionProperties($object) as $reflectionProperty) {
$names[] = $reflectionProperty->getName();
}

return $propertyNames;
return $names;
}

/**
Expand Down Expand Up @@ -94,20 +94,13 @@ protected function getPrivate($object, string $propertyName)
*/
protected function setPrivate($object, string $propertyName, $value): void
{
$reflectionClass = new \ReflectionClass($object);

// Parent properties are not included in the reflection class, so we'll
// go up the inheritance chain and check if the property exists in one
// of the parents.
while (
!$reflectionClass->hasProperty($propertyName)
&& $parent = $reflectionClass->getParentClass()
) {
$reflectionClass = $parent;
$property = $this->getReflectionProperty($object, $propertyName);
if ($property === null) {
return;
}
$reflectionProperty = $reflectionClass->getProperty($propertyName);
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($object, $value);

$property->setAccessible(true);
$property->setValue($object, $value);
}

/**
Expand All @@ -125,18 +118,33 @@ private function isPublic($object, string $propertyName): bool
}

/**
* @param string $propertyPath
* @return string
* @param $object
* @return iterable|\ReflectionProperty[]
*/
private function getRealName(string $propertyPath): string
{
$currChar = \strlen($propertyPath) - 1;
$realName = '';
while ($currChar >= 0 && $propertyPath[$currChar] !== "\x00") {
$realName = $propertyPath[$currChar] . $realName;
$currChar--;
private function getReflectionProperties($object): iterable {
$reflectionClass = new \ReflectionObject($object);
$properties = $reflectionClass->getProperties();
foreach ($properties as $property) {
yield $property;
}


// Parent properties are not included in the reflection class, so we'll
// go up the inheritance chain and collect private properties.
while ($reflectionClass = $reflectionClass->getParentClass()) {
foreach ($reflectionClass->getProperties(\ReflectionProperty::IS_PRIVATE) as $property) {
yield $property;
}
}
}

private function getReflectionProperty($object, string $propertyName): ?\ReflectionProperty {
foreach ($this->getReflectionProperties($object) as $property) {
if ($property->getName() === $propertyName) {
return $property;
}
}

return $realName;
return null;
}
}
8 changes: 8 additions & 0 deletions test/Models/Typed/TypedDestination.php
@@ -0,0 +1,8 @@
<?php

namespace AutoMapperPlus\Test\Models\Typed;

class TypedDestination
{
public string $name;
}
18 changes: 18 additions & 0 deletions test/PropertyAccessor/PropertyAccessorTest.php
Expand Up @@ -4,6 +4,7 @@

use AutoMapperPlus\Test\Models\Inheritance\SourceChild;
use AutoMapperPlus\Test\Models\Issues\Issue33\User;
use AutoMapperPlus\Test\Models\Typed\TypedDestination;
use AutoMapperPlus\Test\Models\Visibility\InheritedVisibility;
use PHPUnit\Framework\TestCase;
use AutoMapperPlus\Test\Models\Visibility\Visibility;
Expand Down Expand Up @@ -164,4 +165,21 @@ public function testItWritesCorrectlyWhenPropertiesShareASuffix()

$this->assertEquals('phone-value', $source->getPhone());
}

public function testItGetsTypedPropertyNames()
{
// Skip the test for PHP versions that don't support typed properties.
// There might be a better way?
if (PHP_VERSION_ID < 70400) {
$this->assertTrue(true);
return;
}

$accessor = new PropertyAccessor();
$destination = new TypedDestination();

$properties = $accessor->getPropertyNames($destination);

$this->assertEquals(['name'], $properties);
}
}

0 comments on commit e280caf

Please sign in to comment.