Skip to content

Commit

Permalink
Merge pull request #13 from zfegg/develop
Browse files Browse the repository at this point in the history
Add transformers keyword.
  • Loading branch information
Moln committed Aug 10, 2021
2 parents 87cee6f + 995b4c8 commit e3e14ef
Show file tree
Hide file tree
Showing 26 changed files with 782 additions and 36 deletions.
2 changes: 1 addition & 1 deletion LICENSE
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2016 Zend Framework Egg
Copyright (c) 2021 ZFEgg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -23,6 +23,7 @@
"doctrine/orm": "^2.9",
"laminas/laminas-diactoros": "^2.5",
"laminas/laminas-eventmanager": "^3.0",
"laminas/laminas-filter": "^2.11",
"laminas/laminas-servicemanager": "^3.7",
"mezzio/mezzio-router": "^3.0",
"phpspec/prophecy-phpunit": "^2.0",
Expand Down
4 changes: 2 additions & 2 deletions phpunit.xml
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./vendor/autoload.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./vendor/autoload.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.4/phpunit.xsd">
<coverage includeUncoveredFiles="true">
<include>
<directory suffix=".php">./src</directory>
Expand Down
1 change: 1 addition & 0 deletions src/ConfigProvider.php
Expand Up @@ -16,6 +16,7 @@ public function __invoke(): array
'factories' => [
ContentValidationMiddleware::class => ContentValidationMiddlewareFactory::class,
Validator::class => Factory\ValidatorFactory::class,
Opis\Resolver\TransformerResolver::class => Factory\TransformerResolverFactory::class,
]
]
];
Expand Down
24 changes: 24 additions & 0 deletions src/Factory/TransformerResolverFactory.php
@@ -0,0 +1,24 @@
<?php

declare(strict_types = 1);

namespace Zfegg\ContentValidation\Factory;

use Laminas\Filter\FilterPluginManager;
use Psr\Container\ContainerInterface;
use Zfegg\ContentValidation\Opis\Resolver\LaminasFilterResolver;
use Zfegg\ContentValidation\Opis\Resolver\TransformerResolver;

class TransformerResolverFactory
{
public function __invoke(ContainerInterface $container): TransformerResolver
{
$resolver = new TransformerResolver();

if ($container->has(FilterPluginManager::class)) {
$resolver->registerNS('laminas', new LaminasFilterResolver($container->get(FilterPluginManager::class)));
}

return $resolver;
}
}
6 changes: 5 additions & 1 deletion src/Factory/ValidatorFactory.php
Expand Up @@ -9,6 +9,8 @@
use Zfegg\ContentValidation\Opis\Filter\DoctrineRecordExistsFilter;
use Zfegg\ContentValidation\Opis\Filter\RecordExistsFilter;
use Zfegg\ContentValidation\Opis\RemoveAdditionalPropertiesParser;
use Zfegg\ContentValidation\Opis\Resolver\TransformerResolver;
use Zfegg\ContentValidation\Opis\TransformersParser;
use Zfegg\ContentValidation\Opis\TypeCastParser;

class ValidatorFactory
Expand All @@ -23,7 +25,9 @@ public function __invoke(ContainerInterface $container): Validator
foreach ($parser->supportedDrafts() as $draft) {
$parser->draft($draft)
->prependKeyword(new TypeCastParser())
->prependKeyword(new RemoveAdditionalPropertiesParser());
->prependKeyword(new RemoveAdditionalPropertiesParser())
->appendKeyword(new TransformersParser($container->get(TransformerResolver::class)))
;
}

if (isset($config['resolvers'])) {
Expand Down
10 changes: 10 additions & 0 deletions src/Opis/Helper.php
@@ -0,0 +1,10 @@
<?php

declare(strict_types = 1);

namespace Zfegg\ContentValidation\Opis;

class Helper
{
const JSON_ALL_TYPES = ['string', 'integer', 'number', 'boolean', 'null', 'object', 'array'];
}
Expand Up @@ -2,7 +2,7 @@

declare(strict_types = 1);

namespace Zfegg\ContentValidation\Opis;
namespace Zfegg\ContentValidation\Opis\Keyword;

use Opis\JsonSchema\Errors\ValidationError;
use Opis\JsonSchema\Keyword;
Expand Down
41 changes: 41 additions & 0 deletions src/Opis/Keyword/SetValueTrait.php
@@ -0,0 +1,41 @@
<?php

declare(strict_types = 1);

namespace Zfegg\ContentValidation\Opis\Keyword;

use Opis\JsonSchema\ValidationContext;

trait SetValueTrait
{

public function setValue(ValidationContext $context, callable $transform): void
{
$path = $context->currentDataPath();
$data = $context->rootData();

$target = $data;
foreach ($path as $key) {
if (is_object($target)) {
$target = &$target->{$key};
} else {
$target = &$target[$key];
}
}

$target = $transform($target);

$resetPath = [];
foreach (array_reverse($path) as $key) {
array_unshift($resetPath, $key);
$context->popDataPath();
if ($context->currentDataType() != 'array') {
break;
}
}

foreach ($resetPath as $key) {
$context->pushDataPath($key);
}
}
}
64 changes: 64 additions & 0 deletions src/Opis/Keyword/TransformerKeyword.php
@@ -0,0 +1,64 @@
<?php

declare(strict_types = 1);

namespace Zfegg\ContentValidation\Opis\Keyword;

use Opis\JsonSchema\Errors\ValidationError;
use Opis\JsonSchema\Exceptions\UnresolvedFilterException;
use Opis\JsonSchema\Keyword;
use Opis\JsonSchema\Keywords\ErrorTrait;
use Opis\JsonSchema\Schema;
use Opis\JsonSchema\ValidationContext;
use Zfegg\ContentValidation\Opis\Transformer\TransformerInterface;

class TransformerKeyword implements Keyword
{
use ErrorTrait;
use SetValueTrait;

/** @var array|object[] */
protected array $filters;

/**
* @param object[] $filters
*/
public function __construct(array $filters)
{
$this->filters = $filters;
}

/**
* @inheritDoc
*/
public function validate(ValidationContext $context, Schema $schema): ?ValidationError
{
$type = $context->currentDataType();
$data = $context->currentData();

foreach ($this->filters as $filter) {
if (! isset($filter->types[$type])) {
throw new UnresolvedFilterException($filter->name, $type, $schema, $context);
}

$func = $filter->types[$type];

if ($filter->args) {
$args = (array)$filter->args->resolve($context->rootData(), $context->currentDataPath());
$args += $context->globals();
} else {
$args = $context->globals();
}

if ($func instanceof TransformerInterface) {
$data = $func->transform($data, $context, $schema->info(), $args);
} else {
$data = $func($data, ...$args);
}
}

$this->setValue($context, fn() => $data);

return null;
}
}
22 changes: 4 additions & 18 deletions src/Opis/TypeCast.php → src/Opis/Keyword/TypeCast.php
Expand Up @@ -2,7 +2,7 @@

declare(strict_types = 1);

namespace Zfegg\ContentValidation\Opis;
namespace Zfegg\ContentValidation\Opis\Keyword;

use Opis\JsonSchema\Errors\ValidationError;
use Opis\JsonSchema\Keyword;
Expand All @@ -11,6 +11,8 @@

class TypeCast implements Keyword
{
use SetValueTrait;

private string $type;

public function __construct(string $type)
Expand All @@ -23,23 +25,7 @@ public function __construct(string $type)
*/
public function validate(ValidationContext $context, Schema $schema): ?ValidationError
{
$path = $context->currentDataPath();
$data = $context->rootData();

$target = $data;
foreach ($path as $key) {
if (is_object($target)) {
$target = &$target->{$key};
} else {
$target = &$target[$key];
}
}

$context->popDataPath();

$target = $this->castValue($target);

$context->pushDataPath($key);
$this->setValue($context, [$this, 'castValue']);

return null;
}
Expand Down
1 change: 1 addition & 0 deletions src/Opis/RemoveAdditionalPropertiesParser.php
Expand Up @@ -8,6 +8,7 @@
use Opis\JsonSchema\Keyword;
use Opis\JsonSchema\Parsers\KeywordParser;
use Opis\JsonSchema\Parsers\SchemaParser;
use Zfegg\ContentValidation\Opis\Keyword\RemoveAdditionalProperties;

class RemoveAdditionalPropertiesParser extends KeywordParser
{
Expand Down
36 changes: 36 additions & 0 deletions src/Opis/Resolver/LaminasFilterResolver.php
@@ -0,0 +1,36 @@
<?php

declare(strict_types = 1);

namespace Zfegg\ContentValidation\Opis\Resolver;

use Laminas\Filter\FilterPluginManager;
use Zfegg\ContentValidation\Opis\Transformer\LaminasTransformer;
use Zfegg\ContentValidation\Opis\Transformer\TransformerInterface;

class LaminasFilterResolver implements ResolverInterface
{
private FilterPluginManager $filterManager;

public function __construct(FilterPluginManager $filterManager)
{
$this->filterManager = $filterManager;
}

public function resolve(string $name, string $type): TransformerInterface
{
return new LaminasTransformer($this->filterManager, $name);
}

/**
* @return TransformerInterface[]|null
*/
public function resolveAll(string $name): ?array
{
$types = ['string', 'number', 'boolean', 'integer'];
return array_fill_keys(
$types,
new LaminasTransformer($this->filterManager, $name)
);
}
}

0 comments on commit e3e14ef

Please sign in to comment.