Skip to content

Commit

Permalink
Merge pull request #564 from veewee/default-prop-values-assembler
Browse files Browse the repository at this point in the history
Add property defaults assembler
  • Loading branch information
veewee authored Jan 10, 2025
2 parents 2ce8101 + c0ca1ce commit 23cfd66
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
14 changes: 14 additions & 0 deletions docs/code-generation/assemblers.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ to generate the code you want to add to the generated SOAP types.
- [IteratorAssembler](#iteratorassembler)
- [JsonSerializableAssembler](#jsonserializableassembler)
- [PropertyAssembler](#propertyassembler)
- [PropertyDefaultsAssembler](#propertydefaultsassembler)
- [RequestAssembler](#requestassembler)
- [ResultAssembler](#resultassembler)
- [ResultProviderAssembler](#resultproviderassembler)
Expand Down Expand Up @@ -317,6 +318,19 @@ new PropertyAssembler(PropertyGenerator::VISIBILITY_PROTECTED)
Please note that the default ruleset has a visibility of private.
If you want to override this, you will have to override all rules by calling `Phpro\SoapClient\CodeGenerator\Config\Config::setRuleSet`.

## PropertyDefaultsAssembler

This `PropertyDefaultsAssembler` can be used together with the default `PropertyAssembler` and can be used to determine basic default values for specific properties.
It adds default values for following scalar types: `string`, `int`, `float`, `bool`, `array`, `mixed`.

Example output:

```php
/**
* @var string
*/
private $prop1 = '';
```

## RequestAssembler

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Phpro\SoapClient\CodeGenerator\Assembler;

use Phpro\SoapClient\CodeGenerator\Context\ContextInterface;
use Phpro\SoapClient\CodeGenerator\Context\PropertyContext;
use Phpro\SoapClient\Exception\AssemblerException;
use function Psl\Result\wrap;

final class PropertyDefaultsAssembler implements AssemblerInterface
{
public function canAssemble(ContextInterface $context): bool
{
return $context instanceof PropertyContext;
}

/**
* @param ContextInterface|PropertyContext $context
*
* @throws AssemblerException
*/
public function assemble(ContextInterface $context): void
{
$class = $context->getClass();
$property = $context->getProperty();
$propertyGenerator = $class->getProperty($property->getName());
if (!$propertyGenerator) {
return;
}

if ($propertyGenerator->getDefaultValue()) {
return;
}

$defaultValue = wrap(
fn (): mixed => match ($property->getPhpType()) {
'mixed' => null,
'string' => '',
'int' => 0,
'bool' => false,
'float' => 0.0,
'array' => [],
default => throw new \RuntimeException('Type with unknown default: ' . $property->getPhpType())
}
);

if ($defaultValue->isFailed()) {
return;
}

$propertyGenerator
->setDefaultValue($defaultValue->getResult())
->omitDefaultValue(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

namespace PhproTest\SoapClient\Unit\CodeGenerator\Assembler;

use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface;
use Phpro\SoapClient\CodeGenerator\Assembler\PropertyAssembler;
use Phpro\SoapClient\CodeGenerator\Assembler\PropertyAssemblerOptions;
use Phpro\SoapClient\CodeGenerator\Assembler\PropertyDefaultsAssembler;
use Phpro\SoapClient\CodeGenerator\Context\PropertyContext;
use Phpro\SoapClient\CodeGenerator\Model\Property;
use Phpro\SoapClient\CodeGenerator\Model\Type;
use PHPUnit\Framework\TestCase;
use Laminas\Code\Generator\ClassGenerator;
use Soap\Engine\Metadata\Model\Property as EngineProperty;
use Soap\Engine\Metadata\Model\Property as MetaProperty;
use Soap\Engine\Metadata\Model\TypeMeta;
use Soap\Engine\Metadata\Model\XsdType;

class PropertyDefaultsAssemblerTest extends TestCase
{
/**
* @test
*/
function it_is_an_assembler()
{
$assembler = new PropertyDefaultsAssembler();
$this->assertInstanceOf(AssemblerInterface::class, $assembler);
}

/**
* @test
* @dataProvider provideAssemblerContexts
*/
function it_can_enhance_assembled_property_with_a_default_value(
PropertyContext $context,
string $expectedCode,
bool $skipPropertyGeneration = false,
): void {
if (!$skipPropertyGeneration) {
(new PropertyAssembler(PropertyAssemblerOptions::create()->withDocBlocks(false)))->assemble($context);
}
(new PropertyDefaultsAssembler())->assemble($context);

$code = $context->getClass()->generate();
$this->assertEquals($expectedCode, $code);
}

public static function provideAssemblerContexts(): iterable
{
$expectedOutput = <<<EOCODE
namespace MyNamespace;
class MyType
{
%s
}
EOCODE;

yield 'mixed' => [
self::createContext(self::configureProperty(XsdType::create('mixed'))),
sprintf($expectedOutput, 'private mixed $prop1 = null;')
];
yield 'string' => [
self::createContext(self::configureProperty(XsdType::create('string'))),
sprintf($expectedOutput, 'private string $prop1 = \'\';')
];
yield 'int' => [
self::createContext(self::configureProperty(XsdType::create('int'))),
sprintf($expectedOutput, 'private int $prop1 = 0;')
];
yield 'bool' => [
self::createContext(self::configureProperty(XsdType::create('bool'))),
sprintf($expectedOutput, 'private bool $prop1 = false;')
];
yield 'float' => [
self::createContext(self::configureProperty(XsdType::create('float'))),
sprintf($expectedOutput, 'private float $prop1 = 0;')
];
yield 'nullable-type' => [
self::createContext(self::configureProperty(XsdType::create('SomeClass')->withMeta(
static fn(TypeMeta $meta): TypeMeta => $meta->withIsNullable(true)
))),
sprintf($expectedOutput, 'private ?\ns1\SomeClass $prop1 = null;')
];
yield 'non-nullable-type' => [
self::createContext(self::configureProperty(XsdType::create('SomeClass'))),
sprintf($expectedOutput, 'private \ns1\SomeClass $prop1;')
];
yield 'without-known-property' => [
self::createContext(self::configureProperty(XsdType::create('SomeClass'))),
<<<EOCODE
namespace MyNamespace;
class MyType
{
}
EOCODE,
true
];
}

private static function configureProperty(XsdType $type): Property
{
return Property::fromMetaData('ns1', new MetaProperty('prop1', $type));
}

private static function createContext(Property $property): PropertyContext
{
$class = new ClassGenerator('MyType', 'MyNamespace');
$type = new Type('MyNamespace', 'MyType', 'MyType', [
$property
], XsdType::create('MyType'));

return new PropertyContext($class, $type, $property);
}
}

0 comments on commit 23cfd66

Please sign in to comment.