Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
StringValueObjectSchemaProvider
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
4 / 4
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 supports
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 addDisplaySchemaFor
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addCreationSchemaFor
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
8
1<?php
2namespace Apie\SchemaGenerator\SchemaProviders;
3
4use Apie\Core\RegexUtils;
5use Apie\Core\ValueObjects\Interfaces\HasRegexValueObjectInterface;
6use Apie\Core\ValueObjects\Interfaces\LimitedOptionsInterface;
7use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
8use Apie\Core\ValueObjects\Interfaces\ValueObjectInterface;
9use Apie\Core\ValueObjects\Utils;
10use Apie\SchemaGenerator\Builders\ComponentsBuilder;
11use Apie\SchemaGenerator\Interfaces\SchemaProvider;
12use Apie\SchemaGenerator\Other\JsonSchemaFormatValidator;
13use cebe\openapi\spec\Components;
14use cebe\openapi\spec\Schema;
15use League\OpenAPIValidation\Schema\TypeFormats\FormatsContainer;
16use ReflectionClass;
17
18/**
19 * @implements SchemaProvider<StringValueObjectInterface>
20 */
21class StringValueObjectSchemaProvider implements SchemaProvider
22{
23    public function __construct(
24        private readonly int $maxEnumSize = 100
25    ) {
26    }
27
28    public function supports(ReflectionClass $class): bool
29    {
30        if (!in_array(ValueObjectInterface::class, $class->getInterfaceNames())) {
31            return false;
32        }
33        $returnType = (string) $class->getMethod('toNative')->getReturnType();
34        return $returnType === 'string' || $returnType === '?string';
35    }
36
37    public function addDisplaySchemaFor(
38        ComponentsBuilder $componentsBuilder,
39        string $componentIdentifier,
40        ReflectionClass $class,
41        bool $nullable = false
42    ): Components {
43        return $this->addCreationSchemaFor($componentsBuilder, $componentIdentifier, $class, $nullable);
44    }
45
46    public function addCreationSchemaFor(
47        ComponentsBuilder $componentsBuilder,
48        string $componentIdentifier,
49        ReflectionClass $class,
50        bool $nullable = false
51    ): Components {
52        $format = strtolower(Utils::getDisplayNameForValueObject($class));
53        if (class_exists(FormatsContainer::class) && !FormatsContainer::getFormat('string', $format)) {
54            FormatsContainer::registerFormat('string', $format, new JsonSchemaFormatValidator($class->name));
55        }
56        $schema = new Schema([
57            'type' => 'string',
58            'format' => $format,
59        ]);
60        ComponentsBuilder::addDescriptionOfObject($schema, $class);
61        if (in_array(HasRegexValueObjectInterface::class, $class->getInterfaceNames())) {
62            $className = $class->name;
63            $schema->pattern = RegexUtils::removeDelimiters($className::getRegularExpression());
64        }
65        if ($nullable) {
66            $schema->nullable = true;
67        }
68        if (in_array(LimitedOptionsInterface::class, $class->getInterfaceNames())) {
69            /** @var class-string<LimitedOptionsInterface> $className */
70            $className = $class->name;
71            $options = $className::getOptions();
72            if (count($options) > 0 && count($options) <= $this->maxEnumSize) {
73                $schema->enum = $options->toArray();
74            }
75        }
76        $componentsBuilder->setSchema($componentIdentifier, $schema);
77
78        return $componentsBuilder->getComponents();
79    }
80}