diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index 1ff54ef..0000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-version: 2.1
-
-commands:
- setup:
- steps:
- - run:
- name: Configure environment
- command: |
- apk update
-
- - checkout
-
- - run:
- working_directory: app
- name: Install dependencies
- command: |
- EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
-
- if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
- >&2 echo 'ERROR: Invalid installer checksum'
- rm composer-setup.php
- exit 1
- fi
-
- php composer-setup.php --quiet
- RESULT=$?
- rm composer-setup.php
-
- php composer.phar install --no-interaction --prefer-dist
-
- setup-pcov:
- steps:
- - run:
- name: Configure pcov
- command: |
- apk add autoconf gcc make musl-dev
- pecl install pcov
- docker-php-ext-enable pcov
-
- run-phpinsights:
- steps:
- - run:
- working_directory: app
- name: Run code quality analysis (PHP Insights)
- command: php -d memory-limit=-1 ./vendor/bin/phpinsights -v --no-interaction --min-quality=100 --min-complexity=50 --min-architecture=100 --min-style=100
-
- run-phpstan:
- steps:
- - run:
- working_directory: app
- name: Run static code analysis (PHPStan)
- command: php -d memory_limit=-1 ./vendor/bin/phpstan analyse --ansi
-
- run-pest:
- steps:
- - run:
- working_directory: app
- name: Run unit tests (Pest)
- command: php -d memory_limit=-1 ./vendor/bin/pest --stop-on-failure
-
- run-snyk:
- steps:
- - run:
- working_directory: app
- name: Run vulnerabilities tests (Snyk)
- command: |
- apk add npm
- npm install -g snyk
- snyk test --dev
-
-jobs:
- phpinsights:
- parameters:
- php:
- type: string
- docker:
- - image: php:<< parameters.php >>-cli-alpine
- steps:
- - setup
- - run-phpinsights
-
- phpstan:
- parameters:
- php:
- type: string
- docker:
- - image: php:<< parameters.php >>-cli-alpine
- steps:
- - setup
- - run-phpstan
-
- pest:
- parameters:
- php:
- type: string
- docker:
- - image: php:<< parameters.php >>-cli-alpine
- steps:
- - setup
- - setup-pcov
- - run-pest
-
- snyk:
- parameters:
- php:
- type: string
- docker:
- - image: php:<< parameters.php >>-cli-alpine
- steps:
- - setup
- - run-snyk
-
- semgrep:
- docker:
- - image: returntocorp/semgrep-agent:v1
- environment:
- SEMGREP_REPO_NAME: "auth0-samples/auth0-php-api-samples"
- SEMGREP_REPO_URL: "https://github.com/auth0-samples/auth0-php-api-samples"
- steps:
- - checkout
- - run:
- name: Run vulnerabilities tests (Semgrep)
- command: |
- semgrep-agent --baseline-ref main --publish-token $SEMGREP_TOKEN
-
-workflows:
- test:
- jobs:
- - phpinsights:
- matrix:
- parameters:
- php: ["7.4", "8.0", "8.1"]
- - phpstan:
- matrix:
- parameters:
- php: ["7.4", "8.0", "8.1"]
- - semgrep:
- context:
- - semgrep-env
- - snyk:
- matrix:
- parameters:
- php: ["8.0", "8.1"]
- context:
- - snyk-env
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index a327b35..0000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-version: 2
-updates:
-
- - package-ecosystem: "composer"
- directory: "/app"
- schedule:
- interval: "daily"
- ignore:
- - dependency-name: "*"
- update-types: ["version-update:semver-major", "version-update:semver-patch"]
diff --git a/.github/stale.yml b/.github/stale.yml
deleted file mode 100644
index b2e13fc..0000000
--- a/.github/stale.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Configuration for probot-stale - https://github.com/probot/stale
-
-# Number of days of inactivity before an Issue or Pull Request becomes stale
-daysUntilStale: 90
-
-# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
-daysUntilClose: 7
-
-# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
-exemptLabels: []
-
-# Set to true to ignore issues with an assignee (defaults to false)
-exemptAssignees: true
-
-# Label to use when marking as stale
-staleLabel: closed:stale
-
-# Comment to post when marking as stale. Set to `false` to disable
-markComment: >
- This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇♂️
\ No newline at end of file
diff --git a/.github/workflows/php_composer.yml b/.github/workflows/php_composer.yml
new file mode 100644
index 0000000..34457b0
--- /dev/null
+++ b/.github/workflows/php_composer.yml
@@ -0,0 +1,36 @@
+name: "Composer"
+
+on:
+ pull_request:
+ merge_group:
+ push:
+ branches: ["master", "main"]
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ validate:
+ name: "Validate"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - run: composer validate
+
+ normalize:
+ name: "Normalize"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - run: composer require --dev ergebnis/composer-normalize
+
+ - run: composer config allow-plugins.ergebnis/composer-normalize true
+
+ - run: composer normalize
diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml
new file mode 100644
index 0000000..f649061
--- /dev/null
+++ b/.github/workflows/php_pest.yml
@@ -0,0 +1,35 @@
+name: "PEST"
+
+on:
+ pull_request:
+ merge_group:
+ push:
+ branches: ["master", "main"]
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ pest:
+ name: "Scan"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.1"
+ coverage: pcov
+
+ - run: composer install --no-progress
+
+ - run: vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --coverage --parallel
+
+ - uses: codecov/codecov-action@v3
+ with:
+ directory: ./coverage/
+ flags: unittests
diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml
new file mode 100644
index 0000000..7915405
--- /dev/null
+++ b/.github/workflows/php_phpcsf.yml
@@ -0,0 +1,29 @@
+name: "PHP CS Fixer"
+
+on:
+ pull_request:
+ merge_group:
+ push:
+ branches: ["master", "main"]
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ phpcsf:
+ name: "Scan"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.1"
+
+ - run: composer install --no-progress
+
+ - run: vendor/bin/php-cs-fixer fix src --dry-run --diff
diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml
new file mode 100644
index 0000000..f8bb2db
--- /dev/null
+++ b/.github/workflows/php_phpstan.yml
@@ -0,0 +1,29 @@
+name: "PHPStan"
+
+on:
+ pull_request:
+ merge_group:
+ push:
+ branches: ["master", "main"]
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ phpstan:
+ name: "Scan"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.1"
+
+ - run: composer install --no-progress
+
+ # - run: vendor/bin/phpstan analyze --no-ansi --no-progress --debug
diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml
new file mode 100644
index 0000000..3b2a1ba
--- /dev/null
+++ b/.github/workflows/php_psalm.yml
@@ -0,0 +1,29 @@
+name: "Psalm"
+
+on:
+ pull_request:
+ merge_group:
+ push:
+ branches: ["master", "main"]
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ psalm:
+ name: "Scan"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.1"
+
+ - run: composer install --no-progress
+
+ # - run: vendor/bin/psalm
diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml
new file mode 100644
index 0000000..5cf3821
--- /dev/null
+++ b/.github/workflows/php_rector.yml
@@ -0,0 +1,29 @@
+name: "Rector"
+
+on:
+ pull_request:
+ merge_group:
+ push:
+ branches: ["master", "main"]
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ rector:
+ name: "Scan"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.1"
+
+ - run: composer install --no-progress
+
+ - run: vendor/bin/rector process --dry-run
diff --git a/.github/workflows/repo_cron_snyk.yml b/.github/workflows/repo_cron_snyk.yml
new file mode 100644
index 0000000..8396351
--- /dev/null
+++ b/.github/workflows/repo_cron_snyk.yml
@@ -0,0 +1,36 @@
+name: "Snyk (Scheduled)"
+
+# This workflow will run after a push to the main branch and as a scheduled job.
+
+on:
+ push:
+ branches: ["master", "main"]
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ snyk:
+ name: "Scan"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.1"
+ coverage: none
+ extensions: mbstring
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - uses: actions/checkout@v3
+
+ - run: composer install --no-progress
+
+ - uses: snyk/actions/php@master
+ continue-on-error: true
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
diff --git a/.github/workflows/repo_pr_await_approval.yml b/.github/workflows/repo_pr_await_approval.yml
new file mode 100644
index 0000000..fed0fd1
--- /dev/null
+++ b/.github/workflows/repo_pr_await_approval.yml
@@ -0,0 +1,20 @@
+name: "Pull Request Approval"
+
+# Monitor for pull requests being approved.
+
+on:
+ pull_request:
+ types: [synchronize]
+ pull_request_review:
+ types: [submitted]
+
+permissions: {}
+
+jobs:
+ wait:
+ name: "Waiting"
+ runs-on: ubuntu-latest
+
+ if: github.actor == 'dependabot[bot]' || github.event.review.state == 'approved'
+ steps:
+ - run: echo "PR approved."
diff --git a/.github/workflows/repo_pr_await_changes.yml b/.github/workflows/repo_pr_await_changes.yml
new file mode 100644
index 0000000..37408b9
--- /dev/null
+++ b/.github/workflows/repo_pr_await_changes.yml
@@ -0,0 +1,17 @@
+name: "Pull Request Changes"
+
+# Monitor for changes to pull requests.
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions: {}
+
+jobs:
+ wait:
+ name: "Watching"
+ runs-on: ubuntu-latest
+
+ steps:
+ - run: echo "Changes detected."
diff --git a/.github/workflows/repo_pr_label_approval.yml b/.github/workflows/repo_pr_label_approval.yml
new file mode 100644
index 0000000..b8672ea
--- /dev/null
+++ b/.github/workflows/repo_pr_label_approval.yml
@@ -0,0 +1,29 @@
+name: "Pull Request Labels (Apply Approval)"
+
+# This workflow will run after a pull request has been approved, and is
+# triggered as a result of the "Pull Request Changes" workflow succeeding.
+# By being executed in this manner, the workflow will have access to the
+# environment variables of the origin repository, allowing builds to
+# successfully run for forked pull requests without exposing secrets.
+
+on:
+ workflow_run:
+ workflows: ["Pull Request Approval"]
+ types:
+ - completed
+
+permissions:
+ # We are modifying labels, and need write access to do so.
+ pull-requests: write
+
+jobs:
+ wait:
+ name: "Applying"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: actions-ecosystem/action-add-labels@v1
+ with:
+ labels: Approved
diff --git a/.github/workflows/repo_pr_label_approval_revoke.yml b/.github/workflows/repo_pr_label_approval_revoke.yml
new file mode 100644
index 0000000..0caca73
--- /dev/null
+++ b/.github/workflows/repo_pr_label_approval_revoke.yml
@@ -0,0 +1,31 @@
+name: "Pull Request Labels (Revoke Approval)"
+
+# This workflow will run after a pull request has been approved, and is
+# triggered as a result of the "Pull Request Changes" workflow succeeding.
+# By being executed in this manner, the workflow will have access to the
+# environment variables of the origin repository, allowing builds to
+# successfully run for forked pull requests without exposing secrets.
+
+on:
+ workflow_run:
+ workflows: ["Pull Request Changes"]
+ types:
+ - completed
+
+permissions:
+ # We are modifying labels, and need write access to do so.
+ pull-requests: write
+
+jobs:
+ wait:
+ name: "Revoking"
+ runs-on: ubuntu-latest
+
+ if: contains(github.event.issue.labels.*.name, 'Approved')
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: actions-ecosystem/action-remove-labels@v1
+ with:
+ labels: Approved
diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml
new file mode 100644
index 0000000..033e2bd
--- /dev/null
+++ b/.github/workflows/sec_snyk.yml
@@ -0,0 +1,44 @@
+name: "Snyk"
+
+# This workflow will run after a pull request has been approved, and is
+# triggered as a result of the "Pull Request Approval" workflow succeeding.
+# By being executed in this manner, the workflow will have access to the
+# environment variables of the origin repository, allowing builds to
+# successfully run for forked pull requests without exposing secrets.
+
+on:
+ workflow_run:
+ workflows: ["Pull Request Approval"]
+ types:
+ - completed
+
+permissions: {}
+
+defaults:
+ run:
+ working-directory: app
+
+jobs:
+ snyk:
+ name: "Scan"
+ runs-on: ubuntu-latest
+
+ if: github.event.workflow_run.conclusion == 'success' && contains(github.event.issue.labels.*.name, 'Approved')
+
+ steps:
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.1"
+ coverage: none
+ extensions: mbstring
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - uses: actions/checkout@v3
+
+ - run: composer install --no-progress
+
+ - uses: snyk/actions/php@master
+ continue-on-error: true
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 11d0ed3..7315fab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ vendor
.env
composer.lock
.DS_Store
+app/.php-cs-fixer.cache
diff --git a/app/.dockerignore b/app/.dockerignore
deleted file mode 100644
index 137a061..0000000
--- a/app/.dockerignore
+++ /dev/null
@@ -1,3 +0,0 @@
-vendor/
-.composer.lock
-.env.example
diff --git a/app/.php-cs-fixer.dist.php b/app/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..54f9af5
--- /dev/null
+++ b/app/.php-cs-fixer.dist.php
@@ -0,0 +1,231 @@
+setRiskyAllowed(true)
+ ->setRules([
+ 'array_indentation' => true,
+ 'array_push' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'assign_null_coalescing_to_coalesce_equal' => true,
+ 'backtick_to_shell_exec' => true,
+ 'binary_operator_spaces' => true,
+ 'blank_line_after_namespace' => true,
+ 'blank_line_after_opening_tag' => true,
+ 'blank_line_before_statement' => true,
+ 'blank_line_between_import_groups' => true,
+ 'braces' => true,
+ 'cast_spaces' => true,
+ 'class_attributes_separation' => ['elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'one', 'case' => 'one']],
+ 'class_definition' => ['multi_line_extends_each_single_line' => true, 'single_line' => true, 'single_item_single_line' => true, 'space_before_parenthesis' => false, 'inline_constructor_arguments' => false],
+ 'class_reference_name_casing' => true,
+ 'clean_namespace' => true,
+ 'combine_consecutive_issets' => true,
+ 'combine_consecutive_unsets' => true,
+ 'combine_nested_dirname' => true,
+ 'comment_to_phpdoc' => ['ignored_tags' => ['codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'phpstan-ignore-next-line']],
+ 'compact_nullable_typehint' => true,
+ 'concat_space' => ['spacing' => 'one'],
+ 'constant_case' => ['case' => 'lower'],
+ 'curly_braces_position' => ['control_structures_opening_brace' => 'same_line', 'functions_opening_brace' => 'next_line_unless_newline_at_signature_end', 'anonymous_functions_opening_brace' => 'same_line', 'classes_opening_brace' => 'next_line_unless_newline_at_signature_end', 'anonymous_classes_opening_brace' => 'same_line', 'allow_single_line_empty_anonymous_classes' => true, 'allow_single_line_anonymous_functions' => true],
+ 'date_time_create_from_format_call' => true,
+ 'date_time_immutable' => true,
+ 'declare_equal_normalize' => ['space' => 'none'],
+ 'declare_parentheses' => true,
+ 'declare_strict_types' => true,
+ 'dir_constant' => true,
+ 'doctrine_annotation_array_assignment' => true,
+ 'doctrine_annotation_braces' => true,
+ 'doctrine_annotation_indentation' => true,
+ 'doctrine_annotation_spaces' => true,
+ 'echo_tag_syntax' => ['format' => 'long'],
+ 'elseif' => true,
+ 'empty_loop_body' => true,
+ 'empty_loop_condition' => true,
+ 'encoding' => true,
+ 'ereg_to_preg' => true,
+ 'error_suppression' => true,
+ 'escape_implicit_backslashes' => true,
+ 'explicit_indirect_variable' => true,
+ 'explicit_string_variable' => true,
+ 'final_class' => true,
+ 'final_internal_class' => true,
+ 'final_public_method_for_abstract_class' => true,
+ 'fopen_flag_order' => true,
+ 'fopen_flags' => true,
+ 'full_opening_tag' => true,
+ 'fully_qualified_strict_types' => true,
+ 'function_declaration' => true,
+ 'function_to_constant' => true,
+ 'function_typehint_space' => true,
+ 'general_phpdoc_annotation_remove' => true,
+ 'general_phpdoc_tag_rename' => true,
+ 'get_class_to_class_keyword' => true,
+ 'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
+ 'group_import' => true,
+ 'heredoc_indentation' => true,
+ 'heredoc_to_nowdoc' => true,
+ 'implode_call' => true,
+ 'include' => true,
+ 'increment_style' => ['style' => 'pre'],
+ 'indentation_type' => true,
+ 'integer_literal_case' => true,
+ 'is_null' => true,
+ 'lambda_not_used_import' => true,
+ 'line_ending' => true,
+ 'linebreak_after_opening_tag' => true,
+ 'list_syntax' => ['syntax' => 'short'],
+ 'logical_operators' => true,
+ 'lowercase_cast' => true,
+ 'lowercase_keywords' => true,
+ 'lowercase_static_reference' => true,
+ 'magic_constant_casing' => true,
+ 'magic_method_casing' => true,
+ 'mb_str_functions' => false,
+ 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline', 'after_heredoc' => true],
+ 'method_chaining_indentation' => true,
+ 'modernize_strpos' => true,
+ 'modernize_types_casting' => true,
+ 'multiline_comment_opening_closing' => true,
+ 'multiline_whitespace_before_semicolons' => true,
+ 'native_function_casing' => true,
+ 'native_function_invocation' => true,
+ 'native_function_type_declaration_casing' => true,
+ 'new_with_braces' => true,
+ 'no_alias_functions' => true,
+ 'no_alias_language_construct_call' => true,
+ 'no_alternative_syntax' => true,
+ 'no_binary_string' => true,
+ 'no_blank_lines_after_class_opening' => true,
+ 'no_blank_lines_after_phpdoc' => true,
+ 'no_break_comment' => true,
+ 'no_closing_tag' => true,
+ 'no_empty_comment' => true,
+ 'no_empty_phpdoc' => true,
+ 'no_empty_statement' => true,
+ 'no_extra_blank_lines' => true,
+ 'no_homoglyph_names' => true,
+ 'no_leading_import_slash' => true,
+ 'no_leading_namespace_whitespace' => true,
+ 'no_mixed_echo_print' => true,
+ 'no_multiline_whitespace_around_double_arrow' => true,
+ 'no_multiple_statements_per_line' => true,
+ 'no_php4_constructor' => true,
+ 'no_short_bool_cast' => true,
+ 'no_singleline_whitespace_before_semicolons' => true,
+ 'no_space_around_double_colon' => true,
+ 'no_spaces_after_function_name' => true,
+ 'no_spaces_around_offset' => true,
+ 'no_spaces_inside_parenthesis' => true,
+ 'no_superfluous_elseif' => true,
+ 'no_trailing_comma_in_singleline' => true,
+ 'no_trailing_whitespace_in_comment' => true,
+ 'no_trailing_whitespace_in_string' => true,
+ 'no_trailing_whitespace' => true,
+ 'no_unneeded_control_parentheses' => true,
+ 'no_unneeded_curly_braces' => true,
+ 'no_unneeded_final_method' => true,
+ 'no_unneeded_import_alias' => true,
+ 'no_unreachable_default_argument_value' => true,
+ 'no_unset_cast' => true,
+ 'no_unused_imports' => true,
+ 'no_useless_concat_operator' => true,
+ 'no_useless_else' => true,
+ 'no_useless_nullsafe_operator' => true,
+ 'no_useless_return' => true,
+ 'no_useless_sprintf' => true,
+ 'no_whitespace_before_comma_in_array' => true,
+ 'no_whitespace_in_blank_line' => true,
+ 'non_printable_character' => true,
+ 'normalize_index_brace' => true,
+ 'not_operator_with_successor_space' => true,
+ 'nullable_type_declaration_for_default_null_value' => true,
+ 'object_operator_without_whitespace' => true,
+ 'octal_notation' => true,
+ 'operator_linebreak' => true,
+ 'ordered_class_elements' => ['sort_algorithm' => 'alpha', 'order' => ['use_trait', 'case', 'constant', 'constant_private', 'constant_protected', 'constant_public', 'property_private', 'property_private_readonly', 'property_private_static', 'property_protected', 'property_protected_readonly', 'property_protected_static', 'property_public', 'property_public_readonly', 'property_public_static', 'property_static', 'protected', 'construct', 'destruct', 'magic', 'method', 'public', 'method_public', 'method_abstract', 'method_public_abstract', 'method_public_abstract_static', 'method_public_static', 'method_static', 'method_private', 'method_private_abstract', 'method_private_abstract_static', 'method_private_static', 'method_protected', 'method_protected_abstract', 'method_protected_abstract_static', 'method_protected_static', 'phpunit', 'private', 'property']],
+ 'ordered_imports' => ['sort_algorithm' => 'alpha', 'imports_order' => ['const', 'class', 'function']],
+ 'ordered_interfaces' => true,
+ 'ordered_traits' => true,
+ 'php_unit_fqcn_annotation' => true,
+ 'phpdoc_add_missing_param_annotation' => ['only_untyped' => false],
+ 'phpdoc_align' => ['align' => 'vertical'],
+ 'phpdoc_indent' => true,
+ 'phpdoc_inline_tag_normalizer' => true,
+ 'phpdoc_line_span' => true,
+ 'phpdoc_no_access' => true,
+ 'phpdoc_no_empty_return' => true,
+ 'phpdoc_no_package' => true,
+ 'phpdoc_no_useless_inheritdoc' => true,
+ 'phpdoc_order_by_value' => true,
+ 'phpdoc_order' => true,
+ 'phpdoc_return_self_reference' => ['replacements' => ['this' => 'self']],
+ 'phpdoc_scalar' => true,
+ 'phpdoc_separation' => true,
+ 'phpdoc_single_line_var_spacing' => true,
+ 'phpdoc_summary' => true,
+ 'phpdoc_tag_type' => true,
+ 'phpdoc_to_comment' => ['ignored_tags' => ['var']],
+ 'phpdoc_trim_consecutive_blank_line_separation' => true,
+ 'phpdoc_trim' => true,
+ 'phpdoc_types_order' => true,
+ 'phpdoc_types' => true,
+ 'phpdoc_var_annotation_correct_order' => true,
+ 'phpdoc_var_without_name' => true,
+ 'pow_to_exponentiation' => true,
+ 'protected_to_private' => true,
+ 'psr_autoloading' => true,
+ 'random_api_migration' => true,
+ 'regular_callable_call' => true,
+ 'return_assignment' => true,
+ 'return_type_declaration' => ['space_before' => 'none'],
+ 'return_type_declaration' => true,
+ 'self_accessor' => true,
+ 'self_static_accessor' => true,
+ 'semicolon_after_instruction' => true,
+ 'set_type_to_cast' => true,
+ 'short_scalar_cast' => true,
+ 'simple_to_complex_string_variable' => true,
+ 'simplified_if_return' => true,
+ 'single_blank_line_at_eof' => true,
+ 'single_blank_line_before_namespace' => true,
+ 'single_class_element_per_statement' => true,
+ 'single_line_after_imports' => true,
+ 'single_line_comment_spacing' => true,
+ 'single_line_comment_style' => ['comment_types' => ['hash']],
+ 'single_line_throw' => true,
+ 'single_quote' => true,
+ 'single_space_after_construct' => true,
+ 'single_space_around_construct' => true,
+ 'single_trait_insert_per_statement' => true,
+ 'space_after_semicolon' => true,
+ 'standardize_increment' => true,
+ 'standardize_not_equals' => true,
+ 'statement_indentation' => true,
+ 'static_lambda' => true,
+ 'strict_comparison' => true,
+ 'strict_param' => true,
+ 'string_length_to_empty' => true,
+ 'string_line_ending' => true,
+ 'switch_case_semicolon_to_colon' => true,
+ 'switch_case_space' => true,
+ 'switch_continue_to_break' => true,
+ 'ternary_operator_spaces' => true,
+ 'ternary_to_elvis_operator' => true,
+ 'ternary_to_null_coalescing' => true,
+ 'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'match', 'parameters']],
+ 'trim_array_spaces' => true,
+ 'types_spaces' => ['space' => 'single', 'space_multiple_catch' => 'single'],
+ 'unary_operator_spaces' => true,
+ 'use_arrow_functions' => true,
+ 'visibility_required' => true,
+ 'void_return' => true,
+ 'whitespace_after_comma_in_array' => true,
+ 'yoda_style' => true,
+ ])
+ ->setFinder(
+ PhpCsFixer\Finder::create()
+ ->exclude('vendor')
+ ->in([__DIR__ . '/src/']),
+ );
diff --git a/app/.phpcs.xml.dist b/app/.phpcs.xml.dist
new file mode 100644
index 0000000..993f321
--- /dev/null
+++ b/app/.phpcs.xml.dist
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/composer.json b/app/composer.json
index 64923c0..d2cbeb8 100644
--- a/app/composer.json
+++ b/app/composer.json
@@ -2,46 +2,62 @@
"name": "auth0-samples/auth0-php-web-app",
"description": "Auth0 Integration Samples for PHP Web Applications.",
"require": {
- "php": "^7.4 | ^8.0",
+ "php": "^8.0",
"auth0/auth0-php": "^8.0",
"guzzlehttp/guzzle": "^7.3",
"guzzlehttp/psr7": "^2.2",
"http-interop/http-factory-guzzle": "^1.0",
+ "hyperf/event": "^2.1",
"php-http/httplug": "^2.2",
"vlucas/phpdotenv": "^5.3"
},
"require-dev": {
- "nunomaduro/phpinsights": "^2.0",
- "phpstan/phpstan": "^0.12",
- "phpstan/phpstan-strict-rules": "^0.12"
+ "friendsofphp/php-cs-fixer": "^3",
+ "mockery/mockery": "^1",
+ "nunomaduro/larastan": "^2",
+ "orchestra/testbench": "^7 || ^8",
+ "pestphp/pest": "^2",
+ "pestphp/pest-plugin-laravel": "^2",
+ "phpstan/phpstan": "^1",
+ "phpstan/phpstan-strict-rules": "^1",
+ "psalm/plugin-laravel": "^2",
+ "rector/rector": "0.17.0",
+ "spatie/laravel-ray": "^1",
+ "squizlabs/php_codesniffer": "^3",
+ "symfony/cache": "^6",
+ "vimeo/psalm": "^5",
+ "wikimedia/composer-merge-plugin": "^2"
},
"config": {
"optimize-autoloader": true,
"sort-packages": true,
"allow-plugins": {
- "dealerdirect/phpcodesniffer-composer-installer": true
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "friendsofphp/well-known-implementations": false,
+ "wikimedia/composer-merge-plugin": true,
+ "php-http/discovery": false,
+ "pestphp/pest-plugin": true
}
},
"scripts": {
- "app": [
+ "pest:coverage": "@php vendor/bin/pest --coverage --parallel --no-progress",
+ "pest:debug": "@php vendor/bin/pest --fail-on-risky --stop-on-defect",
+ "pest:profile": "@php vendor/bin/pest --profile",
+ "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --coverage --parallel",
+ "phpcs:fix": "@php vendor/bin/php-cs-fixer fix",
+ "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff",
+ "phpstan": "@php vendor/bin/phpstan analyze",
+ "psalm:fix": "@php vendor/bin/psalter --issues=all",
+ "psalm": "@php vendor/bin/psalm",
+ "rector:fix": "@php vendor/bin/rector process src",
+ "rector": "@php vendor/bin/rector process src --dry-run",
+ "test": [
"Composer\\Config::disableProcessTimeout",
- "@pre-run-app",
- "composer install --no-dev",
- "php -S 127.0.0.1:3000 public/index.php"
- ],
- "docker": [
- "Composer\\Config::disableProcessTimeout",
- "@pre-run-app",
- "docker-compose run install",
- "docker-compose run --rm --service-ports quickstart"
- ],
- "tests": [
- "Composer\\Config::disableProcessTimeout",
- "@pre-run-app",
- "docker-compose run --rm tests"
- ],
- "pre-run-app": [
- "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
+ "@pest",
+ "@phpstan",
+ "@psalm",
+ "@rector",
+ "@phpcs"
]
},
"license": "MIT"
diff --git a/app/docker-compose.yml b/app/docker-compose.yml
deleted file mode 100644
index 48fc7ce..0000000
--- a/app/docker-compose.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-version: "3.9"
-
-services:
- quickstart:
- image: php:7.4-cli-alpine
- volumes:
- - ./:/app
- working_dir: /app
- entrypoint: ["php", "-S", "0.0.0.0:3000", "public/index.php"]
- ports:
- - "3000:3000"
- env_file: .env
-
- tests:
- image: composer:2.1
- volumes:
- - ./:/app
- working_dir: /app
- command: >
- sh -c "rm -f ./composer.lock &&
- composer validate &&
- composer install &&
- php ./vendor/bin/phpinsights -v --no-interaction &&
- php ./vendor/bin/phpstan analyse --ansi --memory-limit 512M
-
- install:
- image: composer:2.1
- volumes:
- - ./:/app
- working_dir: /app
- command: >
- sh -c "rm -f ./composer.lock &&
- composer install --no-dev"
diff --git a/app/phpinsights.php b/app/phpinsights.php
deleted file mode 100644
index d18426b..0000000
--- a/app/phpinsights.php
+++ /dev/null
@@ -1,67 +0,0 @@
- 'default',
- 'ide' => null,
-
- 'exclude' => [
- 'public/bootstrap.php',
- 'templates',
- ],
-
- 'add' => [
- \NunoMaduro\PhpInsights\Domain\Metrics\Code\Comments::class => [
- \SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class,
- ],
- ],
-
- 'remove' => [
- \NunoMaduro\PhpInsights\Domain\Insights\CyclomaticComplexityIsHigh::class,
- \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenGlobals::class,
- \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenNormalClasses::class,
- \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenTraits::class,
- \NunoMaduro\PhpInsights\Domain\Sniffs\ForbiddenSetterSniff::class,
- \ObjectCalisthenics\Sniffs\Files\ClassTraitAndInterfaceLengthSniff::class,
- \ObjectCalisthenics\Sniffs\Files\FunctionLengthSniff::class,
- \ObjectCalisthenics\Sniffs\Metrics\MethodPerClassLimitSniff::class,
- \ObjectCalisthenics\Sniffs\Metrics\MaxNestingLevelSniff::class,
- \PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff::class,
- \PHP_CodeSniffer\Standards\Generic\Sniffs\Commenting\TodoSniff::class,
- \SlevomatCodingStandard\Sniffs\Classes\SuperfluousExceptionNamingSniff::class,
- \SlevomatCodingStandard\Sniffs\Classes\SuperfluousInterfaceNamingSniff::class,
- \SlevomatCodingStandard\Sniffs\Classes\UnusedPrivateElementsSniff::class,
- \SlevomatCodingStandard\Sniffs\Functions\FunctionLengthSniff::class,
- \SlevomatCodingStandard\Sniffs\TypeHints\DisallowMixedTypeHintSniff::class,
- \SlevomatCodingStandard\Sniffs\TypeHints\ParameterTypeHintSniff::class,
- \SlevomatCodingStandard\Sniffs\TypeHints\PropertyTypeHintSniff::class,
- \SlevomatCodingStandard\Sniffs\TypeHints\ReturnTypeHintSniff::class,
- ],
-
- 'config' => [
- \PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\DeprecatedFunctionsSniff::class => [
- 'exclude' => [
- ],
- ],
- \SlevomatCodingStandard\Sniffs\Functions\UnusedParameterSniff::class => [
- 'exclude' => [
- ],
- ],
- \SlevomatCodingStandard\Sniffs\Classes\ModernClassNameReferenceSniff::class => [
- 'exclude' => [
- ],
- ],
- \SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class => [
- 'minLineLength' => '0',
- ],
- ],
-
- 'requirements' => [
- 'min-quality' => 90,
- 'min-complexity' => 50,
- 'min-architecture' => 90,
- 'min-style' => 90,
- 'disable-security-check' => false,
- ],
-];
diff --git a/app/phpstan.neon.dist b/app/phpstan.neon.dist
index 690472e..d62703b 100644
--- a/app/phpstan.neon.dist
+++ b/app/phpstan.neon.dist
@@ -1,5 +1,6 @@
includes:
- - vendor/phpstan/phpstan-strict-rules/rules.neon
+ - ./vendor/phpstan/phpstan-strict-rules/rules.neon
+ - ./vendor/nunomaduro/larastan/extension.neon
parameters:
level: max
@@ -7,25 +8,10 @@ parameters:
paths:
- src
- bootstrapFiles:
- - public/bootstrap.php
-
ignoreErrors:
- - "#Function (app|auth|event|redirect) not found.#"
- - "#Constructor in (.*) has parameter (.*) with default value.#"
- - "#Constructor in (.*) has parameter (.*) with null as default value.#"
- - "#Method (.*) has parameter (.*) with a nullable type declaration.#"
- - "#Method (.*) has parameter (.*) with null as default value.#"
- - "#Method (.*) has a nullable return type declaration.#"
- - '#Language construct isset\(\) should not be used.#'
- - "#Method (.*) has parameter (.*) with no value type specified in iterable type array.#"
- - "#not allowed to extend#"
- - "#Cannot call method (.*) on mixed#"
- - "#no value type specified in iterable type array.#"
- - "#is not final, but since the containing class is abstract, it should be.#"
- - '#Class "Auth0\\Login\\Exception\\(.*)" is not allowed to extend "Exception".#'
- - '#Class "Auth0\\Laravel\\Exception\\(.*)" is not allowed to extend "Exception".#'
- - '#Call to an undefined method Illuminate\\(.*).#'
- - '#\$hash is never read, only written.#'
+ - '#Method (.*) has parameter (.*) with no value type specified in iterable type array.#'
+ - '#no value type specified in iterable type array.#'
reportUnmatchedIgnoredErrors: false
+ treatPhpDocTypesAsCertain: false
+ checkGenericClassInNonGenericObjectType: false
diff --git a/app/phpunit.xml b/app/phpunit.xml
new file mode 100644
index 0000000..e57bdd1
--- /dev/null
+++ b/app/phpunit.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ ./tests
+
+
+
+
+ ./src
+
+
+
diff --git a/app/psalm.xml.dist b/app/psalm.xml.dist
new file mode 100644
index 0000000..e8a12b6
--- /dev/null
+++ b/app/psalm.xml.dist
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/rector.php b/app/rector.php
new file mode 100644
index 0000000..0581861
--- /dev/null
+++ b/app/rector.php
@@ -0,0 +1,517 @@
+paths([
+ __DIR__ . '/config',
+ __DIR__ . '/src',
+ ]);
+
+ $rectorConfig->ruleWithConfiguration(
+ RenameFunctionRector::class,
+ [
+ 'chop' => 'rtrim',
+ 'doubleval' => 'floatval',
+ 'fputs' => 'fwrite',
+ 'gzputs' => 'gzwrites',
+ 'ini_alter' => 'ini_set',
+ 'is_double' => 'is_float',
+ 'is_integer' => 'is_int',
+ 'is_long' => 'is_int',
+ 'is_real' => 'is_float',
+ 'is_writeable' => 'is_writable',
+ 'join' => 'implode',
+ 'key_exists' => 'array_key_exists',
+ 'mbstrcut' => 'mb_strcut',
+ 'mbstrlen' => 'mb_strlen',
+ 'mbstrpos' => 'mb_strpos',
+ 'mbstrrpos' => 'mb_strrpos',
+ 'mbsubstr' => 'mb_substr',
+ 'pos' => 'current',
+ 'sizeof' => 'count',
+ 'split' => 'explode',
+ 'strchr' => 'strstr',
+ ],
+ );
+
+ $rectorConfig->ruleWithConfiguration(
+ StaticCallToFuncCallRector::class,
+ [
+ new StaticCallToFuncCall('Nette\\Utils\\Strings', 'contains', 'str_contains'),
+ new StaticCallToFuncCall('Nette\\Utils\\Strings', 'endsWith', 'str_ends_with'),
+ new StaticCallToFuncCall('Nette\\Utils\\Strings', 'startsWith', 'str_starts_with'),
+ ],
+ );
+
+ $rectorConfig->ruleWithConfiguration(
+ ArgumentAdderRector::class,
+ [new ArgumentAdder('Nette\\Utils\\Strings', 'replace', 2, 'replacement', '')],
+ );
+
+ $rectorConfig->ruleWithConfiguration(
+ RenameFunctionRector::class,
+ [
+ 'pg_clientencoding' => 'pg_client_encoding',
+ 'pg_cmdtuples' => 'pg_affected_rows',
+ 'pg_errormessage' => 'pg_last_error',
+ 'pg_fieldisnull' => 'pg_field_is_null',
+ 'pg_fieldname' => 'pg_field_name',
+ 'pg_fieldnum' => 'pg_field_num',
+ 'pg_fieldprtlen' => 'pg_field_prtlen',
+ 'pg_fieldsize' => 'pg_field_size',
+ 'pg_fieldtype' => 'pg_field_type',
+ 'pg_freeresult' => 'pg_free_result',
+ 'pg_getlastoid' => 'pg_last_oid',
+ 'pg_loclose' => 'pg_lo_close',
+ 'pg_locreate' => 'pg_lo_create',
+ 'pg_loexport' => 'pg_lo_export',
+ 'pg_loimport' => 'pg_lo_import',
+ 'pg_loopen' => 'pg_lo_open',
+ 'pg_loread' => 'pg_lo_read',
+ 'pg_loreadall' => 'pg_lo_read_all',
+ 'pg_lounlink' => 'pg_lo_unlink',
+ 'pg_lowrite' => 'pg_lo_write',
+ 'pg_numfields' => 'pg_num_fields',
+ 'pg_numrows' => 'pg_num_rows',
+ 'pg_result' => 'pg_fetch_result',
+ 'pg_setclientencoding' => 'pg_set_client_encoding',
+ ],
+ );
+
+ $rectorConfig->ruleWithConfiguration(
+ FunctionArgumentDefaultValueReplacerRector::class,
+ [
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, '', '!='),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, '!', '!='),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'g', 'gt'),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'l', 'lt'),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'),
+ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'n', 'ne'),
+ ],
+ );
+
+ $rectorConfig->ruleWithConfiguration(
+ FuncCallToConstFetchRector::class,
+ [
+ 'php_sapi_name' => 'PHP_SAPI',
+ 'pi' => 'M_PI',
+ ],
+ );
+
+ $rectorConfig->rules([
+ AbsolutizeRequireAndIncludePathRector::class,
+ ActionInjectionToConstructorInjectionRector::class,
+ AddArrayDefaultToArrayPropertyRector::class,
+ AddArrowFunctionReturnTypeRector::class,
+ AddClosureReturnTypeRector::class,
+ AddMethodCallBasedStrictParamTypeRector::class,
+ AddParamBasedOnParentClassMethodRector::class,
+ AddParamTypeBasedOnPHPUnitDataProviderRector::class,
+ AddParamTypeSplFixedArrayRector::class,
+ AddReturnTypeDeclarationBasedOnParentClassMethodRector::class,
+ AddReturnTypeDeclarationFromYieldsRector::class,
+ AddVoidReturnTypeWhereNoReturnRector::class,
+ AndAssignsToSeparateLinesRector::class,
+ ArrayKeyExistsTernaryThenValueToCoalescingRector::class,
+ ArrayKeysAndInArrayToArrayKeyExistsRector::class,
+ ArrayMergeOfNonArraysToSimpleArrayRector::class,
+ ArrayShapeFromConstantArrayReturnRector::class,
+ BinarySwitchToIfElseRector::class,
+ BooleanNotIdenticalToNotIdenticalRector::class,
+ BoolvalToTypeCastRector::class,
+ CallableThisArrayToAnonymousFunctionRector::class,
+ CallUserFuncArrayToVariadicRector::class,
+ CallUserFuncToMethodCallRector::class,
+ CallUserFuncToMethodCallRector::class,
+ CallUserFuncWithArrowFunctionToInlineRector::class,
+ CatchExceptionNameMatchingTypeRector::class,
+ ChangeArrayPushToArrayAssignRector::class,
+ ChangeGlobalVariablesToPropertiesRector::class,
+ ChangeIfElseValueAssignToEarlyReturnRector::class,
+ ChangeNestedForeachIfsToEarlyContinueRector::class,
+ ChangeNestedIfsToEarlyReturnRector::class,
+ ChangeOrIfContinueToMultiContinueRector::class,
+ ChangeSwitchToMatchRector::class,
+ ClassOnObjectRector::class,
+ ClassOnThisVariableObjectRector::class,
+ ClassPropertyAssignToConstructorPromotionRector::class,
+ CombinedAssignRector::class,
+ CombineIfRector::class,
+ CommonNotEqualRector::class,
+ CompactToVariablesRector::class,
+ CompleteDynamicPropertiesRector::class,
+ ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class,
+ ConsistentImplodeRector::class,
+ CountArrayToEmptyArrayComparisonRector::class,
+ CountArrayToEmptyArrayComparisonRector::class,
+ EmptyOnNullableObjectToInstanceOfRector::class,
+ EncapsedStringsToSprintfRector::class,
+ ExplicitBoolCompareRector::class,
+ FinalizeClassesWithoutChildrenRector::class,
+ FinalPrivateToPrivateVisibilityRector::class,
+ FlipTypeControlToUseExclusiveTypeRector::class,
+ FloatvalToTypeCastRector::class,
+ ForeachItemsAssignToEmptyArrayToAssignRector::class,
+ ForeachToInArrayRector::class,
+ ForRepeatedCountToOwnVariableRector::class,
+ FuncGetArgsToVariadicParamRector::class,
+ FuncGetArgsToVariadicParamRector::class,
+ GetClassToInstanceOfRector::class,
+ GetDebugTypeRector::class,
+ InlineArrayReturnAssignRector::class,
+ InlineConstructorDefaultToPropertyRector::class,
+ InlineIfToExplicitIfRector::class,
+ InlineIsAInstanceOfRector::class,
+ IntvalToTypeCastRector::class,
+ IsAWithStringWithThirdArgumentRector::class,
+ IssetOnPropertyObjectToPropertyExistsRector::class,
+ JoinStringConcatRector::class,
+ LogicalToBooleanRector::class,
+ MakeInheritedMethodVisibilitySameAsParentRector::class,
+ MultipleClassFileToPsr4ClassesRector::class,
+ NewlineBeforeNewAssignSetRector::class,
+ NewStaticToNewSelfRector::class,
+ NormalizeNamespaceByPSR4ComposerAutoloadRector::class,
+ NullableCompareToNullRector::class,
+ OptionalParametersAfterRequiredRector::class,
+ OptionalParametersAfterRequiredRector::class,
+ ParamTypeByMethodCallTypeRector::class,
+ ParamTypeByParentCallTypeRector::class,
+ ParamTypeFromStrictTypedPropertyRector::class,
+ Php8ResourceReturnToObjectRector::class,
+ PostIncDecToPreIncDecRector::class,
+ PreparedValueToEarlyReturnRector::class,
+ PrivatizeFinalClassMethodRector::class,
+ PrivatizeFinalClassPropertyRector::class,
+ PropertyTypeFromStrictSetterGetterRector::class,
+ RemoveAlwaysElseRector::class,
+ RemoveAlwaysTrueConditionSetInConstructorRector::class,
+ RemoveAndTrueRector::class,
+ RemoveDeadConditionAboveReturnRector::class,
+ RemoveDeadContinueRector::class,
+ RemoveDeadIfForeachForRector::class,
+ RemoveDeadLoopRector::class,
+ RemoveDeadReturnRector::class,
+ RemoveDeadStmtRector::class,
+ RemoveDeadTryCatchRector::class,
+ RemoveDeadZeroAndOneOperationRector::class,
+ RemoveDelegatingParentCallRector::class,
+ RemoveDoubleAssignRector::class,
+ RemoveDuplicatedArrayKeyRector::class,
+ RemoveDuplicatedCaseInSwitchRector::class,
+ RemoveEmptyClassMethodRector::class,
+ RemoveEmptyTestMethodRector::class,
+ RemoveExtraParametersRector::class,
+ RemoveFinalFromConstRector::class,
+ RemoveJustPropertyFetchForAssignRector::class,
+ RemoveJustVariableAssignRector::class,
+ RemoveLastReturnRector::class,
+ RemoveNonExistingVarAnnotationRector::class,
+ RemoveNullPropertyInitializationRector::class,
+ RemoveParentCallWithoutParentRector::class,
+ RemoveParentCallWithoutParentRector::class,
+ RemoveSoleValueSprintfRector::class,
+ RemoveUnreachableStatementRector::class,
+ RemoveUnusedConstructorParamRector::class,
+ RemoveUnusedForeachKeyRector::class,
+ RemoveUnusedNonEmptyArrayBeforeForeachRector::class,
+ RemoveUnusedPrivateClassConstantRector::class,
+ RemoveUnusedPrivateMethodParameterRector::class,
+ RemoveUnusedPrivatePropertyRector::class,
+ RemoveUnusedPromotedPropertyRector::class,
+ RemoveUnusedVariableAssignRector::class,
+ RemoveUnusedVariableInCatchRector::class,
+ RemoveUselessReturnTagRector::class,
+ RemoveUselessVarTagRector::class,
+ RenameForeachValueVariableToMatchExprVariableRector::class,
+ RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class,
+ ReplaceMultipleBooleanNotRector::class,
+ ReturnAnnotationIncorrectNullableRector::class,
+ ReturnBinaryAndToEarlyReturnRector::class,
+ ReturnBinaryOrToEarlyReturnRector::class,
+ ReturnEarlyIfVariableRector::class,
+ ReturnNeverTypeRector::class,
+ ReturnTypeFromReturnDirectArrayRector::class,
+ ReturnTypeFromReturnNewRector::class,
+ ReturnTypeFromStrictBoolReturnExprRector::class,
+ ReturnTypeFromStrictConstantReturnRector::class,
+ ReturnTypeFromStrictNativeCallRector::class,
+ ReturnTypeFromStrictNewArrayRector::class,
+ ReturnTypeFromStrictScalarReturnExprRector::class,
+ ReturnTypeFromStrictScalarReturnExprRector::class,
+ ReturnTypeFromStrictTernaryRector::class,
+ ReturnTypeFromStrictTypedCallRector::class,
+ ReturnTypeFromStrictTypedPropertyRector::class,
+ SeparateMultiUseImportsRector::class,
+ SetStateToStaticRector::class,
+ SetTypeToCastRector::class,
+ ShortenElseIfRector::class,
+ SimplifyArraySearchRector::class,
+ SimplifyBoolIdenticalTrueRector::class,
+ SimplifyConditionsRector::class,
+ SimplifyDeMorganBinaryRector::class,
+ SimplifyEmptyArrayCheckRector::class,
+ SimplifyEmptyCheckOnEmptyArrayRector::class,
+ SimplifyForeachToArrayFilterRector::class,
+ SimplifyForeachToCoalescingRector::class,
+ SimplifyFuncGetArgsCountRector::class,
+ SimplifyIfElseToTernaryRector::class,
+ SimplifyIfElseWithSameContentRector::class,
+ SimplifyIfNotNullReturnRector::class,
+ SimplifyIfNullableReturnRector::class,
+ SimplifyIfReturnBoolRector::class,
+ SimplifyInArrayValuesRector::class,
+ SimplifyMirrorAssignRector::class,
+ SimplifyRegexPatternRector::class,
+ SimplifyStrposLowerRector::class,
+ SimplifyTautologyTernaryRector::class,
+ SimplifyUselessVariableRector::class,
+ SingleInArrayToCompareRector::class,
+ SingularSwitchToIfRector::class,
+ SplitDoubleAssignRector::class,
+ SplitGroupedClassConstantsRector::class,
+ SplitGroupedPropertiesRector::class,
+ StaticArrowFunctionRector::class,
+ StaticClosureRector::class,
+ StrContainsRector::class,
+ StrEndsWithRector::class,
+ StrictArraySearchRector::class,
+ StringableForToStringRector::class,
+ StrlenZeroToIdenticalEmptyStringRector::class,
+ StrStartsWithRector::class,
+ StrvalToTypeCastRector::class,
+ SwitchNegatedTernaryRector::class,
+ SymplifyQuoteEscapeRector::class,
+ TernaryConditionVariableAssignmentRector::class,
+ TernaryEmptyArrayArrayDimFetchToCoalesceRector::class,
+ TernaryFalseExpressionToIfRector::class,
+ TernaryToBooleanOrFalseToBooleanAndRector::class,
+ ThrowWithPreviousExceptionRector::class,
+ TypedPropertyFromAssignsRector::class,
+ TypedPropertyFromStrictConstructorRector::class,
+ TypedPropertyFromStrictGetterMethodReturnTypeRector::class,
+ TypedPropertyFromStrictSetUpRector::class,
+ UnnecessaryTernaryExpressionRector::class,
+ UnSpreadOperatorRector::class,
+ UnusedForeachValueToArrayKeysRector::class,
+ UnwrapFutureCompatibleIfPhpVersionRector::class,
+ UnwrapSprintfOneArgumentRector::class,
+ UseClassKeywordForClassNameResolutionRector::class,
+ UseIdenticalOverEqualWithSameTypeRector::class,
+ UseIncrementAssignRector::class,
+ VarAnnotationIncorrectNullableRector::class,
+ VarConstantCommentRector::class,
+ VarToPublicPropertyRector::class,
+ VersionCompareFuncCallToConstantRector::class,
+ WrapEncapsedVariableInCurlyBracesRector::class,
+ IfIssetToCoalescingRector::class,
+ CleanupUnneededNullsafeOperatorRector::class,
+ BoolReturnTypeFromStrictScalarReturnsRector::class,
+ ]);
+};
diff --git a/app/src/Application.php b/app/src/Application.php
index 5b0072c..4525424 100644
--- a/app/src/Application.php
+++ b/app/src/Application.php
@@ -4,7 +4,6 @@
namespace Auth0\Quickstart;
-use Auth0\Quickstart\Contract\QuickstartExample;
use Auth0\SDK\Auth0;
use Auth0\SDK\Configuration\SdkConfiguration;
use Auth0\SDK\Exception\InvalidTokenException;
@@ -16,16 +15,6 @@ final class Application
*/
private SdkConfiguration $configuration;
- /**
- * An instance of the Auth0 SDK.
- */
- private Auth0 $sdk;
-
- /**
- * An instance of our application's template rendering helper class, for sending responses.
- */
- private ApplicationTemplates $templates;
-
/**
* An instance of our application's error handling class, for gracefully reporting exceptions.
*/
@@ -37,16 +26,14 @@ final class Application
private ApplicationRouter $router;
/**
- * An instance of a QuickstartExample class, specified from the AUTH0_USE_EXAMPLE env.
+ * An instance of the Auth0 SDK.
*/
- private ?QuickstartExample $example = null;
+ private Auth0 $sdk;
/**
- * An array of hooks with callback functions for examples to override default behavior.
- *
- * @var array
+ * An instance of our application's template rendering helper class, for sending responses.
*/
- private array $exampleHooks = [];
+ private ApplicationTemplates $templates;
/**
* Setup our Quickstart application.
@@ -54,7 +41,7 @@ final class Application
* @param array $env Auth0 configuration imported from .env file.
*/
public function __construct(
- array $env
+ array $env,
) {
// Configure the SDK using our .env configuration.
$this->setupAuth0($env);
@@ -63,41 +50,6 @@ public function __construct(
$this->templates = new ApplicationTemplates($this);
$this->errorHandler = new ApplicationErrorHandler($this);
$this->router = new ApplicationRouter($this);
- $this->example = null;
- }
-
- /**
- * Configure the Auth0 SDK using the .env configuration.
- *
- * @param array $env Auth0 configuration imported from .env file.
- */
- public function setupAuth0(
- array $env
- ): void {
- // Build our SdkConfiguration.
- $this->configuration = new SdkConfiguration([
- 'domain' => $env['AUTH0_DOMAIN'] ?? null,
- 'clientId' => $env['AUTH0_CLIENT_ID'] ?? null,
- 'clientSecret' => $env['AUTH0_CLIENT_SECRET'] ?? null,
- 'audience' => ($env['AUTH0_AUDIENCE'] ?? null) !== null ? [trim($env['AUTH0_AUDIENCE'])] : null,
- 'organization' => ($env['AUTH0_ORGANIZATION'] ?? null) !== null ? [trim($env['AUTH0_ORGANIZATION'])] : null,
- 'strategy' => SdkConfiguration::STRATEGY_API,
- ]);
-
- // Setup the Auth0 SDK.
- $this->sdk = new Auth0($this->configuration);
- }
-
- /**
- * "Run" our application, responding to end-user requests.
- */
- public function run(): void
- {
- // Intercept exceptions to gracefully report them.
- $this->errorHandler->hook();
-
- // Handle incoming requests through the router.
- $this->router->run();
}
/**
@@ -141,40 +93,80 @@ public function &getRouter(): ApplicationRouter
}
/**
- * Called from the ApplicationRouter when end user loads '/'.
+ * Called from the ApplicationRouter when end user loads '/api'.
+ *
+ * @param ApplicationRouter $router
*/
- public function onIndexRoute(
- ApplicationRouter $router
+ public function onApiRoute(
+ ApplicationRouter $router,
): void {
+ $session = $this->getToken();
+
// Send response to browser.
- $this->templates->render('spa', [
- 'config' => $this->getConfiguration(),
+ $this->templates->render('logged-' . ($session instanceof \Auth0\SDK\Contract\TokenInterface ? 'in' : 'out'), [
+ 'session' => $session,
'router' => $router,
]);
}
/**
- * Called from the ApplicationRouter when end user loads '/api'.
+ * Called from the ApplicationRouter when end user loads an unknown route.
+ *
+ * @param ApplicationRouter $router
*/
- public function onApiRoute(
- ApplicationRouter $router
+ public function onError404(
+ ApplicationRouter $router,
): void {
- $session = $this->getToken();
+ $router->setHttpStatus(404);
+ }
+ /**
+ * Called from the ApplicationRouter when end user loads '/'.
+ *
+ * @param ApplicationRouter $router
+ */
+ public function onIndexRoute(
+ ApplicationRouter $router,
+ ): void {
// Send response to browser.
- $this->templates->render('logged-' . ($session === null ? 'out' : 'in'), [
- 'session' => $session,
+ $this->templates->render('spa', [
+ 'config' => $this->getConfiguration(),
'router' => $router,
]);
}
/**
- * Called from the ApplicationRouter when end user loads an unknown route.
+ * "Run" our application, responding to end-user requests.
*/
- public function onError404(
- ApplicationRouter $router
+ public function run(): void
+ {
+ // Intercept exceptions to gracefully report them.
+ $this->errorHandler->hook();
+
+ // Handle incoming requests through the router.
+ $this->router->run();
+ }
+
+ /**
+ * Configure the Auth0 SDK using the .env configuration.
+ *
+ * @param array $env Auth0 configuration imported from .env file.
+ */
+ public function setupAuth0(
+ array $env,
): void {
- $router->setHttpStatus(404);
+ // Build our SdkConfiguration.
+ $this->configuration = new SdkConfiguration([
+ 'domain' => $env['AUTH0_DOMAIN'] ?? null,
+ 'clientId' => $env['AUTH0_CLIENT_ID'] ?? null,
+ 'clientSecret' => $env['AUTH0_CLIENT_SECRET'] ?? null,
+ 'audience' => ($env['AUTH0_AUDIENCE'] ?? null) !== null ? [trim($env['AUTH0_AUDIENCE'])] : null,
+ 'organization' => ($env['AUTH0_ORGANIZATION'] ?? null) !== null ? [trim($env['AUTH0_ORGANIZATION'])] : null,
+ 'strategy' => SdkConfiguration::STRATEGY_API,
+ ]);
+
+ // Setup the Auth0 SDK.
+ $this->sdk = new Auth0($this->configuration);
}
/**
@@ -188,7 +180,7 @@ private function getToken(): ?\Auth0\SDK\Contract\TokenInterface
$token = $_GET['token'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['Authorization'] ?? null;
// If no token was present, abort processing.
- if ($token === null) {
+ if (null === $token) {
return null;
}
@@ -196,7 +188,7 @@ private function getToken(): ?\Auth0\SDK\Contract\TokenInterface
$token = trim($token);
// Remove the 'Bearer ' prefix, if present, in the event we're using an Authorization header that's using it.
- if (substr($token, 0, 7) === 'Bearer ') {
+ if (str_starts_with($token, 'Bearer ')) {
$token = substr($token, 7);
}
diff --git a/app/src/ApplicationErrorHandler.php b/app/src/ApplicationErrorHandler.php
index c972e27..6bcd52c 100644
--- a/app/src/ApplicationErrorHandler.php
+++ b/app/src/ApplicationErrorHandler.php
@@ -7,6 +7,8 @@
use Auth0\SDK\Exception\Auth0Exception;
use Throwable;
+use function array_key_exists;
+
final class ApplicationErrorHandler
{
/**
@@ -20,9 +22,9 @@ final class ApplicationErrorHandler
* @param Application $app An instance of our Quickstart Application.
*/
public function __construct(
- Application &$app
+ Application &$app,
) {
- $this->app = & $app;
+ $this->app = &$app;
}
/**
@@ -30,7 +32,9 @@ public function __construct(
*/
public function hook(): void
{
- set_exception_handler([$this, 'onException']);
+ set_exception_handler(function (Throwable $throwable): void {
+ $this->onException($throwable);
+ });
}
/**
@@ -39,7 +43,7 @@ public function hook(): void
* @param Throwable $throwable The throwable to report.
*/
public function onException(
- \Throwable $throwable
+ Throwable $throwable,
): void {
$exception = $throwable;
diff --git a/app/src/ApplicationRouter.php b/app/src/ApplicationRouter.php
index 7408a8d..b0a291a 100644
--- a/app/src/ApplicationRouter.php
+++ b/app/src/ApplicationRouter.php
@@ -4,6 +4,8 @@
namespace Auth0\Quickstart;
+use function array_key_exists;
+
final class ApplicationRouter
{
/**
@@ -17,93 +19,63 @@ final class ApplicationRouter
* @param Application $app An instance of our Quickstart Application.
*/
public function __construct(
- Application &$app
+ Application &$app,
) {
- $this->app = & $app;
- }
-
- /**
- * Process the current request and route it to the class handler.
- *
- * @param string $uri The new uri to redirect the end user to.
- */
- public function redirect(
- string $uri
- ): void {
- header('Location: ' . $uri, true, 303);
- exit;
+ $this->app = &$app;
}
/**
- * Process the current request and route it to the class handler.
+ * Return the request method (GET, POST, etc.).
*/
- public function run(): void
+ public function getMethod(): string
{
- $requestUri = parse_url($this->getUri(), PHP_URL_PATH);
-
- $routed = false;
-
- if ($requestUri === '/') {
- $this->app->onIndexRoute($this);
- $routed = true;
- }
-
- if ($requestUri === '/api') {
- $this->setHeaders();
- $this->app->onApiRoute($this);
- $routed = true;
- }
-
- if ($routed === false) {
- $this->setHeaders();
- $this->app->onError404($this);
- }
-
- exit;
+ return $_SERVER['REQUEST_METHOD'] ?? 'GET';
}
/**
* Return (and optionally manipulate) the currently requested uri.
*
- * @param string|null $path Unless null, manipulates the resulting path to match the value.
- * @param string|null $query Unless, manipulates the resulting query to match the value.
+ * @param null|string $path Unless null, manipulates the resulting path to match the value.
+ * @param null|string $query Unless, manipulates the resulting query to match the value.
*/
public function getUri(
?string $path = null,
- ?string $query = null
+ ?string $query = null,
): string {
$httpScheme = $_SERVER['HTTPS'] ?? '';
- $httpScheme = $httpScheme === 'on' ? 'https' : 'http';
+ $httpScheme = 'on' === $httpScheme ? 'https' : 'http';
+
$httpPort = (int) $_SERVER['SERVER_PORT'];
$httpHost = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'];
$httpHost = preg_replace('/\:' . $httpPort . '$/', '', $httpHost);
+
$httpRequest = (string) $_SERVER['REQUEST_URI'];
- $httpUri = $httpScheme . '://' . $httpHost . ($httpPort !== 80 ? ':' . $httpPort : '') . $httpRequest;
+ $httpUri = $httpScheme . '://' . $httpHost . (80 !== $httpPort ? ':' . $httpPort : '') . $httpRequest;
// If we aren't making changes, simply return the uri.
- if ($path === null && $query === null) {
+ if (null === $path && null === $query) {
return $httpUri;
}
// Parse a url into it's components so we can manipulate them more easily.
$parsedUri = parse_url($httpUri);
- if ($parsedUri === false) {
+ if (false === $parsedUri) {
return $httpUri;
}
- $parsedUri['scheme'] = $parsedUri['scheme'] ?? 'http';
- $parsedUri['host'] = $parsedUri['host'] ?? $httpHost;
- $parsedUri['path'] = $parsedUri['path'] ?? '';
+ $parsedUri['scheme'] ??= 'http';
+ $parsedUri['host'] ??= $httpHost;
+ $parsedUri['path'] ??= '';
$parsedUri['query'] = '?' . ($parsedUri['query'] ?? '');
// Manipulate the /path portion of the uri.
- if ($path !== null) {
+ if (null !== $path) {
$parsedUri['path'] = $path;
}
// Manipulate the ?query portion of the uri.
- if ($query !== null) {
+ if (null !== $query) {
$parsedUri['query'] = $query;
}
@@ -111,24 +83,56 @@ public function getUri(
$parsedUri['port'] = 80;
}
- if ($parsedUri['query'] === '?') {
+ if ('?' === $parsedUri['query']) {
$parsedUri['query'] = '';
}
- if ($parsedUri['query'] !== '') {
+ if ('' !== $parsedUri['query']) {
$parsedUri['query'] = '?' . $parsedUri['query'];
}
// Reconstruct the manipulated uri and return it.
- return $parsedUri['scheme'] . '://' . $parsedUri['host'] . ($parsedUri['port'] !== 80 ? ':' . $parsedUri['port'] : '') . $parsedUri['path'] . $parsedUri['query'];
+ return $parsedUri['scheme'] . '://' . $parsedUri['host'] . (80 !== $parsedUri['port'] ? ':' . $parsedUri['port'] : '') . $parsedUri['path'] . $parsedUri['query'];
}
/**
- * Return the request method (GET, POST, etc.)
+ * Process the current request and route it to the class handler.
+ *
+ * @param string $uri The new uri to redirect the end user to.
*/
- public function getMethod(): string
+ public function redirect(
+ string $uri,
+ ): void {
+ header('Location: ' . $uri, true, 303);
+ exit;
+ }
+
+ /**
+ * Process the current request and route it to the class handler.
+ */
+ public function run(): void
{
- return $_SERVER['REQUEST_METHOD'] ?? 'GET';
+ $requestUri = parse_url($this->getUri(), PHP_URL_PATH);
+
+ $routed = false;
+
+ if ('/' === $requestUri) {
+ $this->app->onIndexRoute($this);
+ $routed = true;
+ }
+
+ if ('/api' === $requestUri) {
+ $this->setHeaders();
+ $this->app->onApiRoute($this);
+ $routed = true;
+ }
+
+ if (false === $routed) {
+ $this->setHeaders();
+ $this->app->onError404($this);
+ }
+
+ exit;
}
/**
@@ -151,7 +155,7 @@ public function setHeaders(): void
* @param int $status The HTTP status code to send.
*/
public function setHttpStatus(
- int $status
+ int $status,
): void {
http_response_code($status);
}
diff --git a/app/src/ApplicationTemplates.php b/app/src/ApplicationTemplates.php
index dec2cd8..1c17c13 100644
--- a/app/src/ApplicationTemplates.php
+++ b/app/src/ApplicationTemplates.php
@@ -4,6 +4,12 @@
namespace Auth0\Quickstart;
+use Exception;
+use LogicException;
+use Throwable;
+
+use function array_key_exists;
+
final class ApplicationTemplates
{
/**
@@ -14,9 +20,13 @@ final class ApplicationTemplates
/**
* State machine of the template being rendered.
*
- * @var array{section: string|null, sections: array, layout: array{name: string, variables: array}|null}
+ * @var array{section: null|string, sections: array, layout: null|array{name: string, variables: array}}
*/
- private array $state;
+ private array $state = [
+ 'sections' => [],
+ 'section' => null,
+ 'layout' => null,
+ ];
/**
* ApplicationTemplates constructor.
@@ -24,26 +34,20 @@ final class ApplicationTemplates
* @param Application $app An instance of our Quickstart Application.
*/
public function __construct(
- Application &$app
+ Application &$app,
) {
- $this->app = & $app;
-
- $this->state = [
- 'sections' => [],
- 'section' => null,
- 'layout' => null,
- ];
+ $this->app = &$app;
}
/**
* Render a template as the browser response, then exit.
*
- * @param string $template The name of the template to use.
+ * @param string $template The name of the template to use.
* @param array $variables Any variables the template should have access to use.
*/
public function render(
string $template,
- array $variables = []
+ array $variables = [],
): void {
$this->state = [
'sections' => [],
@@ -59,6 +63,22 @@ public function render(
exit;
}
+ /**
+ * Define a container layout in which to render a template.
+ *
+ * @param string $name The name of the layout template to use.
+ * @param array $variables Any additional variables the layout template should have access to use.
+ */
+ private function layout(
+ string $name,
+ array $variables = [],
+ ): void {
+ $this->state['layout'] = [
+ 'name' => $name,
+ 'variables' => $variables,
+ ];
+ }
+
/**
* Render a template, and return the content as a string.
*
@@ -67,19 +87,19 @@ public function render(
*/
private function renderTemplate(
string $template,
- array $variables = []
+ array $variables = [],
): string {
// Keep track of the output buffering 'level'.
$level = 0;
// Resolve the requested template to it's file path:
- $templatePath = join(DIRECTORY_SEPARATOR, [APP_ROOT, 'templates', $template . '.php']);
+ $templatePath = implode(DIRECTORY_SEPARATOR, [APP_ROOT, 'templates', $template . '.php']);
// Extract $variables into current scope, for use in template.
extract($variables);
- if (file_exists($templatePath) === false) {
- throw new \Exception("Template file not found: {$template}");
+ if (! file_exists($templatePath)) {
+ throw new Exception(sprintf('Template file not found: %s', $template));
}
try {
@@ -90,7 +110,7 @@ private function renderTemplate(
$content = ob_get_clean();
- if ($this->state['layout'] !== null) {
+ if (null !== $this->state['layout']) {
$layoutTemplate = $this->state['layout']['name'];
$layoutVariables = array_merge($variables, $this->state['layout']['variables']);
@@ -100,17 +120,17 @@ private function renderTemplate(
$content = $this->renderTemplate($layoutTemplate, $layoutVariables);
}
- if ($content !== false) {
+ if (false !== $content) {
return trim($content);
}
return '';
- } catch (\Throwable $e) {
+ } catch (Throwable $throwable) {
while (ob_get_level() > $level) {
ob_end_clean();
}
- throw $e;
+ throw $throwable;
}
}
@@ -120,7 +140,7 @@ private function renderTemplate(
* @param string $sectionName Name of the section to render into the template.
*/
private function section(
- string $sectionName
+ string $sectionName,
): string {
return $this->state['sections'][$sectionName] ?? '';
}
@@ -131,10 +151,10 @@ private function section(
* @param string $sectionName Name of the section to begin capturing.
*/
private function start(
- string $sectionName
+ string $sectionName,
): void {
- if ($this->state['section'] !== null) {
- throw new \LogicException('Nested sections are not supported.');
+ if (null !== $this->state['section']) {
+ throw new LogicException('Nested sections are not supported.');
}
$this->state['section'] = $sectionName;
@@ -147,8 +167,8 @@ private function start(
*/
private function stop(): void
{
- if ($this->state['section'] === null) {
- throw new \LogicException('You must start a section before stopping it.');
+ if (null === $this->state['section']) {
+ throw new LogicException('You must start a section before stopping it.');
}
if (array_key_exists($this->state['section'], $this->state['sections'])) {
@@ -158,20 +178,4 @@ private function stop(): void
$this->state['sections'][$this->state['section']] = ob_get_clean();
$this->state['section'] = null;
}
-
- /**
- * Define a container layout in which to render a template.
- *
- * @param string $name The name of the layout template to use.
- * @param array $variables Any additional variables the layout template should have access to use.
- */
- private function layout(
- string $name,
- array $variables = []
- ): void {
- $this->state['layout'] = [
- 'name' => $name,
- 'variables' => $variables,
- ];
- }
}
diff --git a/app/tests/Feature/ExampleTest.php b/app/tests/Feature/ExampleTest.php
new file mode 100644
index 0000000..61cd84c
--- /dev/null
+++ b/app/tests/Feature/ExampleTest.php
@@ -0,0 +1,5 @@
+toBeTrue();
+});
diff --git a/app/tests/Pest.php b/app/tests/Pest.php
new file mode 100644
index 0000000..5949c61
--- /dev/null
+++ b/app/tests/Pest.php
@@ -0,0 +1,45 @@
+in('Feature');
+
+/*
+|--------------------------------------------------------------------------
+| Expectations
+|--------------------------------------------------------------------------
+|
+| When you're writing tests, you often need to check that values meet certain conditions. The
+| "expect()" function gives you access to a set of "expectations" methods that you can use
+| to assert different things. Of course, you may extend the Expectation API at any time.
+|
+*/
+
+expect()->extend('toBeOne', function () {
+ return $this->toBe(1);
+});
+
+/*
+|--------------------------------------------------------------------------
+| Functions
+|--------------------------------------------------------------------------
+|
+| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
+| project that you don't want to repeat in every file. Here you can also expose helpers as
+| global functions to help you to reduce the number of lines of code in your test files.
+|
+*/
+
+function something()
+{
+ // ..
+}
diff --git a/app/tests/TestCase.php b/app/tests/TestCase.php
new file mode 100644
index 0000000..cfb05b6
--- /dev/null
+++ b/app/tests/TestCase.php
@@ -0,0 +1,10 @@
+toBeTrue();
+});