From 46617f5f49411404e655e8b8c6faa8f108da4e00 Mon Sep 17 00:00:00 2001 From: ActualFab Date: Mon, 22 Apr 2024 00:59:56 +0200 Subject: [PATCH] Initial Upload --- .gitattributes | 108 ++++++++++++++++++++++++++++ .github/workflows/ci.yml | 38 ++++++++++ .github/workflows/qa.yml | 52 ++++++++++++++ .gitignore | 3 + LICENSE | 21 ++++++ README.md | 33 +++++++++ composer.json | 62 ++++++++++++++++ phpunit.xml | 17 +++++ pint.json | 77 ++++++++++++++++++++ src/Validator.php | 34 +++++++++ tests/Artifacts/Rules/Lowercase.php | 26 +++++++ tests/Artifacts/ValidatableDt0.php | 30 ++++++++ tests/ValidationTest.php | 70 ++++++++++++++++++ 13 files changed, 571 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/qa.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 composer.json create mode 100644 phpunit.xml create mode 100644 pint.json create mode 100644 src/Validator.php create mode 100644 tests/Artifacts/Rules/Lowercase.php create mode 100644 tests/Artifacts/ValidatableDt0.php create mode 100644 tests/ValidationTest.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..2116ae2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,108 @@ +# laravel default +*.css linguist-vendored +*.less linguist-vendored + +# These settings are for any web project + +# Handle line endings automatically for files detected as text +# and leave all files detected as binary untouched. +* text=auto + +# +# The above will handle all files NOT found below +# + +# +## These files are text and should be normalized (Convert crlf => lf) +# + +# source code +*.php text +*.css text +*.sass text +*.scss text +*.less text +*.styl text +*.js text +*.coffee text +*.json text +*.htm text +*.html text +*.xml text +*.svg text +*.txt text +*.ini text +*.inc text +*.pl text +*.rb text +*.py text +*.scm text +*.sql text +*.sh text +*.bat text + +# templates +*.ejs text +*.hbt text +*.jade text +*.haml text +*.hbs text +*.dot text +*.tmpl text +*.phtml text + +# server config +.htaccess text + +# git config +.gitattributes text +.gitignore text + +# code analysis config +.jshintrc text +.jscsrc text +.jshintignore text +.csslintrc text + +# misc config +*.yaml text +*.yml text +.editorconfig text + +# build config +*.npmignore text +*.bowerrc text + +# Heroku +Procfile text +.slugignore text + +# Documentation +*.md text +LICENSE text +AUTHORS text + +# +## These files are binary and should be left untouched +# + +# (binary is a macro for -text -diff) +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.mov binary +*.mp4 binary +*.mp3 binary +*.flv binary +*.fla binary +*.swf binary +*.gz binary +*.zip binary +*.7z binary +*.ttf binary +*.eot binary +*.woff binary +*.pyc binary +*.pdf binary diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6fee533 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI +on: [pull_request] +jobs: + tests: + name: Laravel Dt0 (PHP ${{ matrix.php-versions }}) + runs-on: ubuntu-latest + strategy: + matrix: + php-versions: [ '8.1', '8.2' ] + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, dom, fileinfo, gmp, bcmath + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Remove composer.lock + run: rm -f composer.lock + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Test with phpunit + run: vendor/bin/phpunit diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml new file mode 100644 index 0000000..531f8d8 --- /dev/null +++ b/.github/workflows/qa.yml @@ -0,0 +1,52 @@ +name: QA +on: + push: + branches: + - main + pull_request: + types: [ opened, synchronize ] +jobs: + tests: + name: Laravel Dt0 QA + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.1 + extensions: mbstring, dom, fileinfo, gmp, bcmath + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Remove composer.lock + run: rm -f composer.lock + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Check code style + run: vendor/bin/pint --config pint.json + + - name: Compute Coverage + run: vendor/bin/phpunit --coverage-clover ./coverage.xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + files: ./coverage.xml + flags: unittests + name: codecov-Dt0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbebd00 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor +.*.cache +composer.lock diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d312f8a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 fab2s + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2fc7c65 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# Laravel Dt0 + +[![CI](https://github.com/fab2s/laravel-dt0/actions/workflows/ci.yml/badge.svg)](https://github.com/fab2s/laravel-dt0/actions/workflows/ci.yml) [![CI](https://github.com/fab2s/laravel-dt0/actions/workflows/ci.yml/badge.svg)](https://github.com/fab2s/laravel-dt0/actions/workflows/ci.yml) + +Laravel support for [Dt0](https://github.com/fab2s/dt0), a DTO (_Data-Transport-Object_) PHP implementation than can both secure mutability and implement convenient ways to take control over input and output in various format. + +## Installation + +`Dt0` can be installed using composer: + +```shell +composer require "fab2s/dt0" +``` + +Once done, you can start playing : + +```php + +// either get a Dt0 instance or a ValidationException +$dt0 = SomeValidatableDt0::withValidation(...\Illuminate\Http\Request::all()); +``` + +## Requirements + +`Dt0` is tested against php 8.1 and 8.2 + +## Contributing + +Contributions are welcome, do not hesitate to open issues and submit pull requests. + +## License + +`Dt0` is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..2e71749 --- /dev/null +++ b/composer.json @@ -0,0 +1,62 @@ +{ + "name": "fab2s/laravel-dt0", + "description": "Laravel support for fab2s/dt0", + "type": "library", + "authors": [{ + "name": "Fabrice de Stefanis" + }], + "homepage": "https://github.com/fab2s/laravel-dt0", + "support": { + "issues": "https://github.com/fab2s/laravel-dt0/issues", + "source": "https://github.com/fab2s/laravel-dt0" + }, + "keywords": [ + "Laravel", + "Data-Transport-Object", + "DTO", + "DT0", + "symfony", + "laravel", + "PHP", + "Serializable", + "immutable", + "readonly", + "JSON", + "Data-Processing" + ], + "license": [ + "MIT" + ], + "require": { + "php": "^8.1", + "fab2s/dt0": "*", + "illuminate/translation": "^10.0|^11.0", + "illuminate/validation": "^10.0|^11.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0", + "laravel/pint": "^1.10", + "orchestra/testbench": "^8.0|^9.0" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "autoload": { + "psr-4": { + "fab2s\\Dt0\\Laravel\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "fab2s\\Dt0\\Laravel\\Tests\\": "tests" + } + }, + "scripts": { + "post-update-cmd": [ + "rm -rf .*.cache" + ], + "post-install-cmd": [ + "rm -rf .*.cache" + ], + "fix": "@php vendor/bin/pint --config pint.json" + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..8e81f97 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,17 @@ + + + + + + ./tests + + + + + + + + src/ + + + diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..6a53056 --- /dev/null +++ b/pint.json @@ -0,0 +1,77 @@ +{ + "preset": "laravel", + "rules": { + "header_comment": { + "header": "This file is part of fab2s/laravel-dt0.\n(c) Fabrice de Stefanis / https://github.com/fab2s/dt0\nThis source file is licensed under the MIT license which you will\nfind in the LICENSE file or at https://opensource.org/licenses/MIT" + }, + "assign_null_coalescing_to_coalesce_equal": true, + "binary_operator_spaces": { + "default": "align_single_space_minimal" + }, + "class_definition": true, + "blank_lines_before_namespace": true, + "align_multiline_comment": true, + "class_attributes_separation": { + "elements": { + "method": "one", + "const": "only_if_meta", + "property": "only_if_meta", + "trait_import": "only_if_meta" + } + }, + "concat_space": { + "spacing": "one" + }, + "global_namespace_import": { + "import_classes": true, + "import_functions": false, + "import_constants": false + }, + "no_superfluous_phpdoc_tags": true, + "method_argument_space": { + "on_multiline": "ensure_fully_multiline" + }, + "method_chaining_indentation": true, + "multiline_whitespace_before_semicolons": { + "strategy": "new_line_for_chained_calls" + }, + "operator_linebreak": { + "position": "beginning" + }, + "ordered_class_elements": { + "order": [ + "use_trait", + "constant", + "case", + "property", + "method" + ] + }, + "phpdoc_align": true, + "phpdoc_separation": { + "groups": [ + [ + "param" + ], + [ + "return" + ] + ] + }, + "php_unit_method_casing": { + "case": "snake_case" + }, + "return_type_declaration": true, + "simplified_null_return": true, + "single_trait_insert_per_statement": true, + "trailing_comma_in_multiline": { + "elements": [ + "parameters", + "arguments" + ] + } + }, + "exclude": [ + "vendor" + ] +} diff --git a/src/Validator.php b/src/Validator.php new file mode 100644 index 0000000..fa5932e --- /dev/null +++ b/src/Validator.php @@ -0,0 +1,34 @@ +rules)->validate(); + } + + public function addRule(string $name, Rule $rule): static + { + $this->rules[$name] = $rule->rule; + + return $this; + } +} diff --git a/tests/Artifacts/Rules/Lowercase.php b/tests/Artifacts/Rules/Lowercase.php new file mode 100644 index 0000000..6585b1c --- /dev/null +++ b/tests/Artifacts/Rules/Lowercase.php @@ -0,0 +1,26 @@ +assertSame($e->errors(), $expected); + + return; + } + + $this->assertEquals($args, $dt0->toArray()); + } + + public static function validationProvider(): array + { + return [ + [ + 'args' => [ + 'string' => 'UpPer', + 'int' => 'abc', + 'decimal' => 'def', + ], + 'expected' => [ + 'string' => [ + 'The string must be lowercase.' + ], + 'int' => [ + 'The int field must be an integer.' + ], + 'decimal' => [ + 'The decimal field must have 2 decimal places.' + ], + + ], + ], + [ + 'args' => [ + 'string' => 'lower', + 'int' => '28', + 'decimal' => '12.00', + ], + ], + ]; + } +}