Skip to content

Commit 72112e6

Browse files
committed
Refactored to make use of ClassProp and ClassPropSet
Removed some methods on the PropTypes and replaced with a ClassProp object which maintains some helpful information on the class property Signed-off-by: RJ Garcia <ragboyjr@icloud.com>
1 parent d657caa commit 72112e6

12 files changed

Lines changed: 239 additions & 122 deletions

src/CreateStructStatements/ConstructorCreateStructStatements.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Krak\StructGen\CreateStructStatements;
66
use Krak\StructGen\CreateStructStatementsArgs;
7+
use Krak\StructGen\Internal\Props\ClassProp;
78
use Krak\StructGen\Internal\PropTypes;
89
use PhpParser\Node\Expr;
910
use PhpParser\Node\Stmt\Class_;
@@ -18,10 +19,9 @@ public function __invoke(CreateStructStatementsArgs $args): array {
1819
}
1920

2021
$method = $args->factory()->method('__construct')
21-
->addParams(array_map(
22-
PropTypes::paramBuilderFromProp($args->factory(), $args->printer()),
23-
$args->class()->getProperties()
24-
))
22+
->addParams(array_map(function(ClassProp $prop) use ($args) {
23+
return $prop->toParam($args->factory());
24+
}, $args->props()->toArray()))
2525
->addStmts(array_map(function(Property $prop) use ($args) {
2626
$propName = (string) $prop->props[0]->name;
2727
return new Expr\Assign(
@@ -31,7 +31,7 @@ public function __invoke(CreateStructStatementsArgs $args): array {
3131
}, $args->class()->getProperties()))
3232
->makePublic();
3333

34-
if ($docComment = PropTypes::getParamsDocCommentForProps($args->class()->getProperties())) {
34+
if ($docComment = $args->props()->getNeededDocParams()) {
3535
$method->setDocComment($docComment);
3636
}
3737

src/CreateStructStatements/FromValidatedArrayConstructorCreateStructStatements.php

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Krak\StructGen\CreateStructStatements;
66
use Krak\StructGen\CreateStructStatementsArgs;
7+
use Krak\StructGen\Internal\Props\ClassProp;
78
use Krak\StructGen\Internal\PropTypes;
89
use Krak\StructGen\Internal\TypeParser;
910
use PhpParser\Node\{Stmt, Expr};
@@ -17,20 +18,17 @@ public function __invoke(CreateStructStatementsArgs $args): array {
1718
->makePublic()
1819
->addParam($args->factory()->param('data')->setType('array')->getNode())
1920
->setReturnType('self')
20-
->addStmt(new Stmt\Return_($args->factory()->new('self', array_map(function(Stmt\Property $prop) use ($args) {
21-
$varDef = PropTypes::getVarDefinitionFromProperty($prop);
22-
$type = $varDef ? $type = (new TypeParser())->parse($varDef) : null;
23-
$shouldFromArray = PropTypes::canCallMethodsOnType($type);
24-
$shouldCheckNullable = $shouldFromArray && $type->atomicTypes()[0]->nullable();
25-
$shouldArrayMap = $shouldFromArray && $type->atomicTypes()[0]->isArray();
21+
->addStmt(new Stmt\Return_($args->factory()->new('self', array_map(function(ClassProp $prop) use ($args) {
22+
$shouldFromArray = PropTypes::canCallMethodsOnType($prop->type());
23+
$shouldCheckNullable = $shouldFromArray && $prop->type()->atomicTypes()[0]->nullable();
24+
$shouldArrayMap = $shouldFromArray && $prop->type()->atomicTypes()[0]->isArray();
2625

27-
$propName = (string) $prop->props[0]->name;
2826
$fetchExpr = $fetchFromArray = new Expr\ArrayDimFetch(
2927
$args->factory()->var('data'),
30-
$args->factory()->val($propName)
28+
$args->factory()->val($prop->name())
3129
);
3230
if ($shouldFromArray) {
33-
$fetchExpr = $args->factory()->staticCall($type->atomicTypes()[0]->typeDefinition(), 'fromValidatedArray', [
31+
$fetchExpr = $args->factory()->staticCall($prop->type()->atomicTypes()[0]->typeDefinition(), 'fromValidatedArray', [
3432
$fetchFromArray
3533
]);
3634
}
@@ -42,17 +40,17 @@ public function __invoke(CreateStructStatementsArgs $args): array {
4240
);
4341
}
4442
if ($shouldArrayMap) {
45-
$callFromArray = $args->factory()->staticCall($type->atomicTypes()[0]->typeDefinition(), 'fromValidatedArray', [
43+
$callFromArray = $args->factory()->staticCall($prop->type()->atomicTypes()[0]->typeDefinition(), 'fromValidatedArray', [
4644
$args->factory()->var('value')
4745
]);
4846
$fetchExpr = $args->factory()->funcCall('\array_map', [
4947
new Expr\Closure([
5048
'params' => [
5149
$args->factory()->param('value')
52-
->setType($type->atomicTypes()[0]->nullable() ? '?array' : 'array')
50+
->setType($prop->type()->atomicTypes()[0]->nullable() ? '?array' : 'array')
5351
->getNode()
5452
],
55-
'returnType' => $type->atomicTypes()[0]->withIsArray(false)->toPhpString(),
53+
'returnType' => $prop->type()->atomicTypes()[0]->withIsArray(false)->toPhpString(),
5654
'stmts' => [
5755
new Stmt\Return_($shouldCheckNullable
5856
? new Expr\Ternary(
@@ -67,14 +65,14 @@ public function __invoke(CreateStructStatementsArgs $args): array {
6765
$fetchFromArray
6866
]);
6967
}
70-
return $prop->props[0]->default === null
68+
return $prop->default() === null
7169
? $fetchExpr
7270
: new Expr\Ternary(
73-
$args->factory()->funcCall('array_key_exists', [$args->factory()->val($propName), $args->factory()->var('data')]),
71+
$args->factory()->funcCall('array_key_exists', [$args->factory()->val($prop->name()), $args->factory()->var('data')]),
7472
$fetchExpr,
75-
$prop->props[0]->default
73+
$prop->default()
7674
);
77-
}, $args->class()->getProperties()))))
75+
}, $args->props()->toArray()))))
7876
->getNode()
7977
];
8078
}

src/CreateStructStatements/GettersCreateStructStatements.php

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,25 @@
44

55
use Krak\StructGen\CreateStructStatements;
66
use Krak\StructGen\CreateStructStatementsArgs;
7+
use Krak\StructGen\Internal\Props\ClassProp;
78
use Krak\StructGen\Internal\PropTypes;
89
use Krak\StructGen\Internal\TypeParser;
910
use PhpParser\Node\Stmt;
1011

1112
final class GettersCreateStructStatements implements CreateStructStatements
1213
{
1314
public function __invoke(CreateStructStatementsArgs $args): array {
14-
$methods = [];
15-
foreach ($args->class()->getProperties() as $prop) {
16-
if (count($prop->props) !== 1) {
17-
throw new \RuntimeException('Does not support property definitions that define more than one property.');
18-
}
19-
$method = $args->factory()->method((string) $prop->props[0]->name)
15+
return array_map(function(ClassProp $prop) use ($args) {
16+
$method = $args->factory()->method((string) $prop->name())
2017
->makePublic()
21-
->addStmt(new Stmt\Return_($args->factory()->propertyFetch($args->factory()->var('this'), $prop->props[0]->name)));
22-
23-
$varDef = PropTypes::getVarDefinitionFromProperty($prop);
24-
$type = $varDef ? (new TypeParser())->parse($varDef) : null;
25-
if ($type && $type->toPhpString() !== $type->toString()) {
26-
$method->setDocComment("/** @return {$type->toString()} */");
18+
->addStmt(new Stmt\Return_($args->factory()->propertyFetch($args->factory()->var('this'), $prop->name())));
19+
if (!$prop->type()->isEmpty() && !$prop->type()->canBeFullyExpressedInPhp()) {
20+
$method->setDocComment("/** @return {$prop->type()->toString()} */");
2721
}
28-
if ($type && $type->toPhpString()) {
29-
$method->setReturnType($type->toPhpString());
22+
if ($prop->type()->toPhpString()) {
23+
$method->setReturnType($prop->type()->toPhpString());
3024
}
31-
32-
$methods[] = $method->getNode();
33-
}
34-
return $methods;
25+
return $method->getNode();
26+
}, $args->props()->toArray());
3527
}
3628
}

src/CreateStructStatements/ImmutableWithersCreateStructStatements.php

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,33 @@
44

55
use Krak\StructGen\CreateStructStatements;
66
use Krak\StructGen\CreateStructStatementsArgs;
7+
use Krak\StructGen\Internal\Props\ClassProp;
8+
use Krak\StructGen\Internal\Props\ClassPropSet;
79
use Krak\StructGen\Internal\PropTypes;
810
use PhpParser\Node\{Stmt, Expr};
911

1012
final class ImmutableWithersCreateStructStatements implements CreateStructStatements
1113
{
1214
public function __invoke(CreateStructStatementsArgs $args): array {
13-
$methods = [];
14-
foreach ($args->class()->getProperties() as $prop) {
15-
if (count($prop->props) !== 1) {
16-
throw new \RuntimeException('Does not support property definitions that define more than one property.');
17-
}
18-
$propName = (string) $prop->props[0]->name;
19-
$method = $args->factory()->method('with' . ucfirst($propName))
15+
return array_map(function(ClassProp $prop) use ($args) {
16+
$method = $args->factory()->method('with' . ucfirst($prop->name()))
2017
->makePublic()
2118
->addStmts([
2219
new Expr\Assign($args->factory()->var('self'), new Expr\Clone_($args->factory()->var('this'))),
2320
new Expr\Assign(
24-
$args->factory()->propertyFetch($args->factory()->var('self'), $propName),
25-
$args->factory()->var((string) $propName)
21+
$args->factory()->propertyFetch($args->factory()->var('self'), $prop->name()),
22+
$args->factory()->var($prop->name())
2623
),
2724
new Stmt\Return_($args->factory()->var('self'))
2825
])
2926
->setReturnType('self')
30-
->addParam(PropTypes::paramBuilderFromProp($args->factory(), $args->printer())($prop));
27+
->addParam($prop->toParam($args->factory()))
28+
;
3129

32-
if ($docComment = PropTypes::getParamsDocCommentForProps([$prop])) {
30+
if ($docComment = $prop->getParamDocCommentIfNeeded()) {
3331
$method->setDocComment($docComment);
3432
}
35-
36-
$methods[] = $method->getNode();
37-
}
38-
return $methods;
33+
return $method->getNode();
34+
}, $args->props()->toArray());
3935
}
4036
}

src/CreateStructStatements/ToArrayCreateStructStatements.php

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Krak\StructGen\CreateStructStatements;
66
use Krak\StructGen\CreateStructStatementsArgs;
7+
use Krak\StructGen\Internal\Props\ClassProp;
78
use Krak\StructGen\Internal\PropTypes;
89
use Krak\StructGen\Internal\TypeParser;
910
use Krak\StructGen\Internal\UnionType;
@@ -17,24 +18,22 @@ public function __invoke(CreateStructStatementsArgs $args): array {
1718
$args->factory()->method('toArray')
1819
->makePublic()
1920
->setReturnType('array')
20-
->addStmt(new Stmt\Return_(new Expr\Array_(array_map(function(Stmt\Property $prop) use ($args) {
21+
->addStmt(new Stmt\Return_(new Expr\Array_(array_map(function(ClassProp $prop) use ($args) {
2122
return new Expr\ArrayItem(
2223
$this->accessPropertyExpr($args->factory(), $prop),
23-
$args->factory()->val((string) $prop->props[0]->name)
24+
$args->factory()->val($prop->name())
2425
);
25-
}, $args->class()->getProperties()), ['kind' => Expr\Array_::KIND_SHORT])))
26+
}, $args->props()->toArray()), ['kind' => Expr\Array_::KIND_SHORT])))
2627
->getNode()
2728
];
2829
}
2930

30-
private function accessPropertyExpr(BuilderFactory $factory, Stmt\Property $prop): Expr {
31-
$varDef = PropTypes::getVarDefinitionFromProperty($prop);
32-
$type = $varDef ? $type = (new TypeParser())->parse($varDef) : null;
33-
$shouldToArray = PropTypes::canCallMethodsOnType($type);
34-
$shouldCheckNullable = $shouldToArray && $type->atomicTypes()[0]->nullable();
35-
$shouldArrayMap = $shouldToArray && $type->atomicTypes()[0]->isArray();
31+
private function accessPropertyExpr(BuilderFactory $factory, ClassProp $prop): Expr {
32+
$shouldToArray = PropTypes::canCallMethodsOnType($prop->type());
33+
$shouldCheckNullable = $shouldToArray && $prop->type()->atomicTypes()[0]->nullable();
34+
$shouldArrayMap = $shouldToArray && $prop->type()->atomicTypes()[0]->isArray();
3635

37-
$propExpr = $propFetch = $factory->propertyFetch($factory->var('this'), $prop->props[0]->name);
36+
$propExpr = $propFetch = $factory->propertyFetch($factory->var('this'), $prop->name());
3837
if ($shouldToArray) {
3938
$propExpr = $factory->methodCall($propExpr, 'toArray');
4039
}
@@ -47,10 +46,10 @@ private function accessPropertyExpr(BuilderFactory $factory, Stmt\Property $prop
4746
new Expr\Closure([
4847
'params' => [
4948
$factory->param('value')
50-
->setType($type->atomicTypes()[0]->withIsArray(false)->toPhpString())
49+
->setType($prop->type()->atomicTypes()[0]->withIsArray(false)->toPhpString())
5150
->getNode()
5251
],
53-
'returnType' => $type->atomicTypes()[0]->nullable() ? '?array' : 'array',
52+
'returnType' => $prop->type()->atomicTypes()[0]->nullable() ? '?array' : 'array',
5453
'stmts' => [
5554
new Stmt\Return_($shouldCheckNullable
5655
? new Expr\Ternary(new Expr\BinaryOp\Identical($factory->var('value'), $factory->val(null)), $factory->val(null), $callToArray) : $callToArray)

src/CreateStructStatementsArgs.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Krak\StructGen;
44

55
use Krak\StructGen\Internal\OptionsMap;
6+
use Krak\StructGen\Internal\Props\ClassPropSet;
67
use PhpParser\BuilderFactory;
78
use PhpParser\Node\Stmt\Class_;
89
use PhpParser\PrettyPrinter;
@@ -13,12 +14,14 @@ final class CreateStructStatementsArgs
1314
private $factory;
1415
private $printer;
1516
private $class;
17+
private $props;
1618
private $options;
1719

1820
public function __construct(BuilderFactory $factory, PrettyPrinterAbstract $printer, Class_ $class, ?OptionsMap $options = null) {
1921
$this->factory = $factory;
2022
$this->printer = $printer;
2123
$this->class = $class;
24+
$this->props = ClassPropSet::fromClass($class);
2225
$this->options = $options ?: OptionsMap::empty();
2326
}
2427

@@ -43,6 +46,10 @@ public function class(): Class_ {
4346
return $this->class;
4447
}
4548

49+
public function props(): ClassPropSet {
50+
return $this->props;
51+
}
52+
4653
public function options(): OptionsMap {
4754
return $this->options;
4855
}

src/Internal/PropTypes.php

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,12 @@
99

1010
final class PropTypes
1111
{
12-
private function __construct() {}
13-
14-
/** @param Property[] $props */
15-
public static function getParamsDocCommentForProps(array $props): ?string {
16-
$partialDocComments = array_values(array_filter(array_map(function(Property $property) {
17-
$varDefinition = self::getVarDefinitionFromProperty($property);
18-
if (!$varDefinition) {
19-
return null;
20-
}
21-
22-
$type = (new TypeParser())->parse($varDefinition);
23-
return $type->toString() !== $type->toPhpString() ? '@param ' . $type->toString() . ' $' . $property->props[0]->name : null;
24-
}, $props)));
25-
if (!count($partialDocComments)) {
26-
return null;
27-
}
28-
29-
if (count($partialDocComments) === 1) {
30-
return "/** {$partialDocComments[0]} */";
31-
}
32-
33-
return "/**\n * " . implode("\n * ", $partialDocComments) . "\n */";
34-
}
35-
36-
public static function paramBuilderFromProp(BuilderFactory $builderFactory, PrettyPrinterAbstract $printer): \Closure {
37-
return function(Property $prop) use ($builderFactory, $printer): Param {
38-
$propName = (string) $prop->props[0]->name;
39-
$param = $builderFactory->param($propName);
40-
$varDef = PropTypes::getVarDefinitionFromProperty($prop);
41-
if ($varDef) {
42-
$type = (new TypeParser())->parse($varDef);
43-
$param->setType($type->toPhpString());
44-
}
45-
if ($prop->props[0]->default) {
46-
$param->setDefault($prop->props[0]->default);
47-
}
48-
return $param;
49-
};
12+
private function __construct() {
5013
}
5114

5215
/** Is the property's type an object that likely has it's own methods that can be called? */
5316
public static function canCallMethodsOnType(?UnionType $type): bool {
54-
if (!$type) {
17+
if (!$type || $type->isEmpty()) {
5518
return false;
5619
}
5720
if (count($type->atomicTypes()) > 1) {
@@ -60,20 +23,4 @@ public static function canCallMethodsOnType(?UnionType $type): bool {
6023
$atomicType = $type->atomicTypes()[0];
6124
return !$atomicType->isPrimitiveType();
6225
}
63-
64-
65-
public static function getVarDefinitionFromProperty(Property $prop): ?string {
66-
if (!$prop->getDocComment()) {
67-
return null;
68-
}
69-
70-
$docBlock = DocBlock::stripComments($prop->getDocComment()->getText());
71-
72-
$matches = [];
73-
if (!preg_match('/@var ((?:(?!\*\/).)+)(\*\/)?$/', $docBlock, $matches)) {
74-
return null;
75-
}
76-
77-
return trim($matches[1]);
78-
}
7926
}

0 commit comments

Comments
 (0)