From 6f5ad97e2e4b51f5237a2e3760a0e2524f1fe21f Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Wed, 7 Sep 2022 21:46:34 +0000 Subject: [PATCH 1/7] Removed tightrope from dependencies Signed-off-by: Tom Wright --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 2f3788f..2f90729 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,6 @@ "decodelabs/coercion": "^0.2.2", "decodelabs/dictum": "^0.4", "decodelabs/exceptional": "^0.4", - "decodelabs/tightrope": "^0.1.1", "decodelabs/veneer": "^0.9.2", "nesbot/carbon": "^2.25" From 9a31fcdd5d5d4340f709240b4d6d2f5f1f9402f3 Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 8 Sep 2022 08:15:54 +0000 Subject: [PATCH 2/7] Added Veneer stub Signed-off-by: Tom Wright --- composer.json | 12 +++++++----- stubs/DecodeLabs/Lucid.php | 12 ++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 stubs/DecodeLabs/Lucid.php diff --git a/composer.json b/composer.json index 2f90729..4c39611 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,9 @@ "php-parallel-lint/php-parallel-lint": "^1.3", "symplify/easy-coding-standard": "^11", - "decodelabs/phpstan-decodelabs": "^0.6" + "decodelabs/phpstan-decodelabs": "^0.6", + "decodelabs/atlas": "^0.10.1", + "decodelabs/terminus": "^0.8.3" }, "suggest": {}, "autoload": { @@ -52,10 +54,10 @@ "analyze": "phpstan analyze --no-progress", "ecs": "ecs check --no-progress-bar", "ecs-fix": "ecs check --no-progress-bar --fix", - "lint": "parallel-lint src/ tests/ ecs.php", - "eclint": "eclint check src/ tests/ ecs.php", - "eclint-fix": "eclint fix src/ tests/ ecs.php", - "non-ascii": "! LC_ALL=C.UTF-8 find src/ -type f -name \"*.php\" -print0 | xargs -0 -- grep -PHn \"[^ -~]\" | grep -v '// @ignore-non-ascii$'", + "lint": "parallel-lint src/ stubs/ tests/ ecs.php", + "eclint": "eclint check src/ stubs/ tests/ ecs.php", + "eclint-fix": "eclint fix src/ stubs/ tests/ ecs.php", + "non-ascii": "! LC_ALL=C.UTF-8 find src/ stubs/ tests/ -type f -name \"*.php\" -print0 | xargs -0 -- grep -PHn \"[^ -~]\" | grep -v '// @ignore-non-ascii$'", "check": [ "@composer update", "@analyze", diff --git a/stubs/DecodeLabs/Lucid.php b/stubs/DecodeLabs/Lucid.php new file mode 100644 index 0000000..3ad7bdc --- /dev/null +++ b/stubs/DecodeLabs/Lucid.php @@ -0,0 +1,12 @@ + Date: Thu, 8 Sep 2022 09:01:50 +0000 Subject: [PATCH 3/7] Moved Sanitizer Provider interfaces to lucid-support Signed-off-by: Tom Wright --- .github/workflows/integrate.yml | 2 +- CHANGELOG.md | 2 + composer.json | 11 ++- phpstan.neon | 1 - src/Lucid/Context.php | 93 ++----------------- src/Lucid/Sanitizer/MultiContextProvider.php | 62 ------------- .../Sanitizer/MultiContextProviderTrait.php | 70 -------------- src/Lucid/Sanitizer/SingleContextProvider.php | 59 ------------ .../Sanitizer/SingleContextProviderTrait.php | 66 ------------- tests/AnalyzeMultiContextProvider.php | 50 ---------- tests/AnalyzeSingleContextProvider.php | 48 ---------- 11 files changed, 18 insertions(+), 446 deletions(-) delete mode 100644 src/Lucid/Sanitizer/MultiContextProvider.php delete mode 100644 src/Lucid/Sanitizer/MultiContextProviderTrait.php delete mode 100644 src/Lucid/Sanitizer/SingleContextProvider.php delete mode 100644 src/Lucid/Sanitizer/SingleContextProviderTrait.php delete mode 100644 tests/AnalyzeMultiContextProvider.php delete mode 100644 tests/AnalyzeSingleContextProvider.php diff --git a/.github/workflows/integrate.yml b/.github/workflows/integrate.yml index 1a42dfc..e83e2a0 100644 --- a/.github/workflows/integrate.yml +++ b/.github/workflows/integrate.yml @@ -44,7 +44,7 @@ jobs: dependency-versions: "highest" - name: "Check source code for syntax errors" - run: "composer exec -- parallel-lint src/ ecs.php" + run: "composer exec -- parallel-lint src/ stubs/ ecs.php" # @TODO Check template files for syntax errors unit_tests: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1793e62..983affb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +* Moved Sanitizer Provider interfaces to lucid-support + ## v0.1.0 (2022-09-07) * Built initial Sanitizer structure * Added core Processor and Constraint types diff --git a/composer.json b/composer.json index 4c39611..cd45a12 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "decodelabs/coercion": "^0.2.2", "decodelabs/dictum": "^0.4", "decodelabs/exceptional": "^0.4", + "decodelabs/lucid-support": "^0.1", "decodelabs/veneer": "^0.9.2", "nesbot/carbon": "^2.25" @@ -42,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.1.x-dev" + "dev-develop": "0.2.x-dev" } }, "config": { @@ -54,10 +55,10 @@ "analyze": "phpstan analyze --no-progress", "ecs": "ecs check --no-progress-bar", "ecs-fix": "ecs check --no-progress-bar --fix", - "lint": "parallel-lint src/ stubs/ tests/ ecs.php", - "eclint": "eclint check src/ stubs/ tests/ ecs.php", - "eclint-fix": "eclint fix src/ stubs/ tests/ ecs.php", - "non-ascii": "! LC_ALL=C.UTF-8 find src/ stubs/ tests/ -type f -name \"*.php\" -print0 | xargs -0 -- grep -PHn \"[^ -~]\" | grep -v '// @ignore-non-ascii$'", + "lint": "parallel-lint src/ stubs/ ecs.php", + "eclint": "eclint check src/ stubs/ ecs.php", + "eclint-fix": "eclint fix src/ stubs/ ecs.php", + "non-ascii": "! LC_ALL=C.UTF-8 find src/ stubs/ -type f -name \"*.php\" -print0 | xargs -0 -- grep -PHn \"[^ -~]\" | grep -v '// @ignore-non-ascii$'", "check": [ "@composer update", "@analyze", diff --git a/phpstan.neon b/phpstan.neon index 85fc22a..b625587 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,4 @@ parameters: paths: - src/ - - tests/ level: max diff --git a/src/Lucid/Context.php b/src/Lucid/Context.php index 094b83b..85e3e84 100644 --- a/src/Lucid/Context.php +++ b/src/Lucid/Context.php @@ -9,92 +9,17 @@ namespace DecodeLabs\Lucid; -use Closure; -use DecodeLabs\Lucid\Constraint\NotFoundException as ConstraintNotFoundException; -use DecodeLabs\Lucid\Validate\Result; -use Exception; +use DecodeLabs\Lucid\Sanitizer\DirectContextProvider; +use DecodeLabs\Lucid\Sanitizer\DirectContextProviderTrait; -class Context +/** + * @template TValue + * @implements DirectContextProvider + */ +class Context implements DirectContextProvider { /** - * Apply sanitizer - * - * @template TValue - * @phpstan-param TValue $value - * @param array|Closure|null $setup - */ - public function make( - mixed $value, - string $type, - array|Closure|null $setup = null - ): mixed { - return $this->sanitize($value)->as($type, $setup); - } - - /** - * Force apply sanitizer - * - * @template TValue - * @phpstan-param TValue $value - * @param array|Closure|null $setup - */ - public function force( - mixed $value, - string $type, - array|Closure|null $setup = null - ): mixed { - return $this->sanitize($value)->forceAs($type, $setup); - } - - - /** - * Validate value via sanitizer - * - * @template TValue - * @phpstan-param TValue $value - * @param array|Closure|null $setup - * @return Result - */ - public function validate( - mixed $value, - string $type, - array|Closure|null $setup = null - ): Result { - return $this->sanitize($value)->validate($type, $setup); - } - - - /** - * Check value is valid - * - * @template TValue - * @phpstan-param TValue $value - * @param array|Closure|null $setup - */ - public function is( - mixed $value, - string $type, - array|Closure|null $setup = null - ): bool { - try { - return $this->validate($value, $type, $setup)->isValid(); - } catch (ConstraintNotFoundException $e) { - throw $e; - } catch (Exception $e) { - return false; - } - } - - - /** - * Create sanitizer - * - * @template TValue - * @phpstan-param TValue $value - * @phpstan-return Sanitizer + * @use DirectContextProviderTrait */ - public function sanitize(mixed $value): Sanitizer - { - return new Sanitizer($value); - } + use DirectContextProviderTrait; } diff --git a/src/Lucid/Sanitizer/MultiContextProvider.php b/src/Lucid/Sanitizer/MultiContextProvider.php deleted file mode 100644 index 5b17b61..0000000 --- a/src/Lucid/Sanitizer/MultiContextProvider.php +++ /dev/null @@ -1,62 +0,0 @@ -|Closure|null $setup - */ - public function getAs( - string $key, - string $type, - array|Closure|null $setup = null - ): mixed; - - /** - * @param array|Closure|null $setup - */ - public function forceAs( - string $key, - string $type, - array|Closure|null $setup = null - ): mixed; - - /** - * @param array|Closure|null $setup - * @return Result - */ - public function validate( - string $key, - string $type, - array|Closure|null $setup = null - ): Result; - - /** - * @param array|Closure|null $setup - */ - public function is( - string $key, - string $type, - array|Closure|null $setup = null - ): bool; - - /** - * @phpstan-return Sanitizer - */ - public function sanitize(string $key): Sanitizer; -} diff --git a/src/Lucid/Sanitizer/MultiContextProviderTrait.php b/src/Lucid/Sanitizer/MultiContextProviderTrait.php deleted file mode 100644 index db07c40..0000000 --- a/src/Lucid/Sanitizer/MultiContextProviderTrait.php +++ /dev/null @@ -1,70 +0,0 @@ -sanitize($key)->as($type, $setup); - } - - public function forceAs( - string $key, - string $type, - array|Closure|null $setup = null - ): mixed { - return $this->sanitize($key)->forceAs($type, $setup); - } - - public function validate( - string $key, - string $type, - array|Closure|null $setup = null - ): Result { - return $this->sanitize($key)->validate($type, $setup); - } - - public function is( - string $key, - string $type, - array|Closure|null $setup = null - ): bool { - try { - return $this->validate($key, $type, $setup)->isValid(); - } catch (ConstraintNotFoundException $e) { - throw $e; - } catch (Exception $e) { - return false; - } - } - - public function sanitize(string $key): Sanitizer - { - return new Sanitizer($this->getValue($key)); - } - - /** - * @phpstan-return TValue|null - */ - abstract protected function getValue(string $key): mixed; -} diff --git a/src/Lucid/Sanitizer/SingleContextProvider.php b/src/Lucid/Sanitizer/SingleContextProvider.php deleted file mode 100644 index 9eafb2c..0000000 --- a/src/Lucid/Sanitizer/SingleContextProvider.php +++ /dev/null @@ -1,59 +0,0 @@ -|Closure|null $setup - */ - public function as( - string $type, - array|Closure|null $setup = null - ): mixed; - - /** - * @param array|Closure|null $setup - */ - public function forceAs( - string $type, - array|Closure|null $setup = null - ): mixed; - - /** - * @param array|Closure|null $setup - * @return Result - */ - public function validate( - string $type, - array|Closure|null $setup = null - ): Result; - - /** - * @param array|Closure|null $setup - */ - public function is( - string $type, - array|Closure|null $setup = null - ): bool; - - - /** - * @phpstan-return Sanitizer - */ - public function sanitize(): Sanitizer; -} diff --git a/src/Lucid/Sanitizer/SingleContextProviderTrait.php b/src/Lucid/Sanitizer/SingleContextProviderTrait.php deleted file mode 100644 index 8d92581..0000000 --- a/src/Lucid/Sanitizer/SingleContextProviderTrait.php +++ /dev/null @@ -1,66 +0,0 @@ -sanitize()->as($type, $setup); - } - - public function forceAs( - string $type, - array|Closure|null $setup = null - ): mixed { - return $this->sanitize()->forceAs($type, $setup); - } - - public function validate( - string $type, - array|Closure|null $setup = null - ): Result { - return $this->sanitize()->validate($type, $setup); - } - - public function is( - string $type, - array|Closure|null $setup = null - ): bool { - try { - return $this->validate($type, $setup)->isValid(); - } catch (ConstraintNotFoundException $e) { - throw $e; - } catch (Exception $e) { - return false; - } - } - - public function sanitize(): Sanitizer - { - return new Sanitizer($this->getValue()); - } - - /** - * @phpstan-return TValue - */ - abstract protected function getValue(): mixed; -} diff --git a/tests/AnalyzeMultiContextProvider.php b/tests/AnalyzeMultiContextProvider.php deleted file mode 100644 index 0f7d5ca..0000000 --- a/tests/AnalyzeMultiContextProvider.php +++ /dev/null @@ -1,50 +0,0 @@ - - */ -class AnalyzeMultiContextProvider implements MultiContextProvider -{ - /** - * @use MultiContextProviderTrait - */ - use MultiContextProviderTrait; - - /** - * @phpstan-var array - */ - protected array $values; - - public function __construct( - string $key, - mixed $value - ) { - $this->values[$key] = $value; - } - - /** - * @phpstan-return TValue|null - */ - public function getValue(string $key): mixed - { - return $this->values[$key] ?? null; - } -} - - -// Test passing an Exception through -$test = new AnalyzeMultiContextProvider('value', new \Exception('test')); -$test->sanitize('value')->getValue()->getCode(); diff --git a/tests/AnalyzeSingleContextProvider.php b/tests/AnalyzeSingleContextProvider.php deleted file mode 100644 index 8060d45..0000000 --- a/tests/AnalyzeSingleContextProvider.php +++ /dev/null @@ -1,48 +0,0 @@ - - */ -class AnalyzeSingleContextProvider implements SingleContextProvider -{ - /** - * @use SingleContextProviderTrait - */ - use SingleContextProviderTrait; - - /** - * @phpstan-var TValue - */ - protected mixed $value; - - public function __construct(mixed $value) - { - $this->value = $value; - } - - /** - * @phpstan-return TValue - */ - public function getValue(): mixed - { - return $this->value; - } -} - - -// Test passing an Exception through -$test = new AnalyzeSingleContextProvider(new \Exception('test')); -$test->sanitize()->getValue()->getCode(); From c912c3f5c8a3c4fa4029368b076fe320d9e02482 Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 8 Sep 2022 09:30:12 +0000 Subject: [PATCH 4/7] Removed force* methods Signed-off-by: Tom Wright --- CHANGELOG.md | 3 + composer.json | 2 +- src/Lucid/Constraint.php | 7 +-- src/Lucid/Constraint/DateTime/Max.php | 9 --- src/Lucid/Constraint/DateTime/Min.php | 9 --- src/Lucid/Constraint/Interval/Max.php | 9 --- src/Lucid/Constraint/Interval/Min.php | 9 --- src/Lucid/Constraint/Number/Max.php | 12 ---- src/Lucid/Constraint/Number/Min.php | 12 ---- src/Lucid/Constraint/Processor.php | 40 +++++++++++++ src/Lucid/Constraint/String/Emojis.php | 9 --- src/Lucid/Constraint/String/MaxLength.php | 11 ---- src/Lucid/Constraint/String/MaxWords.php | 13 ----- src/Lucid/Constraint/String/MinLength.php | 5 -- src/Lucid/Constraint/String/Pattern.php | 16 ------ src/Lucid/ConstraintTrait.php | 16 +++--- src/Lucid/Error.php | 13 +++-- src/Lucid/Processor.php | 17 ++---- src/Lucid/Processor/BoolNative.php | 8 --- src/Lucid/Processor/Camel.php | 13 ----- src/Lucid/Processor/Date.php | 8 --- src/Lucid/Processor/Email.php | 70 +++++++++++++++++++++++ src/Lucid/Processor/FloatNative.php | 8 --- src/Lucid/Processor/IntNative.php | 8 --- src/Lucid/Processor/Interval.php | 8 --- src/Lucid/Processor/Name.php | 13 ----- src/Lucid/Processor/PathSlug.php | 13 ----- src/Lucid/Processor/Slug.php | 13 ----- src/Lucid/Processor/StringNative.php | 8 --- src/Lucid/ProcessorTrait.php | 20 ++++--- src/Lucid/Sanitizer.php | 21 +------ 31 files changed, 149 insertions(+), 274 deletions(-) create mode 100644 src/Lucid/Constraint/Processor.php create mode 100644 src/Lucid/Processor/Email.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 983affb..33ae5d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ * Moved Sanitizer Provider interfaces to lucid-support +* Removed force* methods +* Added Processor level validation hook +* Added Email Processor ## v0.1.0 (2022-09-07) * Built initial Sanitizer structure diff --git a/composer.json b/composer.json index cd45a12..c520766 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "decodelabs/coercion": "^0.2.2", "decodelabs/dictum": "^0.4", "decodelabs/exceptional": "^0.4", - "decodelabs/lucid-support": "^0.1", + "decodelabs/lucid-support": "^0.1.1", "decodelabs/veneer": "^0.9.2", "nesbot/carbon": "^2.25" diff --git a/src/Lucid/Constraint.php b/src/Lucid/Constraint.php index 8896a97..fa3af75 100644 --- a/src/Lucid/Constraint.php +++ b/src/Lucid/Constraint.php @@ -27,6 +27,7 @@ public function __construct(Processor $processor); */ public static function getProcessorOutputTypes(): ?array; + public function getName(): string; public function getWeight(): int; /** @@ -54,10 +55,4 @@ public function alterValue(mixed $value): mixed; * @phpstan-return Generator */ public function validate(mixed $value): Generator; - - /** - * @phpstan-param TValue $value - * @phpstan-return TValue - */ - public function constrain(mixed $value): mixed; } diff --git a/src/Lucid/Constraint/DateTime/Max.php b/src/Lucid/Constraint/DateTime/Max.php index 798cd79..c353519 100644 --- a/src/Lucid/Constraint/DateTime/Max.php +++ b/src/Lucid/Constraint/DateTime/Max.php @@ -65,13 +65,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if ($value->greaterThan($this->max)) { - $value = new Carbon('now'); - } - - return $value; - } } diff --git a/src/Lucid/Constraint/DateTime/Min.php b/src/Lucid/Constraint/DateTime/Min.php index 1b14199..a04bf0d 100644 --- a/src/Lucid/Constraint/DateTime/Min.php +++ b/src/Lucid/Constraint/DateTime/Min.php @@ -65,13 +65,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if ($value->lessThan($this->min)) { - $value = new Carbon('now'); - } - - return $value; - } } diff --git a/src/Lucid/Constraint/Interval/Max.php b/src/Lucid/Constraint/Interval/Max.php index 2eeb006..76d4ebd 100644 --- a/src/Lucid/Constraint/Interval/Max.php +++ b/src/Lucid/Constraint/Interval/Max.php @@ -65,13 +65,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if ($value->greaterThan($this->max)) { - $value = new CarbonInterval(); - } - - return $value; - } } diff --git a/src/Lucid/Constraint/Interval/Min.php b/src/Lucid/Constraint/Interval/Min.php index 2565f3e..213ec96 100644 --- a/src/Lucid/Constraint/Interval/Min.php +++ b/src/Lucid/Constraint/Interval/Min.php @@ -65,13 +65,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if ($value->lessThan($this->min)) { - $value = new CarbonInterval(); - } - - return $value; - } } diff --git a/src/Lucid/Constraint/Number/Max.php b/src/Lucid/Constraint/Number/Max.php index 64246b3..9e52399 100644 --- a/src/Lucid/Constraint/Number/Max.php +++ b/src/Lucid/Constraint/Number/Max.php @@ -58,16 +58,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if ( - $this->max !== null && - $value > $this->max - ) { - $value = $this->max; - } - - return $value; - } } diff --git a/src/Lucid/Constraint/Number/Min.php b/src/Lucid/Constraint/Number/Min.php index 8ec2775..8654c28 100644 --- a/src/Lucid/Constraint/Number/Min.php +++ b/src/Lucid/Constraint/Number/Min.php @@ -58,16 +58,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if ( - $this->min !== null && - $value < $this->min - ) { - $value = $this->min; - } - - return $value; - } } diff --git a/src/Lucid/Constraint/Processor.php b/src/Lucid/Constraint/Processor.php new file mode 100644 index 0000000..619e1a2 --- /dev/null +++ b/src/Lucid/Constraint/Processor.php @@ -0,0 +1,40 @@ + + */ +class Processor implements Constraint +{ + /** + * @phpstan-use ConstraintTrait + */ + use ConstraintTrait; + + public const OUTPUT_TYPES = []; + + public function getName(): string + { + return $this->processor->getName(); + } + + public function getWeight(): int + { + return 1; + } +} diff --git a/src/Lucid/Constraint/String/Emojis.php b/src/Lucid/Constraint/String/Emojis.php index 0df8245..6faf68e 100644 --- a/src/Lucid/Constraint/String/Emojis.php +++ b/src/Lucid/Constraint/String/Emojis.php @@ -71,13 +71,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if (!$this->emojis) { - $value = preg_replace(self::REGEX, '', $value) ?? $value; - } - - return $value; - } } diff --git a/src/Lucid/Constraint/String/MaxLength.php b/src/Lucid/Constraint/String/MaxLength.php index 27f70b9..56368e8 100644 --- a/src/Lucid/Constraint/String/MaxLength.php +++ b/src/Lucid/Constraint/String/MaxLength.php @@ -70,15 +70,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - $length = mb_strlen($value); - - if ($length > $this->length) { - $value = substr($value, 0, $this->length); - } - - return $value; - } } diff --git a/src/Lucid/Constraint/String/MaxWords.php b/src/Lucid/Constraint/String/MaxWords.php index 675ddd6..7176d74 100644 --- a/src/Lucid/Constraint/String/MaxWords.php +++ b/src/Lucid/Constraint/String/MaxWords.php @@ -71,17 +71,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - $words = Dictum::countWords($value); - - if ($words > $this->words) { - $parts = explode(' ', $value); - $parts = array_slice($parts, 0, $this->words); - $value = implode(' ', $parts); - } - - return $value; - } } diff --git a/src/Lucid/Constraint/String/MinLength.php b/src/Lucid/Constraint/String/MinLength.php index a85112c..f8f352a 100644 --- a/src/Lucid/Constraint/String/MinLength.php +++ b/src/Lucid/Constraint/String/MinLength.php @@ -70,9 +70,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - return str_pad($value, (int)$this->length, ' '); - } } diff --git a/src/Lucid/Constraint/String/Pattern.php b/src/Lucid/Constraint/String/Pattern.php index e9896c4..eb4e221 100644 --- a/src/Lucid/Constraint/String/Pattern.php +++ b/src/Lucid/Constraint/String/Pattern.php @@ -65,20 +65,4 @@ public function validate(mixed $value): Generator return true; } - - public function constrain(mixed $value): mixed - { - if ( - $this->pattern !== null && - !filter_var( - $value, - \FILTER_VALIDATE_REGEXP, - ['options' => ['regexp' => $this->pattern]] - ) - ) { - $value = ''; - } - - return $value; - } } diff --git a/src/Lucid/ConstraintTrait.php b/src/Lucid/ConstraintTrait.php index c0de775..252daac 100644 --- a/src/Lucid/ConstraintTrait.php +++ b/src/Lucid/ConstraintTrait.php @@ -10,6 +10,7 @@ namespace DecodeLabs\Lucid; use Generator; +use ReflectionClass; /** * @template TParam @@ -44,6 +45,12 @@ public static function getProcessorOutputTypes(): ?array return null; } + public function getName(): string + { + return (new ReflectionClass($this)) + ->getShortName(); + } + public function getWeight(): int { return 10; @@ -86,13 +93,4 @@ public function validate(mixed $value): Generator yield null; return true; } - - /** - * @phpstan-param TValue $value - * @phpstan-return TValue - */ - public function constrain(mixed $value): mixed - { - return $value; - } } diff --git a/src/Lucid/Error.php b/src/Lucid/Error.php index 851aee9..ebc3984 100644 --- a/src/Lucid/Error.php +++ b/src/Lucid/Error.php @@ -10,7 +10,7 @@ namespace DecodeLabs\Lucid; use DecodeLabs\Coercion; -use ReflectionClass; +use DecodeLabs\Lucid\Constraint\Processor as ProcessorConstraint; class Error { @@ -29,23 +29,26 @@ class Error protected string $constraintKey; /** - * @phpstan-param Constraint $constraint + * @phpstan-param Constraint|Processor $constraint * @param array $params */ public function __construct( - Constraint $constraint, + Constraint|Processor $constraint, mixed $value, string $message, array $params = [] ) { + if ($constraint instanceof Processor) { + $constraint = new ProcessorConstraint($constraint); + } + $this->constraint = $constraint; $this->value = $value; $this->message = $message; $this->params = $params; $this->constraintKey = lcfirst( - (new ReflectionClass($this->constraint)) - ->getShortName() + $this->constraint->getName() ); } diff --git a/src/Lucid/Processor.php b/src/Lucid/Processor.php index 54b7f65..9e872f3 100644 --- a/src/Lucid/Processor.php +++ b/src/Lucid/Processor.php @@ -53,13 +53,6 @@ public function alterValue(mixed $value): mixed; */ public function coerce(mixed $value): mixed; - /** - * Force coerce to output type - * - * @phpstan-return TOutput - */ - public function forceCoerce(mixed $value): mixed; - /** * Test validity of constraint @@ -90,13 +83,13 @@ public function prepareConstraints(): array; * @phpstan-param TOutput|null $value * @return Generator */ - public function validateConstraints(mixed $value): Generator; + public function validate(mixed $value): Generator; /** - * Apply constraints to coerced input + * Test type and yield errors in sequence * - * @phpstan-param TOutput $value - * @phpstan-return TOutput + * @phpstan-param TOutput|null $value + * @return Generator */ - public function constrain(mixed $value): mixed; + public function validateType(mixed $value): Generator; } diff --git a/src/Lucid/Processor/BoolNative.php b/src/Lucid/Processor/BoolNative.php index 0b7e27a..4358b0e 100644 --- a/src/Lucid/Processor/BoolNative.php +++ b/src/Lucid/Processor/BoolNative.php @@ -52,12 +52,4 @@ public function coerce(mixed $value): ?bool return Dictum::toBoolean($value); } - - /** - * Convert prepared value to bool - */ - public function forceCoerce(mixed $value): ?bool - { - return $this->coerce($value) ?? false; - } } diff --git a/src/Lucid/Processor/Camel.php b/src/Lucid/Processor/Camel.php index 770b977..39c5c0c 100644 --- a/src/Lucid/Processor/Camel.php +++ b/src/Lucid/Processor/Camel.php @@ -13,7 +13,6 @@ use DecodeLabs\Dictum; use DecodeLabs\Lucid\Processor; use DecodeLabs\Lucid\ProcessorTrait; -use Stringable; /** * @implements Processor @@ -39,19 +38,7 @@ public function coerce(mixed $value): ?string return null; } - if ($value instanceof Stringable) { - $value = (string)$value; - } - $string = Coercion::toString($value); return Dictum::camel($string); } - - /** - * Convert prepared value to string - */ - public function forceCoerce(mixed $value): ?string - { - return $this->coerce($value) ?? ''; - } } diff --git a/src/Lucid/Processor/Date.php b/src/Lucid/Processor/Date.php index dfd6dc1..983d85b 100644 --- a/src/Lucid/Processor/Date.php +++ b/src/Lucid/Processor/Date.php @@ -55,12 +55,4 @@ public function coerce(mixed $value): ?Carbon 'Unable to coerce value to DateTime' ); } - - /** - * Convert prepared value to DateTime - */ - public function forceCoerce(mixed $value): ?Carbon - { - return $this->coerce($value) ?? new Carbon('now'); - } } diff --git a/src/Lucid/Processor/Email.php b/src/Lucid/Processor/Email.php new file mode 100644 index 0000000..c7afb15 --- /dev/null +++ b/src/Lucid/Processor/Email.php @@ -0,0 +1,70 @@ + + */ +class Email implements Processor +{ + /** + * @phpstan-use ProcessorTrait + */ + use ProcessorTrait; + + public function getOutputTypes(): array + { + return ['string:email']; + } + + /** + * Convert prepared value to string or null + */ + public function coerce(mixed $value): ?string + { + if ($value === null) { + return null; + } + + $value = Coercion::toString($value); + + $value = strtolower($value); + $value = str_replace([' at ', ' dot '], ['@', '.'], $value); + + if (false === ($output = filter_var($value, \FILTER_SANITIZE_EMAIL))) { + $output = $value; + } + + return $output; + } + + + + public function validateType(mixed $value): Generator + { + if (!filter_var($value, \FILTER_VALIDATE_EMAIL)) { + yield new Error( + $this, + $value, + 'Value is not a valid email address' + ); + + return false; + } + + return true; + } +} diff --git a/src/Lucid/Processor/FloatNative.php b/src/Lucid/Processor/FloatNative.php index 188c60b..602c68b 100644 --- a/src/Lucid/Processor/FloatNative.php +++ b/src/Lucid/Processor/FloatNative.php @@ -39,12 +39,4 @@ public function coerce(mixed $value): ?float return Coercion::toFloat($value); } - - /** - * Convert prepared value to float - */ - public function forceCoerce(mixed $value): ?float - { - return Coercion::toFloatOrNull($value) ?? 0; - } } diff --git a/src/Lucid/Processor/IntNative.php b/src/Lucid/Processor/IntNative.php index c445d59..f780fb5 100644 --- a/src/Lucid/Processor/IntNative.php +++ b/src/Lucid/Processor/IntNative.php @@ -39,12 +39,4 @@ public function coerce(mixed $value): ?int return Coercion::toInt($value); } - - /** - * Convert prepared value to int - */ - public function forceCoerce(mixed $value): ?int - { - return Coercion::toIntOrNull($value) ?? 0; - } } diff --git a/src/Lucid/Processor/Interval.php b/src/Lucid/Processor/Interval.php index d42f9cb..b08ed31 100644 --- a/src/Lucid/Processor/Interval.php +++ b/src/Lucid/Processor/Interval.php @@ -70,12 +70,4 @@ public function coerce(mixed $value): ?CarbonInterval 'Unable to coerce value to DateTime' ); } - - /** - * Convert prepared value to DateTime - */ - public function forceCoerce(mixed $value): ?CarbonInterval - { - return $this->coerce($value) ?? new CarbonInterval(); - } } diff --git a/src/Lucid/Processor/Name.php b/src/Lucid/Processor/Name.php index 285601f..455e591 100644 --- a/src/Lucid/Processor/Name.php +++ b/src/Lucid/Processor/Name.php @@ -13,7 +13,6 @@ use DecodeLabs\Dictum; use DecodeLabs\Lucid\Processor; use DecodeLabs\Lucid\ProcessorTrait; -use Stringable; /** * @implements Processor @@ -46,19 +45,7 @@ public function coerce(mixed $value): ?string return null; } - if ($value instanceof Stringable) { - $value = (string)$value; - } - $string = Coercion::toString($value); return Dictum::name($string); } - - /** - * Convert prepared value to string - */ - public function forceCoerce(mixed $value): ?string - { - return $this->coerce($value) ?? ''; - } } diff --git a/src/Lucid/Processor/PathSlug.php b/src/Lucid/Processor/PathSlug.php index 965bb81..ed69089 100644 --- a/src/Lucid/Processor/PathSlug.php +++ b/src/Lucid/Processor/PathSlug.php @@ -13,7 +13,6 @@ use DecodeLabs\Dictum; use DecodeLabs\Lucid\Processor; use DecodeLabs\Lucid\ProcessorTrait; -use Stringable; /** * @implements Processor @@ -39,19 +38,7 @@ public function coerce(mixed $value): ?string return null; } - if ($value instanceof Stringable) { - $value = (string)$value; - } - $string = Coercion::toString($value); return Dictum::pathSlug($string); } - - /** - * Convert prepared value to string - */ - public function forceCoerce(mixed $value): ?string - { - return $this->coerce($value) ?? ''; - } } diff --git a/src/Lucid/Processor/Slug.php b/src/Lucid/Processor/Slug.php index 0785428..00a800b 100644 --- a/src/Lucid/Processor/Slug.php +++ b/src/Lucid/Processor/Slug.php @@ -13,7 +13,6 @@ use DecodeLabs\Dictum; use DecodeLabs\Lucid\Processor; use DecodeLabs\Lucid\ProcessorTrait; -use Stringable; /** * @implements Processor @@ -39,19 +38,7 @@ public function coerce(mixed $value): ?string return null; } - if ($value instanceof Stringable) { - $value = (string)$value; - } - $string = Coercion::toString($value); return Dictum::slug($string); } - - /** - * Convert prepared value to string - */ - public function forceCoerce(mixed $value): ?string - { - return $this->coerce($value) ?? ''; - } } diff --git a/src/Lucid/Processor/StringNative.php b/src/Lucid/Processor/StringNative.php index a8ede54..fa36876 100644 --- a/src/Lucid/Processor/StringNative.php +++ b/src/Lucid/Processor/StringNative.php @@ -59,12 +59,4 @@ public function coerce(mixed $value): ?string return Coercion::forceString($value); } - - /** - * Convert prepared value to string - */ - public function forceCoerce(mixed $value): ?string - { - return $this->coerce($value) ?? ''; - } } diff --git a/src/Lucid/ProcessorTrait.php b/src/Lucid/ProcessorTrait.php index 0748255..8d6536c 100644 --- a/src/Lucid/ProcessorTrait.php +++ b/src/Lucid/ProcessorTrait.php @@ -170,24 +170,28 @@ public function prepareConstraints(): array - public function validateConstraints(mixed $value): Generator + public function validate(mixed $value): Generator { + // Type validation + yield from $gen = $this->validateType($value); + + if (false === $gen->getReturn()) { + return; + } + + // Constraint validation foreach ($this->constraints as $constraint) { yield from $gen = $constraint->validate($value); if (false === $gen->getReturn()) { - break; + return; } } } - public function constrain(mixed $value): mixed + public function validateType(mixed $value): Generator { - foreach ($this->constraints as $constraint) { - $value = $constraint->constrain($value); - } - - return $value; + yield null; } } diff --git a/src/Lucid/Sanitizer.php b/src/Lucid/Sanitizer.php index 2661d58..10e1559 100644 --- a/src/Lucid/Sanitizer.php +++ b/src/Lucid/Sanitizer.php @@ -78,7 +78,7 @@ public function as( $value = $processor->alterValue($value); } - foreach ($gen = $processor->validateConstraints($value) as $error) { + foreach ($gen = $processor->validate($value) as $error) { if ($error === null) { continue; } @@ -93,23 +93,6 @@ public function as( } - /** - * Process value as type - * - * @param array|Closure|null $setup - */ - public function forceAs( - string $type, - array|Closure|null $setup = null - ): mixed { - $processor = $this->loadProcessor($type, $setup); - $value = $processor->prepareValue($this->value); - $value = $processor->forceCoerce($value); - $value = $processor->alterValue($value); - return $processor->constrain($value); - } - - /** * Validate value as type * @@ -130,7 +113,7 @@ public function validate( $result = new Result($processor); - foreach ($gen = $processor->validateConstraints($value) as $error) { + foreach ($gen = $processor->validate($value) as $error) { if ($error === null) { continue; } From 08af1e517f528485e8455e7daf8de29b94a08575 Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 8 Sep 2022 09:34:58 +0000 Subject: [PATCH 5/7] Added URL Processor Signed-off-by: Tom Wright --- src/Lucid/Processor/Email.php | 4 +- src/Lucid/Processor/Url.php | 73 +++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/Lucid/Processor/Url.php diff --git a/src/Lucid/Processor/Email.php b/src/Lucid/Processor/Email.php index c7afb15..292b874 100644 --- a/src/Lucid/Processor/Email.php +++ b/src/Lucid/Processor/Email.php @@ -52,7 +52,9 @@ public function coerce(mixed $value): ?string } - + /** + * Check email is valid + */ public function validateType(mixed $value): Generator { if (!filter_var($value, \FILTER_VALIDATE_EMAIL)) { diff --git a/src/Lucid/Processor/Url.php b/src/Lucid/Processor/Url.php new file mode 100644 index 0000000..9f74289 --- /dev/null +++ b/src/Lucid/Processor/Url.php @@ -0,0 +1,73 @@ + + */ +class Url implements Processor +{ + /** + * @phpstan-use ProcessorTrait + */ + use ProcessorTrait; + + public function getOutputTypes(): array + { + return ['string:url']; + } + + /** + * Convert prepared value to string or null + */ + public function coerce(mixed $value): ?string + { + if ($value === null) { + return null; + } + + $value = Coercion::toString($value); + + if (!preg_match('/^[a-zA-Z0-9]+\:/', $value)) { + $value = 'https://' . $value; + } + + if (false === ($output = filter_var($value, \FILTER_SANITIZE_URL))) { + $output = $value; + } + + return $output; + } + + + /** + * Check URL is valid + */ + public function validateType(mixed $value): Generator + { + if (!filter_var($value, \FILTER_VALIDATE_URL)) { + yield new Error( + $this, + $value, + 'Value is not a valid URL' + ); + + return false; + } + + return true; + } +} From 20b50b0c0b17aadac1a83a3fc8a3016fa1891bd8 Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 8 Sep 2022 09:40:04 +0000 Subject: [PATCH 6/7] Updated changelog Signed-off-by: Tom Wright --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33ae5d8..c883fbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ * Moved Sanitizer Provider interfaces to lucid-support * Removed force* methods * Added Processor level validation hook -* Added Email Processor +* Added Email & URL Processors ## v0.1.0 (2022-09-07) * Built initial Sanitizer structure From af7671e4a1783adf15ff4e2dc7a784ce4248695c Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 8 Sep 2022 09:40:42 +0000 Subject: [PATCH 7/7] Updated changelog Signed-off-by: Tom Wright --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c883fbc..87375cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## v0.1.0 (2022-09-08) * Moved Sanitizer Provider interfaces to lucid-support * Removed force* methods * Added Processor level validation hook