Skip to content

Commit 23cfd66

Browse files
authored
Merge pull request #564 from veewee/default-prop-values-assembler
Add property defaults assembler
2 parents 2ce8101 + c0ca1ce commit 23cfd66

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

docs/code-generation/assemblers.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ to generate the code you want to add to the generated SOAP types.
1919
- [IteratorAssembler](#iteratorassembler)
2020
- [JsonSerializableAssembler](#jsonserializableassembler)
2121
- [PropertyAssembler](#propertyassembler)
22+
- [PropertyDefaultsAssembler](#propertydefaultsassembler)
2223
- [RequestAssembler](#requestassembler)
2324
- [ResultAssembler](#resultassembler)
2425
- [ResultProviderAssembler](#resultproviderassembler)
@@ -317,6 +318,19 @@ new PropertyAssembler(PropertyGenerator::VISIBILITY_PROTECTED)
317318
Please note that the default ruleset has a visibility of private.
318319
If you want to override this, you will have to override all rules by calling `Phpro\SoapClient\CodeGenerator\Config\Config::setRuleSet`.
319320

321+
## PropertyDefaultsAssembler
322+
323+
This `PropertyDefaultsAssembler` can be used together with the default `PropertyAssembler` and can be used to determine basic default values for specific properties.
324+
It adds default values for following scalar types: `string`, `int`, `float`, `bool`, `array`, `mixed`.
325+
326+
Example output:
327+
328+
```php
329+
/**
330+
* @var string
331+
*/
332+
private $prop1 = '';
333+
```
320334

321335
## RequestAssembler
322336

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Phpro\SoapClient\CodeGenerator\Assembler;
4+
5+
use Phpro\SoapClient\CodeGenerator\Context\ContextInterface;
6+
use Phpro\SoapClient\CodeGenerator\Context\PropertyContext;
7+
use Phpro\SoapClient\Exception\AssemblerException;
8+
use function Psl\Result\wrap;
9+
10+
final class PropertyDefaultsAssembler implements AssemblerInterface
11+
{
12+
public function canAssemble(ContextInterface $context): bool
13+
{
14+
return $context instanceof PropertyContext;
15+
}
16+
17+
/**
18+
* @param ContextInterface|PropertyContext $context
19+
*
20+
* @throws AssemblerException
21+
*/
22+
public function assemble(ContextInterface $context): void
23+
{
24+
$class = $context->getClass();
25+
$property = $context->getProperty();
26+
$propertyGenerator = $class->getProperty($property->getName());
27+
if (!$propertyGenerator) {
28+
return;
29+
}
30+
31+
if ($propertyGenerator->getDefaultValue()) {
32+
return;
33+
}
34+
35+
$defaultValue = wrap(
36+
fn (): mixed => match ($property->getPhpType()) {
37+
'mixed' => null,
38+
'string' => '',
39+
'int' => 0,
40+
'bool' => false,
41+
'float' => 0.0,
42+
'array' => [],
43+
default => throw new \RuntimeException('Type with unknown default: ' . $property->getPhpType())
44+
}
45+
);
46+
47+
if ($defaultValue->isFailed()) {
48+
return;
49+
}
50+
51+
$propertyGenerator
52+
->setDefaultValue($defaultValue->getResult())
53+
->omitDefaultValue(false);
54+
}
55+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
namespace PhproTest\SoapClient\Unit\CodeGenerator\Assembler;
4+
5+
use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface;
6+
use Phpro\SoapClient\CodeGenerator\Assembler\PropertyAssembler;
7+
use Phpro\SoapClient\CodeGenerator\Assembler\PropertyAssemblerOptions;
8+
use Phpro\SoapClient\CodeGenerator\Assembler\PropertyDefaultsAssembler;
9+
use Phpro\SoapClient\CodeGenerator\Context\PropertyContext;
10+
use Phpro\SoapClient\CodeGenerator\Model\Property;
11+
use Phpro\SoapClient\CodeGenerator\Model\Type;
12+
use PHPUnit\Framework\TestCase;
13+
use Laminas\Code\Generator\ClassGenerator;
14+
use Soap\Engine\Metadata\Model\Property as EngineProperty;
15+
use Soap\Engine\Metadata\Model\Property as MetaProperty;
16+
use Soap\Engine\Metadata\Model\TypeMeta;
17+
use Soap\Engine\Metadata\Model\XsdType;
18+
19+
class PropertyDefaultsAssemblerTest extends TestCase
20+
{
21+
/**
22+
* @test
23+
*/
24+
function it_is_an_assembler()
25+
{
26+
$assembler = new PropertyDefaultsAssembler();
27+
$this->assertInstanceOf(AssemblerInterface::class, $assembler);
28+
}
29+
30+
/**
31+
* @test
32+
* @dataProvider provideAssemblerContexts
33+
*/
34+
function it_can_enhance_assembled_property_with_a_default_value(
35+
PropertyContext $context,
36+
string $expectedCode,
37+
bool $skipPropertyGeneration = false,
38+
): void {
39+
if (!$skipPropertyGeneration) {
40+
(new PropertyAssembler(PropertyAssemblerOptions::create()->withDocBlocks(false)))->assemble($context);
41+
}
42+
(new PropertyDefaultsAssembler())->assemble($context);
43+
44+
$code = $context->getClass()->generate();
45+
$this->assertEquals($expectedCode, $code);
46+
}
47+
48+
public static function provideAssemblerContexts(): iterable
49+
{
50+
$expectedOutput = <<<EOCODE
51+
namespace MyNamespace;
52+
53+
class MyType
54+
{
55+
%s
56+
}
57+
58+
EOCODE;
59+
60+
yield 'mixed' => [
61+
self::createContext(self::configureProperty(XsdType::create('mixed'))),
62+
sprintf($expectedOutput, 'private mixed $prop1 = null;')
63+
];
64+
yield 'string' => [
65+
self::createContext(self::configureProperty(XsdType::create('string'))),
66+
sprintf($expectedOutput, 'private string $prop1 = \'\';')
67+
];
68+
yield 'int' => [
69+
self::createContext(self::configureProperty(XsdType::create('int'))),
70+
sprintf($expectedOutput, 'private int $prop1 = 0;')
71+
];
72+
yield 'bool' => [
73+
self::createContext(self::configureProperty(XsdType::create('bool'))),
74+
sprintf($expectedOutput, 'private bool $prop1 = false;')
75+
];
76+
yield 'float' => [
77+
self::createContext(self::configureProperty(XsdType::create('float'))),
78+
sprintf($expectedOutput, 'private float $prop1 = 0;')
79+
];
80+
yield 'nullable-type' => [
81+
self::createContext(self::configureProperty(XsdType::create('SomeClass')->withMeta(
82+
static fn(TypeMeta $meta): TypeMeta => $meta->withIsNullable(true)
83+
))),
84+
sprintf($expectedOutput, 'private ?\ns1\SomeClass $prop1 = null;')
85+
];
86+
yield 'non-nullable-type' => [
87+
self::createContext(self::configureProperty(XsdType::create('SomeClass'))),
88+
sprintf($expectedOutput, 'private \ns1\SomeClass $prop1;')
89+
];
90+
yield 'without-known-property' => [
91+
self::createContext(self::configureProperty(XsdType::create('SomeClass'))),
92+
<<<EOCODE
93+
namespace MyNamespace;
94+
95+
class MyType
96+
{
97+
}
98+
99+
EOCODE,
100+
true
101+
];
102+
}
103+
104+
private static function configureProperty(XsdType $type): Property
105+
{
106+
return Property::fromMetaData('ns1', new MetaProperty('prop1', $type));
107+
}
108+
109+
private static function createContext(Property $property): PropertyContext
110+
{
111+
$class = new ClassGenerator('MyType', 'MyNamespace');
112+
$type = new Type('MyNamespace', 'MyType', 'MyType', [
113+
$property
114+
], XsdType::create('MyType'));
115+
116+
return new PropertyContext($class, $type, $property);
117+
}
118+
}

0 commit comments

Comments
 (0)