Skip to content

Commit

Permalink
ClassType: added inheritMethod() & inheritProperty()
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Sep 29, 2023
1 parent 04456d8 commit e602704
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/PhpGenerator/ClassType.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,55 @@ public function addMember(Method|Property|Constant|TraitUse $member): static
}


/**
* Inherits property from parent class.
*/
public function inheritProperty(string $name, bool $returnIfExists = false): Property
{
if (isset($this->properties[$name])) {
return $returnIfExists
? $this->properties[$name]
: throw new Nette\InvalidStateException("Cannot inherit property '$name', because it already exists.");

} elseif (!$this->extends) {
throw new Nette\InvalidStateException("Class '{$this->getName()}' has not setExtends() set.");
}

try {
return $this->properties[$name] = (new Factory)->fromPropertyReflection(new \ReflectionProperty($this->extends, $name));
} catch (\ReflectionException) {
throw new Nette\InvalidStateException("Property '$name' has not been found in ancestor {$this->extends}");
}
}


/**
* Inherits method from parent class or interface.
*/
public function inheritMethod(string $name, bool $returnIfExists = false): Method
{
$lower = strtolower($name);
$parents = [...(array) $this->extends, ...$this->implements];
if (isset($this->methods[$lower])) {
return $returnIfExists
? $this->methods[$lower]
: throw new Nette\InvalidStateException("Cannot inherit method '$name', because it already exists.");

} elseif (!$parents) {
throw new Nette\InvalidStateException("Class '{$this->getName()}' has neither setExtends() nor setImplements() set.");
}

foreach ($parents as $parent) {
try {
return $this->methods[$lower] = Method::from([$parent, $name]);
} catch (\ReflectionException) {
}
}

throw new Nette\InvalidStateException("Method '$name' has not been found in any ancestor: " . implode(', ', $parents));
}


/** @throws Nette\InvalidStateException */
public function validate(): void
{
Expand Down
51 changes: 51 additions & 0 deletions tests/PhpGenerator/Method.inherit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

use Tester\Assert;

require __DIR__ . '/../bootstrap.php';


class Foo
{
public function bar(int $a, ...$b): void
{
}
}


// missing parent
$class = new Nette\PhpGenerator\ClassType('Test');
Assert::exception(
fn() => $class->inheritMethod('bar'),
Nette\InvalidStateException::class,
"Class 'Test' has neither setExtends() nor setImplements() set.",
);

$class->setExtends('Unknown1');
$class->addImplement('Unknown2');
Assert::exception(
fn() => $class->inheritMethod('bar'),
Nette\InvalidStateException::class,
"Method 'bar' has not been found in any ancestor: Unknown1, Unknown2",
);


// implement method
$class = new Nette\PhpGenerator\ClassType('Test');
$class->setExtends(Foo::class);
$method = $class->inheritMethod('bar');
Assert::match(<<<'XX'
public function bar(int $a, ...$b): void
{
}

XX, (string) $method);

Assert::same($method, $class->inheritMethod('bar', returnIfExists: true));
Assert::exception(
fn() => $class->inheritMethod('bar', returnIfExists: false),
Nette\InvalidStateException::class,
"Cannot inherit method 'bar', because it already exists.",
);
49 changes: 49 additions & 0 deletions tests/PhpGenerator/Property.inherit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

use Tester\Assert;

require __DIR__ . '/../bootstrap.php';


class Foo
{
public array $bar = [123];
}


// missing parent
$class = new Nette\PhpGenerator\ClassType('Test');
Assert::exception(
fn() => $class->inheritProperty('bar'),
Nette\InvalidStateException::class,
"Class 'Test' has not setExtends() set.",
);

$class->setExtends('Unknown');
Assert::exception(
fn() => $class->inheritProperty('bar'),
Nette\InvalidStateException::class,
"Property 'bar' has not been found in ancestor Unknown",
);


// implement property
$class = new Nette\PhpGenerator\ClassType('Test');
$class->setExtends(Foo::class);
$prop = $class->inheritProperty('bar');
Assert::match(<<<'XX'
class Test extends Foo
{
public array $bar = [123];
}

XX, (string) $class);

Assert::same($prop, $class->inheritProperty('bar', returnIfExists: true));
Assert::exception(
fn() => $class->inheritProperty('bar', returnIfExists: false),
Nette\InvalidStateException::class,
"Cannot inherit property 'bar', because it already exists.",
);

0 comments on commit e602704

Please sign in to comment.