diff --git a/.github/actions/initial-setup/action.yml b/.github/actions/initial-setup/action.yml new file mode 100644 index 0000000..1243226 --- /dev/null +++ b/.github/actions/initial-setup/action.yml @@ -0,0 +1,43 @@ +name: Initial Setup + +runs: + using: "composite" + steps: + - name: Print initial state + run: | + echo -e "GitHub workspace:${{ github.workspace }}" + echo "Current directory:" + pwd + echo "Contents of /etc/hosts:" + cat /etc/hosts + echo "Owner of /etc/hosts:" + ls -l /etc/hosts + echo "Current user:" + whoami + shell: bash + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + # 8.2+ is expected for php-code-quality-tests + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + extensions: mbstring, opcache + + - name: Install Composer + run: | + curl -sS https://getcomposer.org/installer | php + sudo mv composer.phar /usr/local/bin/composer + shell: bash + + - name: Run install-tools.sh + run: bash ${{ github.workspace }}/tools/install-tools.sh + shell: bash + + - name: Build assets + run: cd ${{ github.workspace }}/assets && yarn build:all + shell: bash diff --git a/.github/actions/release/svn-make-commit/action.yml b/.github/actions/release/svn-make-commit/action.yml new file mode 100644 index 0000000..d99cd52 --- /dev/null +++ b/.github/actions/release/svn-make-commit/action.yml @@ -0,0 +1,42 @@ +name: SVN Make Commit + +inputs: + username: + description: "SVN account username to make a commit" + required: true + password: + description: "SVN account password to make a commit" + required: true + tag: + description: "Current release tag" + required: true + +runs: + using: "composite" + steps: + - name: Handle removed items in the trunk folder + run: | + # Check for removed files and handle them + REMOVED_FILES=$(svn status | awk '/^\!/ {print $2}') + if [ -n "$REMOVED_FILES" ]; then + echo "Found removed files:" + echo "$REMOVED_FILES" + echo "$REMOVED_FILES" | sort -r | xargs -r svn delete + else + echo "No removed files to handle." + fi + working-directory: ${{ github.workspace }}/release/trunk + shell: bash + + - name: Add new folders and files + run: | + svn add --force ${{ github.workspace }}/release/trunk + svn add --force ${{ github.workspace }}/release/assets/* + svn add ${{ github.workspace }}/release/tags/${{ inputs.tag }} + shell: bash + + - name: Commit changes + run: | + cd ${{ github.workspace }}/release + svn ci -m "v ${{ inputs.tag }}" --config-option=servers:global:http-timeout=900 --non-interactive --no-auth-cache --username ${{ inputs.username }} --password ${{ inputs.password }} + shell: bash diff --git a/.github/actions/release/svn-prepare-commit/action.yml b/.github/actions/release/svn-prepare-commit/action.yml new file mode 100644 index 0000000..ce92522 --- /dev/null +++ b/.github/actions/release/svn-prepare-commit/action.yml @@ -0,0 +1,63 @@ +name: SVN Prepare Commit + +outputs: + release_tag: + description: "Current release tag" + value: ${{ steps.get_tag.outputs.version }} + +runs: + using: "composite" + steps: + - name: Get tag + id: get_tag + run: | + VERSION="${GITHUB_REF#refs/tags/}" + VERSION="${VERSION#v}" + echo "::set-output name=version::$VERSION" + shell: bash + + - name: Print tag + run: | + echo "Tag: ${{ steps.get_tag.outputs.version }}" + shell: bash + + - name: Make release folder + run: mkdir ${{ github.workspace }}/release + shell: bash + + - name: Init SVN + run: svn co https://plugins.svn.wordpress.org/prosopo-procaptcha ${{ github.workspace }}/release + shell: bash + + - name: Make sure the tag does not exist + run: | + set -e # Exit immediately if a command exits with a non-zero status + cd ${{ github.workspace }}/release + # Check if the tag already exists + if svn ls tags | grep -q ${{ steps.get_tag.outputs.version }}; then + echo "Tag ${{ steps.get_tag.outputs.version }} already exists." + exit 1 + else + echo "Tag ${{ steps.get_tag.outputs.version }} does not exist." + fi + shell: bash + + - name: Copy assets + run: cp ${{ github.workspace }}/wordpress-org-assets/* ${{ github.workspace }}/release/assets + shell: bash + + - name: Create the target Tag folder + run: mkdir ${{ github.workspace }}/release/tags/${{ steps.get_tag.outputs.version }} + shell: bash + + - name: Copy files to the new Tag folder + run: cp -r ${{ github.workspace }}/prosopo-procaptcha/* ${{ github.workspace }}/release/tags/${{ steps.get_tag.outputs.version }} + shell: bash + + - name: Empty Trunk folder + run: rm ${{ github.workspace }}/release/trunk/* -rf + shell: bash + + - name: Copy files and folders to the Trunk folder + run: cp -r ${{ github.workspace }}/prosopo-procaptcha/* ${{ github.workspace }}/release/trunk + shell: bash diff --git a/.github/actions/tests/clone-private-repository/action.yml b/.github/actions/tests/clone-private-repository/action.yml new file mode 100644 index 0000000..d8807bb --- /dev/null +++ b/.github/actions/tests/clone-private-repository/action.yml @@ -0,0 +1,30 @@ +name: Clone Private Repository + +inputs: + private_folder: + description: "Target folder the private repo should be extract to" + required: true + private_repo: + description: "Repo with paid plugin archives" + required: true + private_key: + description: "Private SSH key to access the private repository" + required: true + +runs: + using: "composite" + steps: + - name: Clone Private Plugin Repository + run: | + mkdir -p ${{ inputs.private_folder }} + cd ${{ inputs.private_folder }} + + # Setup SSH Key for Private Repo Access + mkdir -p ~/.ssh + echo "${{ inputs.private_key }}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -t ed25519 github.com >> ~/.ssh/known_hosts + + # Clone the Private Repository + git clone git@github.com:${{ inputs.private_repo }} . + shell: bash diff --git a/.github/actions/tests/install-e2e-packages/action.yml b/.github/actions/tests/install-e2e-packages/action.yml new file mode 100644 index 0000000..c449370 --- /dev/null +++ b/.github/actions/tests/install-e2e-packages/action.yml @@ -0,0 +1,43 @@ +name: Install E2E Packages + +runs: + using: "composite" + steps: + # we need to install PHP 7.4 separately from php 8.2 in the initial-setup, + # cause WordPress is compatible with PHP 7.4 + - name: Install PHP 7.4 + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: mbstring, mysqli, opcache + + - name: Install Nginx + run: sudo apt-get update && sudo apt-get install -y nginx + shell: bash + + - name: Install MySQL client + run: sudo apt-get update && sudo apt-get install -y mysql-client + shell: bash + + # cypress dependencies https://docs.cypress.io/guides/getting-started/installing-cypress#Linux-Prerequisites + - name: Install cypress dependencies + run: sudo apt-get update && sudo apt-get install -y libgtk2.0-0t64 libgtk-3-0t64 libgbm-dev libnotify-dev libnss3 libxss1 libasound2t64 libxtst6 xauth xvfb + shell: bash + + - name: Install Chrome + run: | + wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add - + sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' + sudo apt-get update + sudo apt-get install -y google-chrome-stable + shell: bash + + # used in the tasks/install-wordpress-with-plugins.yml + - name: Install JSON parser + run: sudo apt-get update && sudo apt-get install -y jq + shell: bash + + # used in the /tests.yml + - name: Install wait-on + run: npm install -g wait-on + shell: bash diff --git a/.github/actions/tests/install-wordpress-with-plugins/action.yml b/.github/actions/tests/install-wordpress-with-plugins/action.yml new file mode 100644 index 0000000..d80779f --- /dev/null +++ b/.github/actions/tests/install-wordpress-with-plugins/action.yml @@ -0,0 +1,47 @@ +name: Install WordPress with Plugins + +inputs: + paid_plugins_dir: + description: "Folder with archives for the paid plugins" + required: true + +runs: + using: "composite" + steps: + - name: Download and setup WordPress + run: | + cd ${{ github.workspace }} + curl -O https://wordpress.org/latest.tar.gz + tar -xzf latest.tar.gz + mv wordpress/* ${{ github.workspace }} + cp wp-config-sample.php wp-config.php + sed -i "s/database_name_here/wordpress/" wp-config.php + sed -i "s/username_here/root/" wp-config.php + sed -i "s/password_here/wordpress/" wp-config.php + sed -i "s/localhost/127.0.0.1/" wp-config.php + sed -i "s/define( 'WP_DEBUG', false );/define( 'WP_DEBUG', true );\ndefine( 'WP_DEBUG_DISPLAY', false );\ndefine( 'WP_DEBUG_LOG', true );error_reporting( E_ALL );/" wp-config.php + cp -r ${{ github.workspace }}/prosopo-procaptcha ${{ github.workspace }}/wp-content/plugins/ + mkdir -p ${{ github.workspace }}/wp-content/mu-plugins + cp ${{ github.workspace }}/data-for-tests/mu-plugin.php ${{ github.workspace }}/wp-content/mu-plugins/mu-plugin.php + shell: bash + + - name: Install WordPress plugins + run: | + cd ${{ github.workspace }}/tests/cypress/e2e/${{ matrix.cypress-target }} + plugins=$(cat ./installation-list.json | jq -r '.plugins[]') + for plugin in $plugins; do + echo "Installing $plugin plugin" + + paid_plugin_path="${{ inputs.paid_plugins_dir }}/$plugin.zip" + + if [[ -f "$paid_plugin_path" ]]; then + echo "Found paid plugin ZIP for $plugin in the paid plugins directory." + unzip "$paid_plugin_path" -d ${{ github.workspace }}/wp-content/plugins/ + else + echo "No local ZIP for $plugin, downloading from WordPress repository." + curl -L -o "$plugin.zip" "https://downloads.wordpress.org/plugin/$plugin.latest-stable.zip" + unzip "$plugin.zip" -d ${{ github.workspace }}/wp-content/plugins/ + rm "$plugin.zip" + fi + done + shell: bash diff --git a/.github/actions/tests/prepare-e2e-workflow/action.yml b/.github/actions/tests/prepare-e2e-workflow/action.yml new file mode 100644 index 0000000..9a51f5f --- /dev/null +++ b/.github/actions/tests/prepare-e2e-workflow/action.yml @@ -0,0 +1,27 @@ +name: Prepare E2E Workflow + +runs: + using: "composite" + steps: + - name: Move website files to /var/www/procaptcha + run: sudo mv ${{ github.workspace }}/* /var/www/procaptcha + shell: bash + + # it's necessary, as cypress was installed under the 'runner' user, so these folders should left. + - name: Back tests and tools folders + run: | + sudo mv /var/www/procaptcha/tests ${{ github.workspace }} + sudo mv /var/www/procaptcha/tools ${{ github.workspace }} + shell: bash + + - name: Set ownership of website files to www-data + run: sudo chown -R www-data:www-data /var/www/procaptcha + shell: bash + + - name: Wait for WordPress to start + run: npx wait-on http://procaptcha.local --timeout 10000 + shell: bash + + - name: Check domain resolution + run: curl -I http://procaptcha.local + shell: bash diff --git a/.github/actions/tests/setup-e2e-packages/action.yml b/.github/actions/tests/setup-e2e-packages/action.yml new file mode 100644 index 0000000..4034d8d --- /dev/null +++ b/.github/actions/tests/setup-e2e-packages/action.yml @@ -0,0 +1,46 @@ +name: Setup E2E Packages + +runs: + using: "composite" + steps: + # note when using act, it uses copy of your '/etc/hosts', so it's important to override it instead of appending + - name: Override /etc/hosts + run: echo "127.0.0.1 localhost procaptcha.local" | sudo tee /etc/hosts + shell: bash + + - name: Configure Nginx + run: | + sudo bash -c 'cat > /etc/nginx/sites-available/default <- + --health-cmd="mysqladmin ping --silent" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + + strategy: + matrix: + # names of the test folders: /tests/cypress/e2e/* + cypress-target: [ branding-plugins-1, branding-plugins-2, form-plugins, others, security-plugins, wordpress ] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Clear Cypress cache to avoid session-related issues + run: rm -rf ~/.cache/Cypress + shell: bash + + - name: Initial setup + uses: ./.github/actions/initial-setup + + - name: Install e2e packages + uses: ./.github/actions/tests/install-e2e-packages + + - name: Setup e2e packages + uses: ./.github/actions/tests/setup-e2e-packages + + - name: Clone private repository + uses: ./.github/actions/tests/clone-private-repository + with: + private_folder: ${{ github.workspace }}/private-data + private_repo: prosopo/procaptcha-wordpress-plugin-private + private_key: ${{ secrets.PRIVATE_KEY_FOR_PRIVATE_REPO }} + + - name: Install WordPress with plugins + uses: ./.github/actions/tests/install-wordpress-with-plugins + with: + paid_plugins_dir: ${{ github.workspace }}/private-data/data-for-tests/paid-plugins + + - name: Import database + run: mysql -h 127.0.0.1 -u root -pwordpress wordpress < ${{ github.workspace }}/private-data/data-for-tests/db.sql + shell: bash + + - name: Prepare E2E workflow + uses: ./.github/actions/tests/prepare-e2e-workflow + + - name: Run Cypress tests + run: bash ${{ github.workspace }}/tools/run-tests.sh ${{ matrix.cypress-target }} + + - name: Upload Cypress screenshots and WP debug log + if: always() + uses: actions/upload-artifact@v4 + with: + name: screenshots-and-wp-debug-log-for-${{ matrix.cypress-target }} + path: | + ${{ github.workspace }}/tests/cypress/screenshots + ${{ github.workspace }}/tests/cypress/logs + /var/www/procaptcha/wp-content/debug.log + if-no-files-found: ignore diff --git a/README.md b/README.md index 7651243..c0af6b5 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,13 @@ This repository includes both the plugin code, and the workflow tools: - `assets` - TypeScript and Sass source files; [ESLint](https://eslint.org/), [Prettifier](https://prettier.io/) and [Vite](https://vitejs.dev/) configs - `data-for-tests` - files involved in GitHub actions -- `php-code-quality-tools` - composer packages and configs - for [PHPStan](https://phpstan.org/), [PHPSniffer](https://github.com/squizlabs/PHP_CodeSniffer) - and [Pest](https://pestphp.com/). +- `php-tools` +- + * `code-quality` - composer packages and configs + for [PHPStan](https://phpstan.org/), [PHPSniffer](https://github.com/squizlabs/PHP_CodeSniffer) + and [Pest](https://pestphp.com/) + * `origin-vendors` - composer dependencies + * `scoper` - PHP tool for package scoping (as WP doesn't support composer) - `prosopo-procaptcha` - plugin source code - `tests` - end-to-end [Cypress](https://cypress.io) tests - `tools` - bash scripts, used CI/CD or manually. @@ -40,13 +44,14 @@ This repository includes both the plugin code, and the workflow tools: ## 3. Related Resources -* [Prosopo Procaptcha Website](https://prosopo.io/) +* [Prosopo Procaptcha Website](https://prosopo.io/) * [Plugin Documentation](https://docs.prosopo.io/en/wordpress-plugin/) * [Plugin Support Forum](https://wordpress.org/support/plugin/prosopo-procaptcha/) * [Plugin SVN Repository](http://plugins.svn.wordpress.org/prosopo-procaptcha/) ## 4. Contribution -We would be excited if you decide to contribute 🤝 +We would be excited if you decide to contribute 🤝 -Please read the [for-devs.md](https://github.com/prosopo/procaptcha-wordpress-plugin/blob/main/for-devs.md) file for project guidelines and agreements. +Please read the [for-devs.md](https://github.com/prosopo/procaptcha-wordpress-plugin/blob/main/for-devs.md) file for +project guidelines and agreements. diff --git a/assets/yarn.lock b/assets/yarn.lock index 29ad4c4..d0a4088 100644 --- a/assets/yarn.lock +++ b/assets/yarn.lock @@ -7603,11 +7603,11 @@ __metadata: linkType: hard "nanoid@npm:^3.3.7": - version: 3.3.7 - resolution: "nanoid@npm:3.3.7" + version: 3.3.8 + resolution: "nanoid@npm:3.3.8" bin: nanoid: bin/nanoid.cjs - checksum: 10c0/e3fb661aa083454f40500473bb69eedb85dc160e763150b9a2c567c7e9ff560ce028a9f833123b618a6ea742e311138b591910e795614a629029e86e180660f3 + checksum: 10c0/4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120 languageName: node linkType: hard diff --git a/for-devs.md b/for-devs.md index 91af89b..d274e64 100644 --- a/for-devs.md +++ b/for-devs.md @@ -21,10 +21,10 @@ The project follows the [WordPress Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/). Configure your IDE to use the [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) and use the -`php-code-quality-tools/wp-ruleset.xml` config, or run the following +`php-tools/code-quality/wp-ruleset.xml` config, or run the following command to automatically fix style issues: -`cd php-code-quality-tools; composer install; composer phpcbf` +`cd php-tools/code-quality; composer install; composer phpcbf` ### 2.2) JavaScript @@ -38,7 +38,7 @@ run the following command to automatically fix style issues: ### 3.1) PHP The project uses [PHPStan](https://phpstan.org/) for static analysis. Configure your IDE with the -`php-code-quality-tools/phpstan.neon` config or run the analysis using the following command: +`php-tools/code-quality/phpstan.neon` config or run the analysis using the following command: `cd code-quality-tools; composer install; composer phpstan` diff --git a/for-maintainers.md b/for-maintainers.md index 4e2e87b..3274780 100644 --- a/for-maintainers.md +++ b/for-maintainers.md @@ -46,7 +46,23 @@ Commands: 1. `bash tools/refresh-translations.sh` - updates the `.pot` and `.po` files based on the plugin codebase. 2. `bash tools/compile-translations.sh` - compiles the `.po` files to `.mo` and `.l10n.php` files. -## 4. End-to-End tests +## 4. Updating scoped Composer packages + +WordPress does not natively support Composer, which means plugin authors must scope their Composer packages to avoid +conflicts. + +Each original namespace, such as `Some/Package`, needs to be transformed into a unique namespace like +`CurrentPluginNamespace/Some/Package`. This prevents conflicts when other plugins include the same package but with +different versions. + +To handle this, we use a powerful PHP tool called [Humbug PHP-Scoper](https://github.com/humbug/php-scoper). + +Steps to update the scoped packages: + +1. `cd php-tools/origin-vendors; composer install/update` +2. `bash tools/scope-php-vendors.sh` + +## 5. Local End-to-End tests The integrations are covered by [Cypress](https://www.cypress.io/) e2e tests. These tests are integrated into GitHub Actions but can also be run locally. diff --git a/php-code-quality-tools/ComponentsTest.php b/php-code-quality-tools/ComponentsTest.php deleted file mode 100644 index b8dee24..0000000 --- a/php-code-quality-tools/ComponentsTest.php +++ /dev/null @@ -1,357 +0,0 @@ -getComponents()->make( get_class( $component_class ) ); - - $this->assertEquals( '', $component->string ); - $this->assertEquals( 0, $component->int ); - $this->assertEquals( false, $component->bool ); - $this->assertEquals( array(), $component->array ); - } - - public function testRenderRemoveComments(): void { - $this->assertEquals( - 'Some text', - $this->render( - '{{--Comment--}}Some text' - ) - ); - } - - public function testRenderSupportsPrintBrackets(): void { - $this->assertEquals( - 'Some text', - $this->render( - 'Some {{ $variable }}', - array( - 'variable' => 'text', - ) - ) - ); - } - - public function testRenderEscapesOutputInBrackets(): void { - $this->assertEquals( - 'Some te"xt', - $this->render( - 'Some {{ $variable }}', - array( - 'variable' => 'te"xt', - ) - ) - ); - } - public function testRenderSupportsUnescapedPrintBrackets(): void { - $this->assertEquals( - 'Some text', - $this->render( - 'Some {!! $variable !!}', - array( - 'variable' => 'text', - ) - ) - ); - } - - public function testRenderNotEscapeOutputInBrackets(): void { - $this->assertEquals( - 'Some te"xt', - $this->render( - 'Some {!! $variable !!}', - array( - 'variable' => 'te"xt', - ) - ) - ); - } - - public function testRenderSupportsFor(): void { - $this->assertEquals( - 'Hi!Hi!', - $this->render( - "@for (\$i = 0; \$i < 2; \$i++)\nHi!@endfor" - ) - ); - } - - public function testRenderSupportsForeach(): void { - $this->assertEquals( - 'Hi!Hi!', - $this->render( - "@foreach (\$items as \$item)\n{{ \$item }}@endforeach", - array( - 'items' => array( 'Hi!', 'Hi!' ), - ) - ) - ); - } - - public function testRenderSupportsIf(): void { - $this->assertEquals( - 'Hi', - $this->render( - "@if (\$variable)\nHi@endif", - array( - 'variable' => true, - ) - ) - ); - } - - public function testRenderSupportsElse(): void { - $this->assertEquals( - ' Second ', - $this->render( - '@if ($variable) - First @else Second @endif', - array( - 'variable' => false, - ) - ) - ); - } - - public function testRenderSupportsPhp(): void { - $this->assertEquals( - 'Hi!', - $this->render( - '@php echo "Hi!"; @endphp' - ) - ); - } - - // @selected. - - public function testRenderSupportsSelectedDirectiveWithTrue(): void { - $this->assertEquals( - 'selected=""', - $this->render( - '@selected($variable)', - array( - 'variable' => true, - ) - ) - ); - } - - public function testRenderSupportsSelectedDirectiveWithFalse(): void { - $this->assertEquals( - '', - $this->render( - '@selected($variable)', - array( - 'variable' => false, - ) - ) - ); - } - - public function testRenderSupportsSelectedDirectiveWithMethod(): void { - $component = new class() extends Component{ - public function selected(): bool { - return true; - } - }; - - $this->assertEquals( - 'selected=""', - $this->render( - '@selected($selected())', - array(), - $component - ) - ); - } - - // @checked. - - public function testRenderSupportsCheckedDirectiveWithTrue(): void { - $this->assertEquals( - 'checked=""', - $this->render( - '@checked($variable)', - array( - 'variable' => true, - ) - ) - ); - } - - public function testRenderSupportsCheckedDirectiveWithFalse(): void { - $this->assertEquals( - '', - $this->render( - '@checked($variable)', - array( - 'variable' => false, - ) - ) - ); - } - - public function testRenderSupportsCheckedDirectiveWithMethod(): void { - $component = new class() extends Component{ - public function checked(): bool { - return true; - } - }; - - $this->assertEquals( - 'checked=""', - $this->render( - '@checked($checked())', - array(), - $component - ) - ); - } - - // methods. - - public function testRenderSupportsComponentMethods(): void { - $component = new class() extends Component{ - public function print(): string { - return 'hello'; - } - }; - - $this->assertEquals( - 'hello', - $this->render( '{{ $print() }}', array(), $component ) - ); - } - - public function testRenderSupportsComponentMethodsWithinIf(): void { - $component = new class() extends Component{ - public function checked(): bool { - return true; - } - }; - - $this->assertEquals( - 'ok', - $this->render( - "@if(\$checked())\nok@endif", - array(), - $component - ) - ); - } - - // @switch. - - public function testRenderSupportsSwitch(): void { - $this->assertEquals( - "First\n", - $this->render( - "@switch(\$variable)\n@case(1)\nFirst\n@break\n@case(2)\nSecond\n@break\n@endswitch", - array( - 'variable' => 1, - ) - ) - ); - } - - public function testRenderSupportsSwitchWithSpaceBeforeFirstCase(): void { - $this->assertEquals( - "First\n", - $this->render( - "@switch(\$variable)\n @case(1)\nFirst\n@break\n@case(2)\nSecond\n@break\n@endswitch", - array( - 'variable' => 1, - ) - ) - ); - } - - // @class. - - public function testRenderSupportsClassDirectiveWithTrue(): void { - $this->assertEquals( - 'class="first third last"', - $this->render( - '@class(["first"=>true,"second"=>false,"third"=>true, "last"])' - ) - ); - } - - // Errors; - - public function testRenderDoesNotThrowErrorIfVariableIsMissing(): void { - $this->assertEquals( - '', - $this->render( - '{{ $variable }}' - ) - ); - } - - public function testRenderDoesNotThrowErrorIfVariableHasWrongCharacters(): void { - $this->assertEquals( - '', - $this->render( - '{{ $41 }}' - ) - ); - } - - public function testRenderDoesNotThrowErrorIfWrongFunctionIsCalled(): void { - $this->assertEquals( - '', - $this->render( - '{{ some_function() }}' - ) - ); - } - - - - protected function getComponents() { - $components = Mockery::mock( Component_Renderer::class )->makePartial(); - - $components->shouldAllowMockingProtectedMethods(); - $components->shouldReceive( 'get_cache_key' ) - ->andReturn( null ); - - return $components; - } - - protected function render( string $rough_template, array $variables = array(), $component = null ): string { - $bladeTemplates = new Blade_Templates(); - $template = $bladeTemplates->compile( $rough_template ); - - $components = $this->getComponents(); - $components->shouldReceive( 'get_template' ) - ->andReturn( $template ); - $components->shouldReceive( 'get_cache_key' ) - ->andReturn( null ); - - if ( null === $component ) { - $component = Mockery::mock( Component::class )->makePartial(); - - $component->shouldReceive( 'get_variable_values' ) - ->andReturn( $variables ); - } - - return $components->render( - $component, - null, - true - ); - }//end render() -} diff --git a/php-code-quality-tools/phpstan.neon b/php-code-quality-tools/phpstan.neon deleted file mode 100644 index 93df49e..0000000 --- a/php-code-quality-tools/phpstan.neon +++ /dev/null @@ -1,8 +0,0 @@ -parameters: - level: 9 - paths: - - ../prosopo-procaptcha - scanDirectories: - - ./stubs - excludePaths: - - ../prosopo-procaptcha/lang diff --git a/php-code-quality-tools/templates/all.blade.php b/php-code-quality-tools/templates/all.blade.php deleted file mode 100644 index 0debec3..0000000 --- a/php-code-quality-tools/templates/all.blade.php +++ /dev/null @@ -1,57 +0,0 @@ -{{--it's a comment--}} - -
{{ $var }}
- -
{!! $html !!}
- -@for($i = 0; $i < 3; $i++)item@endfor - -@for($i = 0; $i < 3; $i++) -- item -@endfor - -@foreach($items as $item)item@endforeach - -@foreach($items as $item) -- item -@endforeach - -@if($var)item@endif - -@if($var) --item -@endif - -@if($var) --first -@elseif($var2) --second -@else --third -@endif - -@php -$a = 1; -@endphp - -@use('my\package') - -@use("my\package") - -@selected($var) - -@checked($var) - -@class(['first', -'second' => $var]) - -@switch($var) -@case(1) -- first -@break -@case(2) -- second -@break -@default -- default -@endswitch \ No newline at end of file diff --git a/php-code-quality-tools/templates/all.php b/php-code-quality-tools/templates/all.php deleted file mode 100644 index a7fa686..0000000 --- a/php-code-quality-tools/templates/all.php +++ /dev/null @@ -1,63 +0,0 @@ - - -
- -
- -item - - -- item - - -item - - -- item - - -item - - --item - - - --first - --second - --third - - - - - - - - - - - - - $var] as $key => $value ) { -if ( true === is_int( $key ) ) { echo $e($value) . " "; } -else { if ( true === $value ) { echo $e($key) . " "; } } -} -echo trim( (string)ob_get_clean() ); -echo "\""; ?> - - -- first - - -- second - - -- default - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/break.blade.php b/php-code-quality-tools/templates/inline/break.blade.php deleted file mode 100644 index ad5e382..0000000 --- a/php-code-quality-tools/templates/inline/break.blade.php +++ /dev/null @@ -1 +0,0 @@ -@break \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/break.php b/php-code-quality-tools/templates/inline/break.php deleted file mode 100644 index 5f2b230..0000000 --- a/php-code-quality-tools/templates/inline/break.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/case.blade.php b/php-code-quality-tools/templates/inline/case.blade.php deleted file mode 100644 index 5becf80..0000000 --- a/php-code-quality-tools/templates/inline/case.blade.php +++ /dev/null @@ -1 +0,0 @@ -@case(1) \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/case.php b/php-code-quality-tools/templates/inline/case.php deleted file mode 100644 index 5341ab7..0000000 --- a/php-code-quality-tools/templates/inline/case.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/checked.blade.php b/php-code-quality-tools/templates/inline/checked.blade.php deleted file mode 100644 index 079a4cd..0000000 --- a/php-code-quality-tools/templates/inline/checked.blade.php +++ /dev/null @@ -1 +0,0 @@ -@checked($var) \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/checked.php b/php-code-quality-tools/templates/inline/checked.php deleted file mode 100644 index 74a19e0..0000000 --- a/php-code-quality-tools/templates/inline/checked.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/class.blade.php b/php-code-quality-tools/templates/inline/class.blade.php deleted file mode 100644 index 9268546..0000000 --- a/php-code-quality-tools/templates/inline/class.blade.php +++ /dev/null @@ -1 +0,0 @@ -@class(['first', 'second' => $var]) \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/class.php b/php-code-quality-tools/templates/inline/class.php deleted file mode 100644 index 4fab0b6..0000000 --- a/php-code-quality-tools/templates/inline/class.php +++ /dev/null @@ -1,8 +0,0 @@ - $var] as $key => $value ) { -if ( true === is_int( $key ) ) { echo $e($value) . " "; } -else { if ( true === $value ) { echo $e($key) . " "; } } -} -echo trim( (string)ob_get_clean() ); -echo "\""; ?> \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/comment.blade.php b/php-code-quality-tools/templates/inline/comment.blade.php deleted file mode 100644 index ed13ec9..0000000 --- a/php-code-quality-tools/templates/inline/comment.blade.php +++ /dev/null @@ -1,2 +0,0 @@ -{{--it's a comment--}} -
\ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/comment.php b/php-code-quality-tools/templates/inline/comment.php deleted file mode 100644 index 6e4057d..0000000 --- a/php-code-quality-tools/templates/inline/comment.php +++ /dev/null @@ -1,2 +0,0 @@ - -
\ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/default.blade.php b/php-code-quality-tools/templates/inline/default.blade.php deleted file mode 100644 index 87b1c1b..0000000 --- a/php-code-quality-tools/templates/inline/default.blade.php +++ /dev/null @@ -1 +0,0 @@ -@default \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/default.php b/php-code-quality-tools/templates/inline/default.php deleted file mode 100644 index 06b5108..0000000 --- a/php-code-quality-tools/templates/inline/default.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/echo-unescaped.blade.php b/php-code-quality-tools/templates/inline/echo-unescaped.blade.php deleted file mode 100644 index e2428b7..0000000 --- a/php-code-quality-tools/templates/inline/echo-unescaped.blade.php +++ /dev/null @@ -1 +0,0 @@ -
{!! $html !!}
\ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/echo-unescaped.php b/php-code-quality-tools/templates/inline/echo-unescaped.php deleted file mode 100644 index 01f1884..0000000 --- a/php-code-quality-tools/templates/inline/echo-unescaped.php +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/echo.blade.php b/php-code-quality-tools/templates/inline/echo.blade.php deleted file mode 100644 index bdbeb0f..0000000 --- a/php-code-quality-tools/templates/inline/echo.blade.php +++ /dev/null @@ -1 +0,0 @@ -
{{ $var }}
\ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/echo.php b/php-code-quality-tools/templates/inline/echo.php deleted file mode 100644 index f560cb7..0000000 --- a/php-code-quality-tools/templates/inline/echo.php +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/else-if.blade.php b/php-code-quality-tools/templates/inline/else-if.blade.php deleted file mode 100644 index 341c30d..0000000 --- a/php-code-quality-tools/templates/inline/else-if.blade.php +++ /dev/null @@ -1 +0,0 @@ -@elseif($var)another \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/else-if.php b/php-code-quality-tools/templates/inline/else-if.php deleted file mode 100644 index ae8232d..0000000 --- a/php-code-quality-tools/templates/inline/else-if.php +++ /dev/null @@ -1 +0,0 @@ -another \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/else.blade.php b/php-code-quality-tools/templates/inline/else.blade.php deleted file mode 100644 index 40d29cc..0000000 --- a/php-code-quality-tools/templates/inline/else.blade.php +++ /dev/null @@ -1 +0,0 @@ -@else second \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/else.php b/php-code-quality-tools/templates/inline/else.php deleted file mode 100644 index e8b2abb..0000000 --- a/php-code-quality-tools/templates/inline/else.php +++ /dev/null @@ -1 +0,0 @@ - second \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/for.blade.php b/php-code-quality-tools/templates/inline/for.blade.php deleted file mode 100644 index 754184c..0000000 --- a/php-code-quality-tools/templates/inline/for.blade.php +++ /dev/null @@ -1 +0,0 @@ -@for($i = 0; $i < 3; $i++)item@endfor \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/for.php b/php-code-quality-tools/templates/inline/for.php deleted file mode 100644 index b8b0e78..0000000 --- a/php-code-quality-tools/templates/inline/for.php +++ /dev/null @@ -1 +0,0 @@ -item \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/foreach.blade.php b/php-code-quality-tools/templates/inline/foreach.blade.php deleted file mode 100644 index 18434c5..0000000 --- a/php-code-quality-tools/templates/inline/foreach.blade.php +++ /dev/null @@ -1 +0,0 @@ -@foreach($items as $item)item@endforeach \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/foreach.php b/php-code-quality-tools/templates/inline/foreach.php deleted file mode 100644 index 8ced348..0000000 --- a/php-code-quality-tools/templates/inline/foreach.php +++ /dev/null @@ -1 +0,0 @@ -item \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/if.blade.php b/php-code-quality-tools/templates/inline/if.blade.php deleted file mode 100644 index c8ad66f..0000000 --- a/php-code-quality-tools/templates/inline/if.blade.php +++ /dev/null @@ -1 +0,0 @@ -@if($var)item@endif \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/if.php b/php-code-quality-tools/templates/inline/if.php deleted file mode 100644 index 4c19eae..0000000 --- a/php-code-quality-tools/templates/inline/if.php +++ /dev/null @@ -1 +0,0 @@ -item \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/php-closing-tag.blade.php b/php-code-quality-tools/templates/inline/php-closing-tag.blade.php deleted file mode 100644 index 8d64877..0000000 --- a/php-code-quality-tools/templates/inline/php-closing-tag.blade.php +++ /dev/null @@ -1 +0,0 @@ -@endphp item \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/php-closing-tag.php b/php-code-quality-tools/templates/inline/php-closing-tag.php deleted file mode 100644 index 0125e83..0000000 --- a/php-code-quality-tools/templates/inline/php-closing-tag.php +++ /dev/null @@ -1 +0,0 @@ -?> item \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/php-opening-tag.blade.php b/php-code-quality-tools/templates/inline/php-opening-tag.blade.php deleted file mode 100644 index e639d06..0000000 --- a/php-code-quality-tools/templates/inline/php-opening-tag.blade.php +++ /dev/null @@ -1 +0,0 @@ -@php $var; \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/php-opening-tag.php b/php-code-quality-tools/templates/inline/php-opening-tag.php deleted file mode 100644 index 560af4c..0000000 --- a/php-code-quality-tools/templates/inline/php-opening-tag.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/switch-end.blade.php b/php-code-quality-tools/templates/inline/switch-end.blade.php deleted file mode 100644 index 5104954..0000000 --- a/php-code-quality-tools/templates/inline/switch-end.blade.php +++ /dev/null @@ -1 +0,0 @@ -@endswitch \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/switch-end.php b/php-code-quality-tools/templates/inline/switch-end.php deleted file mode 100644 index f0f344b..0000000 --- a/php-code-quality-tools/templates/inline/switch-end.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/switch.blade.php b/php-code-quality-tools/templates/inline/switch.blade.php deleted file mode 100644 index cebdaca..0000000 --- a/php-code-quality-tools/templates/inline/switch.blade.php +++ /dev/null @@ -1 +0,0 @@ -@switch($var)@case(1) \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/switch.php b/php-code-quality-tools/templates/inline/switch.php deleted file mode 100644 index 361189c..0000000 --- a/php-code-quality-tools/templates/inline/switch.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/use-double-quote.blade.php b/php-code-quality-tools/templates/inline/use-double-quote.blade.php deleted file mode 100644 index 2b8e508..0000000 --- a/php-code-quality-tools/templates/inline/use-double-quote.blade.php +++ /dev/null @@ -1 +0,0 @@ -@use("my\package") \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/use-double-quote.php b/php-code-quality-tools/templates/inline/use-double-quote.php deleted file mode 100644 index a3aea8a..0000000 --- a/php-code-quality-tools/templates/inline/use-double-quote.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/use-single-quote.blade.php b/php-code-quality-tools/templates/inline/use-single-quote.blade.php deleted file mode 100644 index 715f460..0000000 --- a/php-code-quality-tools/templates/inline/use-single-quote.blade.php +++ /dev/null @@ -1 +0,0 @@ -@use('my\package') \ No newline at end of file diff --git a/php-code-quality-tools/templates/inline/use-single-quote.php b/php-code-quality-tools/templates/inline/use-single-quote.php deleted file mode 100644 index a3aea8a..0000000 --- a/php-code-quality-tools/templates/inline/use-single-quote.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/class.blade.php b/php-code-quality-tools/templates/multiline/class.blade.php deleted file mode 100644 index 24b93cd..0000000 --- a/php-code-quality-tools/templates/multiline/class.blade.php +++ /dev/null @@ -1,2 +0,0 @@ -@class(['first', -'second' => $var]) \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/class.php b/php-code-quality-tools/templates/multiline/class.php deleted file mode 100644 index ae9d411..0000000 --- a/php-code-quality-tools/templates/multiline/class.php +++ /dev/null @@ -1,9 +0,0 @@ - $var] as $key => $value ) { -if ( true === is_int( $key ) ) { echo $e($value) . " "; } -else { if ( true === $value ) { echo $e($key) . " "; } } -} -echo trim( (string)ob_get_clean() ); -echo "\""; ?> \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/else-if.blade.php b/php-code-quality-tools/templates/multiline/else-if.blade.php deleted file mode 100644 index 1b20b8e..0000000 --- a/php-code-quality-tools/templates/multiline/else-if.blade.php +++ /dev/null @@ -1,2 +0,0 @@ -@elseif($var) --another \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/else-if.php b/php-code-quality-tools/templates/multiline/else-if.php deleted file mode 100644 index 3b343bc..0000000 --- a/php-code-quality-tools/templates/multiline/else-if.php +++ /dev/null @@ -1,2 +0,0 @@ - --another \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/else.blade.php b/php-code-quality-tools/templates/multiline/else.blade.php deleted file mode 100644 index a8d4d3d..0000000 --- a/php-code-quality-tools/templates/multiline/else.blade.php +++ /dev/null @@ -1,2 +0,0 @@ -@else --second \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/else.php b/php-code-quality-tools/templates/multiline/else.php deleted file mode 100644 index 8df8262..0000000 --- a/php-code-quality-tools/templates/multiline/else.php +++ /dev/null @@ -1,2 +0,0 @@ - --second \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/for.blade.php b/php-code-quality-tools/templates/multiline/for.blade.php deleted file mode 100644 index be8d980..0000000 --- a/php-code-quality-tools/templates/multiline/for.blade.php +++ /dev/null @@ -1,3 +0,0 @@ -@for($i = 0; $i < 3; $i++) -- item -@endfor \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/for.php b/php-code-quality-tools/templates/multiline/for.php deleted file mode 100644 index 12b82b5..0000000 --- a/php-code-quality-tools/templates/multiline/for.php +++ /dev/null @@ -1,3 +0,0 @@ - -- item - \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/foreach.blade.php b/php-code-quality-tools/templates/multiline/foreach.blade.php deleted file mode 100644 index 50cbca1..0000000 --- a/php-code-quality-tools/templates/multiline/foreach.blade.php +++ /dev/null @@ -1,3 +0,0 @@ -@foreach($items as $item) -- item -@endforeach \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/foreach.php b/php-code-quality-tools/templates/multiline/foreach.php deleted file mode 100644 index ae37d3b..0000000 --- a/php-code-quality-tools/templates/multiline/foreach.php +++ /dev/null @@ -1,3 +0,0 @@ - -- item - \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/if.blade.php b/php-code-quality-tools/templates/multiline/if.blade.php deleted file mode 100644 index 8b605fc..0000000 --- a/php-code-quality-tools/templates/multiline/if.blade.php +++ /dev/null @@ -1,3 +0,0 @@ -@if($var) --item -@endif \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/if.php b/php-code-quality-tools/templates/multiline/if.php deleted file mode 100644 index a87494b..0000000 --- a/php-code-quality-tools/templates/multiline/if.php +++ /dev/null @@ -1,3 +0,0 @@ - --item - \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/php-closing-tag.blade.php b/php-code-quality-tools/templates/multiline/php-closing-tag.blade.php deleted file mode 100644 index b46dd35..0000000 --- a/php-code-quality-tools/templates/multiline/php-closing-tag.blade.php +++ /dev/null @@ -1,2 +0,0 @@ -@endphp -item \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/php-closing-tag.php b/php-code-quality-tools/templates/multiline/php-closing-tag.php deleted file mode 100644 index 35f13c8..0000000 --- a/php-code-quality-tools/templates/multiline/php-closing-tag.php +++ /dev/null @@ -1,2 +0,0 @@ -?> -item \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/php-opening-tag.blade.php b/php-code-quality-tools/templates/multiline/php-opening-tag.blade.php deleted file mode 100644 index 45b9388..0000000 --- a/php-code-quality-tools/templates/multiline/php-opening-tag.blade.php +++ /dev/null @@ -1,2 +0,0 @@ -@php -$var; \ No newline at end of file diff --git a/php-code-quality-tools/templates/multiline/php-opening-tag.php b/php-code-quality-tools/templates/multiline/php-opening-tag.php deleted file mode 100644 index 43440a5..0000000 --- a/php-code-quality-tools/templates/multiline/php-opening-tag.php +++ /dev/null @@ -1,2 +0,0 @@ -getFilesByExtension( __DIR__ . '/../../templates', $extension ); - $inline = $this->getFilesByExtension( __DIR__ . '/../../templates/inline', $extension ); - $multiline = $this->getFilesByExtension( __DIR__ . '/../../templates/multiline', $extension ); - - return array_merge( $all, $inline, $multiline ); - } - - public function getTemplate( string $file ): string { - if ( false === file_exists( $file ) ) { - throw new Exception( 'Template is not found: ' . $file ); - } - - return (string) file_get_contents( $file ); - } - - /** - * @return string[] - */ - protected function getFilesByExtension( string $directory, string $fileExtension ): array { - if ( false === is_dir( $directory ) || - false === is_readable( $directory ) ) { - return array(); - } - - $files = scandir( $directory ); - - if ( false === $files ) { - return array(); - } - - $fileNames = array_filter( - $files, - function ( string $file ) use ( $directory, $fileExtension ) { - $filePath = $directory . DIRECTORY_SEPARATOR . $file; - - return true === is_file( $filePath ) && - substr( $file, -strlen( $fileExtension ) ) === $fileExtension; - } - ); - - return array_map( - fn( string $fileName ) => $directory . DIRECTORY_SEPARATOR . str_replace( $fileExtension, '', $fileName ), - $fileNames - ); - } -} diff --git a/php-code-quality-tools/tests/Unit/BladeCompilerTest.php b/php-code-quality-tools/tests/Unit/BladeCompilerTest.php deleted file mode 100644 index 27741d3..0000000 --- a/php-code-quality-tools/tests/Unit/BladeCompilerTest.php +++ /dev/null @@ -1,55 +0,0 @@ -getTemplatesByExtension( '.blade.php' ); - - $testArguments = array_map( - fn( string $template ) => array( $template, 'e' ), - $templates - ); - - $testNames = array_map( - function ( string $template ) { - $fileName = pathinfo( $template, PATHINFO_FILENAME ); - $pureFileName = str_replace( '.blade', '', $fileName ); - - $shortDirName = basename( dirname( $template ) ); - - return $shortDirName . '/' . $pureFileName; - }, - $templates - ); - - return array_combine( $testNames, $testArguments ); - } - - #[DataProvider( 'templateNamesProvider' )] - public function testTemplateCompilation( string $template, string $escape_callback_name ): void { - $compiler = $this->getCompiler(); - - $templatesHelper = self::getTemplatesHelper(); - $phpTemplate = $templatesHelper->getTemplate( $template . '.php' ); - $bladeTemplate = $templatesHelper->getTemplate( $template . '.blade.php' ); - - $compiledPhp = $compiler->compile( $bladeTemplate, $escape_callback_name ); - - $this->assertEquals( $phpTemplate, $compiledPhp, 'Failed to compile template: ' . pathinfo( $template, PATHINFO_FILENAME ) ); - } - - protected function getCompiler(): Template_Compiler_Interface { - return new Blade_Compiler(); - } -} diff --git a/php-code-quality-tools/tests/Unit/CollectionTest.php b/php-code-quality-tools/tests/Unit/CollectionTest.php deleted file mode 100644 index 537e97e..0000000 --- a/php-code-quality-tools/tests/Unit/CollectionTest.php +++ /dev/null @@ -1,53 +0,0 @@ - 1 ) ); - - $collection->merge( array( 'item' => 2 ) ); - - $this->assertEquals( array( 'item' => 2 ), $collection->to_array() ); - } - - public function testMergeDoesNotOverrideWhenFlagIsSet(): void { - $collection = new Collection( array( 'item' => 1 ) ); - - $collection->merge( array( 'item' => 2 ), true ); - - $this->assertEquals( array( 'item' => 1 ), $collection->to_array() ); - } - - public function testGetSubCollectionStaysLinkedInTheParent(): void { - $collection = new Collection( array( 'item' => array( 'sub' => 1 ) ) ); - - $sub_collection = $collection->get_sub_collection( 'item' ); - $sub_collection->add( 'sub', 2 ); - - $this->assertEquals( array( 'item' => array( 'sub' => 2 ) ), $collection->to_array() ); - } - - public function testMergeHtmlAttrsForClass() { - $first = new Collection( array( 'class' => 'first' ) ); - $second = new Collection( array( 'class' => 'second' ) ); - - $this->assertEquals( - 'first second', - $first->merge_html_attrs( $second )->get_string( 'class' ) - ); - } - - public function testMergeHtmlAttrsForStyle() { - $first = new Collection( array( 'style' => 'color:red' ) ); - $second = new Collection( array( 'style' => 'background:blue' ) ); - - $this->assertEquals( - 'color:red;background:blue', - $first->merge_html_attrs( $second )->get_string( 'style' ) - ); - } -} diff --git a/php-code-quality-tools/.gitignore b/php-tools/code-quality/.gitignore similarity index 100% rename from php-code-quality-tools/.gitignore rename to php-tools/code-quality/.gitignore diff --git a/php-code-quality-tools/composer.json b/php-tools/code-quality/composer.json similarity index 76% rename from php-code-quality-tools/composer.json rename to php-tools/code-quality/composer.json index d4bc47e..0f381e9 100644 --- a/php-code-quality-tools/composer.json +++ b/php-tools/code-quality/composer.json @@ -2,7 +2,6 @@ "config": { "allow-plugins": { "composer/installers": true, - "phpstan/extension-installer": true, "dealerdirect/phpcodesniffer-composer-installer": true, "pestphp/pest-plugin": true }, @@ -12,7 +11,6 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", - "phpstan/extension-installer": "^1.3", "szepeviktor/phpstan-wordpress": "^1.3", "phpstan/phpstan-strict-rules": "^1.5", "squizlabs/php_codesniffer": "^3.8", @@ -23,8 +21,8 @@ }, "scripts": { "phpstan": "./vendor/bin/phpstan analys -c phpstan.neon", - "phpcs": "./vendor/bin/phpcs --standard=WordPress", - "phpcbf": "./vendor/bin/phpcbf --standard=WordPress", + "phpcs": "./vendor/bin/phpcs --standard=./wp-ruleset.xml", + "phpcbf": "./vendor/bin/phpcbf --standard=./wp-ruleset.xml", "pest": "./vendor/bin/pest" } } diff --git a/php-code-quality-tools/composer.lock b/php-tools/code-quality/composer.lock similarity index 98% rename from php-code-quality-tools/composer.lock rename to php-tools/code-quality/composer.lock index de46b8c..3781a00 100644 --- a/php-code-quality-tools/composer.lock +++ b/php-tools/code-quality/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3b99cb49c4bf6d56ceaa451f43fc23b3", + "content-hash": "7390d4c762fc5c17d8eed3fe5c0ecbed", "packages": [], "packages-dev": [ { @@ -1683,54 +1683,6 @@ }, "time": "2024-11-09T15:12:26+00:00" }, - { - "name": "phpstan/extension-installer", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/phpstan/extension-installer.git", - "reference": "85e90b3942d06b2326fba0403ec24fe912372936" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", - "reference": "85e90b3942d06b2326fba0403ec24fe912372936", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.0", - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.0 || ^2.0" - }, - "require-dev": { - "composer/composer": "^2.0", - "php-parallel-lint/php-parallel-lint": "^1.2.0", - "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPStan\\ExtensionInstaller\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPStan\\ExtensionInstaller\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Composer plugin for automatic installation of PHPStan extensions", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" - }, - "time": "2024-09-04T20:21:43+00:00" - }, { "name": "phpstan/phpdoc-parser", "version": "1.33.0", diff --git a/php-tools/code-quality/phpstan.neon b/php-tools/code-quality/phpstan.neon new file mode 100644 index 0000000..e7c93c7 --- /dev/null +++ b/php-tools/code-quality/phpstan.neon @@ -0,0 +1,13 @@ +parameters: + level: 9 + paths: + - ../../prosopo-procaptcha + scanDirectories: + - ./stubs + excludePaths: + - ../../prosopo-procaptcha/lang + analyse: + - ../../prosopo-procaptcha/prefixed-vendors +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/szepeviktor/phpstan-wordpress/extension.neon diff --git a/php-code-quality-tools/phpunit.xml b/php-tools/code-quality/phpunit.xml similarity index 100% rename from php-code-quality-tools/phpunit.xml rename to php-tools/code-quality/phpunit.xml diff --git a/php-code-quality-tools/stubs/Fluent_Forms_BaseFieldManager.php b/php-tools/code-quality/stubs/Fluent_Forms_BaseFieldManager.php similarity index 100% rename from php-code-quality-tools/stubs/Fluent_Forms_BaseFieldManager.php rename to php-tools/code-quality/stubs/Fluent_Forms_BaseFieldManager.php diff --git a/php-code-quality-tools/stubs/Formidable_Forms_FieldType.php b/php-tools/code-quality/stubs/Formidable_Forms_FieldType.php similarity index 100% rename from php-code-quality-tools/stubs/Formidable_Forms_FieldType.php rename to php-tools/code-quality/stubs/Formidable_Forms_FieldType.php diff --git a/php-code-quality-tools/stubs/Gravity_Forms_Field.php b/php-tools/code-quality/stubs/Gravity_Forms_Field.php similarity index 100% rename from php-code-quality-tools/stubs/Gravity_Forms_Field.php rename to php-tools/code-quality/stubs/Gravity_Forms_Field.php diff --git a/php-code-quality-tools/stubs/JetPack_Contact_Form.php b/php-tools/code-quality/stubs/JetPack_Contact_Form.php similarity index 100% rename from php-code-quality-tools/stubs/JetPack_Contact_Form.php rename to php-tools/code-quality/stubs/JetPack_Contact_Form.php diff --git a/php-code-quality-tools/stubs/User_Registration_Form_Field.php b/php-tools/code-quality/stubs/User_Registration_Form_Field.php similarity index 100% rename from php-code-quality-tools/stubs/User_Registration_Form_Field.php rename to php-tools/code-quality/stubs/User_Registration_Form_Field.php diff --git a/php-code-quality-tools/stubs/WPForms_Field.php b/php-tools/code-quality/stubs/WPForms_Field.php similarity index 100% rename from php-code-quality-tools/stubs/WPForms_Field.php rename to php-tools/code-quality/stubs/WPForms_Field.php diff --git a/php-code-quality-tools/stubs/elementor/Ajax_Handler.php b/php-tools/code-quality/stubs/elementor/Ajax_Handler.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Ajax_Handler.php rename to php-tools/code-quality/stubs/elementor/Ajax_Handler.php diff --git a/php-code-quality-tools/stubs/elementor/Base_Object.php b/php-tools/code-quality/stubs/elementor/Base_Object.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Base_Object.php rename to php-tools/code-quality/stubs/elementor/Base_Object.php diff --git a/php-code-quality-tools/stubs/elementor/Controls_Manager.php b/php-tools/code-quality/stubs/elementor/Controls_Manager.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Controls_Manager.php rename to php-tools/code-quality/stubs/elementor/Controls_Manager.php diff --git a/php-code-quality-tools/stubs/elementor/Controls_Stack.php b/php-tools/code-quality/stubs/elementor/Controls_Stack.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Controls_Stack.php rename to php-tools/code-quality/stubs/elementor/Controls_Stack.php diff --git a/php-code-quality-tools/stubs/elementor/Element_Base.php b/php-tools/code-quality/stubs/elementor/Element_Base.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Element_Base.php rename to php-tools/code-quality/stubs/elementor/Element_Base.php diff --git a/php-code-quality-tools/stubs/elementor/Field_Base.php b/php-tools/code-quality/stubs/elementor/Field_Base.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Field_Base.php rename to php-tools/code-quality/stubs/elementor/Field_Base.php diff --git a/php-code-quality-tools/stubs/elementor/Form_Fields_Registrar.php b/php-tools/code-quality/stubs/elementor/Form_Fields_Registrar.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Form_Fields_Registrar.php rename to php-tools/code-quality/stubs/elementor/Form_Fields_Registrar.php diff --git a/php-code-quality-tools/stubs/elementor/Form_Record.php b/php-tools/code-quality/stubs/elementor/Form_Record.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Form_Record.php rename to php-tools/code-quality/stubs/elementor/Form_Record.php diff --git a/php-code-quality-tools/stubs/elementor/Registrar.php b/php-tools/code-quality/stubs/elementor/Registrar.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Registrar.php rename to php-tools/code-quality/stubs/elementor/Registrar.php diff --git a/php-code-quality-tools/stubs/elementor/Widget_Base.php b/php-tools/code-quality/stubs/elementor/Widget_Base.php similarity index 100% rename from php-code-quality-tools/stubs/elementor/Widget_Base.php rename to php-tools/code-quality/stubs/elementor/Widget_Base.php diff --git a/php-code-quality-tools/stubs/everest-forms/Everest_Forms_Field.php b/php-tools/code-quality/stubs/everest-forms/Everest_Forms_Field.php similarity index 100% rename from php-code-quality-tools/stubs/everest-forms/Everest_Forms_Field.php rename to php-tools/code-quality/stubs/everest-forms/Everest_Forms_Field.php diff --git a/php-code-quality-tools/stubs/everest-forms/Everest_Forms_Task.php b/php-tools/code-quality/stubs/everest-forms/Everest_Forms_Task.php similarity index 100% rename from php-code-quality-tools/stubs/everest-forms/Everest_Forms_Task.php rename to php-tools/code-quality/stubs/everest-forms/Everest_Forms_Task.php diff --git a/php-code-quality-tools/stubs/ninja-forms/Ninja_Forms_Abstracts_Field.php b/php-tools/code-quality/stubs/ninja-forms/Ninja_Forms_Abstracts_Field.php similarity index 100% rename from php-code-quality-tools/stubs/ninja-forms/Ninja_Forms_Abstracts_Field.php rename to php-tools/code-quality/stubs/ninja-forms/Ninja_Forms_Abstracts_Field.php diff --git a/php-code-quality-tools/stubs/ninja-forms/Ninja_Forms_Abstracts_Input.php b/php-tools/code-quality/stubs/ninja-forms/Ninja_Forms_Abstracts_Input.php similarity index 100% rename from php-code-quality-tools/stubs/ninja-forms/Ninja_Forms_Abstracts_Input.php rename to php-tools/code-quality/stubs/ninja-forms/Ninja_Forms_Abstracts_Input.php diff --git a/php-code-quality-tools/tests/Pest.php b/php-tools/code-quality/tests/Pest.php similarity index 100% rename from php-code-quality-tools/tests/Pest.php rename to php-tools/code-quality/tests/Pest.php diff --git a/php-code-quality-tools/tests/TestCase.php b/php-tools/code-quality/tests/TestCase.php similarity index 100% rename from php-code-quality-tools/tests/TestCase.php rename to php-tools/code-quality/tests/TestCase.php diff --git a/php-tools/code-quality/tests/Unit/Html_Attributes_Collection_Test.php b/php-tools/code-quality/tests/Unit/Html_Attributes_Collection_Test.php new file mode 100644 index 0000000..a3481ad --- /dev/null +++ b/php-tools/code-quality/tests/Unit/Html_Attributes_Collection_Test.php @@ -0,0 +1,28 @@ + 'first' ) ); + $second = new Html_Attributes_Collection( array( 'class' => 'second' ) ); + + $this->assertEquals( + 'first second', + $first->merge( $second )->get_items()['class'] + ); + } + + public function testMergeHtmlAttrsForStyle() { + $first = new Html_Attributes_Collection( array( 'style' => 'color:red' ) ); + $second = new Html_Attributes_Collection( array( 'style' => 'background:blue' ) ); + + $this->assertEquals( + 'color:red;background:blue', + $first->merge( $second )->get_items()['style'] + ); + } +} diff --git a/php-code-quality-tools/tests/bootstrap.php b/php-tools/code-quality/tests/bootstrap.php similarity index 71% rename from php-code-quality-tools/tests/bootstrap.php rename to php-tools/code-quality/tests/bootstrap.php index 6a1565a..cea9f27 100644 --- a/php-code-quality-tools/tests/bootstrap.php +++ b/php-tools/code-quality/tests/bootstrap.php @@ -9,4 +9,4 @@ function esc_html( string $var ): string { require_once __DIR__ . '/../vendor/autoload.php'; require_once __DIR__ . '/TestCase.php'; -require_once __DIR__ . '/../../prosopo-procaptcha/autoloader.php'; +require_once __DIR__ . '/../../../prosopo-procaptcha/prefixed-vendors/vendor/scoper-autoload.php'; diff --git a/php-code-quality-tools/wp-ruleset.xml b/php-tools/code-quality/wp-ruleset.xml similarity index 91% rename from php-code-quality-tools/wp-ruleset.xml rename to php-tools/code-quality/wp-ruleset.xml index 13dacad..10d8afc 100644 --- a/php-code-quality-tools/wp-ruleset.xml +++ b/php-tools/code-quality/wp-ruleset.xml @@ -69,9 +69,10 @@ - ../prosopo-procaptcha - ../prosopo-procaptcha/lang/* - ../prosopo-procaptcha/src/views/* + ../../prosopo-procaptcha + /prosopo-procaptcha/lang/* + /prosopo-procaptcha/prefixed-vendors/* + /prosopo-procaptcha/src/views/* \ No newline at end of file diff --git a/php-tools/origin-vendors/.gitignore b/php-tools/origin-vendors/.gitignore new file mode 100644 index 0000000..88e99d5 --- /dev/null +++ b/php-tools/origin-vendors/.gitignore @@ -0,0 +1,2 @@ +vendor +composer.lock \ No newline at end of file diff --git a/php-tools/origin-vendors/composer.json b/php-tools/origin-vendors/composer.json new file mode 100644 index 0000000..768e602 --- /dev/null +++ b/php-tools/origin-vendors/composer.json @@ -0,0 +1,11 @@ +{ + "require": { + "prosopo/views": "^1.0", + "wplake/typed": "^1.1" + }, + "autoload": { + "psr-4": { + "Io\\Prosopo\\Procaptcha\\": "../src" + } + } +} diff --git a/php-tools/scoper/.gitignore b/php-tools/scoper/.gitignore new file mode 100644 index 0000000..19982ea --- /dev/null +++ b/php-tools/scoper/.gitignore @@ -0,0 +1,2 @@ +composer.lock +vendor \ No newline at end of file diff --git a/php-tools/scoper/composer.json b/php-tools/scoper/composer.json new file mode 100644 index 0000000..d5a11d6 --- /dev/null +++ b/php-tools/scoper/composer.json @@ -0,0 +1,10 @@ +{ + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8" + }, + "config": { + "allow-plugins": { + "bamarni/composer-bin-plugin": true + } + } +} diff --git a/php-tools/scoper/scoper.inc.php b/php-tools/scoper/scoper.inc.php new file mode 100644 index 0000000..07c7ade --- /dev/null +++ b/php-tools/scoper/scoper.inc.php @@ -0,0 +1,25 @@ + 'Io\\Prosopo\\Procaptcha\\Vendors', // string|null + 'php-version' => '7.4', // string|null + 'output-dir' => null, // string|null + 'finders' => [ // list + Finder::create()->files()->in('./../origin-vendors') + ], + 'patchers' => [], // list + + 'exclude-files' => [], // list + 'exclude-namespaces' => [ + 'Io\\Prosopo\\Procaptcha' + ], // list + 'exclude-constants' => [], // list + 'exclude-classes' => [], // list + 'exclude-functions' => [], // list +]; \ No newline at end of file diff --git a/php-tools/scoper/vendor-bin/php-scoper/.gitignore b/php-tools/scoper/vendor-bin/php-scoper/.gitignore new file mode 100644 index 0000000..88e99d5 --- /dev/null +++ b/php-tools/scoper/vendor-bin/php-scoper/.gitignore @@ -0,0 +1,2 @@ +vendor +composer.lock \ No newline at end of file diff --git a/php-tools/scoper/vendor-bin/php-scoper/composer.json b/php-tools/scoper/vendor-bin/php-scoper/composer.json new file mode 100644 index 0000000..0827a89 --- /dev/null +++ b/php-tools/scoper/vendor-bin/php-scoper/composer.json @@ -0,0 +1,5 @@ +{ + "require-dev": { + "humbug/php-scoper": "^0.18.15" + } +} diff --git a/prosopo-procaptcha/autoloader.php b/prosopo-procaptcha/autoloader.php index 88a1dbf..c64e011 100644 --- a/prosopo-procaptcha/autoloader.php +++ b/prosopo-procaptcha/autoloader.php @@ -1,11 +1,7 @@ + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/InstalledVersions.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..15e6019 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/InstalledVersions.php @@ -0,0 +1,313 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Io\Prosopo\Procaptcha\Vendors\Composer; + +use Io\Prosopo\Procaptcha\Vendors\Composer\Autoload\ClassLoader; +use Io\Prosopo\Procaptcha\Vendors\Composer\Semver\VersionParser; +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + /** + * @var bool|null + */ + private static $canGetVendors; + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + if (1 === \count($packages)) { + return $packages[0]; + } + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + return $packagesByType; + } + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = \true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === \false; + } + } + return \false; + } + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + return $provided->matches($constraint); + } + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + return implode(' || ', $ranges); + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + return $installed['versions'][$packageName]['version']; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + return $installed['versions'][$packageName]['pretty_version']; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + return $installed['versions'][$packageName]['reference']; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + return $installed[0]['root']; + } + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', \E_USER_DEPRECATED); + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + return self::$installed; + } + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Io\Prosopo\Procaptcha\Vendors\Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + $installed = array(); + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir . '/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir . '/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; + if (null === self::$installed && strtr($vendorDir . '/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + if (self::$installed !== array()) { + $installed[] = self::$installed; + } + return $installed; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/LICENSE b/prosopo-procaptcha/prefixed-vendors/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_classmap.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..0fb0a2c --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_files.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_files.php new file mode 100644 index 0000000..4a80b0d --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_files.php @@ -0,0 +1,10 @@ + $vendorDir . '/wplake/typed/src/functions.php', +); diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_namespaces.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..15a2ff3 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/wplake/typed/src'), + 'Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\PrivateClasses\\' => array($vendorDir . '/prosopo/views/private-classes'), + 'Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\' => array($vendorDir . '/prosopo/views/src'), + 'Io\\Prosopo\\Procaptcha\\' => array($baseDir . '/../src'), +); diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_real.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_real.php new file mode 100644 index 0000000..902f27f --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_real.php @@ -0,0 +1,50 @@ +register(true); + + $filesToLoad = \Composer\Autoload\ComposerStaticInit043dd16cfbc09f98741d61dc32af3bc2::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + + return $loader; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_static.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_static.php new file mode 100644 index 0000000..a93915a --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/autoload_static.php @@ -0,0 +1,55 @@ + __DIR__ . '/..' . '/wplake/typed/src/functions.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'I' => + array ( + 'Io\\Prosopo\\Procaptcha\\Vendors\\WPLake\\Typed\\' => 43, + 'Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\PrivateClasses\\' => 59, + 'Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\' => 44, + 'Io\\Prosopo\\Procaptcha\\' => 22, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Io\\Prosopo\\Procaptcha\\Vendors\\WPLake\\Typed\\' => + array ( + 0 => __DIR__ . '/..' . '/wplake/typed/src', + ), + 'Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\PrivateClasses\\' => + array ( + 0 => __DIR__ . '/..' . '/prosopo/views/private-classes', + ), + 'Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\' => + array ( + 0 => __DIR__ . '/..' . '/prosopo/views/src', + ), + 'Io\\Prosopo\\Procaptcha\\' => + array ( + 0 => __DIR__ . '/../..' . '/../src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit043dd16cfbc09f98741d61dc32af3bc2::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit043dd16cfbc09f98741d61dc32af3bc2::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit043dd16cfbc09f98741d61dc32af3bc2::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/installed.json b/prosopo-procaptcha/prefixed-vendors/vendor/composer/installed.json new file mode 100644 index 0000000..416f955 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/installed.json @@ -0,0 +1,116 @@ +{ + "packages": [ + { + "name": "prosopo\/views", + "version": "1.0.3", + "version_normalized": "1.0.3.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/prosopo\/php-views.git", + "reference": "7fbc426521a94700f48358e877a1b51fab850247" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/prosopo\/php-views\/zipball\/7fbc426521a94700f48358e877a1b51fab850247", + "reference": "7fbc426521a94700f48358e877a1b51fab850247", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "time": "2024-12-19T16:01:27+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\": "src\/", + "Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\PrivateClasses\\": "private-classes" + } + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Maxim Akimov", + "homepage": "https:\/\/github.com\/light-source\/" + } + ], + "description": "Blazing fast Views with model-driven approach, Blade and multi-namespace support.", + "homepage": "https:\/\/github.com\/prosopo\/php-views", + "keywords": [ + "blade", + "models", + "templates", + "twig", + "views" + ], + "support": { + "issues": "https:\/\/github.com\/prosopo\/php-views\/issues", + "source": "https:\/\/github.com\/prosopo\/php-views\/tree\/1.0.3" + }, + "install-path": "..\/prosopo\/views" + }, + { + "name": "wplake\/typed", + "version": "1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/WPLake\/PHP-Typed.git", + "reference": "c0477d58d4530dba4471a5e64c5523018b2d01d8" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/WPLake\/PHP-Typed\/zipball\/c0477d58d4530dba4471a5e64c5523018b2d01d8", + "reference": "c0477d58d4530dba4471a5e64c5523018b2d01d8", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "require-dev": { + "pestphp\/pest": "^3.7", + "phpstan\/phpstan": "^2.0", + "phpstan\/phpstan-strict-rules": "^2.0", + "slevomat\/coding-standard": "^8.15", + "squizlabs\/php_codesniffer": "^3.11" + }, + "time": "2024-12-20T22:14:10+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + ".\/src\/functions.php" + ], + "psr-4": { + "Io\\Prosopo\\Procaptcha\\Vendors\\WPLake\\Typed\\": ".\/src" + } + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "WPLake", + "homepage": "https:\/\/github.com\/WPLake\/" + } + ], + "description": "Lightweight PHP utility for seamless type-casting and data retrieval from dynamic variables, arrays, and objects.", + "homepage": "https:\/\/github.com\/WPLake\/typed", + "keywords": [ + "cast", + "type" + ], + "support": { + "issues": "https:\/\/github.com\/WPLake\/PHP-Typed\/issues", + "source": "https:\/\/github.com\/WPLake\/PHP-Typed\/tree\/1.1.1" + }, + "install-path": "..\/wplake\/typed" + } + ], + "dev": true, + "dev-package-names": [] +} \ No newline at end of file diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/installed.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/installed.php new file mode 100644 index 0000000..0b57c45 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/installed.php @@ -0,0 +1,5 @@ + array('name' => '__root__', 'pretty_version' => 'dev-main', 'version' => 'dev-main', 'reference' => 'ba586d508bcda7eea75893de51889fee1fe346d2', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => \true), 'versions' => array('__root__' => array('pretty_version' => 'dev-main', 'version' => 'dev-main', 'reference' => 'ba586d508bcda7eea75893de51889fee1fe346d2', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => \false), 'prosopo/views' => array('pretty_version' => '1.0.3', 'version' => '1.0.3.0', 'reference' => '7fbc426521a94700f48358e877a1b51fab850247', 'type' => 'library', 'install_path' => __DIR__ . '/../prosopo/views', 'aliases' => array(), 'dev_requirement' => \false), 'wplake/typed' => array('pretty_version' => '1.1.1', 'version' => '1.1.1.0', 'reference' => 'c0477d58d4530dba4471a5e64c5523018b2d01d8', 'type' => 'library', 'install_path' => __DIR__ . '/../wplake/typed', 'aliases' => array(), 'dev_requirement' => \false))); diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/composer/platform_check.php b/prosopo-procaptcha/prefixed-vendors/vendor/composer/platform_check.php new file mode 100644 index 0000000..580fa96 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70400)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/LICENSE b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/README.md b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/README.md new file mode 100644 index 0000000..a291659 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/README.md @@ -0,0 +1,899 @@ +# PHP Views + +> **PHP Views** is a Composer package designed to simplify templating in PHP. It introduces a model-driven approach, +> supports +> multiple namespaces, and includes a custom [Blade](https://laravel.com/docs/11.x/blade) implementation as the default +> template engine. + +## Table of Contents + +[1. Introduction](#1-introduction) +[2. Installation and minimal usage](#2-installation-and-minimal-usage) +[3. Model-driven approach](#3-model-driven-approach) +[4. Views Manager](#4-views-manager) +[5. View Renderer](#5-view-renderer) +[6. Contribution](#6-contribution) +[7. Credits](#7-credits) + +## 1. Introduction + +While many PHP frameworks come with their own solutions for views, there are countless PHP projects without a templating +system (including CMS, like WordPress). Writing pure PHP templates can be cumbersome and error-prone. PHP Views aims to +make templating simple, flexible, and accessible to anyone. + +### Freedom to choose your template engine + +This package includes a custom [Blade](https://laravel.com/docs/11.x/blade) compiler and uses it as the default template +engine. +However, flexibility is key. You can integrate [Twig](https://twig.symfony.com/), or any other template engine, with +just a few lines of code while +still enjoying the benefits of the model-driven approach and other features that PHP Views brings to the table. + +### Package Benefits + +* **Blazing fast**: Outperforms the original Laravel Blade (see the benchmark below). +* **Zero Dependencies**: Lightweight and easy to integrate into any project. +* **Wide Compatibility**: PHP 7.4+, 8.0+ +* [SOLID architecture](https://en.wikipedia.org/wiki/SOLID): Designed with flexibility in mind, allowing you to easily + override modules to meet your specific requirements +* **Namespace Support**: Seamlessly manage multiple templates under a unified, structured approach. +* **Reliable**: Thoroughly tested with [Pest](https://pestphp.com/) and checked by [PHPStan](https://phpstan.org/). + +### Usage flexibility + +The strength of this package lies in its flexibility. With PHP Views, you’re free to use it in a way that best fits your +project: + +* **As a Views provider:** Combine a model-driven approach with the built-in Blade engine for clean, dynamic templates. +* **As a standalone Blade engine:** Use its custom Blade implementation for your Blade-based templates. +* **For Model-Driven Flexibility:** Leverage the model-driven approach with any template engine, such + as [Twig](https://twig.symfony.com/) or even pure PHP. +* **As a Template Connector:** Integrate and unify templates that utilize different engines under one system. + +### Benchmark + +We conducted a [PHP performance benchmark](https://github.com/prosopo/php-views/blob/main/benchmark/src/Benchmark.php) +to compare this package with the Laravel's Blade (mocked using [jenssegers/blade](https://github.com/jenssegers/blade)) +and [Twig](https://twig.symfony.com/). Here are the results for 1000x renders: + +| Contestant | First Rendering, MS | Cached Rendering, MS | +|----------------------------------------|---------------------|----------------------| +| `prosopo/views` (without models) | 19.75 | 19.75 (no cache atm) | +| `prosopo/views` (with models) | 43.78 | 43.78 (no cache atm) | +| `illuminate/view` (Blade from Laravel) | 181.24 | 56.77 ms | +| `twig/twig` | 441.13 | 9.47 ms | + +The numbers speak for themselves. In uncached rendering, even with model class-related overhead, PHP Views’ +implementation significantly outperforms all competitors. While Twig offers a robust caching solution, PHP Views still +delivers better performance even than Laravel's Blade engine with caching. + +We used the following package versions: + +* [illuminate/view](https://packagist.org/packages/illuminate/view) `11.7.0` +* [twig/twig](https://packagist.org/packages/twig/twig) `3.17.1` +* [jenssegers/blade](https://packagist.org/packages/jenssegers/blade) `2.0.1` + +Since the [benchmark](https://github.com/prosopo/php-views/blob/main/benchmark/src/Benchmark.php) is included in this +repository, you can easily run it locally to verify the results. + +1. `git clone https://github.com/prosopo/php-views.git` +2. `composer install; cd benchmark; composer install` +3. `php benchmark {1000}` - pass your renders count + +## 2. Installation and minimal usage + +### 2.1) Installation + +PHP Views is distributed as a Composer package, making installation straightforward: + +`composer require prosopo/views` + +After installation, ensure that your application includes the Composer autoloader (if it hasn’t been included already): + +`require __DIR__ . '/vendor/autoload.php';` + +### 2.2) Minimal setup + +To get started, you’ll need to create three instances: `ViewTemplateRenderer`, `ViewNamespaceConfig`, and +`ViewsManager`. + +The main configuration takes place in `ViewNamespaceConfig`, where you define the folder for your templates and the root +namespace for the associated models. + +```php +use Prosopo\Views\View\ViewNamespaceConfig; +use Prosopo\Views\View\ViewTemplateRenderer; +use Prosopo\Views\ViewsManager; + +require __DIR__ . '/vendor/autoload.php'; + +// 1. Make the Template Renderer. +// (By default it uses the built-in Blade, but you can connect any) + +$viewTemplateRenderer = new ViewTemplateRenderer(); + +// 2. Make the namespace config + +$namespaceConfig = (new ViewNamespaceConfig($viewTemplateRenderer)) + ->setTemplatesRootPath(__DIR__ . './templates') + ->setTemplateFileExtension('.blade.php'); + +// 3. Make the Views Manager instance: + +$viewsManager = new ViewsManager(); + +// 4. Add the root namespace of your Template Models + +$viewsManager->registerNamespace('MyPackage\Views', $namespaceConfig); +``` + +### 2.3) Model definition + +Now you're ready to create your first model. Similar to many frameworks, such as Laravel, this package embraces a +model-driven approach to templates. + +Each template is paired with its own Model, where the Model's public properties and +methods act as arguments available within the template. + +Model class must extend the `BaseTemplateModel` class or implement the `TemplateModelInterface`: + +```php +namespace MyPackage\Views; + +use Prosopo\Views\BaseTemplateModel; + +class EmployeeTemplateModel extends BaseTemplateModel +{ + public int $salary; + public int $bonus; + public CompanyTemplateModel $company; + + public function total(): int + { + return $this->salary + $this->bonus; + } +} +``` + +Model template (Blade is used in this example): + +```php +

+Your month income is {{ $total() }}, +from which {{ $salary }} is a salary, and {{ $bonus }} is a bonus. +Est. taxes: {{ $company->calcTaxes($salary) }} +

+ +

Company info:

+ +{!! $company !!} +``` + +As you can see, all the public properties of the model are accessible within the template, including nested models like +`$company`. This also enables you to call their public methods directly within the template. + +The `BaseTemplateModel` class which we inherited overrides the `__toString()` method, allowing inner models to be +rendered as strings using [Blade echo statements](https://laravel.com/docs/11.x/blade) with the HTML support. For +instance: + +`{!! $innerModel !!}` part of the template will render the model and print the result. + +> Naming clarification: this package `does not require` the `Model suffix` in the names of model classes. In this +> document, we use +> the +> Model suffix for class names purely for demonstration purposes. + +### 2.4) Automated templates matching + +The built-in `ModelTemplateResolver` automatically matches templates based on the Model names and their relative +namespaces. This automates the process of associating templates with their corresponding Models. + +Example: + +- src/ + - Views/ + - `Homepage.php` + - Settings + - `GeneralSettings.php` + - templates/ + - `homepage{.blade.php}` + - settings/ + - `general-settings{.blade.php}` + +We define the root templates folder along with the models root namespace in the `ViewsNamespaceConfig` (as we already +did above): + +```php +$namespaceConfig = (new ViewNamespaceConfig($viewTemplateRenderer)) + ->setTemplatesRootPath(__DIR__ . './templates') + ->setTemplateFileExtension('.blade.php'); + +// 3. Make the Views Manager instance: + +$viewsManager = new ViewsManager(); + +// 4. Add the root namespace of your Template Models + +$viewsManager->registerNamespace('MyPackage\Views', $namespaceConfig); +``` + +**Naming Note:** Use dashes in template names, as `camelCase` in Model names is automatically converted to +`dash-separated` +names. + +### 2.5) Usage + +The `ViewsManager` instance (which we created during the setup) provides the `createModel` and `renderModel` methods. + +You can create, set values, and render a Model in a single step using the callback argument of the `renderView` method, +as shown below: + +```php +echo $viewsManager->renderModel( + EmployeeTemplateModel::class, + function (EmployeeTemplateModel $employee) use ($salary, $bonus) { + $employee->salary = $salary; + $employee->bonus = $bonus; + } +); +``` + +This approach enables a functional programming style when working with Models. + +**Multi-step creation and rendering** + +When you need split creation, call the `makeModel` method to create the model, and then render later when you need it. + +```php +$employee = $viewsManager->createModel(EmployeeTemplateModel::class); + +// ... + +$employee->salary = $salary; +$employee->bonus = $bonus; + +// ... + +echo $views->renderModel($employee); + +// Tip: you can pass the callback as the second argument for both createModel() and renderModel() models +// to customize the Model properties before returning/rendering. +``` + +**References Advice** + +The `ViewsManager` class implements three interfaces: `ViewNamespaceManagerInterface` for `registerNamespace`, +`ModelFactoryInterface` for `createModel`, and `ModelRendererInterface` for `renderModel`. + +When passing the `ViewsManager` instance to your methods, use one of these interfaces as the argument type instead of +the `ViewsManager` class itself. + +This approach ensures that only the specific actions you expect are accessible, promoting cleaner and more maintainable +code. + +> That's it! You’re now ready to start using the package. In the sections below, we'll dive deeper into its +> configuration and implementation details. + +## 3. Model-driven approach + +This package embraces a model-driven approach to templates. Each template is paired with its own Model, where the +Model's public properties and methods act as arguments available within the template. + +Model class must extend the `BaseTemplateModel` class or implement the `TemplateModelInterface`: + +```php +namespace MyPackage\Views; + +use Prosopo\Views\BaseTemplateModel; + +class EmployeeTemplateModel extends BaseTemplateModel +{ + public int $salary; + public int $bonus; +} +``` + +Public model properties intended for use in the template must have a defined type. By default, any public properties +without a type will be ignored. + +> Naming clarification: This package `does not require` the `Model suffix` in the names of model classes. In this +> document, we use +> the Model +> suffix +> for class names purely for demonstration purposes. + +### 3.1) Benefits + +1. Typed variables: Eliminate the hassle of type matching and renaming associated with array-driven variables. +2. Reduced Routine: During object creation, public fields of the model without default values are automatically + initialized with default values. +3. Enhanced Access: Public methods are made available to the template alongside the variables. +4. Unified Interface: Use the `TemplateModelInterface` in your application when accepting or returning a Model to + maintain + flexibility and avoid specifying the exact component. + +### 3.2) Inner models + +Model can contain one or more nested models or even an array of models. To allow flexibility in deciding the model +type later, define its type as `TemplateModelInterface`. + +This approach enables you to assign any model to this field +during data loading. However, if you want to restrict the field to a specific model, you can define its exact class +type: + +```php +namespace MyPackage\Views; + +use Prosopo\Views\BaseTemplateModel; +use Prosopo\Views\Interfaces\Model\TemplateModelInterface; + +class EmployeeTemplateModel extends BaseTemplateModel +{ + // Use the abstract interface to accept any Model. + public TemplateModelInterface $innerModel; + // Use a specific class only when you want to restrict the usage to it. + public CompanyTemplateModel $company; +} +``` + +By default, inner models are passed to templates as objects, enabling you to call their public methods directly. For +example: + +`{{ $$innerModel->calc($localVar) }}`. + +The `BaseTemplateModel` class overrides the `__toString()` method, allowing inner models to be rendered as strings using +echo statements, which supports HTML output. For instance: + +`{!! $innerModel !!}` will render the model and print the result. + +If you prefer, you can configure the `ViewsManager` to pass models as strings instead of objects. Refer to the [ +ViewsManager section](#4-views-manager) for details. + +### 3.3) Custom property defaults + +Note: In the `TemplateModel` class, in order to satisfy the Model factory, the constructor is marked as final. If you +need to +set custom default values, consider using one of the following approaches: + +```php +namespace MyPackage\Views; + +use Prosopo\Views\BaseTemplateModel; + +class EmployeeTemplateModel extends BaseTemplateModel +{ + // approach for plain field types. + public int $varWithCustomDefaultValue = 'custom default value'; + public Company $company; + + protected function setCustomDefaults(): void + { + // approach for object field types. + $this->company = new Company(); + } +} +``` + +> Tip: If your app Models require additional object dependencies, you can override the `PropertyValueProvider` +> module to +> integrate with a Dependency Injection container like [PHP-DI](https://php-di.org/). This allows model properties to be +> automatically resolved +> while object creation by your application's DI system. + +### 3.4) Custom Model implementation (advanced usage) + +The only requirement for a Model is to implement the `TemplateModelInterface`. This means you can transform any class +into a Model without needing to extend a specific base class, or even define public properties: + +```php +namespace MyPackage\Views; + +use Prosopo\Views\Interfaces\Model\TemplateModelInterface; + +class AnyClass implements TemplateModelInterface +{ + public function getTemplateArguments(): array + { + // you can fill out arguments from any source or define manually. + return [ + 'name' => 'value', + ]; + } +} +``` + +Note: If you plan to define inner models, remember that the default `__toString()` implementation is not provided. You +will need to either implement it yourself or enable the option to pass models as strings in the `ViewsManager` +configuration: + +```php +$namespaceConfig->setModelsAsStringsInTemplates(true); +``` + +When this option is enabled, the renderer will automatically convert objects implementing `TemplateModelInterface` into +strings before passing them to the template. + +## 4. Views Manager + +The `ViewsManager` class provides the `registerNamespace`, `createModel` and `renderModel` methods. It acts as a +namespace manager and brings together different namespace configurations. + +Each `ViewNamespace` has its own independent setup and set of modules. E.g. among these modules is the +`ModelTemplateProvider`, which automates the process of linking models to their +corresponding templates. + +### 4.1) Setup + +```php +use Prosopo\Views\View\ViewNamespaceConfig; +use Prosopo\Views\View\ViewTemplateRenderer; +use Prosopo\Views\ViewsManager; + +// 1. Make the Template Renderer. +// (By default it uses the built-in Blade, but you can connect any) + +$viewTemplateRenderer = new ViewTemplateRenderer(); + +// 2. Make the namespace config + +$namespaceConfig = (new ViewNamespaceConfig($viewTemplateRenderer)) + // required settings: + ->setTemplatesRootPath(__DIR__ . './templates') + ->setTemplateFileExtension('.blade.php') + // optional setting: + ->setTemplateErrorHandler(function (array $eventDetails) { + // logging, notifying, whatever. + }) + // this option enables inner models rendering before passing them into the template + ->setModelsAsStringsInTemplates(true); + +// (This line is necessary only if you defined the templateErrorHandler) +$namespaceConfig->getModules() + ->setEventDispatcher($viewTemplateRenderer->getModules()->getEventDispatcher()); + +// 3. Make the Views instance: + +$viewsManager = new ViewsManager(); + +// 4. Add the root namespace of your Template Models + +$viewsManager->registerNamespace('MyPackage\Views', $namespaceConfig); + +// Tip: you can have multiple namespaces, and mix their Models. +``` + +### 4.2) Single-step Model creation and rendering + +You can create, set values, and render a Model in a single step using the callback argument of the `renderView` method, +as shown below: + +```php +echo $viewsManager->renderModel( + EmployeeModel::class, + function (EmployeeModel $employee) use ($salary, $bonus) { + $employee->salary = $salary; + $employee->bonus = $bonus; + } +); +``` + +This approach enables a functional programming style when working with Models. + +### 4.3) Multi-step creation and rendering + +When you need split creation, use the factory to create the model, and then render later when you need it. + +```php +$employee = $viewsManager->createModel(EmployeeModel::class); + +// ... + +$employee->salary = $salary; +$employee->bonus = $bonus; + +// ... + +echo $views->renderModel($employee); + +// Tip: you can still pass the callback as the second renderModel() argument +// to customize the Model properties before rendering. +``` + +Advice: The `ViewsManager` class implements three interfaces: `ViewNamespaceManagerInterface` (for `registerNamespace`), +`ModelFactoryInterface` (for `createModel`), and `ModelRendererInterface` (for `renderModel`). + +When passing the `ViewsManager` instance to your methods, use one of these interfaces as the argument type instead of +the `ViewsManager` class itself. + +This approach ensures that only the specific actions you expect are accessible, promoting cleaner and more maintainable +code. + +### 4.4) Automated templates matching + +The built-in `ModelTemplateResolver` automatically matches templates based on the Model names and their relative +namespaces. This automates the process of associating templates with their corresponding Models. + +Example: + +- src/ + - Views/ + - `Homepage.php` + - Settings + - `GeneralSettings.php` + - templates/ + - `homepage{.blade.php}` + - settings/ + - `general-settings{.blade.php}` + +We define the root templates folder along with the models root namespace in the `ViewsNamespaceConfig`: + +```php +$namespaceConfig = (new ViewNamespaceConfig($viewTemplateRenderer)) + ->setTemplatesRootPath(__DIR__ . './templates') + ->setTemplateFileExtension('.blade.php'); + +// 3. Make the Views Manager instance: + +$viewsManager = new ViewsManager(); + +// 4. Add the root namespace of your Template Models + +$viewsManager->registerNamespace('MyPackage\Views', $namespaceConfig); +``` + +**Naming Note:** Use dashes in template names, as `camelCase` in Model names is automatically converted to +`dash-separated` +names. + +> Tip: In case this approach doesn't work for your setup, you can override the `ModelTemplateResolver` module to +> implement your own logic. In case the reason is the name-specific only, consider overriding the `ModelNameResolver` +> module instead. + +### 4.5) Custom modules + +By default, the `registerNamespace` class creates module instances for the namespace using classes from the current +package. + +If you need to override the default module behavior, you can define a custom implementation in the +configuration and the package will use the specified implementation. + +> Tip: You can see the full list of the modules in the `ViewNamespaceModules` class. + +#### Example: Using Twig as a Template Renderer (instead of the built-in Blade) + +```php +// 1. Make a facade (for Twig or another template engine) + +use Prosopo\Views\Interfaces\Template\TemplateRendererInterface; +use Prosopo\Views\View\ViewNamespaceConfig; +use Prosopo\Views\ViewsManager; + +class TwigDecorator implements TemplateRendererInterface +{ + private $twig; + + public function __construct() + { + // todo init Twig or another engine. + } + + public function renderTemplate(string $template, array $variables = []): string + { + return $this->twig->render($template, $variables); + } +} + +// 2. Define the namespace config with the facade instance + +$twigDecorator = new TwigDecorator(); + +$namespaceConfig = (new ViewNamespaceConfig($twigDecorator)) + ->setTemplatesRootPath(__DIR__ . './templates') + ->setTemplateFileExtension('.twig'); + +// 3. Make the Views: + +$viewsManager = new ViewsManager(); + +// 4. Add the namespace (you can have multiple namespaces) + +$viewsManager->registerNamespace('MyPackage\Views', $namespaceConfig); + +// ... + +$viewsManager->renderModel(MyTwigModel::class); +``` + +You can override any namespace module in the following way: + +```php +$namespaceConfig->getModules() + // override any available module, like TemplateRenderer or Factory: + ->setModelFactory(new MyFactory()); +``` + +> Note: The package includes only the Blade implementation. If you wish to use a different template engine, +> like Twig, you need to install its Composer package and create a facade object, as demonstrated above. + +### 4.6) Namespace mixing + +The `ViewsManager` class not only supporting multiple namespaces, but also enabling you to use Models from +one namespace within another, preserving their individual setup. + +Example of multi-namespace usage: + +Suppose you have registered a namespace for Twig templates: + +```php +$viewsManager->registerNamespace('App\Twig',$configForTwigNamespace); +``` + +This namespace includes a `Button` model and a `button.twig` template: + +Button's model: + +```php +namespace App\Twig; + +use Prosopo\Views\BaseTemplateModel; + +class ButtonModel extends BaseTemplateModel { + public string $label; +} +``` + +Button's template: + +```html + + +``` + +Additionally, you registered a namespace for Blade templates: + +```php +$viewsManager->registerNamespace('App\Blade',$configForBladeNamespace); +``` + +with a `Popup` model: + +Popup's model: + +```php +namespace App\Blade; + +use Prosopo\Views\BaseTemplateModel; + +class PopupModel extends BaseTemplateModel { +} +``` + +Now is the cool part: you can safely use the `App\Twig\ButtonModel` class as a property of the +`App\Blade\PopupModel` class, so it looks like this: + +Popup's model: + +```php +namespace App\Blade; + +use Prosopo\Views\BaseTemplateModel; +use App\Twig\ButtonModel; + +class PopupModel extends BaseTemplateModel { + public ButtonModel $buttonModel; +} +``` + +Now you can use the `buttonModel` in the popup's template: + +```html + +
+ I'm a popup! + To close, click here - {!! $buttonModel !!} +
+``` + +When you call `ViewsManager->makeModel()` for the `PopupModel` class: + +1. The `App\Blade\PopupModel` instance will be created using the `ModelFactory` from the `App\Blade` namespace. +2. During automated property initialization, an instance of `App\Twig\ButtonModel` will be created using the + `ModelFactory` + from for the `App\Twig` namespace. + +This design allows you to seamlessly reuse models across different namespaces while respecting the specific +configuration of each namespace. + +Namespace resolution also occurs when you call `ViewsManager->renderModel()`. In this example: + +* `App\Twig\ButtonModel` will be rendered using the `ViewTemplateRenderer` from the `App\Twig` namespace, which is + configured for Twig. +* `App\Blade\PopupModel` will be rendered using the `ViewTemplateRenderer` from the `App\Blade` namespace, which is + configured for Blade. + +## 5. View Renderer + +`ViewTemplateRenderer` is the class responsible for rendering templates in this package. By default, it integrates the +Blade compiler, but it is fully customizable. You can replace the Blade compiler with your own implementation or use a +simple stub to enable support for plain PHP template files. + +### 5.1) Built-in Blade integration + +[Blade](https://laravel.com/docs/11.x/blade) is an elegant and powerful template engine originally developed +for [Laravel](https://laravel.com/). Unlike [Twig](https://twig.symfony.com/), Blade embraces PHP usage +rather than restricting it. It enhances templates with syntax sugar (which we all love), making them clean and easy to +read. + +Blade introduces special shorthand tokens that simplify the most cumbersome syntax constructions, while still being +fully-fledged PHP with access to all its functions and capabilities. + +Unfortunately, Blade isn't available as a standalone package, so this package includes its own Blade compiler. It +provides full support for [Blade's key features](https://laravel.com/docs/11.x/blade) while remaining completely +independent of Laravel. + +The following Blade tokens are supported: + +1. Displaying: `{{ $var }}` and `{!! $var }}` +2. IF Conditions: `@if`, `@else`, `@elseif`, `@endif` +3. Switch conditions: `@switch`, `@case`, `@break`, `@default`, `@endswitch`. +4. Loops: `@foreach`, `@endforeach`, `@for`, `@endfor`, `@break`. +5. Helpers: `@selected`, `@checked`, `@class`. +6. PHP-related: `@use`, `@php`, `@endphp`. + +Visit the [official Blade docs](https://laravel.com/docs/11.x/blade) to learn about their usage. + +#### Notes on the standalone Blade implementation + +You may have come across packages that attempt to adapt the official Blade engine by creating +stubs for its Laravel dependencies, such as the [jenssegers/blade](https://github.com/jenssegers/blade) package. +However, we chose not to adopt this approach for several reasons: + +* PHP Version Requirements: It mandates PHP 8.2 or higher. +* External Dependencies: It introduces additional external dependencies. +* Potential Breakage: It can become unstable with future Laravel updates (as demonstrated + by [past incidents](https://github.com/jenssegers/blade/issues/74). +* Limited Flexibility: Since it wasn’t designed as a standalone component, it lacks some of the customization abilities. +* Global functions: Laravel's implementation includes global helper functions, which becomes a problem when you need to + [scope the package](https://github.com/humbug/php-scoper). + +Thanks to great Blade's conceptual design, our compiler implementation required fewer than 200 lines of code. + +### 5.2) View Renderer setup + +```php +use Prosopo\Views\View\ViewTemplateRenderer; + +$viewTemplateRenderer = new ViewTemplateRenderer(); + +echo $viewTemplateRenderer->renderTemplate('/my-template.blade.php', [ + 'var' => true +]); +``` + +> Tip #1: by default, `BladeTemplateRenderer` is configured to work with files, but you can also switch it to work with +> plain strings: + +```php +use Prosopo\Views\View\ViewTemplateRenderer; +use Prosopo\Views\View\ViewTemplateRendererConfig; + +$viewRendererConfig = new ViewTemplateRendererConfig(); +$viewRendererConfig->setFileBasedTemplates(false); + +$viewTemplateRenderer = new ViewTemplateRenderer($viewRendererConfig); + +echo $viewTemplateRenderer->renderTemplate('@if($var)The variable is set.@endif', [ + 'var' => true +]); +``` + +> Tip #2: As you see, the built-in TemplateRenderer implementation is fully standalone and independent of the `Views` +> class. This +> means that even if you can't or don't want to use the model-driven approach, you can still utilize it as an +> independent Blade compiler. + +### 5.3) Available View Renderer settings + +The `ViewTemplateRenderer` supports a variety of settings that let you customize features such as +escaping, error handling, and more: + +```php +use Prosopo\Views\View\ViewTemplateRenderer; +use Prosopo\Views\View\ViewTemplateRendererConfig; + +$viewRendererConfig = (new ViewTemplateRendererConfig()) +// By default, the Renderer expect a file name. +// Set to false if to work with strings + ->setFileBasedTemplates(true) + ->setTemplateErrorHandler(function (array $eventDetails): void { + // Can be used for logging, notifying, etc. + }) + ->setCustomOutputEscapeCallback(function ($variable): string { + if ( + false === is_string($variable) && + false === is_numeric($variable) + ) { + return ''; + } + + // htmlspecialchars is the default one. + return htmlentities((string)$variable, ENT_QUOTES, 'UTF-8', false); + }) + ->setGlobalVariables([ + 'sum' => function (int $a, int $b): string { + return (string)($a + $b); + }, + 'variable' => 'value', + ]) + ->setEscapeVariableName('escape') + ->setCompilerExtensionCallback(function (string $template): string { + // note: just an example, @use is supported by default. + return (string)preg_replace('/@use\s*\((["\'])(.*?)\1\)/s', '', $template); + }); + +$viewTemplateRenderer = new ViewTemplateRenderer($viewRendererConfig); +``` + +### 5.4) Custom View Renderer modules + +By default, the `ViewTemplateRenderer` creates module instances using classes from the current package, including the +Blade compiler. + +If you need to override the default module behavior, you can define a custom implementation in the +configuration. The `ViewTemplateRenderer` will use the specified implementation. + +> Tip: You can see the full list of the modules in the `ViewTemplateRendererModules`. + +#### Example: Overriding the default Blade compiler to use plain PHP views + +```php +use Prosopo\Views\Interfaces\Template\TemplateCompilerInterface; +use Prosopo\Views\View\ViewNamespaceConfig; +use Prosopo\Views\View\ViewTemplateRenderer; +use Prosopo\Views\View\ViewTemplateRendererConfig; +use Prosopo\Views\ViewsManager; + +class CompilerStubForPlainPhpSupport implements TemplateCompilerInterface +{ + public function compileTemplate(string $template): string + { + return $template; + } +} + +// ... + +$viewTemplateRendererConfig = new ViewTemplateRendererConfig(); +$viewTemplateRendererConfig->getModules() + ->setTemplateCompiler(new CompilerStubForPlainPhpSupport()); + +$viewTemplateRenderer = new ViewTemplateRenderer($viewTemplateRendererConfig); + +$views = new ViewsManager(); + +$viewNamespaceConfig = new ViewNamespaceConfig($viewTemplateRenderer); +$viewNamespaceConfig + ->setTemplatesRootPath(__DIR__ . './templates') + ->setTemplateFileExtension('.php'); + +$views->registerNamespace('MyApp\Models', $viewNamespaceConfig); +``` + +Now this namespace is configured to deal with plain PHP template files, while having all the package features, including +model-driven approach and template error handling. + +## 6. Contribution + +We would be excited if you decide to contribute 🤝 + +Please read the [for-devs.md](https://github.com/prosopo/php-views/blob/main/for-devs.md) file for project guidelines and +agreements. + +## 7. Credits + +This package was created by [Maxim Akimov](https://github.com/light-source/) during the development of +the [WordPress integration for Prosopo Procaptcha](https://github.com/prosopo/procaptcha-wordpress-plugin). + +[Procaptcha](https://prosopo.io/) is a privacy-friendly and cost-effective alternative to Google reCaptcha. + +Consider using the Procaptcha service to protect your privacy and support the Prosopo team. diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/composer.json b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/composer.json new file mode 100644 index 0000000..a8872c8 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/composer.json @@ -0,0 +1,28 @@ +{ + "name": "prosopo\/views", + "description": "Blazing fast Views with model-driven approach, Blade and multi-namespace support.", + "homepage": "https:\/\/github.com\/prosopo\/php-views", + "keywords": [ + "Views", + "templates", + "models", + "Blade", + "Twig" + ], + "license": "Apache-2.0", + "authors": [ + { + "name": "Maxim Akimov", + "homepage": "https:\/\/github.com\/light-source\/" + } + ], + "require": { + "php": "^7.4|^8.0" + }, + "autoload": { + "psr-4": { + "Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\": "src\/", + "Io\\Prosopo\\Procaptcha\\Vendors\\Prosopo\\Views\\PrivateClasses\\": "private-classes" + } + } +} \ No newline at end of file diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/for-devs.md b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/for-devs.md new file mode 100644 index 0000000..a0638fd --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/for-devs.md @@ -0,0 +1,33 @@ +# For Devs + +This file provides information about the project and serves as a guide for those interested in contributing. + +## 1. Architecture Guidelines + +The codebase adheres to the [SOLID principles](https://en.wikipedia.org/wiki/SOLID). Please keep these principles in +mind when introducing new classes or modules to ensure consistency and maintainability. + +## 2. Code Style + +The project follows the [PSR-12](https://www.php-fig.org/psr/psr-12/) coding standard. Configure your IDE to use +the [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) and use the `code-quality/phpcs.xml` config, or run +the following command to automatically fix style issues: + +`cd code-quality; composer install; composer phpcbf` + +## 3. Static Analysis + +The project uses [PHPStan](https://phpstan.org/) for static analysis. Configure your IDE with the +`code-quality/phpstan.neon` config or run the analysis using the following command: + +`cd code-quality; composer install; composer phpstan` + +## 4. Tests + +The tests are powered by [Pest](https://pestphp.com/). To run the tests: + +`cd tests; composer install; composer pest` + +## 5. Pull Requests + +Please open your Pull Requests against the `main` branch. \ No newline at end of file diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Blade/BladeCompiler.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Blade/BladeCompiler.php new file mode 100644 index 0000000..7034cb3 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Blade/BladeCompiler.php @@ -0,0 +1,155 @@ +escapeVariableName = $escapeVariableName; + $this->extensionCallback = $extensionCallback; + } + public function compileTemplate(string $template): string + { + $template = $this->removeComments($template); + $template = $this->replaceOpeningTagWithBrackets('for', $template); + $template = $this->replaceOpeningTagWithBrackets('foreach', $template); + $template = $this->replaceClosingLoops($template); + $template = $this->replaceOpeningTagWithBrackets('if', $template); + $template = $this->replaceOpeningTagWithBrackets('elseif', $template); + $template = $this->replaceClosingIf($template); + $template = $this->replaceElse($template); + // With the current regex, it's important to replace echo after 'for' and 'if' + $template = $this->replaceOpeningEcho($template, $this->escapeVariableName); + $template = $this->replaceClosingEcho($template); + $template = $this->replaceOpeningPhp($template); + $template = $this->replaceClosingPhp($template); + $template = $this->replaceUseDirective($template); + $template = $this->replaceSelectedDirective($template); + $template = $this->replaceCheckedDirective($template); + $template = $this->replaceClassDirective($template, $this->escapeVariableName); + $template = $this->replaceSwitchDirectives($template); + return $this->applyExtensionCallback($template); + } + protected function applyExtensionCallback(string $template): string + { + if (null !== $this->extensionCallback) { + $extensionCallback = $this->extensionCallback; + return $extensionCallback($template); + } + return $template; + } + // Removes all parts like: "{{--Comment--}}". + protected function removeComments(string $template): string + { + return (string) preg_replace('/{{--[\s\S]*?--}}/', '', $template); + } + protected function replaceOpeningEcho(string $template, string $escape_callback_name): string + { + $template = str_replace('{{', sprintf('', $template); + return str_replace('!!}', '); ?>', $template); + } + protected function getRegexForTagWithBrackets(string $tag): string + { + // Without 's' flag, .* means everything, but not the new line. + // It's necessary to separate the new line, + // otherwise we'll have troubles with the nested things, like "for(test()->new()) {{ new() }} @endforeach". + return sprintf('/@%s\s*\((.*)\)/', preg_quote($tag, '/')); + } + protected function replaceOpeningTagWithBrackets(string $tag, string $template): string + { + $regex = $this->getRegexForTagWithBrackets($tag); + $replacement = sprintf('', $tag); + return (string) preg_replace($regex, $replacement, $template); + } + protected function replaceClosingLoops(string $template): string + { + // It's important to put 'endforeach' first, because 'endfor' is a part of 'endforeach'. + $template = str_replace('@endforeach', '', $template); + return str_replace('@endfor', '', $template); + } + protected function replaceClosingIf(string $template): string + { + return str_replace('@endif', '', $template); + } + protected function replaceElse(string $template): string + { + return str_replace('@else', '', $template); + } + protected function replaceOpeningPhp(string $template): string + { + return str_replace('@php', '', $template); + } + protected function replaceUseDirective(string $template): string + { + return (string) preg_replace('/@use\s*\((["\'])(.*?)\1\)/s', '', $template); + } + protected function replaceSelectedDirective(string $template): string + { + $regex = $this->getRegexForTagWithBrackets('selected'); + $replacement = ''; + return (string) preg_replace($regex, $replacement, $template); + } + protected function replaceCheckedDirective(string $template): string + { + $regex = $this->getRegexForTagWithBrackets('checked'); + $replacement = ''; + return (string) preg_replace($regex, $replacement, $template); + } + protected function replaceSwitchDirectives(string $template): string + { + $template = $this->replaceOpeningTagWithBrackets('case', $template); + // 1. remove space between @switch and the first "case", + // otherwise it'll case an error (spaces are threat as unexpected HTML). + $regex = '/@switch\s*\((.*)\)\s*<\?php/'; + $template = (string) preg_replace($regex, '', $template); + $template = str_replace('@default', '', $template); + $template = str_replace('@endswitch', '', $template); + return $template; + } + // "@class(['name', 'name2' => $condition])" to 'class="name name2"'. + protected function replaceClassDirective(string $template, string $escape_callback_name): string + { + $regex = '/@class\s*\((\[.*])\)/s'; + $replacement = $this->getCodeForConditionClasses($escape_callback_name); + return (string) preg_replace($regex, $replacement, $template); + } + protected function getCodeForConditionClasses(string $escape_callback_name): string + { + $php_code = array(); + $php_code[] = ' \$value ) {'; + $php_code[] = sprintf('if ( true === is_int( \$key ) ) { echo $%s(\$value) . " "; }', $escape_callback_name); + $php_code[] = sprintf('else { if ( true === \$value ) { echo $%s(\$key) . " "; } }', $escape_callback_name); + $php_code[] = '}'; + // foreach. + $php_code[] = 'echo trim( (string)ob_get_clean() );'; + $php_code[] = 'echo "\""; ?>'; + return implode("\n", $php_code); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithErrorHandler.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithErrorHandler.php new file mode 100644 index 0000000..6527cff --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithErrorHandler.php @@ -0,0 +1,42 @@ +codeExecutor = $codeExecutor; + $this->eventDispatcher = $eventDispatcher; + $this->errorEventName = $errorEventName; + } + public function runCode(string $code, array $arguments = []): void + { + $errorDetails = ['arguments' => $arguments, 'code' => $code]; + try { + // Convert everything, including PHP Warnings into an Exception. + // In this way we process Warnings by our eventDispatcher, rather than having the global PHP Warning. + set_error_handler(function ($severity, $message, $file, $line) { + throw new ErrorException($message, 0, $severity, $file, $line); + }); + $this->codeExecutor->runCode($code, $arguments); + } catch (Throwable $error) { + $errorDetails['error'] = $error; + $this->eventDispatcher->dispatchEvent($this->errorEventName, $errorDetails); + } finally { + restore_error_handler(); + } + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithGlobalArguments.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithGlobalArguments.php new file mode 100644 index 0000000..2c6dcac --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithGlobalArguments.php @@ -0,0 +1,31 @@ + + */ + private array $globalArguments; + /** + * @param array $globalArguments + */ + public function __construct(CodeRunnerInterface $codeExecutor, array $globalArguments) + { + $this->codeExecutor = $codeExecutor; + $this->globalArguments = $globalArguments; + } + public function runCode(string $code, array $arguments = []): void + { + $arguments = array_merge($this->globalArguments, $arguments); + $this->codeExecutor->runCode($code, $arguments); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithTemplateCompilation.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithTemplateCompilation.php new file mode 100644 index 0000000..0018a8b --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/CodeRunnerWithTemplateCompilation.php @@ -0,0 +1,26 @@ +codeExecutor = $codeExecutor; + $this->templateCompiler = $templateCompiler; + } + public function runCode(string $code, array $arguments = []): void + { + $compiledCode = $this->templateCompiler->compileTemplate($code); + $this->codeExecutor->runCode($compiledCode, $arguments); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/PhpCodeRunner.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/PhpCodeRunner.php new file mode 100644 index 0000000..7401643 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/CodeRunner/PhpCodeRunner.php @@ -0,0 +1,20 @@ +' . $code); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/EventDispatcher.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/EventDispatcher.php new file mode 100644 index 0000000..a6640a1 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/EventDispatcher.php @@ -0,0 +1,76 @@ + $details):void>> name => listeners + */ + private array $eventListeners; + /** + * @var array> name => details + */ + private array $eventDetails; + public function __construct() + { + $this->eventListeners = []; + $this->eventDetails = []; + } + public function dispatchEvent(string $eventName, array $eventDetails): void + { + $eventListeners = $this->getEventListeners($eventName); + $eventDetails = array_merge($this->getEventDetails($eventName), $eventDetails); + array_walk($eventListeners, function (callable $listener) use ($eventDetails) { + $listener($eventDetails); + }); + } + public function addEventListener(string $eventName, callable $eventListener): void + { + $eventListeners = $this->getEventListeners($eventName); + $eventListeners[] = $eventListener; + $this->eventListeners[$eventName] = $eventListeners; + } + public function removeEventListener(string $eventName, callable $eventListener): void + { + $eventListeners = $this->getEventListeners($eventName); + $index = array_search($eventListener, $eventListeners, \true); + if (\false === $index) { + return; + } + unset($eventListeners[$index]); + // Reindex. + $eventListeners = array_values($eventListeners); + $this->eventListeners[$eventName] = $eventListeners; + } + public function registerEventDetails(string $eventName, array $eventDetails): void + { + $eventDetails = array_merge($this->getEventDetails($eventName), $eventDetails); + $this->eventDetails[$eventName] = $eventDetails; + } + public function unregisterEventDetails(string $eventName, array $eventDetails): void + { + $eventDetails = array_diff_key($this->getEventDetails($eventName), $eventDetails); + $this->eventDetails[$eventName] = $eventDetails; + } + /** + * @return array + */ + protected function getEventDetails(string $eventName): array + { + return \true === key_exists($eventName, $this->eventDetails) ? $this->eventDetails[$eventName] : []; + } + /** + * @return array $details):void> + */ + protected function getEventListeners(string $eventName): array + { + return \true === key_exists($eventName, $this->eventListeners) ? $this->eventListeners[$eventName] : []; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactory.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactory.php new file mode 100644 index 0000000..d2cf56d --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactory.php @@ -0,0 +1,33 @@ +objectReader = $objectReader; + $this->propertyValueProvider = $propertyValueProvider; + $this->modelTemplateResolver = $modelTemplateResolver; + $this->templateRenderer = $templateRenderer; + } + public function createModel(string $modelClass, ?Closure $setupModelCallback = null) + { + return new $modelClass($this->objectReader, $this->propertyValueProvider, $this->modelTemplateResolver, $this->templateRenderer); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactoryWithDefaultsManagement.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactoryWithDefaultsManagement.php new file mode 100644 index 0000000..2508779 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactoryWithDefaultsManagement.php @@ -0,0 +1,54 @@ +modelFactory = $modelFactory; + $this->objectPropertyReader = $objectReader; + $this->objectPropertyWriter = $objectPropertyWriter; + } + public function createModel(string $modelClass, ?Closure $setupModelCallback = null) + { + $model = $this->modelFactory->createModel($modelClass); + if (\true === $model instanceof TemplateModelWithDefaultsInterface) { + $this->setDefaultValuesRecursively($model); + } + return $model; + } + protected function setDefaultValuesRecursively(TemplateModelWithDefaultsInterface $modelWithDefaults): void + { + $defaultsPropertyValueProvider = $modelWithDefaults->getDefaultPropertyValueProvider(); + $this->objectPropertyWriter->assignPropertyValues($modelWithDefaults, $defaultsPropertyValueProvider); + $innerModelsWithDefaults = $this->getInnerModels($this->objectPropertyReader->extractObjectVariables($modelWithDefaults)); + array_map(function (TemplateModelWithDefaultsInterface $innerModelWithDefaults) { + $this->setDefaultValuesRecursively($innerModelWithDefaults); + }, $innerModelsWithDefaults); + } + /** + * @param array $variables + * + * @return TemplateModelWithDefaultsInterface[] + */ + protected function getInnerModels(array $variables): array + { + return array_filter($variables, function ($item) { + return \true === $item instanceof TemplateModelWithDefaultsInterface; + }); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactoryWithSetupCallback.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactoryWithSetupCallback.php new file mode 100644 index 0000000..8fbe523 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelFactoryWithSetupCallback.php @@ -0,0 +1,27 @@ +modelFactory = $modelFactory; + } + public function createModel(string $modelClass, ?Closure $setupModelCallback = null) + { + $model = $this->modelFactory->createModel($modelClass); + if (null !== $setupModelCallback) { + $setupModelCallback($model); + } + return $model; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelNameResolver.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelNameResolver.php new file mode 100644 index 0000000..89e0e3f --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelNameResolver.php @@ -0,0 +1,29 @@ +objectClassReader = $objectClassReader; + } + public function resolveModelName(TemplateModelInterface $model): string + { + $modelNamespaceWithClassName = $this->objectClassReader->getObjectClass($model); + $lastDelimiterPosition = strrpos($modelNamespaceWithClassName, '\\'); + if (\false === $lastDelimiterPosition) { + return ''; + } + return substr($modelNamespaceWithClassName, $lastDelimiterPosition + 1); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelNamespaceResolver.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelNamespaceResolver.php new file mode 100644 index 0000000..950e5c3 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelNamespaceResolver.php @@ -0,0 +1,29 @@ +objectClassReader = $objectClassReader; + } + public function resolveModelNamespace($modelOrClass): string + { + $modelNamespaceWithClassName = \false === is_string($modelOrClass) ? $this->objectClassReader->getObjectClass($modelOrClass) : $modelOrClass; + $lastDelimiterPosition = strrpos($modelNamespaceWithClassName, '\\'); + if (\false === $lastDelimiterPosition) { + return ''; + } + $className = substr($modelNamespaceWithClassName, $lastDelimiterPosition); + return substr($modelNamespaceWithClassName, 0, -strlen($className)); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelRenderer.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelRenderer.php new file mode 100644 index 0000000..39d23a9 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelRenderer.php @@ -0,0 +1,36 @@ +templateRenderer = $templateRenderer; + $this->viewFactory = $modelFactory; + $this->templateProvider = $templateProvider; + } + public function renderModel($modelOrClass, ?Closure $setupModelCallback = null): string + { + $model = \true === is_string($modelOrClass) ? $this->viewFactory->createModel($modelOrClass) : $modelOrClass; + if (null !== $setupModelCallback) { + $setupModelCallback($model); + } + $variables = $model->getTemplateArguments(); + $template = $this->templateProvider->resolveModelTemplate($model); + return $this->templateRenderer->renderTemplate($template, $variables); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelRendererWithEventDetails.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelRendererWithEventDetails.php new file mode 100644 index 0000000..b309866 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Model/ModelRendererWithEventDetails.php @@ -0,0 +1,33 @@ +viewRenderer = $viewRenderer; + $this->eventDispatcher = $eventDispatcher; + $this->eventName = $eventName; + } + public function renderModel($modelOrClass, ?Closure $setupModelCallback = null): string + { + $modelClass = \true === is_string($modelOrClass) ? $modelOrClass : get_class($modelOrClass); + $eventDetails = ['modelClass' => $modelClass]; + $this->eventDispatcher->registerEventDetails($this->eventName, $eventDetails); + $response = $this->viewRenderer->renderModel($modelOrClass, $setupModelCallback); + $this->eventDispatcher->unregisterEventDetails($this->eventName, $eventDetails); + return $response; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/ObjectClassReader.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/ObjectClassReader.php new file mode 100644 index 0000000..8d80c34 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/ObjectClassReader.php @@ -0,0 +1,20 @@ +getPublicTypedVariables($reflectionClass); + array_map(function (ReflectionProperty $reflectionProperty) use ($instance, $propertyValueProvider) { + if (\true === $reflectionProperty->isInitialized($instance)) { + return; + } + $this->setDefaultValueForSupportedType($instance, $propertyValueProvider, $reflectionProperty); + }, $publicTypedVariables); + } + /** + * @param ReflectionClass $reflection_class + * + * @return ReflectionProperty[] + */ + protected function getPublicTypedVariables(ReflectionClass $reflection_class): array + { + $publicProperties = $reflection_class->getProperties(ReflectionProperty::IS_PUBLIC); + return $this->getTypedProperties($publicProperties); + } + protected function setDefaultValueForSupportedType(object $instance, PropertyValueProviderInterface $propertyValueProvider, ReflectionProperty $reflectionProperty): bool + { + if (\false === $propertyValueProvider->supportsProperty($reflectionProperty)) { + return \false; + } + $value = $propertyValueProvider->getPropertyValue($reflectionProperty); + $reflectionProperty->setValue($instance, $value); + return \true; + } + /** + * @param ReflectionProperty[] $reflectionProperties + * + * @return ReflectionProperty[] + */ + protected function getTypedProperties(array $reflectionProperties): array + { + return array_filter($reflectionProperties, function (ReflectionProperty $property): bool { + return null !== $property->getType(); + }); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/ObjectReader.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/ObjectReader.php new file mode 100644 index 0000000..1c1082e --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/ObjectReader.php @@ -0,0 +1,98 @@ +getPublicTypedVariables($reflectionClass); + $variableValues = $this->getPropertyValues($instance, $publicTypedVariables); + $methodNames = $this->getPublicMethodNames($reflectionClass); + $methodCallbacks = $this->makeMethodCallbacks($instance, $methodNames); + /** + * @var array + */ + return array_merge($variableValues, $methodCallbacks); + } + /** + * @param ReflectionClass $reflection_class + * + * @return ReflectionProperty[] + */ + protected function getPublicTypedVariables(ReflectionClass $reflection_class): array + { + $publicProperties = $reflection_class->getProperties(ReflectionProperty::IS_PUBLIC); + return $this->getTypedProperties($publicProperties); + } + /** + * @param ReflectionClass $reflection_class + * + * @return string[] + */ + protected function getPublicMethodNames(ReflectionClass $reflection_class): array + { + $publicMethods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); + return array_diff($this->extractMethodNames($publicMethods), array('__construct')); + } + /** + * @param ReflectionProperty[] $reflectionProperties + * + * @return ReflectionProperty[] + */ + protected function getTypedProperties(array $reflectionProperties): array + { + return array_filter($reflectionProperties, function (ReflectionProperty $property): bool { + return null !== $property->getType(); + }); + } + /** + * @param ReflectionMethod[] $reflectionMethods + * + * @return string[] + */ + protected function extractMethodNames(array $reflectionMethods): array + { + return array_map(function (ReflectionMethod $method) { + return $method->getName(); + }, $reflectionMethods); + } + /** + * @param ReflectionProperty[] $reflectionProperties + * + * @return array variableName => variableValue + */ + protected function getPropertyValues(object $instance, array $reflectionProperties): array + { + return array_reduce($reflectionProperties, function (array $variableValues, ReflectionProperty $reflection_property) use ($instance) { + // make sure the property is initialized. + // Otherwise, we'll get "must not be accessed before initialization" error. + if (\true === $reflection_property->isInitialized($instance)) { + $variableValues[$reflection_property->getName()] = $reflection_property->getValue($instance); + } + return $variableValues; + }, array()); + } + /** + * @param string[] $methodNames + * + * @return array methodName => method + */ + protected function makeMethodCallbacks(object $instance, array $methodNames): array + { + return array_reduce($methodNames, function (array $methodCallbacks, string $method_name) use ($instance) { + $methodCallbacks[$method_name] = array($instance, $method_name); + return $methodCallbacks; + }, array()); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProvider.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProvider.php new file mode 100644 index 0000000..316bf8b --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProvider.php @@ -0,0 +1,22 @@ + type => value + */ + private array $valuesByType; + /** + * @param array $defaultValues + */ + public function __construct(PropertyValueProviderInterface $propertyValueProvider, array $defaultValues) + { + $this->propertyValueProvider = $propertyValueProvider; + $this->valuesByType = $defaultValues; + } + public function supportsProperty(ReflectionProperty $property): bool + { + if (\true === $this->propertyValueProvider->supportsProperty($property)) { + return \true; + } + $type = $this->getPropertyType($property); + return \true === key_exists($type, $this->valuesByType); + } + public function getPropertyValue(ReflectionProperty $property) + { + if (\true === $this->propertyValueProvider->supportsProperty($property)) { + return $this->propertyValueProvider->getPropertyValue($property); + } + $type = $this->getPropertyType($property); + return \true === key_exists($type, $this->valuesByType) ? $this->valuesByType[$type] : null; + } + protected function getPropertyType(ReflectionProperty $property): string + { + $reflectionType = $property->getType(); + return null !== $reflectionType ? $reflectionType->getName() : ''; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProviderForModels.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProviderForModels.php new file mode 100644 index 0000000..f6bc036 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProviderForModels.php @@ -0,0 +1,54 @@ +propertyValueProvider = $propertyValueProvider; + $this->modelFactory = $viewFactory; + } + public function supportsProperty(ReflectionProperty $property): bool + { + if (\true === $this->propertyValueProvider->supportsProperty($property)) { + return \true; + } + $type = $this->getPropertyType($property); + return null !== $this->getValidModelClass($type); + } + public function getPropertyValue(ReflectionProperty $property) + { + if (\true === $this->propertyValueProvider->supportsProperty($property)) { + return $this->propertyValueProvider->getPropertyValue($property); + } + $type = $this->getPropertyType($property); + $modelClassString = $this->getValidModelClass($type); + return null !== $modelClassString ? $this->modelFactory->createModel($modelClassString) : null; + } + /** + * @param class-string|string $propertyType + * + * @return class-string|null + */ + protected function getValidModelClass(string $propertyType) + { + return \true === class_exists($propertyType) && \true === is_a($propertyType, TemplateModelInterface::class, \true) ? $propertyType : null; + } + protected function getPropertyType(ReflectionProperty $property): string + { + $reflectionType = $property->getType(); + return null !== $reflectionType ? $reflectionType->getName() : ''; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProviderForNullable.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProviderForNullable.php new file mode 100644 index 0000000..0e14bdf --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Object/PropertyValueProviderForNullable.php @@ -0,0 +1,34 @@ +propertyValueProvider = $propertyValueProvider; + } + public function supportsProperty(ReflectionProperty $property): bool + { + if (\true === $this->propertyValueProvider->supportsProperty($property)) { + return \true; + } + $type = $property->getType(); + return null !== $type && \true === $type->allowsNull(); + } + public function getPropertyValue(ReflectionProperty $property) + { + if (\true === $this->propertyValueProvider->supportsProperty($property)) { + return $this->propertyValueProvider->getPropertyValue($property); + } + return null; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/FileModelTemplateResolver.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/FileModelTemplateResolver.php new file mode 100644 index 0000000..a156ec4 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/FileModelTemplateResolver.php @@ -0,0 +1,62 @@ +templatesRootPath = $templatesRootPath; + $this->namespace = $namespace; + $this->extension = $extension; + $this->isFileBasedTemplate = $isFileBasedTemplate; + $this->modelNameProvider = $modelNameProvider; + $this->modelNamespaceProvider = $modelNamespaceProvider; + } + public function resolveModelTemplate(TemplateModelInterface $model): string + { + $modelNamespace = $this->modelNamespaceProvider->resolveModelNamespace($model); + $relativeModelNamespace = substr($modelNamespace, strlen($this->namespace)); + $relativeModelNamespace = ltrim($relativeModelNamespace, '\\'); + $modelName = $this->modelNameProvider->resolveModelName($model); + $relativeTemplatePath = $this->getRelativeTemplatePath($relativeModelNamespace, $modelName); + $absoluteTemplatePath = $this->getAbsoluteTemplatePath($relativeTemplatePath); + return \true === $this->isFileBasedTemplate ? $absoluteTemplatePath : $this->getFileContent($absoluteTemplatePath); + } + protected function getFileContent(string $file): string + { + if (\false === file_exists($file)) { + return ''; + } + // @phpcs:ignore + return (string) file_get_contents($file); + } + protected function getAbsoluteTemplatePath(string $relativeTemplatePath): string + { + return rtrim($this->templatesRootPath, '/') . \DIRECTORY_SEPARATOR . $relativeTemplatePath . $this->extension; + } + protected function getRelativeTemplatePath(string $relativeModelNamespace, string $modelName): string + { + $relativeModelPath = str_replace('\\', \DIRECTORY_SEPARATOR, $relativeModelNamespace); + $modelName = (string) preg_replace('/([a-z])([A-Z])/', '$1-$2', $modelName); + $relativeTemplatePath = $relativeModelPath; + $relativeTemplatePath .= '' !== $relativeTemplatePath ? \DIRECTORY_SEPARATOR : ''; + $relativeTemplatePath .= $modelName; + return strtolower($relativeTemplatePath); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRenderer.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRenderer.php new file mode 100644 index 0000000..c083bd9 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRenderer.php @@ -0,0 +1,25 @@ +codeExecutor = $codeExecutor; + } + public function renderTemplate(string $template, array $variables = []): string + { + ob_start(); + $this->codeExecutor->runCode($template, $variables); + return (string) ob_get_clean(); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithCustomEscape.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithCustomEscape.php new file mode 100644 index 0000000..e7e1bc6 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithCustomEscape.php @@ -0,0 +1,64 @@ +templateRenderer = $templateRenderer; + $this->customOutputEscapeCallback = $customOutputEscapeCallback; + $this->escapeVariableName = $escapeVariableName; + } + public function renderTemplate(string $template, array $variables = []): string + { + $variables = $this->setOutputEscapeCallback($variables, $this->escapeVariableName, $this->customOutputEscapeCallback); + return $this->templateRenderer->renderTemplate($template, $variables); + } + /** + * @param mixed $value + */ + public function escapeOutput($value): string + { + $string_value = $this->caseToString($value); + return htmlspecialchars($string_value, \ENT_QUOTES, 'UTF-8', \false); + } + /** + * @param array $variables + * @param callable(mixed $variable): string|null $customOutputEscapeCallback + * + * @return array + */ + protected function setOutputEscapeCallback(array $variables, string $escapeCallbackName, ?callable $customOutputEscapeCallback): array + { + return array_merge($variables, [$escapeCallbackName => null === $customOutputEscapeCallback ? [$this, 'escapeOutput'] : $customOutputEscapeCallback]); + } + /** + * @param mixed $value + */ + protected function caseToString($value): string + { + if (\true === is_string($value) || \true === is_numeric($value)) { + return (string) $value; + } + if (\true === is_object($value) && method_exists($value, '__toString')) { + return (string) $value; + } + return ''; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithEventDetails.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithEventDetails.php new file mode 100644 index 0000000..131889b --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithEventDetails.php @@ -0,0 +1,31 @@ +templateRenderer = $templateRenderer; + $this->eventDispatcher = $eventDispatcher; + $this->eventName = $eventName; + } + public function renderTemplate(string $template, array $variables = []): string + { + $eventDetails = ['template' => $template]; + $this->eventDispatcher->registerEventDetails($this->eventName, $eventDetails); + $response = $this->templateRenderer->renderTemplate($template, $variables); + $this->eventDispatcher->unregisterEventDetails($this->eventName, $eventDetails); + return $response; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithFileTemplate.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithFileTemplate.php new file mode 100644 index 0000000..e42de8f --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithFileTemplate.php @@ -0,0 +1,30 @@ +templateRenderer = $templateRenderer; + } + public function renderTemplate(string $template, array $variables = []): string + { + $template = $this->getFileContent($template); + return $this->templateRenderer->renderTemplate($template, $variables); + } + protected function getFileContent(string $file): string + { + if (\false === file_exists($file)) { + return ''; + } + return (string) file_get_contents($file); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithModelsRender.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithModelsRender.php new file mode 100644 index 0000000..2ce4f85 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/Template/TemplateRendererWithModelsRender.php @@ -0,0 +1,56 @@ +templateRenderer = $templateRenderer; + $this->modelRenderer = $modelRenderer; + } + public function renderTemplate(string $template, array $variables = []): string + { + $variables = $this->renderModels($variables); + return $this->templateRenderer->renderTemplate($template, $variables); + } + /** + * @param array $variables + * + * @return array + */ + protected function renderModels(array $variables): array + { + return array_map(function ($item) { + return $this->renderIfModel($item); + }, $variables); + } + /** + * @param mixed $item + * + * @return mixed + * + * @throws Exception + */ + protected function renderIfModel($item) + { + if (\true === $item instanceof TemplateModelInterface) { + $item = $this->modelRenderer->renderModel($item); + } elseif (\true === is_array($item) && \false === is_callable($item)) { + // @phpstan-ignore-next-line + $item = $this->renderModels($item); + } + return $item; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/View/ViewNamespace.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/View/ViewNamespace.php new file mode 100644 index 0000000..4244216 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/View/ViewNamespace.php @@ -0,0 +1,92 @@ +getModules(); + //// 1. Modules creation: + $templateErrorEventName = $config->getTemplateErrorEventName(); + $eventDispatcher = $modules->getEventDispatcher(); + $eventDispatcher = null === $eventDispatcher ? new EventDispatcher() : $eventDispatcher; + $templateErrorHandler = $config->getTemplateErrorHandler(); + if (null !== $templateErrorHandler) { + $eventDispatcher->addEventListener($templateErrorEventName, $templateErrorHandler); + } + $objectReader = $modules->getObjectReader(); + $objectReader = null === $objectReader ? new ObjectReader() : $objectReader; + $objectPropertyWriter = $modules->getObjectPropertyWriter(); + $objectPropertyWriter = null === $objectPropertyWriter ? new ObjectPropertyWriter() : $objectPropertyWriter; + $modelNamespaceProvider = $modules->getModelNamespaceResolver(); + $modelNamespaceProvider = null === $modelNamespaceProvider ? new ModelNamespaceResolver(new ObjectClassReader()) : $modelNamespaceProvider; + $modelNameProvider = $modules->getModelNameResolver(); + $modelNameProvider = null === $modelNameProvider ? new ModelNameResolver(new ObjectClassReader()) : $modelNameProvider; + $modelTemplateResolver = $modules->getModelTemplateResolver(); + $modelTemplateResolver = null === $modelTemplateResolver ? new FileModelTemplateResolver($namespace, $config->getTemplatesRootPath(), $config->getTemplateFileExtension(), $config->fileBasedTemplates(), $modelNamespaceProvider, $modelNameProvider) : $modelTemplateResolver; + $propertyValueProvider = $modules->getPropertyValueProvider(); + $propertyValueProvider = null === $propertyValueProvider ? new PropertyValueProvider() : $propertyValueProvider; + $propertyValueProvider = new PropertyValueProviderByTypes($propertyValueProvider, $config->getDefaultPropertyValues()); + $propertyValueProvider = new PropertyValueProviderForModels($propertyValueProvider, $modelFactoryWithNamespaces); + $propertyValueProvider = new PropertyValueProviderForNullable($propertyValueProvider); + // Without null check - templateRenderer is a mandatory module. + $templateRenderer = $modules->getTemplateRenderer(); + $templateRendererWithModelsRender = new TemplateRendererWithModelsRender($templateRenderer, $modelRendererWithNamespace); + if (\true === $config->modelsAsStringsInTemplates()) { + $templateRenderer = $templateRendererWithModelsRender; + } + //// 2. Real Factory and Renderer creation (used in the ViewsManager class): + $realModelFactory = $modules->getModelFactory(); + $realModelFactory = null === $realModelFactory ? new ModelFactory($objectReader, $propertyValueProvider, $modelTemplateResolver, $templateRendererWithModelsRender) : $realModelFactory; + $realModelFactory = new ModelFactoryWithDefaultsManagement( + $realModelFactory, + // Plain reader, without rendering. + $objectReader, + $objectPropertyWriter + ); + $realModelFactory = new ModelFactoryWithSetupCallback($realModelFactory); + $realModelRenderer = $modules->getModelRenderer(); + $realModelRenderer = null === $realModelRenderer ? new ModelRenderer($templateRenderer, $modelFactoryWithNamespaces, $modelTemplateResolver) : $realModelRenderer; + $realModelRenderer = new ModelRendererWithEventDetails($realModelRenderer, $eventDispatcher, $templateErrorEventName); + //// 3. Now we can save the objects to the storage. + $modules->setEventDispatcher($eventDispatcher)->setObjectReader($objectReader)->setObjectPropertyWriter($objectPropertyWriter)->setModelTemplateResolver($modelTemplateResolver)->setPropertyValueProvider($propertyValueProvider)->setModelFactory($realModelFactory)->setModelRenderer($realModelRenderer)->setModelNamespaceResolver($modelNamespaceProvider)->setModelNameResolver($modelNameProvider); + $this->modules = $modules; + } + public function getModules(): ViewNamespaceModules + { + return $this->modules; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/View/ViewNamespaceModulesContainer.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/View/ViewNamespaceModulesContainer.php new file mode 100644 index 0000000..8809710 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/private-classes/View/ViewNamespaceModulesContainer.php @@ -0,0 +1,34 @@ + + */ + private array $viewNamespaceModules; + public function __construct() + { + $this->viewNamespaceModules = []; + } + public function registerNamespaceModules(string $namespace, ViewNamespaceModules $viewNamespaceModules): void + { + $this->viewNamespaceModules[$namespace] = $viewNamespaceModules; + // Sort to ensure the rule is followed: more specific namespaces take precedence. + // For example, /My/Package/Blade will be processed before the more generic /My/Package. + uksort($this->viewNamespaceModules, function (string $key1, string $key2): int { + return strlen($key2) <=> strlen($key1); + }); + } + public function resolveNamespaceModules(string $modelNamespace): ?ViewNamespaceModules + { + $matchedNamespaces = array_filter($this->viewNamespaceModules, function (ViewNamespaceModules $viewNamespaceModules, string $namespace) use ($modelNamespace) { + return 0 === strpos($modelNamespace, $namespace); + }, \ARRAY_FILTER_USE_BOTH); + return count($matchedNamespaces) > 0 ? reset($matchedNamespaces) : null; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/BaseTemplateModel.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/BaseTemplateModel.php new file mode 100644 index 0000000..949bf57 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/BaseTemplateModel.php @@ -0,0 +1,64 @@ +objectReader = $objectPropertyReader; + $this->propertyValueProviderForDefaults = $propertyValueProviderForDefaults; + $this->modelTemplateResolver = $modelTemplateResolver; + $this->templateRenderer = $templateRenderer; + $this->setCustomDefaults(); + } + public function getTemplateArguments(): array + { + return $this->objectReader->extractObjectVariables($this); + } + public function getDefaultPropertyValueProvider(): PropertyValueProviderInterface + { + return $this->propertyValueProviderForDefaults; + } + protected function setCustomDefaults(): void + { + } + public function __toString() + { + $template = $this->modelTemplateResolver->resolveModelTemplate($this); + $arguments = $this->getTemplateArguments(); + return $this->templateRenderer->renderTemplate($template, $arguments); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/CodeRunnerInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/CodeRunnerInterface.php new file mode 100644 index 0000000..d548d39 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/CodeRunnerInterface.php @@ -0,0 +1,12 @@ + $arguments + */ + public function runCode(string $code, array $arguments = []): void; +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/EventDispatcherInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/EventDispatcherInterface.php new file mode 100644 index 0000000..e7cac1a --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/EventDispatcherInterface.php @@ -0,0 +1,28 @@ + $eventDetails + */ + public function dispatchEvent(string $eventName, array $eventDetails): void; + /** + * @param callable(array $eventDetails):void $eventListener + */ + public function addEventListener(string $eventName, callable $eventListener): void; + /** + * @param callable(array $eventDetails):void $eventListener + */ + public function removeEventListener(string $eventName, callable $eventListener): void; + /** + * @param array $eventDetails + */ + public function registerEventDetails(string $eventName, array $eventDetails): void; + /** + * @param array $eventDetails + */ + public function unregisterEventDetails(string $eventName, array $eventDetails): void; +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelFactoryInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelFactoryInterface.php new file mode 100644 index 0000000..080bdf4 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelFactoryInterface.php @@ -0,0 +1,21 @@ + $modelClass + * @param Closure(T):void|null $setupModelCallback + * + * @return T + * + * @throws Exception + */ + public function createModel(string $modelClass, ?Closure $setupModelCallback = null); +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelNameResolverInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelNameResolverInterface.php new file mode 100644 index 0000000..61c34ce --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelNameResolverInterface.php @@ -0,0 +1,9 @@ + $modelOrClass + */ + public function resolveModelNamespace($modelOrClass): string; +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelRendererInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelRendererInterface.php new file mode 100644 index 0000000..6e7e4db --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/ModelRendererInterface.php @@ -0,0 +1,19 @@ + $modelOrClass + * @param Closure(T):void|null $setupModelCallback + * + * @throws Exception + */ + public function renderModel($modelOrClass, ?Closure $setupModelCallback = null): string; +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/TemplateModelInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/TemplateModelInterface.php new file mode 100644 index 0000000..c053394 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/TemplateModelInterface.php @@ -0,0 +1,12 @@ + + */ + public function getTemplateArguments(): array; +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/TemplateModelWithDefaultsInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/TemplateModelWithDefaultsInterface.php new file mode 100644 index 0000000..b1468dd --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Model/TemplateModelWithDefaultsInterface.php @@ -0,0 +1,10 @@ + name => value (or callback) + */ + public function extractObjectVariables(object $instance): array; +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Object/PropertyValueProviderInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Object/PropertyValueProviderInterface.php new file mode 100644 index 0000000..f8ef66c --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/Object/PropertyValueProviderInterface.php @@ -0,0 +1,14 @@ + $variables + */ + public function renderTemplate(string $template, array $variables = []): string; +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/View/ViewNamespaceManagerInterface.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/View/ViewNamespaceManagerInterface.php new file mode 100644 index 0000000..d2064a4 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/Interfaces/View/ViewNamespaceManagerInterface.php @@ -0,0 +1,11 @@ + $eventDetails): void|null + */ + private $templateErrorHandler; + private string $templateErrorEventName; + /** + * @var array + */ + private array $defaultPropertyValues; + private ViewNamespaceModules $modules; + public function __construct(TemplateRendererInterface $templateRenderer) + { + $this->templatesRootPath = ''; + $this->templateFileExtension = ''; + $this->fileBasedTemplates = \true; + $this->modelsAsStringsInTemplates = \false; + $this->templateErrorHandler = null; + $this->defaultPropertyValues = array('array' => array(), 'bool' => \false, 'float' => 0.0, 'int' => 0, 'string' => ''); + $this->templateErrorEventName = 'template_error'; + $this->modules = new ViewNamespaceModules($templateRenderer); + } + //// Getters. + public function getTemplatesRootPath(): string + { + return $this->templatesRootPath; + } + public function getTemplateFileExtension(): string + { + return $this->templateFileExtension; + } + public function fileBasedTemplates(): bool + { + return $this->fileBasedTemplates; + } + public function modelsAsStringsInTemplates(): bool + { + return $this->modelsAsStringsInTemplates; + } + /** + * @return callable(array $eventDetails): void|null + */ + public function getTemplateErrorHandler(): ?callable + { + return $this->templateErrorHandler; + } + public function getTemplateErrorEventName(): string + { + return $this->templateErrorEventName; + } + /** + * @return array + */ + public function getDefaultPropertyValues(): array + { + return $this->defaultPropertyValues; + } + public function getModules(): ViewNamespaceModules + { + return $this->modules; + } + //// Setters: + public function setTemplatesRootPath(string $templatesRootPath): self + { + $this->templatesRootPath = $templatesRootPath; + return $this; + } + public function setTemplateFileExtension(string $templateFileExtension): self + { + $this->templateFileExtension = $templateFileExtension; + return $this; + } + public function setFileBasedTemplates(bool $fileBasedTemplates): self + { + $this->fileBasedTemplates = $fileBasedTemplates; + return $this; + } + public function setModelsAsStringsInTemplates(bool $modelsAsStringsInTemplates): self + { + $this->modelsAsStringsInTemplates = $modelsAsStringsInTemplates; + return $this; + } + /** + * @param callable(array $eventDetails): void|null $templateErrorHandler + */ + public function setTemplateErrorHandler(?callable $templateErrorHandler): self + { + $this->templateErrorHandler = $templateErrorHandler; + return $this; + } + /** + * @param array $defaultPropertyValues + */ + public function setDefaultPropertyValues(array $defaultPropertyValues): self + { + $this->defaultPropertyValues = $defaultPropertyValues; + return $this; + } + public function setTemplateErrorEventName(string $templateErrorEventName): self + { + $this->templateErrorEventName = $templateErrorEventName; + return $this; + } + public function setModules(ViewNamespaceModules $modules): self + { + $this->modules = $modules; + return $this; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewNamespaceModules.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewNamespaceModules.php new file mode 100644 index 0000000..717e1cf --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewNamespaceModules.php @@ -0,0 +1,139 @@ +templateRenderer = $templateRenderer; + $this->modelFactory = null; + $this->modelTemplateResolver = null; + $this->objectReader = null; + $this->objectPropertyWriter = null; + $this->propertyValueProvider = null; + $this->modelRenderer = null; + $this->eventDispatcher = null; + $this->modelNameResolver = null; + $this->modelNamespaceResolver = null; + } + //// Getters. + public function getTemplateRenderer(): TemplateRendererInterface + { + return $this->templateRenderer; + } + public function getModelFactory(): ?ModelFactoryInterface + { + return $this->modelFactory; + } + public function getModelTemplateResolver(): ?ModelTemplateResolverInterface + { + return $this->modelTemplateResolver; + } + public function getObjectReader(): ?ObjectReaderInterface + { + return $this->objectReader; + } + public function getObjectPropertyWriter(): ?ObjectPropertyWriterInterface + { + return $this->objectPropertyWriter; + } + public function getPropertyValueProvider(): ?PropertyValueProviderInterface + { + return $this->propertyValueProvider; + } + public function getModelRenderer(): ?ModelRendererInterface + { + return $this->modelRenderer; + } + public function getEventDispatcher(): ?EventDispatcherInterface + { + return $this->eventDispatcher; + } + public function getModelNameResolver(): ?ModelNameResolverInterface + { + return $this->modelNameResolver; + } + public function getModelNamespaceResolver(): ?ModelNamespaceResolverInterface + { + return $this->modelNamespaceResolver; + } + //// Setters. + public function setTemplateRenderer(TemplateRendererInterface $templateRenderer): self + { + $this->templateRenderer = $templateRenderer; + return $this; + } + public function setModelFactory(?ModelFactoryInterface $viewFactory): self + { + $this->modelFactory = $viewFactory; + return $this; + } + public function setModelTemplateResolver(?ModelTemplateResolverInterface $modelTemplateResolver): self + { + $this->modelTemplateResolver = $modelTemplateResolver; + return $this; + } + public function setObjectReader(?ObjectReaderInterface $objectPropertyReader): self + { + $this->objectReader = $objectPropertyReader; + return $this; + } + public function setObjectPropertyWriter(?ObjectPropertyWriterInterface $objectPropertyWriter): self + { + $this->objectPropertyWriter = $objectPropertyWriter; + return $this; + } + public function setPropertyValueProvider(?PropertyValueProviderInterface $propertyValueProvider): self + { + $this->propertyValueProvider = $propertyValueProvider; + return $this; + } + public function setModelRenderer(?ModelRendererInterface $viewRenderer): self + { + $this->modelRenderer = $viewRenderer; + return $this; + } + public function setEventDispatcher(?EventDispatcherInterface $eventDispatcher): self + { + $this->eventDispatcher = $eventDispatcher; + return $this; + } + public function setModelNameResolver(?ModelNameResolverInterface $modelNameResolver): self + { + $this->modelNameResolver = $modelNameResolver; + return $this; + } + public function setModelNamespaceResolver(?ModelNamespaceResolverInterface $modelNamespaceResolver): self + { + $this->modelNamespaceResolver = $modelNamespaceResolver; + return $this; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRenderer.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRenderer.php new file mode 100644 index 0000000..3a9848b --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRenderer.php @@ -0,0 +1,63 @@ +getModules(); + $errorEventName = $config->getTemplateErrorEventName(); + $eventDispatcher = $modules->getEventDispatcher(); + $eventDispatcher = null === $eventDispatcher ? new EventDispatcher() : $eventDispatcher; + $templateErrorHandler = $config->getTemplateErrorHandler(); + if (null !== $templateErrorHandler) { + $eventDispatcher->addEventListener($errorEventName, $templateErrorHandler); + } + $templateCompiler = $modules->getTemplateCompiler(); + $templateCompiler = null === $templateCompiler ? new BladeCompiler($config->getEscapeVariableName(), $config->getCompilerExtensionCallback()) : $templateCompiler; + $codeExecutor = $modules->getCodeExecutor(); + $codeExecutor = null === $codeExecutor ? new PhpCodeRunner() : $codeExecutor; + $codeExecutor = new CodeRunnerWithErrorHandler($codeExecutor, $eventDispatcher, $errorEventName); + $codeExecutor = new CodeRunnerWithGlobalArguments($codeExecutor, $config->getGlobalVariables()); + $codeExecutor = new CodeRunnerWithTemplateCompilation($codeExecutor, $templateCompiler); + $templateRenderer = $modules->getTemplateRenderer(); + $templateRenderer = null === $templateRenderer ? new TemplateRenderer($codeExecutor) : $templateRenderer; + if (\true === $config->fileBasedTemplates()) { + $templateRenderer = new TemplateRendererWithFileTemplate($templateRenderer); + } + $templateRenderer = new TemplateRendererWithCustomEscape($templateRenderer, $config->getCustomOutputEscapeCallback(), $config->getEscapeVariableName()); + $templateRenderer = new TemplateRendererWithEventDetails($templateRenderer, $eventDispatcher, $errorEventName); + $modules->setEventDispatcher($eventDispatcher)->setTemplateCompiler($templateCompiler)->setTemplateRenderer($templateRenderer)->setCodeExecutor($codeExecutor); + $this->modules = $modules; + $this->templateRenderer = $templateRenderer; + } + public function renderTemplate(string $template, array $variables = []): string + { + return $this->templateRenderer->renderTemplate($template, $variables); + } + public function getModules(): ViewTemplateRendererModules + { + return $this->modules; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRendererConfig.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRendererConfig.php new file mode 100644 index 0000000..2b4812c --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRendererConfig.php @@ -0,0 +1,141 @@ + + */ + private array $globalVariables; + /** + * @var callable(array $eventDetails):void|null + */ + private $templateErrorHandler; + /** + * @var callable(mixed $variable): string|null + */ + private $customOutputEscapeCallback; + /** + * @var callable(string $template): string|null + */ + private $compilerExtensionCallback; + private ViewTemplateRendererModules $modules; + public function __construct() + { + $this->fileBasedTemplates = \true; + $this->escapeVariableName = 'escape'; + $this->templateErrorEventName = 'template_error'; + $this->globalVariables = []; + $this->templateErrorHandler = null; + $this->customOutputEscapeCallback = null; + $this->compilerExtensionCallback = null; + $this->modules = new ViewTemplateRendererModules(); + } + //// Getters: + public function fileBasedTemplates(): bool + { + return $this->fileBasedTemplates; + } + /** + * @return callable(array $eventDetails):void|null + */ + public function getTemplateErrorHandler(): ?callable + { + return $this->templateErrorHandler; + } + /** + * @return array + */ + public function getGlobalVariables(): array + { + return $this->globalVariables; + } + /** + * @return callable(mixed $variable): string|null + */ + public function getCustomOutputEscapeCallback(): ?callable + { + return $this->customOutputEscapeCallback; + } + public function getEscapeVariableName(): string + { + return $this->escapeVariableName; + } + /** + * @return callable(string $template): string|null + */ + public function getCompilerExtensionCallback(): ?callable + { + return $this->compilerExtensionCallback; + } + public function getTemplateErrorEventName(): string + { + return $this->templateErrorEventName; + } + public function getModules(): ViewTemplateRendererModules + { + return $this->modules; + } + //// Setters: + public function setFileBasedTemplates(bool $fileBasedTemplates): self + { + $this->fileBasedTemplates = $fileBasedTemplates; + return $this; + } + /** + * @param callable(array $eventDetails):void|null $templateErrorHandler + */ + public function setTemplateErrorHandler(?callable $templateErrorHandler): self + { + $this->templateErrorHandler = $templateErrorHandler; + return $this; + } + /** + * @param array $globalVariables + */ + public function setGlobalVariables(array $globalVariables): self + { + $this->globalVariables = $globalVariables; + return $this; + } + /** + * @param callable(string $template): string|null $compilerExtensionCallback + */ + public function setCompilerExtensionCallback(?callable $compilerExtensionCallback): self + { + $this->compilerExtensionCallback = $compilerExtensionCallback; + return $this; + } + /** + * @param callable(mixed $variable): string|null $customOutputEscapeCallback + */ + public function setCustomOutputEscapeCallback(?callable $customOutputEscapeCallback): self + { + $this->customOutputEscapeCallback = $customOutputEscapeCallback; + return $this; + } + public function setEscapeVariableName(string $escapeVariableName): self + { + $this->escapeVariableName = $escapeVariableName; + return $this; + } + public function setTemplateErrorEventName(string $templateErrorEventName): self + { + $this->templateErrorEventName = $templateErrorEventName; + return $this; + } + public function setModules(ViewTemplateRendererModules $modules): self + { + $this->modules = $modules; + return $this; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRendererModules.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRendererModules.php new file mode 100644 index 0000000..6ea99ba --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/View/ViewTemplateRendererModules.php @@ -0,0 +1,66 @@ +templateRenderer = null; + $this->eventDispatcher = null; + $this->templateCompiler = null; + $this->phpCodeExecutor = null; + } + //// Getters. + public function getTemplateRenderer(): ?TemplateRendererInterface + { + return $this->templateRenderer; + } + public function getEventDispatcher(): ?EventDispatcherInterface + { + return $this->eventDispatcher; + } + public function getTemplateCompiler(): ?TemplateCompilerInterface + { + return $this->templateCompiler; + } + public function getCodeExecutor(): ?CodeRunnerInterface + { + return $this->phpCodeExecutor; + } + //// Setters. + public function setTemplateRenderer(?TemplateRendererInterface $templateRenderer): self + { + $this->templateRenderer = $templateRenderer; + return $this; + } + public function setEventDispatcher(?EventDispatcherInterface $eventDispatcher): self + { + $this->eventDispatcher = $eventDispatcher; + return $this; + } + public function setTemplateCompiler(?TemplateCompilerInterface $templateCompiler): self + { + $this->templateCompiler = $templateCompiler; + return $this; + } + public function setCodeExecutor(?CodeRunnerInterface $codeExecutor): self + { + $this->phpCodeExecutor = $codeExecutor; + return $this; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/ViewsManager.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/ViewsManager.php new file mode 100644 index 0000000..803aaf0 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/ViewsManager.php @@ -0,0 +1,111 @@ +getModelNamespaceProvider(); + $this->modelNamespaceProvider = null === $modelNamespaceProvider ? new ModelNamespaceResolver(new ObjectClassReader()) : $modelNamespaceProvider; + $namespaceModulesContainer = $config->getNamespaceModulesContainer(); + $this->namespaceModulesContainer = null === $namespaceModulesContainer ? new ViewNamespaceModulesContainer() : $namespaceModulesContainer; + $this->namespaceNotFoundErrorMessage = $config->getNamespaceNotFoundErrorMessage(); + $this->wrongModelErrorMessage = $config->getWrongModelErrorMessage(); + } + public function registerNamespace(string $namespace, ViewNamespaceConfig $config): ViewNamespaceModules + { + $viewNamespace = $this->makeViewNamespace($namespace, $config); + $viewNamespaceModules = $viewNamespace->getModules(); + $this->namespaceModulesContainer->registerNamespaceModules($namespace, $viewNamespaceModules); + return $viewNamespaceModules; + } + public function createModel(string $modelClass, ?Closure $setupModelCallback = null) + { + if (\false === $this->isModel($modelClass)) { + throw $this->makeWrongModelException($modelClass); + } + $modelNamespace = $this->modelNamespaceProvider->resolveModelNamespace($modelClass); + $namespaceModules = $this->namespaceModulesContainer->resolveNamespaceModules($modelNamespace); + if (null === $namespaceModules) { + throw $this->makeNamespaceNotResolvedException($modelNamespace); + } + $modelFactory = $namespaceModules->getModelFactory(); + if (null === $modelFactory) { + throw $this->makeNamespaceNotResolvedException($modelNamespace); + } + return $modelFactory->createModel($modelClass, $setupModelCallback); + } + public function renderModel($modelOrClass, ?Closure $setupModelCallback = null): string + { + if (\false === $this->isModel($modelOrClass)) { + throw $this->makeWrongModelException($modelOrClass); + } + $modelNamespace = $this->modelNamespaceProvider->resolveModelNamespace($modelOrClass); + $namespaceModules = $this->namespaceModulesContainer->resolveNamespaceModules($modelNamespace); + if (null === $namespaceModules) { + throw $this->makeNamespaceNotResolvedException($modelNamespace); + } + $modelRenderer = $namespaceModules->getModelRenderer(); + if (null === $modelRenderer) { + throw $this->makeNamespaceNotResolvedException($modelNamespace); + } + return $modelRenderer->renderModel($modelOrClass, $setupModelCallback); + } + protected function makeViewNamespace(string $namespace, ViewNamespaceConfig $config): ViewNamespace + { + return new ViewNamespace($namespace, $config, $this, $this); + } + protected function makeNamespaceNotResolvedException(string $namespace): Exception + { + $message = sprintf('%s : %s', $this->namespaceNotFoundErrorMessage, $namespace); + return new Exception($message); + } + /** + * @param string|object $modelOrClass + */ + protected function makeWrongModelException($modelOrClass): Exception + { + $modelClass = \true === is_object($modelOrClass) ? get_class($modelOrClass) : $modelOrClass; + $message = sprintf('%s : %s', $this->wrongModelErrorMessage, $modelClass); + return new Exception($message); + } + /** + * @param string|object $modelOrClass + */ + protected function isModel($modelOrClass): bool + { + if (\true === is_object($modelOrClass)) { + return $modelOrClass instanceof TemplateModelInterface; + } + if (\false === class_exists($modelOrClass)) { + return \false; + } + $implementedList = class_implements($modelOrClass); + return \true === in_array(TemplateModelInterface::class, $implementedList, \true); + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/ViewsManagerConfig.php b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/ViewsManagerConfig.php new file mode 100644 index 0000000..de8756e --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/prosopo/views/src/ViewsManagerConfig.php @@ -0,0 +1,63 @@ +modelNamespaceProvider = null; + $this->namespaceModulesContainer = null; + $this->namespaceNotFoundErrorMessage = 'Model namespace cannot be resolved'; + $this->wrongModelErrorMessage = 'Passed Model does not implement TemplateModelInterface'; + } + //// Getters: + public function getNamespaceNotFoundErrorMessage(): string + { + return $this->namespaceNotFoundErrorMessage; + } + public function getWrongModelErrorMessage(): string + { + return $this->wrongModelErrorMessage; + } + public function getModelNamespaceProvider(): ?ModelNamespaceResolverInterface + { + return $this->modelNamespaceProvider; + } + public function getNamespaceModulesContainer(): ?ViewNamespaceModulesContainerInterface + { + return $this->namespaceModulesContainer; + } + //// Setters: + public function setNamespaceNotFoundErrorMessage(string $namespaceNotFoundErrorMessage): self + { + $this->namespaceNotFoundErrorMessage = $namespaceNotFoundErrorMessage; + return $this; + } + public function setWrongModelErrorMessage(string $wrongModelErrorMessage): self + { + $this->wrongModelErrorMessage = $wrongModelErrorMessage; + return $this; + } + public function setModelNamespaceProvider(?ModelNamespaceResolverInterface $modelNamespaceProvider): self + { + $this->modelNamespaceProvider = $modelNamespaceProvider; + return $this; + } + public function setNamespaceModulesContainer(?ViewNamespaceModulesContainerInterface $namespaceModulesContainer): self + { + $this->namespaceModulesContainer = $namespaceModulesContainer; + return $this; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/scoper-autoload.php b/prosopo-procaptcha/prefixed-vendors/vendor/scoper-autoload.php new file mode 100644 index 0000000..d42ccd1 --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/scoper-autoload.php @@ -0,0 +1,34 @@ + `Typed` is a lightweight PHP utility for seamless type-casting and data retrieval from dynamic variables, arrays, and +> objects. + +This package provides a single `Typed` class with static methods and offers compatibility with PHP versions `7.4+` and +`8.0+`. + +## 1. Why Use Typed? + +Handling type casting in PHP often leads to verbose and repetitive constructions, especially in array-related cases. + +`Typed` streamlines this process, +allowing you to fetch and cast values with concise, readable code. + +**Example: Plain PHP** + +```php +function getTypedIntFromArray(array $array): int +{ + return true === isset($array['meta']['number']) && + true === is_numeric($array['meta']['number']) + ? (int)$array['meta']['number'] + : 0; +} + +function getTypedStringFromMixedVariable($mixed): string +{ + return true === is_string($mixed) || + true === is_numeric($mixed) + ? (string)$mixed + : ''; +} +``` + +**The same with the `Typed` utility** + +```php +use function WPLake\Typed\int; +use function WPLake\Typed\string; + +function getTypedIntFromArray(array $data): int +{ + return int($data, 'meta.number'); +} + +function getTypedStringFromMixedVariable($mixedData): string +{ + return string($mixedData); +} +``` + +The code like `string($array, 'key')` resembles `(string)$array['key']` while being +safe and smart — it even handles nested keys. + +> In case now you're thinking: "Hold on guys, but this code won't work! Are your using type names as function names?" +> +> Our answer is: "Yes! And actually it isn't prohibited." +> +> See the explanation in the special section - [5. Note about the function names](#5-note-about-the-function-names) + +Backing to the package. Want to provide a default value when the key is missing? Here you go: + +```php +string($data, 'some.key', 'Default Value'); +``` + +Don't like functions? The same functions set is available as static methods of the `Typed` class: + +```php +use WPLake\Typed\Typed; + +Typed::int($data,'key'); +``` + +## 2. Installation and usage + +Typed class is distributed as a Composer package, making installation straightforward: + +`composer require wplake/typed` + +After installation, ensure that your application includes the Composer autoloader (if it hasn’t been included already): + +`require __DIR__ . '/vendor/autoload.php';` + +Usage: + +```php +use function WPLake\Typed\string; +use WPLake\Typed\Typed; + +$string = string($array, 'first.second','default value'); +// alternatively: +$string = Typed::string($array, 'first.second','default value'); +``` + +## 3. Supported types + +Functions for the following types are present: + +* `string` +* `int` +* `float` +* `bool` +* `array` +* `object` +* `dateTime` +* `any` (allows to use short dot-keys usage for unknowns) + +Additionally: + +* `boolExtended` (`true`,`1`,`"1"`, `"on"` are treated as true, `false`,`0`,`"0"`, `"off"` as false) +* `stringExtended` (supports objects with `__toString`) + +For optional cases, each item has an `OrNull` method option (e.g. `stringOrNull`, `intOrNull`, and so on), +which returns `null` if the key doesn’t exist. + +## 4. How It Works + +The logic of all casting methods follows this simple principle: + +> “Provide me a value of the requested type from the given source by the given path, or return the default value.” + +For example, let's review the `string` method declaration: + +```php +namespace WPLake\Typed; + +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function string($source, $keys = null, string $default = ''): string; +``` + +Usage Scenarios: + +1. Extract a string from a mixed variable (returning the default if absent or of an incompatible type) + +```php +$userName = string($unknownVar); +``` + +2. Retrieve a string from an array, including nested structures (with dot notation or as an array). + +```php +$userName = string($array, 'user.name'); +// alternatively: +$userName = string($array, ['user','name',]); +``` + +3. Access a string from an object. It also supports the nested properties. + +```php +$userName = string($companyObject, 'user.name'); +// alternatively: +$userName = string($companyObject, ['user', 'name',]); +``` + +4. Work with mixed structures (e.g., `object->arrayProperty['key']->anotherProperty or ['key' => $object]`). + +```php +$userName = string($companyObject,'users.john.name'); +// alternatively: +$userName = string($companyObject,['users','john','name',]); +``` + +In all the cases, you can pass a default value as the third argument, e.g.: + +```php +$userName = string($companyObject,'users.john.name', 'Guest'); +``` + +## 5. Note about the function names + +Surprisingly, PHP allows functions to use the same names as variable types. + +Think it’s prohibited? Not quite! While certain names are restricted for classes, interfaces, and traits, function names +are not: + +> “These names cannot be used to name a **class, interface, or +> trait**” - [PHP Manual: Reserved Other Reserved Words](https://www.php.net/manual/en/reserved.other-reserved-words.php) + +This means you we can have things like `string($array, 'key')`, which resembles `(string)$array['key']` while being +safer +and smarter — it even handles nested keys. + +Note: Unlike all the other types, the `array` keyword falls under +a [different category](https://www.php.net/manual/en/reserved.keywords.php), which also prohibits its usage for function +names. That's why in this case we used the `arr` name instead. + +## 6. FAQ + +### 6.1) Why not just straight type casting? + +Straight type casting in PHP can be unsafe and unpredictable in certain scenarios. + +For example, the following code will throw an error if the `$mixed` variable is an object of a class that doesn’t +explicitly implement `__toString`: + +```php +class Example { +// ... +} +$mixed = new Example(); +// ... +function getName($mixed):void{ + return (string)$mixed; +} +``` + +Additionally, attempting to cast an array to a string, like `(string)$myArray` will: + +1. Produce a PHP Notice: Array to string conversion. +2. Return the string "Array", which is rarely the intended behavior. + +This unpredictability can lead to unexpected bugs and unreliable code. + +### 6.2) Why not just Null Coalescing Operator? + +While the Null Coalescing Operator (`??`) is useful, it doesn’t address type checking or casting requirements. + +```php +// Plain PHP: +$number = $data['meta']['number']?? 10; +$number = true === is_numeric($number)? +(int)$number: +10; + +// Typed: +$number = Typed::int($data, 'meta.number', 10); +``` + +Additionally, with Null Coalescing Operator and a custom default value, you have to repeat yourself. + +### 6.3) Shouldn't we use typed objects instead? + +OOP is indeed powerful, and you should always prioritize using objects whenever possible. However, the reality is that +our code often interacts with external dependencies beyond our control. + +This package simplifies handling such scenarios. +Any seasoned PHP developer knows the pain of type-casting when working with environments outside of frameworks, e.g. in +WordPress. + +### 6.4) Is the dot syntax in keys inspired by Laravel Collections? + +Yes, the dot syntax is inspired by [Laravel Collections](https://laravel.com/docs/11.x/collections) and similar +solutions. It provides an intuitive way to access +nested data structures. + +### 6.5) Why not just use Laravel Collections? + +Laravel Collections and similar libraries don’t offer type-specific methods like this package does. + +While extending +[Laravel Collections package](https://github.com/illuminate/collections) could be a theoretical solution, we opted for a +standalone package because: + +1. **PHP Version Requirements:** Laravel Collections require PHP 8.2+, while Typed supports PHP 7.4+. +2. **Dependencies:** Laravel Collections bring several external Laravel-specific dependencies. +3. **Global Functions:** Laravel Collections rely on global helper functions, which are difficult to scope when needed. + +In addition, when we only need to extract a single variable, requiring the entire array to be wrapped in a collection +would be excessive. + +## 7. Contribution + +We would be excited if you decide to contribute 🤝 + +Please open Pull Requests against the `main` branch. + +### Code Style Agreements: + +#### 7.1) PSR-12 Compliance + +Use the [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) tool in your IDE with the provided `phpcs.xml`, +or run `composer phpcbf` to format your code. + +#### 7.2) Static Analysis with PHPStan + +Set up [PHPStan](https://phpstan.org/) in your IDE with the provided `phpstan.neon`, or run `composer phpstan` to +validate your code. + +#### 7.3) Unit Tests + +[Pest](https://pestphp.com/) is setup for Unit tests. Run them using `composer pest`. \ No newline at end of file diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/composer.json b/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/composer.json new file mode 100644 index 0000000..18b273e --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/composer.json @@ -0,0 +1,46 @@ +{ + "name": "wplake\/typed", + "description": "Lightweight PHP utility for seamless type-casting and data retrieval from dynamic variables, arrays, and objects.", + "homepage": "https:\/\/github.com\/WPLake\/typed", + "keywords": [ + "type", + "cast" + ], + "license": "Apache-2.0", + "authors": [ + { + "name": "WPLake", + "homepage": "https:\/\/github.com\/WPLake\/" + } + ], + "require": { + "php": "^7.4|^8.0" + }, + "autoload": { + "psr-4": { + "Io\\Prosopo\\Procaptcha\\Vendors\\WPLake\\Typed\\": ".\/src" + }, + "files": [ + ".\/src\/functions.php" + ] + }, + "require-dev": { + "pestphp\/pest": "^3.7", + "phpstan\/phpstan": "^2.0", + "phpstan\/phpstan-strict-rules": "^2.0", + "squizlabs\/php_codesniffer": "^3.11", + "slevomat\/coding-standard": "^8.15" + }, + "config": { + "allow-plugins": { + "pestphp\/pest-plugin": true, + "dealerdirect\/phpcodesniffer-composer-installer": true + } + }, + "scripts": { + "pest": ".\/vendor\/bin\/pest", + "phpstan": "php .\/vendor\/bin\/phpstan analys -c .\/phpstan.neon", + "phpcs": "php .\/vendor\/bin\/phpcs --standard=phpcs.xml .\/src", + "phpcbf": "php .\/vendor\/bin\/phpcbf --standard=phpcs.xml .\/src" + } +} \ No newline at end of file diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/src/Typed.php b/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/src/Typed.php new file mode 100644 index 0000000..e247eea --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/src/Typed.php @@ -0,0 +1,267 @@ +|null $keys + * @param mixed $default + * + * @return mixed + */ + public static function any($source, $keys = null, $default = null) + { + if (null === $keys) { + return $source; + } + if (\false === is_array($keys)) { + $keys = explode('.', (string) $keys); + } + return self::resolveKeys($source, $keys, $default); + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function string($source, $keys = null, string $default = ''): string + { + $value = self::any($source, $keys, $default); + return \true === is_string($value) || \true === is_numeric($value) ? (string) $value : $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function stringExtended($source, $keys = null, string $default = ''): string + { + $value = self::any($source, $keys, $default); + if (\true === is_string($value) || \true === is_numeric($value)) { + return (string) $value; + } + if (\true === is_object($value) && \true === method_exists($value, '__toString')) { + return (string) $value; + } + return $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function stringOrNull($source, $keys = null): ?string + { + $value = self::any($source, $keys); + return \true === is_string($value) || \true === is_numeric($value) ? (string) $value : null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function stringExtendedOrNull($source, $keys = null): ?string + { + $value = self::any($source, $keys); + if (\true === is_string($value) || \true === is_numeric($value)) { + return (string) $value; + } + if (\true === is_object($value) && \true === method_exists($value, '__toString')) { + return (string) $value; + } + return null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function int($source, $keys = null, int $default = 0): int + { + $value = self::any($source, $keys, $default); + return \true === is_numeric($value) ? (int) $value : $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function intOrNull($source, $keys = null): ?int + { + $value = self::any($source, $keys); + return \true === is_numeric($value) ? (int) $value : null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function float($source, $keys = null, float $default = 0.0): float + { + $value = self::any($source, $keys, $default); + return \true === is_numeric($value) ? (float) $value : $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function floatOrNull($source, $keys = null): ?float + { + $value = self::any($source, $keys); + return \true === is_numeric($value) ? (float) $value : null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function bool($source, $keys = null, bool $default = \false): bool + { + $value = self::any($source, $keys, $default); + return \true === is_bool($value) ? $value : $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function boolOrNull($source, $keys = null): ?bool + { + $value = self::any($source, $keys); + return \true === is_bool($value) ? $value : null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + * @param array $positive + * @param array $negative + */ + public static function boolExtended($source, $keys = null, bool $default = \false, array $positive = [\true, 1, '1', 'on'], array $negative = [\false, 0, '0', 'off']): bool + { + $value = self::any($source, $keys, $default); + if (\true === in_array($value, $positive, \true)) { + return \true; + } + if (\true === in_array($value, $negative, \true)) { + return \false; + } + return $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + * @param array $positive + * @param array $negative + */ + public static function boolExtendedOrNull($source, $keys = null, array $positive = [\true, 1, '1', 'on'], array $negative = [\false, 0, '0', 'off']): ?bool + { + $value = self::any($source, $keys); + if (\true === in_array($value, $positive, \true)) { + return \true; + } + if (\true === in_array($value, $negative, \true)) { + return \false; + } + return null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + * @param array $default + * + * @return array + */ + public static function array($source, $keys = null, array $default = []): array + { + $value = self::any($source, $keys, $default); + return \true === is_array($value) ? $value : $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + * + * @return array|null + */ + public static function arrayOrNull($source, $keys = null): ?array + { + $value = self::any($source, $keys); + return \true === is_array($value) ? $value : null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function object($source, $keys = null, ?object $default = null): object + { + $default = null === $default ? new stdClass() : $default; + $value = self::any($source, $keys, $default); + return \true === is_object($value) ? $value : $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function objectOrNull($source, $keys = null): ?object + { + $value = self::any($source, $keys); + return \true === is_object($value) ? $value : null; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function dateTime($source, $keys = null, ?DateTime $default = null): DateTime + { + $default = null === $default ? new DateTime() : $default; + $value = self::object($source, $keys, $default); + return \true === $value instanceof DateTime ? $value : $default; + } + /** + * @param mixed $source + * @param int|string|array|null $keys + */ + public static function dateTimeOrNull($source, $keys = null): ?DateTime + { + $value = self::any($source, $keys); + return \true === $value instanceof DateTime ? $value : null; + } + /** + * @param mixed $source + * @param int|string $key + * @param mixed $value + */ + protected static function resolveKey($source, $key, &$value): bool + { + if (\true === is_object($source) && \true === isset($source->{$key})) { + $value = $source->{$key}; + return \true; + } + if (\true === is_array($source) && \true === isset($source[$key])) { + $value = $source[$key]; + return \true; + } + return \false; + } + /** + * @param mixed $source + * @param array $keys + * @param mixed $default + * + * @return mixed + */ + protected static function resolveKeys($source, array $keys, $default) + { + foreach ($keys as $key) { + $value = null; + if (\true === self::resolveKey($source, $key, $value)) { + $source = $value; + continue; + } + return $default; + } + return $source; + } +} diff --git a/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/src/functions.php b/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/src/functions.php new file mode 100644 index 0000000..270bd3f --- /dev/null +++ b/prosopo-procaptcha/prefixed-vendors/vendor/wplake/typed/src/functions.php @@ -0,0 +1,179 @@ +|null $keys + * @param mixed $default + * + * @return mixed + */ +function any($source, $keys = null, $default = null) +{ + return Typed::any($source, $keys, $default); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function string($source, $keys = null, string $default = ''): string +{ + return Typed::string($source, $keys, $default); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function stringExtended($source, $keys = null, string $default = ''): string +{ + return Typed::stringExtended($source, $keys, $default); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function stringOrNull($source, $keys = null): ?string +{ + return Typed::stringOrNull($source, $keys); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function stringExtendedOrNull($source, $keys = null): ?string +{ + return Typed::stringExtendedOrNull($source, $keys); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function int($source, $keys = null, int $default = 0): int +{ + return Typed::int($source, $keys, $default); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function intOrNull($source, $keys = null): ?int +{ + return Typed::intOrNull($source, $keys); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function float($source, $keys = null, float $default = 0.0): float +{ + return Typed::float($source, $keys, $default); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function floatOrNull($source, $keys = null): ?float +{ + return Typed::floatOrNull($source, $keys); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function bool($source, $keys = null, bool $default = \false): bool +{ + return Typed::bool($source, $keys, $default); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + */ +function boolOrNull($source, $keys = null): ?bool +{ + return Typed::boolOrNull($source, $keys); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + * @param array $positive + * @param array $negative + */ +function boolExtended($source, $keys = null, bool $default = \false, array $positive = [\true, 1, '1', 'on'], array $negative = [\false, 0, '0', 'off']): bool +{ + return Typed::boolExtended($source, $keys, $default, $positive, $negative); +} +/** + * @param mixed $source + * @param int|string|array|null $keys + * @param array $positive + * @param array $negative + */ +function boolExtendedOrNull($source, $keys = null, array $positive = [\true, 1, '1', 'on'], array $negative = [\false, 0, '0', 'off']): ?bool +{ + return Typed::boolExtendedOrNull($source, $keys, $positive, $negative); +} +/** + * Unlike other types, the 'array' keyword falls under a different category, + * which also prohibits its usage for function names – https://www.php.net/manual/en/reserved.keywords.php + * That's why we'll stick to using 'arr' instead. + * + * @param mixed $source + * @param int|string|array|null $keys + * @param array $default + * + * @return array + */ +function arr($source, $keys = null, array $default = []): array +{ + return Typed::array($source, $keys, $default); +} +/** +* @param mixed $source +* @param int|string|array|null $keys +* +* @return array|null +*/ +function arrayOrNull($source, $keys = null): ?array +{ + return Typed::arrayOrNull($source, $keys); +} +/** +* @param mixed $source +* @param int|string|array|null $keys +*/ +function object($source, $keys = null, ?object $default = null): object +{ + return Typed::object($source, $keys, $default); +} +/** +* @param mixed $source +* @param int|string|array|null $keys +*/ +function objectOrNull($source, $keys = null): ?object +{ + return Typed::objectOrNull($source, $keys); +} +/** +* @param mixed $source +* @param int|string|array|null $keys +*/ +function dateTime($source, $keys = null, ?DateTime $default = null): DateTime +{ + return Typed::dateTime($source, $keys, $default); +} +/** +* @param mixed $source +* @param int|string|array|null $keys +*/ +function dateTimeOrNull($source, $keys = null): ?DateTime +{ + return Typed::dateTimeOrNull($source, $keys); +} diff --git a/prosopo-procaptcha/src/Assets_Manager.php b/prosopo-procaptcha/src/Assets_Manager.php index e7747b6..43e33e0 100644 --- a/prosopo-procaptcha/src/Assets_Manager.php +++ b/prosopo-procaptcha/src/Assets_Manager.php @@ -27,7 +27,7 @@ public function get_asset_url( string $asset ): string { public function get_asset_content( string $asset ): string { $file = plugin_dir_path( $this->plugin_file ) . 'dist/' . $asset; - if ( false === $this->wp_filesystem->exists( $file ) ) { + if ( ! $this->wp_filesystem->exists( $file ) ) { return ''; } @@ -37,14 +37,4 @@ public function get_asset_content( string $asset ): string { public function get_assets_version(): string { return $this->version; } - - protected function get_wp_filesystem(): WP_Filesystem_Base { - global $wp_filesystem; - - require_once ABSPATH . 'wp-admin/includes/file.php'; - - WP_Filesystem(); - - return $wp_filesystem; - } } diff --git a/prosopo-procaptcha/src/Autoloader.php b/prosopo-procaptcha/src/Autoloader.php deleted file mode 100644 index 361101d..0000000 --- a/prosopo-procaptcha/src/Autoloader.php +++ /dev/null @@ -1,35 +0,0 @@ -namespace = $name_space; - $this->root_dir = $root_dir; - - spl_autoload_register( array( $this, 'maybe_load_class' ) ); - } - - public function maybe_load_class( string $class_name ): void { - if ( 0 !== strpos( $class_name, $this->namespace ) ) { - return; - } - - $relative_path = substr( $class_name, strlen( $this->namespace ) ); - $relative_path = str_replace( '\\', DIRECTORY_SEPARATOR, $relative_path ); - $full_path = $this->root_dir . $relative_path . '.php'; - - if ( false === file_exists( $full_path ) ) { - return; - } - - require_once $full_path; - } -} diff --git a/prosopo-procaptcha/src/Captcha/Captcha_Assets.php b/prosopo-procaptcha/src/Captcha/Captcha_Assets.php index 8f67ee7..b8ddf97 100644 --- a/prosopo-procaptcha/src/Captcha/Captcha_Assets.php +++ b/prosopo-procaptcha/src/Captcha/Captcha_Assets.php @@ -6,9 +6,9 @@ defined( 'ABSPATH' ) || exit; -use Io\Prosopo\Procaptcha\Collection; use Io\Prosopo\Procaptcha\Interfaces\Assets_Manager_Interface; use Io\Prosopo\Procaptcha\Settings\Tabs\General_Settings; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class Captcha_Assets { @@ -26,11 +26,14 @@ public function add_module_attr_when_missing( string $tag ): string { return str_replace( 'src', 'type="module" src', $tag ); } - public function enqueue_widget_js( string $handle, Assets_Manager_Interface $assets_manager, Collection $general_settings ): void { + /** + * @param array $general_settings + */ + public function enqueue_widget_js( string $handle, Assets_Manager_Interface $assets_manager, array $general_settings ): void { $captcha_attributes = array( - 'captchaType' => $general_settings->get_string( General_Settings::TYPE ), - 'siteKey' => $general_settings->get_string( General_Settings::SITE_KEY ), - 'theme' => $general_settings->get_string( General_Settings::THEME ), + 'captchaType' => string( $general_settings, General_Settings::TYPE ), + 'siteKey' => string( $general_settings, General_Settings::SITE_KEY ), + 'theme' => string( $general_settings, General_Settings::THEME ), ); $captcha_attributes = apply_filters( 'prosopo/procaptcha/captcha_attributes', $captcha_attributes ); diff --git a/prosopo-procaptcha/src/Captcha/Captcha_Assets_Manager.php b/prosopo-procaptcha/src/Captcha/Captcha_Assets_Manager.php index 082c412..3808b79 100644 --- a/prosopo-procaptcha/src/Captcha/Captcha_Assets_Manager.php +++ b/prosopo-procaptcha/src/Captcha/Captcha_Assets_Manager.php @@ -53,7 +53,7 @@ public function __construct( public function set_hooks( bool $is_admin_area ): void { add_filter( 'script_loader_tag', array( $this, 'add_module_attrs_for_target' ), 10, 2 ); - $hook = true === $is_admin_area ? + $hook = $is_admin_area ? 'admin_print_footer_scripts' : 'wp_print_footer_scripts'; @@ -74,7 +74,7 @@ public function add_widget(): void { } public function enqueue_assets_when_in_use(): void { - if ( false === $this->is_in_use ) { + if ( ! $this->is_in_use ) { return; } @@ -102,7 +102,7 @@ public function enqueue_assets_when_in_use(): void { // We have to manually add the module attribute for our scripts, // as wp_enqueue_script_module() doesn't work on the login screens. public function add_module_attrs_for_target( string $tag, string $handle ): string { - if ( false === $this->is_target_script( $handle ) ) { + if ( ! $this->is_target_script( $handle ) ) { return $tag; } @@ -110,7 +110,7 @@ public function add_module_attrs_for_target( string $tag, string $handle ): stri } protected function is_target_script( string $handle ): bool { - return true === in_array( $handle, array( $this->service_script_handle, self::WIDGET_JS_HANDLE ), true ) || + return in_array( $handle, array( $this->service_script_handle, self::WIDGET_JS_HANDLE ), true ) || 0 === strpos( $handle, self::INTEGRATION_JS_HANDLE_PREFIX ); } } diff --git a/prosopo-procaptcha/src/Captcha/Procaptcha.php b/prosopo-procaptcha/src/Captcha/Procaptcha.php index ac64406..f25c0af 100644 --- a/prosopo-procaptcha/src/Captcha/Procaptcha.php +++ b/prosopo-procaptcha/src/Captcha/Procaptcha.php @@ -1,6 +1,6 @@ settings_storage = $settings_storage; $this->captcha_assets_manager = $captcha_assets_manager; @@ -77,7 +81,7 @@ public function get_field_label(): string { /** * @param string|null $token Allows to define the token value for JS-based custom forms (like NinjaForms). */ - public function is_human_made_request( ?string $token = null ): bool { + public function human_made_request( ?string $token = null ): bool { $token = null === $token ? $this->query_arguments->get_string_for_non_action( self::FORM_FIELD_NAME, Query_Arguments::POST ) : $token; @@ -87,14 +91,16 @@ public function is_human_made_request( ?string $token = null ): bool { return false; } - if ( defined( self::ALLOW_BYPASS_CONSTANT_NAME ) && - true === constant( self::ALLOW_BYPASS_CONSTANT_NAME ) && + $allow_bypass = defined( self::ALLOW_BYPASS_CONSTANT_NAME ) && + true === constant( self::ALLOW_BYPASS_CONSTANT_NAME ); + + if ( $allow_bypass && 'bypass' === $token ) { return true; } $general_settings = $this->settings_storage->get( General_Settings::class )->get_settings(); - $secret_key = $general_settings->get_string( General_Settings::SECRET_KEY ); + $secret_key = string( $general_settings, General_Settings::SECRET_KEY ); $response = wp_remote_post( self::API_URL, @@ -114,7 +120,7 @@ public function is_human_made_request( ?string $token = null ): bool { ) ); - if ( true === is_wp_error( $response ) || + if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { // something went wrong, maybe connection issue, but we still shouldn't allow the request. // todo log. @@ -125,13 +131,11 @@ public function is_human_made_request( ?string $token = null ): bool { $body = json_decode( $body, true ); - $body = true === is_array( $body ) ? + $body = is_array( $body ) ? $body : array(); - $body = make_collection( $body ); - - return true === $body->get_bool( 'verified' ); + return bool( $body, 'verified' ); } public function add_validation_error( WP_Error $error = null ): WP_Error { @@ -149,23 +153,23 @@ public function add_validation_error( WP_Error $error = null ): WP_Error { } // Note: this function is available only after the 'set_current_user' hook. - public function is_present(): bool { - $is_user_authorized = wp_get_current_user()->exists(); + public function present(): bool { + $user_authorized = wp_get_current_user()->exists(); - $general_settings = $this->settings_storage->get( General_Settings::class )->get_settings(); - $is_enabled_for_authorized = true === $general_settings->get_bool( General_Settings::IS_ENABLED_FOR_AUTHORIZED ); + $general_settings = $this->settings_storage->get( General_Settings::class )->get_settings(); + $enabled_for_authorized = bool( $general_settings, General_Settings::IS_ENABLED_FOR_AUTHORIZED ); - $is_present = false === $is_user_authorized || - true === $is_enabled_for_authorized; + $present = ! $user_authorized || + $enabled_for_authorized; - return apply_filters( 'prosopo/procaptcha/is_captcha_present', $is_present ); + return apply_filters( 'prosopo/procaptcha/is_captcha_present', $present ); } public function is_available(): bool { $general_settings = $this->settings_storage->get( General_Settings::class )->get_settings(); - return '' !== $general_settings->get_string( General_Settings::SECRET_KEY ) && - '' !== $general_settings->get_string( General_Settings::SITE_KEY ); + return '' !== string( $general_settings, General_Settings::SECRET_KEY ) && + '' !== string( $general_settings, General_Settings::SITE_KEY ); } public function add_integration_js( string $integration_name ): void { @@ -177,30 +181,35 @@ public function add_integration_css( string $css_code ): void { } public function print_form_field( array $settings = array() ): string { - $settings = make_collection( $settings ); + $desired_on_guests = bool( $settings, Widget_Arguments::IS_DESIRED_ON_GUESTS ); - $is_field_stub = true === $settings->get_bool( Widget_Arguments::IS_DESIRED_ON_GUESTS ) && - false === $this->is_present(); + $is_field_stub = $desired_on_guests && + ! $this->present(); - if ( false === $is_field_stub ) { + if ( ! $is_field_stub ) { // automatically mark as in use. $this->captcha_assets_manager->add_widget(); } - $form_field = $this->renderer->render_view( + $form_field = $this->renderer->renderModel( Widget::class, function ( Widget $widget ) use ( $is_field_stub, $settings ) { - $widget->attributes = $settings->get_sub_collection( Widget_Arguments::ELEMENT_ATTRIBUTES ); - $widget->hidden_input_attrs = $settings->get_sub_collection( Widget_Arguments::HIDDEN_INPUT_ATTRIBUTES ); + $attributes = arr( $settings, Widget_Arguments::ELEMENT_ATTRIBUTES ); + $hidden_input_attrs = arr( $settings, Widget_Arguments::HIDDEN_INPUT_ATTRIBUTES ); + + $widget->attributes = html_attrs_collection( $attributes ); + $widget->hidden_input_attrs = html_attrs_collection( $hidden_input_attrs ); $widget->is_stub = $is_field_stub; - $widget->no_client_validation = $settings->get_bool( Widget_Arguments::IS_WITHOUT_CLIENT_VALIDATION ); - $widget->is_error_visible = $settings->get_bool( Widget_Arguments::IS_ERROR_ACTIVE ); + $widget->no_client_validation = bool( $settings, Widget_Arguments::IS_WITHOUT_CLIENT_VALIDATION ); + $widget->is_error_visible = bool( $settings, Widget_Arguments::IS_ERROR_ACTIVE ); $widget->error_message = $this->get_validation_error_message(); } ); - if ( false === $settings->get_bool( Widget_Arguments::IS_RETURN_ONLY ) ) { - // @phpcs:ignore WordPress.Security.EscapeOutput + $return_only = bool( $settings, Widget_Arguments::IS_RETURN_ONLY ); + + if ( ! $return_only ) { + // @phpcs:ignore WordPress.Security.EscapeOutput echo $form_field; $form_field = ''; } diff --git a/prosopo-procaptcha/src/Collection.php b/prosopo-procaptcha/src/Collection.php deleted file mode 100644 index cee442e..0000000 --- a/prosopo-procaptcha/src/Collection.php +++ /dev/null @@ -1,195 +0,0 @@ - - */ - protected array $items; - - /** - * @param array $data - */ - public function __construct( array $data ) { - $this->items = $data; - } - - // Cast to types. - - /** - * @return array - */ - public function get_array( string $item_name ): array { - return true === $this->exists( $item_name ) && - true === is_array( $this->items[ $item_name ] ) ? - $this->items[ $item_name ] : - array(); - } - - public function get_int( string $item_name ): int { - return true === $this->exists( $item_name ) && - true === is_numeric( $this->items[ $item_name ] ) ? - (int) $this->items[ $item_name ] : - 0; - } - - public function get_bool( string $item_name ): bool { - return true === $this->exists( $item_name ) && - // [1] and '1' are allowed values for [true] if we talk about boolean, - // e.g. ACF uses [1] it for the 'multiple' attribute of the select field. - true === in_array( $this->items[ $item_name ], array( true, 1, '1', 'on' ), true ); - } - - public function get_string( string $item_name ): string { - return true === $this->exists( $item_name ) && - ( true === is_string( $this->items[ $item_name ] ) || true === is_numeric( $this->items[ $item_name ] ) ) ? - (string) $this->items[ $item_name ] : - ''; - } - - // Items. - - public function exists( string $item_name ): bool { - return true === key_exists( $item_name, $this->items ); - } - - /** - * @return array - */ - public function keys(): array { - return array_keys( $this->items ); - } - - /** - * @param mixed $item_value - */ - public function add( string $item_name, $item_value ): self { - $this->items[ $item_name ] = $item_value; - - return $this; - } - - public function remove( string $item_name ): self { - if ( true === $this->exists( $item_name ) ) { - unset( $this->items[ $item_name ] ); - } - - return $this; - } - - /** - * @param self|array $origin - */ - public function merge( $origin, bool $use_as_defaults = false ): self { - $origin_array = false === is_array( $origin ) ? - $origin->items : - $origin; - - $this->items = false === $use_as_defaults ? - array_merge( $this->items, $origin_array ) : - array_merge( $origin_array, $this->items ); - - return $this; - } - - /** - * @param self|array $origin - */ - public function merge_html_attrs( $origin, bool $use_as_defaults = false ): self { - $origin_collection = false === is_array( $origin ) ? - $origin : - new self( $origin ); - - foreach ( $origin_collection->keys() as $origin_key ) { - if ( false === is_string( $origin_key ) ) { - continue; - } - - $is_present = $this->exists( $origin_key ); - $origin_value = $origin_collection->get_string( $origin_key ); - - if ( 'class' === $origin_key && - true === $is_present ) { - $current_classes = explode( ' ', $this->get_string( $origin_key ) ); - $new_classes = explode( ' ', $origin_value ); - - $origin_value = array_unique( array_merge( $current_classes, $new_classes ) ); - $origin_value = join( ' ', $origin_value ); - - $is_present = false; - } - - if ( 'style' === $origin_key && - true === $is_present ) { - $current_styles = explode( ';', $this->get_string( $origin_key ) ); - $new_styles = explode( ';', $origin_value ); - - $origin_value = array_unique( array_merge( $current_styles, $new_styles ) ); - $origin_value = join( ';', $origin_value ); - - $is_present = false; - } - - if ( true === $is_present && - true === $use_as_defaults ) { - continue; - } - - $this->add( $origin_key, $origin_value ); - } - - return $this; - } - - public function empty(): bool { - return array() === $this->items; - } - - // General. - - public function get_sub_collection( string $item_name ): self { - // Make an object, so future changes to it will be reflected in the current object as well. - if ( false === $this->exists( $item_name ) || - false === ( $this->items[ $item_name ] instanceof self ) ) { - $items = $this->get_array( $item_name ); - $this->items[ $item_name ] = new self( $items ); - } - - return $this->items[ $item_name ]; - } - - /** - * @return array - */ - public function to_array(): array { - $items = $this->items; - - foreach ( $items as $item_name => $item_value ) { - if ( true === ( $item_value instanceof self ) ) { - $items[ $item_name ] = $item_value->to_array(); - } - } - - return $items; - } - - public function __toString(): string { - $attributes = array(); - - foreach ( $this->items as $item_key => $item_value ) { - $item_key = (string) $item_key; - $item_value = $this->get_string( $item_key ); - - $attributes[] = sprintf( '%s="%s"', esc_html( $item_key ), esc_html( $item_value ) ); - } - - $attributes = join( ' ', $attributes ); - - return $attributes; - } -} diff --git a/prosopo-procaptcha/src/Html_Attributes_Collection.php b/prosopo-procaptcha/src/Html_Attributes_Collection.php new file mode 100644 index 0000000..2e01f4f --- /dev/null +++ b/prosopo-procaptcha/src/Html_Attributes_Collection.php @@ -0,0 +1,122 @@ + + */ + protected array $items; + + /** + * @param array $data + */ + public function __construct( array $data ) { + $this->items = $data; + } + + /** + * @param self|array $origin + */ + public function merge( $origin, bool $use_as_defaults = false ): self { + $origin_collection = is_array( $origin ) ? + new self( $origin ) : + $origin; + + foreach ( $origin_collection->keys() as $origin_key ) { + if ( ! is_string( $origin_key ) ) { + continue; + } + + $present = key_exists( $origin_key, $this->items ); + $origin_value = string( $origin_collection->get_items(), $origin_key ); + + if ( 'class' === $origin_key && + $present ) { + $current_classes = explode( ' ', string( $this->items, $origin_key ) ); + $new_classes = explode( ' ', $origin_value ); + + $origin_value = array_unique( array_merge( $current_classes, $new_classes ) ); + $origin_value = join( ' ', $origin_value ); + + $present = false; + } + + if ( 'style' === $origin_key && + $present ) { + $current_styles = explode( ';', string( $this->items, $origin_key ) ); + $new_styles = explode( ';', $origin_value ); + + $origin_value = array_unique( array_merge( $current_styles, $new_styles ) ); + $origin_value = join( ';', $origin_value ); + + $present = false; + } + + if ( $present && + $use_as_defaults ) { + continue; + } + + $this->add( $origin_key, $origin_value ); + } + + return $this; + } + + public function empty(): bool { + return 0 === count( $this->items ); + } + + /** + * @return array + */ + public function get_items(): array { + return $this->items; + } + + /** + * @return array + */ + protected function keys(): array { + return array_keys( $this->items ); + } + + /** + * @param mixed $item_value + */ + protected function add( string $item_name, $item_value ): self { + $this->items[ $item_name ] = $item_value; + + return $this; + } + + protected function remove( string $item_name ): self { + if ( key_exists( $item_name, $this->items ) ) { + unset( $this->items[ $item_name ] ); + } + + return $this; + } + + public function __toString(): string { + $attributes = array(); + + foreach ( $this->items as $item_key => $item_value ) { + $item_key = (string) $item_key; + $item_value = string( $this->items, $item_key ); + + $attributes[] = sprintf( '%s="%s"', esc_html( $item_key ), esc_html( $item_value ) ); + } + + $attributes = join( ' ', $attributes ); + + return $attributes; + } +} diff --git a/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrations.php b/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrations.php index 44d035f..2b01e90 100644 --- a/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrations.php +++ b/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrations.php @@ -59,13 +59,13 @@ public function initialize_integrations( array $plugin_integrations ): void { $std_plugin_integrations = array_filter( $plugin_integrations, function ( $plugin_integration ) { - return false === $plugin_integration->requires_late_hooking(); + return ! $plugin_integration->requires_late_hooking(); } ); $late_plugin_integrations = array_filter( $plugin_integrations, function ( $plugin_integration ) { - return true === $plugin_integration->requires_late_hooking(); + return $plugin_integration->requires_late_hooking(); } ); @@ -101,7 +101,7 @@ function ( Plugin_Integration_Interface $plugin_integration ) { */ protected function initialize_integrations_with_priority( array $plugin_integrations, int $hook_priority ): void { $item_init = function ( Plugin_Integration_Interface $plugin_integration ) { - if ( false === $this->plugin_integrator->is_integration_active( $plugin_integration ) ) { + if ( ! $this->plugin_integrator->integration_active( $plugin_integration ) ) { return; } @@ -128,7 +128,7 @@ protected function initialize_integration( Plugin_Integration_Interface $plugin_ $hookable_form_integrations = $this->plugin_integrator->create_hookable_form_integrations( $form_integrations ); $this->plugin_integrator->set_hooks_for_hookable_form_instances( $hookable_form_integrations, $this->is_admin_area ); - if ( true === ( $plugin_integration instanceof Hooks_Interface ) ) { + if ( $plugin_integration instanceof Hooks_Interface ) { $plugin_integration->set_hooks( $this->is_admin_area ); } diff --git a/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrator.php b/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrator.php index fa7f784..071ed9c 100644 --- a/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrator.php +++ b/prosopo-procaptcha/src/Integration/Plugin/Plugin_Integrator.php @@ -12,12 +12,12 @@ use Io\Prosopo\Procaptcha\Interfaces\Integration\Plugin\Plugin_Integration_Interface; class Plugin_Integrator { - public function is_integration_active( Plugin_Integration_Interface $plugin_integration ): bool { + public function integration_active( Plugin_Integration_Interface $plugin_integration ): bool { $plugin_classes = $plugin_integration->get_target_plugin_classes(); // No target classes means core WP integration. return array() === $plugin_classes || - true === $this->is_one_of_classes_is_loaded( $plugin_classes ); + $this->is_one_of_classes_is_loaded( $plugin_classes ); } /** @@ -51,11 +51,11 @@ public function create_hookable_form_integrations( array $form_integrations ): a $form_integrations, function ( string $form_integration ) { $class_implements = class_implements( $form_integration ); - $class_implements = true === is_array( $class_implements ) ? + $class_implements = is_array( $class_implements ) ? $class_implements : array(); - return true === in_array( Hookable_Form_Integration_Interface::class, $class_implements, true ); + return in_array( Hookable_Form_Integration_Interface::class, $class_implements, true ); } ); @@ -86,7 +86,7 @@ function ( Hookable_Form_Integration_Interface $hookable_form_instance ) use ( $ */ protected function is_one_of_classes_is_loaded( array $classes ): bool { foreach ( $classes as $class ) { - if ( false === class_exists( $class, false ) ) { + if ( ! class_exists( $class, false ) ) { continue; } diff --git a/prosopo-procaptcha/src/Integrations/BBPress/BBPress_Forum.php b/prosopo-procaptcha/src/Integrations/BBPress/BBPress_Forum.php index ff2fb70..2313e06 100644 --- a/prosopo-procaptcha/src/Integrations/BBPress/BBPress_Forum.php +++ b/prosopo-procaptcha/src/Integrations/BBPress/BBPress_Forum.php @@ -33,8 +33,7 @@ public function update_option( int $post_id ): void { public function print_metabox(): void { $forum_id = (int) get_the_ID(); - $value = $this->is_enabled( $forum_id ); - $enabled_checked_attr = true === $value ? + $enabled_checked_attr = $this->is_enabled( $forum_id ) ? ' checked' : ''; @@ -64,7 +63,7 @@ public function add_settings_metabox(): void { public function maybe_print_captcha(): void { $forum_id = $this->get_current_forum_id(); - if ( false === $this->is_enabled( $forum_id ) ) { + if ( ! $this->is_enabled( $forum_id ) ) { return; } @@ -82,13 +81,13 @@ public function maybe_validate_captcha(): void { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $this->is_enabled( $forum_id ) || - false === $captcha->is_present() || - true === $captcha->is_human_made_request() ) { + if ( ! $this->is_enabled( $forum_id ) || + ! $captcha->present() || + $captcha->human_made_request() ) { return; } - if ( true === function_exists( 'bbp_add_error' ) ) { + if ( function_exists( 'bbp_add_error' ) ) { bbp_add_error( $captcha->get_field_name(), $captcha->get_validation_error_message() ); } } @@ -104,7 +103,7 @@ protected function is_enabled( int $forum_id ): bool { } protected function get_current_forum_id(): int { - return true === function_exists( 'bbp_get_forum_id' ) ? + return function_exists( 'bbp_get_forum_id' ) ? bbp_get_forum_id() : 0; } diff --git a/prosopo-procaptcha/src/Integrations/Contact_Form_7.php b/prosopo-procaptcha/src/Integrations/Contact_Form_7.php index b616cb3..48be97c 100644 --- a/prosopo-procaptcha/src/Integrations/Contact_Form_7.php +++ b/prosopo-procaptcha/src/Integrations/Contact_Form_7.php @@ -35,7 +35,7 @@ public function set_hooks( bool $is_admin_area ): void { } public function add_field(): void { - if ( false === function_exists( 'wpcf7_add_form_tag' ) ) { + if ( ! function_exists( 'wpcf7_add_form_tag' ) ) { return; } @@ -79,16 +79,16 @@ public function print_field(): string { public function validate( $result, $tag ) { $captcha = $this->get_captcha(); - if ( true === property_exists( $tag, 'name' ) && + if ( property_exists( $tag, 'name' ) && '' === $tag->name ) { $tag->name = $captcha->get_field_name(); } - if ( true === $captcha->is_human_made_request() ) { + if ( $captcha->human_made_request() ) { return $result; } - if ( true === method_exists( $result, 'invalidate' ) ) { + if ( method_exists( $result, 'invalidate' ) ) { $result->invalidate( $tag, $captcha->get_validation_error_message() ); } diff --git a/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Form_Field.php b/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Form_Field.php index 3bff41f..ed7299f 100644 --- a/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Form_Field.php +++ b/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Form_Field.php @@ -4,14 +4,14 @@ namespace Io\Prosopo\Procaptcha\Integrations\Elementor_Pro; +defined( 'ABSPATH' ) || exit; + use ElementorPro\Modules\Forms\Classes; use ElementorPro\Modules\Forms\Fields\Field_Base; use Io\Prosopo\Procaptcha\Captcha\Widget_Arguments; use Io\Prosopo\Procaptcha\Integration\Form\Form_Integration; use Io\Prosopo\Procaptcha\Interfaces\Integration\Form\Form_Integration_Interface; -use function Io\Prosopo\Procaptcha\make_collection; - -defined( 'ABSPATH' ) || exit; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class Elementor_Form_Field extends Field_Base implements Form_Integration_Interface { use Form_Integration; @@ -40,7 +40,7 @@ public function maybe_replace_field_stub( string $content ): string { $captcha = self::get_form_helper()->get_captcha(); // Remove the stub if the captcha is not present. - if ( false === $captcha->is_present() ) { + if ( ! $captcha->present() ) { return str_replace( $stub, '', $content ); } @@ -73,14 +73,11 @@ public function maybe_replace_field_stub( string $content ): string { * @param mixed $form */ public function render( $item, $item_index, $form ): void { - $item_data = true === is_array( $item ) ? - $item : - array(); - $item_info = make_collection( $item_data ); + $item_id = string( $item, '_id' ); // Without an element with the target id, the built-in Elementor validation will not add the error message after failed validation, // while we can't get this field id during the real widget rendering. - $hidden_input = sprintf( '', $item_info->get_string( '_id' ) ); + $hidden_input = sprintf( '', $item_id ); // @phpcs:ignore WordPress.Security.EscapeOutput echo $this->get_field_stub() . $hidden_input; @@ -94,18 +91,15 @@ public function validation( $field, Classes\Form_Record $record, Classes\Ajax_Ha $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request() ) { + if ( ! $captcha->present() || + $captcha->human_made_request() ) { return; } - $field_data = true === is_array( $field ) ? - $field : - array(); - $field_info = make_collection( $field_data ); + $field_id = string( $field, 'id' ); $ajax_handler->add_error( - $field_info->get_string( 'id' ), + $field_id, $captcha->get_validation_error_message() ); } diff --git a/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Login_Widget.php b/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Login_Widget.php index b0b92f3..c45f4c1 100644 --- a/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Login_Widget.php +++ b/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Login_Widget.php @@ -42,8 +42,8 @@ public function register_widget_setting( Controls_Stack $element ): void { } public function inject_captcha_into_target_widget( string $content, Widget_Base $widget ): string { - if ( false === $this->is_target_widget( $widget ) || - false === $this->is_active_widget( $widget ) ) { + if ( ! $this->is_target_widget( $widget ) || + ! $this->is_active_widget( $widget ) ) { return $content; } diff --git a/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Pro.php b/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Pro.php index 228398e..7a3a674 100644 --- a/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Pro.php +++ b/prosopo-procaptcha/src/Integrations/Elementor_Pro/Elementor_Pro.php @@ -11,6 +11,7 @@ use Io\Prosopo\Procaptcha\Interfaces\Hooks_Interface; use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Storage_Interface; use Io\Prosopo\Procaptcha\Settings\Tabs\Account_Forms_Settings; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\bool; class Elementor_Pro extends Plugin_Integration implements Hooks_Interface { public function get_target_plugin_classes(): array { @@ -46,7 +47,7 @@ protected function get_conditional_integrations( Settings_Storage_Interface $set return array( // Login Widget submits to wp-login.php, so validation happens there, // therefore that option should be active. - Elementor_Login_Widget::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), + Elementor_Login_Widget::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), ); } } diff --git a/prosopo-procaptcha/src/Integrations/Everest_Forms/Everest_Forms_Field.php b/prosopo-procaptcha/src/Integrations/Everest_Forms/Everest_Forms_Field.php index 3c1f3fb..0e1d293 100644 --- a/prosopo-procaptcha/src/Integrations/Everest_Forms/Everest_Forms_Field.php +++ b/prosopo-procaptcha/src/Integrations/Everest_Forms/Everest_Forms_Field.php @@ -4,13 +4,13 @@ namespace Io\Prosopo\Procaptcha\Integrations\Everest_Forms; +defined( 'ABSPATH' ) || exit; + use EVF_Form_Fields; use Io\Prosopo\Procaptcha\Captcha\Widget_Arguments; use Io\Prosopo\Procaptcha\Integration\Form\Form_Integration; use Io\Prosopo\Procaptcha\Interfaces\Integration\Form\Form_Integration_Interface; -use function Io\Prosopo\Procaptcha\make_collection; - -defined( 'ABSPATH' ) || exit; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class Everest_Forms_Field extends EVF_Form_Fields implements Form_Integration_Interface { use Form_Integration; @@ -56,10 +56,8 @@ public function field_preview( $field ) { public function field_display( $field, $field_atts, $form_data ) { $captcha = self::get_form_helper()->get_captcha(); - $field_id = make_collection( $field ) - ->get_string( 'id' ); - $form_id = make_collection( $form_data ) - ->get_string( 'id' ); + $field_id = string( $field, 'id' ); + $form_id = string( $form_data, 'id' ); $captcha->print_form_field( array( @@ -83,27 +81,26 @@ public function field_display( $field, $field_atts, $form_data ) { */ // @phpstan-ignore-next-line public function validate( $field_id, $field_submit, $form_data ) { - $field_submit = true === is_string( $field_submit ) ? + $field_submit = is_string( $field_submit ) ? $field_submit : ''; $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request( $field_submit ) ) { + if ( ! $captcha->present() || + $captcha->human_made_request( $field_submit ) ) { return; } - $form_id = make_collection( $form_data ) - ->get_string( 'id' ); + $form_id = string( $form_data, 'id' ); /** * @var \EVF_Form_Task $task */ $task = evf()->task; // @phpstan-ignore-line - if ( false === key_exists( $form_id, $task->errors ) || - false === is_array( $task->errors[ $form_id ] ) ) { + if ( ! key_exists( $form_id, $task->errors ) || + ! is_array( $task->errors[ $form_id ] ) ) { $task->errors[ $form_id ] = array(); } diff --git a/prosopo-procaptcha/src/Integrations/Fluent_Forms/Fluent_Forms_Field.php b/prosopo-procaptcha/src/Integrations/Fluent_Forms/Fluent_Forms_Field.php index 1a41f6e..31d95e9 100644 --- a/prosopo-procaptcha/src/Integrations/Fluent_Forms/Fluent_Forms_Field.php +++ b/prosopo-procaptcha/src/Integrations/Fluent_Forms/Fluent_Forms_Field.php @@ -4,13 +4,13 @@ namespace Io\Prosopo\Procaptcha\Integrations\Fluent_Forms; +defined( 'ABSPATH' ) || exit; + use FluentForm\App\Services\FormBuilder\BaseFieldManager; use Io\Prosopo\Procaptcha\Captcha\Widget_Arguments; use Io\Prosopo\Procaptcha\Integration\Form\Form_Integration; use Io\Prosopo\Procaptcha\Interfaces\Integration\Form\Form_Integration_Interface; -use function Io\Prosopo\Procaptcha\make_collection; - -defined( 'ABSPATH' ) || exit; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class Fluent_Forms_Field extends BaseFieldManager implements Form_Integration_Interface { use Form_Integration; @@ -101,13 +101,12 @@ public function render( $element, $form ) { * @return string|string[] */ public function validate( $error_message, array $field, $form_data, $fields, $form ) { - $token = make_collection( $form_data ) - ->get_string( $this->key ); + $token = string( $form_data, $this->key ); $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request( $token ) ) { + if ( ! $captcha->present() || + $captcha->human_made_request( $token ) ) { return $error_message; } diff --git a/prosopo-procaptcha/src/Integrations/Formidable_Forms/Formidable_Form_Field.php b/prosopo-procaptcha/src/Integrations/Formidable_Forms/Formidable_Form_Field.php index d5e496b..f3caa74 100644 --- a/prosopo-procaptcha/src/Integrations/Formidable_Forms/Formidable_Form_Field.php +++ b/prosopo-procaptcha/src/Integrations/Formidable_Forms/Formidable_Form_Field.php @@ -10,7 +10,8 @@ use Io\Prosopo\Procaptcha\Captcha\Widget_Arguments; use Io\Prosopo\Procaptcha\Integration\Form\Form_Integration; use Io\Prosopo\Procaptcha\Interfaces\Integration\Form\Form_Integration_Interface; -use function Io\Prosopo\Procaptcha\make_collection; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\arr; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class Formidable_Form_Field extends FrmFieldType implements Form_Integration_Interface { use Form_Integration; @@ -67,13 +68,12 @@ public function displayed_field_type( $field ) { public function front_field_input( $args, $shortcode_atts ) { $captcha = self::get_form_helper()->get_captcha(); - $arguments = make_collection( $args ); + $field_id = string( $args, 'field_id' ); - $field_id = $arguments->get_string( 'field_id' ); $field_key = $this->get_field_key( $field_id ); - $form_errors = $arguments->get_array( 'errors' ); - $is_error = true === key_exists( $field_key, $form_errors ); + $form_errors = arr( $args, 'errors' ); + $is_error = key_exists( $field_key, $form_errors ); return $captcha->print_form_field( array( @@ -94,18 +94,17 @@ public function front_field_input( $args, $shortcode_atts ) { */ // @phpstan-ignore-next-line public function validate( $args ) { - $errors = array(); - $captcha = self::get_form_helper()->get_captcha(); - $arguments = make_collection( $args ); + $errors = array(); + $captcha = self::get_form_helper()->get_captcha(); - $token = $arguments->get_string( 'value' ); + $token = string( $args, 'value' ); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request( $token ) ) { + if ( ! $captcha->present() || + $captcha->human_made_request( $token ) ) { return $errors; } - $field_id = $arguments->get_string( 'id' ); + $field_id = string( $args, 'id' ); $field_key = $this->get_field_key( $field_id ); $error_message = $captcha->get_validation_error_message(); diff --git a/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Form_Field.php b/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Form_Field.php index 60b030c..095b879 100644 --- a/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Form_Field.php +++ b/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Form_Field.php @@ -1,6 +1,6 @@ $data @@ -25,7 +27,7 @@ public function __construct( $data = array() ) { parent::__construct( $data ); $this->type = self::get_form_helper()->get_captcha()->get_field_name(); - $this->isRequired = true; // @phpcs:ignore + $this->isRequired = true; // @phpcs:ignore } /** @@ -53,13 +55,13 @@ public function get_form_editor_field_settings() { /** * Retrieve the field label. * - * @since unknown - * @since 2.5 Move conditions about the singleproduct and calculation fields to their own class. - * - * @param bool $force_frontend_label Should the frontend label be displayed in the admin even if an admin label is configured. - * @param string $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission. + * @param bool $force_frontend_label Should the frontend label be displayed in the admin even if an admin label is configured. + * @param string $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission. * * @return string + * @since 2.5 Move conditions about the singleproduct and calculation fields to their own class. + * + * @since unknown */ public function get_field_label( $force_frontend_label, $value ) { return self::get_form_helper()->get_captcha()->get_field_label(); @@ -70,9 +72,8 @@ public function get_field_label( $force_frontend_label, $value ) { * * This could be an icon url or a gform-icon class. * - * @since 2.5 - * * @return string + * @since 2.5 */ public function get_form_editor_field_icon() { return 'gform-icon--recaptcha'; @@ -100,38 +101,32 @@ public function get_form_editor_button() { * * The {FIELD} placeholder will be replaced in GFFormDisplay::get_field_content with the markup returned by GF_Field::get_field_input(). * - * @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission. + * @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission. * @param bool $force_frontend_label Should the frontend label be displayed in the admin even if an admin label is configured. - * @param array $form The Form Object currently being processed. + * @param array $form The Form Object currently being processed. * * @return string */ // @phpstan-ignore-next-line public function get_field_content( $value, $force_frontend_label, $form ) { - if ( true === $this->is_form_editor() ) { + if ( $this->is_form_editor() ) { return parent::get_field_content( $value, $force_frontend_label, $form ); } - $form_data = make_collection( $form ); - $form_id = $form_data->get_int( 'id' ); + $form_id = int( $form, 'id' ); $validation_message_id = 'validation_message_' . $form_id . '_' . $this->id; $validation_message = true === $this->failed_validation && - true === is_string( $this->validation_message ) && - '' !== $this->validation_message ? + is_string( $this->validation_message ) && + '' !== $this->validation_message ? sprintf( "
%s
", esc_attr( $validation_message_id ), esc_html( $this->validation_message ) ) : - ''; + ''; - // Cast to string. - $field_id = make_collection( - array( - 'id' => $this->id, - ) - )->get_string( 'id' ); + $field_id = string( $this->id ); return self::get_form_helper()->get_captcha()->print_form_field( array( @@ -151,23 +146,22 @@ public function get_field_content( $value, $force_frontend_label, $form ) { * Return the result (bool) by setting $this->failed_validation. * Return the validation message (string) by setting $this->validation_message. * - * @since 1.9 - * * @param string|array $value The field value from get_value_submission(). - * @param array $form The Form Object currently being processed. + * @param array $form The Form Object currently being processed. * * @return void + * @since 1.9 */ // @phpstan-ignore-next-line public function validate( $value, $form ) { $captcha = self::get_form_helper()->get_captcha(); - $token = true === is_string( $value ) ? + $token = is_string( $value ) ? $value : ''; - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request( $token ) ) { + if ( ! $captcha->present() || + $captcha->human_made_request( $token ) ) { return; } diff --git a/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Forms.php b/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Forms.php index 2d49af5..9010d86 100644 --- a/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Forms.php +++ b/prosopo-procaptcha/src/Integrations/Gravity_Forms/Gravity_Forms.php @@ -25,8 +25,8 @@ public function get_form_integrations( Settings_Storage_Interface $settings_stor } public function set_hooks( bool $is_admin_area ): void { - if ( true === class_exists( 'GF_Fields' ) && - true === is_callable( array( 'GF_Fields', 'register' ) ) ) { + if ( class_exists( 'GF_Fields' ) && + is_callable( array( 'GF_Fields', 'register' ) ) ) { // While we create the object ourselves, don't pass objects directly, as GravityForms will save its class, // and then create instances itself on the fly. GF_Fields::register( new Gravity_Form_Field() ); diff --git a/prosopo-procaptcha/src/Integrations/JetPack/JetPack_Form_Field.php b/prosopo-procaptcha/src/Integrations/JetPack/JetPack_Form_Field.php index 0dbff6d..a4d5654 100644 --- a/prosopo-procaptcha/src/Integrations/JetPack/JetPack_Form_Field.php +++ b/prosopo-procaptcha/src/Integrations/JetPack/JetPack_Form_Field.php @@ -4,11 +4,11 @@ namespace Io\Prosopo\Procaptcha\Integrations\JetPack; +defined( 'ABSPATH' ) || exit; + use Automattic\Jetpack\Forms\ContactForm\Contact_Form; use Io\Prosopo\Procaptcha\Integration\Form\Hookable_Form_Integration; -use function Io\Prosopo\Procaptcha\make_collection; - -defined( 'ABSPATH' ) || exit; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class JetPack_Form_Field extends Hookable_Form_Integration { public function set_hooks( bool $is_admin_area ): void { @@ -19,10 +19,10 @@ public function maybe_validate( string $output, string $tag ): string { $captcha = self::get_form_helper()->get_captcha(); if ( $captcha->get_field_name() !== $tag || - false === $captcha->is_present() || + ! $captcha->present() || null === Contact_Form::$current_form || - false === $this->is_form_submitted( Contact_Form::$current_form ) || - true === $captcha->is_human_made_request() ) { + ! $this->is_form_submitted( Contact_Form::$current_form ) || + $captcha->human_made_request() ) { return $output; } @@ -32,9 +32,7 @@ public function maybe_validate( string $output, string $tag ): string { } protected function is_form_submitted( Contact_Form $form ): bool { - // @phpstan-ignore-next-line - $form_id = make_collection( $form->attributes ) - ->get_string( 'id' ); + $form_id = string( $form, 'attributes.id' ); $query_arguments = self::get_form_helper()->get_query_arguments(); diff --git a/prosopo-procaptcha/src/Integrations/Ninja_Forms/Ninja_Form_Field.php b/prosopo-procaptcha/src/Integrations/Ninja_Forms/Ninja_Form_Field.php index ca52e05..78795ee 100644 --- a/prosopo-procaptcha/src/Integrations/Ninja_Forms/Ninja_Form_Field.php +++ b/prosopo-procaptcha/src/Integrations/Ninja_Forms/Ninja_Form_Field.php @@ -10,7 +10,8 @@ use Io\Prosopo\Procaptcha\Integration\Form\Form_Integration; use Io\Prosopo\Procaptcha\Interfaces\Integration\Form\Form_Integration_Interface; use NF_Abstracts_Input; -use function Io\Prosopo\Procaptcha\make_collection; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\arr; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; // todo: find a way to make the field required by default. class Ninja_Form_Field extends NF_Abstracts_Input implements Form_Integration_Interface { @@ -55,16 +56,15 @@ public function render_field( array $field ): array { $element .= ''; $captcha->add_integration_js( 'ninja-forms' ); - $field_data = make_collection( $field ); - $field_data->get_sub_collection( 'settings' ) - ->merge( - array( - 'label_pos' => 'hidden', // Hide the label. - 'procaptcha' => $element, - ) - ); + $field['settings'] = array_merge( + arr( $field, 'settings' ), + array( + 'label_pos' => 'hidden', // Hide the label. + 'procaptcha' => $element, + ) + ); - return $field_data->to_array(); + return $field; } /** @@ -77,16 +77,15 @@ public function render_field( array $field ): array { public function validate( $field, $data ) { $captcha = self::get_form_helper()->get_captcha(); - if ( false === is_array( $field ) || - false === is_array( $data ) || - false === $captcha->is_present() ) { + if ( ! is_array( $field ) || + ! is_array( $data ) || + ! $captcha->present() ) { return array(); } - $token = make_collection( $field ) - ->get_string( 'value' ); + $token = string( $field, 'value' ); - if ( false === $captcha->is_human_made_request( $token ) ) { + if ( ! $captcha->human_made_request( $token ) ) { // For some reason it doesn't display error if array is returned... return $captcha->get_validation_error_message(); // @phpstan-ignore-line. } diff --git a/prosopo-procaptcha/src/Integrations/Spectra/Spectra_Form_Block_Field.php b/prosopo-procaptcha/src/Integrations/Spectra/Spectra_Form_Block_Field.php index aadd37a..2cdf447 100644 --- a/prosopo-procaptcha/src/Integrations/Spectra/Spectra_Form_Block_Field.php +++ b/prosopo-procaptcha/src/Integrations/Spectra/Spectra_Form_Block_Field.php @@ -33,7 +33,7 @@ public function inject_field_when_target_input_is_present( string $content ): st $captcha = self::get_form_helper()->get_captcha(); $input_name = $captcha->get_field_name(); - if ( false === $this->is_input_present( $input_name, $content ) ) { + if ( ! $this->is_input_present( $input_name, $content ) ) { return $content; } @@ -68,25 +68,25 @@ public function process_submission_when_block_has_target_input(): void { $post_id = $query_arguments->get_int_for_non_action( 'post_id', Query_Arguments::POST ); $block_id = $query_arguments->get_string_for_non_action( 'block_id', Query_Arguments::POST ); - if ( false === $captcha->is_present() || - false === $this->is_valid_post_id( $post_id ) || + if ( ! $captcha->present() || + ! $this->is_valid_post_id( $post_id ) || '' === $block_id ) { return; } $field_name = $captcha->get_field_name(); - if ( false === $this->form_block_has_hidden_field( $post_id, $block_id, $field_name ) ) { + if ( ! $this->form_block_has_hidden_field( $post_id, $block_id, $field_name ) ) { return; } $form_data = $query_arguments->get_string_for_non_action( 'form_data', Query_Arguments::POST ); $token_value = $this->get_value_from_json_string( $field_name, $form_data ); - $token = true === is_string( $token_value ) ? + $token = is_string( $token_value ) ? $token_value : ''; - if ( true === $captcha->is_human_made_request( $token ) ) { + if ( $captcha->human_made_request( $token ) ) { return; } @@ -99,8 +99,8 @@ public function process_submission_when_block_has_target_input(): void { */ protected function get_value_from_json_string( string $field_name, string $json_string ) { $form_data = json_decode( $json_string, true ); - return true === is_array( $form_data ) && - true === key_exists( $field_name, $form_data ) ? + return is_array( $form_data ) && + key_exists( $field_name, $form_data ) ? $form_data[ $field_name ] : ''; } @@ -128,8 +128,8 @@ protected function form_block_has_hidden_field( int $post_id, string $block_id, * @return array */ protected function find_inner_block( array $parent_block, string $block_name, string $attr_name, string $attr_value ): array { - $form_inner_blocks = true === key_exists( 'innerBlocks', $parent_block ) && - true === is_array( $parent_block['innerBlocks'] ) ? + $form_inner_blocks = key_exists( 'innerBlocks', $parent_block ) && + is_array( $parent_block['innerBlocks'] ) ? $parent_block['innerBlocks'] : array(); @@ -150,8 +150,8 @@ protected function find_block( string $block_name, string $attr_name, string $at $target_blocks = array_filter( $blocks, function ( $block ) use ( $block_name, $attr_name, $attr_value ) { - return true === isset( $block['blockName'], $block['attrs'] ) && - true === is_array( $block['attrs'] ) && + return isset( $block['blockName'], $block['attrs'] ) && + is_array( $block['attrs'] ) && $block_name === $block['blockName'] && $attr_value === $block['attrs'][ $attr_name ]; } @@ -159,7 +159,7 @@ function ( $block ) use ( $block_name, $attr_name, $attr_value ) { $target_block = array_pop( $target_blocks ); - return true === is_array( $target_block ) ? + return is_array( $target_block ) ? $target_block : array(); } diff --git a/prosopo-procaptcha/src/Integrations/User_Registration/UR_Form_Field_Prosopo_Procaptcha.php b/prosopo-procaptcha/src/Integrations/User_Registration/UR_Form_Field_Prosopo_Procaptcha.php index bdfee59..7857e51 100644 --- a/prosopo-procaptcha/src/Integrations/User_Registration/UR_Form_Field_Prosopo_Procaptcha.php +++ b/prosopo-procaptcha/src/Integrations/User_Registration/UR_Form_Field_Prosopo_Procaptcha.php @@ -9,7 +9,7 @@ use Io\Prosopo\Procaptcha\Captcha\Widget_Arguments; use Io\Prosopo\Procaptcha\Integration\Form\Form_Integration; use Io\Prosopo\Procaptcha\Interfaces\Integration\Form\Hookable_Form_Integration_Interface; -use function Io\Prosopo\Procaptcha\make_collection; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; // Class name must match the UR_Form_Field_{field_type} format. class UR_Form_Field_Prosopo_Procaptcha extends UR_Form_Field implements Hookable_Form_Integration_Interface { @@ -75,12 +75,10 @@ public function get_registered_admin_fields() { public function validation( $single_form_field, $form_data, $filter_hook, $form_id ) { $captcha = self::get_form_helper()->get_captcha(); - $form_data = get_object_vars( $form_data ); - $token = make_collection( $form_data ) - ->get_string( 'value' ); + $token = string( $form_data, 'value' ); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request( $token ) ) { + if ( ! $captcha->present() || + $captcha->human_made_request( $token ) ) { return; } diff --git a/prosopo-procaptcha/src/Integrations/User_Registration/User_Registration.php b/prosopo-procaptcha/src/Integrations/User_Registration/User_Registration.php index c684836..bd062c5 100644 --- a/prosopo-procaptcha/src/Integrations/User_Registration/User_Registration.php +++ b/prosopo-procaptcha/src/Integrations/User_Registration/User_Registration.php @@ -11,6 +11,7 @@ use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Storage_Interface; use Io\Prosopo\Procaptcha\Settings\Tabs\Account_Forms_Settings; use UR_Form_Field_Prosopo_Procaptcha; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\bool; class User_Registration extends Plugin_Integration implements Hooks_Interface { public function get_target_plugin_classes(): array { @@ -72,8 +73,8 @@ protected function get_conditional_integrations( Settings_Storage_Interface $set $account_forms = $settings_storage->get( Account_Forms_Settings::class )->get_settings(); return array( - UR_Login_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), - UR_Lost_Password_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_LOST_PASSWORD_FORM ), + UR_Login_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), + UR_Lost_Password_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_LOST_PASSWORD_FORM ), ); } } diff --git a/prosopo-procaptcha/src/Integrations/WPForms/WPForms_Field.php b/prosopo-procaptcha/src/Integrations/WPForms/WPForms_Field.php index 77597ee..d98ebdb 100644 --- a/prosopo-procaptcha/src/Integrations/WPForms/WPForms_Field.php +++ b/prosopo-procaptcha/src/Integrations/WPForms/WPForms_Field.php @@ -9,7 +9,7 @@ use Io\Prosopo\Procaptcha\Captcha\Widget_Arguments; use Io\Prosopo\Procaptcha\Integration\Form\Form_Integration; use Io\Prosopo\Procaptcha\Interfaces\Integration\Form\Form_Integration_Interface; -use function Io\Prosopo\Procaptcha\make_collection; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class WPForms_Field extends \WPForms_Field implements Form_Integration_Interface { use Form_Integration; @@ -60,14 +60,8 @@ public function field_preview( $field ) { */ // @phpstan-ignore-next-line public function field_display( $field, $field_atts, $form_data ) { - $input_data = make_collection( $field ) - ->get_sub_collection( 'properties' ) - ->get_sub_collection( 'inputs' ) - ->get_sub_collection( 'primary' ); - - $id = $input_data->get_string( 'id' ); - $name = $input_data->get_sub_collection( 'attr' ) - ->get_string( 'name' ); + $id = string( $field, 'properties.inputs.primary.id' ); + $name = string( $field, 'properties.inputs.primary.attr.name' ); self::get_form_helper()->get_captcha()->print_form_field( array( @@ -91,17 +85,17 @@ public function field_display( $field, $field_atts, $form_data ) { */ // @phpstan-ignore-next-line public function validate( $field_id, $field_submit, $form_data ) { - $token = true === is_string( $field_submit ) ? + $token = is_string( $field_submit ) ? $field_submit : ''; $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request( $token ) ) { + if ( ! $captcha->present() || + $captcha->human_made_request( $token ) ) { return; } - if ( false === function_exists( 'wpforms' ) ) { + if ( ! function_exists( 'wpforms' ) ) { return; } diff --git a/prosopo-procaptcha/src/Integrations/WooCommerce/WooCommerce.php b/prosopo-procaptcha/src/Integrations/WooCommerce/WooCommerce.php index 7636653..6dde881 100644 --- a/prosopo-procaptcha/src/Integrations/WooCommerce/WooCommerce.php +++ b/prosopo-procaptcha/src/Integrations/WooCommerce/WooCommerce.php @@ -10,6 +10,7 @@ use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Storage_Interface; use Io\Prosopo\Procaptcha\Settings\Tabs\Account_Forms_Settings; use Io\Prosopo\Procaptcha\Settings\Tabs\Woo_Commerce_Settings; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\bool; class WooCommerce extends Plugin_Integration { public function get_target_plugin_classes(): array { @@ -31,11 +32,11 @@ protected function get_conditional_integrations( Settings_Storage_Interface $set $woo_settings = $settings_storage->get( Woo_Commerce_Settings::class )->get_settings(); return array( - Woo_Checkout_Form::class => $woo_settings->get_bool( Woo_Commerce_Settings::IS_ON_CHECKOUT ), - Woo_Login_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), - Woo_Lost_Password_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_LOST_PASSWORD_FORM ), - Woo_Order_Tracking_Form::class => $woo_settings->get_bool( Woo_Commerce_Settings::IS_ON_ORDER_TRACKING ), - Woo_Register_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_REGISTER_FORM ), + Woo_Checkout_Form::class => bool( $woo_settings, Woo_Commerce_Settings::IS_ON_CHECKOUT ), + Woo_Login_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), + Woo_Lost_Password_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_LOST_PASSWORD_FORM ), + Woo_Order_Tracking_Form::class => bool( $woo_settings, Woo_Commerce_Settings::IS_ON_ORDER_TRACKING ), + Woo_Register_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_REGISTER_FORM ), ); } } diff --git a/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Checkout_Form.php b/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Checkout_Form.php index 20a368f..4e2aa95 100644 --- a/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Checkout_Form.php +++ b/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Checkout_Form.php @@ -15,7 +15,7 @@ class Woo_Checkout_Form extends Hookable_Form_Integration { public function print_classic_field(): void { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() ) { + if ( ! $captcha->present() ) { return; } @@ -32,8 +32,8 @@ public function print_classic_field(): void { public function verify( array $data, WP_Error $errors ): void { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request() ) { + if ( ! $captcha->present() || + $captcha->human_made_request() ) { return; } @@ -49,12 +49,12 @@ public function verify( array $data, WP_Error $errors ): void { public function verify_block_field( $value, array $field ) { $captcha = self::get_form_helper()->get_captcha(); - $token = true === is_string( $value ) ? + $token = is_string( $value ) ? $value : ''; // Without checking ->is_present() because this Woo Rest API doesn't pass the Auth cookie. - if ( true === $captcha->is_human_made_request( $token ) ) { + if ( $captcha->human_made_request( $token ) ) { return; } @@ -97,7 +97,7 @@ public function set_hooks( bool $is_admin_area ): void { // It's necessary to use priority, otherwise for some reason Woo prints this block multiple times. add_filter( 'render_block', array( $this, 'print_blocks_checkout_field' ), 999, 2 ); - if ( true === function_exists( 'woocommerce_register_additional_checkout_field' ) ) { + if ( function_exists( 'woocommerce_register_additional_checkout_field' ) ) { woocommerce_register_additional_checkout_field( array( 'id' => Plugin::SLUG . '/' . self::get_form_helper()->get_captcha()->get_field_name(), diff --git a/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Order_Tracking_Form.php b/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Order_Tracking_Form.php index 63f34cf..8f3108b 100644 --- a/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Order_Tracking_Form.php +++ b/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Order_Tracking_Form.php @@ -16,7 +16,7 @@ class Woo_Order_Tracking_Form extends Hookable_Form_Integration { public function print_field(): void { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() ) { + if ( ! $captcha->present() ) { return; } @@ -45,8 +45,8 @@ public function maybe_verify_submission( $output, string $tag ) { $captcha = self::get_form_helper()->get_captcha(); if ( '' === $order_id || - false === $captcha->is_present() || - true === $captcha->is_human_made_request() ) { + ! $captcha->present() || + $captcha->human_made_request() ) { return $output; } @@ -60,13 +60,13 @@ public function maybe_verify_submission( $output, string $tag ) { public function maybe_add_error( string $output, string $tag ): string { if ( 'woocommerce_order_tracking' !== $tag || - false === $this->is_invalid ) { + ! $this->is_invalid ) { return $output; } $prefix = ''; - if ( true === function_exists( 'wc_print_notice' ) ) { + if ( function_exists( 'wc_print_notice' ) ) { $validation_error_message = self::get_form_helper()->get_captcha()->get_validation_error_message(); $prefix = wc_print_notice( $validation_error_message, 'error', array(), true ); } diff --git a/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Register_Form.php b/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Register_Form.php index c4e6ccd..0c64e8b 100644 --- a/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Register_Form.php +++ b/prosopo-procaptcha/src/Integrations/WooCommerce/Woo_Register_Form.php @@ -24,7 +24,7 @@ public function print_field(): void { public function verify_submission( WP_Error $error ): WP_Error { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_human_made_request() ) { + if ( ! $captcha->human_made_request() ) { $captcha->add_validation_error( $error ); } diff --git a/prosopo-procaptcha/src/Integrations/WordPress/Comment_Form.php b/prosopo-procaptcha/src/Integrations/WordPress/Comment_Form.php index e11d7a5..75acdb6 100644 --- a/prosopo-procaptcha/src/Integrations/WordPress/Comment_Form.php +++ b/prosopo-procaptcha/src/Integrations/WordPress/Comment_Form.php @@ -34,9 +34,9 @@ public function include_captcha_field( string $submit_field, array $args ): stri public function verify_submission( $approved, array $comment_data ) { $captcha = self::get_form_helper()->get_captcha(); - if ( true === $captcha->is_present() && - false === $captcha->is_human_made_request() ) { - $error = true === ( $approved instanceof WP_Error ) ? + if ( $captcha->present() && + ! $captcha->human_made_request() ) { + $error = $approved instanceof WP_Error ? $approved : null; diff --git a/prosopo-procaptcha/src/Integrations/WordPress/Login_Form.php b/prosopo-procaptcha/src/Integrations/WordPress/Login_Form.php index df143e5..d770bdb 100644 --- a/prosopo-procaptcha/src/Integrations/WordPress/Login_Form.php +++ b/prosopo-procaptcha/src/Integrations/WordPress/Login_Form.php @@ -18,8 +18,8 @@ class Login_Form extends WordPress_Form { public function verify_submission( $user_or_error ) { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_human_made_request() ) { - $error_instance = true === ( $user_or_error instanceof WP_Error ) ? + if ( ! $captcha->human_made_request() ) { + $error_instance = $user_or_error instanceof WP_Error ? $user_or_error : null; diff --git a/prosopo-procaptcha/src/Integrations/WordPress/Lost_Password_Form.php b/prosopo-procaptcha/src/Integrations/WordPress/Lost_Password_Form.php index 3b9ec54..740b8c2 100644 --- a/prosopo-procaptcha/src/Integrations/WordPress/Lost_Password_Form.php +++ b/prosopo-procaptcha/src/Integrations/WordPress/Lost_Password_Form.php @@ -17,7 +17,7 @@ class Lost_Password_Form extends WordPress_Form { public function verify_submission( WP_Error $errors, $user_data ): void { $captcha = self::get_form_helper()->get_captcha(); - if ( true === $captcha->is_human_made_request() ) { + if ( $captcha->human_made_request() ) { return; } diff --git a/prosopo-procaptcha/src/Integrations/WordPress/Password_Protected_Form.php b/prosopo-procaptcha/src/Integrations/WordPress/Password_Protected_Form.php index 072d877..835b949 100644 --- a/prosopo-procaptcha/src/Integrations/WordPress/Password_Protected_Form.php +++ b/prosopo-procaptcha/src/Integrations/WordPress/Password_Protected_Form.php @@ -24,8 +24,8 @@ public function add_form_field( string $output, WP_Post $post ): string { public function verify_submission(): void { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_present() || - true === $captcha->is_human_made_request() ) { + if ( ! $captcha->present() || + $captcha->human_made_request() ) { return; } diff --git a/prosopo-procaptcha/src/Integrations/WordPress/Register_Form.php b/prosopo-procaptcha/src/Integrations/WordPress/Register_Form.php index 4f919d5..bf6e72b 100644 --- a/prosopo-procaptcha/src/Integrations/WordPress/Register_Form.php +++ b/prosopo-procaptcha/src/Integrations/WordPress/Register_Form.php @@ -12,7 +12,7 @@ class Register_Form extends WordPress_Form { public function verify_submission( WP_Error $errors ): WP_Error { $captcha = self::get_form_helper()->get_captcha(); - if ( false === $captcha->is_human_made_request() ) { + if ( ! $captcha->human_made_request() ) { $captcha->add_validation_error( $errors ); } diff --git a/prosopo-procaptcha/src/Integrations/WordPress/WordPress.php b/prosopo-procaptcha/src/Integrations/WordPress/WordPress.php index 6ba2aee..0364f5d 100644 --- a/prosopo-procaptcha/src/Integrations/WordPress/WordPress.php +++ b/prosopo-procaptcha/src/Integrations/WordPress/WordPress.php @@ -9,6 +9,7 @@ use Io\Prosopo\Procaptcha\Integration\Plugin\Plugin_Integration; use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Storage_Interface; use Io\Prosopo\Procaptcha\Settings\Tabs\Account_Forms_Settings; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\bool; class WordPress extends Plugin_Integration { public function get_form_integrations( Settings_Storage_Interface $settings_storage ): array { @@ -28,11 +29,11 @@ protected function get_conditional_integrations( Settings_Storage_Interface $set $account_forms = $settings_storage->get( Account_Forms_Settings::class )->get_settings(); return array( - Comment_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_COMMENT_FORM ), - Login_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), - Lost_Password_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_LOST_PASSWORD_FORM ), - Password_Protected_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_POST_FORM ), - Register_Form::class => $account_forms->get_bool( Account_Forms_Settings::IS_ON_WP_REGISTER_FORM ), + Comment_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_COMMENT_FORM ), + Login_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_LOGIN_FORM ), + Lost_Password_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_LOST_PASSWORD_FORM ), + Password_Protected_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_POST_FORM ), + Register_Form::class => bool( $account_forms, Account_Forms_Settings::IS_ON_WP_REGISTER_FORM ), ); } } diff --git a/prosopo-procaptcha/src/Interfaces/Captcha/Captcha_Interface.php b/prosopo-procaptcha/src/Interfaces/Captcha/Captcha_Interface.php index ca32fd3..224eb9b 100644 --- a/prosopo-procaptcha/src/Interfaces/Captcha/Captcha_Interface.php +++ b/prosopo-procaptcha/src/Interfaces/Captcha/Captcha_Interface.php @@ -18,14 +18,14 @@ public function add_integration_js( string $integration_name ): void; public function add_integration_css( string $css_code ): void; - public function is_human_made_request( ?string $token = null ): bool; + public function human_made_request( ?string $token = null ): bool; public function add_validation_error( WP_Error $error = null ): WP_Error; public function get_validation_error_message(): string; // By default, skips captcha for authorized users, also can be customized by the filter 'prosopo/procaptcha/is_captcha_present'. - public function is_present(): bool; + public function present(): bool; // true if both keys are set. public function is_available(): bool; diff --git a/prosopo-procaptcha/src/Interfaces/Settings/Settings_Tab_Interface.php b/prosopo-procaptcha/src/Interfaces/Settings/Settings_Tab_Interface.php index ecf2ddc..ec2000c 100644 --- a/prosopo-procaptcha/src/Interfaces/Settings/Settings_Tab_Interface.php +++ b/prosopo-procaptcha/src/Interfaces/Settings/Settings_Tab_Interface.php @@ -6,14 +6,16 @@ defined( 'ABSPATH' ) || exit; -use Io\Prosopo\Procaptcha\Collection; use Io\Prosopo\Procaptcha\Interfaces\Captcha\Captcha_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Factory_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Interface; use Io\Prosopo\Procaptcha\Query_Arguments; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\ModelFactoryInterface; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\TemplateModelInterface; interface Settings_Tab_Interface { - public function get_settings(): Collection; + /** + * @return array + */ + public function get_settings(): array; public function process_form( Query_Arguments $query_arguments ): void; @@ -21,7 +23,7 @@ public function get_tab_name(): string; public function get_tab_title(): string; - public function make_tab_component( View_Factory_Interface $creator, Captcha_Interface $captcha ): View_Interface; + public function make_tab_component( ModelFactoryInterface $factory, Captcha_Interface $captcha ): TemplateModelInterface; public function get_tab_js_file(): string; diff --git a/prosopo-procaptcha/src/Interfaces/View/Object_Property_Manager_Interface.php b/prosopo-procaptcha/src/Interfaces/View/Object_Property_Manager_Interface.php deleted file mode 100644 index 5f41fc8..0000000 --- a/prosopo-procaptcha/src/Interfaces/View/Object_Property_Manager_Interface.php +++ /dev/null @@ -1,14 +0,0 @@ - name => value (or callback) - */ - public function get_variables( object $instance ): array; -} diff --git a/prosopo-procaptcha/src/Interfaces/View/Template_Compiler_Interface.php b/prosopo-procaptcha/src/Interfaces/View/Template_Compiler_Interface.php deleted file mode 100644 index f182bfd..0000000 --- a/prosopo-procaptcha/src/Interfaces/View/Template_Compiler_Interface.php +++ /dev/null @@ -1,9 +0,0 @@ - $variables - */ - public function render_template( string $template, array $variables, bool $do_print = false ): string; -} diff --git a/prosopo-procaptcha/src/Interfaces/View/View_Factory_Interface.php b/prosopo-procaptcha/src/Interfaces/View/View_Factory_Interface.php deleted file mode 100644 index ae7bff4..0000000 --- a/prosopo-procaptcha/src/Interfaces/View/View_Factory_Interface.php +++ /dev/null @@ -1,17 +0,0 @@ - $view_class - * @param Closure(T):void|null $setup_callback - */ - public function make_view( string $view_class, ?Closure $setup_callback = null ): View_Interface; -} diff --git a/prosopo-procaptcha/src/Interfaces/View/View_Interface.php b/prosopo-procaptcha/src/Interfaces/View/View_Interface.php deleted file mode 100644 index 6963f9a..0000000 --- a/prosopo-procaptcha/src/Interfaces/View/View_Interface.php +++ /dev/null @@ -1,9 +0,0 @@ - $view_or_class - * @param Closure(T):void|null $setup_callback - */ - public function render_view( $view_or_class, Closure $setup_callback = null, bool $do_print = false ): string; -} diff --git a/prosopo-procaptcha/src/Plugin.php b/prosopo-procaptcha/src/Plugin.php index 89b2d28..7c24658 100644 --- a/prosopo-procaptcha/src/Plugin.php +++ b/prosopo-procaptcha/src/Plugin.php @@ -30,12 +30,9 @@ use Io\Prosopo\Procaptcha\Integration\Plugin\Plugin_Integrations; use Io\Prosopo\Procaptcha\Integration\Plugin\Plugin_Integrator; use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Tab_Interface; -use Io\Prosopo\Procaptcha\View\Blade_Compiler; -use Io\Prosopo\Procaptcha\View\View_Factory; -use Io\Prosopo\Procaptcha\View\View_Renderer; -use Io\Prosopo\Procaptcha\View\Template_Provider; -use Io\Prosopo\Procaptcha\View\Object_Property_Manager; -use Io\Prosopo\Procaptcha\View\Template_Renderer; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\View\ViewNamespaceConfig; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\View\ViewTemplateRenderer; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\ViewsManager; use Io\Prosopo\Procaptcha\Settings\{Settings_Page, Settings_Storage, Tabs\Account_Forms_Settings, @@ -63,18 +60,16 @@ public function __construct( string $plugin_file = '' ) { $this->plugin_file = $plugin_file; $wp_filesystem = $this->get_wp_filesystem(); - $template_provider = new Template_Provider( - __DIR__ . '/blade-templates', - 'Io\\Prosopo\\Procaptcha\\Views' - ); - $object_property_manager = new Object_Property_Manager(); - $view_factory = new View_Factory( $object_property_manager, $template_provider ); - $view_renderer = new View_Renderer( - new Template_Renderer( new Blade_Compiler() ), - $view_factory, - $object_property_manager - ); - $assets_manager = new Assets_Manager( $plugin_file, $this->version, $wp_filesystem ); + $view_template_renderer = new ViewTemplateRenderer(); + + $namespace_config = ( new ViewNamespaceConfig( $view_template_renderer ) ) + ->setTemplatesRootPath( __DIR__ . '/views' ) + ->setTemplateFileExtension( '.blade.php' ); + + $views_manager = new ViewsManager(); + $views_manager->registerNamespace( 'Io\\Prosopo\\Procaptcha\\Template_Models', $namespace_config ); + + $assets_manager = new Assets_Manager( $plugin_file, $this->version, $wp_filesystem ); $this->settings_storage = new Settings_Storage(); $this->captcha_assets_manager = new Captcha_Assets_Manager( @@ -91,15 +86,15 @@ public function __construct( string $plugin_file = '' ) { $this->settings_storage, $this->captcha_assets_manager, $this->query_arguments, - $view_renderer + $views_manager ); $this->settings_page = new Settings_Page( $this, $this->settings_storage, $this->captcha, $this->query_arguments, - $view_factory, - $view_renderer, + $views_manager, + $views_manager, $assets_manager ); diff --git a/prosopo-procaptcha/src/Query_Arguments.php b/prosopo-procaptcha/src/Query_Arguments.php index 1294b11..72b7f6c 100644 --- a/prosopo-procaptcha/src/Query_Arguments.php +++ b/prosopo-procaptcha/src/Query_Arguments.php @@ -4,6 +4,10 @@ namespace Io\Prosopo\Procaptcha; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\boolExtended; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\int; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; + defined( 'ABSPATH' ) || exit; class Query_Arguments { @@ -11,32 +15,22 @@ class Query_Arguments { const POST = 'post'; const SERVER = 'server'; - private ?Collection $post; - private ?Collection $get; - private ?Collection $server; - - public function __construct() { - $this->post = null; - $this->get = null; - $this->server = null; - } - public function get_string_for_non_action( string $arg_name, string $from = self::GET ): string { $source = $this->get_source( $from ); - return $this->sanitize_string( $source->get_string( $arg_name ) ); + return $this->sanitize_string( string( $source, $arg_name ) ); } public function get_int_for_non_action( string $arg_name, string $from = self::GET ): int { $source = $this->get_source( $from ); - return $source->get_int( $arg_name ); + return int( $source, $arg_name ); } public function get_bool_for_non_action( string $arg_name, string $from = self::GET ): bool { $source = $this->get_source( $from ); - return $source->get_bool( $arg_name ); + return boolExtended( $source, $arg_name ); } public function get_string_for_admin_action( @@ -47,7 +41,7 @@ public function get_string_for_admin_action( $source = $this->get_source( $from ); // separately check for presence, otherwise check_admin_referer will fail the request. - if ( false === $source->exists( $arg_name ) || + if ( ! key_exists( $arg_name, $source ) || false === check_admin_referer( $nonce_action_name ) ) { return ''; } @@ -63,7 +57,7 @@ public function get_bool_for_admin_action( $source = $this->get_source( $from ); // separately check for presence, otherwise check_admin_referer will fail the request. - if ( false === $source->exists( $arg_name ) || + if ( ! key_exists( $arg_name, $source ) || false === check_admin_referer( $nonce_action_name ) ) { return false; } @@ -71,31 +65,22 @@ public function get_bool_for_admin_action( return $this->get_bool_for_non_action( $arg_name, $from ); } - protected function get_source( string $from ): Collection { + /** + * @return array + */ + protected function get_source( string $from ): array { switch ( $from ) { case self::GET: - if ( null === $this->get ) { // phpcs:ignore WordPress.Security.NonceVerification - $this->get = make_collection( $_GET ); - } - - return $this->get; + return $_GET; case self::POST: - if ( null === $this->post ) { // phpcs:ignore WordPress.Security.NonceVerification - $this->post = make_collection( $_POST ); - } - - return $this->post; + return $_POST; case self::SERVER: - if ( null === $this->server ) { // phpcs:ignore WordPress.Security.NonceVerification - $this->server = make_collection( $_SERVER ); - } - - return $this->server; + return $_SERVER; default: - return make_collection( array() ); + return array(); } } diff --git a/prosopo-procaptcha/src/Settings/Settings_Page.php b/prosopo-procaptcha/src/Settings/Settings_Page.php index dcb7f53..df1cf9e 100644 --- a/prosopo-procaptcha/src/Settings/Settings_Page.php +++ b/prosopo-procaptcha/src/Settings/Settings_Page.php @@ -10,13 +10,12 @@ use Io\Prosopo\Procaptcha\Interfaces\Captcha\Captcha_Interface; use Io\Prosopo\Procaptcha\Interfaces\Hooks_Interface; use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Tab_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Factory_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Renderer_Interface; use Io\Prosopo\Procaptcha\Plugin; use Io\Prosopo\Procaptcha\Query_Arguments; -use Io\Prosopo\Procaptcha\Views\Settings\Settings; -use function Io\Prosopo\Procaptcha\make_collection; +use Io\Prosopo\Procaptcha\Template_Models\Settings\Settings; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\ModelFactoryInterface; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\ModelRendererInterface; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\TemplateModelInterface; class Settings_Page implements Hooks_Interface { const FORM_NONCE = 'prosopo-captcha__settings'; @@ -28,8 +27,8 @@ class Settings_Page implements Hooks_Interface { private Settings_Storage $settings_storage; private Captcha_Interface $captcha; private Query_Arguments $query_arguments; - private View_Factory_Interface $component_creator; - private View_Renderer_Interface $renderer; + private ModelFactoryInterface $component_creator; + private ModelRendererInterface $renderer; private Assets_Manager_Interface $assets_manager; /** * @var array @@ -41,8 +40,8 @@ public function __construct( Settings_Storage $settings_storage, Captcha_Interface $captcha, Query_Arguments $query_arguments, - View_Factory_Interface $component_creator, - View_Renderer_Interface $component_renderer, + ModelFactoryInterface $component_creator, + ModelRendererInterface $component_renderer, Assets_Manager_Interface $assets_manager ) { $this->plugin = $plugin; @@ -56,7 +55,7 @@ public function __construct( } public function set_hooks( bool $is_admin_area ): void { - if ( false === $is_admin_area ) { + if ( ! $is_admin_area ) { return; } @@ -75,7 +74,7 @@ public function get_active_tab( string $from = Query_Arguments::GET ): string { ); } - public function make_component(): ?View_Interface { + public function make_component(): ?TemplateModelInterface { $current_tab = $this->maybe_process_form(); $is_just_saved = '' !== $current_tab; @@ -90,24 +89,22 @@ public function make_component(): ?View_Interface { $current_tab = self::DEFAULT_TAB; } - if ( false === key_exists( $current_tab, $this->setting_tabs ) ) { + if ( ! key_exists( $current_tab, $this->setting_tabs ) ) { return null; } $tabs = array(); foreach ( $this->setting_tabs as $settings_tab ) { - $tabs[] = make_collection( - array( - 'is_active' => $settings_tab->get_tab_name() === $current_tab, - 'title' => $settings_tab->get_tab_title(), - 'url' => $this->get_tab_url( $settings_tab->get_tab_name() ), - ) + $tabs[] = array( + 'is_active' => $settings_tab->get_tab_name() === $current_tab, + 'title' => $settings_tab->get_tab_title(), + 'url' => $this->get_tab_url( $settings_tab->get_tab_name() ), ); } $tab = $this->setting_tabs[ $current_tab ]; - return $this->component_creator->make_view( + return $this->component_creator->createModel( Settings::class, function ( Settings $settings ) use ( $is_just_saved, $tabs, $tab, $current_tab ) { $js_file = $tab->get_tab_js_file(); @@ -143,7 +140,8 @@ function () { $component = $this->make_component(); if ( null !== $component ) { - $this->renderer->render_view( $component, null, true ); + // @phpcs:ignore + echo $this->renderer->renderModel( $component ); } } ); @@ -178,14 +176,14 @@ public function add_setting_tabs( array $classes ): void { } protected function maybe_process_form(): string { - if ( false === current_user_can( 'manage_options' ) ) { + if ( ! current_user_can( 'manage_options' ) ) { return ''; } $tab_name = $this->get_active_tab( Query_Arguments::POST ); if ( '' === $tab_name || - false === key_exists( $tab_name, $this->setting_tabs ) ) { + ! key_exists( $tab_name, $this->setting_tabs ) ) { return ''; } diff --git a/prosopo-procaptcha/src/Settings/Settings_Storage.php b/prosopo-procaptcha/src/Settings/Settings_Storage.php index a4e202c..a570bf8 100644 --- a/prosopo-procaptcha/src/Settings/Settings_Storage.php +++ b/prosopo-procaptcha/src/Settings/Settings_Storage.php @@ -25,7 +25,7 @@ public function __construct() { * @return Settings_Tab_Interface */ public function get( string $item_class ): Settings_Tab_Interface { - if ( true === key_exists( $item_class, $this->settings_tabs ) ) { + if ( key_exists( $item_class, $this->settings_tabs ) ) { return $this->settings_tabs[ $item_class ]; } diff --git a/prosopo-procaptcha/src/Settings/Settings_Tab.php b/prosopo-procaptcha/src/Settings/Settings_Tab.php index 5217e14..ef15de2 100644 --- a/prosopo-procaptcha/src/Settings/Settings_Tab.php +++ b/prosopo-procaptcha/src/Settings/Settings_Tab.php @@ -6,26 +6,32 @@ defined( 'ABSPATH' ) || exit; -use Io\Prosopo\Procaptcha\Collection; use Io\Prosopo\Procaptcha\Interfaces\Captcha\Captcha_Interface; use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Storage_Interface; use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Tab_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Factory_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Interface; use Io\Prosopo\Procaptcha\Query_Arguments; -use Io\Prosopo\Procaptcha\Views\Settings\Settings_Form; -use function Io\Prosopo\Procaptcha\make_collection; +use Io\Prosopo\Procaptcha\Template_Models\Settings\Settings_Form; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\ModelFactoryInterface; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\TemplateModelInterface; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\bool; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; abstract class Settings_Tab implements Settings_Tab_Interface { const OPTION_BASE = 'prosopo-procaptcha__settings'; const OPTION_PREFIX = self::OPTION_BASE . '__'; - protected Collection $validated_fields; - protected ?Collection $settings; + /** + * @var array + */ + protected array $validated_fields; + /** + * @var array|null + */ + protected ?array $settings; public function __construct() { $this->settings = null; - $this->validated_fields = make_collection( array() ); + $this->validated_fields = array(); } abstract public function get_tab_title(): string; @@ -35,10 +41,10 @@ public function process_form( Query_Arguments $query_arguments ): void { $this->update_settings(); } - public function get_settings(): Collection { + public function get_settings(): array { if ( null !== $this->settings ) { // Return a separate instance to avoid out-of-the-class modifications. - return make_collection( $this->settings->to_array() ); + return $this->settings; } $option_name = $this->get_option_name(); @@ -48,14 +54,14 @@ public function get_settings(): Collection { get_option( $this->get_option_name(), array() ) : array(); - $current = true === is_array( $current ) ? + $current = is_array( $current ) ? $current : array(); - $this->settings = make_collection( $current ); + $this->settings = $current; // Setup defaults. - $this->settings->merge( $this->get_default_values(), true ); + $this->settings = array_merge( $this->get_default_values(), $this->settings ); return $this->settings; } @@ -71,7 +77,10 @@ public function clear_data(): void { delete_option( $this->get_option_name() ); } - public function make_tab_component( View_Factory_Interface $creator, Captcha_Interface $captcha ): View_Interface { + public function make_tab_component( + ModelFactoryInterface $factory, + Captcha_Interface $captcha + ): TemplateModelInterface { $string_settings = $this->get_string_settings(); $bool_settings = $this->get_bool_settings(); $select_inputs = $this->get_select_inputs(); @@ -82,39 +91,35 @@ public function make_tab_component( View_Factory_Interface $creator, Captcha_Int $this->load_field_values_from_settings(); foreach ( $string_settings as $field_name => $field_label ) { - $input = make_collection( - array( - 'label' => $field_label, - 'name' => $field_name, - 'type' => 'text', - 'value' => $this->validated_fields->get_string( $field_name ), - ) + $input = array( + 'label' => $field_label, + 'name' => $field_name, + 'type' => 'text', + 'value' => string( $this->validated_fields, $field_name ), ); - if ( true === key_exists( $field_name, $select_inputs ) ) { - $input->add( 'options', $select_inputs[ $field_name ] ); - $input->add( 'type', 'select' ); + if ( key_exists( $field_name, $select_inputs ) ) { + $input['options'] = $select_inputs[ $field_name ]; + $input['type'] = 'select'; } - if ( true === in_array( $field_name, $password_inputs, true ) ) { - $input->add( 'type', 'password' ); + if ( in_array( $field_name, $password_inputs, true ) ) { + $input['type'] = 'password'; } $inputs[] = $input; } foreach ( $bool_settings as $field_name => $field_label ) { - $checkboxes[] = make_collection( - array( - 'label' => $field_label, - 'name' => $field_name, - 'type' => 'checkbox', - 'value' => $this->validated_fields->get_bool( $field_name ), - ) + $checkboxes[] = array( + 'label' => $field_label, + 'name' => $field_name, + 'type' => 'checkbox', + 'value' => bool( $this->validated_fields, $field_name ), ); } - return $creator->make_view( + return $factory->createModel( Settings_Form::class, function ( Settings_Form $settings_form ) use ( $inputs, $checkboxes ) { $settings_form->nonce = wp_create_nonce( Settings_Page::FORM_NONCE ); @@ -192,10 +197,10 @@ protected function validate_settings( Query_Arguments $query_arguments ): void { Query_Arguments::POST ); - $this->validated_fields->add( $bool_setting_name, $bool_setting_value ); + $this->validated_fields[ $bool_setting_name ] = $bool_setting_value; } - $select_inputs = make_collection( $this->get_select_inputs() ); + $select_inputs = $this->get_select_inputs(); foreach ( array_keys( $this->get_string_settings() ) as $string_setting_name ) { $string_setting_value = $query_arguments->get_string_for_admin_action( @@ -204,15 +209,15 @@ protected function validate_settings( Query_Arguments $query_arguments ): void { Query_Arguments::POST ); - if ( true === $select_inputs->exists( $string_setting_name ) ) { - $options = $select_inputs->get_sub_collection( $string_setting_name ); + if ( key_exists( $string_setting_name, $select_inputs ) ) { + $options = $select_inputs[ $string_setting_name ]; - if ( false === $options->exists( $string_setting_value ) ) { + if ( ! key_exists( $string_setting_value, $options ) ) { continue; } } - $this->validated_fields->add( $string_setting_name, $string_setting_value ); + $this->validated_fields[ $string_setting_name ] = $string_setting_value; } } @@ -220,15 +225,15 @@ protected function load_field_values_from_settings(): void { $settings = $this->get_settings(); foreach ( array_keys( $this->get_bool_settings() ) as $bool_setting_name ) { - $bool_setting_value = $settings->get_bool( $bool_setting_name ); + $bool_setting_value = bool( $settings, $bool_setting_name ); - $this->validated_fields->add( $bool_setting_name, $bool_setting_value ); + $this->validated_fields[ $bool_setting_name ] = $bool_setting_value; } foreach ( array_keys( $this->get_string_settings() ) as $string_setting_name ) { - $string_setting_value = $settings->get_string( $string_setting_name ); + $string_setting_value = string( $settings, $string_setting_name ); - $this->validated_fields->add( $string_setting_name, $string_setting_value ); + $this->validated_fields[ $string_setting_name ] = $string_setting_value; } } @@ -236,7 +241,7 @@ protected function update_settings(): void { $settings = $this->get_settings(); // Merge instead of overwrite, as it may contain other settings as well. - $settings->merge( $this->validated_fields ); + $settings = array_merge( $settings, $this->validated_fields ); // Update our settings cache to reflect the merge changes. $this->settings = $settings; @@ -248,6 +253,6 @@ protected function update_settings(): void { return; } - update_option( $option_name, $settings->to_array() ); + update_option( $option_name, $settings ); } } diff --git a/prosopo-procaptcha/src/Settings/Tabs/General_Settings.php b/prosopo-procaptcha/src/Settings/Tabs/General_Settings.php index 5669d8f..285ffdb 100644 --- a/prosopo-procaptcha/src/Settings/Tabs/General_Settings.php +++ b/prosopo-procaptcha/src/Settings/Tabs/General_Settings.php @@ -8,10 +8,10 @@ use Io\Prosopo\Procaptcha\Captcha\Widget_Arguments; use Io\Prosopo\Procaptcha\Interfaces\Captcha\Captcha_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Factory_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Interface; use Io\Prosopo\Procaptcha\Settings\Settings_Tab; -use Io\Prosopo\Procaptcha\Views\Settings\Settings_General_Tab; +use Io\Prosopo\Procaptcha\Template_Models\Settings\Settings_General_Tab; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\ModelFactoryInterface; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\TemplateModelInterface; class General_Settings extends Settings_Tab { const SITE_KEY = 'site_key'; @@ -28,11 +28,11 @@ public function get_tab_name(): string { return 'general'; } - public function make_tab_component( View_Factory_Interface $creator, Captcha_Interface $captcha ): View_Interface { - return $creator->make_view( + public function make_tab_component( ModelFactoryInterface $factory, Captcha_Interface $captcha ): TemplateModelInterface { + return $factory->createModel( Settings_General_Tab::class, - function ( Settings_General_Tab $settings_general_tab ) use ( $creator, $captcha ) { - $settings_general_tab->form = parent::make_tab_component( $creator, $captcha ); + function ( Settings_General_Tab $settings_general_tab ) use ( $factory, $captcha ) { + $settings_general_tab->form = parent::make_tab_component( $factory, $captcha ); $settings_general_tab->preview = $captcha->print_form_field( array( diff --git a/prosopo-procaptcha/src/Settings/Tabs/Statistics.php b/prosopo-procaptcha/src/Settings/Tabs/Statistics.php index 54c13ac..3bfb27b 100644 --- a/prosopo-procaptcha/src/Settings/Tabs/Statistics.php +++ b/prosopo-procaptcha/src/Settings/Tabs/Statistics.php @@ -8,10 +8,11 @@ use Io\Prosopo\Procaptcha\Interfaces\Captcha\Captcha_Interface; use Io\Prosopo\Procaptcha\Interfaces\Settings\Settings_Storage_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Factory_Interface; -use Io\Prosopo\Procaptcha\Interfaces\View\View_Interface; use Io\Prosopo\Procaptcha\Settings\Settings_Tab; -use Io\Prosopo\Procaptcha\Views\Settings\Settings_Statistics; +use Io\Prosopo\Procaptcha\Template_Models\Settings\Settings_Statistics; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\ModelFactoryInterface; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\Interfaces\Model\TemplateModelInterface; +use function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string; class Statistics extends Settings_Tab { public function get_tab_title(): string { @@ -22,8 +23,8 @@ public function get_tab_name(): string { return 'statistics'; } - public function make_tab_component( View_Factory_Interface $creator, Captcha_Interface $captcha ): View_Interface { - return $creator->make_view( + public function make_tab_component( ModelFactoryInterface $factory, Captcha_Interface $captcha ): TemplateModelInterface { + return $factory->createModel( Settings_Statistics::class, function ( Settings_Statistics $statistics ) use ( $captcha ) { $statistics->is_available = $captcha->is_available(); @@ -69,8 +70,8 @@ public function get_tab_js_data( Settings_Storage_Interface $settings_storage ): 'title' => __( 'Whitelisted Domains', 'prosopo-procaptcha' ), ), 'isDebugMode' => false, // todo move into settings as 'debug mode' option. - 'secretKey' => $general_settings->get_string( General_Settings::SECRET_KEY ), - 'siteKey' => $general_settings->get_string( General_Settings::SITE_KEY ), + 'secretKey' => string( $general_settings, General_Settings::SECRET_KEY ), + 'siteKey' => string( $general_settings, General_Settings::SITE_KEY ), 'stateLabels' => array( 'failedToLoad' => __( 'Failed to load. Please try again later.', 'prosopo-procaptcha' ), 'lastRefreshedAt' => __( 'Successfully loaded at', 'prosopo-procaptcha' ), diff --git a/prosopo-procaptcha/src/Template_Models/Settings/Settings.php b/prosopo-procaptcha/src/Template_Models/Settings/Settings.php new file mode 100644 index 0000000..11b2c09 --- /dev/null +++ b/prosopo-procaptcha/src/Template_Models/Settings/Settings.php @@ -0,0 +1,26 @@ + + */ + public array $js_data; + public bool $is_just_saved; + /** + * @var array + */ + public array $tabs; + public string $current_tab; + public TemplateModelInterface $tab_content; +} diff --git a/prosopo-procaptcha/src/Views/Settings/Settings_Form.php b/prosopo-procaptcha/src/Template_Models/Settings/Settings_Form.php similarity index 52% rename from prosopo-procaptcha/src/Views/Settings/Settings_Form.php rename to prosopo-procaptcha/src/Template_Models/Settings/Settings_Form.php index e908daa..ee08d8d 100644 --- a/prosopo-procaptcha/src/Views/Settings/Settings_Form.php +++ b/prosopo-procaptcha/src/Template_Models/Settings/Settings_Form.php @@ -2,22 +2,21 @@ declare( strict_types=1 ); -namespace Io\Prosopo\Procaptcha\Views\Settings; +namespace Io\Prosopo\Procaptcha\Template_Models\Settings; defined( 'ABSPATH' ) || exit; -use Io\Prosopo\Procaptcha\Collection; -use Io\Prosopo\Procaptcha\View\View; +use Io\Prosopo\Procaptcha\Vendors\Prosopo\Views\BaseTemplateModel; -class Settings_Form extends View { +class Settings_Form extends BaseTemplateModel { public string $nonce; public string $tab_name; /** - * @var Collection[] + * @var array */ public array $inputs; /** - * @var Collection[] + * @var array */ public array $checkboxes; public string $inputs_title; diff --git a/prosopo-procaptcha/src/Template_Models/Settings/Settings_General_Tab.php b/prosopo-procaptcha/src/Template_Models/Settings/Settings_General_Tab.php new file mode 100644 index 0000000..4a7976b --- /dev/null +++ b/prosopo-procaptcha/src/Template_Models/Settings/Settings_General_Tab.php @@ -0,0 +1,15 @@ +is_error_visible ? + 'visible' : + 'hidden'; + } + + protected function setCustomDefaults(): void { + $this->attributes = html_attrs_collection( array() ); + $this->hidden_input_attrs = html_attrs_collection( array() ); + } +} diff --git a/prosopo-procaptcha/src/Interfaces/View/index.php b/prosopo-procaptcha/src/Template_Models/index.php similarity index 100% rename from prosopo-procaptcha/src/Interfaces/View/index.php rename to prosopo-procaptcha/src/Template_Models/index.php diff --git a/prosopo-procaptcha/src/View/Blade_Compiler.php b/prosopo-procaptcha/src/View/Blade_Compiler.php deleted file mode 100644 index 6b19683..0000000 --- a/prosopo-procaptcha/src/View/Blade_Compiler.php +++ /dev/null @@ -1,147 +0,0 @@ -remove_comments( $template ); - - $template = $this->replace_opening_echo( $template, $escape_callback_name ); - $template = $this->replace_closing_echo( $template ); - - $template = $this->replace_opening_tag_with_brackets( 'for', $template ); - $template = $this->replace_opening_tag_with_brackets( 'foreach', $template ); - $template = $this->replace_closing_loops( $template ); - - $template = $this->replace_opening_tag_with_brackets( 'if', $template ); - $template = $this->replace_opening_tag_with_brackets( 'elseif', $template ); - $template = $this->replace_closing_if( $template ); - $template = $this->replace_else( $template ); - - $template = $this->replace_opening_php( $template ); - $template = $this->replace_closing_php( $template ); - - $template = $this->replace_use_directive( $template ); - $template = $this->replace_selected_directive( $template ); - $template = $this->replace_checked_directive( $template ); - $template = $this->replace_class_directive( $template, $escape_callback_name ); - $template = $this->replace_switch_directives( $template ); - - return $template; - } - - // Removes all parts like: "{{--Comment--}}". - protected function remove_comments( string $template ): string { - return (string) preg_replace( '/{{--[\s\S]*?--}}/', '', $template ); - } - - protected function replace_opening_echo( string $template, string $escape_callback_name ): string { - $template = str_replace( '{{', sprintf( '', $template ); - - return str_replace( '!!}', '); ?>', $template ); - } - - protected function get_regex_for_tag_with_brackets( string $tag ): string { - // Without 's' flag, .* means everything, but not the new line. - // It's necessary to separate the new line, - // otherwise we'll have big troubles with nested things, like "for(test()->new()) {{ new() }} @endforeach". - return sprintf( '/@%s\s*\((.*)\)/', preg_quote( $tag, '/' ) ); - } - - protected function replace_opening_tag_with_brackets( string $tag, string $template ): string { - $regex = $this->get_regex_for_tag_with_brackets( $tag ); - $replacement = sprintf( '', $tag ); - - return (string) preg_replace( $regex, $replacement, $template ); - } - - protected function replace_closing_loops( string $template ): string { - // It's important to put 'endforeach' first, because 'endfor' is a part of 'endforeach'. - $template = str_replace( '@endforeach', '', $template ); - - return str_replace( '@endfor', '', $template ); - } - - protected function replace_closing_if( string $template ): string { - return str_replace( '@endif', '', $template ); - } - - protected function replace_else( string $template ): string { - return str_replace( '@else', '', $template ); - } - - protected function replace_opening_php( string $template ): string { - return str_replace( '@php', '', $template ); - } - - protected function replace_use_directive( string $template ): string { - return (string) preg_replace( '/@use\s*\((["\'])(.*?)\1\)/s', '', $template ); - } - - protected function replace_selected_directive( string $template ): string { - $regex = $this->get_regex_for_tag_with_brackets( 'selected' ); - - $replacement = ''; - - return (string) preg_replace( $regex, $replacement, $template ); - } - - protected function replace_checked_directive( string $template ): string { - $regex = $this->get_regex_for_tag_with_brackets( 'checked' ); - - $replacement = ''; - - return (string) preg_replace( $regex, $replacement, $template ); - } - - protected function replace_switch_directives( string $template ): string { - $template = $this->replace_opening_tag_with_brackets( 'case', $template ); - - // 1. remove space between @switch and the first "case", otherwise it'll case an error (spaces are threat as unexpected HTML). - $regex = '/@switch\s*\((.*)\)\s*<\?php/'; - $template = (string) preg_replace( $regex, '', $template ); - $template = str_replace( '@default', '', $template ); - $template = str_replace( '@endswitch', '', $template ); - - return $template; - } - - // "@class(['name', 'name2' => $condition])" to 'class="name name2"'. - protected function replace_class_directive( string $template, string $escape_callback_name ): string { - $regex = '/@class\s*\((\[.*])\)/s'; - $replacement = $this->get_php_for_condition_classes( $escape_callback_name ); - - return (string) preg_replace( $regex, $replacement, $template ); - } - - protected function get_php_for_condition_classes( string $escape_callback_name ): string { - $php_code = array(); - - $php_code[] = ' \$value ) {'; - $php_code[] = sprintf( 'if ( true === is_int( \$key ) ) { echo $%s(\$value) . " "; }', $escape_callback_name ); - $php_code[] = sprintf( 'else { if ( true === \$value ) { echo $%s(\$key) . " "; } }', $escape_callback_name ); - $php_code[] = '}';// foreach. - $php_code[] = 'echo trim( (string)ob_get_clean() );'; - $php_code[] = 'echo "\""; ?>'; - - return implode( "\n", $php_code ); - } -} diff --git a/prosopo-procaptcha/src/View/Object_Property_Manager.php b/prosopo-procaptcha/src/View/Object_Property_Manager.php deleted file mode 100644 index e840ebf..0000000 --- a/prosopo-procaptcha/src/View/Object_Property_Manager.php +++ /dev/null @@ -1,173 +0,0 @@ - array(), - 'bool' => false, - 'float' => 0.0, - 'int' => 0, - 'object' => null, - 'string' => '', - ); - - /** - * @var array $default_values type => default_value - */ - private array $default_values; - - /** - * @param array $default_values type => default_value - */ - public function __construct( array $default_values = self::DEFAULT_VALUES ) { - $this->default_values = $default_values; - } - - public function set_default_values( object $instance ): void { - $reflection_class = $this->get_reflection_class( $instance ); - $public_typed_variables = $this->get_public_typed_variables( $reflection_class ); - - array_map( - function ( ReflectionProperty $reflection_property ) use ( $instance ) { - if ( true === $reflection_property->isInitialized( $instance ) ) { - return; - } - - $this->set_default_value_when_type_is_supported( $instance, $reflection_property ); - }, - $public_typed_variables - ); - } - - public function get_variables( object $instance ): array { - $reflection_class = $this->get_reflection_class( $instance ); - - $public_typed_variables = $this->get_public_typed_variables( $reflection_class ); - $variable_values = $this->get_property_values( $instance, $public_typed_variables ); - - $method_names = $this->get_public_method_names( $reflection_class ); - $method_callbacks = $this->make_method_callbacks( $instance, $method_names ); - - /** - * @var array - */ - return array_merge( $variable_values, $method_callbacks ); - } - - /** - * @param ReflectionClass $reflection_class - * - * @return ReflectionProperty[] - */ - protected function get_public_typed_variables( ReflectionClass $reflection_class ): array { - $public_properties = $reflection_class->getProperties( ReflectionProperty::IS_PUBLIC ); - - return $this->get_typed_properties( $public_properties ); - } - - /** - * @param ReflectionClass $reflection_class - * - * @return string[] - */ - protected function get_public_method_names( ReflectionClass $reflection_class ): array { - $public_methods = $reflection_class->getMethods( ReflectionMethod::IS_PUBLIC ); - - return array_diff( - $this->get_method_names_for_given_methods( $public_methods ), - array( '__construct' ) - ); - } - - /** - * @return ReflectionClass - */ - protected function get_reflection_class( object $instance ): ReflectionClass { - return new ReflectionClass( $instance ); - } - - /** - * @param ReflectionProperty[] $reflection_properties - * - * @return ReflectionProperty[] - */ - protected function get_typed_properties( array $reflection_properties ): array { - return array_filter( - $reflection_properties, - function ( ReflectionProperty $property ): bool { - return null !== $property->getType(); - } - ); - } - - /** - * @param ReflectionMethod[] $reflection_methods - * - * @return string[] - */ - protected function get_method_names_for_given_methods( array $reflection_methods ): array { - return array_map( - function ( ReflectionMethod $method ) { - return $method->getName(); - }, - $reflection_methods - ); - } - - /** - * @param ReflectionProperty[] $reflection_properties - * - * @return array variableName => variableValue - */ - protected function get_property_values( object $instance, array $reflection_properties ): array { - return array_reduce( - $reflection_properties, - function ( array $variable_values, ReflectionProperty $reflection_property ) use ( $instance ) { - $variable_values[ $reflection_property->getName() ] = $reflection_property->getValue( $instance ); - - return $variable_values; - }, - array() - ); - } - - /** - * @param string[] $method_names - * - * @return array methodName => method - */ - protected function make_method_callbacks( object $instance, array $method_names ): array { - return array_reduce( - $method_names, - function ( array $method_callbacks, string $method_name ) use ( $instance ) { - $method_callbacks[ $method_name ] = array( $instance, $method_name ); - - return $method_callbacks; - }, - array() - ); - } - - protected function set_default_value_when_type_is_supported( object $instance, ReflectionProperty $reflection_property ): void { - $type = $reflection_property->getType(); - - $type_name = null !== $type ? - // @phpstan-ignore-next-line - $type->getName() : - ''; - - if ( false === key_exists( $type_name, $this->default_values ) ) { - return; - } - - $reflection_property->setValue( $instance, $this->default_values[ $type_name ] ); - } -} diff --git a/prosopo-procaptcha/src/View/Template_Provider.php b/prosopo-procaptcha/src/View/Template_Provider.php deleted file mode 100644 index bc3c674..0000000 --- a/prosopo-procaptcha/src/View/Template_Provider.php +++ /dev/null @@ -1,51 +0,0 @@ -views_path = $views_path; - $this->root_namespace = $root_namespace; - $this->template_extension = $template_extension; - } - - public function get_template( View_Interface $view ): string { - $view_name = $this->get_view_filename( get_class( $view ), $this->root_namespace ); - - $path_to_view = $this->get_path_to_view( $view_name ); - - return $this->get_file_content_safely( $path_to_view ); - } - - protected function get_file_content_safely( string $file ): string { - if ( false === file_exists( $file ) ) { - // todo log. - return ''; - } - - // @phpcs:ignore - return (string) file_get_contents( $file ); - } - - protected function get_path_to_view( string $view_name ): string { - return $this->views_path . DIRECTORY_SEPARATOR . $view_name . $this->template_extension; - } - - protected function get_view_filename( string $component_class, string $root_namespace ): string { - $relative_namespace = str_replace( $root_namespace, '', $component_class ); - $relative_namespace = ltrim( $relative_namespace, '\\' ); - - $short_class_name = str_replace( '\\', DIRECTORY_SEPARATOR, $relative_namespace ); - - return strtolower( $short_class_name ); - } -} diff --git a/prosopo-procaptcha/src/View/Template_Renderer.php b/prosopo-procaptcha/src/View/Template_Renderer.php deleted file mode 100644 index 44ba85a..0000000 --- a/prosopo-procaptcha/src/View/Template_Renderer.php +++ /dev/null @@ -1,121 +0,0 @@ -template_compiler = $template_engine; - - $this->escape_callback = null === $escape_callback ? - array( $this, 'escape' ) : - $escape_callback; - - $this->escape_callback_name = $escape_callback_name; - $this->error_handler = $error_handler; - } - - public function render_template( string $template, array $variables, bool $do_print = false ): string { - $php_template = $this->template_compiler->compile( $template, $this->escape_callback_name ); - - $variables[ $this->escape_callback_name ] = $this->escape_callback; - - // @phpcs:ignore - extract( $variables ); - - ob_start(); - - try { - // Catch all level-errors and turn into the generic error. - // @phpcs:ignore - set_error_handler( - function ( $errno, $errstr ) { - // @phpcs:ignore - throw new Error( $errstr, $errno ); - } - ); - - // @phpcs:ignore - eval( '?>' . $php_template ); - } catch ( Error $error ) { - $this->dispatch_template_error( $error->getMessage(), $error->getLine(), $php_template ); - } catch ( Exception $error ) { - // Separate catch handlers to handle all the error types, cause some errors do not inherit Error. - $this->dispatch_template_error( $error->getMessage(), $error->getLine(), $php_template ); - } finally { - restore_error_handler(); - } - - $html = (string) ob_get_clean(); - - if ( true === $do_print ) { - // @phpcs:ignore - echo $html; - } - - return $html; - } - - /** - * @param mixed $value - * - * @return string - */ - public function escape( $value ): string { - $string_value = $this->cast_to_string( $value ); - - return htmlspecialchars( $string_value, ENT_QUOTES, 'UTF-8', false ); - } - - /** - * @param mixed $value - */ - protected function cast_to_string( $value ): string { - if ( true === is_string( $value ) || - true === is_numeric( $value ) ) { - return (string) $value; - } - - if ( true === is_object( $value ) && - method_exists( $value, '__toString' ) ) { - return (string) $value; - } - - return ''; - } - - protected function dispatch_template_error( string $message, int $line, string $php_template ): void { - if ( null === $this->error_handler ) { - return; - } - - $handler = $this->error_handler; - $handler( $message, $line, $php_template ); - } -} diff --git a/prosopo-procaptcha/src/View/View.php b/prosopo-procaptcha/src/View/View.php deleted file mode 100644 index b3a2e28..0000000 --- a/prosopo-procaptcha/src/View/View.php +++ /dev/null @@ -1,25 +0,0 @@ -template_provider = $template_provider; - - $this->set_custom_defaults(); - } - - public function get_template(): string { - return $this->template_provider->get_template( $this ); - } - - protected function set_custom_defaults(): void { - } -} diff --git a/prosopo-procaptcha/src/View/View_Factory.php b/prosopo-procaptcha/src/View/View_Factory.php deleted file mode 100644 index ecfb166..0000000 --- a/prosopo-procaptcha/src/View/View_Factory.php +++ /dev/null @@ -1,34 +0,0 @@ -object_property_manager = $object_property_manager; - $this->template_provider = $template_provider; - } - - public function make_view( string $view_class, ?Closure $setup_callback = null ): View_Interface { - // todo add optional container support. - $view_instance = new $view_class( $this->template_provider ); - - $this->object_property_manager->set_default_values( $view_instance ); - - if ( null !== $setup_callback ) { - $setup_callback( $view_instance ); - } - - return $view_instance; - } -} diff --git a/prosopo-procaptcha/src/View/View_Renderer.php b/prosopo-procaptcha/src/View/View_Renderer.php deleted file mode 100644 index d8ffdb7..0000000 --- a/prosopo-procaptcha/src/View/View_Renderer.php +++ /dev/null @@ -1,70 +0,0 @@ -template_renderer = $template_renderer; - $this->view_factory = $view_factory; - $this->object_property_manager = $object_property_manager; - } - - public function render_view( $view_or_class, ?Closure $setup_callback = null, bool $do_print = false ): string { - $component = true === is_string( $view_or_class ) ? - $this->view_factory->make_view( $view_or_class, $setup_callback ) : - $view_or_class; - - $template = $component->get_template(); - $variables = $this->object_property_manager->get_variables( $component ); - - $variables = $this->render_nested_views( $variables ); - - return $this->template_renderer->render_template( $template, $variables, $do_print ); - } - - /** - * @param array $variables - * - * @return array - */ - protected function render_nested_views( array $variables ): array { - return array_map( - function ( $item ) { - return $this->render_if_view( $item ); - }, - $variables - ); - } - - /** - * @param mixed $item - * - * @return mixed - */ - protected function render_if_view( $item ) { - if ( true === ( $item instanceof View_Interface ) ) { - $item = $this->render_view( $item ); - } elseif ( true === is_array( $item ) && - false === is_callable( $item ) ) { - $item = $this->render_nested_views( $item ); - } - - return $item; - } -} diff --git a/prosopo-procaptcha/src/Views/Settings/Settings.php b/prosopo-procaptcha/src/Views/Settings/Settings.php deleted file mode 100644 index b367bfd..0000000 --- a/prosopo-procaptcha/src/Views/Settings/Settings.php +++ /dev/null @@ -1,27 +0,0 @@ - - */ - public array $js_data; - public bool $is_just_saved; - /** - * @var Collection[] - */ - public array $tabs; - public string $current_tab; - public View_Interface $tab_content; -} diff --git a/prosopo-procaptcha/src/Views/Settings/Settings_General_Tab.php b/prosopo-procaptcha/src/Views/Settings/Settings_General_Tab.php deleted file mode 100644 index b4f7909..0000000 --- a/prosopo-procaptcha/src/Views/Settings/Settings_General_Tab.php +++ /dev/null @@ -1,15 +0,0 @@ -is_error_visible ? - 'visible' : - 'hidden'; - } - - protected function set_custom_defaults(): void { - parent::set_custom_defaults(); - - $this->attributes = make_collection( array() ); - $this->hidden_input_attrs = make_collection( array() ); - } -} diff --git a/prosopo-procaptcha/src/blade-templates/index.php b/prosopo-procaptcha/src/blade-templates/index.php deleted file mode 100644 index edaaa4e..0000000 --- a/prosopo-procaptcha/src/blade-templates/index.php +++ /dev/null @@ -1,2 +0,0 @@ - $items */ -function make_collection( array $items ): Collection { - return new Collection( $items ); +function html_attrs_collection( array $items ): Html_Attributes_Collection { + return new Html_Attributes_Collection( $items ); } diff --git a/prosopo-procaptcha/src/View/index.php b/prosopo-procaptcha/src/views/index.php similarity index 100% rename from prosopo-procaptcha/src/View/index.php rename to prosopo-procaptcha/src/views/index.php diff --git a/prosopo-procaptcha/src/Views/index.php b/prosopo-procaptcha/src/views/settings/index.php similarity index 100% rename from prosopo-procaptcha/src/Views/index.php rename to prosopo-procaptcha/src/views/settings/index.php diff --git a/prosopo-procaptcha/src/blade-templates/settings/settings.blade.php b/prosopo-procaptcha/src/views/settings/settings.blade.php similarity index 85% rename from prosopo-procaptcha/src/blade-templates/settings/settings.blade.php rename to prosopo-procaptcha/src/views/settings/settings.blade.php index 32aeb81..740426e 100644 --- a/prosopo-procaptcha/src/blade-templates/settings/settings.blade.php +++ b/prosopo-procaptcha/src/views/settings/settings.blade.php @@ -1,3 +1,6 @@ +@use('function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\string') +@use('function Io\Prosopo\Procaptcha\Vendors\WPLake\Typed\bool') +