diff --git a/.github/ISSUE_TEMPLATE/Bug_report.yml b/.github/ISSUE_TEMPLATE/Bug_report.yml
index d7173ece8..6ae4bf5bd 100644
--- a/.github/ISSUE_TEMPLATE/Bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/Bug_report.yml
@@ -8,14 +8,14 @@ body:
attributes:
label: Apiato Core Version
description: Provide the Apiato Core version that you are using. [Please ensure it is still supported.](https://apiato.io/docs/prologue/release-notes#support-policy)
- placeholder: 8.x
+ placeholder: 13.x
validations:
required: true
- type: input
attributes:
label: PHP Version
description: Provide the PHP version that you are using.
- placeholder: 8.1.x
+ placeholder: 8.2.x
validations:
required: true
- type: input
diff --git a/.github/workflows/composer-quality.yaml b/.github/workflows/composer-quality.yaml
new file mode 100644
index 000000000..32ef9ad3a
--- /dev/null
+++ b/.github/workflows/composer-quality.yaml
@@ -0,0 +1,44 @@
+name: "Composer - quality"
+
+on:
+ push:
+ branches: [ master, '*.x' ]
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ composer-quality:
+ name: Composer Quality Checks
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.3'
+ extensions: dom, curl, libxml, mbstring, zip
+ coverage: none
+
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v3
+ with:
+ composer-options: --prefer-dist --optimize-autoloader
+
+ - name: Validate composer.json / composer.lock
+ run: composer validate --strict --no-check-publish --ansi
+
+ - name: Detect unused packages
+ run: vendor/bin/composer-unused --no-progress --ansi
diff --git a/.github/workflows/composer-security.yaml b/.github/workflows/composer-security.yaml
new file mode 100644
index 000000000..22b5f0ee4
--- /dev/null
+++ b/.github/workflows/composer-security.yaml
@@ -0,0 +1,47 @@
+name: "Composer - security audit"
+
+on:
+ push:
+ branches: [ master, '*.x' ]
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+ schedule:
+ - cron: '0 6 * * *' # daily at 06:00 UTC
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ composer-security:
+ name: Composer Security Audit
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.3'
+ extensions: dom, curl, libxml, mbstring, zip
+ coverage: none
+
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v3
+ with:
+ dependency-versions: locked
+ composer-options: --prefer-dist
+
+ - name: Run composer audit
+ run: composer audit --locked --ansi
+
+ - name: Run security check (roave/security-advisories)
+ run: composer update --dry-run --ansi --quiet --no-scripts --no-interaction roave/security-advisories
diff --git a/.github/workflows/matrix_includes.json b/.github/workflows/matrix_includes.json
index 78cb73101..3e16f9fdc 100644
--- a/.github/workflows/matrix_includes.json
+++ b/.github/workflows/matrix_includes.json
@@ -15,7 +15,7 @@
"runs_on": "ubuntu-latest",
"runOn":"master",
"php_version":"8.4",
- "php_unit_version": "phpunit:11.*"
+ "php_unit_version": "phpunit:12.*"
},
{
"runs_on": "ubuntu-latest",
@@ -33,18 +33,6 @@
"runs_on": "ubuntu-latest",
"runOn":"13.x",
"php_version":"8.4",
- "php_unit_version": "phpunit:11.*"
- },
- {
- "runs_on": "ubuntu-latest",
- "runOn":"8.x",
- "php_version":"8.1",
- "php_unit_version": "phpunit:10.*"
- },
- {
- "runs_on": "ubuntu-latest",
- "runOn":"8.x",
- "php_version":"8.2",
- "php_unit_version": "phpunit:10.*"
+ "php_unit_version": "phpunit:12.*"
}
]
diff --git a/.github/workflows/php-cs-fixer.yaml b/.github/workflows/php-cs-fixer.yaml
index bdf3f93a6..71c419cdb 100644
--- a/.github/workflows/php-cs-fixer.yaml
+++ b/.github/workflows/php-cs-fixer.yaml
@@ -1,35 +1,49 @@
-name: Check & fix styling
+name: "Linter - PHP-CS-Fixer"
on:
push:
- branches:
- - master
- - '*.x'
+ branches: [ master, '*.x' ]
pull_request:
types: [ opened, synchronize, reopened ]
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
php-cs-fixer:
name: PHP-CS-Fixer
runs-on: ubuntu-latest
- permissions:
- contents: write
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- - name: Use Cache
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.3'
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
+ coverage: none
+
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Cache PHP-CS-Fixer results
uses: actions/cache@v4
with:
path: .php-cs-fixer.cache
- key: ${{ runner.OS }}-${{ github.repository }}-phpcsfixer-${{ github.sha }}
+ key: ${{ runner.OS }}-${{ github.repository }}-php-cs-fixer-${{ github.sha }}
restore-keys: |
- ${{ runner.OS }}-${{ github.repository }}-phpcsfixer-
- - name: Run PHP CS Fixer
- uses: docker://oskarstark/php-cs-fixer-ga
- with:
- args: --config=.php-cs-fixer.dist.php
- - name: Commit changes
- uses: stefanzweifel/git-auto-commit-action@v4
+ ${{ runner.OS }}-${{ github.repository }}-php-cs-fixer-
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v3
with:
- commit_message: "style(automated): apply php-cs-fixer rules"
+ composer-options: --prefer-dist
+
+ - name: Run PHP-CS-Fixer
+ run: vendor/bin/php-cs-fixer fix --dry-run --format=txt --diff --allow-risky=yes --using-cache=yes --ansi -vv
diff --git a/.github/workflows/phpcs.yaml b/.github/workflows/phpcs.yaml
new file mode 100644
index 000000000..67e56eb26
--- /dev/null
+++ b/.github/workflows/phpcs.yaml
@@ -0,0 +1,49 @@
+name: "Linter - PHP_CodeSniffer"
+
+on:
+ push:
+ branches: [ master, '*.x' ]
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ phpcs:
+ name: PHP_CodeSniffer
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.3'
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
+ coverage: none
+
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Cache PHPCS results
+ uses: actions/cache@v4
+ with:
+ path: .phpcs-cache
+ key: ${{ runner.OS }}-${{ github.repository }}-phpcs-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.OS }}-${{ github.repository }}-phpcs-
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v3
+ with:
+ composer-options: --prefer-dist
+
+ - name: Run PHP_CodeSniffer
+ run: vendor/bin/phpcs -p --error-severity=1 --warning-severity=6 --colors --cache=.phpcs-cache
diff --git a/.github/workflows/phpmd.yaml b/.github/workflows/phpmd.yaml
index 48c0eb999..f47430256 100644
--- a/.github/workflows/phpmd.yaml
+++ b/.github/workflows/phpmd.yaml
@@ -1,25 +1,50 @@
-name: PHPMD
+name: "Linter - PHPMD"
on:
push:
- branches:
- - master
- - '*.x'
+ branches: [ master, '*.x' ]
pull_request:
types: [ opened, synchronize, reopened ]
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
phpmd:
- name: PHPMD
+ name: PHP Mess Detector
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- - name: Setup PHP environment
+
+ - name: Setup PHP
uses: shivammathur/setup-php@v2
with:
+ php-version: '8.3'
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
coverage: none
- tools: phpmd
+
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Cache PHPMD results
+ uses: actions/cache@v4
+ with:
+ path: .phpmd.result-cache.php
+ key: ${{ runner.OS }}-${{ github.repository }}-phpmd-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.OS }}-${{ github.repository }}-phpmd-
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v3
+ with:
+ composer-options: --prefer-dist
+
- name: Run PHPMD
- run: phpmd . github ruleset.xml --exclude 'tests/*,vendor/*'
+ run: vendor/bin/phpmd . github phpmd.ruleset.xml --ignore-violations-on-exit --color --cache
+
diff --git a/.github/workflows/phpstan.yaml b/.github/workflows/phpstan.yaml
new file mode 100644
index 000000000..ec15c8ddd
--- /dev/null
+++ b/.github/workflows/phpstan.yaml
@@ -0,0 +1,39 @@
+name: "Static analysis - PHPStan"
+
+on:
+ push:
+ branches: [ master, '*.x' ]
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ phpstan:
+ name: PHPStan Static Analysis
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v3
+ with:
+ composer-options: --prefer-dist
+
+ - name: Run PHPStan
+ uses: php-actions/phpstan@v3
+ with:
+ configuration: phpstan.neon
+ path: app/ config/ tests/ database/
+ version: 'composer'
+ php_version: '8.3'
diff --git a/.github/workflows/rector.yaml b/.github/workflows/rector.yaml
new file mode 100644
index 000000000..d29f03da5
--- /dev/null
+++ b/.github/workflows/rector.yaml
@@ -0,0 +1,52 @@
+name: "Refactor - Rector"
+
+on:
+ push:
+ branches: [ master, '*.x' ]
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ rector:
+ name: Rector Code Analysis
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.3'
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
+ coverage: none
+
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Prepare Rector cache directory
+ run: mkdir -p ./tmp/rector
+
+ - name: Cache Rector results
+ uses: actions/cache@v4
+ with:
+ path: ./tmp/rector
+ key: ${{ runner.OS }}-${{ github.repository }}-rector-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.OS }}-${{ github.repository }}-rector-
+
+ - name: Install Composer dependencies
+ uses: ramsey/composer-install@v3
+ with:
+ composer-options: --prefer-dist
+
+ - name: Run Rector Dry Run
+ run: vendor/bin/rector process --dry-run --no-progress-bar --output-format=github --ansi
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index c25980089..34319d256 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -1,15 +1,17 @@
-name: Tests
+name: "Test suite"
on:
push:
- branches:
- - master
- - '*.x'
+ branches: [ master, '*.x' ]
pull_request:
permissions:
contents: read
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
matrix_prep:
runs-on: ubuntu-latest
@@ -42,15 +44,30 @@ jobs:
coverage: xdebug
tools: ${{ matrix.php_unit_version }}
+ - name: Setup Composer token
+ run: composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Cache PHPUnit results
+ uses: actions/cache@v4
+ with:
+ path: .phpunit.result.cache
+ key: ${{ runner.OS }}-${{ github.repository }}-php-${{ matrix.php }}-phpunit-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.OS }}-${{ github.repository }}-php-${{ matrix.php }}-phpunit-
+
- name: Install Composer dependencies
- run: composer install --prefer-dist --no-interaction --no-progress
+ uses: ramsey/composer-install@v3
+ with:
+ composer-options: --prefer-dist
- name: Execute tests
- run: vendor/bin/pest --ci --coverage-clover=coverage.xml
+ run: vendor/bin/pest --ci --coverage-clover=coverage.xml --cache-directory=.phpunit.result.cache --order-by=random --colors=always --display-deprecations --display-incomplete --display-notices --display-warnings
- name: Upload coverage reports to Codecov
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
+ slug: apiato/core
+ files: coverage.xml
fail_ci_if_error: true
verbose: true
env:
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 4d592738a..ef1357e08 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -1,36 +1,142 @@
in([
- __DIR__ . '/src',
- __DIR__ . '/tests',
- __DIR__ . '/workbench',
- ])
- ->name('*.php')
- ->notName('*.blade.php')
- ->exclude([
- 'Support/Doubles/Fakes/Laravel/bootstrap',
- 'Support/Doubles/Fakes/Laravel/storage',
- ]);
-
-return (new PhpCsFixer\Config())
+declare(strict_types=1);
+
+/**
+ * @link https://mlocati.github.io/php-cs-fixer-configurator/
+ * @link https://cs.symfony.com/doc/usage.html
+ */
+/** Don't use finder for vscode. It will be slow. */
+$isVSCodeRun = isset($_SERVER['VSCODE_AGENT_FOLDER']);
+$finder = [];
+if ($isVSCodeRun === false) {
+ $finder = PhpCsFixer\Finder::create()
+ ->ignoreVCS(true)
+ ->ignoreDotFiles(true)
+ ->name('*.php')
+ ->notName(['*.blade.php'])
+ ->in([
+ __DIR__ . '/src',
+ __DIR__ . '/tests',
+ __DIR__ . '/workbench',
+ ])
+ ->ignoreVCSIgnored(true)
+ ->exclude([
+ 'Support/Doubles/Fakes/Laravel/bootstrap',
+ 'Support/Doubles/Fakes/Laravel/storage',
+ ]);
+}
+$config = new PhpCsFixer\Config();
+
+return $config
+ ->setRiskyAllowed(true)
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
->setRules([
- '@Symfony' => true,
- 'concat_space' => ['spacing' => 'one'],
- 'method_argument_space' => [
- 'on_multiline' => 'ensure_fully_multiline',
- ],
- 'phpdoc_align' => [
- 'align' => 'left',
- ],
- 'trailing_comma_in_multiline' => [
- 'elements' => ['arguments', 'arrays', 'match', 'parameters'],
+ // Global:
+ '@PSR12' => true,
+ 'psr_autoloading' => true,
+ 'single_quote' => true,
+ 'no_mixed_echo_print' => [
+ 'use' => 'echo',
],
- 'blank_line_before_statement' => [
- 'statements' => ['return', 'throw', 'try'],
- ],
- 'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => true],
- 'nullable_type_declaration' => ['syntax' => 'union'],
- ])
- ->setFinder($finder);
+ 'heredoc_to_nowdoc' => true,
+ 'increment_style' => ['style' => 'post'],
+ 'no_empty_statement' => true,
+ 'no_short_bool_cast' => true,
+ 'no_unneeded_control_parentheses' => true,
+ 'self_accessor' => true,
+ 'simplified_null_return' => false, // disabled by Shift
+ 'standardize_not_equals' => true,
+ 'simple_to_complex_string_variable' => true,
+ 'declare_strict_types' => true, // thinking about it
+ 'void_return' => false, // thinking about it
+ 'is_null' => false, // thinking about it
+ 'strict_comparison' => true,
+ 'strict_param' => true, // https://mlocati.github.io/php-cs-fixer-configurator/#version:3.2|fixer:strict_param
+ 'ordered_traits' => true,
+
+ // Disabled for any Global rules
+ 'phpdoc_no_alias_tag' => false,
+ 'phpdoc_types_order' => false,
+ 'phpdoc_tag_type' => false,
+ 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false],
+ 'single_line_throw' => false,
+ 'php_unit_test_case_static_method_calls' => false,
+ 'php_unit_test_annotation' => false,
+ 'php_unit_strict' => false,
+ 'php_unit_set_up_tear_down_visibility' => false,
+
+ // Function/Methods/Const:
+ 'magic_method_casing' => true, // added from Symfony
+ 'magic_constant_casing' => true,
+ 'native_function_casing' => true,
+ 'no_alias_functions' => true,
+ 'no_trailing_comma_in_singleline' => true,
+ 'combine_consecutive_unsets' => true,
+ 'explicit_indirect_variable' => true,
+ 'lambda_not_used_import' => true,
+
+ // Unit
+ 'php_unit_method_casing' => true,
+
+ // Import:
+ 'ordered_imports' => ['imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha'], //rewrite psr-12 rule
+ 'no_unused_imports' => true,
+ 'fully_qualified_strict_types' => true,
+ 'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced', 'strict' => true],
+
+ // Spacing/New Lines:
+ 'concat_space' => ['spacing' => 'one'],
+ 'cast_spaces' => false,
+ 'unary_operator_spaces' => false,
+ 'linebreak_after_opening_tag' => true,
+ 'blank_line_after_opening_tag' => true,
+ 'binary_operator_spaces' => ['default' => 'at_least_single_space', 'operators' => ['=>' => 'align_single_space_minimal']],
+ 'blank_line_before_statement' => ['statements' => ['return', 'do', 'exit', 'if', 'switch', 'try']],
+ 'no_extra_blank_lines' => ['tokens' => ['extra', 'throw', 'use']],
+ 'class_attributes_separation' => ['elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none']],
+ 'type_declaration_spaces' => true,
+ 'include' => true,
+ 'no_blank_lines_after_phpdoc' => true,
+ 'no_leading_namespace_whitespace' => true,
+ 'no_multiline_whitespace_around_double_arrow' => true,
+ 'multiline_whitespace_before_semicolons' => true,
+ 'no_singleline_whitespace_before_semicolons' => true,
+ 'no_spaces_around_offset' => true,
+ 'not_operator_with_successor_space' => false,
+ 'object_operator_without_whitespace' => true,
+ 'space_after_semicolon' => true,
+ 'method_argument_space' => true,
+ 'return_assignment' => true,
+ 'single_space_around_construct' => true,
+
+ // Array:
+ 'array_syntax' => ['syntax' => 'short'],
+ 'trim_array_spaces' => true,
+ 'whitespace_after_comma_in_array' => true,
+ 'no_whitespace_before_comma_in_array' => true,
+ 'normalize_index_brace' => true,
+ 'trailing_comma_in_multiline' => true,
+ 'array_indentation' => true,
+
+ // Comments:
+ 'align_multiline_comment' => ['comment_type' => 'phpdocs_like'],
+ 'single_line_comment_style' => ['comment_types' => ['hash']],
+
+ // PhpDocs:
+ 'phpdoc_to_comment' => false,
+ 'phpdoc_indent' => true,
+ 'no_empty_phpdoc' => true,
+ 'phpdoc_no_access' => true,
+ 'phpdoc_no_package' => true,
+ 'phpdoc_no_useless_inheritdoc' => true,
+ 'phpdoc_scalar' => true,
+ 'phpdoc_single_line_var_spacing' => true,
+ 'phpdoc_summary' => true,
+ 'phpdoc_trim' => true,
+ 'phpdoc_types' => true,
+ 'phpdoc_var_without_name' => true,
+ 'phpdoc_separation' => true,
+ 'phpdoc_align' => ['align' => 'vertical', 'tags' => ['param', 'property', 'property-read', 'property-write', 'return', 'throws', 'type', 'var', 'method']],
+ 'no_superfluous_phpdoc_tags' => true, // thinking about it
+ ])->setFinder($finder);
diff --git a/composer-unused.php b/composer-unused.php
new file mode 100644
index 000000000..a049f11e7
--- /dev/null
+++ b/composer-unused.php
@@ -0,0 +1,13 @@
+addNamedFilter(NamedFilter::fromString('apiato/container-installer'));
+
+ return $config;
+};
diff --git a/composer.json b/composer.json
index de6a0cbd3..2daee8278 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,8 @@
{
"name": "apiato/core",
"description": "Core package for Apiato.",
+ "license": "MIT",
+ "type": "library",
"keywords": [
"apiato",
"apiato core",
@@ -8,12 +10,6 @@
"Porto",
"Porto SAP"
],
- "license": "MIT",
- "homepage": "https://apiato.io/",
- "support": {
- "issues": "https://github.com/apiato/core/issues",
- "source": "https://github.com/apiato/core"
- },
"authors": [
{
"name": "Mahmoud Zalt",
@@ -27,43 +23,56 @@
"role": "Developer"
}
],
+ "homepage": "https://apiato.io/",
+ "support": {
+ "issues": "https://github.com/apiato/core/issues",
+ "source": "https://github.com/apiato/core"
+ },
"require": {
"php": "^8.2",
"apiato/container-installer": "^2.0.8",
"composer/class-map-generator": "^1.5",
- "laravel/framework": "^11.23|^12.0",
+ "laravel/framework": "^11.23 || ^12.0",
"laravel/tinker": "^2.0",
"prettus/l5-repository": "^2.9.1",
"spatie/laravel-fractal": "^6.3.1",
"thecodingmachine/safe": "^3.0",
- "vinkla/hashids": "^12.0|^13.0",
+ "vinkla/hashids": "^12.0 || ^13.0",
"webmozart/assert": "^1.11"
},
"require-dev": {
- "fakerphp/faker": "^1.19.1",
- "friendsofphp/php-cs-fixer": "^3.0",
+ "driftingly/rector-laravel": "^2.0",
+ "fakerphp/faker": "^1.24",
+ "friendsofphp/php-cs-fixer": "^3.8.0",
+ "icanhazstring/composer-unused": "^0.9.3",
"jetbrains/phpstorm-attributes": "^1.0",
"larastan/larastan": "^3.0",
- "mockery/mockery": "^1.4.4",
- "nunomaduro/collision": "^8.0",
+ "mockery/mockery": "^1.6",
+ "nunomaduro/collision": "^8.5",
"orchestra/testbench": "^9.0|^10.0",
"pestphp/pest": "^3.7",
"pestphp/pest-plugin-faker": "^3.0",
"pestphp/pest-plugin-type-coverage": "^3.2",
"phpmd/phpmd": "@stable",
+ "phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.1",
+ "phpstan/phpstan-mockery": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0",
"rector/rector": "^2.0",
"roave/security-advisories": "dev-latest",
+ "slevomat/coding-standard": "^8.15",
+ "squizlabs/php_codesniffer": "^3.12",
"thecodingmachine/phpstan-safe-rule": "^1.3"
},
+ "minimum-stability": "stable",
+ "prefer-stable": true,
"autoload": {
"psr-4": {
"Apiato\\": "src/"
},
"files": [
- "src/Foundation/helpers.php"
+ "src/Foundation/helpers.php"
]
},
"autoload-dev": {
@@ -72,6 +81,20 @@
"Workbench\\App\\": "workbench/app/"
}
},
+ "config": {
+ "allow-plugins": {
+ "apiato/container-installer": true,
+ "composer/package-versions-deprecated": true,
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true,
+ "phpstan/extension-installer": true,
+ "wikimedia/composer-merge-plugin": true
+ },
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true
+ },
"extra": {
"laravel": {
"providers": [
@@ -80,22 +103,22 @@
}
},
"scripts": {
- "artisan": [
- "@php vendor/bin/testbench"
- ],
- "fixer": "php-cs-fixer fix --config=./.php-cs-fixer.dist.php",
- "phpstan": [
- "./vendor/bin/phpstan analyse"
- ],
"post-autoload-dump": [
"@clear",
"@prepare"
],
+ "artisan": [
+ "@php vendor/bin/testbench"
+ ],
"clear": "@php vendor/bin/testbench package:purge-skeleton --ansi",
- "prepare": "@php vendor/bin/testbench package:discover --ansi",
+ "fixer": "php-cs-fixer fix --config=./.php-cs-fixer.dist.php",
"lint": [
"@php vendor/bin/phpstan analyse --verbose --ansi"
],
+ "phpstan": [
+ "./vendor/bin/phpstan analyse"
+ ],
+ "prepare": "@php vendor/bin/testbench package:discover --ansi",
"test": [
"@clear",
"@php vendor/bin/pest"
@@ -103,19 +126,5 @@
},
"scripts-descriptions": {
"phpstan": "Run PHPStan static analysis against your application."
- },
- "config": {
- "optimize-autoloader": true,
- "preferred-install": "dist",
- "sort-packages": true,
- "allow-plugins": {
- "apiato/container-installer": true,
- "composer/package-versions-deprecated": true,
- "wikimedia/composer-merge-plugin": true,
- "pestphp/pest-plugin": true,
- "php-http/discovery": true
- }
- },
- "minimum-stability": "stable",
- "prefer-stable": true
+ }
}
diff --git a/config/apiato.php b/config/apiato.php
index 14022ac04..f5b851403 100644
--- a/config/apiato.php
+++ b/config/apiato.php
@@ -1,5 +1,9 @@
[
'web' => [
- 'class' => \App\Ship\Apps\Web::class,
+ 'class' => Web::class,
'url' => env('FRONTEND_URL', env('APP_URL', 'http://localhost:3000')),
],
],
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 000000000..41ad3bc52
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,786 @@
+
+
+ PHP Code Style
+
+
+
+
+
+
+
+
+
+
+
+
+
+ config
+ src
+ tests
+ workbench
+
+
+
+ vendor
+ workbench/bootstrap
+ *\.blade\.php$
+
+
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ warning
+
+
+ warning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ workbench/app/Containers/*/*/Data/Seeders/*_\d+.php
+
+
+
+
+ workbench/app/Containers/*/*/Data/Seeders/*_\d+.php
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please review this TODO comment: %s
+ warning
+
+
+
+ Please review this FIXME comment: %s
+ warning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+
+
+
+ tests/*.php
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+ warning
+
+
+
+ warning
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+ warning
+
+
+
+
+
+
+ warning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpmd.baseline.xml b/phpmd.baseline.xml
new file mode 100644
index 000000000..676452fb7
--- /dev/null
+++ b/phpmd.baseline.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpmd.ruleset.xml b/phpmd.ruleset.xml
new file mode 100644
index 000000000..da23e5348
--- /dev/null
+++ b/phpmd.ruleset.xml
@@ -0,0 +1,94 @@
+
+
+
+
+ Apiato PHPMD rulesets
+
+
+ phpstan_cache/*
+ vendor/*
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+ 3
+
+
+
+
+ 2
+
+
+
+
+
+
+ 2
+
+
+
+
+ 2
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+
+ 2
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 000000000..661b6a8c5
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,4177 @@
+parameters:
+ ignoreErrors:
+ -
+ message: '#^Call to an undefined method PhpCsFixer\\ConfigInterface\:\:setParallelConfig\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: .php-cs-fixer.dist.php
+
+ -
+ message: '#^Cannot call method setFinder\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: .php-cs-fixer.dist.php
+
+ -
+ message: '#^Cannot call method setRules\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: .php-cs-fixer.dist.php
+
+ -
+ message: '#^Called ''env'' outside of the config directory which returns null when the config is cached, use ''config''\.$#'
+ identifier: larastan.noEnvCallsOutsideOfConfig
+ count: 8
+ path: config/apiato.php
+
+ -
+ message: '#^Class App\\Ship\\Apps\\Web not found\.$#'
+ identifier: class.notFound
+ count: 1
+ path: config/apiato.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Console\\Commands\\ListActions\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Console/Commands/ListActions.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Console\\Commands\\ListTasks\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Console/Commands/ListTasks.php
+
+ -
+ message: '#^Call to an undefined method Apiato\\Core\\Actions\\Action\:\:run\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: src/Core/Actions/Action.php
+
+ -
+ message: '#^Method Apiato\\Core\\Actions\\Action\:\:transactionalRun\(\) has parameter \$args with no type specified\.$#'
+ identifier: missingType.parameter
+ count: 1
+ path: src/Core/Actions/Action.php
+
+ -
+ message: '#^Dynamic call to static method Illuminate\\Database\\Eloquent\\Builder\\:\:first\(\)\.$#'
+ identifier: staticMethod.dynamicCall
+ count: 1
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Method Apiato\\Core\\Models\\BaseModel\:\:getHashedKey\(\) should return int\|string\|null but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Method Apiato\\Core\\Models\\BaseModel\:\:newFactory\(\) has no return type specified\.$#'
+ identifier: missingType.return
+ count: 1
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Only booleans are allowed in &&, mixed given on the left side\.$#'
+ identifier: booleanAnd.leftNotBoolean
+ count: 1
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, mixed given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Out of 286 possible return types, only 267 \- 93\.3 %% actually have it\. Add more return types to get over 99 %%$#'
+ identifier: typeCoverage.returnTypeCoverage
+ count: 3
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 6
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Parameter \#1 \$hash of method Apiato\\Support\\HashidsManagerDecorator\:\:decode\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Trait Apiato\\Core\\Models\\Concerns\\HandlesFactoryDiscovery uses generic trait Illuminate\\Database\\Eloquent\\Factories\\HasFactory but does not specify its types\: TFactory$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Core/Models/BaseModel.php
+
+ -
+ message: '#^Call to function is_callable\(\) with Closure will always evaluate to true\.$#'
+ identifier: function.alreadyNarrowedType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Cannot cast mixed to int\.$#'
+ identifier: cast.int
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Dead catch \- Illuminate\\Database\\Eloquent\\ModelNotFoundException is never thrown in the try block\.$#'
+ identifier: catch.neverThrown
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Dynamic call to static method Illuminate\\Database\\Eloquent\\Model\:\:with\(\)\.$#'
+ identifier: staticMethod.dynamicCall
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Expression on left side of \?\? is not nullable\.$#'
+ identifier: nullCoalesce.expr
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:all\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:all\(\) should return Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\), TModel of Illuminate\\Database\\Eloquent\\Model\> but returns mixed\.$#'
+ identifier: return.type
+ count: 2
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:arrayToSearchQuery\(\) has parameter \$decodedSearchArray with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:create\(\) has parameter \$attributes with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:create\(\) should return TModel of Illuminate\\Database\\Eloquent\\Model but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:find\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:find\(\) has parameter \$id with generic interface Illuminate\\Contracts\\Support\\Arrayable but does not specify its types\: TKey, TValue$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:find\(\) has parameter \$id with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:find\(\) return type with generic interface Illuminate\\Contracts\\Support\\Arrayable does not specify its types\: TKey, TValue$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:find\(\) should return Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\), TModel of Illuminate\\Database\\Eloquent\\Model\>\|\(TModel of Illuminate\\Database\\Eloquent\\Model\)\|null but returns mixed\.$#'
+ identifier: return.type
+ count: 2
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findByField\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findByField\(\) has parameter \$field with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findByField\(\) has parameter \$value with no type specified\.$#'
+ identifier: missingType.parameter
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findByField\(\) should return Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\), TModel of Illuminate\\Database\\Eloquent\\Model\> but returns mixed\.$#'
+ identifier: return.type
+ count: 2
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findById\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findMany\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findMany\(\) has parameter \$ids with generic interface Illuminate\\Contracts\\Support\\Arrayable but does not specify its types\: TKey, TValue$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findMany\(\) has parameter \$ids with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findOrFail\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findWhere\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findWhere\(\) has parameter \$where with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:findWhere\(\) should return Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\), TModel of Illuminate\\Database\\Eloquent\\Model\> but returns mixed\.$#'
+ identifier: return.type
+ count: 2
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:firstOrCreate\(\) has parameter \$attributes with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:firstOrCreate\(\) has parameter \$values with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:getDecodedSearchValues\(\) has parameter \$searchData with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:getDecodedSearchValues\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:getModel\(\) should return TModel of Illuminate\\Database\\Eloquent\\Model but returns Illuminate\\Database\\Eloquent\\Model\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:make\(\) has parameter \$attributes with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:paginate\(\) has parameter \$columns with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:parserSearchData\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:store\(\) has parameter \$data with generic interface Illuminate\\Contracts\\Support\\Arrayable but does not specify its types\: TKey, TValue$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:store\(\) has parameter \$data with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:update\(\) has Apiato\\Core\\Repositories\\Exceptions\\ResourceNotFound in PHPDoc @throws tag but it''s not thrown\.$#'
+ identifier: throws.unusedType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:update\(\) has parameter \$attributes with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Repositories\\Repository\:\:update\(\) should return TModel of Illuminate\\Database\\Eloquent\\Model but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Only booleans are allowed in &&, mixed given on the left side\.$#'
+ identifier: booleanAnd.leftNotBoolean
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Only booleans are allowed in &&, mixed given on the right side\.$#'
+ identifier: booleanAnd.rightNotBoolean
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Out of 286 possible return types, only 267 \- 93\.3 %% actually have it\. Add more return types to get over 99 %%$#'
+ identifier: typeCoverage.returnTypeCoverage
+ count: 14
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 13
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$attributes of method Illuminate\\Database\\Eloquent\\Model\:\:update\(\) expects array\, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$field \(array\|\(Closure\(static\)\: mixed\)\|Illuminate\\Contracts\\Database\\Query\\Expression\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:findByField\(\) should be contravariant with parameter \$field \(mixed\) of method Prettus\\Repository\\Contracts\\RepositoryInterface\:\:findByField\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$field \(array\|\(Closure\(static\)\: mixed\)\|Illuminate\\Contracts\\Database\\Query\\Expression\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:findByField\(\) should be contravariant with parameter \$field \(mixed\) of method Prettus\\Repository\\Eloquent\\BaseRepository\:\:findByField\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$hash of method Apiato\\Support\\HashidsManagerDecorator\:\:decode\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$id \(array\|Illuminate\\Contracts\\Support\\Arrayable\|int\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:find\(\) should be contravariant with parameter \$id \(mixed\) of method Prettus\\Repository\\Contracts\\RepositoryInterface\:\:find\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$id \(array\|Illuminate\\Contracts\\Support\\Arrayable\|int\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:find\(\) should be contravariant with parameter \$id \(mixed\) of method Prettus\\Repository\\Eloquent\\BaseRepository\:\:find\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$id \(int\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:delete\(\) should be contravariant with parameter \$id \(mixed\) of method Prettus\\Repository\\Contracts\\RepositoryInterface\:\:delete\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$id \(int\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:delete\(\) should be contravariant with parameter \$id \(mixed\) of method Prettus\\Repository\\Eloquent\\BaseRepository\:\:delete\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$key of method Illuminate\\Http\\Request\:\:filled\(\) expects array\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#2 \$columns of method Prettus\\Repository\\Eloquent\\BaseRepository\:\:findWhere\(\) expects array, array\|string given\.$#'
+ identifier: argument.type
+ count: 2
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#2 \$id \(int\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:update\(\) should be contravariant with parameter \$id \(mixed\) of method Prettus\\Repository\\Contracts\\RepositoryInterface\:\:update\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#2 \$id \(int\|string\) of method Apiato\\Core\\Repositories\\Repository\:\:update\(\) should be contravariant with parameter \$id \(mixed\) of method Prettus\\Repository\\Eloquent\\BaseRepository\:\:update\(\)$#'
+ identifier: method.childParameterType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Parameter \#3 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Property Prettus\\Repository\\Eloquent\\BaseRepository\:\:\$model \(Illuminate\\Database\\Eloquent\\Model\) does not accept mixed\.$#'
+ identifier: assign.propertyType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Return type \(bool\) of method Apiato\\Core\\Repositories\\Repository\:\:delete\(\) should be compatible with return type \(int\) of method Prettus\\Repository\\Contracts\\RepositoryInterface\:\:delete\(\)$#'
+ identifier: method.childReturnType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Return type \(bool\) of method Apiato\\Core\\Repositories\\Repository\:\:delete\(\) should be compatible with return type \(int\) of method Prettus\\Repository\\Eloquent\\BaseRepository\:\:delete\(\)$#'
+ identifier: method.childReturnType
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Using nullsafe method call on non\-nullable type Illuminate\\Http\\Request\. Use \-\> instead\.$#'
+ identifier: nullsafe.neverNull
+ count: 1
+ path: src/Core/Repositories/Repository.php
+
+ -
+ message: '#^Method Apiato\\Core\\Requests\\Request\:\:route\(\) should return object\|string\|null but returns array\\|int\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Method Apiato\\Core\\Requests\\Request\:\:route\(\) should return object\|string\|null but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Only booleans are allowed in &&, mixed given on the right side\.$#'
+ identifier: booleanAnd.rightNotBoolean
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#'
+ identifier: booleanNot.exprNotBoolean
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Out of 286 possible return types, only 267 \- 93\.3 %% actually have it\. Add more return types to get over 99 %%$#'
+ identifier: typeCoverage.returnTypeCoverage
+ count: 2
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 4
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Parameter \#1 \$array of static method Illuminate\\Support\\Arr\:\:dot\(\) expects iterable, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Parameter \#1 \$array of static method Illuminate\\Support\\Arr\:\:set\(\) expects array, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Parameter \#1 \.\.\.\$hash of method Apiato\\Support\\HashidsManagerDecorator\:\:decodeOrFail\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Parameter \#1 \.\.\.\$hash of method Apiato\\Support\\HashidsManagerDecorator\:\:decodeOrFail\(\) expects string, object\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Core/Requests/Request.php
+
+ -
+ message: '#^Out of 9 possible constant types, only 0 \- 0\.0 %% actually have it\. Add more constant types to get over 99 %%$#'
+ identifier: typeCoverage.constantTypeCoverage
+ count: 1
+ path: src/Core/Seeders/Seeder.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 4
+ path: src/Core/Transformers/Transformer.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:commands\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:configs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:events\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:factory\(\) return type with generic class Apiato\\Foundation\\Configuration\\Factory does not specify its types\: TModel, TFactory$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:helpers\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:inferBasePath\(\) should return string but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:migrations\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:provider\(\) return type with generic class Apiato\\Foundation\\Configuration\\Provider does not specify its types\: T$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:providers\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:repository\(\) return type with generic class Apiato\\Foundation\\Configuration\\Repository does not specify its types\: TModel, TRepository$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:seeding\(\) return type with generic class Apiato\\Foundation\\Configuration\\Seeding does not specify its types\: TSeeder$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Apiato\:\:webRoutes\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 2
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Property Apiato\\Foundation\\Apiato\:\:\$factory with generic class Apiato\\Foundation\\Configuration\\Factory does not specify its types\: TModel, TFactory$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Property Apiato\\Foundation\\Apiato\:\:\$provider with generic class Apiato\\Foundation\\Configuration\\Provider does not specify its types\: T$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Property Apiato\\Foundation\\Apiato\:\:\$repository with generic class Apiato\\Foundation\\Configuration\\Repository does not specify its types\: TModel, TRepository$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Property Apiato\\Foundation\\Apiato\:\:\$seeding with generic class Apiato\\Foundation\\Configuration\\Seeding does not specify its types\: TSeeder$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Apiato.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\ApplicationBuilder\:\:getDirs\(\) should return array\ but returns list\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/ApplicationBuilder.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Factory\:\:resolveFactoryName\(\) should return class\-string\\|null but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/Factory.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Factory\:\:resolveFactoryNameUsing\(\) return type with generic class Apiato\\Foundation\\Configuration\\Factory does not specify its types\: TModel, TFactory$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Configuration/Factory.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Apiato\\Foundation\\Configuration\\Factory\\:\:resolveFactoryNameUsing\(\) expects Closure\(class\-string\\)\: \(class\-string\\|null\), Closure\(string\)\: \(class\-string\|null\) given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Configuration/Factory.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Localization\:\:buildNamespaceFor\(\) should return string but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/Localization.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Provider\:\:loadFrom\(\) return type with generic class Apiato\\Foundation\\Configuration\\Provider does not specify its types\: T$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Configuration/Provider.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Provider\:\:toArray\(\) should return array\\> but returns array\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/Provider.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Repository\:\:resolveModelName\(\) should return class\-string\ but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/Repository.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Repository\:\:resolveModelNameUsing\(\) return type with generic class Apiato\\Foundation\\Configuration\\Repository does not specify its types\: TModel, TRepository$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Configuration/Repository.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Apiato\\Foundation\\Configuration\\Repository\\:\:resolveModelNameUsing\(\) expects Closure\(class\-string\\)\: class\-string\, Closure\(string\)\: class\-string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Configuration/Repository.php
+
+ -
+ message: '#^Binary operation "\." between ''throttle\:'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Foundation/Configuration/Routing.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Routing\:\:resolveApiVersionFor\(\) should return string but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/Routing.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Routing\:\:webRoutes\(\) should return array\ but returns array\\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/Routing.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, mixed given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Foundation/Configuration/Routing.php
+
+ -
+ message: '#^Parameter \#1 \$value of method Illuminate\\Routing\\RouteRegistrar\:\:domain\(\) expects BackedEnum\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Configuration/Routing.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Seeding\:\:getSortedFiles\(\) should return array\\> but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/Seeding.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Seeding\:\:loadFrom\(\) return type with generic class Apiato\\Foundation\\Configuration\\Seeding does not specify its types\: TSeeder$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Configuration/Seeding.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\Seeding\:\:sortUsing\(\) return type with generic class Apiato\\Foundation\\Configuration\\Seeding does not specify its types\: TSeeder$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Foundation/Configuration/Seeding.php
+
+ -
+ message: '#^Only numeric types are allowed in \+, int\<0, max\>\|false given on the left side\.$#'
+ identifier: plus.leftNonNumeric
+ count: 1
+ path: src/Foundation/Configuration/Seeding.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Apiato\\Foundation\\Configuration\\Seeding\\:\:sortUsing\(\) expects Closure\(array\, non\-empty\-string\>\>\)\: class\-string\, Closure\(array\)\: array\ given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Configuration/Seeding.php
+
+ -
+ message: '#^Parameter \#1 \$classMapGroupedByDirectory of method Apiato\\Foundation\\Configuration\\Seeding\\:\:getSortedFiles\(\) expects array\, non\-empty\-string\>\>, list\\> given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Configuration/Seeding.php
+
+ -
+ message: '#^Method Apiato\\Foundation\\Configuration\\View\:\:buildNamespaceFor\(\) should return string but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Foundation/Configuration/View.php
+
+ -
+ message: '#^PHPDoc tag @var with type Apiato\\Core\\Seeders\\Seeder is not subtype of native type \$this\(Apiato\\Foundation\\Database\\DatabaseSeeder\)\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: src/Foundation/Database/DatabaseSeeder.php
+
+ -
+ message: '#^Parameter \#1 \$callback of static method Illuminate\\Database\\Connection\:\:transaction\(\) expects Closure\(Illuminate\\Database\\Connection\)\: Apiato\\Core\\Seeders\\Seeder, Closure\(string\)\: Apiato\\Core\\Seeders\\Seeder given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Database/DatabaseSeeder.php
+
+ -
+ message: '#^Variable \$class in PHPDoc tag @var does not exist\.$#'
+ identifier: varTag.variableNotFound
+ count: 1
+ path: src/Foundation/Database/DatabaseSeeder.php
+
+ -
+ message: '#^Parameter \#1 \$path of method Illuminate\\Support\\ServiceProvider\:\:mergeConfigFrom\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Support/Providers/ConfigServiceProvider.php
+
+ -
+ message: '#^Parameter \#1 \$string of static method Illuminate\\Support\\Str\:\:of\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Support/Providers/ConfigServiceProvider.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, mixed given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Foundation/Support/Providers/RateLimitingServiceProvider.php
+
+ -
+ message: '#^Parameter \#1 \$decayMinutes of static method Illuminate\\Cache\\RateLimiting\\Limit\:\:perMinutes\(\) expects int, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Support/Providers/RateLimitingServiceProvider.php
+
+ -
+ message: '#^Parameter \#1 \$name of static method Illuminate\\Support\\Facades\\RateLimiter\:\:for\(\) expects string\|UnitEnum, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Support/Providers/RateLimitingServiceProvider.php
+
+ -
+ message: '#^Parameter \#2 \$maxAttempts of static method Illuminate\\Cache\\RateLimiting\\Limit\:\:perMinutes\(\) expects int, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Foundation/Support/Providers/RateLimitingServiceProvider.php
+
+ -
+ message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#'
+ identifier: ternary.shortNotAllowed
+ count: 1
+ path: src/Foundation/Support/Providers/RateLimitingServiceProvider.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ActionGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ActionGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ActionGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ActionGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ActionGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ActionGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Pluralizer\:\:plural\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ActionGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ActionGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:upper\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ActionGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ActionGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ActionGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ConfigurationGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ConfigurationGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ConfigurationGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ConfigurationGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ConfigurationGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ConfigurationGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ConfigurationGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ConfigurationGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Create'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 7
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Delete'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 7
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Find'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 7
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''List'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 7
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Update'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 7
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''Created'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''Deleted'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''Factory'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''FactoryTest'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''Listed'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''MigrationTest'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''Requested'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''Transformer'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''Updated'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerApiGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerApiGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerApiGenerator\:\:runCallParam\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in &&, array\|bool\|string\|null given on the left side\.$#'
+ identifier: booleanAnd.leftNotBoolean
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in &&, array\|bool\|string\|null given on the right side\.$#'
+ identifier: booleanAnd.rightNotBoolean
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in a ternary operator condition, array\|bool\|string\|null given\.$#'
+ identifier: ternary.condNotBoolean
+ count: 2
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, array\|bool\|string\|null given\.$#'
+ identifier: if.condNotBoolean
+ count: 3
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ContainerApiGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Pluralizer\:\:plural\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:kebab\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ContainerApiGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#'
+ identifier: ternary.shortNotAllowed
+ count: 2
+ path: src/Generator/Commands/ContainerApiGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ContainerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, array\|bool\|string\|null given\.$#'
+ identifier: if.condNotBoolean
+ count: 2
+ path: src/Generator/Commands/ContainerGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ContainerGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ContainerGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ContainerGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Create'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 5
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Delete'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 5
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Edit'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 3
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Find'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 5
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''List'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 5
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Store'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 3
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''Update'' and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 5
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerWebGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerWebGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ContainerWebGenerator\:\:runCallParam\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ContainerWebGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:kebab\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ContainerWebGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ContainerWebGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ControllerGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ControllerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ControllerGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ControllerGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ControllerGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ControllerGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Pluralizer\:\:plural\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ControllerGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:camel\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ControllerGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 2
+ path: src/Generator/Commands/ControllerGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ControllerGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ControllerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\EventGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\EventGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, array\|bool\|string\|null given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\EventGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\EventGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#'
+ identifier: ternary.shortNotAllowed
+ count: 1
+ path: src/Generator/Commands/EventGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\EventListenerGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/EventListenerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\EventListenerGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/EventListenerGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\EventListenerGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/EventListenerGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\EventListenerGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/EventListenerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ExceptionGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ExceptionGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ExceptionGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ExceptionGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ExceptionGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ExceptionGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ExceptionGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ExceptionGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\FunctionalTestGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/FunctionalTestGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\FunctionalTestGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/FunctionalTestGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#'
+ identifier: ternary.condNotBoolean
+ count: 1
+ path: src/Generator/Commands/FunctionalTestGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\FunctionalTestGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/FunctionalTestGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/FunctionalTestGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\FunctionalTestGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/FunctionalTestGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\JobGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/JobGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\JobGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/JobGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\JobGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/JobGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\JobGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/JobGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\MailGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/MailGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\MailGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/MailGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\MailGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/MailGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\MailGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/MailGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\MiddlewareGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/MiddlewareGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\MiddlewareGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/MiddlewareGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\MiddlewareGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/MiddlewareGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\MiddlewareGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/MiddlewareGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\MigrationGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/MigrationGenerator.php
+
+ -
+ message: '#^Out of 9 possible constant types, only 0 \- 0\.0 %% actually have it\. Add more constant types to get over 99 %%$#'
+ identifier: typeCoverage.constantTypeCoverage
+ count: 1
+ path: src/Generator/Commands/MigrationGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\MigrationGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/MigrationGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$path of method Apiato\\Generator\\Generator\:\:getFilePath\(\) expects string, array\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/MigrationGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/MigrationGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\MigrationGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/MigrationGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ModelFactoryGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ModelFactoryGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ModelFactoryGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ModelFactoryGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ModelFactoryGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ModelFactoryGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/ModelFactoryGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ModelFactoryGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ModelFactoryGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ModelGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ModelGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ModelGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ModelGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, array\|bool\|string\|null given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Generator/Commands/ModelGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ModelGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ModelGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ModelGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ModelGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\NotificationGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/NotificationGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\NotificationGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/NotificationGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\NotificationGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/NotificationGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\NotificationGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/NotificationGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\PolicyGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/PolicyGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\PolicyGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/PolicyGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\PolicyGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/PolicyGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\PolicyGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/PolicyGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ReadmeGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ReadmeGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ReadmeGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ReadmeGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ReadmeGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ReadmeGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ReadmeGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ReadmeGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\RepositoryGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/RepositoryGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\RepositoryGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/RepositoryGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\RepositoryGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/RepositoryGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RepositoryGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\RepositoryGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/RepositoryGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\RequestGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/RequestGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\RequestGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/RequestGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#'
+ identifier: ternary.condNotBoolean
+ count: 1
+ path: src/Generator/Commands/RequestGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\RequestGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/RequestGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RequestGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\RequestGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/RequestGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''/v'' and array\|int\|string results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''v'' and array\|int\|string results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''/'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\RouteGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\RouteGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, array\|bool\|string\|null given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\RouteGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:headline\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:snake\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:studly\(\) expects string, string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:upper\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\RouteGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/RouteGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\SeederGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/SeederGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\SeederGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/SeederGenerator.php
+
+ -
+ message: '#^Out of 9 possible constant types, only 0 \- 0\.0 %% actually have it\. Add more constant types to get over 99 %%$#'
+ identifier: typeCoverage.constantTypeCoverage
+ count: 1
+ path: src/Generator/Commands/SeederGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\SeederGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/SeederGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\SeederGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/SeederGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ServiceProviderGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ServiceProviderGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ServiceProviderGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ServiceProviderGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in a negated boolean, string\|null given\.$#'
+ identifier: booleanNot.exprNotBoolean
+ count: 1
+ path: src/Generator/Commands/ServiceProviderGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ServiceProviderGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ServiceProviderGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ServiceProviderGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ServiceProviderGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\SubActionGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/SubActionGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\SubActionGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/SubActionGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\SubActionGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/SubActionGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\SubActionGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/SubActionGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\TaskGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\TaskGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#'
+ identifier: ternary.condNotBoolean
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\TaskGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Pluralizer\:\:plural\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:camel\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\TaskGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/TaskGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\TestCaseGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/TestCaseGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\TestCaseGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/TestCaseGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\TestCaseGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/TestCaseGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TestCaseGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\TestCaseGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/TestCaseGenerator.php
+
+ -
+ message: '#^Binary operation "\." between non\-falsy\-string and mixed results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Call to an undefined method object\:\:getHidden\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Call to an undefined method object\:\:getTable\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Call to function in_array\(\) requires parameter \#3 to be true\.$#'
+ identifier: function.strict
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\TransformerGenerator\:\:getEndOfLine\(\) has parameter \$fields with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\TransformerGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\TransformerGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\TransformerGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$table of static method Illuminate\\Support\\Facades\\Schema\:\:getColumnListing\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:lower\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Parameter \#2 \$haystack of function in_array expects array, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Parameter \#2 \$model of method Apiato\\Generator\\Commands\\TransformerGenerator\:\:getListOfAllAttributes\(\) expects string, array\|int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\TransformerGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/TransformerGenerator.php
+
+ -
+ message: '#^Binary operation "\." between ''\{section\-name\}/…'' and array\|int\|non\-empty\-string results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^Binary operation "\." between mixed and ''/\*'' results in an error\.$#'
+ identifier: binaryOp.invalid
+ count: 1
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\UnitTestGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\UnitTestGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, string\|null given\.$#'
+ identifier: if.condNotBoolean
+ count: 3
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\UnitTestGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^Parameter \#1 \$value of static method Illuminate\\Support\\Str\:\:studly\(\) expects string, string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\UnitTestGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/UnitTestGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ValueGenerator\:\:getUserInputs\(\) never returns null so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Generator/Commands/ValueGenerator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Commands\\ValueGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ValueGenerator.php
+
+ -
+ message: '#^PHPDoc type string of property Apiato\\Generator\\Commands\\ValueGenerator\:\:\$description is not the same as PHPDoc type string\|null of overridden property Illuminate\\Console\\Command\:\:\$description\.$#'
+ identifier: property.phpDocType
+ count: 1
+ path: src/Generator/Commands/ValueGenerator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Commands\\ValueGenerator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Commands/ValueGenerator.php
+
+ -
+ message: '#^Access to an undefined property \$this\(Apiato\\Generator\\Generator\)&Apiato\\Generator\\Interfaces\\ComponentsGenerator\:\:\$nameStructure\.$#'
+ identifier: property.notFound
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Access to an undefined property \$this\(Apiato\\Generator\\Generator\)&Apiato\\Generator\\Interfaces\\ComponentsGenerator\:\:\$pathStructure\.$#'
+ identifier: property.notFound
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Cannot cast array\|int\|string to string\.$#'
+ identifier: cast.string
+ count: 2
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:checkParameterOrAsk\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:checkParameterOrAsk\(\) should return array\|int\|string but returns array\|bool\|string\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:checkParameterOrChoice\(\) has parameter \$choices with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:checkParameterOrChoice\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:checkParameterOrChoice\(\) should return array\|bool\|string\|null but returns int\|string\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:checkParameterOrConfirm\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:getInput\(\) has parameter \$arg with no type specified\.$#'
+ identifier: missingType.parameter
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:getInput\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:getInput\(\) should return array\|string\|null but returns array\|bool\|string\|null\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:getOptions\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:parseFileStructure\(\) has parameter \$data with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:parsePathStructure\(\) has parameter \$data with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:parsePathStructure\(\) has parameter \$path with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:parsePathStructure\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:parseStubContent\(\) has parameter \$data with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:parseStubContent\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:sanitizeUserData\(\) has parameter \$data with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Generator\:\:sanitizeUserData\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Out of 9 possible constant types, only 0 \- 0\.0 %% actually have it\. Add more constant types to get over 99 %%$#'
+ identifier: typeCoverage.constantTypeCoverage
+ count: 4
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#1 \$filename of method Apiato\\Generator\\Generator\:\:parseFileStructure\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#1 \$key of method Illuminate\\Console\\Command\:\:argument\(\) expects string\|null, mixed given\.$#'
+ identifier: argument.type
+ count: 2
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#1 \$path of method Apiato\\Generator\\Generator\:\:getFilePath\(\) expects string, array\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#1 \$path of method Apiato\\Generator\\Generator\:\:parsePathStructure\(\) expects array\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#1 \$string of function trim expects string, array\|bool\|string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#1 \$string of function ucfirst expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 2
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#2 \$data of method Apiato\\Generator\\Generator\:\:parseFileStructure\(\) expects array, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#2 \$data of method Apiato\\Generator\\Generator\:\:parsePathStructure\(\) expects array, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#2 \$data of method Apiato\\Generator\\Generator\:\:parseStubContent\(\) expects array, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#2 \$options of function Laravel\\Prompts\\select expects array\\|Illuminate\\Support\\Collection\, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#2 \$replace of function str_replace expects array\\|string, list given\.$#'
+ identifier: argument.type
+ count: 3
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \#3 \$subject of function str_replace expects array\\|string, array\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Parameter \$default of function Laravel\\Prompts\\text expects string, int\|string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Generator\:\:\$defaultInputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Generator\:\:\$fileName \(string\) does not accept array\|int\|string\.$#'
+ identifier: assign.propertyType
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Generator\:\:\$inputs type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Generator\:\:\$renderedStubContent \(string\) does not accept array\|string\.$#'
+ identifier: assign.propertyType
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Property Apiato\\Generator\\Generator\:\:\$userData type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Generator.php
+
+ -
+ message: '#^Method Apiato\\Generator\\GeneratorsServiceProvider\:\:getGeneratorCommands\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/GeneratorsServiceProvider.php
+
+ -
+ message: '#^Method Apiato\\Generator\\Interfaces\\ComponentsGenerator\:\:getUserInputs\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Generator/Interfaces/ComponentsGenerator.php
+
+ -
+ message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#'
+ identifier: booleanNot.exprNotBoolean
+ count: 1
+ path: src/Http/Middleware/ProcessETag.php
+
+ -
+ message: '#^Only booleans are allowed in &&, mixed given on the right side\.$#'
+ identifier: booleanAnd.rightNotBoolean
+ count: 1
+ path: src/Http/Middleware/ValidateJsonContent.php
+
+ -
+ message: '#^Call to function array_filter\(\) requires parameter \#2 to be passed to avoid loose comparison semantics\.$#'
+ identifier: arrayFilter.strict
+ count: 1
+ path: src/Http/RequestRelation.php
+
+ -
+ message: '#^Method Apiato\\Http\\RequestRelation\:\:parseIncludes\(\) should return array\ but returns array\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Http/RequestRelation.php
+
+ -
+ message: '#^PHPDoc tag @var for variable \$relation contains generic class Illuminate\\Database\\Eloquent\\Relations\\Relation but does not specify its types\: TRelatedModel, TDeclaringModel, TResult$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Http/RequestRelation.php
+
+ -
+ message: '#^Using nullsafe method call on non\-nullable type Illuminate\\Config\\Repository\. Use \-\> instead\.$#'
+ identifier: nullsafe.neverNull
+ count: 1
+ path: src/Http/RequestRelation.php
+
+ -
+ message: '#^Variable method call on Illuminate\\Database\\Eloquent\\Model\.$#'
+ identifier: method.dynamicName
+ count: 1
+ path: src/Http/RequestRelation.php
+
+ -
+ message: '#^Method Apiato\\Http\\Response\:\:toArray\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Http/Response.php
+
+ -
+ message: '#^Strict comparison using \=\=\= between string and false will always evaluate to false\.$#'
+ identifier: identical.alwaysFalse
+ count: 1
+ path: src/Http/Response.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 100000 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 50200 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 50300 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 50400 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 50500 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 50600 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 70000 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 70100 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 70200 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 70300 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 70400 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 80000 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 80100 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 80300 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 80400 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:provideMinPhpVersion\(\) never returns 80500 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Out of 9 possible constant types, only 0 \- 0\.0 %% actually have it\. Add more constant types to get over 99 %%$#'
+ identifier: typeCoverage.constantTypeCoverage
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^PHPDoc tag @implements contains generic type Rector\\VersionBonding\\Contract\\MinPhpVersionInterface\ but interface Rector\\VersionBonding\\Contract\\MinPhpVersionInterface is not generic\.$#'
+ identifier: generics.notGeneric
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Parameter \#1 \$node \(PhpParser\\Node\\Expr\\MethodCall\) of method Apiato\\Linters\\Rector\\AssertInstanceToStaticCallRector\:\:refactor\(\) should be contravariant with parameter \$node \(PhpParser\\Node\) of method Rector\\Contract\\Rector\\RectorInterface\:\:refactor\(\)$#'
+ identifier: method.childParameterType
+ count: 2
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Parameter \#2 \$name of class PhpParser\\Node\\Expr\\StaticCall constructor expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Identifier\|string, string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Linters/Rector/AssertInstanceToStaticCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 100000 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 50200 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 50300 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 50400 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 50500 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 50600 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 70000 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 70100 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 70200 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 70300 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 70400 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 80000 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 80100 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 80300 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 80400 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:provideMinPhpVersion\(\) never returns 80500 so it can be removed from the return type\.$#'
+ identifier: return.unusedType
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Out of 9 possible constant types, only 0 \- 0\.0 %% actually have it\. Add more constant types to get over 99 %%$#'
+ identifier: typeCoverage.constantTypeCoverage
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^PHPDoc tag @implements contains generic type Rector\\VersionBonding\\Contract\\MinPhpVersionInterface\ but interface Rector\\VersionBonding\\Contract\\MinPhpVersionInterface is not generic\.$#'
+ identifier: generics.notGeneric
+ count: 1
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Parameter \#1 \$node \(PhpParser\\Node\\Expr\\StaticCall\) of method Apiato\\Linters\\Rector\\MockObjectStaticToInstanceCallRector\:\:refactor\(\) should be contravariant with parameter \$node \(PhpParser\\Node\) of method Rector\\Contract\\Rector\\RectorInterface\:\:refactor\(\)$#'
+ identifier: method.childParameterType
+ count: 2
+ path: src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
+
+ -
+ message: '#^Anonymous function should return int but returns array\\|int\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Macros/MacroServiceProvider.php
+
+ -
+ message: '#^PHPDoc tag @var for variable \$this contains generic class Illuminate\\Support\\Collection but does not specify its types\: TKey, TValue$#'
+ identifier: missingType.generics
+ count: 1
+ path: src/Macros/MacroServiceProvider.php
+
+ -
+ message: '#^PHPDoc tag @var with type Illuminate\\Config\\Repository is not subtype of native type \$this\(Apiato\\Macros\\MacroServiceProvider\)\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: src/Macros/MacroServiceProvider.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),mixed\>\:\:map\(\) expects callable\(mixed, int\|string\)\: int, Closure\(string\)\: int given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Macros/MacroServiceProvider.php
+
+ -
+ message: '#^Parameter \#1 \$source of static method Apiato\\Support\\Sanitizer\:\:sanitize\(\) expects array\, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Macros/MacroServiceProvider.php
+
+ -
+ message: '#^Parameter \#2 \$fields of static method Apiato\\Support\\Sanitizer\:\:sanitize\(\) expects array\, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Macros/MacroServiceProvider.php
+
+ -
+ message: '#^Property Illuminate\\Config\\Repository\:\:\$items \(array\\) does not accept array\.$#'
+ identifier: assign.propertyType
+ count: 1
+ path: src/Macros/MacroServiceProvider.php
+
+ -
+ message: '#^Class Apiato\\Support\\Facades\\Response has PHPDoc tag @method for method respond\(\) parameter \#2 \$headers with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Support/Facades/Response.php
+
+ -
+ message: '#^Method Apiato\\Support\\HashidsManagerDecorator\:\:__call\(\) has no return type specified\.$#'
+ identifier: missingType.return
+ count: 1
+ path: src/Support/HashidsManagerDecorator.php
+
+ -
+ message: '#^Method Apiato\\Support\\HashidsManagerDecorator\:\:__call\(\) has parameter \$parameters with no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: src/Support/HashidsManagerDecorator.php
+
+ -
+ message: '#^Method Apiato\\Support\\HashidsManagerDecorator\:\:decode\(\) should return array\\|int\|null but returns array\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Support/HashidsManagerDecorator.php
+
+ -
+ message: '#^Method Apiato\\Support\\HashidsManagerDecorator\:\:decodeOrFail\(\) should return array\\|int but returns array\\|int\>\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Support/HashidsManagerDecorator.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 2
+ path: src/Support/HashidsManagerDecorator.php
+
+ -
+ message: '#^Parameter \#1 \.\.\.\$numbers of method Apiato\\Support\\HashidsManagerDecorator\:\:encode\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Support/HashidsManagerDecorator.php
+
+ -
+ message: '#^Method Apiato\\Support\\Sanitizer\:\:sanitize\(\) should return array\ but returns array\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Support/Sanitizer.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\TestCall\:\:expect\(\)\.$#'
+ identifier: method.notFound
+ count: 4
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\TestCall\:\:preset\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot access property \$not on mixed\.$#'
+ identifier: property.nonObject
+ count: 2
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method classes\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method ignoring\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method php\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method toBeAbstract\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method toBeFinal\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method toOnlyBeUsedIn\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method toUse\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Cannot call method toUseStrictEquality\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Arch/CoreTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Console/CommandServiceProviderTest.php
+
+ -
+ message: '#^Parameter \#1 \$key of method Illuminate\\Support\\Collection\<\(int\|string\),mixed\>\:\:has\(\) expects array\<\(int\|string\)\>\|int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Functional/Console/CommandServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:artisan\(\)\.$#'
+ identifier: method.notFound
+ count: 2
+ path: tests/Functional/Console/Commands/ListActionsTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Console/Commands/ListActionsTest.php
+
+ -
+ message: '#^Cannot call method assertExitCode\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Console/Commands/ListActionsTest.php
+
+ -
+ message: '#^Cannot call method expectsOutput\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 8
+ path: tests/Functional/Console/Commands/ListActionsTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:artisan\(\)\.$#'
+ identifier: method.notFound
+ count: 2
+ path: tests/Functional/Console/Commands/ListTasksTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Console/Commands/ListTasksTest.php
+
+ -
+ message: '#^Cannot call method assertExitCode\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Console/Commands/ListTasksTest.php
+
+ -
+ message: '#^Cannot call method expectsOutput\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 4
+ path: tests/Functional/Console/Commands/ListTasksTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:getJson\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot access property \$author on mixed\.$#'
+ identifier: property.nonObject
+ count: 1
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot access property \$books on mixed\.$#'
+ identifier: property.nonObject
+ count: 2
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot access property \$children on mixed\.$#'
+ identifier: property.nonObject
+ count: 3
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot access property \$name on mixed\.$#'
+ identifier: property.nonObject
+ count: 2
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method content\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method first\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method getHashedKey\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method has\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method last\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Parameter \#2 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Parameter \#3 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Parameter \#4 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Functional/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\Expectation\:\:relationLoaded\(\)\.$#'
+ identifier: method.notFound
+ count: 3
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\Expectation\\:\:relationLoaded\(\)\.$#'
+ identifier: method.notFound
+ count: 2
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method each\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method has\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 4
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method toBeFalse\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method toBeTrue\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Functional/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:patchJson\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Core/Requests/RequestTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Core/Requests/RequestTest.php
+
+ -
+ message: '#^Cannot call method json\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Functional/Core/Requests/RequestTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$app\.$#'
+ identifier: property.notFound
+ count: 1
+ path: tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:get\(\)\.$#'
+ identifier: method.notFound
+ count: 2
+ path: tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
+
+ -
+ message: '#^Cannot call method assertOk\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
+
+ -
+ message: '#^Cannot call method providerIsLoaded\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
+
+ -
+ message: '#^Parameter \#1 \$key of method Illuminate\\Support\\Collection\<\(int\|string\),mixed\>\:\:has\(\) expects array\<\(int\|string\)\>\|int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$app\.$#'
+ identifier: property.notFound
+ count: 1
+ path: tests/Functional/Foundation/Providers/ApiatoServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:artisan\(\)\.$#'
+ identifier: method.notFound
+ count: 3
+ path: tests/Functional/Foundation/Providers/ApiatoServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Providers/ApiatoServiceProviderTest.php
+
+ -
+ message: '#^Cannot call method assertExitCode\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Functional/Foundation/Providers/ApiatoServiceProviderTest.php
+
+ -
+ message: '#^Cannot call method providerIsLoaded\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Functional/Foundation/Providers/ApiatoServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Mockery\\ExpectationInterface\|Mockery\\ExpectsHigherOrderMessage\:\:withArgs\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Support/Providers/ConfigServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:artisan\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Support/Providers/ConfigServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Support/Providers/ConfigServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Support/Providers/HelperServiceProviderTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$app\.$#'
+ identifier: property.notFound
+ count: 3
+ path: tests/Functional/Foundation/Support/Providers/LocalizationServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Support/Providers/LocalizationServiceProviderTest.php
+
+ -
+ message: '#^Cannot call method setLocale\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Functional/Foundation/Support/Providers/LocalizationServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Support/Providers/MigrationServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Foundation/Support/Providers/ViewServiceProviderTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$repository\.$#'
+ identifier: property.notFound
+ count: 5
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$user\.$#'
+ identifier: property.notFound
+ count: 5
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot access property \$children on mixed\.$#'
+ identifier: property.nonObject
+ count: 3
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot access property \$id on mixed\.$#'
+ identifier: property.nonObject
+ count: 4
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot call method findById\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 4
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot call method first\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot call method has\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot call method relationLoaded\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 13
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Cannot call method with\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Functional/IncludeEagerLoadingTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Functional/Macros/MacroServiceProviderTest.php
+
+ -
+ message: '#^Cannot call method freezeTime\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Pest.php
+
+ -
+ message: '#^Cannot call method toBe\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Pest.php
+
+ -
+ message: '#^Undefined variable\: \$this$#'
+ identifier: variable.undefined
+ count: 2
+ path: tests/Pest.php
+
+ -
+ message: '#^Access to an undefined property Pest\\Mixins\\Expectation\\>\|Pest\\Mixins\\Expectation\\:\:\$email\.$#'
+ identifier: property.notFound
+ count: 1
+ path: tests/Unit/Core/Actions/ActionTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Actions/ActionTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Actions/ActionTest.php
+
+ -
+ message: '#^Cannot call method toBe\(\) on Pest\\Expectation\\|Pest\\Expectations\\EachExpectation\\|Pest\\Expectations\\HigherOrderExpectation\, Workbench\\App\\Containers\\Identity\\User\\Models\\User\|null\>\|Pest\\Expectations\\OppositeExpectation\\|Workbench\\App\\Containers\\Identity\\User\\Models\\User\|null\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Actions/ActionTest.php
+
+ -
+ message: '#^Cannot call method toBe\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Actions/ActionTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$model\.$#'
+ identifier: property.notFound
+ count: 2
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot access property \$author_id on mixed\.$#'
+ identifier: property.nonObject
+ count: 1
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot access property \$id on mixed\.$#'
+ identifier: property.nonObject
+ count: 2
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot access property \$title on mixed\.$#'
+ identifier: property.nonObject
+ count: 3
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method count\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method create\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 6
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method getHashedKey\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 5
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method getKey\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 4
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method is\(\) on Illuminate\\Database\\Eloquent\\Model\|null\.$#'
+ identifier: method.nonObject
+ count: 4
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Cannot call method makeOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 6
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Parameter \#1 \$class of function class_uses_recursive expects object\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Parameter \#1 \.\.\.\$numbers of method Apiato\\Support\\HashidsManagerDecorator\:\:encode\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 5
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Property Apiato\\Core\\Models\\BaseModel@anonymous/tests/Unit/Core/Models/BaseModelTest\.php\:12\:\:\$resourceKey has no type specified\.$#'
+ identifier: missingType.property
+ count: 1
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#'
+ identifier: ternary.shortNotAllowed
+ count: 1
+ path: tests/Unit/Core/Models/BaseModelTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/Exceptions/ResourceCreationFailedTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/Exceptions/ResourceNotFoundTest.php
+
+ -
+ message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$email\.$#'
+ identifier: property.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$name\.$#'
+ identifier: property.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$app\.$#'
+ identifier: property.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Access to an undefined property Workbench\\App\\Containers\\MySection\\Book\\Models\\Book\:\:\$title\.$#'
+ identifier: property.notFound
+ count: 5
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\), Workbench\\App\\Containers\\MySection\\Book\\Models\\Book\>\|Workbench\\App\\Containers\\MySection\\Book\\Models\\Book\:\:getKey\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Mockery\\ExpectationInterface\|Mockery\\HigherOrderMessage\|Mockery\\MockInterface\:\:andReturnUsing\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Mockery\\MockInterface\:\:canSkipPagination\(\)\.$#'
+ identifier: method.notFound
+ count: 2
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Mockery\\MockInterface\:\:exceedsMaxPaginationLimit\(\)\.$#'
+ identifier: method.notFound
+ count: 2
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:assertModelExists\(\)\.$#'
+ identifier: method.notFound
+ count: 3
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:assertModelMissing\(\)\.$#'
+ identifier: method.notFound
+ count: 3
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\Expectation\\>\:\:first\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot access property \$email on mixed\.$#'
+ identifier: property.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot access property \$id on Workbench\\App\\Containers\\MySection\\Book\\Models\\Book\|null\.$#'
+ identifier: property.nonObject
+ count: 2
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot access property \$id on mixed\.$#'
+ identifier: property.nonObject
+ count: 11
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot access property \$name on mixed\.$#'
+ identifier: property.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot access property \$title on mixed\.$#'
+ identifier: property.nonObject
+ count: 2
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method and\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method create\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 10
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method getCacheKey\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method last\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method make\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method makeOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method offsetGet\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method orWhere\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method pluck\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method toArray\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method toBe\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Cannot call method where\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Method Workbench\\App\\Containers\\Identity\\User\\Data\\Repositories\\UserRepository@anonymous/tests/Unit/Core/Repositories/RepositoryTest\.php\:208\:\:getScopes\(\) return type has no value type specified in iterable type array\.$#'
+ identifier: missingType.iterableValue
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 9
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$data of method Apiato\\Core\\Repositories\\Repository\\:\:store\(\) expects array\|Illuminate\\Contracts\\Support\\Arrayable, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$id of method Apiato\\Core\\Repositories\\Repository\\:\:delete\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$id of method Apiato\\Core\\Repositories\\Repository\\:\:find\(\) expects array\|Illuminate\\Contracts\\Support\\Arrayable\|int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$id of method Apiato\\Core\\Repositories\\Repository\\:\:findById\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$id of method Apiato\\Core\\Repositories\\Repository\\:\:findOrFail\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$ids of method Apiato\\Core\\Repositories\\Repository\\:\:findMany\(\) expects array\|Illuminate\\Contracts\\Support\\Arrayable, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$key of static method Illuminate\\Support\\Facades\\Cache\:\:has\(\) expects array\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$key of static method Illuminate\\Support\\Facades\\Cache\:\:missing\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$model of method Apiato\\Core\\Repositories\\Repository\\:\:save\(\) expects Workbench\\App\\Containers\\MySection\\Book\\Models\\Book, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#2 \$id of method Apiato\\Core\\Repositories\\Repository\\:\:update\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#2 \$values of method Apiato\\Core\\Repositories\\Repository\\:\:firstOrCreate\(\) expects array, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Unable to resolve the template type TAndValue in call to method Pest\\Expectation\\:\:and\(\)$#'
+ identifier: argument.templateType
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Unable to resolve the template type TAndValue in call to method Pest\\Expectation\\:\:and\(\)$#'
+ identifier: argument.templateType
+ count: 4
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Unable to resolve the template type TAndValue in call to method Pest\\Expectation\\:\:and\(\)$#'
+ identifier: argument.templateType
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Unable to resolve the template type TValue in call to function expect$#'
+ identifier: argument.templateType
+ count: 5
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Variable method call on mixed\.$#'
+ identifier: method.dynamicName
+ count: 1
+ path: tests/Unit/Core/Repositories/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Requests/RequestTest.php
+
+ -
+ message: '#^Dynamic call to static method Apiato\\Core\\Requests\\Request@anonymous/tests/Unit/Core/Requests/RequestTest\.php\:9\:\:sanitize\(\)\.$#'
+ identifier: staticMethod.dynamicCall
+ count: 1
+ path: tests/Unit/Core/Requests/RequestTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$sut\.$#'
+ identifier: property.notFound
+ count: 2
+ path: tests/Unit/Core/Tests/TestCaseTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Tests/TestCaseTest.php
+
+ -
+ message: '#^Parameter \#1 \$class of function class_uses_recursive expects object\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Core/Tests/TestCaseTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Core/Transformers/TransformerTest.php
+
+ -
+ message: '#^Cannot call method make\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Core/Transformers/TransformerTest.php
+
+ -
+ message: '#^Cannot call method makeOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Core/Transformers/TransformerTest.php
+
+ -
+ message: '#^Out of 383 possible param types, only 340 \- 88\.7 %% actually have it\. Add more param types to get over 99 %%$#'
+ identifier: typeCoverage.paramTypeCoverage
+ count: 2
+ path: tests/Unit/Core/Transformers/TransformerTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/ApiatoTest.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Apiato\\Foundation\\Configuration\\Factory\\:\:resolveFactoryNameUsing\(\) expects Closure\(class\-string\\)\: \(class\-string\\|null\), Closure\(string\)\: ''test'' given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Foundation/ApiatoTest.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Apiato\\Foundation\\Configuration\\Repository\\:\:resolveModelNameUsing\(\) expects Closure\(class\-string\\)\: class\-string\, Closure\(string\)\: ''test'' given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Foundation/ApiatoTest.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Apiato\\Foundation\\Configuration\\Seeding\\:\:sortUsing\(\) expects Closure\(array\, non\-empty\-string\>\>\)\: class\-string\, Closure\(array\)\: array\{''test''\} given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Foundation/ApiatoTest.php
+
+ -
+ message: '#^Parameter \#1 \$modelName of method Apiato\\Foundation\\Configuration\\Factory\\:\:resolveFactoryName\(\) expects class\-string\, string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Foundation/ApiatoTest.php
+
+ -
+ message: '#^Parameter \#1 \$repositoryName of method Apiato\\Foundation\\Configuration\\Repository\\:\:resolveModelName\(\) expects class\-string\, string given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Foundation/ApiatoTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Configuration/FactoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$modelName of method Apiato\\Foundation\\Configuration\\Factory\\:\:resolveFactoryName\(\) expects class\-string\, string given\.$#'
+ identifier: argument.type
+ count: 2
+ path: tests/Unit/Foundation/Configuration/FactoryTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Configuration/LocalizationTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Configuration/ProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Configuration/RepositoryTest.php
+
+ -
+ message: '#^Parameter \#1 \$repositoryName of method Apiato\\Foundation\\Configuration\\Repository\\:\:resolveModelName\(\) expects class\-string\, string given\.$#'
+ identifier: argument.type
+ count: 3
+ path: tests/Unit/Foundation/Configuration/RepositoryTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Configuration/RoutingTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Configuration/SeedingTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Configuration/ViewTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:assertDatabaseCount\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Database/DatabaseSeederTest.php
+
+ -
+ message: '#^Call to an undefined method PHPUnit\\Framework\\TestCase\:\:assertDatabaseHas\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Database/DatabaseSeederTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Foundation/Database/DatabaseSeederTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Foundation/Database/DatabaseSeederTest.php
+
+ -
+ message: '#^Parameter \#1 \$callback of method Apiato\\Foundation\\Configuration\\Seeding\\:\:sortUsing\(\) expects Closure\(array\, non\-empty\-string\>\>\)\: class\-string\, Closure\(\)\: array\{''AnonymousClass9d10017f3e9f351a03aca329a51dd202''\} given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Foundation/Database/DatabaseSeederTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$next\.$#'
+ identifier: property.notFound
+ count: 8
+ path: tests/Unit/Http/Middleware/ProcessETagTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Http/Middleware/ProcessETagTest.php
+
+ -
+ message: '#^Call to protected method expectException\(\) of class PHPUnit\\Framework\\TestCase\.$#'
+ identifier: method.protected
+ count: 1
+ path: tests/Unit/Http/Middleware/ProcessETagTest.php
+
+ -
+ message: '#^Parameter \#2 \$next of method Apiato\\Http\\Middleware\\ProcessETag\:\:handle\(\) expects Closure\(Illuminate\\Http\\Request\)\: Symfony\\Component\\HttpFoundation\\Response, mixed given\.$#'
+ identifier: argument.type
+ count: 7
+ path: tests/Unit/Http/Middleware/ProcessETagTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$next\.$#'
+ identifier: property.notFound
+ count: 3
+ path: tests/Unit/Http/Middleware/ValidateJsonContentTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Http/Middleware/ValidateJsonContentTest.php
+
+ -
+ message: '#^Call to protected method expectException\(\) of class PHPUnit\\Framework\\TestCase\.$#'
+ identifier: method.protected
+ count: 1
+ path: tests/Unit/Http/Middleware/ValidateJsonContentTest.php
+
+ -
+ message: '#^Parameter \#1 \.\.\.\$data of method Pest\\PendingCalls\\TestCall\:\:with\(\) expects array\\|string\>\|Closure\|string, array\{true, false\} given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Http/Middleware/ValidateJsonContentTest.php
+
+ -
+ message: '#^Parameter \#2 \$next of method Apiato\\Http\\Middleware\\ValidateJsonContent\:\:handle\(\) expects Closure\(Illuminate\\Http\\Request\)\: Symfony\\Component\\HttpFoundation\\Response, mixed given\.$#'
+ identifier: argument.type
+ count: 2
+ path: tests/Unit/Http/Middleware/ValidateJsonContentTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Http/RequestRelationTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Http/Resources/CollectionTest.php
+
+ -
+ message: '#^Cannot call method getIterator\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Http/Resources/CollectionTest.php
+
+ -
+ message: '#^Cannot call method make\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Http/Resources/CollectionTest.php
+
+ -
+ message: '#^Cannot call method makeOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Http/Resources/CollectionTest.php
+
+ -
+ message: '#^Function json_encode is unsafe to use\. It can return FALSE instead of throwing an exception\. Please add ''use function Safe\\json_encode;'' at the beginning of the file to use the variant provided by the ''thecodingmachine/safe'' library\.$#'
+ identifier: theCodingMachineSafe.function
+ count: 1
+ path: tests/Unit/Http/Resources/CollectionTest.php
+
+ -
+ message: '#^Parameter \#2 \$message of method Pest\\Mixins\\Expectation\\:\:toBe\(\) expects string, string\|false given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Http/Resources/CollectionTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Http/Resources/ItemTest.php
+
+ -
+ message: '#^Cannot call method getIterator\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Http/Resources/ItemTest.php
+
+ -
+ message: '#^Cannot call method make\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Http/Resources/ItemTest.php
+
+ -
+ message: '#^Cannot call method makeOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Http/Resources/ItemTest.php
+
+ -
+ message: '#^Function json_encode is unsafe to use\. It can return FALSE instead of throwing an exception\. Please add ''use function Safe\\json_encode;'' at the beginning of the file to use the variant provided by the ''thecodingmachine/safe'' library\.$#'
+ identifier: theCodingMachineSafe.function
+ count: 1
+ path: tests/Unit/Http/Resources/ItemTest.php
+
+ -
+ message: '#^Parameter \#2 \$message of method Pest\\Mixins\\Expectation\\:\:toBe\(\) expects string, string\|false given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Http/Resources/ItemTest.php
+
+ -
+ message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$app\.$#'
+ identifier: property.notFound
+ count: 2
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\Expectation\\:\:getStatusCode\(\)\.$#'
+ identifier: method.notFound
+ count: 3
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method create\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 2
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method createOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method for\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method getCurrentScope\(\) on \(callable\)\|League\\Fractal\\TransformerAbstract\|string\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method getData\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method has\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 4
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method makeOne\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method toBe\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Cannot call method toHaveKey\(\) on mixed\.$#'
+ identifier: method.nonObject
+ count: 3
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Function getUser\(\) should return Workbench\\App\\Containers\\Identity\\User\\Models\\User but returns mixed\.$#'
+ identifier: return.type
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Parameter \#1 \$include of method League\\Fractal\\Manager\:\:getIncludeParams\(\) expects string, string\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Parameter \#1 \$key of method Illuminate\\Testing\\Fluent\\AssertableJson\:\:has\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 3
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Parameter \#1 \$key of method Illuminate\\Testing\\Fluent\\AssertableJson\:\:missing\(\) expects string, mixed given\.$#'
+ identifier: argument.type
+ count: 3
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Parameter \#1 \$resourceName of method Spatie\\Fractalistic\\Fractal\:\:withResourceName\(\) expects string, bool\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Http/ResponseTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Macros/MacroServiceProviderTest.php
+
+ -
+ message: '#^Dynamic call to static method Illuminate\\Support\\Collection\\>\:\:containsDecodedHash\(\)\.$#'
+ identifier: staticMethod.dynamicCall
+ count: 1
+ path: tests/Unit/Macros/MacroServiceProviderTest.php
+
+ -
+ message: '#^Dynamic call to static method Illuminate\\Support\\Collection\\:\:decode\(\)\.$#'
+ identifier: staticMethod.dynamicCall
+ count: 2
+ path: tests/Unit/Macros/MacroServiceProviderTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Support/DefaultProvidersTest.php
+
+ -
+ message: '#^Anonymous function should return Pest\\Expectation but returns Pest\\Mixins\\Expectation\\.$#'
+ identifier: return.type
+ count: 10
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Anonymous function should return Pest\\Expectation but returns Pest\\Mixins\\Expectation\\.$#'
+ identifier: return.type
+ count: 8
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Anonymous function should return Pest\\Expectation but returns Pest\\Mixins\\Expectation\\.$#'
+ identifier: return.type
+ count: 5
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Parameter \#3 \$headers of static method Apiato\\Http\\Response\:\:json\(\) expects array\, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Static method Apiato\\Support\\Facades\\Response\:\:accepted\(\) invoked with 3 parameters, 0 required\.$#'
+ identifier: arguments.count
+ count: 1
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Static method Apiato\\Support\\Facades\\Response\:\:created\(\) invoked with 3 parameters, 0 required\.$#'
+ identifier: arguments.count
+ count: 1
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Static method Apiato\\Support\\Facades\\Response\:\:noContent\(\) invoked with 2 parameters, 0 required\.$#'
+ identifier: arguments.count
+ count: 1
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Static method Apiato\\Support\\Facades\\Response\:\:ok\(\) invoked with 3 parameters, 0 required\.$#'
+ identifier: arguments.count
+ count: 1
+ path: tests/Unit/Support/Facades/ResponseTest.php
+
+ -
+ message: '#^Anonymous function should return Pest\\Expectation but returns Pest\\Mixins\\Expectation\<\(Closure\)\|null\>\.$#'
+ identifier: return.type
+ count: 4
+ path: tests/Unit/Support/HashidsManagerDecoratorTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Support/HashidsManagerDecoratorTest.php
+
+ -
+ message: '#^Dynamic call to static method GrahamCampbell\\Manager\\AbstractManager\:\:connection\(\)\.$#'
+ identifier: staticMethod.dynamicCall
+ count: 1
+ path: tests/Unit/Support/HashidsManagerDecoratorTest.php
+
+ -
+ message: '#^Dynamic call to static method GrahamCampbell\\Manager\\AbstractManager\:\:getDefaultConnection\(\)\.$#'
+ identifier: staticMethod.dynamicCall
+ count: 1
+ path: tests/Unit/Support/HashidsManagerDecoratorTest.php
+
+ -
+ message: '#^Function class_parents is unsafe to use\. It can return FALSE instead of throwing an exception\. Please add ''use function Safe\\class_parents;'' at the beginning of the file to use the variant provided by the ''thecodingmachine/safe'' library\.$#'
+ identifier: theCodingMachineSafe.function
+ count: 1
+ path: tests/Unit/Support/HashidsManagerDecoratorTest.php
+
+ -
+ message: '#^Function class_uses is unsafe to use\. It can return FALSE instead of throwing an exception\. Please add ''use function Safe\\class_uses;'' at the beginning of the file to use the variant provided by the ''thecodingmachine/safe'' library\.$#'
+ identifier: theCodingMachineSafe.function
+ count: 2
+ path: tests/Unit/Support/HashidsManagerDecoratorTest.php
+
+ -
+ message: '#^Parameter \#1 \.\.\.\$numbers of method Apiato\\Support\\HashidsManagerDecorator\:\:encode\(\) expects int\|string, mixed given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Support/HashidsManagerDecoratorTest.php
+
+ -
+ message: '#^Call to an undefined method Pest\\PendingCalls\\DescribeCall\:\:covers\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: tests/Unit/Support/SanitizerTest.php
+
+ -
+ message: '#^Parameter \#1 \$source of static method Apiato\\Support\\Sanitizer\:\:sanitize\(\) expects array\, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Support/SanitizerTest.php
+
+ -
+ message: '#^Parameter \#2 \$fields of static method Apiato\\Support\\Sanitizer\:\:sanitize\(\) expects array\, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: tests/Unit/Support/SanitizerTest.php
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 000000000..c54066911
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,23 @@
+#https://phpstan.org/user-guide/getting-started
+
+includes:
+ - phpstan-baseline.neon
+
+parameters:
+ level: max
+ paths:
+ - config
+ - src
+ - tests
+ - .php-cs-fixer.dist.php
+ tmpDir: phpstan_cache
+ excludePaths:
+ - tests/Support/Doubles/Fakes/Laravel/vendor (?)
+
+ reportUnmatchedIgnoredErrors: true
+
+# ignoreErrors:
+# - '#PHPDoc tag @var#'
+
+ fileExtensions:
+ - php
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
deleted file mode 100644
index 2e6d80242..000000000
--- a/phpstan.neon.dist
+++ /dev/null
@@ -1,16 +0,0 @@
-includes:
- - vendor/phpstan/phpstan-strict-rules/rules.neon
- - vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon
- - vendor/larastan/larastan/extension.neon
- - vendor/nesbot/carbon/extension.neon
- - vendor/phpstan/phpstan-phpunit/extension.neon
-parameters:
- level: max
- paths:
- - config
- - src
- - tests
- - .php-cs-fixer.dist.php
- tmpDir: phpstan_cache
- excludePaths:
- - tests/Support/Doubles/Fakes/Laravel/vendor (?)
diff --git a/psalm.xml b/psalm.xml
deleted file mode 100644
index 0a3ccfeaa..000000000
--- a/psalm.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/rector.php b/rector.php
index 0d292ceb6..a62dc66a9 100644
--- a/rector.php
+++ b/rector.php
@@ -2,16 +2,133 @@
declare(strict_types=1);
+use Apiato\Linters\Rector\AssertInstanceToStaticCallRector;
+use Apiato\Linters\Rector\MockObjectStaticToInstanceCallRector;
+use Rector\Caching\ValueObject\Storage\FileCacheStorage;
+use Rector\CodeQuality\Rector\ClassMethod\LocallyCalledStaticMethodToNonStaticRector;
+use Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector;
+use Rector\CodeQuality\Rector\Identical\SimplifyBoolIdenticalTrueRector;
+use Rector\CodeQuality\Rector\Isset_\IssetOnPropertyObjectToPropertyExistsRector;
+use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector;
+use Rector\CodingStyle\Rector\PostInc\PostIncDecToPreIncDecRector;
+use Rector\CodingStyle\Rector\Use_\SeparateMultiUseImportsRector;
use Rector\Config\RectorConfig;
+use Rector\DeadCode\Rector\StaticCall\RemoveParentCallWithoutParentRector;
+use Rector\Doctrine\Dbal211\Rector\MethodCall\ReplaceFetchAllMethodCallRector;
+use Rector\Doctrine\Orm214\Rector\Param\ReplaceLifecycleEventArgsByDedicatedEventArgsRector;
+use Rector\Naming\Rector\Assign\RenameVariableToMatchMethodCallReturnTypeRector;
+use Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector;
+use Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector;
+use Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector;
+use Rector\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchExprVariableRector;
+use Rector\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector;
+use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector;
+use Rector\Php73\Rector\BooleanOr\IsCountableRector;
+use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;
+use Rector\Php74\Rector\Property\RestoreDefaultNullToNullableTypePropertyRector;
+use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector;
+use Rector\PHPUnit\Set\PHPUnitSetList;
+use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector;
+use Rector\Set\ValueObject\LevelSetList;
+use Rector\Set\ValueObject\SetList;
+use Rector\TypeDeclaration\Rector\Class_\TypedPropertyFromCreateMockAssignRector;
+use Rector\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector;
+use Rector\ValueObject\PhpVersion;
+use RectorLaravel\Set\LaravelLevelSetList;
+use RectorLaravel\Set\LaravelSetList;
return RectorConfig::configure()
+ ->withCache(
+ // specify a path that works locally as well as on CI job runners
+ cacheDirectory: '/tmp/rector',
+ // ensure file system caching is used instead of in-memory
+ cacheClass: FileCacheStorage::class
+ )
+ ->withRootFiles()
+ // https://getrector.com/documentation/troubleshooting-parallel
+ ->withParallel(360, 2, 40)
+ ->withImportNames(importDocBlockNames: false, importShortClasses: false)
+ ->withPreparedSets(
+ deadCode: true,
+ codeQuality: true,
+ codingStyle: true,
+ typeDeclarations: true,
+ privatization: true,
+ naming: true,
+ instanceOf: true,
+ earlyReturn: true,
+ strictBooleans: true,
+ carbon: true,
+ rectorPreset: true,
+ phpunitCodeQuality: true,
+ doctrineCodeQuality: false,
+ symfonyCodeQuality: true,
+ symfonyConfigs: false,
+ )
+ ->withComposerBased(
+ phpunit: true,
+ )
+ ->withAttributesSets(
+ phpunit: true,
+ )
+ ->withRules([
+ ReplaceFetchAllMethodCallRector::class,
+ ReplaceLifecycleEventArgsByDedicatedEventArgsRector::class,
+ MockObjectStaticToInstanceCallRector::class,
+ AssertInstanceToStaticCallRector::class,
+ ])
+ ->withSets([
+ PHPUnitSetList::PHPUNIT_90,
+ PHPUnitSetList::PHPUNIT_100,
+ PHPUnitSetList::PHPUNIT_110,
+ PHPUnitSetList::PHPUNIT_CODE_QUALITY,
+ PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES,
+
+ SetList::CODE_QUALITY,
+ SetList::CODING_STYLE,
+ SetList::TYPE_DECLARATION,
+ SetList::EARLY_RETURN,
+ SetList::STRICT_BOOLEANS,
+
+ LevelSetList::UP_TO_PHP_82,
+ LaravelLevelSetList::UP_TO_LARAVEL_120,
+ LaravelSetList::LARAVEL_120,
+ LaravelSetList::LARAVEL_CODE_QUALITY,
+ LaravelSetList::LARAVEL_ARRAY_STR_FUNCTION_TO_STATIC_CALL,
+ ])
+ ->withPhpVersion(PhpVersion::PHP_82)
->withPaths([
__DIR__ . '/config',
__DIR__ . '/src',
__DIR__ . '/tests',
__DIR__ . '/workbench',
])
- ->withPhpSets(php82: true)
- ->withTypeCoverageLevel(100)
- ->withDeadCodeLevel(100)
- ->withCodeQualityLevel(100);
+ ->withSkip([
+ __DIR__ . '/workbench/bootstrap/',
+ SimplifyBoolIdenticalTrueRector::class, // it's breaks the Routers
+ IsCountableRector::class, // this rule does not fit, a lot of where it goes wrong
+ RestoreDefaultNullToNullableTypePropertyRector::class, // don't work with DTO nullable parameter
+ RemoveExtraParametersRector::class, // catting an argument in dump() function
+ ClosureToArrowFunctionRector::class, // it's breaks the Routers
+ SeparateMultiUseImportsRector::class, // it's breaks the using multiple Traits
+ LocallyCalledStaticMethodToNonStaticRector::class,
+ PreferPHPUnitThisCallRector::class, // it's breaks with phpstan
+ RenamePropertyToMatchTypeRector::class, // it's breaks the Entity
+ RenameVariableToMatchMethodCallReturnTypeRector::class, // it's redundant
+ RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class, // it's redundant
+ RenameForeachValueVariableToMatchExprVariableRector::class, // it's breaks the unit tests
+ TypedPropertyFromCreateMockAssignRector::class, // it's breaks the unit tests
+ RenameVariableToMatchNewTypeRector::class, // it's breaks the unit tests
+
+ // THINKING
+ AddMethodCallBasedStrictParamTypeRector::class, // it's breaks the using multiple Traits
+ FlipTypeControlToUseExclusiveTypeRector::class,
+ IssetOnPropertyObjectToPropertyExistsRector::class,
+ RenameParamToMatchTypeRector::class,
+ PostIncDecToPreIncDecRector::class,
+
+ // WAITING FIX
+ MakeInheritedMethodVisibilitySameAsParentRector::class,
+ RemoveParentCallWithoutParentRector::class,
+ ])
+ ->withFileExtensions(['php']);
diff --git a/ruleset.xml b/ruleset.xml
deleted file mode 100644
index 8b9d18b08..000000000
--- a/ruleset.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- Apiato PHPMD rulesets
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
diff --git a/src/Console/CommandServiceProvider.php b/src/Console/CommandServiceProvider.php
index 63b2f3576..f0f75c207 100644
--- a/src/Console/CommandServiceProvider.php
+++ b/src/Console/CommandServiceProvider.php
@@ -1,5 +1,7 @@
beforeLast(DIRECTORY_SEPARATOR)
->afterLast(DIRECTORY_SEPARATOR)
->value())->each(function (Collection $files, string $group): void {
- $this->comment("[{$group}]");
+ $this->comment(\sprintf('[%s]', $group));
/** @var SplFileInfo $file */
foreach ($files as $file) {
@@ -38,10 +43,10 @@ public function handle(): void
->headline();
if ($this->option('with-file-name')) {
- $includeFileName = "({$originalFileName})";
- $this->info(" - {$fileName} {$includeFileName}");
+ $includeFileName = \sprintf('(%s)', $originalFileName);
+ $this->info(\sprintf(' - %s %s', $fileName, $includeFileName));
} else {
- $this->info(" - {$fileName}");
+ $this->info(' - ' . $fileName);
}
}
});
diff --git a/src/Console/Commands/ListTasks.php b/src/Console/Commands/ListTasks.php
index 6347bcf60..303798a58 100644
--- a/src/Console/Commands/ListTasks.php
+++ b/src/Console/Commands/ListTasks.php
@@ -1,5 +1,7 @@
beforeLast(DIRECTORY_SEPARATOR)
->afterLast(DIRECTORY_SEPARATOR)
->value())->each(function (Collection $files, string $group): void {
- $this->comment("[{$group}]");
+ $this->comment(\sprintf('[%s]', $group));
/** @var SplFileInfo $file */
foreach ($files as $file) {
@@ -38,10 +43,10 @@ public function handle(): void
->headline();
if ($this->option('with-file-name')) {
- $includeFileName = "({$originalFileName})";
- $this->info(" - {$fileName} {$includeFileName}");
+ $includeFileName = \sprintf('(%s)', $originalFileName);
+ $this->info(\sprintf(' - %s %s', $fileName, $includeFileName));
} else {
- $this->info(" - {$fileName}");
+ $this->info(' - ' . $fileName);
}
}
});
diff --git a/src/Core/Actions/Action.php b/src/Core/Actions/Action.php
index f54a9df59..83c2eb397 100644
--- a/src/Core/Actions/Action.php
+++ b/src/Core/Actions/Action.php
@@ -1,5 +1,7 @@
static::run(...$args));
+ return DB::transaction(fn (): mixed => $this->run(...$args));
}
}
diff --git a/src/Core/Actions/SubAction.php b/src/Core/Actions/SubAction.php
index 089010c14..baaef371b 100644
--- a/src/Core/Actions/SubAction.php
+++ b/src/Core/Actions/SubAction.php
@@ -1,5 +1,7 @@
factory()
->resolveFactoryName(static::class);
- if (is_string($factoryName)) {
+ if (\is_string($factoryName)) {
return $factoryName::new();
}
diff --git a/src/Core/Models/Concerns/HandlesHashedIdRouteModelBinding.php b/src/Core/Models/Concerns/HandlesHashedIdRouteModelBinding.php
index b517e1128..65a44ffd6 100644
--- a/src/Core/Models/Concerns/HandlesHashedIdRouteModelBinding.php
+++ b/src/Core/Models/Concerns/HandlesHashedIdRouteModelBinding.php
@@ -1,5 +1,7 @@
getKeyName();
}
$attribute = $this->getAttribute($field);
- if (is_null($attribute)) {
+ if (\is_null($attribute)) {
return null;
}
diff --git a/src/Core/Models/InteractsWithApiato.php b/src/Core/Models/InteractsWithApiato.php
index c11453175..71ee3bec9 100644
--- a/src/Core/Models/InteractsWithApiato.php
+++ b/src/Core/Models/InteractsWithApiato.php
@@ -1,5 +1,7 @@
scope(function (Builder|Model $model) use ($requestRelation): Builder|Model {
+ $this->scope(static function (Builder|Model $model) use ($requestRelation): Builder|Model {
if ($requestRelation->requestingIncludes()) {
if ($model instanceof Model) {
return $model->with($requestRelation->getValidRelationsFor($model));
@@ -106,12 +110,13 @@ public function getModel()
/**
* Retrieve all data of repository, paginated.
*
- * @param int|null $limit The number of entries per page. If set to 0, the pagination is disabled.
- * @param array $columns
- * @param string $method
+ * @param int|null $limit The number of entries per page. If set to 0, the pagination is disabled.
+ * @param array $columns
+ * @param string $method
*
* @throws RepositoryException
*/
+ #[\Override]
public function paginate($limit = null, $columns = ['*'], $method = 'paginate'): mixed
{
$limit = $this->setPaginationLimit($limit);
@@ -128,7 +133,7 @@ public function paginate($limit = null, $columns = ['*'], $method = 'paginate'):
return parent::paginate($limit, $columns, $method);
}
- $key = $this->getCacheKey('paginate', func_get_args());
+ $key = $this->getCacheKey('paginate', \func_get_args());
$time = $this->getCacheTime();
$value = $this->getCacheRepository()->remember($key, $time, function () use ($limit, $columns, $method) {
@@ -141,26 +146,26 @@ public function paginate($limit = null, $columns = ['*'], $method = 'paginate'):
return $value;
}
- public function setPaginationLimit($limit): mixed
+ public function setPaginationLimit(null|int|string $limit = null): int
{
- // the priority is for the function parameter, if not available then take
- // it from the request if available and if not keep it null.
- return $limit ?? request()?->input('limit');
+ // The priority is for the function parameter, if not available then take it
+ // from the request if available and if not keep it null.
+ return (int)($limit ?? request()?->input('limit', 0));
}
- public function wantsToSkipPagination(string|int|null $limit): bool
+ public function wantsToSkipPagination(int $limit): bool
{
- return '0' === $limit || 0 === $limit;
+ return $limit === 0;
}
public function canSkipPagination(): mixed
{
- // check local (per repository) rule
- if (!is_null($this->allowDisablePagination)) {
+ // Check local (per repository) rule
+ if (!\is_null($this->allowDisablePagination)) {
return $this->allowDisablePagination;
}
- // check global (.env) rule
+ // Check global (.env) rule
return config('repository.pagination.skip');
}
@@ -179,7 +184,7 @@ public function all($columns = ['*'])
return parent::all($columns);
}
- $key = $this->getCacheKey('all', func_get_args());
+ $key = $this->getCacheKey('all', \func_get_args());
$time = $this->getCacheTime();
$value = $this->getCacheRepository()->remember($key, $time, function () use ($columns) {
return parent::all($columns);
@@ -194,6 +199,7 @@ public function all($columns = ['*'])
public function resetScope(): static
{
parent::resetScope();
+
$this->resetScopes();
return $this;
@@ -214,125 +220,41 @@ public function exceedsMaxPaginationLimit(mixed $limit): bool
/**
* @throws RepositoryException
*/
- public function addRequestCriteria(array $fieldsToDecode = ['id']): static
+ public function addRequestCriteria(): static
{
- $this->pushCriteria(app(RequestCriteria::class));
if ($this->shouldDecodeSearch()) {
- $this->decodeSearchQueryString($fieldsToDecode);
- }
-
- return $this;
- }
-
- private function shouldDecodeSearch(): bool
- {
- return config('apiato.hash-id') && $this->isSearching(request()->query());
- }
-
- private function isSearching(array $query): bool
- {
- return array_key_exists('search', $query) && $query['search'];
- }
-
- public function decodeSearchQueryString(array $fieldsToDecode): void
- {
- $query = request()->query();
- $searchQuery = $query['search'];
-
- $decodedValue = $this->decodeValue($searchQuery);
- $decodedData = $this->decodeData($fieldsToDecode, $searchQuery);
-
- $decodedQuery = $this->arrayToSearchQuery($decodedData);
-
- if ($decodedValue) {
- if (empty($decodedQuery)) {
- $decodedQuery .= $decodedValue;
- } else {
- $decodedQuery .= (';' . $decodedValue);
- }
+ $this->decodeSearchQueryString();
}
- $query['search'] = $decodedQuery;
-
- request()->query->replace($query);
- }
-
- private function decodeValue(string $searchQuery): string|int|null
- {
- $searchValue = $this->parserSearchValue($searchQuery);
-
- if (is_string($searchValue)) {
- return hashids()->decode($searchValue) ?? $searchValue;
- }
-
- return null;
- }
-
- private function parserSearchValue($search)
- {
- if (strpos((string) $search, ';') || strpos((string) $search, ':')) {
- $values = explode(';', (string) $search);
- foreach ($values as $value) {
- $s = explode(':', $value);
- if (1 === count($s)) {
- return $s[0];
- }
- }
-
- return null;
- }
+ $this->pushCriteria(app(RequestCriteria::class));
- return $search;
+ return $this;
}
- private function decodeData(array $fieldsToDecode, string $searchQuery): array
+ public function decodeSearchQueryString(): void
{
- $searchArray = $this->parserSearchData($searchQuery);
+ /** @var Request $request */
+ $request = app(Request::class);
+ $query = $request->query();
+ $searchKey = config('repository.criteria.params.search', 'search');
+ $searchQuery = $query[$searchKey];
- foreach ($fieldsToDecode as $field) {
- if (array_key_exists($field, $searchArray)) {
- $searchArray[$field] = hashids()->decodeOrFail($searchArray[$field]);
- }
+ if (\is_string($searchQuery) === false || $searchQuery === '') {
+ return;
}
- return $searchArray;
- }
+ $searchData = $this->parserSearchData($searchQuery);
+ $decodedData = $this->getDecodedSearchValues($searchData);
- private function parserSearchData($search): array
- {
- $searchData = [];
-
- if (strpos((string) $search, ':')) {
- $fields = explode(';', (string) $search);
-
- foreach ($fields as $row) {
- try {
- [$field, $value] = explode(':', $row);
- $searchData[$field] = $value;
- } catch (\Exception) {
- // Surround offset error
- }
- }
+ if ($decodedData === $searchData) {
+ return;
}
- return $searchData;
- }
-
- private function arrayToSearchQuery(array $decodedSearchArray): string
- {
- $decodedSearchQuery = '';
+ $newSearchQuery = $this->arrayToSearchQuery($decodedData);
- $fields = array_keys($decodedSearchArray);
- $length = count($fields);
- for ($i = 0; $i < $length; ++$i) {
- $field = $fields[$i];
- $decodedSearchQuery .= "{$field}:$decodedSearchArray[$field]";
- if (1 !== $length && $i < $length - 1) {
- $decodedSearchQuery .= ';';
- }
- }
+ $query[$searchKey] = $newSearchQuery;
- return $decodedSearchQuery;
+ $request->query->replace($query);
}
public function removeRequestCriteria(): static
@@ -361,7 +283,7 @@ public function make(array $attributes)
*/
public function store(Arrayable|array $data)
{
- if (is_array($data)) {
+ if (\is_array($data)) {
return $this->create($data);
}
@@ -379,7 +301,7 @@ public function create(array $attributes)
{
try {
return parent::create($attributes);
- } catch (\Exception) {
+ } catch (\Throwable) {
throw ResourceCreationFailed::create(class_basename($this->model()));
}
}
@@ -412,6 +334,7 @@ public function firstOrCreate(array $attributes = [], array $values = [])
{
/** @var TModel $model */
$model = parent::firstOrCreate($attributes);
+
if ($model->wasRecentlyCreated) {
$model->update($values);
}
@@ -454,7 +377,7 @@ public function findOrFail(int|string $id, array $columns = ['*'])
* Find an entity/s by its primary key.
*
* @param int|string|array|Arrayable $id
- * @param array $columns
+ * @param array $columns
*
* @return ($id is array|Arrayable ? Collection : TModel|null)
*
@@ -467,7 +390,7 @@ public function find($id, $columns = ['*'])
return parent::find($id, $columns);
}
- $key = $this->getCacheKey('find', func_get_args());
+ $key = $this->getCacheKey('find', \func_get_args());
$time = $this->getCacheTime();
$value = $this->getCacheRepository()->remember($key, $time, function () use ($id, $columns) {
return parent::find($id, $columns);
@@ -506,7 +429,7 @@ public function findMany(array|Arrayable $ids, array $columns = ['*'])
* Find data by field and value.
*
* @param (\Closure(static): mixed)|string|array|Expression $field
- * @param array $columns
+ * @param array $columns
*
* @return Collection
*/
@@ -516,7 +439,7 @@ public function findByField($field, $value = null, $columns = ['*'])
return parent::findByField($field, $value, $columns);
}
- $key = $this->getCacheKey('findByField', func_get_args());
+ $key = $this->getCacheKey('findByField', \func_get_args());
$time = $this->getCacheTime();
$value = $this->getCacheRepository()->remember($key, $time, function () use ($field, $value, $columns) {
return parent::findByField($field, $value, $columns);
@@ -541,7 +464,7 @@ public function findWhere(array $where, $columns = ['*'])
return parent::findWhere($where, $columns);
}
- $key = $this->getCacheKey('findWhere', func_get_args());
+ $key = $this->getCacheKey('findWhere', \func_get_args());
$time = $this->getCacheTime();
$value = $this->getCacheRepository()->remember($key, $time, function () use ($where, $columns) {
return parent::findWhere($where, $columns);
@@ -571,7 +494,7 @@ public function delete($id): bool
/**
* @param class-string $criteria Criteria class name
- * @param array $args Arguments to pass to the criteria constructor
+ * @param array $args Arguments to pass to the criteria constructor
*
* @throws RepositoryException
* @throws BindingResolutionException
@@ -587,6 +510,7 @@ public function pushCriteriaWith(string $criteria, array $args): static
protected function applyScope(): static
{
parent::applyScope();
+
$this->applyScopes();
return $this;
@@ -595,12 +519,109 @@ protected function applyScope(): static
protected function applyScopes(): static
{
foreach ($this->scopes as $scope) {
- if (!is_callable($scope)) {
+ if (!\is_callable($scope)) {
throw new \RuntimeException('Query scope is not callable');
}
+
$this->model = $scope($this->model);
}
return $this;
}
+
+ private function parserSearchData(string $search): array
+ {
+ $searchData = [];
+
+ if (str_contains($search, ':') === false) {
+ return $searchData;
+ }
+
+ $fields = explode(';', $search);
+
+ foreach ($fields as $field) {
+ if (str_contains($field, ':') === false) {
+ continue;
+ }
+
+ $parts = explode(':', $field, 2);
+
+ if (\count($parts) !== 2) {
+ continue;
+ }
+
+ $field = trim($parts[0]);
+
+ if ($field === '') {
+ continue;
+ }
+
+ $searchData[$field] = trim($parts[1]);
+ }
+
+ return $searchData;
+ }
+
+ private function getDecodedSearchValues(array $searchData): array
+ {
+ foreach ($searchData as $field => $value) {
+ $isBool = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+
+ if ($isBool !== null) {
+ $searchData[$field] = $value;
+ continue;
+ }
+
+ if (is_numeric($value)) {
+ $searchData[$field] = $value;
+ continue;
+ }
+
+ $decodedId = hashids()->decode($value);
+
+ if ($decodedId === null) {
+ $searchData[$field] = $value;
+ continue;
+ }
+
+ $searchData[$field] = $decodedId;
+ }
+
+ return $searchData;
+ }
+
+ private function shouldDecodeSearch(): bool
+ {
+ return config('apiato.hash-id') && $this->isSearching();
+ }
+
+ private function isSearching(): bool
+ {
+ $searchKey = config('repository.criteria.params.search', 'search');
+ /** @var Request $request */
+ $request = app(Request::class);
+
+ return $request->filled($searchKey);
+ }
+
+ /**
+ * Reconstructs the search string from an array of field => value pairs.
+ */
+ private function arrayToSearchQuery(array $decodedSearchArray): string
+ {
+ $decodedSearchQuery = '';
+
+ $fields = array_keys($decodedSearchArray);
+ $length = \count($fields);
+ foreach ($fields as $i => $iValue) {
+ $field = $iValue;
+ $decodedSearchQuery .= \sprintf('%s:%s', $field, $decodedSearchArray[$field]);
+
+ if ($length !== 1 && $i < $length - 1) {
+ $decodedSearchQuery .= ';';
+ }
+ }
+
+ return $decodedSearchQuery;
+ }
}
diff --git a/src/Core/Requests/Request.php b/src/Core/Requests/Request.php
index 743e7d018..58ac86025 100644
--- a/src/Core/Requests/Request.php
+++ b/src/Core/Requests/Request.php
@@ -1,5 +1,7 @@
decode;
}
+ /** @inheritDoc */
+ #[\Override]
public function route($param = null, $default = null)
{
- if (in_array($param, $this->decode, true) && config('apiato.hash-id')) {
+ if (\in_array($param, $this->decode, true) && config('apiato.hash-id')) {
$value = parent::route($param);
- if (is_null($value)) {
+ if (\is_null($value)) {
return $default;
}
@@ -42,6 +46,8 @@ public function route($param = null, $default = null)
return parent::route($param, $default);
}
+ /** @inheritDoc */
+ #[\Override]
public function input($key = null, $default = null)
{
if (!config('apiato.hash-id')) {
diff --git a/src/Core/Seeders/Seeder.php b/src/Core/Seeders/Seeder.php
index c4f722f42..7fcb65aac 100644
--- a/src/Core/Seeders/Seeder.php
+++ b/src/Core/Seeders/Seeder.php
@@ -1,9 +1,17 @@
$expectedColumns The key is the column name and the value is the column type.
*
- * Example: $this->assertDatabaseTable('users', ['id' => 'bigint']);
+ * Example: self::assertDatabaseTable('users', ['id' => 'bigint']);
*/
- protected function assertDatabaseTable(string $table, array $expectedColumns): void
+ protected static function assertDatabaseTable(string $table, array $expectedColumns): void
{
- $this->assertSameSize($expectedColumns, Schema::getColumnListing($table), "Column count mismatch for '{$table}' table.");
+ self::assertSameSize($expectedColumns, Schema::getColumnListing($table), \sprintf("Column count mismatch for '%s' table.", $table));
foreach ($expectedColumns as $column => $type) {
- $this->assertTrue(Schema::hasColumn($table, $column), "Column '{$column}' not found in '{$table}' table.");
- $this->assertEquals($type, Schema::getColumnType($table, $column), "Column '{$column}' in '{$table}' table does not match expected {$type} type.");
+ self::assertTrue(Schema::hasColumn($table, $column), \sprintf("Column '%s' not found in '%s' table.", $column, $table));
+ self::assertEquals($type, Schema::getColumnType($table, $column), \sprintf("Column '%s' in '%s' table does not match expected %s type.", $column, $table, $type));
}
}
}
diff --git a/src/Core/Testing/TestCase.php b/src/Core/Testing/TestCase.php
index 2638ea203..39797533c 100644
--- a/src/Core/Testing/TestCase.php
+++ b/src/Core/Testing/TestCase.php
@@ -1,5 +1,7 @@
[];
}
- public function nullableItem(mixed $data, callable|self $transformer, string|null $resourceKey = null): Primitive|Item
+ public function nullableItem(mixed $data, callable|self $transformer, null|string $resourceKey = null): Primitive|Item
{
- if (is_null($data)) {
+ if (\is_null($data)) {
return $this->primitive(null);
}
return $this->item($data, $transformer, $resourceKey);
}
- public function item($data, $transformer, string|null $resourceKey = null): Item
+ /** @inheritDoc */
+ #[\Override]
+ public function item($data, $transformer, null|string $resourceKey = null): Item
{
return new Item($data, $transformer, $resourceKey);
}
- public function collection($data, $transformer, string|null $resourceKey = null): Collection
+ /** @inheritDoc */
+ #[\Override]
+ public function collection($data, $transformer, null|string $resourceKey = null): Collection
{
return new Collection($data, $transformer, $resourceKey);
}
diff --git a/src/Core/Values/Value.php b/src/Core/Values/Value.php
index 59f57bb04..549278c85 100644
--- a/src/Core/Values/Value.php
+++ b/src/Core/Values/Value.php
@@ -1,5 +1,7 @@
basePath);
+
+ return (new ApplicationBuilder(self::$instance))->create();
+ }
+
+ public static function configure(null|string $basePath = null): ApplicationBuilder
{
if (isset(self::$instance)) {
return new ApplicationBuilder(self::$instance);
}
$basePath = match (true) {
- is_string($basePath) => $basePath,
- default => self::inferBasePath(),
+ \is_string($basePath) => $basePath,
+ default => self::inferBasePath(),
};
self::$instance = new self($basePath);
@@ -64,28 +97,10 @@ public static function inferBasePath(): string
{
return match (true) {
isset($_ENV['APP_BASE_PATH']) => $_ENV['APP_BASE_PATH'],
- default => dirname(array_keys(ClassLoader::getRegisteredLoaders())[0]),
+ default => self::findShortestVendorPath(),
};
}
- /**
- * Get the singleton instance of the class.
- */
- public static function instance(): self
- {
- return self::$instance;
- }
-
- /**
- * Reset the configured instance to its default state.
- */
- public static function reset(): self
- {
- self::$instance = new self(self::$instance->basePath);
-
- return (new ApplicationBuilder(self::$instance))->create();
- }
-
public function basePath(): string
{
return $this->basePath;
@@ -96,7 +111,7 @@ public function basePath(): string
*/
public function sharedPath(string $path = ''): string
{
- return join_paths($this->sharedPath ?: app_path('Ship'), $path);
+ return join_paths($this->sharedPath !== '' && $this->sharedPath !== '0' ? $this->sharedPath : app_path('Ship'), $path);
}
/**
@@ -109,77 +124,77 @@ public function useSharedPath(string $path): self
return $this;
}
- public function withRouting(callable|null $callback = null): self
+ public function withRouting(null|callable $callback = null): self
{
$this->routing ??= new Routing();
- if (!is_null($callback)) {
+ if (!\is_null($callback)) {
$callback($this->routing);
}
return $this;
}
- public function withFactories(callable|null $callback = null): self
+ public function withFactories(null|callable $callback = null): self
{
$this->factory ??= new Factory();
- if (!is_null($callback)) {
+ if (!\is_null($callback)) {
$callback($this->factory);
}
return $this;
}
- public function withRepositories(callable|null $callback = null): self
+ public function withRepositories(null|callable $callback = null): self
{
$this->repository ??= new Repository();
- if (!is_null($callback)) {
+ if (!\is_null($callback)) {
$callback($this->repository);
}
return $this;
}
- public function withViews(callable|null $callback = null): self
+ public function withViews(null|callable $callback = null): self
{
$this->view ??= new View();
- if (!is_null($callback)) {
+ if (!\is_null($callback)) {
$callback($this->view);
}
return $this;
}
- public function withTranslations(callable|null $callback = null): self
+ public function withTranslations(null|callable $callback = null): self
{
$this->localization ??= new Localization();
- if (!is_null($callback)) {
+ if (!\is_null($callback)) {
$callback($this->localization);
}
return $this;
}
- public function withSeeders(callable|null $callback = null): self
+ public function withSeeders(null|callable $callback = null): self
{
$this->seeding ??= new Seeding();
- if (!is_null($callback)) {
+ if (!\is_null($callback)) {
$callback($this->seeding);
}
return $this;
}
- public function withProviders(callable|null $callback = null): self
+ public function withProviders(null|callable $callback = null): self
{
$this->provider ??= new Provider();
- if (!is_null($callback)) {
+ if (!\is_null($callback)) {
$callback($this->provider);
}
@@ -221,7 +236,7 @@ public function withConfigs(string ...$path): void
public function configs(): array
{
return collect($this->configPaths)->flatMap(
- static fn (string $path): array => \Safe\glob($path . '/*.php'),
+ static fn (string $path): array => glob($path . '/*.php'),
)->toArray();
}
@@ -233,7 +248,7 @@ public function configs(): array
public function helpers(): array
{
return collect($this->helperPaths)->flatMap(
- static fn (string $path): array => \Safe\glob($path . '/*.php'),
+ static fn (string $path): array => glob($path . '/*.php'),
)->toArray();
}
@@ -337,4 +352,27 @@ public function view(): View
{
return $this->view;
}
+
+ /**
+ * Find the shortest vendor path, which should be the main project's vendor directory.
+ *
+ * TODO: This approach is needed because:
+ * 1. In CI environments, the order of ClassLoader instances can differ from local/Docker environments
+ * 2. There can be multiple ClassLoader instances (main project + nested ones like rector/rector)
+ * 3. When CI runs, sometimes the nested loader from vendor/rector/rector/vendor appears first
+ * causing base path to be incorrectly resolved to /home/runner/work/core/core/vendor/rector/rector
+ * 4. By selecting the shortest path, we consistently get the main project's vendor dir
+ * regardless of loader registration order
+ */
+ private static function findShortestVendorPath(): string
+ {
+ $registeredLoaders = ClassLoader::getRegisteredLoaders();
+ $vendorPaths = array_keys($registeredLoaders);
+
+ usort($vendorPaths, static function ($a, $b): int {
+ return \strlen($a) - \strlen($b);
+ });
+
+ return \dirname($vendorPaths[0]);
+ }
}
diff --git a/src/Foundation/Configuration/ApplicationBuilder.php b/src/Foundation/Configuration/ApplicationBuilder.php
index 5e1a10afb..2a9ea15c2 100644
--- a/src/Foundation/Configuration/ApplicationBuilder.php
+++ b/src/Foundation/Configuration/ApplicationBuilder.php
@@ -1,117 +1,69 @@
withDefaults($this->apiato->basePath());
- }
-
- private function withDefaults(string $basePath): void
+ public function __construct(private Apiato $apiato)
{
- $this->useSharedPath(
- $this->joinPaths($basePath, 'app/Ship'),
- )->withConfigs(
- shared_path('Configs'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Configs')),
- )->withEvents(
- shared_path('Listeners'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Listeners')),
- )->withCommands(
- shared_path('Commands'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/CLI/Commands')),
- )->withHelpers(
- shared_path('Helpers'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Helpers')),
- )->withMigrations(
- shared_path('Migrations'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Data/Migrations')),
- )->withProviders(function (Provider $provider) use ($basePath): void {
- $provider->loadFrom(
- shared_path('Providers'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Providers')),
- );
- })->withSeeders(function (Seeding $seeding) use ($basePath): void {
- $seeding->loadFrom(
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Data/Seeders')),
- );
- })->withTranslations(function (Localization $localization) use ($basePath): void {
- $localization->loadFrom(
- shared_path('Languages'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Languages')),
- );
- })->withViews(function (View $view) use ($basePath): void {
- $view->loadFrom(
- shared_path('Views'),
- shared_path('Mails/Templates'),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/WEB/Views')),
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Mails/Templates')),
- );
- })->withRouting(function (Routing $routing) use ($basePath): void {
- $routing->loadApiRoutesFrom(
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/API/Routes')),
- )->loadWebRoutesFrom(
- ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/WEB/Routes')),
- );
- })->withFactories()
- ->withRepositories();
+ $this->withDefaults($this->apiato->basePath());
}
// TODO: remove non-standard Laravel configs like the specific Repository classes we have in Apiato.
// Extend the config and add the repository configuration. So anybody can add their own custom configuration.
- // Also the same goes for the helpers config I guess? Checkout what other configs we added that could be considered custom and
- // non-standard Laravel stuff.
- public function withRepositories(callable|null $callback = null): self
+ // Also the same goes for the helpers config I guess?
+ // Checkout what other configs we added that could be considered custom and non-standard Laravel stuff.
+ public function withRepositories(null|callable $callback = null): self
{
$this->apiato->withRepositories($callback);
return $this;
}
- public function withFactories(callable|null $callback = null): self
+ public function withFactories(null|callable $callback = null): self
{
$this->apiato->withFactories($callback);
return $this;
}
- public function withRouting(callable|null $callback = null): self
+ public function withRouting(null|callable $callback = null): self
{
$this->apiato->withRouting($callback);
return $this;
}
- public function withViews(callable|null $callback = null): self
+ public function withViews(null|callable $callback = null): self
{
$this->apiato->withViews($callback);
return $this;
}
- public function withTranslations(callable|null $callback = null): self
+ public function withTranslations(null|callable $callback = null): self
{
$this->apiato->withTranslations($callback);
return $this;
}
- public function withSeeders(callable|null $callback = null): self
+ public function withSeeders(null|callable $callback = null): self
{
$this->apiato->withSeeders($callback);
return $this;
}
- public function withProviders(callable|null $callback = null): self
+ public function withProviders(null|callable $callback = null): self
{
$this->apiato->withProviders($callback);
@@ -163,6 +115,61 @@ public function useSharedPath(string $path): self
return $this;
}
+ public function create(): Apiato
+ {
+ return $this->apiato;
+ }
+
+ private function withDefaults(string $basePath): void
+ {
+ $this->useSharedPath(
+ $this->joinPaths($basePath, 'app/Ship'),
+ )->withConfigs(
+ shared_path('Configs'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Configs')),
+ )->withEvents(
+ shared_path('Listeners'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Listeners')),
+ )->withCommands(
+ shared_path('Commands'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/CLI/Commands')),
+ )->withHelpers(
+ shared_path('Helpers'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Helpers')),
+ )->withMigrations(
+ shared_path('Migrations'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Data/Migrations')),
+ )->withProviders(function (Provider $provider) use ($basePath): void {
+ $provider->loadFrom(
+ shared_path('Providers'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Providers')),
+ );
+ })->withSeeders(function (Seeding $seeding) use ($basePath): void {
+ $seeding->loadFrom(
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Data/Seeders')),
+ );
+ })->withTranslations(function (Localization $localization) use ($basePath): void {
+ $localization->loadFrom(
+ shared_path('Languages'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Languages')),
+ );
+ })->withViews(function (View $view) use ($basePath): void {
+ $view->loadFrom(
+ shared_path('Views'),
+ shared_path('Mails/Templates'),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/WEB/Views')),
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/Mails/Templates')),
+ );
+ })->withRouting(function (Routing $routing) use ($basePath): void {
+ $routing->loadApiRoutesFrom(
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/API/Routes')),
+ )->loadWebRoutesFrom(
+ ...$this->getDirs($this->joinPaths($basePath, 'app/Containers/*/*/UI/WEB/Routes')),
+ );
+ })->withFactories()
+ ->withRepositories();
+ }
+
private function joinPaths(string $basePath, string $path = ''): string
{
return join_paths($basePath, $path);
@@ -175,14 +182,6 @@ private function joinPaths(string $basePath, string $path = ''): string
*/
private function getDirs(string $pattern): array
{
- /** @var string[] $dirs */
- $dirs = \Safe\glob($pattern, GLOB_ONLYDIR | GLOB_NOSORT);
-
- return $dirs;
- }
-
- public function create(): Apiato
- {
- return $this->apiato;
+ return glob($pattern, GLOB_ONLYDIR | GLOB_NOSORT);
}
}
diff --git a/src/Foundation/Configuration/Factory.php b/src/Foundation/Configuration/Factory.php
index 27752d867..60ec9312f 100644
--- a/src/Foundation/Configuration/Factory.php
+++ b/src/Foundation/Configuration/Factory.php
@@ -1,5 +1,7 @@
resolveFactoryNameUsing(
- static function (string $modelName): string|null {
+ static function (string $modelName): null|string {
$factoryName = Str::of($modelName)->beforeLast('Models\\')
->append('Data\\Factories\\' . class_basename($modelName) . 'Factory')
->value();
@@ -46,7 +48,7 @@ public function resolveFactoryNameUsing(\Closure $callback): self
*
* @return class-string|null
*/
- public function resolveFactoryName(string $modelName): string|null
+ public function resolveFactoryName(string $modelName): null|string
{
return app()->call(self::$nameResolver, ['modelName' => $modelName]);
}
diff --git a/src/Foundation/Configuration/Localization.php b/src/Foundation/Configuration/Localization.php
index 6fb69f153..894229c11 100644
--- a/src/Foundation/Configuration/Localization.php
+++ b/src/Foundation/Configuration/Localization.php
@@ -1,18 +1,21 @@
buildNamespaceUsing(function (string $path): string {
+ $this->buildNamespaceUsing(static function (string $path): string {
if (Str::contains($path, shared_path())) {
return Str::of(shared_path())
->afterLast(DIRECTORY_SEPARATOR)
diff --git a/src/Foundation/Configuration/Provider.php b/src/Foundation/Configuration/Provider.php
index 791c10d14..af5d24ada 100644
--- a/src/Foundation/Configuration/Provider.php
+++ b/src/Foundation/Configuration/Provider.php
@@ -1,5 +1,7 @@
[]|null $providers
*/
- public function __construct(array|null $providers = null)
+ public function __construct(null|array $providers = null)
{
parent::__construct($providers ?? DefaultProviders::providers());
}
@@ -30,12 +32,12 @@ public function toArray(): array
public function loadFrom(string ...$paths): self
{
- $classMapper = new ClassMapGenerator();
+ $classMapGenerator = new ClassMapGenerator();
foreach ($paths as $path) {
- $classMapper->scanPaths($path);
+ $classMapGenerator->scanPaths($path);
}
- $this->merge(array_keys($classMapper->getClassMap()->getMap()));
+ $this->merge(array_keys($classMapGenerator->getClassMap()->getMap()));
return $this;
}
diff --git a/src/Foundation/Configuration/Repository.php b/src/Foundation/Configuration/Repository.php
index 7682e8720..62817a957 100644
--- a/src/Foundation/Configuration/Repository.php
+++ b/src/Foundation/Configuration/Repository.php
@@ -1,5 +1,7 @@
append('Models\\')
->append(
Str::of(class_basename($repositoryName))
- ->beforeLast('Repository')
- ->value(),
+ ->beforeLast('Repository')
+ ->value(),
)->value();
if (class_exists($modelName)) {
return $modelName;
}
- throw new \RuntimeException("Model not found for repository: {$repositoryName}");
+ throw new \RuntimeException('Model not found for repository: ' . $repositoryName);
},
);
}
diff --git a/src/Foundation/Configuration/Routing.php b/src/Foundation/Configuration/Routing.php
index 8ab0de27e..e745af2fa 100644
--- a/src/Foundation/Configuration/Routing.php
+++ b/src/Foundation/Configuration/Routing.php
@@ -1,5 +1,7 @@
apiVersionAutoPrefix) {
- return $this->apiPrefix . $this->resolveApiVersionFor($file);
- }
-
- return $this->apiPrefix;
- }
-
- private function resolveApiVersionFor(string $file): string
- {
- return app()->call(self::$apiVersionResolver, ['file' => $file]);
- }
-
public function getApiPrefix(): string
{
return $this->apiPrefix;
@@ -119,4 +98,32 @@ public function webRoutes(): array
->flatMap(static fn (string $path): array => recursiveGlob($path . '/*.php'))
->toArray();
}
+
+ /**
+ * @return string[]
+ */
+ private function getApiMiddlewares(): array
+ {
+ $middlewares = ['api'];
+
+ if (config('apiato.api.rate-limiter.enabled')) {
+ $middlewares[] = 'throttle:' . config('apiato.api.rate-limiter.name');
+ }
+
+ return $middlewares;
+ }
+
+ private function buildApiPrefixFor(string $file): string
+ {
+ if ($this->apiVersionAutoPrefix) {
+ return $this->apiPrefix . $this->resolveApiVersionFor($file);
+ }
+
+ return $this->apiPrefix;
+ }
+
+ private function resolveApiVersionFor(string $file): string
+ {
+ return app()->call(self::$apiVersionResolver, ['file' => $file]);
+ }
}
diff --git a/src/Foundation/Configuration/Seeding.php b/src/Foundation/Configuration/Seeding.php
index 9e8c77624..b34e0325f 100644
--- a/src/Foundation/Configuration/Seeding.php
+++ b/src/Foundation/Configuration/Seeding.php
@@ -1,5 +1,7 @@
getSortedFiles($classMapGroupedByDirectory);
}
+ public function loadFrom(string ...$paths): self
+ {
+ $this->paths = $paths;
+
+ return $this;
+ }
+
/**
* @param array, non-empty-string>> $classMapGroupedByDirectory
*
@@ -66,11 +76,4 @@ private function getSortedFiles(array $classMapGroupedByDirectory): array
{
return app()->call(self::$seederSorter, ['classMapGroupedByDirectory' => $classMapGroupedByDirectory]);
}
-
- public function loadFrom(string ...$paths): self
- {
- $this->paths = $paths;
-
- return $this;
- }
}
diff --git a/src/Foundation/Configuration/View.php b/src/Foundation/Configuration/View.php
index ffa825dcd..856b9c664 100644
--- a/src/Foundation/Configuration/View.php
+++ b/src/Foundation/Configuration/View.php
@@ -1,18 +1,21 @@
buildNamespaceUsing(function (string $path): string {
+ $this->buildNamespaceUsing(static function (string $path): string {
if (Str::contains($path, shared_path())) {
return Str::of(shared_path())
->afterLast(DIRECTORY_SEPARATOR)
diff --git a/src/Foundation/Database/DatabaseSeeder.php b/src/Foundation/Database/DatabaseSeeder.php
index 3efc67162..8f47dbdfa 100644
--- a/src/Foundation/Database/DatabaseSeeder.php
+++ b/src/Foundation/Database/DatabaseSeeder.php
@@ -1,9 +1,12 @@
seeding()->seeders();
- collect($classes)->each(fn (string $class) => $this->call($class));
+ /**
+ * @var class-string $class
+ * @var Seeder $this
+ */
+ collect($classes)->each(fn (string $class) => $class::WITH_TRANSACTIONS
+ ? DB::transaction(fn (string $class) => $this->call($class))
+ : $this->call($class));
}
}
diff --git a/src/Foundation/Providers/ApiatoServiceProvider.php b/src/Foundation/Providers/ApiatoServiceProvider.php
index f29e8d2ce..75dba76c7 100644
--- a/src/Foundation/Providers/ApiatoServiceProvider.php
+++ b/src/Foundation/Providers/ApiatoServiceProvider.php
@@ -1,5 +1,7 @@
app->singletonIf(Apiato::class, static fn (): Apiato => Apiato::instance());
- $this->app->extend('hashids', static function (HashidsManager $manager) {
+ $this->app->extend('hashids', static function (HashidsManager $manager): HashidsManagerDecorator {
return new HashidsManagerDecorator($manager);
});
}
diff --git a/src/Foundation/Support/Providers/ConfigServiceProvider.php b/src/Foundation/Support/Providers/ConfigServiceProvider.php
index 71fab0da0..f71ad6e55 100644
--- a/src/Foundation/Support/Providers/ConfigServiceProvider.php
+++ b/src/Foundation/Support/Providers/ConfigServiceProvider.php
@@ -1,5 +1,7 @@
localization();
- foreach ($configuration->paths() as $path) {
- $this->loadTranslationsFrom($path, $configuration->buildNamespaceFor($path));
+ $localization = $apiato->localization();
+ foreach ($localization->paths() as $path) {
+ $this->loadTranslationsFrom($path, $localization->buildNamespaceFor($path));
$this->loadJsonTranslationsFrom($path);
}
}
diff --git a/src/Foundation/Support/Providers/MigrationServiceProvider.php b/src/Foundation/Support/Providers/MigrationServiceProvider.php
index 97a43a99b..abc705f40 100644
--- a/src/Foundation/Support/Providers/MigrationServiceProvider.php
+++ b/src/Foundation/Support/Providers/MigrationServiceProvider.php
@@ -1,5 +1,7 @@
view();
- foreach ($configuration->paths() as $path) {
- $this->loadViewsFrom($path, $configuration->buildNamespaceFor($path));
+ $view = $apiato->view();
+ foreach ($view->paths() as $path) {
+ $this->loadViewsFrom($path, $view->buildNamespaceFor($path));
}
}
}
diff --git a/src/Foundation/helpers.php b/src/Foundation/helpers.php
index 2d8832dd4..4149d0bcf 100644
--- a/src/Foundation/helpers.php
+++ b/src/Foundation/helpers.php
@@ -1,9 +1,13 @@
checkParameterOrAsk('model', 'Enter the name of the model this action is for.', $this->containerName);
$ui = Str::upper($this->checkParameterOrChoice('ui', 'Which UI is this Action for?', ['API', 'WEB'], 0));
@@ -68,18 +76,18 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- 'models' => $models,
- 'ui' => $ui,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ 'models' => $models,
+ 'ui' => $ui,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -90,6 +98,7 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultAction';
diff --git a/src/Generator/Commands/ConfigurationGenerator.php b/src/Generator/Commands/ConfigurationGenerator.php
index cd307b200..0bb6a4abd 100644
--- a/src/Generator/Commands/ConfigurationGenerator.php
+++ b/src/Generator/Commands/ConfigurationGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -66,6 +74,7 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return Str::camel($this->sectionName) . '-' . Str::camel($this->containerName);
diff --git a/src/Generator/Commands/ContainerApiGenerator.php b/src/Generator/Commands/ContainerApiGenerator.php
index 1575bddb8..7b13cf2a9 100644
--- a/src/Generator/Commands/ContainerApiGenerator.php
+++ b/src/Generator/Commands/ContainerApiGenerator.php
@@ -1,15 +1,20 @@
sectionName;
- $_sectionName = Str::lower($this->sectionName);
-
- $containerName = $this->containerName;
- $_containerName = Str::lower($this->containerName);
-
- $model = $this->containerName;
- $models = Pluralizer::plural($model);
-
- $this->printInfoMessage('Generating README File');
- $this->call('apiato:make:readme', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => 'README',
- ]);
-
- $this->printInfoMessage('Generating Configuration File');
- $this->call('apiato:make:configuration', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => Str::camel($this->sectionName) . '-' . Str::camel($this->containerName),
- ]);
-
- $this->printInfoMessage('Generating Model and Repository');
- $this->call('apiato:make:model', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => $model,
- '--repository' => true,
- ]);
-
- $this->printInfoMessage('Generating a basic Migration file');
- $this->call('apiato:make:migration', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => 'create_' . Str::snake($models) . '_table',
- '--tablename' => Str::snake($models),
- ]);
+ [
+ $sectionName,
+ $_sectionName,
+ $containerName,
+ $_containerName,
+ $model,
+ $models,
+ ] = $this->runCallParam();
$this->printInfoMessage('Generating Transformer for the Model');
$this->call('apiato:make:transformer', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $containerName . 'Transformer',
- '--model' => $model,
- '--full' => false,
+ '--file' => $containerName . 'Transformer',
+ '--model' => $model,
+ '--full' => false,
]);
$this->printInfoMessage('Generating Factory for the Model');
$this->call('apiato:make:factory', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $containerName . 'Factory',
- '--model' => $model,
+ '--file' => $containerName . 'Factory',
+ '--model' => $model,
]);
$this->printInfoMessage('Generating Default Routes');
- $version = $this->checkParameterOrAsk('docversion', 'Enter the version for all API endpoints (integer)', 1);
+ $version = $this->checkParameterOrAsk('docversion', 'Enter the version for all API endpoints (integer)', '1');
$doctype = $this->checkParameterOrChoice('doctype', 'Select the type for all API endpoints', ['private', 'public'], 0);
- // get the URI and remove the first trailing slash
+ // Get the URI and remove the first trailing slash
$url = Str::lower($this->checkParameterOrAsk('url', 'Enter the base URI for all API endpoints (foo/bar/{id})', Str::kebab($models)));
$url = ltrim($url, '/');
- $controllertype = Str::lower($this->checkParameterOrChoice('controllertype', 'Select the controller type (Single or Multi Action Controller)', ['SAC', 'MAC'], 0));
+ $controllerType = Str::lower($this->checkParameterOrChoice('controllertype', 'Select the controller type (Single or Multi Action Controller)', ['SAC', 'MAC'], 0));
$generateEvents = $this->checkParameterOrConfirm('events', 'Do you want to generate the corresponding CRUD Events for this Container?', false);
$generateListeners = false;
+
if ($generateEvents) {
$generateListeners = $this->checkParameterOrConfirm('listeners', 'Do you want to generate the corresponding Event Listeners for this Events?', false);
}
+
$generateTests = $this->checkParameterOrConfirm('tests', 'Do you want to generate the corresponding Tests for this Container?', true);
$generateEvents ?: $this->printInfoMessage('Generating CRUD Events');
$generateTests ?: $this->printInfoMessage('Generating Tests for Container');
+
$this->printInfoMessage('Generating Requests for Routes');
$this->printInfoMessage('Generating Default Actions');
$this->printInfoMessage('Generating Default Tasks');
@@ -140,236 +124,236 @@ public function getUserInputs(): array|null
$events = [];
$routes = [
[
- 'stub' => 'List',
- 'name' => 'List' . $models,
+ 'stub' => 'List',
+ 'name' => 'List' . $models,
'operation' => 'list',
- 'verb' => 'GET',
- 'url' => $url,
- 'action' => 'List' . $models . 'Action',
- 'request' => 'List' . $models . 'Request',
- 'task' => 'List' . $models . 'Task',
- 'unittest' => [
+ 'verb' => 'GET',
+ 'url' => $url,
+ 'action' => 'List' . $models . 'Action',
+ 'request' => 'List' . $models . 'Request',
+ 'task' => 'List' . $models . 'Task',
+ 'unittest' => [
'task' => [
'stubfoldername' => 'tasks',
- 'foldername' => 'Tasks',
- 'filename' => 'List' . $models . 'TaskTest',
+ 'foldername' => 'Tasks',
+ 'filename' => 'List' . $models . 'TaskTest',
],
],
'functionaltest' => 'List' . $models . 'Test',
- 'event' => $models . 'Listed',
- 'controller' => 'List' . $models . 'Controller',
+ 'event' => $models . 'Listed',
+ 'controller' => 'List' . $models . 'Controller',
],
[
- 'stub' => 'Find',
- 'name' => 'Find' . $model . 'ById',
+ 'stub' => 'Find',
+ 'name' => 'Find' . $model . 'ById',
'operation' => 'findById',
- 'verb' => 'GET',
- 'url' => $url . '/{id}',
- 'action' => 'Find' . $model . 'ByIdAction',
- 'request' => 'Find' . $model . 'ByIdRequest',
- 'task' => 'Find' . $model . 'ByIdTask',
- 'unittest' => [
+ 'verb' => 'GET',
+ 'url' => $url . '/{id}',
+ 'action' => 'Find' . $model . 'ByIdAction',
+ 'request' => 'Find' . $model . 'ByIdRequest',
+ 'task' => 'Find' . $model . 'ByIdTask',
+ 'unittest' => [
'task' => [
'stubfoldername' => 'tasks',
- 'foldername' => 'Tasks',
- 'filename' => 'Find' . $model . 'ByIdTaskTest',
+ 'foldername' => 'Tasks',
+ 'filename' => 'Find' . $model . 'ByIdTaskTest',
],
],
'functionaltest' => 'Find' . $model . 'ByIdTest',
- 'event' => $model . 'Requested',
- 'controller' => 'Find' . $model . 'ByIdController',
+ 'event' => $model . 'Requested',
+ 'controller' => 'Find' . $model . 'ByIdController',
],
[
- 'stub' => 'Create',
- 'name' => 'Create' . $model,
+ 'stub' => 'Create',
+ 'name' => 'Create' . $model,
'operation' => 'create',
- 'verb' => 'POST',
- 'url' => $url,
- 'action' => 'Create' . $model . 'Action',
- 'request' => 'Create' . $model . 'Request',
- 'task' => 'Create' . $model . 'Task',
- 'unittest' => [
+ 'verb' => 'POST',
+ 'url' => $url,
+ 'action' => 'Create' . $model . 'Action',
+ 'request' => 'Create' . $model . 'Request',
+ 'task' => 'Create' . $model . 'Task',
+ 'unittest' => [
'task' => [
'stubfoldername' => 'tasks',
- 'foldername' => 'Tasks',
- 'filename' => 'Create' . $model . 'TaskTest',
+ 'foldername' => 'Tasks',
+ 'filename' => 'Create' . $model . 'TaskTest',
],
],
'functionaltest' => 'Create' . $model . 'Test',
- 'event' => $model . 'Created',
- 'controller' => 'Create' . $model . 'Controller',
+ 'event' => $model . 'Created',
+ 'controller' => 'Create' . $model . 'Controller',
],
[
- 'stub' => 'Update',
- 'name' => 'Update' . $model,
+ 'stub' => 'Update',
+ 'name' => 'Update' . $model,
'operation' => 'update',
- 'verb' => 'PATCH',
- 'url' => $url . '/{id}',
- 'action' => 'Update' . $model . 'Action',
- 'request' => 'Update' . $model . 'Request',
- 'task' => 'Update' . $model . 'Task',
- 'unittest' => [
+ 'verb' => 'PATCH',
+ 'url' => $url . '/{id}',
+ 'action' => 'Update' . $model . 'Action',
+ 'request' => 'Update' . $model . 'Request',
+ 'task' => 'Update' . $model . 'Task',
+ 'unittest' => [
'task' => [
'stubfoldername' => 'tasks',
- 'foldername' => 'Tasks',
- 'filename' => 'Update' . $model . 'TaskTest',
+ 'foldername' => 'Tasks',
+ 'filename' => 'Update' . $model . 'TaskTest',
],
],
'functionaltest' => 'Update' . $model . 'Test',
- 'event' => $model . 'Updated',
- 'controller' => 'Update' . $model . 'Controller',
+ 'event' => $model . 'Updated',
+ 'controller' => 'Update' . $model . 'Controller',
],
[
- 'stub' => 'Delete',
- 'name' => 'Delete' . $model,
+ 'stub' => 'Delete',
+ 'name' => 'Delete' . $model,
'operation' => 'delete',
- 'verb' => 'DELETE',
- 'url' => $url . '/{id}',
- 'action' => 'Delete' . $model . 'Action',
- 'request' => 'Delete' . $model . 'Request',
- 'task' => 'Delete' . $model . 'Task',
- 'unittest' => [
+ 'verb' => 'DELETE',
+ 'url' => $url . '/{id}',
+ 'action' => 'Delete' . $model . 'Action',
+ 'request' => 'Delete' . $model . 'Request',
+ 'task' => 'Delete' . $model . 'Task',
+ 'unittest' => [
'task' => [
'stubfoldername' => 'tasks',
- 'foldername' => 'Tasks',
- 'filename' => 'Delete' . $model . 'TaskTest',
+ 'foldername' => 'Tasks',
+ 'filename' => 'Delete' . $model . 'TaskTest',
],
],
'functionaltest' => 'Delete' . $model . 'Test',
- 'event' => $model . 'Deleted',
- 'controller' => 'Delete' . $model . 'Controller',
+ 'event' => $model . 'Deleted',
+ 'controller' => 'Delete' . $model . 'Controller',
],
];
foreach ($routes as $route) {
$this->call('apiato:make:request', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['request'],
- '--ui' => $ui,
- '--stub' => $route['stub'],
+ '--file' => $route['request'],
+ '--ui' => $ui,
+ '--stub' => $route['stub'],
]);
$this->call('apiato:make:action', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['action'],
- '--ui' => $ui,
- '--model' => $model,
- '--stub' => $route['stub'],
+ '--file' => $route['action'],
+ '--ui' => $ui,
+ '--model' => $model,
+ '--stub' => $route['stub'],
]);
$this->call('apiato:make:task', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['task'],
- '--model' => $model,
- '--stub' => $route['stub'],
- '--event' => $generateEvents ? $route['event'] : false,
+ '--file' => $route['task'],
+ '--model' => $model,
+ '--stub' => $route['stub'],
+ '--event' => $generateEvents ? $route['event'] : false,
]);
if ($generateEvents) {
$this->call('apiato:make:event', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['event'],
- '--model' => $model,
- '--stub' => $route['stub'],
- '--listener' => false,
+ '--file' => $route['event'],
+ '--model' => $model,
+ '--stub' => $route['stub'],
+ '--listener' => false,
]);
$events[] = $route['event'];
}
if ($generateTests) {
$this->call('apiato:make:test:unit', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => $route['unittest']['task']['filename'],
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => $route['unittest']['task']['filename'],
'--stubfoldername' => $route['unittest']['task']['stubfoldername'],
- '--foldername' => $route['unittest']['task']['foldername'],
- '--model' => $model,
- '--stub' => $route['stub'],
- '--event' => $generateEvents ? $route['event'] : false,
+ '--foldername' => $route['unittest']['task']['foldername'],
+ '--model' => $model,
+ '--stub' => $route['stub'],
+ '--event' => $generateEvents ? $route['event'] : false,
]);
$this->call('apiato:make:test:unit', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => $model . 'FactoryTest',
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => $model . 'FactoryTest',
'--foldername' => 'Factories',
- '--model' => $model,
- '--stub' => 'factory',
- '--event' => false,
+ '--model' => $model,
+ '--stub' => 'factory',
+ '--event' => false,
]);
$this->call('apiato:make:test:unit', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => $models . 'MigrationTest',
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => $models . 'MigrationTest',
'--stubfoldername' => 'data',
- '--foldername' => 'Data/Migrations',
- '--model' => $model,
- '--stub' => 'migration',
- '--event' => false,
- '--tablename' => Str::snake(Pluralizer::plural($containerName)),
+ '--foldername' => 'Data/Migrations',
+ '--model' => $model,
+ '--stub' => 'migration',
+ '--event' => false,
+ '--tablename' => Str::snake(Pluralizer::plural($containerName)),
]);
$this->call('apiato:make:test:functional', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['functionaltest'],
- '--model' => $model,
- '--ui' => $ui,
- '--stub' => $route['stub'],
- '--url' => $route['url'],
+ '--file' => $route['functionaltest'],
+ '--model' => $model,
+ '--ui' => $ui,
+ '--stub' => $route['stub'],
+ '--url' => $route['url'],
]);
}
$routeArgs = [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => $route['name'],
- '--ui' => $ui,
- '--operation' => $route['operation'],
- '--doctype' => $doctype,
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => $route['name'],
+ '--ui' => $ui,
+ '--operation' => $route['operation'],
+ '--doctype' => $doctype,
'--docversion' => $version,
- '--url' => $route['url'],
- '--verb' => $route['verb'],
+ '--url' => $route['url'],
+ '--verb' => $route['verb'],
];
- if ('sac' === $controllertype) {
+ if ($controllerType === 'sac') {
$this->call('apiato:make:route', [
...$routeArgs,
'--controller' => $route['controller'],
- '--sac' => true,
+ '--sac' => true,
]);
$this->call('apiato:make:controller', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['controller'],
- '--model' => $model,
- '--ui' => $ui,
- '--stub' => $route['stub'],
+ '--file' => $route['controller'],
+ '--model' => $model,
+ '--ui' => $ui,
+ '--stub' => $route['stub'],
]);
} else {
$this->call('apiato:make:route', [
...$routeArgs,
'--controller' => 'Controller',
- '--sac' => false,
+ '--sac' => false,
]);
}
}
- if ('mac' === $controllertype) {
+ if ($controllerType === 'mac') {
$this->printInfoMessage('Generating Controller to wire everything together');
$this->call('apiato:make:controller', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--model' => $model,
- '--file' => 'Controller',
- '--ui' => $ui,
- '--stub' => 'crud',
+ '--model' => $model,
+ '--file' => 'Controller',
+ '--ui' => $ui,
+ '--stub' => 'crud',
]);
}
@@ -378,33 +362,33 @@ public function getUserInputs(): array|null
foreach ($events as $event) {
$listener = $event . 'Listener';
$this->call('apiato:make:listener', [
- '--section' => $this->sectionName,
+ '--section' => $this->sectionName,
'--container' => $this->containerName,
- '--file' => $listener,
- '--event' => $event,
+ '--file' => $listener,
+ '--event' => $event,
]);
}
}
$this->printInfoMessage('Generating ServiceProvider');
$this->call('apiato:make:provider', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => Str::title($this->containerName) . 'ServiceProvider',
- '--stub' => 'service-provider',
+ '--file' => Str::title($this->containerName) . 'ServiceProvider',
+ '--stub' => 'service-provider',
]);
$generateComposerFile = [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => $_sectionName,
- 'section-name' => $this->sectionName,
+ '_section-name' => $_sectionName,
+ 'section-name' => $this->sectionName,
'_container-name' => $_containerName,
- 'container-name' => $containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -417,14 +401,16 @@ public function getUserInputs(): array|null
return $generateComposerFile;
}
- return null;
+ return [];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'composer';
}
+ #[\Override]
public function getDefaultFileExtension(): string
{
return 'json';
diff --git a/src/Generator/Commands/ContainerGenerator.php b/src/Generator/Commands/ContainerGenerator.php
index 046ce6fda..50e8f7c99 100644
--- a/src/Generator/Commands/ContainerGenerator.php
+++ b/src/Generator/Commands/ContainerGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrChoice('ui', 'Select the UI for this container', ['API', 'WEB', 'BOTH'], 0));
$generateEvents = $this->checkParameterOrConfirm('events', 'Do you want to generate the corresponding CRUD Events for this Container?', false);
$generateListeners = false;
+
if ($generateEvents) {
$generateListeners = $this->checkParameterOrConfirm('listeners', 'Do you want to generate the corresponding Event Listeners for this Events?', false);
}
+
$generateTests = $this->checkParameterOrConfirm('tests', 'Do you want to generate the corresponding Tests for this Container?', true);
+
if ($generateTests) {
$this->call('apiato:make:test:testcase', [
- '--section' => $this->sectionName,
+ '--section' => $this->sectionName,
'--container' => $this->containerName,
- '--file' => 'TestCase',
- '--type' => 'container',
+ '--file' => 'TestCase',
+ '--type' => 'container',
]);
$this->call('apiato:make:test:testcase', [
- '--section' => $this->sectionName,
+ '--section' => $this->sectionName,
'--container' => $this->containerName,
- '--file' => 'TestCase',
- '--type' => 'unit',
+ '--file' => 'TestCase',
+ '--type' => 'unit',
]);
$this->call('apiato:make:test:testcase', [
- '--section' => $this->sectionName,
+ '--section' => $this->sectionName,
'--container' => $this->containerName,
- '--file' => 'TestCase',
- '--type' => 'functional',
+ '--file' => 'TestCase',
+ '--type' => 'functional',
]);
// $this->call('apiato:make:test:testcase', [
// '--section' => $this->sectionName,
@@ -83,10 +94,10 @@ public function getUserInputs(): array|null
// '--type' => 'e2e',
// ]);
$this->call('apiato:make:test:testcase', [
- '--section' => $this->sectionName,
+ '--section' => $this->sectionName,
'--container' => $this->containerName,
- '--file' => 'TestCase',
- '--type' => 'api',
+ '--file' => 'TestCase',
+ '--type' => 'api',
]);
// $this->call('apiato:make:test:testcase', [
// '--section' => $this->sectionName,
@@ -107,23 +118,23 @@ public function getUserInputs(): array|null
$sectionName = $this->sectionName;
$_sectionName = Str::lower($this->sectionName);
- if ('api' === $ui || 'both' === $ui) {
+ if ($ui === 'api' || $ui === 'both') {
$this->call('apiato:make:container:api', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => 'composer',
- '--events' => $generateEvents,
- '--listeners' => $generateListeners,
- '--tests' => $generateTests,
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => 'composer',
+ '--events' => $generateEvents,
+ '--listeners' => $generateListeners,
+ '--tests' => $generateTests,
'--maincalled' => true,
]);
}
- if ('web' === $ui || 'both' === $ui) {
+ if ($ui === 'web' || $ui === 'both') {
$this->call('apiato:make:container:web', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => 'composer',
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => 'composer',
'--maincalled' => true,
]);
}
@@ -132,15 +143,15 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => $_sectionName,
- 'section-name' => $this->sectionName,
+ '_section-name' => $_sectionName,
+ 'section-name' => $this->sectionName,
'_container-name' => $_containerName,
- 'container-name' => $containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -151,11 +162,13 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return 'composer';
}
+ #[\Override]
public function getDefaultFileExtension(): string
{
return 'json';
diff --git a/src/Generator/Commands/ContainerWebGenerator.php b/src/Generator/Commands/ContainerWebGenerator.php
index 4763d8ac2..571a196cb 100644
--- a/src/Generator/Commands/ContainerWebGenerator.php
+++ b/src/Generator/Commands/ContainerWebGenerator.php
@@ -1,15 +1,19 @@
sectionName;
- $_sectionName = Str::lower($this->sectionName);
-
- $containerName = $this->containerName;
- $_containerName = Str::lower($this->containerName);
-
- $model = $this->containerName;
- $models = Pluralizer::plural($model);
-
- $this->printInfoMessage('Generating README File');
- $this->call('apiato:make:readme', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => 'README',
- ]);
-
- $this->printInfoMessage('Generating Configuration File');
- $this->call('apiato:make:configuration', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => Str::camel($this->sectionName) . '-' . Str::camel($this->containerName),
- ]);
+ [
+ $sectionName,
+ $_sectionName,
+ $containerName,
+ $_containerName,
+ $model,
+ $models,
+ ] = $this->runCallParam();
$this->printInfoMessage('Generating ServiceProvider');
$this->call('apiato:make:provider', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => Str::title($this->containerName) . 'ServiceProvider',
- '--stub' => 'service-provider',
- ]);
-
- $this->printInfoMessage('Generating Model and Repository');
- $this->call('apiato:make:model', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => $model,
- '--repository' => true,
- ]);
-
- $this->printInfoMessage('Generating a basic Migration file');
- $this->call('apiato:make:migration', [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => 'create_' . Str::snake($models) . '_table',
- '--tablename' => Str::snake($models),
+ '--file' => Str::title($this->containerName) . 'ServiceProvider',
+ '--stub' => 'service-provider',
]);
$this->printInfoMessage('Generating Default Routes');
@@ -115,173 +95,173 @@ public function getUserInputs(): array|null
$routes = [
[
- 'stub' => 'List',
- 'name' => 'List' . $models,
- 'operation' => 'index',
- 'verb' => 'GET',
- 'url' => $url,
- 'action' => 'List' . $models . 'Action',
- 'request' => 'List' . $models . 'Request',
- 'task' => 'List' . $models . 'Task',
+ 'stub' => 'List',
+ 'name' => 'List' . $models,
+ 'operation' => 'index',
+ 'verb' => 'GET',
+ 'url' => $url,
+ 'action' => 'List' . $models . 'Action',
+ 'request' => 'List' . $models . 'Request',
+ 'task' => 'List' . $models . 'Task',
'controller' => 'List' . $models . 'Controller',
],
[
- 'stub' => 'Find',
- 'name' => 'Find' . $model . 'ById',
- 'operation' => 'show',
- 'verb' => 'GET',
- 'url' => $url . '/{id}',
- 'action' => 'Find' . $model . 'ByIdAction',
- 'request' => 'Find' . $model . 'ByIdRequest',
- 'task' => 'Find' . $model . 'ByIdTask',
+ 'stub' => 'Find',
+ 'name' => 'Find' . $model . 'ById',
+ 'operation' => 'show',
+ 'verb' => 'GET',
+ 'url' => $url . '/{id}',
+ 'action' => 'Find' . $model . 'ByIdAction',
+ 'request' => 'Find' . $model . 'ByIdRequest',
+ 'task' => 'Find' . $model . 'ByIdTask',
'controller' => 'Find' . $model . 'ByIdController',
],
[
- 'stub' => 'Store',
- 'name' => 'Store' . $model,
- 'operation' => 'store',
- 'verb' => 'POST',
- 'url' => $url . '/store',
- 'action' => 'Create' . $model . 'Action',
- 'request' => 'Store' . $model . 'Request',
- 'task' => 'Create' . $model . 'Task',
+ 'stub' => 'Store',
+ 'name' => 'Store' . $model,
+ 'operation' => 'store',
+ 'verb' => 'POST',
+ 'url' => $url . '/store',
+ 'action' => 'Create' . $model . 'Action',
+ 'request' => 'Store' . $model . 'Request',
+ 'task' => 'Create' . $model . 'Task',
'controller' => 'Store' . $model . 'Controller',
],
[
- 'stub' => 'Create',
- 'name' => 'Create' . $model,
- 'operation' => 'create',
- 'verb' => 'GET',
- 'url' => $url . '/create',
- 'action' => null,
- 'request' => 'Create' . $model . 'Request',
- 'task' => null,
+ 'stub' => 'Create',
+ 'name' => 'Create' . $model,
+ 'operation' => 'create',
+ 'verb' => 'GET',
+ 'url' => $url . '/create',
+ 'action' => null,
+ 'request' => 'Create' . $model . 'Request',
+ 'task' => null,
'controller' => 'Create' . $model . 'Controller',
],
[
- 'stub' => 'Update',
- 'name' => 'Update' . $model,
- 'operation' => 'update',
- 'verb' => 'PATCH',
- 'url' => $url . '/{id}',
- 'action' => 'Update' . $model . 'Action',
- 'request' => 'Update' . $model . 'Request',
- 'task' => 'Update' . $model . 'Task',
+ 'stub' => 'Update',
+ 'name' => 'Update' . $model,
+ 'operation' => 'update',
+ 'verb' => 'PATCH',
+ 'url' => $url . '/{id}',
+ 'action' => 'Update' . $model . 'Action',
+ 'request' => 'Update' . $model . 'Request',
+ 'task' => 'Update' . $model . 'Task',
'controller' => 'Update' . $model . 'Controller',
],
[
- 'stub' => 'Edit',
- 'name' => 'Edit' . $model,
- 'operation' => 'edit',
- 'verb' => 'GET',
- 'url' => $url . '/{id}/edit',
- 'action' => null,
- 'request' => 'Edit' . $model . 'Request',
- 'task' => null,
+ 'stub' => 'Edit',
+ 'name' => 'Edit' . $model,
+ 'operation' => 'edit',
+ 'verb' => 'GET',
+ 'url' => $url . '/{id}/edit',
+ 'action' => null,
+ 'request' => 'Edit' . $model . 'Request',
+ 'task' => null,
'controller' => 'Edit' . $model . 'Controller',
],
[
- 'stub' => 'Delete',
- 'name' => 'Delete' . $model,
- 'operation' => 'destroy',
- 'verb' => 'DELETE',
- 'url' => $url . '/{id}',
- 'action' => 'Delete' . $model . 'Action',
- 'request' => 'Delete' . $model . 'Request',
- 'task' => 'Delete' . $model . 'Task',
+ 'stub' => 'Delete',
+ 'name' => 'Delete' . $model,
+ 'operation' => 'destroy',
+ 'verb' => 'DELETE',
+ 'url' => $url . '/{id}',
+ 'action' => 'Delete' . $model . 'Action',
+ 'request' => 'Delete' . $model . 'Request',
+ 'task' => 'Delete' . $model . 'Task',
'controller' => 'Delete' . $model . 'Controller',
],
];
foreach ($routes as $route) {
$this->call('apiato:make:request', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['request'],
- '--ui' => $ui,
- '--stub' => $route['stub'],
+ '--file' => $route['request'],
+ '--ui' => $ui,
+ '--stub' => $route['stub'],
]);
- if (null !== $route['action']) {
+ if ($route['action'] !== null) {
$this->call('apiato:make:action', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['action'],
- '--ui' => $ui,
- '--model' => $model,
- '--stub' => $route['stub'],
+ '--file' => $route['action'],
+ '--ui' => $ui,
+ '--model' => $model,
+ '--stub' => $route['stub'],
]);
}
- if (null !== $route['task']) {
+ if ($route['task'] !== null) {
$this->call('apiato:make:task', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['task'],
- '--model' => $model,
- '--stub' => $route['stub'],
+ '--file' => $route['task'],
+ '--model' => $model,
+ '--stub' => $route['stub'],
]);
}
$routeArgs = [
- '--section' => $sectionName,
- '--container' => $containerName,
- '--file' => $route['name'],
- '--ui' => $ui,
- '--operation' => $route['operation'],
- '--doctype' => $doctype,
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => $route['name'],
+ '--ui' => $ui,
+ '--operation' => $route['operation'],
+ '--doctype' => $doctype,
'--docversion' => $version,
- '--url' => $route['url'],
- '--verb' => $route['verb'],
+ '--url' => $route['url'],
+ '--verb' => $route['verb'],
];
- if ('sac' === $controllertype) {
+ if ($controllertype === 'sac') {
$this->call('apiato:make:route', [
...$routeArgs,
'--controller' => $route['controller'],
- '--sac' => true,
+ '--sac' => true,
]);
$this->call('apiato:make:controller', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => $route['controller'],
- '--model' => $model,
- '--ui' => $ui,
- '--stub' => $route['stub'],
+ '--file' => $route['controller'],
+ '--model' => $model,
+ '--ui' => $ui,
+ '--stub' => $route['stub'],
]);
} else {
$this->call('apiato:make:route', [
...$routeArgs,
'--controller' => 'Controller',
- '--sac' => false,
+ '--sac' => false,
]);
}
}
- if ('mac' === $controllertype) {
+ if ($controllertype === 'mac') {
$this->printInfoMessage('Generating Controller to wire everything together');
$this->call('apiato:make:controller', [
- '--section' => $sectionName,
+ '--section' => $sectionName,
'--container' => $containerName,
- '--file' => 'Controller',
- '--model' => $model,
- '--ui' => $ui,
- '--stub' => 'crud',
+ '--file' => 'Controller',
+ '--model' => $model,
+ '--ui' => $ui,
+ '--stub' => 'crud',
]);
}
$generateComposerFile = [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => $_sectionName,
- 'section-name' => $this->sectionName,
+ '_section-name' => $_sectionName,
+ 'section-name' => $this->sectionName,
'_container-name' => $_containerName,
- 'container-name' => $containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -294,14 +274,16 @@ public function getUserInputs(): array|null
return $generateComposerFile;
}
- return null;
+ return [];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'composer';
}
+ #[\Override]
public function getDefaultFileExtension(): string
{
return 'json';
diff --git a/src/Generator/Commands/ControllerGenerator.php b/src/Generator/Commands/ControllerGenerator.php
index 1e46b16f7..60bf35190 100644
--- a/src/Generator/Commands/ControllerGenerator.php
+++ b/src/Generator/Commands/ControllerGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('model', 'Enter the name of the Model that this controller uses', $this->containerName);
$models = Pluralizer::plural($model);
@@ -75,22 +83,22 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
'user-interface' => Str::upper($ui),
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'user-interface' => Str::upper($ui),
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'user-interface' => Str::upper($ui),
'base-controller' => $basecontroller,
- 'model' => $model,
- 'models' => $models,
- 'entity' => $entity,
+ 'model' => $model,
+ 'models' => $models,
+ 'entity' => $entity,
'entities' => $entities,
],
'file-parameters' => [
@@ -99,6 +107,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'Controller';
diff --git a/src/Generator/Commands/EventGenerator.php b/src/Generator/Commands/EventGenerator.php
index 6deff42d6..6a21791da 100644
--- a/src/Generator/Commands/EventGenerator.php
+++ b/src/Generator/Commands/EventGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('model', 'Enter the name of the Model to generate this Event for', Str::ucfirst($this->containerName));
$listener = $this->option('listener');
- if (is_null($listener)) {
+
+ if (\is_null($listener)) {
$listener = $this->checkParameterOrConfirm('listener', 'Do you want to generate a Listener for this Event?', false);
+
if ($listener) {
$this->call('apiato:make:listener', [
- '--section' => $this->sectionName,
+ '--section' => $this->sectionName,
'--container' => $this->containerName,
- '--file' => $this->fileName . 'Listener',
- '--event' => $this->fileName,
+ '--file' => $this->fileName . 'Listener',
+ '--event' => $this->fileName,
]);
}
}
@@ -69,17 +79,17 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- '_model' => Str::lower($model),
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ '_model' => Str::lower($model),
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/EventListenerGenerator.php b/src/Generator/Commands/EventListenerGenerator.php
index 5c5b426bc..632214fbb 100644
--- a/src/Generator/Commands/EventListenerGenerator.php
+++ b/src/Generator/Commands/EventListenerGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('event', 'Enter the name of the Event to generate this Listener for');
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $event,
+ 'class-name' => $this->fileName,
+ 'model' => $event,
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/ExceptionGenerator.php b/src/Generator/Commands/ExceptionGenerator.php
index 4d43d61e4..579d60e3b 100644
--- a/src/Generator/Commands/ExceptionGenerator.php
+++ b/src/Generator/Commands/ExceptionGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/FunctionalTestGenerator.php b/src/Generator/Commands/FunctionalTestGenerator.php
index a725c7df6..4dd650df8 100644
--- a/src/Generator/Commands/FunctionalTestGenerator.php
+++ b/src/Generator/Commands/FunctionalTestGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrChoice('ui', 'Select the UI for the Test', ['API', 'CLI'], 0));
@@ -56,10 +64,11 @@ public function getUserInputs(): array|null
$stub = $this->option('stub');
$url = $this->option('url');
- if ('api' === $ui) {
+ if ($ui === 'api') {
$this->pathStructure = '{section-name}/{container-name}/Tests/Functional/API/*';
}
- if ('cli' === $ui) {
+
+ if ($ui === 'cli') {
$this->pathStructure = '{section-name}/{container-name}/Tests/Functional/CLI/*';
}
@@ -70,21 +79,21 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
'user-interface' => Str::upper($ui),
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- '_model' => Str::camel($model),
- 'models' => $models,
- '_models' => Str::lower($models),
- 'url' => $url,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ '_model' => Str::camel($model),
+ 'models' => $models,
+ '_models' => Str::lower($models),
+ 'url' => $url,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -92,6 +101,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultFunctionalTest';
diff --git a/src/Generator/Commands/JobGenerator.php b/src/Generator/Commands/JobGenerator.php
index c1df45bcf..5bdb21706 100644
--- a/src/Generator/Commands/JobGenerator.php
+++ b/src/Generator/Commands/JobGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -66,6 +74,7 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultJob';
diff --git a/src/Generator/Commands/MailGenerator.php b/src/Generator/Commands/MailGenerator.php
index 34b79e54f..22090fcf8 100644
--- a/src/Generator/Commands/MailGenerator.php
+++ b/src/Generator/Commands/MailGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('view', 'Enter the name of the view to be loaded when sending this Mail', '');
$subject = $this->checkParameterOrAsk('subject', "What's the the subject this Mail?", '');
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
- 'sectionName' => Str::camel($this->sectionName),
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
+ 'sectionName' => Str::camel($this->sectionName),
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'containerName' => Str::camel($this->containerName),
- 'class-name' => $this->fileName,
- 'view' => $view,
- 'subject' => $subject,
+ 'container-name' => $this->containerName,
+ 'containerName' => Str::camel($this->containerName),
+ 'class-name' => $this->fileName,
+ 'view' => $view,
+ 'subject' => $subject,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -73,6 +81,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultMail';
diff --git a/src/Generator/Commands/MiddlewareGenerator.php b/src/Generator/Commands/MiddlewareGenerator.php
index 6c640febb..db147e3fe 100644
--- a/src/Generator/Commands/MiddlewareGenerator.php
+++ b/src/Generator/Commands/MiddlewareGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -63,6 +71,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultMiddleware';
diff --git a/src/Generator/Commands/MigrationGenerator.php b/src/Generator/Commands/MigrationGenerator.php
index 0a5c07daf..cacf9f4ca 100644
--- a/src/Generator/Commands/MigrationGenerator.php
+++ b/src/Generator/Commands/MigrationGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('tablename', 'Enter the name of the database table', Str::snake(Pluralizer::plural($this->containerName))));
@@ -57,7 +70,7 @@ public function getUserInputs(): array|null
$exists = false;
$folder = $this->parsePathStructure($this->pathStructure, [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
]);
$folder = $this->getFilePath($folder);
@@ -80,19 +93,19 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => Str::studly($this->fileName),
- 'table-name' => $tableName,
+ 'container-name' => $this->containerName,
+ 'class-name' => Str::studly($this->fileName),
+ 'table-name' => $tableName,
],
'file-parameters' => [
- 'date' => Carbon::now()->format('Y_m_d_His'),
+ 'date' => Carbon::now()->format(self::FORMAT_TIME),
'file-name' => $this->fileName,
],
];
@@ -101,6 +114,7 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return 'create_' . Str::snake(Pluralizer::plural($this->containerName)) . '_table';
@@ -109,6 +123,7 @@ public function getDefaultFileName(): string
/**
* Removes "special characters" from a string.
*/
+ #[\Override]
protected function removeSpecialChars(string $str): string
{
return $str;
diff --git a/src/Generator/Commands/ModelFactoryGenerator.php b/src/Generator/Commands/ModelFactoryGenerator.php
index 9facd6502..098f8cc06 100644
--- a/src/Generator/Commands/ModelFactoryGenerator.php
+++ b/src/Generator/Commands/ModelFactoryGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('model', 'Enter the name of the Model to generate this Factory for');
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- '_model' => Str::lower($model),
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ '_model' => Str::lower($model),
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/ModelGenerator.php b/src/Generator/Commands/ModelGenerator.php
index 0cc1930f6..0e0453beb 100644
--- a/src/Generator/Commands/ModelGenerator.php
+++ b/src/Generator/Commands/ModelGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrConfirm('repository', 'Do you want to generate the corresponding Repository for this Model?', true);
+
if ($repository) {
// We need to generate a corresponding repository
// so call the other command
$status = $this->call('apiato:make:repository', [
- '--section' => $this->sectionName,
+ '--section' => $this->sectionName,
'--container' => $this->containerName,
- '--file' => $this->fileName . 'Repository',
- '--model' => $this->fileName,
+ '--file' => $this->fileName . 'Repository',
+ '--model' => $this->fileName,
]);
- if (0 !== $status) {
+ if ($status !== 0) {
$this->printErrorMessage('Could not generate the corresponding Repository!');
}
}
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'resource-key' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'resource-key' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/NotificationGenerator.php b/src/Generator/Commands/NotificationGenerator.php
index 0f573cc9a..b14e7fd62 100644
--- a/src/Generator/Commands/NotificationGenerator.php
+++ b/src/Generator/Commands/NotificationGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/PolicyGenerator.php b/src/Generator/Commands/PolicyGenerator.php
index 29c53478e..c96ec3453 100644
--- a/src/Generator/Commands/PolicyGenerator.php
+++ b/src/Generator/Commands/PolicyGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -63,6 +71,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return $this->containerName . 'Policy';
diff --git a/src/Generator/Commands/ReadmeGenerator.php b/src/Generator/Commands/ReadmeGenerator.php
index bace26370..37dc9c73e 100644
--- a/src/Generator/Commands/ReadmeGenerator.php
+++ b/src/Generator/Commands/ReadmeGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -66,11 +74,13 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return 'README';
}
+ #[\Override]
public function getDefaultFileExtension(): string
{
return 'md';
diff --git a/src/Generator/Commands/RepositoryGenerator.php b/src/Generator/Commands/RepositoryGenerator.php
index 7a0d8e518..aa064bfcf 100644
--- a/src/Generator/Commands/RepositoryGenerator.php
+++ b/src/Generator/Commands/RepositoryGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('model', 'Enter the name of the Model to generate this Repository for');
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- '_model' => Str::lower($model),
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ '_model' => Str::lower($model),
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/RequestGenerator.php b/src/Generator/Commands/RequestGenerator.php
index 9f3d7b880..71acdf34c 100644
--- a/src/Generator/Commands/RequestGenerator.php
+++ b/src/Generator/Commands/RequestGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrChoice('ui', 'Select the UI for the controller', ['API', 'WEB'], 0));
$stub = $this->option('stub');
@@ -62,17 +64,17 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
'user-interface' => Str::upper($ui),
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'user-interface' => Str::upper($ui),
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'user-interface' => Str::upper($ui),
],
'file-parameters' => [
'file-name' => $this->fileName,
diff --git a/src/Generator/Commands/RouteGenerator.php b/src/Generator/Commands/RouteGenerator.php
index d69272744..c30c3178f 100644
--- a/src/Generator/Commands/RouteGenerator.php
+++ b/src/Generator/Commands/RouteGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrChoice('ui', 'Select the UI for the controller', ['API', 'WEB'], 0));
- $version = $this->checkParameterOrAsk('docversion', 'Enter the endpoint version (integer)', 1);
+ $version = $this->checkParameterOrAsk('docversion', 'Enter the endpoint version (integer)', '1');
$doctype = $this->checkParameterOrChoice('doctype', 'Select the type for this endpoint', ['private', 'public'], 0);
$verb = Str::upper($this->checkParameterOrChoice('verb', 'Enter the HTTP verb of this endpoint (GET, POST,...)', ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], 0));
// Get the URI and remove the first trailing slash
@@ -66,46 +76,54 @@ public function getUserInputs(): array|null
$operation = '__invoke';
$sac = $this->checkParameterOrConfirm('sac', 'Is this a Single Action Controller route?', true);
- if (!$sac) {
+
+ if ($sac === false || $sac === null) {
$operation = $this->checkParameterOrAsk('operation', 'Enter the name of the controller action', '__invoke');
}
- $docUrl = \Safe\preg_replace('~{(.+?)}~', ':$1', $url);
+ $routeName = $operation;
+
+ if ($operation === '__invoke') {
+ $routeName = $this->fileName;
+ }
+
+ $docUrl = preg_replace('~{(.+?)}~', ':$1', $url);
- $routeName = Str::lower($ui . '_' . $this->containerName . '_' . Str::snake($operation));
+ $routeName = Str::lower($ui . '_' . $this->containerName . '_' . Str::snake($routeName));
$this->stubName = 'routes/' . $ui . '.mac.stub';
+
if ($sac) {
$this->stubName = 'routes/' . $ui . '.sac.stub';
}
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
'user-interface' => Str::upper($ui),
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
- '_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'operation' => $operation,
- 'doc-api-name' => Str::studly($this->option('operation')),
- 'user-interface' => Str::upper($ui),
- 'endpoint-url' => $url,
- 'endpoint-title' => Str::headline($operation),
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
+ '_container-name' => Str::lower($this->containerName),
+ 'container-name' => $this->containerName,
+ 'operation' => $operation,
+ 'doc-api-name' => Str::studly($this->option('operation')),
+ 'user-interface' => Str::upper($ui),
+ 'endpoint-url' => $url,
+ 'endpoint-title' => Str::headline($operation),
'doc-endpoint-url' => '/v' . $version . '/' . $docUrl,
'endpoint-version' => $version,
- 'http-verb' => Str::lower($verb),
- 'doc-http-verb' => Str::upper($verb),
- 'route-name' => $routeName,
- 'auth-middleware' => Str::lower($ui),
- 'controller-name' => $controllerName,
+ 'http-verb' => Str::lower($verb),
+ 'doc-http-verb' => Str::upper($verb),
+ 'route-name' => $routeName,
+ 'auth-middleware' => Str::lower($ui),
+ 'controller-name' => $controllerName,
],
'file-parameters' => [
- 'endpoint-name' => $this->fileName,
- 'endpoint-version' => 'v' . $version,
+ 'endpoint-name' => $this->fileName,
+ 'endpoint-version' => 'v' . $version,
'documentation-type' => $doctype,
],
];
diff --git a/src/Generator/Commands/SeederGenerator.php b/src/Generator/Commands/SeederGenerator.php
index df97e2705..ab5445865 100644
--- a/src/Generator/Commands/SeederGenerator.php
+++ b/src/Generator/Commands/SeederGenerator.php
@@ -1,61 +1,77 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -66,8 +82,18 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
- return $this->containerName . 'Seeder';
+ return \sprintf('Order_%s_%sSeeder', $this->getDate(), $this->containerName);
+ }
+
+ private function getDate(): string
+ {
+ if ($this->fileParametersDate === null) {
+ $this->fileParametersDate = Carbon::now()->format(self::FORMAT_TIME);
+ }
+
+ return $this->fileParametersDate;
}
}
diff --git a/src/Generator/Commands/ServiceProviderGenerator.php b/src/Generator/Commands/ServiceProviderGenerator.php
index e580eb6b6..fb44f853d 100644
--- a/src/Generator/Commands/ServiceProviderGenerator.php
+++ b/src/Generator/Commands/ServiceProviderGenerator.php
@@ -1,5 +1,7 @@
option('stub');
+
if (!$stub) {
$stub = $this->checkParameterOrChoice(
'stub',
@@ -58,22 +67,23 @@ public function getUserInputs(): array|null
$stub = match ($stub) {
'EventServiceProvider' => 'event-service-provider',
- default => 'service-provider',
+ default => 'service-provider',
};
}
- $this->stubName = "providers/$stub.stub";
+
+ $this->stubName = \sprintf('providers/%s.stub', $stub);
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -84,6 +94,7 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return 'ServiceProvider';
diff --git a/src/Generator/Commands/SubActionGenerator.php b/src/Generator/Commands/SubActionGenerator.php
index 05811f717..6fbd254a4 100644
--- a/src/Generator/Commands/SubActionGenerator.php
+++ b/src/Generator/Commands/SubActionGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -66,8 +74,9 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
- return 'DefaultAction';
+ return 'DefaultSubAction';
}
}
diff --git a/src/Generator/Commands/TaskGenerator.php b/src/Generator/Commands/TaskGenerator.php
index def90dac7..2353191ff 100644
--- a/src/Generator/Commands/TaskGenerator.php
+++ b/src/Generator/Commands/TaskGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('model', 'Enter the name of the model this task is for.', $this->containerName);
$stub = Str::lower(
@@ -68,20 +76,20 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- 'models' => $models,
- '_model' => Str::lower($model),
- 'model_' => Str::camel($model),
- 'event' => $event,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ 'models' => $models,
+ '_model' => Str::lower($model),
+ 'model_' => Str::camel($model),
+ 'event' => $event,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -92,6 +100,7 @@ public function getUserInputs(): array|null
/**
* Get the default file name for this component to be generated.
*/
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultTask';
diff --git a/src/Generator/Commands/TestCaseGenerator.php b/src/Generator/Commands/TestCaseGenerator.php
index 54727b563..8a55d456b 100644
--- a/src/Generator/Commands/TestCaseGenerator.php
+++ b/src/Generator/Commands/TestCaseGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrChoice('type', 'Select the TestCase type', ['Container', 'Unit', 'Functional', 'E2E', 'API', 'CLI', 'WEB'], 0));
$this->stubName = 'tests/testcase/' . $type . '.stub';
- if ('e2e' === $type) {
+
+ if ($type === 'e2e') {
$this->fileName = Str::upper($type) . $this->fileName;
} else {
$this->fileName = Str::ucfirst($type) . $this->fileName;
}
- if ('api' === $type || 'cli' === $type) {
+
+ if ($type === 'api' || $type === 'cli') {
$this->pathStructure = '{section-name}/{container-name}/Tests/Functional/*';
}
- if ('web' === $type) {
+
+ if ($type === 'web') {
$this->pathStructure = '{section-name}/{container-name}/Tests/E2E/*';
}
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -80,6 +91,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'TestCase';
diff --git a/src/Generator/Commands/TransformerGenerator.php b/src/Generator/Commands/TransformerGenerator.php
index 36b55d3ae..c3d84206c 100644
--- a/src/Generator/Commands/TransformerGenerator.php
+++ b/src/Generator/Commands/TransformerGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('model', 'Enter the name of the Model to generate this Transformer for');
- $full = $this->checkParameterOrConfirm('full', 'Generate a Transformer with all fields', false);
+ $full = (bool)$this->checkParameterOrConfirm('full', 'Generate a Transformer with all fields', false);
$attributes = $this->getListOfAllAttributes($full, $model);
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- '_model' => Str::lower($model),
- 'attributes' => $attributes,
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ '_model' => Str::lower($model),
+ 'attributes' => $attributes,
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -75,7 +83,7 @@ public function getUserInputs(): array|null
];
}
- private function getListOfAllAttributes(string|bool|array|null $full, string $model): string
+ private function getListOfAllAttributes(bool $full, string $model): string
{
$indent = str_repeat(' ', 12);
$_model = Str::lower($model);
@@ -89,7 +97,7 @@ private function getListOfAllAttributes(string|bool|array|null $full, string $mo
$columns = Schema::getColumnListing($obj->getTable());
foreach ($columns as $column) {
- if (in_array($column, $obj->getHidden(), false)) {
+ if (\in_array($column, $obj->getHidden(), false)) {
// Skip all hidden fields of respective model
continue;
}
@@ -102,9 +110,12 @@ private function getListOfAllAttributes(string|bool|array|null $full, string $mo
'id' => '$' . $_model . '->getHashedKey()',
]);
+ $lengths = array_map(Str::length(...), array_keys($fields));
+ $maxLength = max($lengths);
$attributes = '';
foreach ($fields as $key => $value) {
- $attributes .= $indent . "'$key' => $value," . $this->getEndOfLine($key, $fields);
+ $tab = str_repeat(' ', $maxLength - Str::length($key));
+ $attributes .= $indent . \sprintf("'%s'%s => %s,", $key, $tab, $value) . $this->getEndOfLine($key, $fields);
}
return $attributes;
@@ -115,6 +126,6 @@ private function getEndOfLine(string $currentKey, array $fields): string
$keys = array_keys($fields);
$lastKey = end($keys);
- return $currentKey === $lastKey ? '' : PHP_EOL;
+ return $currentKey === (string)$lastKey ? '' : PHP_EOL;
}
}
diff --git a/src/Generator/Commands/UnitTestGenerator.php b/src/Generator/Commands/UnitTestGenerator.php
index 90c3bcfeb..db41bba85 100644
--- a/src/Generator/Commands/UnitTestGenerator.php
+++ b/src/Generator/Commands/UnitTestGenerator.php
@@ -1,5 +1,7 @@
checkParameterOrAsk('foldername', 'Enter the folder name to create the test in');
- if ($folderName) {
+
+ if ($folderName !== '') {
$this->pathStructure = '{section-name}/{container-name}/Tests/Unit/' . $folderName . '/*';
}
@@ -65,6 +74,7 @@ public function getUserInputs(): array|null
if ($stub) {
$stubBasePath = 'tests/unit';
+
if ($stubFolderName) {
$stubBasePath = 'tests/unit/' . $stubFolderName;
}
@@ -81,22 +91,22 @@ public function getUserInputs(): array|null
return [
'path-parameters' => [
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'model' => $model,
- '_model' => Str::camel($model),
- 'models' => $models,
- '_models' => Str::lower($models),
- 'event' => $event,
- 'table-name' => $tableName,
- '_table-name_' => Str::studly($tableName),
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'model' => $model,
+ '_model' => Str::camel($model),
+ 'models' => $models,
+ '_models' => Str::lower($models),
+ 'event' => $event,
+ 'table-name' => $tableName,
+ '_table-name_' => Str::studly($tableName),
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -104,6 +114,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultUnitTest';
diff --git a/src/Generator/Commands/ValueGenerator.php b/src/Generator/Commands/ValueGenerator.php
index face12479..e92c3acf4 100644
--- a/src/Generator/Commands/ValueGenerator.php
+++ b/src/Generator/Commands/ValueGenerator.php
@@ -1,5 +1,7 @@
[
- 'section-name' => $this->sectionName,
+ 'section-name' => $this->sectionName,
'container-name' => $this->containerName,
],
'stub-parameters' => [
- '_section-name' => Str::lower($this->sectionName),
- 'section-name' => $this->sectionName,
+ '_section-name' => Str::lower($this->sectionName),
+ 'section-name' => $this->sectionName,
'_container-name' => Str::lower($this->containerName),
- 'container-name' => $this->containerName,
- 'class-name' => $this->fileName,
- 'resource-key' => strtolower(Pluralizer::plural($this->fileName)),
+ 'container-name' => $this->containerName,
+ 'class-name' => $this->fileName,
+ 'resource-key' => strtolower(Pluralizer::plural($this->fileName)),
],
'file-parameters' => [
'file-name' => $this->fileName,
@@ -65,6 +73,7 @@ public function getUserInputs(): array|null
];
}
+ #[\Override]
public function getDefaultFileName(): string
{
return 'DefaultValue';
diff --git a/src/Generator/Generator.php b/src/Generator/Generator.php
index 405088d08..032478634 100644
--- a/src/Generator/Generator.php
+++ b/src/Generator/Generator.php
@@ -1,10 +1,11 @@
sectionName = $this->removeSpecialChars($this->sectionName);
$this->containerName = $this->removeSpecialChars($this->containerName);
- if ('Configuration' !== $this->fileType) {
+
+ if ($this->fileType !== 'Configuration') {
$this->fileName = $this->removeSpecialChars($this->fileName);
}
@@ -117,10 +121,11 @@ public function handle(): int|null
// Get user inputs
$this->userData = $this->getUserInputs();
- if (null === $this->userData) {
+ if ($this->userData === null || $this->userData === []) {
// The user skipped this step
- return null;
+ return Command::SUCCESS;
}
+
$this->userData = $this->sanitizeUserData($this->userData);
// Get the actual path of the output file as well as the correct filename
@@ -138,19 +143,23 @@ public function handle(): int|null
}
// Exit the command successfully
- return 0;
+ return Command::SUCCESS;
}
/**
* Checks if the param is set (via CLI), otherwise asks the user for a value.
*/
- protected function checkParameterOrAsk($param, $question, string|null $default = null): mixed
- {
+ protected function checkParameterOrAsk(
+ string $param,
+ string $question,
+ null|string|int $default = null,
+ ): array|string|int {
// Check if we already have a param set
$value = $this->option($param);
- if (null === $value) {
- // There was no value provided via CLI, so ask the user…
- $value = text(
+
+ if ($value === null) {
+ // There was no value provided via CLI, so ask the user.
+ return text(
label: $question,
default: $default ?? '',
);
@@ -173,31 +182,10 @@ protected function getDefaultFileName(): string
protected function removeSpecialChars(string $str): string
{
// remove everything that is NOT a character or digit
- return \Safe\preg_replace('/[^A-Za-z0-9]/', '', $str);
+ return preg_replace('/[^A-Za-z0-9]/', '', $str);
}
- /**
- * Checks, if the data from the generator contains path, stub and file-parameters.
- * Adds empty arrays, if they are missing.
- */
- private function sanitizeUserData(array $data): mixed
- {
- if (!array_key_exists('path-parameters', $data)) {
- $data['path-parameters'] = [];
- }
-
- if (!array_key_exists('stub-parameters', $data)) {
- $data['stub-parameters'] = [];
- }
-
- if (!array_key_exists('file-parameters', $data)) {
- $data['file-parameters'] = [];
- }
-
- return $data;
- }
-
- protected function getFilePath($path): string
+ protected function getFilePath(string $path): string
{
// Complete the missing parts of the path
$path = base_path() . '/' .
@@ -246,35 +234,58 @@ protected function getOptions(): array
return array_merge($this->defaultInputs, $this->inputs);
}
- protected function getInput($arg, bool $trim = true): array|string|null
+ protected function getInput($arg, bool $trim = true): null|array|string
{
- return $trim ? $this->trimString($this->argument($arg)) : $this->argument($arg);
+ return $trim ? trim($this->argument($arg)) : $this->argument($arg);
}
/**
* Checks if the param is set (via CLI), otherwise proposes choices to the user.
*/
- protected function checkParameterOrChoice($param, $question, array $choices, mixed $default = null): bool|array|string|null
+ protected function checkParameterOrChoice(string $param, string $question, array $choices, null|string|int $default = null): null|bool|array|string
{
// Check if we already have a param set
$value = $this->option($param);
- if (null === $value) {
- // There was no value provided via CLI, so ask the user…
- $value = select($question, $choices, $default);
+
+ if ($value === null) {
+ // There was no value provided via CLI, so ask the user.
+ return select($question, $choices, $default);
}
return $value;
}
- protected function checkParameterOrConfirm($param, $question, bool $default = false): string|array|bool|null
+ protected function checkParameterOrConfirm(string $param, string $question, bool $default = false): null|string|array|bool
{
// Check if we already have a param set
$value = $this->option($param);
- if (null === $value) {
- // There was no value provided via CLI, so ask the user...
- $value = confirm($question, $default);
+
+ if ($value === null) {
+ // There was no value provided via CLI, so ask the user.
+ return confirm($question, $default);
}
return $value;
}
+
+ /**
+ * Checks, if the data from the generator contains path, stub and file-parameters.
+ * Adds empty arrays, if they are missing.
+ */
+ private function sanitizeUserData(array $data): array
+ {
+ if (!\array_key_exists('path-parameters', $data)) {
+ $data['path-parameters'] = [];
+ }
+
+ if (!\array_key_exists('stub-parameters', $data)) {
+ $data['stub-parameters'] = [];
+ }
+
+ if (!\array_key_exists('file-parameters', $data)) {
+ $data['file-parameters'] = [];
+ }
+
+ return $data;
+ }
}
diff --git a/src/Generator/GeneratorsServiceProvider.php b/src/Generator/GeneratorsServiceProvider.php
index f71b8ed9b..54a75da1f 100644
--- a/src/Generator/GeneratorsServiceProvider.php
+++ b/src/Generator/GeneratorsServiceProvider.php
@@ -1,5 +1,7 @@
update{{model}}Task->run($data, $request->id);
+ return $this->update{{model}}Task->run($request->id, $data);
}
}
diff --git a/src/Generator/Stubs/config.stub b/src/Generator/Stubs/config.stub
index e1045aac4..e3fe0b1d0 100644
--- a/src/Generator/Stubs/config.stub
+++ b/src/Generator/Stubs/config.stub
@@ -1,5 +1,7 @@
{{_model}} = ${{_model}}->withoutRelations();
}
/**
diff --git a/src/Generator/Stubs/events/delete.stub b/src/Generator/Stubs/events/delete.stub
index 1d7e52c06..a644ec257 100644
--- a/src/Generator/Stubs/events/delete.stub
+++ b/src/Generator/Stubs/events/delete.stub
@@ -1,5 +1,7 @@
fake()->name(),
+ ];
+ }
+
+ public function name(): self
+ {
+ return $this->state(fn (array $attributes): array => [
+ 'name' => fake()->name(),
+ ]);
}
}
diff --git a/src/Generator/Stubs/job.stub b/src/Generator/Stubs/job.stub
index 3abc6b424..cdec3d798 100644
--- a/src/Generator/Stubs/job.stub
+++ b/src/Generator/Stubs/job.stub
@@ -1,5 +1,7 @@
id();
$table->timestamps();
});
diff --git a/src/Generator/Stubs/model.stub b/src/Generator/Stubs/model.stub
index eac36b75b..1da39b04a 100644
--- a/src/Generator/Stubs/model.stub
+++ b/src/Generator/Stubs/model.stub
@@ -1,5 +1,7 @@
[
+ // OrderShipped::class => [
// SendShipmentNotification::class,
// ],
];
diff --git a/src/Generator/Stubs/providers/service-provider.stub b/src/Generator/Stubs/providers/service-provider.stub
index 28500bd0d..4355380d5 100644
--- a/src/Generator/Stubs/providers/service-provider.stub
+++ b/src/Generator/Stubs/providers/service-provider.stub
@@ -1,5 +1,7 @@
'=',
];
diff --git a/src/Generator/Stubs/requests/create.stub b/src/Generator/Stubs/requests/create.stub
index ca49b46bf..c10c984ea 100644
--- a/src/Generator/Stubs/requests/create.stub
+++ b/src/Generator/Stubs/requests/create.stub
@@ -1,5 +1,7 @@
'', 'roles' => '']
*
* @apiHeader {String} accept=application/json
@@ -21,10 +29,6 @@
* // Insert the response of the request here...
* }
*/
-
-use App\Containers\{{section-name}}\{{container-name}}\UI\API\Controllers\{{controller-name}};
-use Illuminate\Support\Facades\Route;
-
Route::{{http-verb}}('{{endpoint-url}}', [{{controller-name}}::class, '{{operation}}'])
+ ->name('{{route-name}}')
->middleware(['auth:{{auth-middleware}}']);
-
diff --git a/src/Generator/Stubs/routes/api.sac.stub b/src/Generator/Stubs/routes/api.sac.stub
index 4dbea61fc..6ca538ca1 100644
--- a/src/Generator/Stubs/routes/api.sac.stub
+++ b/src/Generator/Stubs/routes/api.sac.stub
@@ -1,13 +1,21 @@
'', 'roles' => '']
*
* @apiHeader {String} accept=application/json
@@ -21,10 +29,6 @@
* // Insert the response of the request here...
* }
*/
-
-use App\Containers\{{section-name}}\{{container-name}}\UI\API\Controllers\{{controller-name}};
-use Illuminate\Support\Facades\Route;
-
Route::{{http-verb}}('{{endpoint-url}}', {{controller-name}}::class)
+ ->name('{{route-name}}')
->middleware(['auth:{{auth-middleware}}']);
-
diff --git a/src/Generator/Stubs/routes/generic.stub b/src/Generator/Stubs/routes/generic.stub
index 1493d899d..399dcb57c 100644
--- a/src/Generator/Stubs/routes/generic.stub
+++ b/src/Generator/Stubs/routes/generic.stub
@@ -1,8 +1,10 @@
name('{{route-name}}')
->middleware(['auth:{{auth-middleware}}']);
-
diff --git a/src/Generator/Stubs/routes/web.mac.stub b/src/Generator/Stubs/routes/web.mac.stub
index 1c17e258e..fff5c317c 100644
--- a/src/Generator/Stubs/routes/web.mac.stub
+++ b/src/Generator/Stubs/routes/web.mac.stub
@@ -1,8 +1,10 @@
name('{{route-name}}')
->middleware(['auth:{{auth-middleware}}']);
-
diff --git a/src/Generator/Stubs/routes/web.sac.stub b/src/Generator/Stubs/routes/web.sac.stub
index d6ca3aa38..c24fd0836 100644
--- a/src/Generator/Stubs/routes/web.sac.stub
+++ b/src/Generator/Stubs/routes/web.sac.stub
@@ -1,8 +1,10 @@
name('{{route-name}}')
->middleware(['auth:{{auth-middleware}}']);
-
diff --git a/src/Generator/Stubs/seeder.stub b/src/Generator/Stubs/seeder.stub
index ad074470e..ae471a1c4 100644
--- a/src/Generator/Stubs/seeder.stub
+++ b/src/Generator/Stubs/seeder.stub
@@ -1,5 +1,7 @@
repository->delete($id);
}
diff --git a/src/Generator/Stubs/tasks/find.stub b/src/Generator/Stubs/tasks/find.stub
index 478257c96..acfa94e22 100644
--- a/src/Generator/Stubs/tasks/find.stub
+++ b/src/Generator/Stubs/tasks/find.stub
@@ -1,5 +1,7 @@
repository->findOrFail($id);
}
diff --git a/src/Generator/Stubs/tasks/generic.stub b/src/Generator/Stubs/tasks/generic.stub
index df735b944..e7151b6f7 100644
--- a/src/Generator/Stubs/tasks/generic.stub
+++ b/src/Generator/Stubs/tasks/generic.stub
@@ -1,5 +1,7 @@
repository->addRequestCriteria()->paginate();
}
diff --git a/src/Generator/Stubs/tasks/update.stub b/src/Generator/Stubs/tasks/update.stub
index 05ec993b8..00119bdbb 100644
--- a/src/Generator/Stubs/tasks/update.stub
+++ b/src/Generator/Stubs/tasks/update.stub
@@ -1,5 +1,7 @@
repository->update($data, $id);
}
diff --git a/src/Generator/Stubs/tasks/with_event/create.stub b/src/Generator/Stubs/tasks/with_event/create.stub
index 29801bcca..2e5ef137c 100644
--- a/src/Generator/Stubs/tasks/with_event/create.stub
+++ b/src/Generator/Stubs/tasks/with_event/create.stub
@@ -1,5 +1,7 @@
repository->delete($id);
diff --git a/src/Generator/Stubs/tasks/with_event/find.stub b/src/Generator/Stubs/tasks/with_event/find.stub
index 82b2bec65..eeae479b1 100644
--- a/src/Generator/Stubs/tasks/with_event/find.stub
+++ b/src/Generator/Stubs/tasks/with_event/find.stub
@@ -1,5 +1,7 @@
repository->findOrFail($id);
diff --git a/src/Generator/Stubs/tasks/with_event/generic.stub b/src/Generator/Stubs/tasks/with_event/generic.stub
index df735b944..29dc9d367 100644
--- a/src/Generator/Stubs/tasks/with_event/generic.stub
+++ b/src/Generator/Stubs/tasks/with_event/generic.stub
@@ -1,5 +1,7 @@
repository->addRequestCriteria()->paginate();
diff --git a/src/Generator/Stubs/tasks/with_event/update.stub b/src/Generator/Stubs/tasks/with_event/update.stub
index 5e3f5798d..143b60807 100644
--- a/src/Generator/Stubs/tasks/with_event/update.stub
+++ b/src/Generator/Stubs/tasks/with_event/update.stub
@@ -1,5 +1,7 @@
repository->update($data, $id);
diff --git a/src/Generator/Stubs/tests/e2e/web.stub b/src/Generator/Stubs/tests/e2e/web.stub
index 949536ded..597b176f1 100644
--- a/src/Generator/Stubs/tests/e2e/web.stub
+++ b/src/Generator/Stubs/tests/e2e/web.stub
@@ -1,11 +1,16 @@
actingAs(User::factory()->createOne());
$data = [
- // TODO: test
// 'something' => 'value',
];
@@ -23,7 +27,7 @@ final class {{class-name}} extends ApiTestCase
$response->assertCreated();
$response->assertJson(
- fn (AssertableJson $json) =>
+ static fn (AssertableJson $json): AssertableJson =>
$json->has('data')
->where('data.type', '{{model}}')
// ->where('data.something', $data['something'])
diff --git a/src/Generator/Stubs/tests/functional/delete.stub b/src/Generator/Stubs/tests/functional/delete.stub
index fbdb828d1..07900a688 100644
--- a/src/Generator/Stubs/tests/functional/delete.stub
+++ b/src/Generator/Stubs/tests/functional/delete.stub
@@ -1,5 +1,7 @@
assertOk();
$response->assertJson(
- fn (AssertableJson $json) =>
+ static fn (AssertableJson $json): AssertableJson =>
$json->has('data')
->where('data.id', ${{_model}}->getHashedKey())
->etc()
diff --git a/src/Generator/Stubs/tests/functional/generic.stub b/src/Generator/Stubs/tests/functional/generic.stub
index 754c0fc17..58b8cf37d 100644
--- a/src/Generator/Stubs/tests/functional/generic.stub
+++ b/src/Generator/Stubs/tests/functional/generic.stub
@@ -1,5 +1,7 @@
assertOk();
$response->assertJson(
- static fn (AssertableJson $json) =>
+ static fn (AssertableJson $json): AssertableJson =>
$json->has('data', 2)
->etc()
);
diff --git a/src/Generator/Stubs/tests/functional/update.stub b/src/Generator/Stubs/tests/functional/update.stub
index 122d81782..613aeeb9d 100644
--- a/src/Generator/Stubs/tests/functional/update.stub
+++ b/src/Generator/Stubs/tests/functional/update.stub
@@ -1,5 +1,7 @@
assertOk();
$response->assertJson(
- fn (AssertableJson $json) =>
+ static fn (AssertableJson $json): AssertableJson =>
$json->has('data')
->where('data.type', '{{model}}')
->where('data.id', ${{_model}}->getHashedKey())
diff --git a/src/Generator/Stubs/tests/testcase/api.stub b/src/Generator/Stubs/tests/testcase/api.stub
index cdd2afb59..9103340e9 100644
--- a/src/Generator/Stubs/tests/testcase/api.stub
+++ b/src/Generator/Stubs/tests/testcase/api.stub
@@ -1,5 +1,7 @@
'int8',
+ 'id' => 'int8',
'created_at' => 'timestamp',
'updated_at' => 'timestamp',
];
diff --git a/src/Generator/Stubs/tests/unit/factory.stub b/src/Generator/Stubs/tests/unit/factory.stub
index b35664289..023ec3445 100644
--- a/src/Generator/Stubs/tests/unit/factory.stub
+++ b/src/Generator/Stubs/tests/unit/factory.stub
@@ -1,19 +1,24 @@
make();
- $this->assertInstanceOf({{model}}::class, ${{_model}});
+ self::assertInstanceOf({{model}}::class, ${{_model}});
}
}
diff --git a/src/Generator/Stubs/tests/unit/generic.stub b/src/Generator/Stubs/tests/unit/generic.stub
index bccacf3f3..b5a46c233 100644
--- a/src/Generator/Stubs/tests/unit/generic.stub
+++ b/src/Generator/Stubs/tests/unit/generic.stub
@@ -1,5 +1,7 @@
'new_field_value',
];
- $updated{{model}} = app(Update{{model}}Task::class)->run($data, ${{_model}}->id);
+ $updated{{model}} = app(Update{{model}}Task::class)->run(${{_model}}->id, $data);
- $this->assertEquals(${{_model}}->id, $updated{{model}}->id);
- // $this->assertEquals($data['some_field'], $updated{{model}}->some_field);
+ self::assertEquals(${{_model}}->id, $updated{{model}}->id);
+ // self::assertEquals($data['some_field'], $updated{{model}}->some_field);
}
}
diff --git a/src/Generator/Stubs/tests/unit/tasks/with_event/create.stub b/src/Generator/Stubs/tests/unit/tasks/with_event/create.stub
index f74ca9879..6cde4e2b5 100644
--- a/src/Generator/Stubs/tests/unit/tasks/with_event/create.stub
+++ b/src/Generator/Stubs/tests/unit/tasks/with_event/create.stub
@@ -1,5 +1,7 @@
run(${{_model}}->id);
- $this->assertEquals(1, $result);
+ self::assertEquals(1, $result);
Event::assertDispatched({{event}}::class);
}
}
diff --git a/src/Generator/Stubs/tests/unit/tasks/with_event/find.stub b/src/Generator/Stubs/tests/unit/tasks/with_event/find.stub
index 8b76146a7..90e489995 100644
--- a/src/Generator/Stubs/tests/unit/tasks/with_event/find.stub
+++ b/src/Generator/Stubs/tests/unit/tasks/with_event/find.stub
@@ -1,5 +1,7 @@
run(${{_model}}->id);
- $this->assertEquals(${{_model}}->id, $found{{model}}->id);
+ self::assertEquals(${{_model}}->id, $found{{model}}->id);
Event::assertDispatched({{event}}::class);
}
}
diff --git a/src/Generator/Stubs/tests/unit/tasks/with_event/list.stub b/src/Generator/Stubs/tests/unit/tasks/with_event/list.stub
index 3970c4eab..4ca2fe242 100644
--- a/src/Generator/Stubs/tests/unit/tasks/with_event/list.stub
+++ b/src/Generator/Stubs/tests/unit/tasks/with_event/list.stub
@@ -1,5 +1,7 @@
run();
- $this->assertCount(3, $found{{models}});
- $this->assertInstanceOf(LengthAwarePaginator::class, $found{{models}});
+ self::assertCount(3, $found{{models}});
+ self::assertInstanceOf(LengthAwarePaginator::class, $found{{models}});
Event::assertDispatched({{event}}::class);
}
}
diff --git a/src/Generator/Stubs/tests/unit/tasks/with_event/update.stub b/src/Generator/Stubs/tests/unit/tasks/with_event/update.stub
index 8f03dd268..f1ad25f97 100644
--- a/src/Generator/Stubs/tests/unit/tasks/with_event/update.stub
+++ b/src/Generator/Stubs/tests/unit/tasks/with_event/update.stub
@@ -1,5 +1,7 @@
'new_field_data',
];
- $updated{{model}} = app(Update{{model}}Task::class)->run($data, ${{_model}}->id);
+ $updated{{model}} = app(Update{{model}}Task::class)->run(${{_model}}->id, $data);
- $this->assertEquals(${{_model}}->id, $updated{{model}}->id);
- // $this->assertEquals($data['some_field'], $updated{{model}}->some_field);
+ self::assertEquals(${{_model}}->id, $updated{{model}}->id);
+ // self::assertEquals($data['some_field'], $updated{{model}}->some_field);
Event::assertDispatched({{event}}::class);
}
}
diff --git a/src/Generator/Stubs/transformer.stub b/src/Generator/Stubs/transformer.stub
index b4a9cf43c..ccf23dd3e 100644
--- a/src/Generator/Stubs/transformer.stub
+++ b/src/Generator/Stubs/transformer.stub
@@ -1,5 +1,7 @@
${{_model}}->created_at,
- 'updated_at' => ${{_model}}->updated_at,
+ 'created_at' => ${{_model}}->created_at,
+ 'updated_at' => ${{_model}}->updated_at,
'readable_created_at' => ${{_model}}->created_at->diffForHumans(),
'readable_updated_at' => ${{_model}}->updated_at->diffForHumans(),
];
diff --git a/src/Generator/Stubs/value.stub b/src/Generator/Stubs/value.stub
index 7f59de5e4..c4a610b3f 100644
--- a/src/Generator/Stubs/value.stub
+++ b/src/Generator/Stubs/value.stub
@@ -1,5 +1,7 @@
fileSystem->put($filePath, $stubContent);
}
@@ -17,25 +21,23 @@ public function createDirectory(string $path): void
if ($this->alreadyExists($path)) {
$this->printErrorMessage($this->fileType . ' already exists');
- // the file does exist - return but NOT exit
+ // The file does exist - return but NOT exit.
return;
}
try {
- if (!$this->fileSystem->isDirectory(dirname($path))) {
- $this->fileSystem->makeDirectory(dirname($path), 0777, true, true);
+ if (!$this->fileSystem->isDirectory(\dirname($path))) {
+ $this->fileSystem->makeDirectory(\dirname($path), 0777, true, true);
}
- } catch (\Exception) {
- $this->printErrorMessage('Could not create ' . $path);
+ } catch (Throwable) {
+ $this->printErrorMessage(\sprintf('Could not create %s', $path));
}
}
/**
* Determine if the file already exists.
- *
- * @return bool
*/
- protected function alreadyExists($path)
+ protected function alreadyExists(string $path): bool
{
return $this->fileSystem->exists($path);
}
diff --git a/src/Generator/Traits/FormatterTrait.php b/src/Generator/Traits/FormatterTrait.php
deleted file mode 100644
index 6aa89334a..000000000
--- a/src/Generator/Traits/FormatterTrait.php
+++ /dev/null
@@ -1,23 +0,0 @@
-capitalize($className);
- }
-
- public function capitalize($word): string
- {
- return ucfirst((string) $word);
- }
-
- protected function trimString($string): string
- {
- return trim((string) $string);
- }
-}
diff --git a/src/Generator/Traits/ParserTrait.php b/src/Generator/Traits/ParserTrait.php
index 13288852a..aa4d6b522 100644
--- a/src/Generator/Traits/ParserTrait.php
+++ b/src/Generator/Traits/ParserTrait.php
@@ -1,31 +1,47 @@
parsedFileName, $path);
}
/**
- * replaces the variables in the file structure with defined values.
+ * Replaces the variables in the file structure with defined values.
*/
- public function parseFileStructure($filename, $data): string|array
+ public function parseFileStructure(string $filename, array $data): string
{
- return str_replace(array_map([$this, 'maskFileVariables'], array_keys($data)), array_values($data), $filename);
+ return str_replace(
+ array_map(
+ [$this, 'maskFileVariables'],
+ array_keys($data)
+ ),
+ array_values($data),
+ $filename,
+ );
}
/**
- * replaces the variables in the stub file with defined values.
+ * Replaces the variables in the stub file with defined values.
*/
- public function parseStubContent($stub, $data): string|array
+ public function parseStubContent(string $stub, array $data): string|array
{
return str_replace(array_map([$this, 'maskStubVariables'], array_keys($data)), array_values($data), $stub);
}
diff --git a/src/Generator/Traits/PrinterTrait.php b/src/Generator/Traits/PrinterTrait.php
index a1531eccb..918b11cc5 100644
--- a/src/Generator/Traits/PrinterTrait.php
+++ b/src/Generator/Traits/PrinterTrait.php
@@ -1,5 +1,7 @@
printInfoMessage('> Generating (' . $fileName . ') in (' . $containerName . ') Container.');
}
- public function printInfoMessage($message): void
+ public function printInfoMessage(string $message): void
{
info($message);
}
@@ -22,7 +24,7 @@ public function printFinishedMessage(string $type): void
$this->printInfoMessage($type . ' generated successfully.');
}
- public function printErrorMessage($message): void
+ public function printErrorMessage(string $message): void
{
error($message);
}
diff --git a/src/Generator/Traits/UIGeneratorTrait.php b/src/Generator/Traits/UIGeneratorTrait.php
new file mode 100644
index 000000000..05751729c
--- /dev/null
+++ b/src/Generator/Traits/UIGeneratorTrait.php
@@ -0,0 +1,66 @@
+sectionName;
+ $_sectionName = Str::lower($this->sectionName);
+
+ $containerName = $this->containerName;
+ $_containerName = Str::lower($this->containerName);
+
+ $model = $this->containerName;
+ $models = Pluralizer::plural($model);
+
+ $this->printInfoMessage('Generating README File');
+ $this->call('apiato:make:readme', [
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => 'README',
+ ]);
+
+ $this->printInfoMessage('Generating Configuration File');
+ $this->call('apiato:make:configuration', [
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => Str::camel($this->sectionName) . '-' . Str::camel($this->containerName),
+ ]);
+
+ $this->printInfoMessage('Generating Model and Repository');
+ $this->call('apiato:make:model', [
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => $model,
+ '--repository' => true,
+ ]);
+
+ $this->printInfoMessage('Generating a basic Migration file');
+ $this->call('apiato:make:migration', [
+ '--section' => $sectionName,
+ '--container' => $containerName,
+ '--file' => 'create_' . Str::snake($models) . '_table',
+ '--tablename' => Str::snake($models),
+ ]);
+
+ return [
+ $sectionName,
+ $_sectionName,
+ $containerName,
+ $_containerName,
+ $model,
+ $models,
+ ];
+ }
+}
diff --git a/src/Http/Middleware/ProcessETag.php b/src/Http/Middleware/ProcessETag.php
index 9caed5b2a..4038e1515 100644
--- a/src/Http/Middleware/ProcessETag.php
+++ b/src/Http/Middleware/ProcessETag.php
@@ -1,5 +1,7 @@
headers->set('Etag', $etag);
if ($request->hasHeader('if-none-match') && $request->header('if-none-match') === $etag) {
- $response->setStatusCode(304);
+ $response->setStatusCode(Response::HTTP_NOT_MODIFIED);
}
return $response;
diff --git a/src/Http/Middleware/ValidateJsonContent.php b/src/Http/Middleware/ValidateJsonContent.php
index a74d29977..2eb3a5684 100644
--- a/src/Http/Middleware/ValidateJsonContent.php
+++ b/src/Http/Middleware/ValidateJsonContent.php
@@ -1,5 +1,7 @@
request->has(config()->string('fractal.auto_includes.request_key'));
+ return $this->request->has(config()?->string('fractal.auto_includes.request_key'));
}
/**
@@ -34,7 +35,7 @@ public function getValidRelationsFor(Model $model): array
return $this->getDeepestRelations(
...array_filter(
array_map(
- static fn (string $include) => self::isValidRelationOf($model, ...explode('.', $include)),
+ static fn (string $include): ?string => self::isValidRelationOf($model, ...explode('.', $include)),
$this->parseIncludes(),
),
),
@@ -46,7 +47,7 @@ public function getValidRelationsFor(Model $model): array
*/
public function getDeepestRelations(string ...$relations): array
{
- return array_filter($relations, static function ($relation) use ($relations) {
+ return array_filter($relations, static function (string $relation) use ($relations): bool {
foreach ($relations as $otherRelation) {
if ($relation !== $otherRelation && Str::startsWith($otherRelation, $relation . '.')) {
return false;
@@ -57,9 +58,9 @@ public function getDeepestRelations(string ...$relations): array
});
}
- public static function isValidRelationOf(Model $model, string ...$relationParts): string|null
+ public static function isValidRelationOf(Model $model, string ...$relationParts): null|string
{
- if ([] === $relationParts) {
+ if ($relationParts === []) {
return null;
}
@@ -74,13 +75,13 @@ public static function isValidRelationOf(Model $model, string ...$relationParts)
$nextModel = $relation->getRelated();
- if ([] === $relationParts) {
+ if ($relationParts === []) {
return $relationName;
}
$nextRelation = self::isValidRelationOf($nextModel, ...$relationParts);
- if (!is_null($nextRelation)) {
+ if (!\is_null($nextRelation)) {
return $relationName . '.' . $nextRelation;
}
@@ -89,7 +90,7 @@ public static function isValidRelationOf(Model $model, string ...$relationParts)
public static function figureOutRelationName(string $includeName): string
{
- return Str::of($includeName)->camel();
+ return Str::of($includeName)->camel()->toString();
}
/**
@@ -107,7 +108,7 @@ public function parseIncludes(): array
$includes = $this->request->input($requestKey, []);
- if (is_array($includes)) {
+ if (\is_array($includes)) {
Assert::allString($includes);
} else {
Assert::string($includes);
diff --git a/src/Http/Resources/Collection.php b/src/Http/Resources/Collection.php
index ad4bde00a..38c8d8122 100644
--- a/src/Http/Resources/Collection.php
+++ b/src/Http/Resources/Collection.php
@@ -1,25 +1,33 @@
resourceKey)) {
+ if (!\is_null($this->resourceKey)) {
return $this->resourceKey;
}
$resource = $this->data;
- if (is_array($resource)) {
+ if (\is_array($resource)) {
$resource = reset($resource);
}
+
if ($resource instanceof \IteratorAggregate) {
$resource = $resource->getIterator();
}
+
if ($resource instanceof \Iterator) {
$resource = $resource->current();
}
diff --git a/src/Http/Resources/HasResourceKey.php b/src/Http/Resources/HasResourceKey.php
index d6a75dd8f..fc4096410 100644
--- a/src/Http/Resources/HasResourceKey.php
+++ b/src/Http/Resources/HasResourceKey.php
@@ -1,5 +1,7 @@
resourceKey)) {
+ if (!\is_null($this->resourceKey)) {
return $this->resourceKey;
}
diff --git a/src/Http/Resources/ResourceKeyAware.php b/src/Http/Resources/ResourceKeyAware.php
index a44ea491c..537c75ffa 100644
--- a/src/Http/Resources/ResourceKeyAware.php
+++ b/src/Http/Resources/ResourceKeyAware.php
@@ -1,5 +1,7 @@
getResourceName();
- if (is_null($resourceName)) {
- return $this->getResource()->getResourceKey();
- }
-
- return $resourceName;
- }
-
- /**
- * Add meta information about available includes to the response.
- */
- private function setAvailableIncludesMeta(): void
- {
- $this->addMeta([
- 'include' => $this->getTransformerAvailableIncludes(),
- ]);
- }
-
- /**
- * Get the available includes of the transformer.
- *
- * @return string[]
- */
- private function getTransformerAvailableIncludes(): array
- {
- if (is_null($this->transformer) || is_callable($this->transformer)) {
- return [];
- }
-
- $includes = null;
-
- if (is_string($this->transformer)) {
- Assert::subclassOf($this->transformer, TransformerAbstract::class);
-
- $includes = (new $this->transformer())->getAvailableIncludes();
- }
-
- if ($this->transformer instanceof TransformerAbstract) {
- $includes = $this->transformer->getAvailableIncludes();
- }
-
- Assert::allString($includes);
-
- return $includes;
- }
-
/**
* Get the resource class based on the data type.
*/
@@ -100,11 +53,11 @@ public function getResourceClass(): string
{
$this->dataType = $this->determineDataType($this->data);
- if ('item' === $this->dataType) {
+ if ($this->dataType === 'item') {
return Item::class;
}
- if ('collection' === $this->dataType) {
+ if ($this->dataType === 'collection') {
return Collection::class;
}
@@ -113,6 +66,9 @@ public function getResourceClass(): string
/**
* Convert the response data to an array.
+ *
+ * @throws InvalidTransformation
+ * @throws NoTransformerSpecified
*/
public function toArray(): array
{
@@ -124,9 +80,9 @@ public function toArray(): array
*
* @param array $headers
*/
- public function json(mixed $data = null, int $status = 200, array $headers = [], int $options = 0): JsonResponse
+ public function json(mixed $data = null, int $status = SymfonyResponse::HTTP_OK, array $headers = [], int $options = 0): JsonResponse
{
- if (is_null($data) && !is_null($this->data)) {
+ if (\is_null($data) && !\is_null($this->data)) {
return $this->respond($status, $headers, $options);
}
@@ -140,11 +96,11 @@ public function json(mixed $data = null, int $status = 200, array $headers = [],
*/
public function accepted(mixed $data = null, array $headers = [], int $options = 0): JsonResponse
{
- if (is_null($this->getTransformer())) {
+ if (\is_null($this->getTransformer())) {
$this->transformWith(Transformer::empty());
}
- return $this->json($data, 202, $headers, $options);
+ return $this->json($data, SymfonyResponse::HTTP_ACCEPTED, $headers, $options);
}
/**
@@ -154,11 +110,11 @@ public function accepted(mixed $data = null, array $headers = [], int $options =
*/
public function created(mixed $data = null, array $headers = [], int $options = 0): JsonResponse
{
- if (is_null($this->getTransformer())) {
+ if (\is_null($this->getTransformer())) {
$this->transformWith(Transformer::empty());
}
- return $this->json($data, 201, $headers, $options);
+ return $this->json($data, SymfonyResponse::HTTP_CREATED, $headers, $options);
}
/**
@@ -168,11 +124,11 @@ public function created(mixed $data = null, array $headers = [], int $options =
*/
public function ok(mixed $data = null, array $headers = [], int $options = 0): JsonResponse
{
- if (is_null($this->getTransformer())) {
+ if (\is_null($this->getTransformer())) {
$this->transformWith(Transformer::empty());
}
- return $this->json($data, 200, $headers, $options);
+ return $this->json($data, SymfonyResponse::HTTP_OK, $headers, $options);
}
/**
@@ -184,6 +140,60 @@ public function noContent(array $headers = [], int $options = 0): JsonResponse
{
$this->transformWith(Transformer::empty());
- return new JsonResponse(null, 204, $headers, $options);
+ return new JsonResponse(null, SymfonyResponse::HTTP_NO_CONTENT, $headers, $options);
+ }
+
+ /**
+ * Get the resource key or a default value if none is set.
+ *
+ * @throws InvalidTransformation
+ */
+ private function resourceKeyOrDefault(): string
+ {
+ $resourceName = $this->getResourceName();
+
+ if (\is_null($resourceName) || $resourceName === false) {
+ return $this->getResource()->getResourceKey();
+ }
+
+ return $resourceName;
+ }
+
+ /**
+ * Add meta information about available includes to the response.
+ */
+ private function setAvailableIncludesMeta(): void
+ {
+ $this->addMeta([
+ 'include' => $this->getTransformerAvailableIncludes(),
+ ]);
+ }
+
+ /**
+ * Get the available includes of the transformer.
+ *
+ * @return string[]
+ */
+ private function getTransformerAvailableIncludes(): array
+ {
+ if (\is_null($this->transformer) || \is_callable($this->transformer)) {
+ return [];
+ }
+
+ $includes = null;
+
+ if (\is_string($this->transformer)) {
+ Assert::subclassOf($this->transformer, TransformerAbstract::class);
+
+ $includes = (new $this->transformer())->getAvailableIncludes();
+ }
+
+ if ($this->transformer instanceof TransformerAbstract) {
+ $includes = $this->transformer->getAvailableIncludes();
+ }
+
+ Assert::allString($includes);
+
+ return $includes;
}
}
diff --git a/src/Linters/Rector/AssertInstanceToStaticCallRector.php b/src/Linters/Rector/AssertInstanceToStaticCallRector.php
new file mode 100644
index 000000000..0f8ad434d
--- /dev/null
+++ b/src/Linters/Rector/AssertInstanceToStaticCallRector.php
@@ -0,0 +1,131 @@
+
+ */
+final class AssertInstanceToStaticCallRector extends AbstractRector implements MinPhpVersionInterface
+{
+ /**
+ * @var string[]
+ */
+ private const ASSERT_METHODS = [
+ 'assertInstanceOf',
+ 'assertNotInstanceOf',
+ 'assertContains',
+ 'assertNotContains',
+ 'markTestSkipped',
+ 'assertFalse',
+ 'assertTrue',
+ 'assertSame',
+ 'assertEquals',
+ 'assertCount',
+ 'assertNull',
+ 'assertNotNull',
+ 'assertEmpty',
+ 'assertNotEmpty',
+ 'assertIsString',
+ 'assertIsArray',
+ 'assertArrayHasKey',
+ 'assertArrayNotHasKey',
+ 'assertDatabaseTable',
+ ];
+
+ public function __construct(
+ private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
+ ) {
+ }
+
+ /**
+ * @throws PoorDocumentationException
+ */
+ public function getRuleDefinition(): RuleDefinition
+ {
+ return new RuleDefinition(
+ 'Changes PHPUnit assertion instance calls like $this->assertInstanceOf() to static calls like self::assertInstanceOf()',
+ [
+ new CodeSample(
+ <<<'CODE_SAMPLE'
+use PHPUnit\Framework\TestCase;
+
+final class SomeTest extends TestCase
+{
+ public function test(): void
+ {
+ $this->assertInstanceOf(Something::class, $object);
+ $this->assertTrue($value);
+ $this->assertCount(5, $items);
+ }
+}
+CODE_SAMPLE
+ ,
+ <<<'CODE_SAMPLE'
+use PHPUnit\Framework\TestCase;
+
+final class SomeTest extends TestCase
+{
+ public function test(): void
+ {
+ self::assertInstanceOf(Something::class, $object);
+ self::assertTrue($value);
+ self::assertCount(5, $items);
+ }
+}
+CODE_SAMPLE
+ ),
+ ]
+ );
+ }
+
+ /**
+ * @return array>
+ */
+ public function getNodeTypes(): array
+ {
+ return [MethodCall::class];
+ }
+
+ /**
+ * @param MethodCall $node
+ */
+ public function refactor(Node $node): ?Node
+ {
+ if (!$this->testsNodeAnalyzer->isInTestClass($node)) {
+ return null;
+ }
+
+ if (!$this->isName($node->var, 'this')) {
+ return null;
+ }
+
+ if (!$this->isNames($node->name, self::ASSERT_METHODS)) {
+ return null;
+ }
+
+ return new StaticCall(
+ new Name('self'),
+ $this->getName($node->name),
+ $node->args
+ );
+ }
+
+ public function provideMinPhpVersion(): int
+ {
+ return PhpVersion::PHP_82;
+ }
+}
diff --git a/src/Linters/Rector/MockObjectStaticToInstanceCallRector.php b/src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
new file mode 100644
index 000000000..c080b626c
--- /dev/null
+++ b/src/Linters/Rector/MockObjectStaticToInstanceCallRector.php
@@ -0,0 +1,119 @@
+
+ */
+final class MockObjectStaticToInstanceCallRector extends AbstractRector implements MinPhpVersionInterface
+{
+ /**
+ * @var array
+ */
+ private const MOCK_METHODS = ['any', 'once', 'never', 'atLeast', 'atLeastOnce', 'atMost', 'exactly'];
+
+ public function __construct(
+ private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
+ ) {
+ }
+
+ /**
+ * @throws PoorDocumentationException
+ */
+ public function getRuleDefinition(): RuleDefinition
+ {
+ return new RuleDefinition(
+ 'Changes PHPUnit MockObject static calls like self::any() to instance calls like $this->any()',
+ [
+ new CodeSample(
+ <<<'CODE_SAMPLE'
+use PHPUnit\Framework\TestCase;
+
+final class SomeTest extends TestCase
+{
+ public function test(): void
+ {
+ $mock = $this->createMock(Something::class);
+ $mock->expects(self::any())
+ ->method('someMethod')
+ ->willReturn(true);
+
+ $mock->expects(self::once())
+ ->method('otherMethod');
+ }
+}
+CODE_SAMPLE
+ ,
+ <<<'CODE_SAMPLE'
+use PHPUnit\Framework\TestCase;
+
+final class SomeTest extends TestCase
+{
+ public function test(): void
+ {
+ $mock = $this->createMock(Something::class);
+ $mock->expects($this->any())
+ ->method('someMethod')
+ ->willReturn(true);
+
+ $mock->expects($this->once())
+ ->method('otherMethod');
+ }
+}
+CODE_SAMPLE
+ ),
+ ]
+ );
+ }
+
+ /**
+ * @return array>
+ */
+ public function getNodeTypes(): array
+ {
+ return [StaticCall::class];
+ }
+
+ /**
+ * @param StaticCall $node
+ */
+ public function refactor(Node $node): ?Node
+ {
+ if (!$this->testsNodeAnalyzer->isInTestClass($node)) {
+ return null;
+ }
+
+ if (!$this->isNames($node->class, ['self', 'static'])) {
+ return null;
+ }
+
+ if (!$this->isNames($node->name, self::MOCK_METHODS)) {
+ return null;
+ }
+
+ return new MethodCall(
+ new Variable('this'),
+ $node->name,
+ $node->args
+ );
+ }
+
+ public function provideMinPhpVersion(): int
+ {
+ return PhpVersion::PHP_82;
+ }
+}
diff --git a/src/Macros/MacroServiceProvider.php b/src/Macros/MacroServiceProvider.php
index 1b77b9358..73bf6373d 100644
--- a/src/Macros/MacroServiceProvider.php
+++ b/src/Macros/MacroServiceProvider.php
@@ -1,5 +1,7 @@
- /* @var Collection $this */
+ fn (string $hashedValue, string $key = 'id'): bool => /** @var Collection $this */
$this->contains($key, hashids()->decode($hashedValue)),
);
}
@@ -34,6 +35,7 @@ public function boot(): void
* or throws an exception if any value fails to decode.
*/
function (): Collection {
+ /** @var Collection $this */
return $this->map(static fn (string $id): int => hashids()->decodeOrFail($id));
},
);
@@ -43,9 +45,17 @@ function (): Collection {
Config::macro(
'unset',
function (array|string|int|float $key): void {
- /* @var Repository $this */
- Arr::forget($this->items, $key);
- },
+ $deleter = \Closure::bind(
+ static function (Repository $repo, array|string|int|float $key): void {
+ Arr::forget($repo->items, $key);
+ },
+ null,
+ Repository::class
+ );
+
+ /** @var Repository $this */
+ $deleter($this, $key);
+ }
);
}
@@ -53,7 +63,7 @@ function (array|string|int|float $key): void {
Request::macro(
'sanitize',
function (array $fields): array {
- /* @var Request $this */
+ /** @var Request $this */
return Sanitizer::sanitize($this->all(), $fields);
},
);
diff --git a/src/Support/DefaultProviders.php b/src/Support/DefaultProviders.php
index dc536a88e..98f19ae14 100644
--- a/src/Support/DefaultProviders.php
+++ b/src/Support/DefaultProviders.php
@@ -1,5 +1,7 @@
manager->decode($hash);
- if (1 === count($result) && is_int($result[0])) {
+ if (\count($result) === 1 && \is_int($result[0])) {
return $result[0];
}
- if (1 < count($result)) {
+ if (\count($result) > 1) {
return $result;
}
@@ -50,7 +51,7 @@ public function decode(string $hash): int|array|null
*/
public function decodeOrFail(string ...$hash): int|array
{
- if (1 < count($hash)) {
+ if (\count($hash) > 1) {
Assert::allStringNotEmpty($hash);
return array_map(fn (string $id): int|array => $this->decodeOrFail($id), $hash);
@@ -60,18 +61,18 @@ public function decodeOrFail(string ...$hash): int|array
$result = $this->decode($hash[0]);
- if (is_null($result)) {
+ if (\is_null($result)) {
throw new \InvalidArgumentException('Invalid hash id.');
}
return $result;
}
- public function encode(string|int ...$numbers): string|null
+ public function encode(string|int ...$numbers): null|string
{
$result = $this->manager->encode(...$numbers);
- if ('' === $result) {
+ if ($result === '') {
return null;
}
@@ -85,7 +86,7 @@ public function encodeOrFail(mixed ...$numbers): string
{
$result = $this->encode(...$numbers);
- if (is_null($result)) {
+ if (\is_null($result)) {
throw new \InvalidArgumentException('Encoding failed.');
}
@@ -96,7 +97,7 @@ public function encodeOrFail(mixed ...$numbers): string
* Dynamically pass method calls to the underlying resource.
*
* @param string $method
- * @param array $parameters
+ * @param array $parameters
*/
public function __call($method, $parameters)
{
diff --git a/src/Support/Sanitizer.php b/src/Support/Sanitizer.php
index 6d03b857d..4262ee7e4 100644
--- a/src/Support/Sanitizer.php
+++ b/src/Support/Sanitizer.php
@@ -1,5 +1,7 @@
$value) {
- if (is_int($key)) {
+ if (\is_int($key)) {
if (Arr::has($source, $value)) {
Arr::set($sanitized, $value, Arr::get($source, $value));
}
diff --git a/tests/Arch/CoreTest.php b/tests/Arch/CoreTest.php
index d06e381d2..f3d83d85d 100644
--- a/tests/Arch/CoreTest.php
+++ b/tests/Arch/CoreTest.php
@@ -1,7 +1,10 @@
preset()->php();
@@ -18,7 +21,7 @@
'Apiato\Core',
'Apiato\Generator',
'Apiato\Support\Facades',
- Apiato\Http\Response::class,
+ Response::class,
]);
arch('src/abstract')
diff --git a/tests/Functional/Console/CommandServiceProviderTest.php b/tests/Functional/Console/CommandServiceProviderTest.php
index 7ca86b3a2..276da88e5 100644
--- a/tests/Functional/Console/CommandServiceProviderTest.php
+++ b/tests/Functional/Console/CommandServiceProviderTest.php
@@ -1,5 +1,7 @@
true]);
- $user = User::factory()
+ $model = User::factory()
->has(User::factory(1, ['name' => 'child_name'])
->has(Book::factory(2)), 'children')
->createOne();
$response = $this->getJson(
- "v1/authors/{$user->getHashedKey()}/children/{$user->children->first()->name}/books/{$user->children->first()->books->last()->getHashedKey()}",
+ sprintf('v1/authors/%s/children/%s/books/%s', $model->getHashedKey(), $model->children->first()->name, $model->children->first()->books->last()->getHashedKey()),
);
- expect($response->content())->toBe($user->children->first()->books->last()->author->name);
+ expect($response->content())->toBe($model->children->first()->books->last()->author->name);
},
);
});
diff --git a/tests/Functional/Core/Repositories/RepositoryTest.php b/tests/Functional/Core/Repositories/RepositoryTest.php
index 4bd3f648c..2cdccc6af 100644
--- a/tests/Functional/Core/Repositories/RepositoryTest.php
+++ b/tests/Functional/Core/Repositories/RepositoryTest.php
@@ -1,5 +1,7 @@
has(Book::factory(3))
->createOne();
- $repository = new class extends UserRepository {
+ $repository = new class () extends UserRepository {
public function shouldEagerLoadIncludes(): bool
{
return true;
@@ -33,16 +35,18 @@ public function shouldEagerLoadIncludes(): bool
expect($result)->toBeInstanceOf(Collection::class)
->each(function (Expectation $expectation) use ($userMustLoadRelations, $booksMustLoadRelations, $mustNotLoadRelations): void {
- foreach ($userMustLoadRelations as $relation) {
- $expectation->relationLoaded($relation)->toBeTrue();
+ foreach ($userMustLoadRelations as $userMustLoadRelation) {
+ $expectation->relationLoaded($userMustLoadRelation)->toBeTrue();
}
- foreach ($booksMustLoadRelations as $relation) {
- $expectation->books->each(function (Expectation $expectation) use ($relation): void {
- $expectation->relationLoaded($relation)->toBeTrue();
+
+ foreach ($booksMustLoadRelations as $bookMustLoadRelation) {
+ $expectation->books->each(function (Expectation $expectation) use ($bookMustLoadRelation): void {
+ $expectation->relationLoaded($bookMustLoadRelation)->toBeTrue();
});
}
- foreach ($mustNotLoadRelations as $relation) {
- $expectation->relationLoaded($relation)->toBeFalse();
+
+ foreach ($mustNotLoadRelations as $mustNotLoadRelation) {
+ $expectation->relationLoaded($mustNotLoadRelation)->toBeFalse();
}
});
})->with([
@@ -87,10 +91,9 @@ public function shouldEagerLoadIncludes(): bool
it('can disable eager loading', function (bool $enabled): void {
request()->merge(['include' => 'books']);
User::factory()->has(Book::factory())->createOne();
- $repository = new class($enabled) extends UserRepository {
- public function __construct(
- private readonly bool $enabled,
- ) {
+ $repository = new class ($enabled) extends UserRepository {
+ public function __construct(private readonly bool $enabled)
+ {
parent::__construct();
}
@@ -111,7 +114,7 @@ public function shouldEagerLoadIncludes(): bool
});
});
})->with([
- 'enabled' => [true],
+ 'enabled' => [true],
'disabled' => [false],
]);
})->covers(Repository::class);
diff --git a/tests/Functional/Core/Requests/RequestTest.php b/tests/Functional/Core/Requests/RequestTest.php
index bc90e50aa..c2ee0295f 100644
--- a/tests/Functional/Core/Requests/RequestTest.php
+++ b/tests/Functional/Core/Requests/RequestTest.php
@@ -1,6 +1,9 @@
encodeOrFail($ids[0]),
hashids()->encodeOrFail($ids[1]),
];
- $result = $this->patchJson("v1/books/{$bookIdHashed}", [
- 'title' => 'New Title',
+ $result = $this->patchJson('v1/books/' . $bookIdHashed, [
+ 'title' => 'New Title',
'hashed_id' => $HashedId,
'author_id' => $authorIdHashed,
- 'authors' => [
+ 'authors' => [
[
- 'id' => $authorIdHashed,
+ 'id' => $authorIdHashed,
'name' => 'Author Name',
],
],
- 'ids' => $hashedIds,
+ 'ids' => $hashedIds,
'just_a_number' => 123,
- 'nested' => [
- 'id' => $nestedIdHashed,
+ 'nested' => [
+ 'id' => $nestedIdHashed,
'ids' => $nestedIdsHashed,
],
]);
@@ -48,22 +51,22 @@
expect($result->json())
->toBe([
'input(val)' => [
- 'id' => null,
- 'id-default' => 100,
- 'title' => 'New Title',
- 'hashed_id' => $HashedId,
- 'nested.id' => $expectedNestedId,
+ 'id' => null,
+ 'id-default' => 100,
+ 'title' => 'New Title',
+ 'hashed_id' => $HashedId,
+ 'nested.id' => $expectedNestedId,
'nested.with-default' => 200,
- 'author_id' => $expectedAuthorId,
- 'authors' => [
+ 'author_id' => $expectedAuthorId,
+ 'authors' => [
['id' => $expectedAuthorId, 'name' => 'Author Name'],
],
- 'authors.*.id' => [$expectedAuthorId],
+ 'authors.*.id' => [$expectedAuthorId],
'authors.*.with-default' => [null],
- 'ids' => $expectedIds,
- 'with-default' => [1, 2, 3],
- 'none_existing' => null,
- 'optional_id' => null,
+ 'ids' => $expectedIds,
+ 'with-default' => [1, 2, 3],
+ 'none_existing' => null,
+ 'optional_id' => null,
],
'all(val)' => [
'id' => [
@@ -93,56 +96,56 @@
],
],
'route(val)' => [
- 'id' => $expectedBookId,
+ 'id' => $expectedBookId,
'none_existing' => null,
],
'request->val' => [
- 'id' => $expectedBookId,
- 'title' => 'New Title',
+ 'id' => $expectedBookId,
+ 'title' => 'New Title',
'none_existing' => null,
- 'optional_id' => null,
+ 'optional_id' => null,
],
'input()' => [
- 'title' => 'New Title',
+ 'title' => 'New Title',
'hashed_id' => $HashedId,
'author_id' => $expectedAuthorId,
- 'authors' => [
+ 'authors' => [
['id' => $expectedAuthorId, 'name' => 'Author Name'],
],
- 'ids' => $expectedIds,
+ 'ids' => $expectedIds,
'just_a_number' => 123,
- 'nested' => [
- 'id' => $expectedNestedId,
+ 'nested' => [
+ 'id' => $expectedNestedId,
'ids' => $expectedNestedIds,
],
],
'all()' => [
- 'title' => 'New Title',
+ 'title' => 'New Title',
'hashed_id' => $HashedId,
'author_id' => $expectedAuthorId,
- 'authors' => [
+ 'authors' => [
['id' => $expectedAuthorId, 'name' => 'Author Name'],
],
- 'ids' => $expectedIds,
+ 'ids' => $expectedIds,
'just_a_number' => 123,
- 'nested' => [
- 'id' => $expectedNestedId,
+ 'nested' => [
+ 'id' => $expectedNestedId,
'ids' => $expectedNestedIds,
],
],
'validated' => [
- 'title' => 'New Title',
+ 'title' => 'New Title',
'author_id' => $expectedAuthorId,
- 'nested' => [
- 'id' => $expectedNestedId,
+ 'nested' => [
+ 'id' => $expectedNestedId,
'ids' => $expectedNestedIds,
],
- 'ids' => $expectedIds,
+ 'ids' => $expectedIds,
'authors' => [
['id' => $expectedAuthorId],
],
],
- 'route()::class' => Illuminate\Routing\Route::class,
+ 'route()::class' => Route::class,
]);
})->with([
[true],
diff --git a/tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php b/tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
index 2c63fc41a..8cb9ab195 100644
--- a/tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
+++ b/tests/Functional/Foundation/Configuration/ApplicationBuilderTest.php
@@ -1,5 +1,7 @@
localization();
+ $localization = apiato()->localization();
$this->app->setLocale('en');
- foreach ($configuration->paths() as $path) {
- expect(__($configuration->buildNamespaceFor($path) . '::errors.forbidden'))->toBe('forbidden');
+ foreach ($localization->paths() as $path) {
+ expect(__($localization->buildNamespaceFor($path) . '::errors.forbidden'))->toBe('forbidden');
}
$this->app->setLocale('fa');
- foreach ($configuration->paths() as $path) {
- expect(__($configuration->buildNamespaceFor($path) . '::errors.forbidden'))->toBe('ممنوع');
+ foreach ($localization->paths() as $path) {
+ expect(__($localization->buildNamespaceFor($path) . '::errors.forbidden'))->toBe('ممنوع');
}
});
diff --git a/tests/Functional/Foundation/Support/Providers/MigrationServiceProviderTest.php b/tests/Functional/Foundation/Support/Providers/MigrationServiceProviderTest.php
index abb394ae9..d0a8a044f 100644
--- a/tests/Functional/Foundation/Support/Providers/MigrationServiceProviderTest.php
+++ b/tests/Functional/Foundation/Support/Providers/MigrationServiceProviderTest.php
@@ -1,5 +1,7 @@
merge([
'include' => 'children.books,parent',
]);
- $this->repository = new class extends UserRepository {
+ $this->repository = new class () extends UserRepository {
public function shouldEagerLoadIncludes(): bool
{
return true;
diff --git a/tests/Functional/Macros/MacroServiceProviderTest.php b/tests/Functional/Macros/MacroServiceProviderTest.php
index bb2124111..c9b3059a7 100644
--- a/tests/Functional/Macros/MacroServiceProviderTest.php
+++ b/tests/Functional/Macros/MacroServiceProviderTest.php
@@ -1,6 +1,6 @@
afterEach(function () {
+pest()->afterEach(function (): void {
$this->freezeTime();
});
/*
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 004eed958..a01472af7 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -1,5 +1,7 @@
createOne([
- 'name' => $name,
+ 'name' => $name,
'email' => $email,
]);
diff --git a/tests/Unit/Core/Models/BaseModelTest.php b/tests/Unit/Core/Models/BaseModelTest.php
index d8faf00c3..b1f8d818d 100644
--- a/tests/Unit/Core/Models/BaseModelTest.php
+++ b/tests/Unit/Core/Models/BaseModelTest.php
@@ -1,5 +1,7 @@
model = new class extends BaseModel {
+ $this->model = new class () extends BaseModel {
protected $resourceKey = 'custom-resource-key';
};
});
@@ -26,10 +28,10 @@
it('can locate the factory of the model using different call styles', function (): void {
$usingModel = Book::factory()->makeOne();
- $usingFactory = Book::factory()->makeOne();
+ $model = Book::factory()->makeOne();
expect($usingModel)->toBeInstanceOf(Book::class)
- ->and($usingFactory)->toBeInstanceOf(Book::class);
+ ->and($model)->toBeInstanceOf(Book::class);
});
describe('getHashedKey()', function (): void {
@@ -38,35 +40,35 @@
});
it('returns hashed primary key by default', function (): void {
- $book = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- expect($book->getHashedKey())->toBe(hashids()->encode($book->getKey()));
+ expect($model->getHashedKey())->toBe(hashids()->encode($model->getKey()));
});
it('can return hashed key for a specific field', function (): void {
- $book = Book::factory()->makeOne();
+ $model = Book::factory()->makeOne();
- expect($book->getHashedKey('author_id'))->toBe(hashids()->encode($book->author_id));
+ expect($model->getHashedKey('author_id'))->toBe(hashids()->encode($model->author_id));
});
it('returns null if the field is null', function (): void {
- $book = Book::factory()->makeOne(['author_id' => null]);
+ $model = Book::factory()->makeOne(['author_id' => null]);
- expect($book->getHashedKey('author_id'))->toBeNull();
+ expect($model->getHashedKey('author_id'))->toBeNull();
});
it('returns the original field value if hash-id is disabled', function (): void {
config(['apiato.hash-id' => false]);
- $book = Book::factory()->makeOne();
+ $model = Book::factory()->makeOne();
- expect($book->getHashedKey())->toEqual($book->getKey());
+ expect($model->getHashedKey())->toEqual($model->getKey());
});
it('returns the original field value if the field is not hashable and hash-id is disabled', function (): void {
config(['apiato.hash-id' => false]);
- $book = Book::factory()->makeOne();
+ $model = Book::factory()->makeOne();
- expect($book->getHashedKey('title'))->toEqual($book->title);
+ expect($model->getHashedKey('title'))->toEqual($model->title);
});
});
@@ -74,12 +76,12 @@
it('can handle hashed ids', function (): void {
config(['apiato.hash-id' => true]);
Book::factory()->count(3)->create();
- $target = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
expect(
Book::newModelInstance()->resolveRouteBinding(
- hashids()->encode($target->getKey()),
- )->is($target),
+ hashids()->encode($model->getKey()),
+ )->is($model),
)->toBeTrue();
});
@@ -90,9 +92,9 @@ function (bool $enabled, bool $incrementing, bool $isHashedId, bool $expectation
expect(
Book::newModelInstance()
- ->setIncrementing($incrementing)
- ->shouldProcessHashIdRouteBinding(!$isHashedId ?: hashids()->encode(1)),
- )->toBe($expectation, "Enabled: {$enabled}, Incrementing: {$incrementing}");
+ ->setIncrementing($incrementing)
+ ->shouldProcessHashIdRouteBinding(!$isHashedId ?: hashids()->encode(1)),
+ )->toBe($expectation, sprintf('Enabled: %s, Incrementing: %s', $enabled, $incrementing));
},
)->with([
[true, true, true, true],
@@ -118,7 +120,7 @@ function (bool $enabled, bool $incrementing, bool $isHashedId, bool $expectation
it(
'can detect when it should resolve hashed ids and when it should not 2',
- function (string $value, string|null $field, Book $target): void {
+ function (string $value, null|string $field, Book $target): void {
config(['apiato.hash-id' => true]);
expect(
@@ -130,39 +132,39 @@ function (string $value, string|null $field, Book $target): void {
},
)->with([
function (): array {
- $target = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- return [hashids()->encode($target->id), null, $target];
+ return [hashids()->encode($model->id), null, $model];
},
function (): array {
- $target = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- return [hashids()->encode($target->id), 'id', $target];
+ return [hashids()->encode($model->id), 'id', $model];
},
function (): array {
- $target = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- return [$target->title, 'title', $target];
+ return [$model->title, 'title', $model];
},
])->skip();
it('can handle unhashed ids', function (): void {
config(['apiato.hash-id' => false]);
Book::factory()->count(3)->create();
- $target = Book::factory()->createOne([
+ $model = Book::factory()->createOne([
'title' => 'Target',
]);
expect(
Book::newModelInstance()->resolveRouteBinding(
- $target->getKey(),
- )->is($target),
+ $model->getKey(),
+ )->is($model),
)->toBeTrue()
->and(
Book::newModelInstance()->resolveRouteBinding(
- $target->title,
+ $model->title,
'title',
- )->is($target),
+ )->is($model),
)->toBeTrue();
});
});
diff --git a/tests/Unit/Core/Repositories/Exceptions/ResourceCreationFailedTest.php b/tests/Unit/Core/Repositories/Exceptions/ResourceCreationFailedTest.php
index 9ea5918f6..597580a5c 100644
--- a/tests/Unit/Core/Repositories/Exceptions/ResourceCreationFailedTest.php
+++ b/tests/Unit/Core/Repositories/Exceptions/ResourceCreationFailedTest.php
@@ -1,14 +1,14 @@
toBeInstanceOf(ResourceCreationFailed::class);
- expect($exception->getMessage())->toBe('Resource creation failed.');
- expect($exception->getStatusCode())->toBe(417);
+ $resourceCreationFailed = ResourceCreationFailed::create();
+ expect($resourceCreationFailed)->toBeInstanceOf(ResourceCreationFailed::class);
+ expect($resourceCreationFailed->getMessage())->toBe('Resource creation failed.');
+ expect($resourceCreationFailed->getStatusCode())->toBe(417);
});
})->covers(ResourceCreationFailed::class);
diff --git a/tests/Unit/Core/Repositories/Exceptions/ResourceNotFoundTest.php b/tests/Unit/Core/Repositories/Exceptions/ResourceNotFoundTest.php
index 9c2ded7f7..58485f21a 100644
--- a/tests/Unit/Core/Repositories/Exceptions/ResourceNotFoundTest.php
+++ b/tests/Unit/Core/Repositories/Exceptions/ResourceNotFoundTest.php
@@ -1,14 +1,14 @@
toBeInstanceOf(ResourceNotFound::class);
- expect($exception->getMessage())->toBe('Resource not found.');
- expect($exception->getStatusCode())->toBe(404);
+ $resourceNotFound = ResourceNotFound::create();
+ expect($resourceNotFound)->toBeInstanceOf(ResourceNotFound::class);
+ expect($resourceNotFound->getMessage())->toBe('Resource not found.');
+ expect($resourceNotFound->getStatusCode())->toBe(404);
});
})->covers(ResourceNotFound::class);
diff --git a/tests/Unit/Core/Repositories/RepositoryTest.php b/tests/Unit/Core/Repositories/RepositoryTest.php
index 1a73edf75..6c3045d2c 100644
--- a/tests/Unit/Core/Repositories/RepositoryTest.php
+++ b/tests/Unit/Core/Repositories/RepositoryTest.php
@@ -1,40 +1,163 @@
addRequestCriteria();
+
+ expect($bookRepository->getCriteria())->toHaveCount(1)
+ ->and($bookRepository->getCriteria()->first())->toBeInstanceOf(RequestCriteria::class);
+ });
+
+ it('can remove request criteria', function (): void {
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $bookRepository = $repository->removeRequestCriteria();
+
+ expect($bookRepository->getCriteria())->toBeEmpty();
+ });
+
+ it('decodes search query when hash-id is enabled', function (): void {
+ config(['apiato.hash-id' => true]);
+
+ $hashedId = hashids()->encode(123);
+ $searchString = 'id:' . $hashedId;
+ $expectedString = 'id:123';
+
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['search' => $searchString]);
+ app()->instance(Request::class, $request);
+
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $actualQuery = app(Request::class)->query('search');
+
+ expect($actualQuery)->toBe($expectedString);
+ });
+
+ it('does not decode search query when hash-id is disabled', function (): void {
+ config(['apiato.hash-id' => false]);
+
+ $hashedId = hashids()->encode(123);
+ $searchString = 'id:' . $hashedId;
+
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['search' => $searchString]);
+ app()->instance(Request::class, $request);
+
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $actualQuery = app(Request::class)->query('search');
+
+ expect($actualQuery)->toBe($searchString);
+ });
+
+ it('ignores boolean values when decoding search query', function (): void {
+ config(['apiato.hash-id' => true]);
+
+ $searchString = 'is_active:true;is_admin:false;status:1;flag:0';
+
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['search' => $searchString]);
+ app()->instance(Request::class, $request);
+
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $actualQuery = app(Request::class)->query('search');
+
+ expect($actualQuery)->toBe($searchString);
+ });
+
+ it('ignores numeric values when decoding search query', function (): void {
+ config(['apiato.hash-id' => true]);
+
+ $searchString = 'age:30;count:5';
+
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['search' => $searchString]);
+ app()->instance(Request::class, $request);
+
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $actualQuery = app(Request::class)->query('search');
+
+ expect($actualQuery)->toBe($searchString);
+ });
+
+ it('handles complex search input with mixed values', function (): void {
+ config(['apiato.hash-id' => true]);
+
+ $hashedId1 = hashids()->encode(123);
+ $hashedId2 = hashids()->encode(456);
+ $searchString = sprintf('id:%s;name:John;is_active:true;role_id:%s;age:30', $hashedId1, $hashedId2);
+ $expectedString = 'id:123;name:John;is_active:true;role_id:456;age:30';
+
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['search' => $searchString]);
+ app()->instance(Request::class, $request);
+
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $actualQuery = app(Request::class)->query('search');
+
+ expect($actualQuery)->toBe($expectedString);
+ });
+
+ it('does nothing when search parameter is empty', function (): void {
+ config(['apiato.hash-id' => true]);
- $result = $repository->addRequestCriteria();
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['search' => '']);
+ app()->instance(Request::class, $request);
+
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $actualQuery = app(Request::class)->query('search');
+
+ expect($actualQuery)->toBe('');
+ });
- expect($result->getCriteria())->toHaveCount(1)
- ->and($result->getCriteria()->first())->toBeInstanceOf(RequestCriteria::class);
+ it('does nothing when search parameter is not a string', function (): void {
+ config(['apiato.hash-id' => true]);
- $result = $repository->removeRequestCriteria();
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['search' => null]);
+ app()->instance(Request::class, $request);
- expect($result->getCriteria())->toBeEmpty();
+ $repository = new BookRepository();
+ $repository->addRequestCriteria();
+
+ $actualQuery = app(Request::class)->query('search');
+
+ expect($actualQuery)->toBeNull();
+ });
});
it('can push criteria and passing args', function (): void {
$repository = new BookRepository();
- $result = $repository->pushCriteriaWith(RequestCriteria::class, ['criteria' => request()]);
+ $bookRepository = $repository->pushCriteriaWith(RequestCriteria::class, ['criteria' => app(Request::class)]);
- expect($result->getCriteria())->toHaveCount(1)
- ->and($result->getCriteria()->first())->toBeInstanceOf(RequestCriteria::class);
+ expect($bookRepository->getCriteria())->toHaveCount(1)
+ ->and($bookRepository->getCriteria()->first())->toBeInstanceOf(RequestCriteria::class);
});
it('discover its model', function (): void {
@@ -43,28 +166,28 @@
expect($repository->model())->toBe(Book::class);
});
- it('can cache method call results', function (string $method, \Closure $args): void {
+ it('can cache method call results', function (string $method, Closure $args): void {
Cache::clear();
config(['repository.cache.enabled' => true]);
- $user = User::factory()->createOne();
+ $model = User::factory()->createOne();
$repository = $this->app->make(UserRepository::class);
- $arguments = $args($user->id);
+ $arguments = $args($model->id);
$cacheKey = $repository->getCacheKey($method, [$arguments]);
expect(Cache::missing($cacheKey))->toBeTrue();
// hit the cache
- $repository->$method($arguments);
+ $repository->{$method}($arguments);
expect(Cache::has($cacheKey))->toBeTrue();
})->with([
'all' => [
'all',
- static fn () => ['*'],
+ static fn (): array => ['*'],
],
'paginate' => [
'paginate',
- static fn () => null,
+ static fn (): int => 0,
],
'find' => [
'find',
@@ -72,17 +195,17 @@
],
'findByField' => [
'findByField',
- static fn ($id) => ['id', $id],
+ static fn ($id): array => ['id', $id],
],
'findWhere' => [
'findWhere',
- static fn ($id) => [$id],
+ static fn ($id): array => [$id],
],
]);
describe('scopes', function (): void {
it('can push/reset scopes stack', function (): void {
- $repository = new class extends UserRepository {
+ $repository = new class () extends UserRepository {
public function shouldEagerLoadIncludes(): bool
{
return false;
@@ -130,30 +253,30 @@ public function getScopes(): array
it('can make new model instance', function (): void {
$repository = new BookRepository();
- $result = $repository->make(['title' => 'test']);
+ $book = $repository->make(['title' => 'test']);
- expect($result)->toBeInstanceOf(Book::class)
- ->and($result->title)->toBe('test');
+ expect($book)->toBeInstanceOf(Book::class)
+ ->and($book->title)->toBe('test');
});
it('can get the model instance', function (): void {
$repository = new BookRepository();
- $result = $repository->getModel();
+ $book = $repository->getModel();
- expect($result)->toBeInstanceOf(Book::class);
+ expect($book)->toBeInstanceOf(Book::class);
});
it('can store a new model instance', function ($data): void {
$repository = new BookRepository();
- $result = $repository->store($data);
+ $book = $repository->store($data);
- expect($result)->toBeInstanceOf(Book::class)
- ->and($result->title)->toBe('test');
+ expect($book)->toBeInstanceOf(Book::class)
+ ->and($book->title)->toBe('test');
})->with([
'array' => [
- fn () => ['title' => 'test'],
+ fn (): array => ['title' => 'test'],
],
'model' => [
fn () => Book::factory()->makeOne(['title' => 'test']),
@@ -164,10 +287,10 @@ public function getScopes(): array
it('can create a new model instance', function (): void {
$repository = new BookRepository();
- $result = $repository->create(['title' => 'test']);
+ $book = $repository->create(['title' => 'test']);
- expect($result)->toBeInstanceOf(Book::class)
- ->and($result->title)->toBe('test');
+ expect($book)->toBeInstanceOf(Book::class)
+ ->and($book->title)->toBe('test');
});
it('throws custom exception', function (): void {
@@ -181,36 +304,36 @@ public function getScopes(): array
it('can save the model instance', function (): void {
$repository = new BookRepository();
- $book = Book::factory()->makeOne();
+ $model = Book::factory()->makeOne();
- $this->assertModelMissing($book);
+ $this->assertModelMissing($model);
- $repository->save($book);
+ $repository->save($model);
- $this->assertModelExists($book);
+ $this->assertModelExists($model);
});
describe('first or create', function (): void {
it('can find first or create', function (): void {
$repository = new BookRepository();
- $book = Book::factory()->makeOne();
+ $model = Book::factory()->makeOne();
- $this->assertModelMissing($book);
+ $this->assertModelMissing($model);
- $result = $repository->firstOrCreate(['title' => $book->title], $book->toArray());
+ $book = $repository->firstOrCreate(['title' => $model->title], $model->toArray());
- expect($result)->toBeInstanceOf(Book::class)
- ->and($result->title)->toBe($book->title);
+ expect($book)->toBeInstanceOf(Book::class)
+ ->and($book->title)->toBe($model->title);
- $this->assertModelExists($result);
+ $this->assertModelExists($book);
});
it('can update attributes if model is found', function (): void {
$repository = new UserRepository();
- $result = $repository->firstOrCreate(
+ $model = $repository->firstOrCreate(
[
- 'email' => 'saruman@the.white',
+ 'email' => 'saruman@the.white',
'password' => 'password',
],
[
@@ -218,21 +341,21 @@ public function getScopes(): array
],
);
- expect($result)->toBeInstanceOf(User::class)
- ->and($result->name)->toBe('saruman')
- ->and($result->email)->toBe('saruman@the.white');
+ expect($model)->toBeInstanceOf(User::class)
+ ->and($model->name)->toBe('saruman')
+ ->and($model->email)->toBe('saruman@the.white');
});
});
describe('update', function (): void {
it('can update an entity instance', function (): void {
$repository = new BookRepository();
- $book = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- $result = $repository->update(['title' => 'updated'], $book->id);
+ $book = $repository->update(['title' => 'updated'], $model->id);
- $this->assertModelExists($result);
- expect($result->title)->toBe('updated');
+ $this->assertModelExists($book);
+ expect($book->title)->toBe('updated');
});
it('throws custom exception', function (): void {
@@ -247,12 +370,12 @@ public function getScopes(): array
describe('findOrFail', function (): void {
it('can find an entity instance', function (): void {
$repository = new BookRepository();
- $book = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- $result = $repository->findOrFail($book->id);
+ $book = $repository->findOrFail($model->id);
- expect($result)->toBeInstanceOf(Book::class)
- ->and($result->id)->toBe($book->id);
+ expect($book)->toBeInstanceOf(Book::class)
+ ->and($book->id)->toBe($model->id);
});
it('throws custom exception', function (): void {
@@ -267,12 +390,12 @@ public function getScopes(): array
describe('find', function (): void {
it('can find an entity instance', function (): void {
$repository = new BookRepository();
- $book = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- $result = $repository->find($book->id);
+ $result = $repository->find($model->id);
expect($result)->toBeInstanceOf(Book::class)
- ->and($result->id)->toBe($book->id);
+ ->and($result?->getKey())->toBe($model->id);
});
it('returns null if model is not found', function (): void {
@@ -287,12 +410,12 @@ public function getScopes(): array
describe('findById', function (): void {
it('can find an entity instance', function (): void {
$repository = new BookRepository();
- $book = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- $result = $repository->findById($book->id);
+ $result = $repository->findById($model->id);
expect($result)->toBeInstanceOf(Book::class)
- ->and($result->id)->toBe($book->id);
+ ->and($result?->getKey())->toBe($model->id);
});
it('returns null if model is not found', function (): void {
@@ -377,12 +500,12 @@ public function getScopes(): array
describe('delete', function (): void {
it('can delete an entity instance', function (): void {
$repository = new BookRepository();
- $book = Book::factory()->createOne();
+ $model = Book::factory()->createOne();
- $result = $repository->delete($book->id);
+ $result = $repository->delete($model->id);
expect($result)->toBeTrue();
- $this->assertModelMissing($book);
+ $this->assertModelMissing($model);
});
it('throws custom exception', function (): void {
@@ -392,5 +515,73 @@ public function getScopes(): array
$repository->findOrFail(777);
})->toThrow(ResourceNotFound::create('Book'));
});
+
+ it('throws exception when deleting non-existent entity', function (): void {
+ expect(function (): void {
+ $repository = new BookRepository();
+
+ $repository->delete(777);
+ })->toThrow(Error::class);
+ });
+ });
+
+ describe('pagination handling', function (): void {
+ it('can set pagination limit from request', function (): void {
+ $repository = new BookRepository();
+
+ $request = Request::create('/', SymfonyRequest::METHOD_GET, ['limit' => '42']);
+ app()->instance(Request::class, $request);
+
+ $limit = $repository->setPaginationLimit(42);
+
+ expect($limit)->toBe(42);
+ });
+
+ it('can set pagination limit from parameter', function (): void {
+ $repository = new BookRepository();
+
+ $limit = $repository->setPaginationLimit(42);
+
+ expect($limit)->toBe(42);
+ });
+
+ it('can check if pagination should be skipped', function (): void {
+ $repository = new BookRepository();
+
+ expect($repository->wantsToSkipPagination(0))->toBeTrue();
+ expect($repository->wantsToSkipPagination(5))->toBeFalse();
+ });
+
+ it('checks if disable pagination is allowed via repository property', function (): void {
+ $repository = mock(UserRepository::class)->makePartial();
+ $repository->shouldReceive('canSkipPagination')->andReturn(true);
+
+ expect($repository->canSkipPagination())->toBeTrue();
+
+ $repository = mock(UserRepository::class)->makePartial();
+ $repository->shouldReceive('canSkipPagination')->andReturn(false);
+
+ expect($repository->canSkipPagination())->toBeFalse();
+ });
+
+ it('checks if disable pagination is allowed via global config', function (): void {
+ $repository = new BookRepository();
+
+ config(['repository.pagination.skip' => true]);
+ expect($repository->canSkipPagination())->toBeTrue();
+
+ config(['repository.pagination.skip' => false]);
+ expect($repository->canSkipPagination())->toBeFalse();
+ });
+
+ it('can check if limit exceeds max pagination limit', function (): void {
+ $legacyMock = mock(BookRepository::class)->makePartial();
+ $legacyMock->allows('exceedsMaxPaginationLimit')->andReturnUsing(
+ fn ($limit): bool => $limit > 10
+ );
+
+ expect($legacyMock->exceedsMaxPaginationLimit(20))->toBeTrue();
+ expect($legacyMock->exceedsMaxPaginationLimit(5))->toBeFalse();
+ });
});
})->covers(Repository::class);
diff --git a/tests/Unit/Core/Requests/RequestTest.php b/tests/Unit/Core/Requests/RequestTest.php
index 7cbf83507..764cea129 100644
--- a/tests/Unit/Core/Requests/RequestTest.php
+++ b/tests/Unit/Core/Requests/RequestTest.php
@@ -1,16 +1,16 @@
merge([
'name' => 'Gandalf',
- 'age' => 100,
+ 'age' => 100,
]);
$result = $sut->sanitize(['age']);
diff --git a/tests/Unit/Core/Tests/TestCaseTest.php b/tests/Unit/Core/Tests/TestCaseTest.php
index f0071698f..ed8b482f4 100644
--- a/tests/Unit/Core/Tests/TestCaseTest.php
+++ b/tests/Unit/Core/Tests/TestCaseTest.php
@@ -1,12 +1,13 @@
sut = new class('Anonym') extends TestCase {};
+ $this->sut = new class ('Anonym') extends TestCase {
+ };
});
describe(class_basename(TestCase::class), function (): void {
it('uses expected traits', function (): void {
diff --git a/tests/Unit/Core/Transformers/TransformerTest.php b/tests/Unit/Core/Transformers/TransformerTest.php
index 3014ff14d..c6b4df83e 100644
--- a/tests/Unit/Core/Transformers/TransformerTest.php
+++ b/tests/Unit/Core/Transformers/TransformerTest.php
@@ -1,5 +1,7 @@
[null, 'Book'],
+ 'null resource key' => [null, 'Book'],
'override resource key' => ['CustomKey', 'CustomKey'],
]);
- it('can return an item', function (string|null $resourceKey, $expected): void {
+ it('can return an item', function (null|string $resourceKey, $expected): void {
$transformer = new BookTransformer();
$transformer->setDefaultIncludes(['author']);
@@ -39,7 +41,7 @@
->and($item->getResourceKey())->toBe($expected);
})->with('resourceKeys');
- it('can return a collection', function (string|null $resourceKey, $expected): void {
+ it('can return a collection', function (null|string $resourceKey, $expected): void {
$transformer = new BookTransformer();
$transformer->setDefaultIncludes(['author']);
diff --git a/tests/Unit/Foundation/ApiatoTest.php b/tests/Unit/Foundation/ApiatoTest.php
index b8fabf74a..0ba28dc97 100644
--- a/tests/Unit/Foundation/ApiatoTest.php
+++ b/tests/Unit/Foundation/ApiatoTest.php
@@ -1,5 +1,7 @@
create();
@@ -92,7 +96,7 @@
});
it('can be instantiated without a path', function (): void {
- $basePath = Safe\realpath(__DIR__ . '/../../../workbench');
+ $basePath = realpath(__DIR__ . '/../../../workbench');
$apiato = Apiato::configure()->create();
@@ -100,9 +104,11 @@
});
it('can infer base path', function (): void {
- $basePath = Safe\realpath(__DIR__ . '/../../..');
+ $basePath = realpath(__DIR__ . '/../../..');
+
+ $expectation = Apiato::inferBasePath();
- expect(Apiato::inferBasePath())->toBe($basePath);
+ expect($expectation)->toBe($basePath);
});
it('accepts and apply routing config override', function (): void {
diff --git a/tests/Unit/Foundation/Configuration/FactoryTest.php b/tests/Unit/Foundation/Configuration/FactoryTest.php
index 55d2ee94a..234be9d73 100644
--- a/tests/Unit/Foundation/Configuration/FactoryTest.php
+++ b/tests/Unit/Foundation/Configuration/FactoryTest.php
@@ -1,5 +1,7 @@
toArray())
- ->filter(static fn (string $provider): bool => StrayServiceProvider::class === $provider)
+ ->filter(static fn (string $provider): bool => $provider === StrayServiceProvider::class)
->count(),
)->toBe(1);
});
diff --git a/tests/Unit/Foundation/Configuration/RepositoryTest.php b/tests/Unit/Foundation/Configuration/RepositoryTest.php
index 18ad68256..098139cd8 100644
--- a/tests/Unit/Foundation/Configuration/RepositoryTest.php
+++ b/tests/Unit/Foundation/Configuration/RepositoryTest.php
@@ -1,5 +1,7 @@
withSeeders(
static fn (Seeding $seeding): Seeding => $seeding->sortUsing(
static fn (): array => [
- (new class extends Seeder {
+ (new class () extends Seeder {
public function run(): void
{
User::factory()->createOne([
diff --git a/tests/Unit/Foundation/HelpersTest.php b/tests/Unit/Foundation/HelpersTest.php
index a76655967..ea5aaeaf0 100644
--- a/tests/Unit/Foundation/HelpersTest.php
+++ b/tests/Unit/Foundation/HelpersTest.php
@@ -1,14 +1,21 @@
toBeInstanceOf(Apiato::class);
})->coversFunction('apiato');
- it('can get the path to the application\'s shared directory', function (): void {
+ it("can get the path to the application's shared directory", function (): void {
expect(shared_path())->toBe(base_path('app/Ship'));
})->coversFunction('shared_path');
@@ -16,19 +23,19 @@
expect(hashids())->toBeInstanceOf(HashidsManagerDecorator::class);
})->coversFunction('hashids');
- it('can find php files recursively', function () {
+ it('can find php files recursively', function (): void {
$baseDir = sys_get_temp_dir() . '/test_' . uniqid('', true);
- \Safe\mkdir($baseDir . '/subdir', 0777, true);
- \Safe\file_put_contents($baseDir . '/file1.php', 'toHaveCount(2);
// Clean up
- \Safe\unlink($baseDir . '/file1.php');
- \Safe\unlink($baseDir . '/subdir/file2.php');
- \Safe\rmdir($baseDir . '/subdir');
- \Safe\rmdir($baseDir);
+ unlink($baseDir . '/file1.php');
+ unlink($baseDir . '/subdir/file2.php');
+ rmdir($baseDir . '/subdir');
+ rmdir($baseDir);
});
});
diff --git a/tests/Unit/Http/Middleware/ProcessETagTest.php b/tests/Unit/Http/Middleware/ProcessETagTest.php
index b43c7a339..f58dcdd40 100644
--- a/tests/Unit/Http/Middleware/ProcessETagTest.php
+++ b/tests/Unit/Http/Middleware/ProcessETagTest.php
@@ -1,5 +1,7 @@
true]);
$request = Request::create('/test', 'GET');
$request->headers->remove('Accept');
+
$middleware = new ValidateJsonContent();
$this->expectException(RuntimeException::class);
@@ -25,6 +28,7 @@
config(['apiato.requests.force-accept-header' => $enabled]);
$request = Request::create('/test', 'GET');
$request->headers->set('Accept', 'application/json');
+
$middleware = new ValidateJsonContent();
$response = $middleware->handle($request, $this->next);
diff --git a/tests/Unit/Http/RequestRelationTest.php b/tests/Unit/Http/RequestRelationTest.php
index 8ce42c254..cd0265d55 100644
--- a/tests/Unit/Http/RequestRelationTest.php
+++ b/tests/Unit/Http/RequestRelationTest.php
@@ -1,6 +1,6 @@
getResourceKey())->toBe($expectation, json_encode($data));
@@ -23,9 +25,19 @@ function (User|LaravelCollection|stdClass|array|Iterator|null $data, string $exp
fn (): array => [[User::factory()->makeOne()], 'User'],
[fn () => User::factory(2)->make(), 'User'],
[fn () => User::factory(2)->make()->getIterator(), 'User'],
- [[new class {}], ''],
- [fn () => collect([new class {}]), ''],
- [fn () => collect([new class {}])->getIterator(), ''],
+ [
+ [new class () {
+ },
+ ], '',
+ ],
+ [fn () => collect([new class () {
+ },
+ ]), '',
+ ],
+ [fn () => collect([new class () {
+ },
+ ])->getIterator(), '',
+ ],
[fn () => User::factory()->makeOne(), 'User'],
[fn (): stdClass => new stdClass(), ''],
]);
diff --git a/tests/Unit/Http/Resources/ItemTest.php b/tests/Unit/Http/Resources/ItemTest.php
index defba1114..fbc08d782 100644
--- a/tests/Unit/Http/Resources/ItemTest.php
+++ b/tests/Unit/Http/Resources/ItemTest.php
@@ -1,5 +1,7 @@
getResourceKey())->toBe($expectation, json_encode($data));
@@ -23,9 +25,19 @@ function (User|LaravelCollection|stdClass|array|Iterator|null $data, string $exp
fn (): array => [[User::factory()->makeOne()], ''],
fn (): array => [User::factory(2)->make(), ''],
fn (): array => [User::factory(2)->make()->getIterator(), ''],
- [[new class {}], ''],
- fn (): array => [collect([new class {}]), ''],
- fn (): array => [collect([new class {}])->getIterator(), ''],
+ [
+ [new class () {
+ },
+ ], '',
+ ],
+ fn (): array => [collect([new class () {
+ },
+ ]), '',
+ ],
+ fn (): array => [collect([new class () {
+ },
+ ])->getIterator(), '',
+ ],
fn (): array => [User::factory()->makeOne(), 'User'],
fn (): array => [new stdClass(), ''],
]);
diff --git a/tests/Unit/Http/ResponseTest.php b/tests/Unit/Http/ResponseTest.php
index e4f909196..31baf2479 100644
--- a/tests/Unit/Http/ResponseTest.php
+++ b/tests/Unit/Http/ResponseTest.php
@@ -1,6 +1,6 @@
manager();
+ $manager = $response->manager();
- expect($result)->toBeInstanceOf(Manager::class);
+ expect($manager)->toBeInstanceOf(Manager::class);
});
it('can handle CSV includes for single resource', function (string $include, array $expected): void {
@@ -43,26 +43,26 @@ function getUser(): User
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
foreach ($expected as $expectation) {
- $result->has($expectation);
+ $assertableJson->has($expectation);
}
})->with([
'single string' => [
- 'include' => 'parent',
+ 'include' => 'parent',
'expected' => ['data.parent'],
],
'single string nested' => [
- 'include' => 'children.books',
+ 'include' => 'children.books',
'expected' => ['data.children.data.0.books'],
],
'csv string' => [
- 'include' => 'parent,children',
+ 'include' => 'parent,children',
'expected' => ['data.parent', 'data.children'],
],
'csv string and nested' => [
- 'include' => 'parent,children.books',
+ 'include' => 'parent,children.books',
'expected' => ['data.parent', 'data.children.data.0.books'],
],
]);
@@ -72,22 +72,22 @@ function getUser(): User
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
foreach ($expected as $expectation) {
- $result->has($expectation);
+ $assertableJson->has($expectation);
}
})->with([
'single array' => [
- 'include' => ['parent'],
+ 'include' => ['parent'],
'expected' => ['data.parent'],
],
'multiple array' => [
- 'include' => ['parent', 'children'],
+ 'include' => ['parent', 'children'],
'expected' => ['data.parent', 'data.children'],
],
'multiple array nested' => [
- 'include' => ['parent.books', 'children'],
+ 'include' => ['parent.books', 'children'],
'expected' => ['data.parent.data.books', 'data.children'],
],
]);
@@ -98,9 +98,9 @@ function getUser(): User
$users = app(UserRepository::class, ['app' => $this->app])->paginate();
$response = Response::create($users)->transformWith(UserTransformer::class);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
- $result->has('meta.include', fn (AssertableJson $json): AssertableJson => $json->whereAll(['parent', 'children', 'books']));
+ $assertableJson->has('meta.include', fn (AssertableJson $json): AssertableJson => $json->whereAll(['parent', 'children', 'books']));
})->with([
'single string' => [
'include' => 'parent',
@@ -130,45 +130,46 @@ function getUser(): User
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
foreach ($expected as $expectation) {
- $result->has($expectation);
- $result->has('meta.include', fn (AssertableJson $json): AssertableJson => $json->whereAll(['parent', 'children', 'books']));
+ $assertableJson->has($expectation);
+ $assertableJson->has('meta.include', fn (AssertableJson $json): AssertableJson => $json->whereAll(['parent', 'children', 'books']));
}
+
foreach ($missing as $expectation) {
- $result->missing($expectation);
+ $assertableJson->missing($expectation);
}
})->with([
'without includes' => [
- 'fields' => ['User' => 'id,email'],
+ 'fields' => ['User' => 'id,email'],
'expected' => ['data.id', 'data.email'],
- 'missing' => ['data.type', 'data.name', 'data.created_at', 'data.updated_at', 'data.children', 'data.books'],
+ 'missing' => ['data.type', 'data.name', 'data.created_at', 'data.updated_at', 'data.children', 'data.books'],
],
'only filter nested include keys' => [
- 'fields' => ['Book' => 'author,title'],
+ 'fields' => ['Book' => 'author,title'],
'expected' => ['data.type', 'data.id', 'data.email', 'data.name', 'data.created_at', 'data.updated_at', 'data.books.data.0.author', 'data.books.data.0.title'],
- 'missing' => ['data.books.data.0.id', 'data.books.data.0.created_at', 'data.books.data.0.updated_at'],
+ 'missing' => ['data.books.data.0.id', 'data.books.data.0.created_at', 'data.books.data.0.updated_at'],
],
'with first level includes - no filter' => [
- 'fields' => ['User' => 'type,id,email,books'],
+ 'fields' => ['User' => 'type,id,email,books'],
'expected' => ['data.type', 'data.id', 'data.email', 'data.books.data.0.type', 'data.books.data.0.id', 'data.books.data.0.title', 'data.books.data.0.author', 'data.books.data.0.created_at', 'data.books.data.0.updated_at'],
- 'missing' => ['data.name', 'data.created_at', 'data.updated_at'],
+ 'missing' => ['data.name', 'data.created_at', 'data.updated_at'],
],
'with first level includes - filter' => [
- 'fields' => ['User' => 'type,id,email,books', 'Book' => 'type,author'],
+ 'fields' => ['User' => 'type,id,email,books', 'Book' => 'type,author'],
'expected' => ['data.type', 'data.id', 'data.email', 'data.books.data.0.type', 'data.books.data.0.author'],
- 'missing' => ['data.children', 'data.books.data.0.id', 'data.books.data.0.title', 'data.books.data.0.created_at', 'data.books.data.0.updated_at', 'data.name', 'data.created_at', 'data.updated_at'],
+ 'missing' => ['data.children', 'data.books.data.0.id', 'data.books.data.0.title', 'data.books.data.0.created_at', 'data.books.data.0.updated_at', 'data.name', 'data.created_at', 'data.updated_at'],
],
'with nested includes - no filter' => [
- 'fields' => ['User' => 'type,id,email,children,books'],
+ 'fields' => ['User' => 'type,id,email,children,books'],
'expected' => ['data.type', 'data.id', 'data.email', 'data.children.data.0.type', 'data.children.data.0.id', 'data.children.data.0.email', 'data.children.data.0.books.data.0.type', 'data.children.data.0.books.data.0.id', 'data.children.data.0.books.data.0.title', 'data.children.data.0.books.data.0.author', 'data.children.data.0.books.data.0.created_at', 'data.children.data.0.books.data.0.updated_at'],
- 'missing' => ['data.name', 'data.created_at', 'data.updated_at'],
+ 'missing' => ['data.name', 'data.created_at', 'data.updated_at'],
],
'with nested includes - filter' => [
- 'fields' => ['User' => 'id,email,children,books', 'Book' => 'id'],
+ 'fields' => ['User' => 'id,email,children,books', 'Book' => 'id'],
'expected' => ['data.id', 'data.email', 'data.children.data.0.id', 'data.children.data.0.email', 'data.children.data.0.books.data.0.id'],
- 'missing' => ['data.type', 'data.children.data.0.type', 'data.children.data.0.books.data.0.type', 'data.children.data.0.books.data.0.title', 'data.children.data.0.books.data.0.author', 'data.children.data.0.books.data.0.created_at', 'data.children.data.0.books.data.0.updated_at', 'data.name', 'data.created_at', 'data.updated_at'],
+ 'missing' => ['data.type', 'data.children.data.0.type', 'data.children.data.0.books.data.0.type', 'data.children.data.0.books.data.0.title', 'data.children.data.0.books.data.0.author', 'data.children.data.0.books.data.0.created_at', 'data.children.data.0.books.data.0.updated_at', 'data.name', 'data.created_at', 'data.updated_at'],
],
]);
@@ -177,26 +178,26 @@ function getUser(): User
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class)->parseIncludes($exclude);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
foreach ($expected as $expectation) {
- $result->missing($expectation);
+ $assertableJson->missing($expectation);
}
})->with([
'single string' => [
- 'exclude' => 'parent',
+ 'exclude' => 'parent',
'expected' => ['data.parent'],
],
'single string nested' => [
- 'exclude' => 'children.books',
+ 'exclude' => 'children.books',
'expected' => ['data.children.data.0.books'],
],
'csv string' => [
- 'exclude' => 'parent,children',
+ 'exclude' => 'parent,children',
'expected' => ['data.parent', 'data.children'],
],
'csv string and nested' => [
- 'exclude' => 'parent,children.books',
+ 'exclude' => 'parent,children.books',
'expected' => ['data.parent', 'data.children.data.0.books'],
],
]);
@@ -206,22 +207,22 @@ function getUser(): User
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class)->parseIncludes($exclude);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
foreach ($expected as $expectation) {
- $result->missing($expectation);
+ $assertableJson->missing($expectation);
}
})->with([
'single array' => [
- 'exclude' => ['parent'],
+ 'exclude' => ['parent'],
'expected' => ['data.parent'],
],
'multiple array' => [
- 'exclude' => ['parent', 'children'],
+ 'exclude' => ['parent', 'children'],
'expected' => ['data.parent', 'data.children'],
],
'multiple array nested' => [
- 'exclude' => ['parent.books', 'children'],
+ 'exclude' => ['parent.books', 'children'],
'expected' => ['data.parent.data.books', 'data.children'],
],
]);
@@ -232,9 +233,9 @@ function getUser(): User
$users = app(UserRepository::class, ['app' => $this->app])->paginate();
$response = Response::create($users)->transformWith(UserTransformer::class)->parseIncludes($exclude);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
- $result->has('meta.include', fn (AssertableJson $json): AssertableJson => $json->whereAll(['parent', 'children', 'books']));
+ $assertableJson->has('meta.include', fn (AssertableJson $json): AssertableJson => $json->whereAll(['parent', 'children', 'books']));
})->with([
'single string' => [
'exclude' => 'parent',
@@ -265,9 +266,9 @@ function getUser(): User
$response->transformWith(UserTransformer::class);
$response->withResourceName($resourceName);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
- $result->missing('data.type');
+ $assertableJson->missing('data.type');
})->with([
'empty string' => [
'resourceName' => '',
@@ -277,15 +278,15 @@ function getUser(): User
],
]);
- it('can use fallback default resource name', function (bool|null $resourceName): void {
+ it('can use fallback default resource name', function (null|bool $resourceName): void {
request()->merge(['include' => 'books,children.books', 'fields' => [$resourceName => 'id', 'Book' => 'author,title']]);
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class);
$response->withResourceName($resourceName);
- $result = AssertableJson::fromArray($response->toArray());
+ $assertableJson = AssertableJson::fromArray($response->toArray());
- $result->has('data.type');
+ $assertableJson->has('data.type');
})->with([
'null' => [
'resourceName' => null,
@@ -298,39 +299,39 @@ function getUser(): User
it('can generate 200/OK response', function (): void {
$response = Response::create(getUser());
- $result = $response->ok();
+ $jsonResponse = $response->ok();
- expect($result)->getStatusCode()->toBe(200)->getData()->toHaveKey('data', []);
+ expect($jsonResponse)->getStatusCode()->toBe(200)->getData()->toHaveKey('data', []);
});
it('can generate 202/Accepted response', function (): void {
$response = Response::create(getUser());
- $result = $response->accepted();
+ $jsonResponse = $response->accepted();
- expect($result)->getStatusCode()->toBe(202)->getData()->toHaveKey('data', []);
+ expect($jsonResponse)->getStatusCode()->toBe(202)->getData()->toHaveKey('data', []);
});
it('can generate 201/Created response', function (): void {
$response = Response::create(getUser());
- $result = $response->created();
+ $jsonResponse = $response->created();
- expect($result)->getStatusCode()->toBe(201)->getData()->toHaveKey('data', []);
+ expect($jsonResponse)->getStatusCode()->toBe(201)->getData()->toHaveKey('data', []);
});
it('can generate 204/NoContent response', function (): void {
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class);
- $result = $response->noContent();
+ $jsonResponse = $response->noContent();
- expect($result->getStatusCode())->toBe(204);
+ expect($jsonResponse->getStatusCode())->toBe(204);
});
it('can parse include params with resource name', function (): void {
$include = 'books';
- $includeWithParams = "$include:test(2|value)";
+ $includeWithParams = $include . ':test(2|value)';
request()->merge(['include' => $includeWithParams]);
$response = Response::create(getUser());
$response->transformWith(UserTransformer::class);
@@ -347,7 +348,7 @@ function getUser(): User
expect($expectedParams)->toEqual($actualParams);
});
- it('returns the custom resource class', function (Collection|User|array|null $data, string $expectation): void {
+ it('returns the custom resource class', function (null|Collection|User|array $data, string $expectation): void {
$response = Response::create($data);
$result = $response->getResourceClass();
@@ -355,8 +356,8 @@ function getUser(): User
expect($result)->toBe($expectation);
})->with([
[fn () => User::factory()->makeOne(), Item::class],
- [Collection::empty(), \Apiato\Http\Resources\Collection::class],
- [[], \Apiato\Http\Resources\Collection::class],
+ [Collection::empty(), Apiato\Http\Resources\Collection::class],
+ [[], Apiato\Http\Resources\Collection::class],
[null, NullResource::class],
]);
diff --git a/tests/Unit/Macros/MacroServiceProviderTest.php b/tests/Unit/Macros/MacroServiceProviderTest.php
index 7bed5a760..ba29d92cd 100644
--- a/tests/Unit/Macros/MacroServiceProviderTest.php
+++ b/tests/Unit/Macros/MacroServiceProviderTest.php
@@ -1,5 +1,7 @@
toBeInstanceOf(Apiato\Http\Response::class);
});
- dataset('method_params', function () {
+ dataset('method_params', function (): array {
return [
[null, [], 0],
['foo', [], 0],
@@ -31,18 +33,18 @@
expect($result)
->toBeInstanceOf(JsonResponse::class)
->and($result->getData(true))
- ->when(!is_null($data), fn (Expectation $ex) => $ex->toBe($data))
- ->when(is_null($data), fn (Expectation $ex) => $ex->toBeArray()->toBeEmpty())
+ ->when(!is_null($data), fn (Expectation $ex): Expectation => $ex->toBe($data))
+ ->when(is_null($data), fn (Expectation $ex): Expectation => $ex->toBeArray()->toBeEmpty())
->and($result->getStatusCode())
->toBe(200)
->and($result->headers->get('foo'))
- ->when([] !== $headers, fn (Expectation $ex) => $ex->toBe('bar'))
+ ->when($headers !== [], fn (Expectation $ex): Expectation => $ex->toBe('bar'))
->when(
- [] === $headers,
- fn (Expectation $ex) => $ex->toBeEmpty()
- ->and($result->getEncodingOptions())
- ->when(0 !== $options, fn (Expectation $ex) => $ex->toBe(1))
- ->when(0 === $options, fn (Expectation $ex) => $ex->toBe(0)),
+ $headers === [],
+ fn (Expectation $ex): Expectation => $ex->toBeEmpty()
+ ->and($result->getEncodingOptions())
+ ->when($options !== 0, fn (Expectation $ex): Expectation => $ex->toBe(1))
+ ->when($options === 0, fn (Expectation $ex): Expectation => $ex->toBe(0)),
);
})->with('method_params');
@@ -51,23 +53,23 @@
array $headers,
int $options,
): void {
- $result = Response::accepted($data, $headers, $options);
+ $jsonResponse = Response::accepted($data, $headers, $options);
- expect($result)
+ expect($jsonResponse)
->toBeInstanceOf(JsonResponse::class)
- ->and($result->getData(true))
- ->when(!is_null($data), fn (Expectation $ex) => $ex->toBe($data))
- ->when(is_null($data), fn (Expectation $ex) => $ex->toBeArray()->toBeEmpty())
- ->and($result->getStatusCode())
+ ->and($jsonResponse->getData(true))
+ ->when(!is_null($data), fn (Expectation $ex): Expectation => $ex->toBe($data))
+ ->when(is_null($data), fn (Expectation $ex): Expectation => $ex->toBeArray()->toBeEmpty())
+ ->and($jsonResponse->getStatusCode())
->toBe(202)
- ->and($result->headers->get('foo'))
- ->when([] !== $headers, fn (Expectation $ex) => $ex->toBe('bar'))
+ ->and($jsonResponse->headers->get('foo'))
+ ->when($headers !== [], fn (Expectation $ex): Expectation => $ex->toBe('bar'))
->when(
- [] === $headers,
- fn (Expectation $ex) => $ex->toBeEmpty()
- ->and($result->getEncodingOptions())
- ->when(0 !== $options, fn (Expectation $ex) => $ex->toBe(1))
- ->when(0 === $options, fn (Expectation $ex) => $ex->toBe(0)),
+ $headers === [],
+ fn (Expectation $ex): Expectation => $ex->toBeEmpty()
+ ->and($jsonResponse->getEncodingOptions())
+ ->when($options !== 0, fn (Expectation $ex): Expectation => $ex->toBe(1))
+ ->when($options === 0, fn (Expectation $ex): Expectation => $ex->toBe(0)),
);
})->with('method_params');
@@ -76,23 +78,23 @@
array $headers,
int $options,
): void {
- $result = Response::created($data, $headers, $options);
+ $jsonResponse = Response::created($data, $headers, $options);
- expect($result)
+ expect($jsonResponse)
->toBeInstanceOf(JsonResponse::class)
- ->and($result->getData(true))
- ->when(!is_null($data), fn (Expectation $ex) => $ex->toBe($data))
- ->when(is_null($data), fn (Expectation $ex) => $ex->toBeArray()->toBeEmpty())
- ->and($result->getStatusCode())
+ ->and($jsonResponse->getData(true))
+ ->when(!is_null($data), fn (Expectation $ex): Expectation => $ex->toBe($data))
+ ->when(is_null($data), fn (Expectation $ex): Expectation => $ex->toBeArray()->toBeEmpty())
+ ->and($jsonResponse->getStatusCode())
->toBe(201)
- ->and($result->headers->get('foo'))
- ->when([] !== $headers, fn (Expectation $ex) => $ex->toBe('bar'))
+ ->and($jsonResponse->headers->get('foo'))
+ ->when($headers !== [], fn (Expectation $ex): Expectation => $ex->toBe('bar'))
->when(
- [] === $headers,
- fn (Expectation $ex) => $ex->toBeEmpty()
- ->and($result->getEncodingOptions())
- ->when(0 !== $options, fn (Expectation $ex) => $ex->toBe(1))
- ->when(0 === $options, fn (Expectation $ex) => $ex->toBe(0)),
+ $headers === [],
+ fn (Expectation $ex): Expectation => $ex->toBeEmpty()
+ ->and($jsonResponse->getEncodingOptions())
+ ->when($options !== 0, fn (Expectation $ex): Expectation => $ex->toBe(1))
+ ->when($options === 0, fn (Expectation $ex): Expectation => $ex->toBe(0)),
);
})->with('method_params');
@@ -101,23 +103,23 @@
array $headers,
int $options,
): void {
- $result = Response::ok($data, $headers, $options);
+ $jsonResponse = Response::ok($data, $headers, $options);
- expect($result)
+ expect($jsonResponse)
->toBeInstanceOf(JsonResponse::class)
- ->and($result->getData(true))
- ->when(!is_null($data), fn (Expectation $ex) => $ex->toBe($data))
- ->when(is_null($data), fn (Expectation $ex) => $ex->toBeArray()->toBeEmpty())
- ->and($result->getStatusCode())
+ ->and($jsonResponse->getData(true))
+ ->when(!is_null($data), fn (Expectation $ex): Expectation => $ex->toBe($data))
+ ->when(is_null($data), fn (Expectation $ex): Expectation => $ex->toBeArray()->toBeEmpty())
+ ->and($jsonResponse->getStatusCode())
->toBe(200)
- ->and($result->headers->get('foo'))
- ->when([] !== $headers, fn (Expectation $ex) => $ex->toBe('bar'))
+ ->and($jsonResponse->headers->get('foo'))
+ ->when($headers !== [], fn (Expectation $ex): Expectation => $ex->toBe('bar'))
->when(
- [] === $headers,
- fn (Expectation $ex) => $ex->toBeEmpty()
- ->and($result->getEncodingOptions())
- ->when(0 !== $options, fn (Expectation $ex) => $ex->toBe(1))
- ->when(0 === $options, fn (Expectation $ex) => $ex->toBe(0)),
+ $headers === [],
+ fn (Expectation $ex): Expectation => $ex->toBeEmpty()
+ ->and($jsonResponse->getEncodingOptions())
+ ->when($options !== 0, fn (Expectation $ex): Expectation => $ex->toBe(1))
+ ->when($options === 0, fn (Expectation $ex): Expectation => $ex->toBe(0)),
);
})->with('method_params');
@@ -125,22 +127,22 @@
array $headers,
int $options,
): void {
- $result = Response::noContent($headers, $options);
+ $jsonResponse = Response::noContent($headers, $options);
- expect($result)
+ expect($jsonResponse)
->toBeInstanceOf(JsonResponse::class)
- ->and($result->getData(true))
+ ->and($jsonResponse->getData(true))
->toBeEmpty()
- ->and($result->getStatusCode())
+ ->and($jsonResponse->getStatusCode())
->toBe(204)
- ->and($result->headers->get('foo'))
- ->when([] !== $headers, fn (Expectation $ex) => $ex->toBe('bar'))
+ ->and($jsonResponse->headers->get('foo'))
+ ->when($headers !== [], fn (Expectation $ex): Expectation => $ex->toBe('bar'))
->when(
- [] === $headers,
- fn (Expectation $ex) => $ex->toBeEmpty()
- ->and($result->getEncodingOptions())
- ->when(0 !== $options, fn (Expectation $ex) => $ex->toBe(1))
- ->when(0 === $options, fn (Expectation $ex) => $ex->toBe(0)),
+ $headers === [],
+ fn (Expectation $ex): Expectation => $ex->toBeEmpty()
+ ->and($jsonResponse->getEncodingOptions())
+ ->when($options !== 0, fn (Expectation $ex): Expectation => $ex->toBe(1))
+ ->when($options === 0, fn (Expectation $ex): Expectation => $ex->toBe(0)),
);
})->with([
[[], 0],
diff --git a/tests/Unit/Support/HashidsManagerDecoratorTest.php b/tests/Unit/Support/HashidsManagerDecoratorTest.php
index 57120f179..bf549f93c 100644
--- a/tests/Unit/Support/HashidsManagerDecoratorTest.php
+++ b/tests/Unit/Support/HashidsManagerDecoratorTest.php
@@ -1,5 +1,7 @@
toBeTrue();
+ expect(in_array(ForwardsCalls::class, class_uses(HashidsManagerDecorator::class), true))->toBeTrue();
});
it('should use the Macroable trait', function (): void {
- expect(in_array(Macroable::class, class_uses(HashidsManagerDecorator::class)))->toBeTrue();
+ expect(in_array(Macroable::class, class_uses(HashidsManagerDecorator::class), true))->toBeTrue();
});
- it('can decode or null', function (string $hashId, int|array|null $expectation): void {
+ it('can decode or null', function (string $hashId, null|int|array $expectation): void {
$sut = new HashidsManagerDecorator(new HashidsManager(config(), app('hashids.factory')));
$result = $sut->decode($hashId);
expect($result)->toBe($expectation);
})->with([
- [fn () => hashids()->encodeOrFail(10), 10],
- [fn () => hashids()->encodeOrFail(10, 13, 2), [10, 13, 2]],
+ [fn (): string => hashids()->encodeOrFail(10), 10],
+ [fn (): string => hashids()->encodeOrFail(10, 13, 2), [10, 13, 2]],
['invalid', null],
]);
- it('can decode or throw an exception', function (string $hashId, int|array|null $expectation): void {
+ it('can decode or throw an exception', function (string $hashId, null|int|array $expectation): void {
$sut = new HashidsManagerDecorator(new HashidsManager(config(), app('hashids.factory')));
- expect(static function () use ($sut, $hashId) {
+ expect(static function () use ($sut, $hashId): void {
$sut->decodeOrFail($hashId);
})->when(
is_null($expectation),
- fn (Expectation $ex) => $ex
+ fn (Expectation $ex): Expectation => $ex
->toThrow(InvalidArgumentException::class),
- )->unless(is_null($expectation), fn (Expectation $ex) => $ex
+ )->unless(is_null($expectation), fn (Expectation $ex): Expectation => $ex
->toBe($ex->value));
})->with([
- [fn () => hashids()->encodeOrFail(10), 10],
- [fn () => hashids()->encodeOrFail(10, 13, 2), [10, 13, 2]],
+ [fn (): string => hashids()->encodeOrFail(10), 10],
+ [fn (): string => hashids()->encodeOrFail(10, 13, 2), [10, 13, 2]],
['invalid', null],
]);
@@ -63,36 +65,36 @@
expect($result)->toBe([1, 2, 3]);
});
- it('can encode or null', function (array $numbers, string|null $expectation): void {
+ it('can encode or null', function (array $numbers, null|string $expectation): void {
$sut = new HashidsManagerDecorator(new HashidsManager(config(), app('hashids.factory')));
$result = $sut->encode(...$numbers);
expect($result)->toBe($expectation);
})->with([
- [[10], fn () => hashids()->encodeOrFail(10)],
- [['15'], fn () => hashids()->encodeOrFail(15)],
- [[10, 20], fn () => hashids()->encodeOrFail(10, 20)],
- [[10, '20'], fn () => hashids()->encodeOrFail(10, 20)],
+ [[10], fn (): string => hashids()->encodeOrFail(10)],
+ [['15'], fn (): string => hashids()->encodeOrFail(15)],
+ [[10, 20], fn (): string => hashids()->encodeOrFail(10, 20)],
+ [[10, '20'], fn (): string => hashids()->encodeOrFail(10, 20)],
[[], null],
]);
- it('can encode or throw', function (array $numbers, string|null $expectation): void {
+ it('can encode or throw', function (array $numbers, null|string $expectation): void {
$sut = new HashidsManagerDecorator(new HashidsManager(config(), app('hashids.factory')));
- expect(static function () use ($sut, $numbers) {
+ expect(static function () use ($sut, $numbers): void {
$sut->encodeOrFail(...$numbers);
})->when(
is_null($expectation),
- fn (Expectation $ex) => $ex
+ fn (Expectation $ex): Expectation => $ex
->toThrow(InvalidArgumentException::class),
)->when(
!is_null($expectation),
- fn (Expectation $ex) => $ex
+ fn (Expectation $ex): Expectation => $ex
->toBe($ex->value),
);
})->with([
- [[10], fn () => hashids()->encodeOrFail(10)],
+ [[10], fn (): string => hashids()->encodeOrFail(10)],
[[], null],
]);
@@ -105,7 +107,7 @@
it('prioritize macro methods if it exists when delegating method calls', function (): void {
$sut = new HashidsManagerDecorator(new HashidsManager(config(), app('hashids.factory')));
- HashidsManagerDecorator::macro('getDefaultConnection', fn () => 'something');
+ HashidsManagerDecorator::macro('getDefaultConnection', fn (): string => 'something');
expect($sut->getDefaultConnection())->toBe('something');
});
diff --git a/tests/Unit/Support/SanitizerTest.php b/tests/Unit/Support/SanitizerTest.php
index a98cbea8e..a12e70949 100644
--- a/tests/Unit/Support/SanitizerTest.php
+++ b/tests/Unit/Support/SanitizerTest.php
@@ -1,11 +1,14 @@
merge([
...$requestData,
'something' => 'that should be removed',
@@ -58,7 +61,7 @@
'dot notation with default value' => [
[],
['data.name' => 'Gandalf'],
- ['data' => ['name' => 'Gandalf']],
+ ['data' => ['name' => 'Gandalf']],
],
]);
})->covers(Sanitizer::class);
diff --git a/tests/UnitTestCase.php b/tests/UnitTestCase.php
index 126f50de5..b27cf7ec2 100644
--- a/tests/UnitTestCase.php
+++ b/tests/UnitTestCase.php
@@ -1,5 +1,7 @@
- */
+ /** @var class-string */
protected $model = User::class;
public function definition(): array
{
return [
- 'name' => $this->faker->name,
- 'email' => $this->faker->unique()->safeEmail,
- 'password' => $this->faker->password,
+ 'name' => fake()->name,
+ 'email' => fake()->unique()->safeEmail,
+ 'password' => fake()->password,
];
}
public function withParent(): static
{
- return $this->state(fn (array $attributes): array => [
+ return $this->state(static fn (array $attributes): array => [
'parent_id' => static::new()->createOne()->id,
]);
}
public function withChildren(int $count = 1): static
{
- return $this->afterCreating(function (User $user) use ($count): void {
+ return $this->afterCreating(static function (User $user) use ($count): void {
static::new()->count($count)->create([
'parent_id' => $user->id,
]);
diff --git a/workbench/app/Containers/Identity/User/Data/Migrations/0001_01_01_000000_testbench_create_users_table.php b/workbench/app/Containers/Identity/User/Data/Migrations/0001_01_01_000000_testbench_create_users_table.php
index 56a78a136..c15b74fba 100644
--- a/workbench/app/Containers/Identity/User/Data/Migrations/0001_01_01_000000_testbench_create_users_table.php
+++ b/workbench/app/Containers/Identity/User/Data/Migrations/0001_01_01_000000_testbench_create_users_table.php
@@ -1,10 +1,12 @@
'datetime',
- ];
-
public function parent(): BelongsTo
{
return $this->belongsTo(self::class, 'parent_id');
@@ -49,4 +47,11 @@ public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}
+
+ protected function casts(): array
+ {
+ return [
+ 'email_verified_at' => 'datetime',
+ ];
+ }
}
diff --git a/workbench/app/Containers/Identity/User/UI/API/Transformers/UserTransformer.php b/workbench/app/Containers/Identity/User/UI/API/Transformers/UserTransformer.php
index da624caed..fb2eb783d 100644
--- a/workbench/app/Containers/Identity/User/UI/API/Transformers/UserTransformer.php
+++ b/workbench/app/Containers/Identity/User/UI/API/Transformers/UserTransformer.php
@@ -1,5 +1,7 @@
$user->getResourceKey(),
- 'id' => $user->getHashedKey(),
- 'name' => $user->name,
- 'email' => $user->email,
+ 'type' => $user->getResourceKey(),
+ 'id' => $user->getHashedKey(),
+ 'name' => $user->name,
+ 'email' => $user->email,
'created_at' => $user->created_at,
'updated_at' => $user->updated_at,
];
@@ -51,6 +53,6 @@ public function includeBooks(User $user): Collection
public function includeComments(User $user): Collection
{
- return $this->collection($user->comments, fn (Comment $comment) => $comment->toArray());
+ return $this->collection($user->comments, static fn (Comment $comment) => $comment->toArray());
}
}
diff --git a/workbench/app/Containers/MySection/Author/Actions/SimpleAction.php b/workbench/app/Containers/MySection/Author/Actions/SimpleAction.php
index b366efdf7..1c21afefb 100644
--- a/workbench/app/Containers/MySection/Author/Actions/SimpleAction.php
+++ b/workbench/app/Containers/MySection/Author/Actions/SimpleAction.php
@@ -1,5 +1,7 @@
This is a fake mail view for testing purposes.
+ 'List all Authors');
diff --git a/workbench/app/Containers/MySection/Author/UI/WEB/Routes/ListAuthors.php b/workbench/app/Containers/MySection/Author/UI/WEB/Routes/ListAuthors.php
index 403486b53..fb1b4f033 100644
--- a/workbench/app/Containers/MySection/Author/UI/WEB/Routes/ListAuthors.php
+++ b/workbench/app/Containers/MySection/Author/UI/WEB/Routes/ListAuthors.php
@@ -1,5 +1,7 @@
'List all Authors');
diff --git a/workbench/app/Containers/MySection/Book/Actions/CreateBookAction.php b/workbench/app/Containers/MySection/Book/Actions/CreateBookAction.php
index 1515dad31..2d1b85ddc 100644
--- a/workbench/app/Containers/MySection/Book/Actions/CreateBookAction.php
+++ b/workbench/app/Containers/MySection/Book/Actions/CreateBookAction.php
@@ -1,5 +1,7 @@
- */
+ /** @var class-string */
protected $model = Book::class;
public function definition(): array
{
return [
- 'title' => fake()->sentence,
+ 'title' => fake()->sentence,
'author_id' => User::factory(),
];
}
diff --git a/workbench/app/Containers/MySection/Book/Data/Migrations/2024_12_29_144159_create_books_table.php b/workbench/app/Containers/MySection/Book/Data/Migrations/2024_12_29_144159_create_books_table.php
index bfba11516..7d5da9303 100644
--- a/workbench/app/Containers/MySection/Book/Data/Migrations/2024_12_29_144159_create_books_table.php
+++ b/workbench/app/Containers/MySection/Book/Data/Migrations/2024_12_29_144159_create_books_table.php
@@ -1,10 +1,12 @@
'forbidden',
];
diff --git a/workbench/app/Containers/MySection/Book/Languages/fa/errors.php b/workbench/app/Containers/MySection/Book/Languages/fa/errors.php
index 63bb48986..86ebe1d8b 100644
--- a/workbench/app/Containers/MySection/Book/Languages/fa/errors.php
+++ b/workbench/app/Containers/MySection/Book/Languages/fa/errors.php
@@ -1,5 +1,7 @@
'ممنوع',
];
diff --git a/workbench/app/Containers/MySection/Book/Listeners/BookCreatedListener.php b/workbench/app/Containers/MySection/Book/Listeners/BookCreatedListener.php
index 61656794c..7d7d180ac 100644
--- a/workbench/app/Containers/MySection/Book/Listeners/BookCreatedListener.php
+++ b/workbench/app/Containers/MySection/Book/Listeners/BookCreatedListener.php
@@ -1,5 +1,7 @@
afterResolving(Kernel::class, function (Kernel $kernel): void {
+ app()->afterResolving(Kernel::class, static function (Kernel $kernel): void {
$kernel->pushMiddleware(BeforeMiddleware::class);
});
}
diff --git a/workbench/app/Containers/MySection/Book/Providers/EventServiceProvider.php b/workbench/app/Containers/MySection/Book/Providers/EventServiceProvider.php
index 54a54e4aa..e62e8d8eb 100644
--- a/workbench/app/Containers/MySection/Book/Providers/EventServiceProvider.php
+++ b/workbench/app/Containers/MySection/Book/Providers/EventServiceProvider.php
@@ -1,5 +1,7 @@
[
- 'id' => $request->input('id'),
- 'id-default' => $request->input('id', 100),
- 'title' => $request->input('title'),
- 'hashed_id' => $request->input('hashed_id'),
- 'nested.id' => $request->input('nested.id'),
- 'nested.with-default' => $request->input('nested.with', 200),
- 'author_id' => $request->input('author_id'),
- 'authors' => $request->input('authors'),
- 'authors.*.id' => $request->input('authors.*.id'),
+ 'id' => $request->input('id'),
+ 'id-default' => $request->input('id', 100),
+ 'title' => $request->input('title'),
+ 'hashed_id' => $request->input('hashed_id'),
+ 'nested.id' => $request->input('nested.id'),
+ 'nested.with-default' => $request->input('nested.with', 200),
+ 'author_id' => $request->input('author_id'),
+ 'authors' => $request->input('authors'),
+ 'authors.*.id' => $request->input('authors.*.id'),
'authors.*.with-default' => $request->input('authors.*.with', 150),
- 'ids' => $request->input('ids'),
- 'with-default' => $request->input('with', [1, 2, 3]),
- 'none_existing' => $request->input('none_existing'),
- 'optional_id' => $request->input('optional_id'),
+ 'ids' => $request->input('ids'),
+ 'with-default' => $request->input('with', [1, 2, 3]),
+ 'none_existing' => $request->input('none_existing'),
+ 'optional_id' => $request->input('optional_id'),
],
'all(val)' => [
- 'id' => $request->all('id'),
- 'title' => $request->all('title'),
- 'nested.id' => $request->all('nested.id'),
- 'nested.ids' => $request->all('nested.ids'),
- 'author_id' => $request->all('author_id'),
+ 'id' => $request->all('id'),
+ 'title' => $request->all('title'),
+ 'nested.id' => $request->all('nested.id'),
+ 'nested.ids' => $request->all('nested.ids'),
+ 'author_id' => $request->all('author_id'),
'none_existing' => $request->all('none_existing'),
- 'optional_id' => $request->all('optional_id'),
+ 'optional_id' => $request->all('optional_id'),
],
'route(val)' => [
- 'id' => $request->route('id'),
+ 'id' => $request->route('id'),
'none_existing' => $request->route('none_existing'),
],
'request->val' => [
- 'id' => $request->id,
- 'title' => $request->title,
+ 'id' => $request->id,
+ 'title' => $request->title,
'none_existing' => $request->none_existing,
- 'optional_id' => $request->optional_id,
+ 'optional_id' => $request->optional_id,
],
- 'input()' => $request->input(),
- 'all()' => $request->all(),
- 'validated' => $request->validated(),
+ 'input()' => $request->input(),
+ 'all()' => $request->all(),
+ 'validated' => $request->validated(),
'route()::class' => $request->route()::class,
]);
}
diff --git a/workbench/app/Containers/MySection/Book/UI/API/Requests/CreateBookRequest.php b/workbench/app/Containers/MySection/Book/UI/API/Requests/CreateBookRequest.php
index 33cb358e0..f25f10942 100644
--- a/workbench/app/Containers/MySection/Book/UI/API/Requests/CreateBookRequest.php
+++ b/workbench/app/Containers/MySection/Book/UI/API/Requests/CreateBookRequest.php
@@ -1,5 +1,7 @@
'required',
- 'author_id' => 'required',
- 'ids.*' => ['required', Rule::when($hashIdEnabled, 'integer', 'string')],
+ 'title' => 'required',
+ 'author_id' => 'required',
+ 'ids.*' => ['required', Rule::when($hashIdEnabled, 'integer', 'string')],
'authors.*.id' => ['required', Rule::when($hashIdEnabled, 'integer', 'string')],
- 'nested.id' => ['required', Rule::when($hashIdEnabled, 'integer', 'string')],
- 'nested.ids' => 'array',
+ 'nested.id' => ['required', Rule::when($hashIdEnabled, 'integer', 'string')],
+ 'nested.ids' => 'array',
'nested.ids.*' => Rule::when($hashIdEnabled, 'integer', 'string'),
];
}
diff --git a/workbench/app/Containers/MySection/Book/UI/API/Routes/CreateBook.v1.private.php b/workbench/app/Containers/MySection/Book/UI/API/Routes/CreateBook.v1.private.php
index ac456e69d..c33e6ec1c 100644
--- a/workbench/app/Containers/MySection/Book/UI/API/Routes/CreateBook.v1.private.php
+++ b/workbench/app/Containers/MySection/Book/UI/API/Routes/CreateBook.v1.private.php
@@ -1,5 +1,7 @@
'Get All Books');
diff --git a/workbench/app/Containers/MySection/Book/UI/API/Routes/UpdateBook.v1.private.php b/workbench/app/Containers/MySection/Book/UI/API/Routes/UpdateBook.v1.private.php
index 9636e3a27..1291c20e4 100644
--- a/workbench/app/Containers/MySection/Book/UI/API/Routes/UpdateBook.v1.private.php
+++ b/workbench/app/Containers/MySection/Book/UI/API/Routes/UpdateBook.v1.private.php
@@ -1,5 +1,7 @@
$book->getResourceKey(),
- 'id' => $book->getHashedKey(),
- 'title' => $book->title,
- 'author' => $book->author?->name,
+ 'type' => $book->getResourceKey(),
+ 'id' => $book->getHashedKey(),
+ 'title' => $book->title,
+ 'author' => $book->author?->name,
'created_at' => $book->created_at,
'updated_at' => $book->updated_at,
];
diff --git a/workbench/app/Containers/MySection/Book/UI/CLI/Commands/ContainerTestCommand.php b/workbench/app/Containers/MySection/Book/UI/CLI/Commands/ContainerTestCommand.php
index 313d9dddb..c6b1aeb0c 100644
--- a/workbench/app/Containers/MySection/Book/UI/CLI/Commands/ContainerTestCommand.php
+++ b/workbench/app/Containers/MySection/Book/UI/CLI/Commands/ContainerTestCommand.php
@@ -1,5 +1,7 @@
'Get All Books');
diff --git a/workbench/app/Containers/MySection/Book/UI/WEB/Views/book-me.blade.php b/workbench/app/Containers/MySection/Book/UI/WEB/Views/book-me.blade.php
index bf6d11aa3..33fc011a6 100644
--- a/workbench/app/Containers/MySection/Book/UI/WEB/Views/book-me.blade.php
+++ b/workbench/app/Containers/MySection/Book/UI/WEB/Views/book-me.blade.php
@@ -1,3 +1,9 @@
+
This is a fake view
+ $this->faker->text,
+ 'content' => fake()->text,
];
}
}
diff --git a/workbench/app/Containers/SocialInteraction/Comment/Data/Migrations/2025_01_25_224724_create_comments_table.php b/workbench/app/Containers/SocialInteraction/Comment/Data/Migrations/2025_01_25_224724_create_comments_table.php
index 5de9121a6..cd0a4a577 100644
--- a/workbench/app/Containers/SocialInteraction/Comment/Data/Migrations/2025_01_25_224724_create_comments_table.php
+++ b/workbench/app/Containers/SocialInteraction/Comment/Data/Migrations/2025_01_25_224724_create_comments_table.php
@@ -1,10 +1,12 @@
Apiato\Http\Response::class,
+ 'fractal_class' => Response::class,
'auto_includes' => [
/*
diff --git a/workbench/app/Ship/Configs/repository.php b/workbench/app/Ship/Configs/repository.php
index 71fa24bdc..d2a7f016a 100644
--- a/workbench/app/Ship/Configs/repository.php
+++ b/workbench/app/Ship/Configs/repository.php
@@ -1,5 +1,9 @@
[
'include' => 'include',
],
- 'serializer' => League\Fractal\Serializer\DataArraySerializer::class,
+ 'serializer' => DataArraySerializer::class,
],
/*
@@ -137,7 +141,7 @@
| 'except' =>['find'],
*/
'allowed' => [
- 'only' => null,
+ 'only' => null,
'except' => null,
],
],
@@ -210,14 +214,14 @@
|
*/
'params' => [
- 'search' => 'search',
+ 'search' => 'search',
'searchFields' => 'searchFields',
// 'filter' => 'filter',
- 'orderBy' => 'orderBy',
+ 'orderBy' => 'orderBy',
'sortedBy' => 'sortedBy',
// 'with' => 'with',
'searchJoin' => 'searchJoin',
- 'withCount' => 'withCount',
+ 'withCount' => 'withCount',
],
],
/*
@@ -227,19 +231,19 @@
|
*/
'generator' => [
- 'basePath' => app()->path(),
- 'rootNamespace' => 'App\\',
+ 'basePath' => app()->path(),
+ 'rootNamespace' => 'App\\',
'stubsOverridePath' => app()->path(),
- 'paths' => [
- 'models' => 'Entities',
+ 'paths' => [
+ 'models' => 'Entities',
'repositories' => 'Repositories',
- 'interfaces' => 'Repositories',
+ 'interfaces' => 'Repositories',
'transformers' => 'Transformers',
- 'presenters' => 'Presenters',
- 'validators' => 'Validators',
- 'controllers' => 'Http/Controllers',
- 'provider' => 'RepositoryServiceProvider',
- 'criteria' => 'Criteria',
+ 'presenters' => 'Presenters',
+ 'validators' => 'Validators',
+ 'controllers' => 'Http/Controllers',
+ 'provider' => 'RepositoryServiceProvider',
+ 'criteria' => 'Criteria',
],
],
];
diff --git a/workbench/app/Ship/Exceptions/CreateResourceFailed.php b/workbench/app/Ship/Exceptions/CreateResourceFailed.php
index d57d4d890..f0d161061 100755
--- a/workbench/app/Ship/Exceptions/CreateResourceFailed.php
+++ b/workbench/app/Ship/Exceptions/CreateResourceFailed.php
@@ -1,5 +1,7 @@
'forbidden',
];
diff --git a/workbench/app/Ship/Languages/fa/errors.php b/workbench/app/Ship/Languages/fa/errors.php
index 63bb48986..86ebe1d8b 100644
--- a/workbench/app/Ship/Languages/fa/errors.php
+++ b/workbench/app/Ship/Languages/fa/errors.php
@@ -1,5 +1,7 @@
'ممنوع',
];
diff --git a/workbench/app/Ship/Mails/Templates/welcome-cheers.blade.php b/workbench/app/Ship/Mails/Templates/welcome-cheers.blade.php
index 1b6be34a7..0d320d246 100644
--- a/workbench/app/Ship/Mails/Templates/welcome-cheers.blade.php
+++ b/workbench/app/Ship/Mails/Templates/welcome-cheers.blade.php
@@ -1,3 +1,9 @@
+
This is a fake email view
+
This is a fake view
+webRoutes(),
then: static fn () => $apiato->registerApiRoutes(),
)
- ->withMiddleware(function (Middleware $middleware): void {
+ ->withMiddleware(static function (Middleware $middleware): void {
$middleware->api([
ValidateJsonContent::class,
ProcessETag::class,