Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 2.7.0

* JSON Schema: Add support for generating property schema format for Url and Hostname (#4185)
* JSON Schema: Add support for generating property schema with Count restriction (#4186)
* JSON Schema: Manage Compound constraint when generating property metadata (#4180)
* Validator: Add an option to disable query parameter validation (#4165)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Hostname;
use Symfony\Component\Validator\Constraints\Ip;
use Symfony\Component\Validator\Constraints\Ulid;
use Symfony\Component\Validator\Constraints\Url;
use Symfony\Component\Validator\Constraints\Uuid;

/**
Expand All @@ -36,6 +38,14 @@ public function create(Constraint $constraint, PropertyMetadata $propertyMetadat
return ['format' => 'email'];
}

if ($constraint instanceof Url) {
return ['format' => 'uri'];
}

if ($constraint instanceof Hostname) {
return ['format' => 'hostname'];
}

if ($constraint instanceof Uuid) {
return ['format' => 'uuid'];
}
Expand All @@ -62,6 +72,6 @@ public function supports(Constraint $constraint, PropertyMetadata $propertyMetad
{
$schema = $propertyMetadata->getSchema();

return empty($schema['format']) && ($constraint instanceof Email || $constraint instanceof Uuid || $constraint instanceof Ulid || $constraint instanceof Ip);
return empty($schema['format']) && ($constraint instanceof Email || $constraint instanceof Url || $constraint instanceof Hostname || $constraint instanceof Uuid || $constraint instanceof Ulid || $constraint instanceof Ip);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Core\Tests\Bridge\Symfony\Validator\Metadata\Property\Restriction;

use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaFormat;
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
use ApiPlatform\Core\Tests\ProphecyTrait;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Hostname;
use Symfony\Component\Validator\Constraints\Ip;
use Symfony\Component\Validator\Constraints\Positive;
use Symfony\Component\Validator\Constraints\Ulid;
use Symfony\Component\Validator\Constraints\Url;
use Symfony\Component\Validator\Constraints\Uuid;

final class PropertySchemaFormatTest extends TestCase
{
use ProphecyTrait;

private $propertySchemaFormatRestriction;

protected function setUp(): void
{
$this->propertySchemaFormatRestriction = new PropertySchemaFormat();
}

/**
* @dataProvider supportsProvider
*/
public function testSupports(Constraint $constraint, PropertyMetadata $propertyMetadata, bool $expectedResult): void
{
self::assertSame($expectedResult, $this->propertySchemaFormatRestriction->supports($constraint, $propertyMetadata));
}

public function supportsProvider(): \Generator
{
yield 'email' => [new Email(), new PropertyMetadata(), true];
yield 'url' => [new Url(), new PropertyMetadata(), true];
if (class_exists(Hostname::class)) {
yield 'hostname' => [new Hostname(), new PropertyMetadata(), true];
}
yield 'uuid' => [new Uuid(), new PropertyMetadata(), true];
if (class_exists(Ulid::class)) {
yield 'ulid' => [new Ulid(), new PropertyMetadata(), true];
}
yield 'ip' => [new Ip(), new PropertyMetadata(), true];
yield 'not supported' => [new Positive(), new PropertyMetadata(), false];
}

/**
* @dataProvider createProvider
*/
public function testCreate(Constraint $constraint, PropertyMetadata $propertyMetadata, array $expectedResult): void
{
self::assertSame($expectedResult, $this->propertySchemaFormatRestriction->create($constraint, $propertyMetadata));
}

public function createProvider(): \Generator
{
yield 'email' => [new Email(), new PropertyMetadata(), ['format' => 'email']];
yield 'url' => [new Url(), new PropertyMetadata(), ['format' => 'uri']];
if (class_exists(Hostname::class)) {
yield 'hostname' => [new Hostname(), new PropertyMetadata(), ['format' => 'hostname']];
}
yield 'uuid' => [new Uuid(), new PropertyMetadata(), ['format' => 'uuid']];
if (class_exists(Ulid::class)) {
yield 'ulid' => [new Ulid(), new PropertyMetadata(), ['format' => 'ulid']];
}
yield 'ipv4' => [new Ip(['version' => '4']), new PropertyMetadata(), ['format' => 'ipv4']];
yield 'ipv6' => [new Ip(['version' => '6']), new PropertyMetadata(), ['format' => 'ipv6']];
yield 'not supported' => [new Positive(), new PropertyMetadata(), []];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@
use ApiPlatform\Core\Tests\Fixtures\DummyUniqueValidatedEntity;
use ApiPlatform\Core\Tests\Fixtures\DummyValidatedChoiceEntity;
use ApiPlatform\Core\Tests\Fixtures\DummyValidatedEntity;
use ApiPlatform\Core\Tests\Fixtures\DummyValidatedHostnameEntity;
use ApiPlatform\Core\Tests\Fixtures\DummyValidatedUlidEntity;
use ApiPlatform\Core\Tests\ProphecyTrait;
use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Validator\Constraints\AtLeastOneOf;
use Symfony\Component\Validator\Constraints\Compound;
use Symfony\Component\Validator\Constraints\Hostname;
use Symfony\Component\Validator\Constraints\Sequentially;
use Symfony\Component\Validator\Constraints\Ulid;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
Expand Down Expand Up @@ -318,36 +322,45 @@ public function testCreateWithPropertyRegexRestriction(): void
$this->assertEquals('dummy', $schema['pattern']);
}

public function testCreateWithPropertyFormatRestriction(): void
/**
* @dataProvider providePropertySchemaFormatCases
*/
public function testCreateWithPropertyFormatRestriction(string $property, string $class, array $expectedSchema): void
{
$validatorClassMetadata = new ClassMetadata(DummyValidatedEntity::class);
$validatorClassMetadata = new ClassMetadata($class);
(new AnnotationLoader(new AnnotationReader()))->loadClassMetadata($validatorClassMetadata);

$validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
$validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)
$validatorMetadataFactory->getMetadataFor($class)
->willReturn($validatorClassMetadata)
->shouldBeCalled();
$formats = [
'dummyEmail' => 'email',
'dummyUuid' => 'uuid',
'dummyIpv4' => 'ipv4',
'dummyIpv6' => 'ipv6',
];

foreach ($formats as $property => $format) {
$decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
$decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, $property, [])->willReturn(
new PropertyMetadata()
)->shouldBeCalled();
$validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
$validatorMetadataFactory->reveal(),
$decoratedPropertyMetadataFactory->reveal(),
[new PropertySchemaFormat()]
);
$schema = $validationPropertyMetadataFactory->create(DummyValidatedEntity::class, $property)->getSchema();
$this->assertNotNull($schema);
$this->assertArrayHasKey('format', $schema);
$this->assertEquals($format, $schema['format']);
$decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
$decoratedPropertyMetadataFactory->create($class, $property, [])->willReturn(
new PropertyMetadata()
)->shouldBeCalled();
$validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
$validatorMetadataFactory->reveal(),
$decoratedPropertyMetadataFactory->reveal(),
[new PropertySchemaFormat()]
);
$schema = $validationPropertyMetadataFactory->create($class, $property)->getSchema();

$this->assertSame($expectedSchema, $schema);
}

public function providePropertySchemaFormatCases(): \Generator
{
yield ['dummyEmail', DummyValidatedEntity::class, ['format' => 'email']];
yield ['dummyUuid', DummyValidatedEntity::class, ['format' => 'uuid']];
yield ['dummyIpv4', DummyValidatedEntity::class, ['format' => 'ipv4']];
yield ['dummyIpv6', DummyValidatedEntity::class, ['format' => 'ipv6']];
yield ['dummyUrl', DummyValidatedEntity::class, ['format' => 'uri']];
if (class_exists(Ulid::class)) {
yield ['dummyUlid', DummyValidatedUlidEntity::class, ['format' => 'ulid']];
}
if (class_exists(Hostname::class)) {
yield ['dummyHostname', DummyValidatedHostnameEntity::class, ['format' => 'hostname']];
}
}

Expand Down
7 changes: 7 additions & 0 deletions tests/Fixtures/DummyValidatedEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,11 @@ class DummyValidatedEntity
* @Assert\NotNull(groups={"dummy"})
*/
public $dummyGroup;

/**
* @var string A dummy url
*
* @Assert\Url
*/
public $dummyUrl;
}
26 changes: 26 additions & 0 deletions tests/Fixtures/DummyValidatedHostnameEntity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Core\Tests\Fixtures;

use Symfony\Component\Validator\Constraints as Assert;

class DummyValidatedHostnameEntity
{
/**
* @var string
*
* @Assert\Hostname
*/
public $dummyHostname;
}
26 changes: 26 additions & 0 deletions tests/Fixtures/DummyValidatedUlidEntity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Core\Tests\Fixtures;

use Symfony\Component\Validator\Constraints as Assert;

class DummyValidatedUlidEntity
{
/**
* @var string
*
* @Assert\Ulid
*/
public $dummyUlid;
}