Skip to content

Commit

Permalink
Merge pull request #11 from zfegg/develop
Browse files Browse the repository at this point in the history
Fix register filter in validator.
  • Loading branch information
Moln committed Aug 4, 2021
2 parents 2c9a7d6 + beba21b commit 5bb39bb
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 30 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zfegg/content-validation",
"description": "Content validation for PSR-15 middleware or laminas-mvc",
"description": "Content validation for PSR-15 middleware",
"keywords": [
"validation",
"middleware",
Expand Down
14 changes: 14 additions & 0 deletions src/Factory/ValidatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use Opis\JsonSchema\Validator;
use Psr\Container\ContainerInterface;
use Zfegg\ContentValidation\Opis\Filter\DoctrineRecordExistsFilter;
use Zfegg\ContentValidation\Opis\Filter\RecordExistsFilter;
use Zfegg\ContentValidation\Opis\RemoveAdditionalPropertiesParser;
use Zfegg\ContentValidation\Opis\TypeCastParser;

Expand All @@ -20,6 +22,18 @@ public function __invoke(ContainerInterface $container): Validator
->prependKeyword(new RemoveAdditionalPropertiesParser())
;

$types = ['string', 'integer', 'number'];
$parser->getFilterResolver()->registerMultipleTypes(
'db-exists',
new RecordExistsFilter($container),
$types
);
$parser->getFilterResolver()->registerMultipleTypes(
'orm-exists',
new DoctrineRecordExistsFilter($container),
$types
);

return $validator;
}
}
34 changes: 21 additions & 13 deletions src/Opis/Filter/DoctrineRecordExistsFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,38 @@
use Opis\JsonSchema\Filter;
use Opis\JsonSchema\Schema;
use Opis\JsonSchema\ValidationContext;
use Psr\Container\ContainerInterface;

class DoctrineRecordExistsFilter implements Filter
{
private ContainerInterface $container;
private string $defaultId;

private EntityManagerInterface $em;

public function __construct(EntityManagerInterface $em)
public function __construct(ContainerInterface $container, string $defaultId = EntityManagerInterface::class)
{
$this->em = $em;
$this->container = $container;
$this->defaultId = $defaultId;
}

public function validate(ValidationContext $context, Schema $schema, array $args = []): bool
{
$criteria = $args['criteria'] ?? [];
$exists = $args['exists'] ?? false;

if (isset($args['field'])) {
$rs = $this->em->getRepository($args['entity'])->findOneBy(
[$args['field'] => $context->currentData()] + $criteria
);
/** @var EntityManagerInterface $em */
$em = $this->container->get($args['db'] ?? $this->defaultId);

if (isset($args['dql'])) {
$dql = $args['dql'];
} elseif (isset($args['entity'])) {
$field = isset($args['field']) ? 'o.' . $args['field'] : 'o';
$dql = sprintf('SELECT COUNT(o) FROM %s o WHERE %s=?1', $args['entity'], $field);
} else {
$rs = $this->em->find($args['entity'], $context->currentData());
throw new \InvalidArgumentException('Invalid args.');
}

return ((bool) $rs) == $exists;
$exists = $args['exists'] ?? false;
$query = $em->createQuery($dql);
$query->setParameter(1, $context->currentData());
$row = $query->getSingleScalarResult();

return $row == $exists;
}
}
13 changes: 9 additions & 4 deletions src/Opis/Filter/RecordExistsFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,24 @@
use Opis\JsonSchema\Schema;
use Opis\JsonSchema\ValidationContext;
use PDO;
use Psr\Container\ContainerInterface;

class RecordExistsFilter implements Filter
{

private PDO $db;
private ContainerInterface $container;
private string $defaultId;

public function __construct(PDO $db)
public function __construct(ContainerInterface $container, string $defaultId = 'db')
{
$this->db = $db;
$this->container = $container;
$this->defaultId = $defaultId;
}

public function validate(ValidationContext $context, Schema $schema, array $args = []): bool
{
$db = $this->container->get($args['db'] ?? $this->defaultId);

if (isset($args['sql'])) {
$sql = $args['sql'];
} elseif (isset($args['table']) && isset($args['field'])) {
Expand All @@ -30,7 +35,7 @@ public function validate(ValidationContext $context, Schema $schema, array $args
}

$exists = $args['exists'] ?? false;
$sth = $this->db->prepare($sql);
$sth = $db->prepare($sql);
$sth->execute([$context->currentData()]);
$row = $sth->fetch(PDO::FETCH_NUM);

Expand Down
33 changes: 27 additions & 6 deletions test/Opis/Filter/DoctrineRecordExistsFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,23 @@
namespace ZfeggTest\ContentValidation\Opis\Filter;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\Setup;
use Opis\JsonSchema\Schema;
use Opis\JsonSchema\SchemaLoader;
use Opis\JsonSchema\ValidationContext;
use Opis\JsonSchema\Validator;
use PHPUnit\Framework\TestCase;
use Zfegg\ContentValidation\Opis\Filter\DoctrineRecordExistsFilter;
use ZfeggTest\ContentValidation\Entity\Foo;
use ZfeggTest\ContentValidation\SetupTrait;

class DoctrineRecordExistsFilterTest extends TestCase
{
use SetupTrait {
setUp as setUpContainer;
}

const SQL = <<<SQL
create table foo
(
Expand All @@ -27,31 +34,45 @@ class DoctrineRecordExistsFilterTest extends TestCase

protected function setUp(): void
{
$this->setUpContainer();
$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration([__DIR__ . "/../../Entity"], $isDevMode);
$em = EntityManager::create(['url' => 'sqlite:///:memory:',], $config);
$em->getConnection()->prepare(self::SQL)->executeStatement();

$this->em = $em;
$em->getConnection()->prepare('INSERT INTO foo VALUES(NULL, "exists","123")')->executeStatement();
$this->container->setService(EntityManagerInterface::class, $em);
}

public function testValidate(): void
{
$filter = new DoctrineRecordExistsFilter($this->em);
$filter = new DoctrineRecordExistsFilter($this->container);
$entity = Foo::class;

$context = new ValidationContext('test', new SchemaLoader());
$schema = $this->createMock(Schema::class);
$rs = $filter->validate($context, $schema, ['entity' => Foo::class]);
$rs = $filter->validate($context, $schema, ['entity' => $entity]);
$this->assertTrue($rs);

$rs = $filter->validate($context, $schema, ['entity' => Foo::class, 'exists' => true]);
$rs = $filter->validate($context, $schema, ['entity' => $entity, 'exists' => true]);
$this->assertFalse($rs);

$rs = $filter->validate(
$context,
$schema,
['entity' => Foo::class, 'field' => 'key', 'criteria' => ['value' => 123]]
['dql' => "SELECT COUNT(o) FROM {$entity} o WHERE o.key=?1"]
);
$this->assertTrue($rs);
}

public function testInValidator(): void
{
$validator = $this->container->get(Validator::class);
$data = <<<'JSON'
{"key": "exists"}
JSON;
$data = json_decode($data);
$result = $validator->validate($data, 'test:test/test-doctrine-filter.json');

$this->assertTrue($result->isValid());
}
}
25 changes: 23 additions & 2 deletions test/Opis/Filter/RecordExistsFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
use Opis\JsonSchema\Schema;
use Opis\JsonSchema\SchemaLoader;
use Opis\JsonSchema\ValidationContext;
use Opis\JsonSchema\Validator;
use Zfegg\ContentValidation\Opis\Filter\RecordExistsFilter;
use PHPUnit\Framework\TestCase;
use ZfeggTest\ContentValidation\SetupTrait;

class RecordExistsFilterTest extends TestCase
{
use SetupTrait {
setUp as setUpContainer;
}

const SQL = <<<SQL
create table foo
(
Expand All @@ -24,14 +30,16 @@ class RecordExistsFilterTest extends TestCase

protected function setUp(): void
{
$this->setUpContainer();
$db = new \PDO('sqlite::memory:');
$db->query(self::SQL);
$this->db = $db;
$db->query('INSERT INTO foo VALUES(NULL, "exists","123")');
$this->container->setService('db', $db);
}

public function testValidate(): void
{
$filter = new RecordExistsFilter($this->db);
$filter = new RecordExistsFilter($this->container);

$context = new ValidationContext('test', new SchemaLoader());
$schema = $this->createMock(Schema::class);
Expand All @@ -44,4 +52,17 @@ public function testValidate(): void
$rs = $filter->validate($context, $schema, ['table' => 'foo', 'field' => 'key']);
$this->assertTrue($rs);
}


public function testInValidator(): void
{
$validator = $this->container->get(Validator::class);
$data = <<<'JSON'
{"key": "exists"}
JSON;
$data = json_decode($data);
$result = $validator->validate($data, 'test:test/test-db-filter.json');

$this->assertTrue($result->isValid());
}
}
3 changes: 1 addition & 2 deletions test/SetupTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@

use Laminas\ServiceManager\ServiceManager;
use Opis\JsonSchema\Validator;
use Psr\Container\ContainerInterface;
use Zfegg\ContentValidation\ConfigProvider;
use Zfegg\ContentValidation\ContentValidationMiddleware;

trait SetupTrait
{

private ContainerInterface $container;
private ServiceManager $container;

public function setUp(): void
{
Expand Down
22 changes: 22 additions & 0 deletions test/test-db-filter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"$filters": [
{
"$func": "db-exists",
"$vars": {
"table": "foo",
"field": "key",
"exists": true
}
}
]
}
},
"required": ["key"],
"additionalProperties": false
}
22 changes: 22 additions & 0 deletions test/test-doctrine-filter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"$filters": [
{
"$func": "orm-exists",
"$vars": {
"entity": "ZfeggTest\\ContentValidation\\Entity\\Foo",
"field": "key",
"exists": true
}
}
]
}
},
"required": ["key"],
"additionalProperties": false
}
3 changes: 1 addition & 2 deletions test/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"name": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"pattern": "^[a-zA-Z0-9\\-]+(\\s[a-zA-Z0-9\\-]+)*$"
"maxLength": 64
},
"age": {
"type": "integer",
Expand Down

0 comments on commit 5bb39bb

Please sign in to comment.