Skip to content

Commit

Permalink
Merge pull request #2 from php-soap/psalm
Browse files Browse the repository at this point in the history
Improve static analysis
  • Loading branch information
veewee authored Jun 6, 2024
2 parents 50d70ab + c9f8f69 commit 5a86b18
Show file tree
Hide file tree
Showing 47 changed files with 367 additions and 247 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/analyzers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Analyzers

on: [push, pull_request]
jobs:
run:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest]
php-versions: ['8.1', '8.2', '8.3']
fail-fast: false
name: PHP ${{ matrix.php-versions }} @ ${{ matrix.operating-system }}
steps:
- name: Checkout
uses: actions/checkout@master
- name: Install PHP
uses: shivammathur/setup-php@master
with:
php-version: ${{ matrix.php-versions }}
tools: 'composer:v2'
extensions: pcov, mbstring, posix, dom, soap
- name: Install dependencies
run: composer update --prefer-dist --no-progress --no-suggest ${{ matrix.composer-options }}
- name: Run the tests
run: ./vendor/bin/psalm
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"require": {
"php": "~8.1.0 || ~8.2.0 || ~8.3.0",
"azjezz/psl": "^2.9.0",
"veewee/reflecta": "^0.4.0",
"veewee/reflecta": "^0.5.0",
"veewee/xml": "^3.1",
"php-soap/engine": "^2.9.0",
"php-soap/wsdl": "^1.6",
Expand Down
13 changes: 12 additions & 1 deletion psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,15 @@
<directory name="vendor"/>
</ignoreFiles>
</projectFiles>
<plugins><pluginClass class="Psl\Psalm\Plugin"/></plugins></psalm>
<plugins>
<pluginClass class="Psl\Psalm\Plugin"/>
<pluginClass class="VeeWee\Reflecta\Psalm\Plugin"/>
</plugins>
<issueHandlers>
<PossiblyUnusedMethod>
<errorLevel type="suppress">
<directory name="src"/>
</errorLevel>
</PossiblyUnusedMethod>
</issueHandlers>
</psalm>
16 changes: 13 additions & 3 deletions src/Decoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Soap\Engine\Metadata\Metadata;
use Soap\WsdlReader\Model\Definitions\BindingUse;
use Soap\WsdlReader\Model\Definitions\Namespaces;
use function Psl\Type\non_empty_string;
use function Psl\Vec\map;

final class Decoder implements SoapDecoder
Expand All @@ -21,6 +22,9 @@ public function __construct(
) {
}

/**
* @psalm-return mixed
*/
public function decode(string $method, SoapResponse $response): mixed
{
$methodInfo = $this->metadata->getMethods()->fetchByName($method);
Expand All @@ -30,15 +34,21 @@ public function decode(string $method, SoapResponse $response): mixed
$returnType = $methodInfo->getReturnType();
$context = new Context($returnType, $this->metadata, $this->registry, $this->namespaces, $bindingUse);
$decoder = $this->registry->detectEncoderForContext($context);
$iso = $decoder->iso($context);

// The SoapResponse only contains the payload of the response (with no headers).
// It can be parsed directly as XML.
$parts = (new OperationReader($meta))($response->getPayload());
$parts = (new OperationReader($meta))(
non_empty_string()->assert($response->getPayload())
);

return match(count($parts)) {
0 => null,
1 => $decoder->iso($context)->from($parts[0]),
default => map($parts, $decoder->iso($context)->from(...)),
1 => $iso->from($parts[0]),
default => map(
$parts,
static fn (string $part): mixed => $iso->from($part)
),
};
}
}
6 changes: 4 additions & 2 deletions src/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static function createFromWsdl1(
Wsdl1 $wsdl,
?ServiceSelectionCriteria $serviceSelectionCriteria = null,
?EncoderRegistry $registry = null
) {
): self {
$registry ??= EncoderRegistry::default();
$metadataProvider = new Wsdl1MetadataProvider(
$wsdl,
Expand Down Expand Up @@ -54,7 +54,9 @@ public static function createFromMetadata(
);
}


/**
* @return mixed
*/
public function decode(string $method, SoapResponse $response)
{
return $this->decoder->decode($method, $response);
Expand Down
9 changes: 7 additions & 2 deletions src/Encoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use Soap\WsdlReader\Model\Definitions\EncodingStyle;
use Soap\WsdlReader\Model\Definitions\Namespaces;
use Soap\WsdlReader\Model\Definitions\SoapVersion;
use function Psl\Type\mixed;
use function Psl\Type\non_empty_string;
use function VeeWee\Reflecta\Lens\index;

final class Encoder implements SoapEncoder
Expand All @@ -31,15 +33,18 @@ public function encode(string $method, array $arguments): SoapRequest

$soapVersion = $meta->soapVersion()->map(SoapVersion::from(...))->unwrapOr(SoapVersion::SOAP_12);
$bindingUse = $meta->inputBindingUsage()->map(BindingUse::from(...))->unwrapOr(BindingUse::LITERAL);
$encodingStyle = $meta->inputEncodingStyle()->map(EncodingStyle::tryFrom(...));
$encodingStyle = $meta->inputEncodingStyle()->map(EncodingStyle::from(...));

$request = [];
foreach ($methodInfo->getParameters() as $index => $parameter) {
$type = $parameter->getType();
$context = new Context($type, $this->metadata, $this->registry, $this->namespaces, $bindingUse);
/** @var mixed $argument */
$argument = index($index)->get($arguments);

$request[] = $this->registry->detectEncoderForContext($context)->iso($context)->to($argument);
$request[] = non_empty_string()->assert(
$this->registry->detectEncoderForContext($context)->iso($context)->to($argument)
);
}

$operation = new OperationBuilder($meta, $this->namespaces, $request);
Expand Down
3 changes: 3 additions & 0 deletions src/Encoder/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

final class Context
{
/**
* TODO : READONLY !
*/
public function __construct(
public /*readonly*/ XsdType $type,
public /*readonly*/ Metadata $metadata,
Expand Down
14 changes: 10 additions & 4 deletions src/Encoder/ElementEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,38 @@
use VeeWee\Xml\Dom\Document;

/**
* @template T of mixed
* @implements XmlEncoder<string, T>
* @implements XmlEncoder<mixed, string>
*/
final class ElementEncoder implements XmlEncoder
{
/**
* @param XmlEncoder<string, T> $typeEncoder
* @param XmlEncoder<mixed, string> $typeEncoder
*/
public function __construct(
private readonly XmlEncoder $typeEncoder
) {
}

/**
* @return Iso<string, T>
* @return Iso<mixed, string>
*/
public function iso(Context $context): Iso
{
$typeEncoder = $this->typeEncoder;
$typeIso = $typeEncoder->iso($context);

return new Iso(
/**
* @psalm-param mixed $raw
*/
static fn (mixed $raw): string => (new XsdTypeXmlElementWriter())(
$context,
(new ElementValueBuilder($context, $typeIso, $raw))
),
/**
* @psalm-param non-empty-string $xml
* @psalm-return mixed
*/
static fn (string $xml): mixed => (new ElementValueReader())(
$context,
$typeEncoder,
Expand Down
8 changes: 5 additions & 3 deletions src/Encoder/EncoderDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
final class EncoderDetector
{
/**
* @return XmlEncoder<string, mixed>
* @return XmlEncoder<mixed, string>
*
* @psalm-suppress InvalidReturnType, PossiblyInvalidArgument, InvalidReturnStatement - The simple type detector could return string|null, but should not be an issue here.
*/
public function __invoke(Context $context): XmlEncoder
{
Expand All @@ -29,7 +31,7 @@ public function __invoke(Context $context): XmlEncoder
}

/**
* @return XmlEncoder<string, mixed>
* @return XmlEncoder<mixed, string>
*/
private function detectComplexTypeEncoder(XsdType $type, Context $context): XmlEncoder
{
Expand All @@ -43,7 +45,7 @@ private function detectComplexTypeEncoder(XsdType $type, Context $context): XmlE
// Try to find a match for the extended complex type:
// Or fallback to the default object encoder.
return $meta->extends()
->filter(static fn ($extend): bool => !$extend['isSimple'])
->filter(static fn ($extend): bool => !($extend['isSimple'] ?? false))
->map(static fn ($extends) : XmlEncoder => $context->registry->findComplexEncoderByNamespaceName(
$extends['namespace'],
$extends['type'],
Expand Down
21 changes: 16 additions & 5 deletions src/Encoder/ErrorHandlingEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,29 @@
use VeeWee\Reflecta\Iso\Iso;

/**
* @template I
* @template O
* @template-covariant TData
* @template-covariant TXml
*
* @implements XmlEncoder<I, O>
* @implements XmlEncoder<TData, TXml>
*
*/
final class ErrorHandlingEncoder implements XmlEncoder
{
/**
* @param XmlEncoder<I, O> $encoder
* @param XmlEncoder<TData, TXml> $encoder
*/
public function __construct(
private readonly XmlEncoder $encoder
) {
}

/**
* @return Iso<TData, TXml>
*/
public function iso(Context $context): Iso
{
$innerIso = $this->encoder->iso($context);
$buildPath = static function() use ($context): ?string {
$buildPath = static function () use ($context): ?string {
$meta = $context->type->getMeta();
$isElement = $meta->isElement()->unwrapOr(false);
$isAttribute = $meta->isAttribute()->unwrapOr(false);
Expand All @@ -44,13 +47,21 @@ public function iso(Context $context): Iso
};

return new Iso(
/**
* @psalm-param TData $value
* @psalm-return TXml
*/
static function (mixed $value) use ($innerIso, $context, $buildPath): mixed {
try {
return $innerIso->to($value);
} catch (Throwable $exception) {
throw EncodingException::encodingValue($value, $context->type, $exception, $buildPath());
}
},
/**
* @psalm-param TXml $value
* @psalm-return TData
*/
static function (mixed $value) use ($innerIso, $context, $buildPath): mixed {
try {
return $innerIso->from($value);
Expand Down
Loading

0 comments on commit 5a86b18

Please sign in to comment.