Skip to content

Commit

Permalink
Added first idea for in initializers
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Petri <[email protected]>
  • Loading branch information
michaelpetri committed Nov 20, 2021
1 parent e9e2dcc commit ac34d26
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/Generator/ClassGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Laminas\Code\Generator;

use Laminas\Code\Generator\Exception\InvalidArgumentException;
use Laminas\Code\Reflection\ClassReflection;

use function array_diff;
Expand Down Expand Up @@ -847,6 +848,14 @@ public function addMethodFromGenerator(MethodGenerator $method)
));
}

if ('__construct' === $methodName) {
foreach ($method->getParameters() as $parameter) {
if ($parameter instanceof InInitializerGenerator) {
throw new InvalidArgumentException('In Initializer can only be added to constructor.');
}
}
}

$this->methods[strtolower($methodName)] = $method;
return $this;
}
Expand Down
39 changes: 39 additions & 0 deletions src/Generator/InInitializerGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Laminas\Code\Generator;

final class InInitializerGenerator extends ParameterGenerator
{
public const VISIBILITY_PUBLIC = 'public';
public const VISIBILITY_PROTECTED = 'protected';
public const VISIBILITY_PRIVATE = 'private';

/** @psalm-var ParameterGenerator::VISIBILITY_* */
private string $visibility;

/**
* @psalm-param non-empty-string $name
* @psalm-param ?non-empty-string $type
* @psalm-param ParameterGenerator::VISIBILITY_* $inInitializer
*/
public function __construct(
string $name,
?string $type = null,
string $visibility = self::VISIBILITY_PUBLIC,
$defaultValue = null,
?int $position = null,
bool $passByReference = false
) {
parent::__construct(
$name,
$type,
$defaultValue,
$position,
$passByReference,
);

$this->visibility = $visibility;
}
}
19 changes: 19 additions & 0 deletions src/Generator/ObjectGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Laminas\Code\Generator;

final class ObjectGenerator
{
/**
* @psalm-param non-empty-string $className
* @psalm-param non-empty-string $constructorName
*/
public function __construct(
string $className,
array $parameters = [],
string $constructorName = '__construct'
){
}
}
102 changes: 102 additions & 0 deletions test/Generator/ClassGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@
use Laminas\Code\Generator\Exception\ExceptionInterface;
use Laminas\Code\Generator\Exception\InvalidArgumentException;
use Laminas\Code\Generator\GeneratorInterface;
use Laminas\Code\Generator\InInitializerGenerator;
use Laminas\Code\Generator\MethodGenerator;
use Laminas\Code\Generator\ObjectGenerator;
use Laminas\Code\Generator\ParameterGenerator;
use Laminas\Code\Generator\PropertyGenerator;
use Laminas\Code\Generator\ValueGenerator;
use Laminas\Code\Reflection\ClassReflection;
use Laminas\Code\Reflection\MethodReflection;
use LaminasTest\Code\TestAsset\FooClass;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionMethod;
use Serializable;
use stdClass;
Expand All @@ -22,6 +28,8 @@
use function fclose;
use function fopen;
use function key;
use function self;
use function uniqid;

/**
* @group Laminas_Code_Generator
Expand Down Expand Up @@ -1313,4 +1321,98 @@ public function testCorrectImplementNames()
$expected = 'class ClassName implements ClassInterface, GeneratorInterface, \Iteratable';
self::assertStringContainsString($expected, $classGenerator->generate());
}

/** @requires PHP >= 8.1 */
public function testGenerateClassWithInInitializer(): void
{
$classGenerator = new ClassGenerator();
$classGenerator->setName('InInitializer');

$classGenerator->addMethod('__construct', [
new InInitializerGenerator('inInitializer', 'string')
]);

$expectedOutput = <<<EOS
class InInitializer
{
public function __construct(
public string \$inInitializer
);
}
EOS;

self::assertEquals($expectedOutput, $classGenerator->generate());
}

/** @requires PHP >= 8.1 */
public function testGenerateClassWithInInitializerWithDefaultValue(): void
{
$classGenerator = new ClassGenerator();
$classGenerator->setName('InInitializerWithDefaultValue');

$classGenerator->addMethod('__construct', [
new InInitializerGenerator(
'inInitializer',
'Foo',
InInitializerGenerator::VISIBILITY_PRIVATE,
new ObjectGenerator(
'Foo',
[
'baz' => 'qux'
],
'bar',
)
)
]);

$expectedOutput = <<<EOS
class InInitializerWithDefaultValue
{
public function __construct(
private Foo \$inInitializer = Foo::bar(baz: 'qux')
);
}
EOS;

self::assertEquals($expectedOutput, $classGenerator->generate());
}

/** @requires PHP >= 8.1 */
public function testClassFromReflectionWithInInitializer(): void
{
$className = uniqid('ClassWithInInitializer', false);

eval('namespace ' . __NAMESPACE__ . '; class ' . $className . '{ public function __construct( public string \$inInitializer){} }');

$classGenerator = ClassGenerator::fromReflection(new ReflectionClass(__NAMESPACE__ . '\\' . $className));

$expectedOutput = <<<EOS
class ClassWithInInitializer
{
public function __construct(
public string $inInitializer
);
}
EOS;

self::assertEquals($expectedOutput, $classGenerator->generate());
}

/** @requires PHP >= 8.1 */
public function testFailToGenerateClassWithInInitializerOnOtherMethods(): void
{
$classGenerator = new ClassGenerator();
$classGenerator->setName('InInitializerOnOtherMethods');

$this->expectExceptionObject(
new InvalidArgumentException('In Initializer can only be added to constructor.')
);

$classGenerator->addMethod('thisIsNoConstructor', [
new InInitializerGenerator('inInitializer', 'string')
]);
}
}

0 comments on commit ac34d26

Please sign in to comment.