Skip to content

Commit

Permalink
prevent immutability check
Browse files Browse the repository at this point in the history
  • Loading branch information
juliangut committed Aug 27, 2020
1 parent 4ef1036 commit 106b66c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 80 deletions.
119 changes: 60 additions & 59 deletions src/PayloadBehaviour.php
Expand Up @@ -49,15 +49,14 @@ trait PayloadBehaviour
final protected function setPayload(array $payload): void
{
$this->assertPayloadSingleCall();
$this->assertPayloadCallConstraints();

$class = static::class;

if (!isset(static::$payloadDefinitionMap[$class])) {
$this->assertPayloadCallConstraints();

static::$payloadDefinitionMap[$class] = $this->getPayloadDefinition();

$this->assertImmutable();
$this->assertImmutabilityPropertyVisibility();
$this->assertImmutabilityMethodVisibility();
}

$reflection = new \ReflectionClass($this);
Expand All @@ -72,6 +71,8 @@ final protected function setPayload(array $payload): void
* @param \ReflectionClass $reflection
* @param string $parameter
* @param mixed $value
*
* @throws InvalidParameterException
*/
private function setPayloadParameter(\ReflectionClass $reflection, string $parameter, $value): void
{
Expand All @@ -86,34 +87,10 @@ private function setPayloadParameter(\ReflectionClass $reflection, string $param
$property->setValue($this, $value);
}

/**
* Get payload definition.
*
* @return string[]
*/
private function getPayloadDefinition(): array
{
$excludedProperties = \array_filter(\array_map(
static function (\ReflectionProperty $property): ?string {
return !$property->isStatic() ? $property->getName() : null;
},
(new \ReflectionClass(PayloadBehaviour::class))->getProperties()
));

return \array_filter(\array_map(
static function (\ReflectionProperty $property) use ($excludedProperties): ?string {
return !$property->isStatic() && !\in_array($property->getName(), $excludedProperties, true)
? $property->getName()
: null;
},
(new \ReflectionClass($this))->getProperties()
));
}

/**
* Assert single call.
*
* @throws ImmutabilityViolationException
* @throws DTOViolationException
*/
private function assertPayloadSingleCall(): void
{
Expand Down Expand Up @@ -164,42 +141,27 @@ private function getPayloadFilteredCallStack(): array
}

/**
* {@inheritdoc}
* Replace original to only accept call from setPayload().
*/
private function assertImmutabilityCallConstraints(): void
{
$stack = $this->getImmutabilityFilteredCallStack();

if (!isset($stack[1]) || $stack[1]['function'] !== 'setPayload') {
throw new ImmutabilityViolationException(\sprintf(
'Immutability check available only through "setPayload" method, called from "%s"',
isset($stack[1]) ? static::class . '::' . $stack[1]['function'] : 'unknown'
));
}
}

/**
* {@inheritdoc}
* Extend original to allow payload getters.
* Get payload definition.
*
* @return string[]
*/
private function getImmutabilityAllowedPublicMethods(): array
private function getPayloadDefinition(): array
{
$allowedPublicMethods = \array_unique(\array_merge(
$this->defaultGetImmutabilityAllowedPublicMethods(),
\array_map(
static function (string $parameter): string {
return 'get' . \ucfirst($parameter);
},
static::$payloadDefinitionMap[static::class]
)
$excludedProperties = \array_filter(\array_map(
static function (\ReflectionProperty $property): ?string {
return !$property->isStatic() ? $property->getName() : null;
},
(new \ReflectionClass(PayloadBehaviour::class))->getProperties()
));

\sort($allowedPublicMethods);

return $allowedPublicMethods;
return \array_filter(\array_map(
static function (\ReflectionProperty $property) use ($excludedProperties): ?string {
return !$property->isStatic() && !\in_array($property->getName(), $excludedProperties, true)
? $property->getName()
: null;
},
(new \ReflectionClass($this))->getProperties()
));
}

/**
Expand Down Expand Up @@ -296,4 +258,43 @@ final public function __call(string $methodName, array $arguments)
? $this->get(\lcfirst($parameter))
: $this->get($parameter);
}

/**
* {@inheritdoc}
* Replace original to forbid usage.
*
* @throws ImmutabilityViolationException
*/
final protected function assertImmutable(): void
{
$stack = $this->getImmutabilityFilteredCallStack();

throw new ImmutabilityViolationException(\sprintf(
'Immutability check available only through "setPayload" method, called from "%s"',
isset($stack[1]) ? static::class . '::' . $stack[1]['function'] : 'unknown'
));
}

/**
* {@inheritdoc}
* Extend original to allow payload getters.
*
* @return string[]
*/
private function getImmutabilityAllowedPublicMethods(): array
{
$allowedPublicMethods = \array_unique(\array_merge(
$this->defaultGetImmutabilityAllowedPublicMethods(),
\array_map(
static function (string $parameter): string {
return 'get' . \ucfirst($parameter);
},
static::$payloadDefinitionMap[static::class]
)
));

\sort($allowedPublicMethods);

return $allowedPublicMethods;
}
}
10 changes: 0 additions & 10 deletions tests/DTO/PayloadBehaviourTest.php
Expand Up @@ -38,16 +38,6 @@ public function testNoImmutabilityAssertion(): void
new PayloadBehaviourInvalidImmutableCallStub([]);
}

public function testNoImmutabilityChecked(): void
{
$this->expectException(ImmutabilityViolationException::class);
$this->expectExceptionMessage(
'Class "Gears\DTO\Tests\Stub\PayloadBehaviourStub" was already checked for immutability'
);

PayloadBehaviourStub::callImmutableAssertion();
}

public function testSingleCall(): void
{
$this->expectException(DTOViolationException::class);
Expand Down
11 changes: 0 additions & 11 deletions tests/DTO/Stub/PayloadBehaviourStub.php
Expand Up @@ -39,17 +39,6 @@ public function __construct(array $payload)
$this->setPayload($payload);
}

protected function testImmutable(): void
{
$this->assertImmutable();
}

public static function callImmutableAssertion(): void
{
$dto = new static([]);
$dto->testImmutable();
}

protected function testPayload(): void
{
$this->setPayload([]);
Expand Down

0 comments on commit 106b66c

Please sign in to comment.