Skip to content

Commit

Permalink
Factory::fromClassReflection() added option to copy traits or not [Cl…
Browse files Browse the repository at this point in the history
…oses #89]
  • Loading branch information
mikepsinn authored and dg committed Sep 14, 2021
1 parent 7faa6ed commit b1249f2
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/PhpGenerator/ClassType.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ public static function enum(string $name = null, PhpNamespace $namespace = null)
/**
* @param string|object $class
*/
public static function from($class): self
public static function from($class, bool $withBodies = false, bool $copyTraits = true): self
{
return (new Factory)->fromClassReflection(new \ReflectionClass($class));
return (new Factory)->fromClassReflection(new \ReflectionClass($class), $withBodies, $copyTraits);
}


Expand Down
36 changes: 27 additions & 9 deletions src/PhpGenerator/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace Nette\PhpGenerator;

use Nette;
use Nette\Utils\Reflection;
use PhpParser;
use PhpParser\Node;
use PhpParser\ParserFactory;
Expand All @@ -22,8 +23,11 @@ final class Factory
{
use Nette\SmartObject;

public function fromClassReflection(\ReflectionClass $from, bool $withBodies = false): ClassType
{
public function fromClassReflection(
\ReflectionClass $from,
bool $withBodies = false,
bool $copyTraits = true
): ClassType {
$class = $from->isAnonymous()
? new ClassType
: new ClassType($from->getShortName(), new PhpNamespace($from->getNamespaceName()));
Expand Down Expand Up @@ -61,8 +65,12 @@ public function fromClassReflection(\ReflectionClass $from, bool $withBodies = f

$props = [];
foreach ($from->getProperties() as $prop) {
$declaringClass = $copyTraits
? $prop->getDeclaringClass()
: Reflection::getPropertyDeclaringClass($prop);

if ($prop->isDefault()
&& $prop->getDeclaringClass()->name === $from->name
&& $declaringClass->name === $from->name
&& (PHP_VERSION_ID < 80000 || !$prop->isPromoted())
&& !$class->isEnum()
) {
Expand All @@ -73,23 +81,33 @@ public function fromClassReflection(\ReflectionClass $from, bool $withBodies = f

$methods = $bodies = [];
foreach ($from->getMethods() as $method) {
$realMethod = Reflection::getMethodDeclaringMethod($method);
$realClass = $realMethod->getDeclaringClass();
$declaringClass = $copyTraits
? $method->getDeclaringClass()
: $realClass;

if (
$method->getDeclaringClass()->name === $from->name
$declaringClass->name === $from->name
&& (!$enumIface || !method_exists($enumIface, $method->name))
) {
$methods[] = $m = $this->fromMethodReflection($method);
if ($withBodies) {
$srcMethod = Nette\Utils\Reflection::getMethodDeclaringMethod($method);
$srcClass = $srcMethod->getDeclaringClass()->name;
$b = $bodies[$srcClass] = $bodies[$srcClass] ?? $this->loadMethodBodies($srcMethod->getDeclaringClass());
if (isset($b[$srcMethod->name])) {
$m->setBody($b[$srcMethod->name]);
$b = $bodies[$realClass->name] = $bodies[$realClass->name] ?? $this->loadMethodBodies($realClass);
if (isset($b[$realMethod->name])) {
$m->setBody($b[$realMethod->name]);
}
}
}
}
$class->setMethods($methods);

if (!$copyTraits) {
foreach ($from->getTraitNames() as $trait) {
$class->addTrait($trait);
}
}

$consts = $cases = [];
foreach ($from->getReflectionConstants() as $const) {
if ($class->isEnum() && $from->hasCase($const->name)) {
Expand Down
25 changes: 25 additions & 0 deletions tests/PhpGenerator/ClassType.from.trait.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require __DIR__ . '/../bootstrap.php';
require __DIR__ . '/fixtures/traits.php';


$res = [];
$res[] = ClassType::from('Trait1');
$res[] = ClassType::from('Trait2');
$res[] = ClassType::from('Class1');
Expand All @@ -24,6 +25,18 @@ $res[] = ClassType::from('Class5');
sameFile(__DIR__ . '/expected/ClassType.from.trait.expect', implode("\n", $res));


$res = [];
$res[] = ClassType::from('Trait1', /*withBodies:*/ false, /*copyTraits:*/ false);
$res[] = ClassType::from('Trait2', /*withBodies:*/ false, /*copyTraits:*/ false);
$res[] = ClassType::from('Class1', /*withBodies:*/ false, /*copyTraits:*/ false);
$res[] = ClassType::from('Class2', /*withBodies:*/ false, /*copyTraits:*/ false);
$res[] = ClassType::from('Class3', /*withBodies:*/ false, /*copyTraits:*/ false);
$res[] = ClassType::from('Class4', /*withBodies:*/ false, /*copyTraits:*/ false);
$res[] = ClassType::from('Class5', /*withBodies:*/ false, /*copyTraits:*/ false);

sameFile(__DIR__ . '/expected/ClassType.from.trait-use.expect', implode("\n", $res));


$res = [];
$res[] = ClassType::withBodiesFrom('Trait1');
$res[] = ClassType::withBodiesFrom('Trait2');
Expand All @@ -34,3 +47,15 @@ $res[] = ClassType::withBodiesFrom('Class4');
$res[] = ClassType::withBodiesFrom('Class5');

sameFile(__DIR__ . '/expected/ClassType.from.trait.bodies.expect', implode("\n", $res));


$res = [];
$res[] = ClassType::from('Trait1', /*withBodies:*/ true, /*copyTraits:*/ false);
$res[] = ClassType::from('Trait2', /*withBodies:*/ true, /*copyTraits:*/ false);
$res[] = ClassType::from('Class1', /*withBodies:*/ true, /*copyTraits:*/ false);
$res[] = ClassType::from('Class2', /*withBodies:*/ true, /*copyTraits:*/ false);
$res[] = ClassType::from('Class3', /*withBodies:*/ true, /*copyTraits:*/ false);
$res[] = ClassType::from('Class4', /*withBodies:*/ true, /*copyTraits:*/ false);
$res[] = ClassType::from('Class5', /*withBodies:*/ true, /*copyTraits:*/ false);

sameFile(__DIR__ . '/expected/ClassType.from.trait-use.bodies.expect', implode("\n", $res));
71 changes: 71 additions & 0 deletions tests/PhpGenerator/expected/ClassType.from.trait-use.bodies.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Trait1
*/
trait Trait1
{
public $x1;


public function f1()
{
echo 'Trait1::f1';
}
}

trait Trait2
{
use Trait1;

protected $x2;


public function f2()
{
echo 'Trait2::f2';
}
}

class Class1 extends ParentClass
{
use Trait2;
}

class Class2 extends ParentClass
{
use Trait2;

public function f1()
{
echo 'Class2::f1';
}
}

class Class3 extends ParentClass
{
use Trait2;

/** info */
public $x1;


public function f1()
{
echo 'Class3::f1';
}
}

class Class4 extends ParentClass
{
use Trait2;

public function aliased()
{
echo 'Class4::aliased';
}
}

class Class5
{
use Trait1;
use Trait1b;
}
66 changes: 66 additions & 0 deletions tests/PhpGenerator/expected/ClassType.from.trait-use.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Trait1
*/
trait Trait1
{
public $x1;


public function f1()
{
}
}

trait Trait2
{
use Trait1;

protected $x2;


public function f2()
{
}
}

class Class1 extends ParentClass
{
use Trait2;
}

class Class2 extends ParentClass
{
use Trait2;

public function f1()
{
}
}

class Class3 extends ParentClass
{
use Trait2;

/** info */
public $x1;


public function f1()
{
}
}

class Class4 extends ParentClass
{
use Trait2;

public function aliased()
{
}
}

class Class5
{
use Trait1;
use Trait1b;
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class Class2 extends ParentClass

class Class3 extends ParentClass
{
/** info */
public $x1;
protected $x2;

Expand Down
1 change: 1 addition & 0 deletions tests/PhpGenerator/expected/ClassType.from.trait.expect
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Class2 extends ParentClass

class Class3 extends ParentClass
{
/** info */
public $x1;
protected $x2;

Expand Down
1 change: 1 addition & 0 deletions tests/PhpGenerator/fixtures/traits.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class Class3 extends ParentClass
Trait2::f1 as aliased;
}

/** info */
public $x1;


Expand Down

0 comments on commit b1249f2

Please sign in to comment.