diff --git a/.github/ci/files/bin/console b/.github/ci/files/bin/console index f6d43d5..8e34b19 100644 --- a/.github/ci/files/bin/console +++ b/.github/ci/files/bin/console @@ -40,7 +40,7 @@ if ($input->hasParameterOption('--no-debug', true)) { putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); } -/** @var \Pimcore\Kernel $kernel */ +/** @var \OpenDxp\Kernel $kernel */ $kernel = \OpenDxp\Bootstrap::startupCli(); $application = new \OpenDxp\Console\Application($kernel); $application->run(); diff --git a/.github/ci/files/config/packages/security.yaml b/.github/ci/files/config/packages/security.yaml index cfd57fc..2476bc2 100644 --- a/.github/ci/files/config/packages/security.yaml +++ b/.github/ci/files/config/packages/security.yaml @@ -1,6 +1,4 @@ security: - enable_authenticator_manager: true - providers: opendxp_admin: id: OpenDxp\Security\User\UserProvider @@ -10,17 +8,17 @@ security: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false - # Pimcore WebDAV HTTP basic // DO NOT CHANGE! + # OpenDxp WebDAV HTTP basic // DO NOT CHANGE! opendxp_webdav: pattern: ^/asset/webdav provider: opendxp_admin http_basic: ~ - # Pimcore Admin Bundle firewall + # OpenDxp Admin Bundle firewall opendxp_admin: '%opendxp_admin_bundle.firewall_settings%' access_control: - # Pimcore admin ACl // DO NOT CHANGE! + # OpenDxp admin ACl // DO NOT CHANGE! - { path: ^/admin/settings/display-custom-logo, roles: PUBLIC_ACCESS } - { path: ^/admin/login/2fa-verify, roles: IS_AUTHENTICATED_2FA_IN_PROGRESS } - { path: ^/admin/login/2fa-setup, roles: ROLE_OPENDXP_USER } @@ -31,5 +29,5 @@ security: - { path: ^/asset/webdav, roles: ROLE_OPENDXP_USER } role_hierarchy: - # Pimcore admin // DO NOT CHANGE! + # OpenDxp admin // DO NOT CHANGE! ROLE_OPENDXP_ADMIN: [ROLE_OPENDXP_USER] diff --git a/.github/ci/files/config/packages/test/config.yaml b/.github/ci/files/config/packages/test/config.yaml index 72e6778..d66b071 100644 --- a/.github/ci/files/config/packages/test/config.yaml +++ b/.github/ci/files/config/packages/test/config.yaml @@ -1,7 +1,7 @@ imports: - { resource: ../../config.yaml } -# this cache is used during tests when setting up pimcore +# this cache is used during tests when setting up opendxp framework: cache: pools: diff --git a/.github/ci/files/config/services.yaml b/.github/ci/files/config/services.yaml index 0198555..ec7e73d 100644 --- a/.github/ci/files/config/services.yaml +++ b/.github/ci/files/config/services.yaml @@ -23,7 +23,7 @@ services: # Example event listener for objects # AppBundle\EventListener\TestListener: # tags: - # - { name: kernel.event_listener, event: pimcore.dataobject.preUpdate, method: onObjectPreUpdate } + # - { name: kernel.event_listener, event: opendxp.dataobject.preUpdate, method: onObjectPreUpdate } OpenDxp\Bundle\PersonalizationBundle\Installer: public: true diff --git a/.github/ci/files/config/system.yml b/.github/ci/files/config/system.yml index 84bb458..7024eaf 100644 --- a/.github/ci/files/config/system.yml +++ b/.github/ci/files/config/system.yml @@ -4,7 +4,6 @@ opendxp: path_variable: '' domain: opendxp-test.dev redirect_to_maindomain: false - language: en valid_languages: 'en,de' fallback_languages: en: '' diff --git a/.github/ci/files/public/index_test.php b/.github/ci/files/public/index_test.php index 26e86cb..f6cc53a 100644 --- a/.github/ci/files/public/index_test.php +++ b/.github/ci/files/public/index_test.php @@ -29,7 +29,7 @@ // request stack available yet Tool::setCurrentRequest($request); -/** @var \Pimcore\Kernel $kernel */ +/** @var \OpenDxp\Kernel $kernel */ $kernel = \OpenDxp\Bootstrap::kernel(); // reset current request - will be read from request stack from now on diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml new file mode 100644 index 0000000..a56a5bd --- /dev/null +++ b/.github/workflows/cla.yaml @@ -0,0 +1,14 @@ +name: CLA check [centralised] + +on: + issue_comment: + types: [ created ] + pull_request_target: + types: [ opened, closed, synchronize ] + +jobs: + cla-workflow: + uses: open-dxp/workflows-collection-public/.github/workflows/reusable-cla-check.yaml@main + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' + secrets: + CLA_ACTION_ACCESS_TOKEN: ${{ secrets.CLA_ACTION_ACCESS_TOKEN }} diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml deleted file mode 100644 index 454c851..0000000 --- a/.github/workflows/cla.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: CLA check - -on: - issue_comment: - types: [created] - pull_request_target: - types: [opened, closed, synchronize] - -jobs: - cla-workflow: - uses: opendxp/workflows-collection-public/.github/workflows/reusable-cla-check.yaml@v1.3.0 - if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - secrets: - CLA_ACTION_ACCESS_TOKEN: ${{ secrets.CLA_ACTION_ACCESS_TOKEN }} diff --git a/.github/workflows/codeception.yaml b/.github/workflows/codeception.yaml index 6f178b6..0c60363 100644 --- a/.github/workflows/codeception.yaml +++ b/.github/workflows/codeception.yaml @@ -1,85 +1,86 @@ -name: "Codeception Tests" +name: Codeception Tests [centralised] on: - schedule: - - cron: '0 3 * * 1,3,5' - pull_request: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - paths-ignore: - - 'doc/**' - - 'src/Resources/public/**' + workflow_dispatch: push: branches: - "[0-9]+.[0-9]+" - "[0-9]+.x" - paths-ignore: - - 'doc/**' - - 'src/Resources/public/**' + - "feature-*" + pull_request: + types: [ opened, synchronize, reopened ] env: OPENDXP_PROJECT_ROOT: ${{ github.workspace }} - APP_ENV: test - OPENDXP_TEST: 1 - OPENDXP_TEST_DB_DSN: "mysql://root@127.0.0.1:33006/opendxp_test" jobs: - codeception-tests: - name: "Codeception tests" - runs-on: "ubuntu-latest" - continue-on-error: ${{ matrix.experimental }} - env: - OPENDXP_TEST_DB_DSN: "mysql://root@127.0.0.1:33006/opendxp_test" - strategy: - matrix: - include: - - { php-version: 8.1, database: "mariadb:10.3", dependencies: lowest, experimental: false } - - { php-version: 8.2, database: "mariadb:10.11", dependencies: highest, experimental: false } - - { php-version: 8.3, database: "mariadb:10.11", opendxp_version: "11.5", dependencies: highest, experimental: true } - services: - mariadb: - image: "${{ matrix.database }}" - ports: - - 33006:3306 - env: - MYSQL_ALLOW_EMPTY_PASSWORD: yes - + setup-matrix: + runs-on: ubuntu-latest + outputs: + php_versions: ${{ steps.parse-php-versions.outputs.php_versions }} + matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - - name: "Checkout code" - uses: "actions/checkout@v2" + - name: Checkout code + uses: actions/checkout@v4 - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" + - name: Checkout reusable workflow repo + uses: actions/checkout@v4 with: - coverage: "none" - extensions: imagick - ini-values: display_errors=On, display_startup_errors=On, error_reporting=32767 - php-version: "${{ matrix.php-version }}" + repository: open-dxp/workflows-collection-public + ref: main + path: reusable-workflows - - name: Verify MariaDB connection + - name: Parse PHP versions from composer.json + id: parse-php-versions run: | - cp .github/ci/files/.my.cnf ~/.my.cnf - while ! mysqladmin ping --silent; do - sleep 1 - done - - name: "Setup OpenDxp environment" - run: | - mysql -e "CREATE DATABASE opendxp_test CHARSET=utf8mb4;" - chmod 755 .github/ci/scripts/setup-opendxp-environment.sh - .github/ci/scripts/setup-opendxp-environment.sh - - name: "Update OpenDxp version" - env: - OPENDXP_VERSION: "${{ matrix.opendxp_version }}" - run: | - if [ ! -z "$OPENDXP_VERSION" ]; then - composer require --no-update open-dxp/opendxp:"${OPENDXP_VERSION}" - composer require --no-update open-dxp/admin-bundle:1.0 + if [ -f composer.json ]; then + php_versions=$(jq -r '.require.php' composer.json | grep -oP '\d+\.\d+' | tr '\n' ',' | sed 's/,$//') + if [ -z "$php_versions" ]; then + echo "No PHP versions found in composer.json" + echo "Setting default PHP value" + echo "php_versions=default" >> $GITHUB_OUTPUT + else + echo "php_versions=$php_versions" >> $GITHUB_OUTPUT + echo "#### php versions #### : $php_versions" + fi + else + echo "composer.json not found" + exit 1 fi - - name: "Install dependencies with Composer" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "${{ matrix.dependencies }}" - - name: "Run Codeception" - run: "vendor/bin/codecept run -c . -vvv --xml" + - name: Set up matrix + id: set-matrix + run: | + php_versions="${{ steps.parse-php-versions.outputs.php_versions }}" + + MATRIX_JSON=$(cat reusable-workflows/codeception-tests-configuration/matrix-config.json) + + IFS=',' read -ra VERSIONS_ARRAY <<< "$php_versions" + + FILTERED_MATRIX_JSON=$(echo $MATRIX_JSON | jq --arg php_versions "$php_versions" ' + { + matrix: [ + .configs[] | + select(.php_version == $php_versions) | + .matrix[] + ] + }') + + ENCODED_MATRIX_JSON=$(echo $FILTERED_MATRIX_JSON | jq -c .) + + echo "matrix=${ENCODED_MATRIX_JSON}" >> $GITHUB_OUTPUT + + codeception-tests: + needs: setup-matrix + strategy: + matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }} + uses: open-dxp/workflows-collection-public/.github/workflows/reusable-codeception-tests-centralized.yaml@main + with: + APP_ENV: test + OPENDXP_TEST: 1 + PHP_VERSION: ${{ matrix.matrix.php-version }} + DATABASE: ${{ matrix.matrix.database }} + SERVER_VERSION: ${{ matrix.matrix.server_version }} + DEPENDENCIES: ${{ matrix.matrix.dependencies }} + EXPERIMENTAL: ${{ matrix.matrix.experimental }} + OPENDXP_VERSION: ${{ matrix.matrix.opendxp_version }} diff --git a/.github/workflows/docs.yaml.bak b/.github/workflows/docs.yaml.bak deleted file mode 100644 index f205e14..0000000 --- a/.github/workflows/docs.yaml.bak +++ /dev/null @@ -1,75 +0,0 @@ -# Original docs workflow disabled in favor of new-docs.yml -# This file is kept only for reference. The active workflow is .github/workflows/new-docs.yml -# Backup of the original content: .github/workflows/docs.yaml.bak - -# -# name: "Documentation" -# -# on: -# pull_request_target: -# branches: -# - "[0-9]+.[0-9]+" -# - "[0-9]+.x" -# paths: -# - 'doc/**' -# - '.github/workflows/docs.yaml' -# - 'README.md' -# push: -# branches: -# - "[0-9]+.[0-9]+" -# - "[0-9]+.x" -# - "*_actions" -# paths: -# - 'doc/**' -# - '.github/workflows/docs.yaml' -# - 'README.md' -# -# permissions: -# contents: read -# -# jobs: -# docs: -# name: "Generate docs OpenDxp Docs Generator" -# runs-on: "ubuntu-latest" -# steps: -# - name: "Checkout code" -# uses: "actions/checkout@v4" -# with: -# ref: ${{ github.event.pull_request.head.sha }} -# -# - name: "Checkout Docs Generator" -# uses: "actions/checkout@v4" -# with: -# repository: "opendxp/docs-generator" -# ref: "main" -# path: "./docs-generator" -# token: ${{ secrets.DOCS_GENERATOR_ACCESS_TOKEN }} -# -# - name: "Install Node" -# uses: actions/setup-node@v4 -# with: -# node-version: 'lts/*' -# registry-url: 'https://registry.npmjs.org' -# -# - name: Prepare Docs -# working-directory: "./docs-generator" -# run: | -# mkdir docs -# # copy docs to working directory -# cp -r ../doc ./docs/ -# -# # copy readme to working directory -# cp -r ../README.md ./docs/ -# -# # copy index page -# cp bin/resources/00_index_empty.md ./docs/00_index.md -# -# # use special docusaurus config (to exclude search plugin) and check for broken links -# mv docusaurus.config.js.repos-tests docusaurus.config.js -# -# - name: Build Docs -# working-directory: "./docs-generator" -# run: | -# npm install -# npm run build -# diff --git a/.github/workflows/new-docs.yml b/.github/workflows/new-docs.yml deleted file mode 100644 index 72f36d1..0000000 --- a/.github/workflows/new-docs.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: "Documentation (Reusable)" - -on: - pull_request_target: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "docs_actions" - paths: - - "doc/**" - - ".github/workflows/new-docs.yml" - - "README.md" - push: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "docs_actions" - paths: - - "doc/**" - - ".github/workflows/new-docs.yml" - - "README.md" - -permissions: - contents: read - -jobs: - docs: - uses: opendxp/workflows-collection-public/.github/workflows/reusable-docs.yaml@reusable-workflows - with: - docs_path: "doc" - secrets: - DOCS_GENERATOR_ACCESS_TOKEN: ${{ secrets.DOCS_GENERATOR_ACCESS_TOKEN }} diff --git a/.github/workflows/new-php-cs-fixer.yaml b/.github/workflows/new-php-cs-fixer.yaml deleted file mode 100644 index 3cf4e7f..0000000 --- a/.github/workflows/new-php-cs-fixer.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: "PHP-CS-Fixer" - -on: - workflow_dispatch: - push: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "*_actions" - - "feature-*" - -permissions: - contents: write - -jobs: - php-style: - uses: opendxp/workflows-collection-public/.github/workflows/reusable-php-cs-fixer.yaml@fix-failed-workflow - with: - head_ref: ${{ github.head_ref || github.ref_name }} - repository: ${{ github.repository }} - config_file: ".php-cs-fixer.dist.php" - secrets: - PHP_CS_FIXER_GITHUB_TOKEN: ${{ secrets.PHP_CS_FIXER_GITHUB_TOKEN }} diff --git a/.github/workflows/new-poeditor-export.yml b/.github/workflows/new-poeditor-export.yml deleted file mode 100644 index 0821f91..0000000 --- a/.github/workflows/new-poeditor-export.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "Trigger POEditor Translations Export (Reusable)" - -on: - workflow_dispatch: - push: - branches: - - "[0-9]+.x" - - "docs_actions" - - "main" - paths: - - "src/Resources/translations/admin.en.yml" - -permissions: - contents: read - -jobs: - poeditor: - uses: opendxp/workflows-collection-public/.github/workflows/reusable-poeditor.yaml@main - secrets: - POEDITOR_ACTION_TRIGGER_TOKEN: ${{ secrets.POEDITOR_ACTION_TRIGGER_TOKEN }} - diff --git a/.github/workflows/php-cs-fixer.yaml b/.github/workflows/php-cs-fixer.yaml new file mode 100644 index 0000000..881d807 --- /dev/null +++ b/.github/workflows/php-cs-fixer.yaml @@ -0,0 +1,23 @@ +name: PHP-CS-Fixer [centralised] + +on: + workflow_dispatch: + push: + branches: + - "[0-9]+.[0-9]+" + - "[0-9]+.x" + - "*_actions" + - "feature-*" + +permissions: + contents: write + +jobs: + php-style: + uses: open-dxp/workflows-collection-public/.github/workflows/reusable-php-cs-fixer.yaml@main + secrets: + PHP_CS_FIXER_GITHUB_TOKEN: ${{ secrets.PHP_CS_FIXER_GITHUB_TOKEN }} + with: + head_ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + config_file: .php-cs-fixer.dist.php \ No newline at end of file diff --git a/.github/workflows/php-cs-fixer.yaml.bak b/.github/workflows/php-cs-fixer.yaml.bak deleted file mode 100644 index 6d19d4f..0000000 --- a/.github/workflows/php-cs-fixer.yaml.bak +++ /dev/null @@ -1,35 +0,0 @@ -name: "PHP-CS-Fixer" - -on: - pull_request_target: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "feature-*" - push: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "*_actions" - - "feature-*" - -permissions: - contents: read - -jobs: - php-cs-fixer: - permissions: - contents: write # for stefanzweifel/git-auto-commit-action to push code in repo - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - - - name: PHP-CS-Fixer - uses: docker://oskarstark/php-cs-fixer-ga:latest - - - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Apply php-cs-fixer changes diff --git a/.github/workflows/poeditor-export.yaml b/.github/workflows/poeditor-export.yaml new file mode 100644 index 0000000..d246f95 --- /dev/null +++ b/.github/workflows/poeditor-export.yaml @@ -0,0 +1,19 @@ +name: POEditor Translations Export [centralised] + +on: + workflow_dispatch: + push: + branches: + - "[0-9]+.x" + paths: + - 'translations/admin.en.yaml' + - 'translations/admin_ext.en.yaml' + +permissions: + contents: read + +jobs: + php-style: + uses: open-dxp/workflows-collection-public/.github/workflows/reusable-poeditor.yaml@main + secrets: + POEDITOR_ACTION_TRIGGER_TOKEN: ${{ secrets.POEDITOR_ACTION_TRIGGER_TOKEN }} diff --git a/.github/workflows/poeditor-export.yaml.bak b/.github/workflows/poeditor-export.yaml.bak deleted file mode 100644 index dc04070..0000000 --- a/.github/workflows/poeditor-export.yaml.bak +++ /dev/null @@ -1,20 +0,0 @@ -name: "Trigger POEditor Translations Export" - -on: - workflow_dispatch: - push: - branches: - - "[0-9]+.x" - paths: - - 'translations/admin.en.yaml' - -permissions: - contents: read - -jobs: - poeditor: - runs-on: ubuntu-latest - steps: - - name: Trigger workflow in opendxp/poeditor-export-action - run: | - gh workflow run -R opendxp/poeditor-export-action poeditor-export.yaml diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 0000000..11e2539 --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,10 @@ +name: Stale issues [centralised] + +on: + workflow_dispatch: + schedule: + - cron: '37 7 * * *' + +jobs: + call-stale-workflow: + uses: open-dxp/workflows-collection-public/.github/workflows/stale.yml@main diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index 9cb137f..0000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: Handle stale issues - -on: - workflow_dispatch: - schedule: - - cron: '37 7 * * *' - -jobs: - call-stale-workflow: - uses: opendxp/workflows-collection-public/.github/workflows/stale.yml@v1.1.0 diff --git a/.github/workflows/static-analysis.yaml b/.github/workflows/static-analysis.yaml deleted file mode 100644 index 86bf6aa..0000000 --- a/.github/workflows/static-analysis.yaml +++ /dev/null @@ -1,61 +0,0 @@ -name: "Static Analysis" - -on: - schedule: - - cron: '0 3 * * 1,3,5' - pull_request: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - paths-ignore: - - 'doc/**' - - 'src/Resources/public/**' - push: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - paths-ignore: - - 'doc/**' - - 'src/Resources/public/**' - -jobs: - static-analysis-phpstan: - name: "Static Analysis with PHPStan" - runs-on: "ubuntu-latest" - continue-on-error: ${{ matrix.experimental }} - strategy: - matrix: - include: - - { php-version: "8.1", dependencies: "lowest", opendxp_version: "", phpstan_args: "", experimental: false } - - { php-version: "8.2", dependencies: "highest", phpstan_args: "", experimental: false } - - { php-version: "8.3", dependencies: "highest", opendxp_version: "11.5", phpstan_args: "", experimental: true } - steps: - - name: "Checkout code" - uses: "actions/checkout@v2" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "none" - php-version: "${{ matrix.php-version }}" - - - name: "Setup OpenDxp environment" - run: | - .github/ci/scripts/setup-opendxp-environment.sh - - - name: "Update OpenDxp version" - env: - OPENDXP_VERSION: "${{ matrix.opendxp_version }}" - run: | - if [ ! -z "$OPENDXP_VERSION" ]; then - composer require --no-update open-dxp/opendxp:${OPENDXP_VERSION} - composer require --no-update open-dxp/admin-bundle:1.0 - fi - - - name: "Install dependencies with Composer" - uses: "ramsey/composer-install@v1" - with: - dependency-versions: "${{ matrix.dependencies }}" - - - name: "Run a static analysis with phpstan/phpstan" - run: "vendor/bin/phpstan analyse ${{ matrix.phpstan_args }} -c phpstan.neon --memory-limit=-1" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..b91c37c --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,91 @@ +name: Static analysis [centralised] + +on: + schedule: + - cron: '0 3 * * 1,3,5' + workflow_dispatch: + push: + branches: + - "[0-9]+.[0-9]+" + - "[0-9]+.x" + - "feature-*" + pull_request: + types: [ opened, synchronize, reopened ] + +env: + OPENDXP_PROJECT_ROOT: ${{ github.workspace }} + PRIVATE_REPO: ${{ github.event.repository.private }} + +jobs: + setup-matrix: + runs-on: ubuntu-latest + outputs: + php_versions: ${{ steps.parse-php-versions.outputs.php_versions }} + matrix: ${{ steps.set-matrix.outputs.matrix }} + private_repo: ${{ env.PRIVATE_REPO }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Checkout reusable workflow repo + uses: actions/checkout@v4 + with: + repository: open-dxp/workflows-collection-public + ref: main + path: reusable-workflows + + - name: Parse PHP versions from composer.json + id: parse-php-versions + run: | + if [ -f composer.json ]; then + php_versions=$(jq -r '.require.php' composer.json | grep -oP '\d+\.\d+' | tr '\n' ',' | sed 's/,$//') + if [ -z "$php_versions" ]; then + echo "No PHP versions found in composer.json" + echo "Setting default PHP value" + echo "php_versions=default" >> $GITHUB_OUTPUT + else + echo "php_versions=$php_versions" >> $GITHUB_OUTPUT + echo "#### php versions #### : $php_versions" + fi + else + echo "composer.json not found" + exit 1 + fi + + - name: Set up matrix + id: set-matrix + run: | + php_versions="${{ steps.parse-php-versions.outputs.php_versions }}" + + MATRIX_JSON=$(cat reusable-workflows/phpstan-configuration/matrix-config.json) + + IFS=',' read -ra VERSIONS_ARRAY <<< "$php_versions" + + FILTERED_MATRIX_JSON=$(echo $MATRIX_JSON | jq --arg php_versions "$php_versions" ' + { + matrix: [ + .configs[] | + select(.php_version == $php_versions) | + .matrix[] + ] + }') + + ENCODED_MATRIX_JSON=$(echo $FILTERED_MATRIX_JSON | jq -c .) + + echo "matrix=${ENCODED_MATRIX_JSON}" >> $GITHUB_OUTPUT + + static-analysis: + needs: setup-matrix + strategy: + matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }} + uses: open-dxp/workflows-collection-public/.github/workflows/reusable-static-analysis-centralized.yaml@main + with: + APP_ENV: test + OPENDXP_TEST: 1 + PRIVATE_REPO: ${{ needs.setup-matrix.outputs.private_repo}} + PHP_VERSION: ${{ matrix.matrix.php-version }} + SYMFONY: ${{ matrix.matrix.symfony }} + DEPENDENCIES: ${{ matrix.matrix.dependencies }} + EXPERIMENTAL: ${{ matrix.matrix.experimental }} + OPENDXP_VERSION: ${{ matrix.matrix.opendxp_version }} + COMPOSER_OPTIONS: ${{ matrix.matrix.composer_options }} diff --git a/.github/workflows/sync-changes-scheduled.yml b/.github/workflows/sync-changes-scheduled.yml deleted file mode 100644 index 861aba8..0000000 --- a/.github/workflows/sync-changes-scheduled.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Sync changes scheduled from CE to EE -on: - workflow_dispatch: - schedule: - - cron: '30 21 * * *' - -jobs: - sync-branches: - uses: opendxp/workflows-collection-public/.github/workflows/reusable-sync-changes.yaml@main - if: github.repository == 'opendxp/personalization-bundle' - strategy: - fail-fast: false - matrix: - ref: [{'base': '1.0', 'destination': '1.0'},{'base': '1.1', 'destination': '1.1'}] - with: - base_ref: ${{ matrix.ref.base }} - ref_name: ${{ matrix.ref.destination }} - target_repo: 'ee-personalization-bundle' - auto_merge: true - secrets: - SYNC_TOKEN: ${{ secrets.SYNC_TOKEN }} - GIT_NAME: ${{ secrets.GIT_NAME }} - GIT_EMAIL: ${{ secrets.GIT_EMAIL }} diff --git a/.gitignore b/.gitignore index ad3501f..a1a9dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -14,12 +14,6 @@ Thumbs.db /app/config/local/* !app/config/local/.gitkeep -# pimcore legacy (remove this for your own development) -!/legacy -/legacy/* -!legacy/.gitkeep -!legacy/bundle - /var/* !/var/.gitkeep !/var/classes/ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 9ee91ea..325d567 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -5,12 +5,14 @@ __DIR__ . '/src', __DIR__ . '/tests', ]) + ->exclude([ __DIR__ . '/tests/_output', __DIR__ . '/tests/Support/_generated', - ]); + ]) +; -// do not enable self_accessor as it breaks pimcore models relying on get_called_class() +// do not enable self_accessor as it breaks opendxp models relying on get_called_class() $config = new PhpCsFixer\Config(); $config->setRules([ '@PSR1' => true, @@ -20,17 +22,17 @@ 'header_comment' => [ 'comment_type' => 'PHPDoc', - 'header' => 'Pimcore' . PHP_EOL . PHP_EOL . - 'This source file is available under two different licenses:' . PHP_EOL . - '- GNU General Public License version 3 (GPLv3)' . PHP_EOL . - '- Pimcore Commercial License (PCL)' . PHP_EOL . + 'header' => 'OpenDXP' . PHP_EOL + . PHP_EOL . + 'This source file is licensed under the GNU General Public License version 3 (GPLv3).' . PHP_EOL + . PHP_EOL . 'Full copyright and license information is available in' . PHP_EOL . - 'LICENSE.md which is distributed with this source code.' . PHP_EOL . - PHP_EOL . - ' @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)' . PHP_EOL . - ' @license http://www.pimcore.org/license GPLv3 and PCL' + 'LICENSE.md which is distributed with this source code.' . PHP_EOL + . PHP_EOL . + '@copyright Copyright (c) Pimcore GmbH (https://pimcore.com)' . PHP_EOL . + '@copyright Modification Copyright (c) OpenDXP (https://www.opendxp.ch)' . PHP_EOL . + '@license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License version 3 (GPLv3)' ], - 'blank_line_before_statement' => true, 'encoding' => true, 'function_typehint_space' => true, diff --git a/LICENSE.md b/LICENSE.md index 4dd4db4..9b28fbc 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,11 +1,8 @@ # License -Copyright (C) Pimcore GmbH +- Original Copyright (c) Pimcore GmbH (https://pimcore.com) +- Modification Copyright (c) OpenDXP (https://www.opendxp.ch) -This software is available under two different licenses: -* GNU General Public License version 3 (GPLv3) as Pimcore Community Edition -* Pimcore Commercial License (PCL) - -The default Pimcore license, without a valid Pimcore Commercial License agreement, is the Open-Source GPLv3 license. +This software is a fork of Pimcore Community Edition, originally licensed under the GNU General Public License version 3 (GPLv3). ## GNU General Public License version 3 (GPLv3) If you decide to choose the GPLv3 license, you must comply with the following terms: @@ -23,14 +20,12 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -## Pimcore Commercial License (PCL) -Alternatively, commercial and supported versions of the program - also known as -Commercial Distributions - must be used in accordance with the terms and conditions -contained in a separate written agreement between you and Pimcore GmbH. -For more information about the Pimcore Commercial License (PCL) please contact info@pimcore.com. +--- +This fork is named "OpenDXP | admin-bundle" and is not affiliated with Pimcore GmbH. +For the original Pimcore project, visit https://pimcore.com +--- -Please see also (files in this directory): -- [Licensing FAQ - license-faq.md](https://github.com/pimcore/pimcore/blob/master/license-faq.md) -- [GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - gpl-3.0.txt](gpl-3.0.txt) \ No newline at end of file +See also: +- [GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - gpl-3.0.txt](gpl-3.0.txt) diff --git a/README.md b/README.md index 69ffe1b..f295c70 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,19 @@ OpenDXP provides a very powerful integrated behavioral targeting and personalization engine. With this toolkit, it is possible to profile visitors based on their behavior, assign target groups to them and provide personalized content to these target groups. This makes it possible to show your customers contextual, relevant, and personalized content. +*** + +## Disclaimer + +> OpenDXP is a community-driven fork based on the Pimcore® Community Edition (GPLv3). +> OpenDXP is independent and maintained by its community and contributors. +> It is not affiliated with, endorsed by, or sponsored by Pimcore GmbH. +> Original credits: [Pimcore GmbH](https://www.pimcore.com) + +**OpenDXP Personalization Bundle is based on the Pimcore® Community Edition and remains licensed under GPLv3.** + +*** + Before starting with Personalization you should know about the following OpenDXP concepts: * [Target Group](./doc/01_Usage/01_Concepts.md#target-group) @@ -45,3 +58,32 @@ After reading everything about the base concepts, you are * [Action Handler](./doc/02_Development_Documentation/07_Action_Handlers.md) * [Targeting Storage](./doc/02_Development_Documentation/09_Targeting_Storage.md) * [Frontend JavaScript](./doc/02_Development_Documentation/11_Frontend_Javascript.md) + +*** + +## Upstream Origin & Version Transparency +This project is a fork of the [Pimcore personalization-bundle (03c5e04 / v1.1.1)](https://github.com/pimcore/personalization-bundle/tree/03c5e044acd2361ed4a4355ecac0a90fb37e4306), which is © Pimcore GmbH and licensed under GPLv3. + +## License +Licensed under the GNU General Public License v3.0 (GPLv3). For details, please see [LICENSE.md](LICENSE.md). + +## Copyright +© Pimcore GmbH +© 2025 OpenDXP Contributors — GPLv3 + +## Trademarks +Pimcore® is a registered [trademark](https://www.trademarkelite.com/europe/trademark/trademark-detail/009309841/PIMCORE) of Pimcore GmbH. +Any use of the Pimcore® mark in this repository is purely descriptive to identify the original upstream project. + +*** + +## Contact +For inquiries, suggestions, or contributions, feel free to reach us at contact@opendxp.ch. + +## About +OpenDXP is a community-driven project initiated by [DACHCOM.DIGITAL](https://www.dachcom.com/de-ch) (Rheineck, Switzerland) and maintained by its community and contributors. +OpenDXP is independent and not affiliated with Pimcore GmbH. + +The project’s purpose is to preserve and maintain a GPLv3‑licensed codebase for community use. + +It is **not positioned as a competitor** to products or services of Pimcore GmbH and does **not** purport to replace or supersede any Pimcore offering. diff --git a/SECURITY.md b/SECURITY.md index 15268a0..d5a52de 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,13 +10,13 @@ Please follow the [instructions](https://docs.github.com/en/code-security/securi ## Resolving Process -Every submitted security issue is handled with top priority by following these steps: +Every submitted security issue is handled with top priority by following these steps: 1. Confirm the vulnerability 2. Determine the severity 3. Contact reporter 4. Work on a patch 5. Get a CVE identification number (may be done by the reporter or a security service provider) -6. Patch reviewing +6. Patch reviewing 7. Tagging a new release for supported versions 8. Publish security announcement diff --git a/config/targeting.yaml b/config/targeting.yaml index ad3a854..a6559ee 100644 --- a/config/targeting.yaml +++ b/config/targeting.yaml @@ -7,7 +7,7 @@ services: # TARGETING STORAGE # # The TargetingStorageInterface alias will be set to whatever service_id is configured - # in pimcore_personalization.targeting.service_id. The services below are just the core storages, but + # in opendxp_personalization.targeting.service_id. The services below are just the core storages, but # it's possible to define a custom service which can be configured via service_id. # @@ -25,7 +25,7 @@ services: $saveHandler: '@OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\Cookie\JWTCookieSaveHandler' # Session Storage. - # If this is used, the pimcore_personalization.targeting.session.enabled entry + # If this is used, the opendxp_personalization.targeting.session.enabled entry # must be set to true to load the session configurator. OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\SessionStorage: ~ @@ -35,21 +35,21 @@ services: OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\DbStorage: ~ # Example for redis - # pimcore_personalization.targeting.storage.redis.connection: + # opendxp_personalization.targeting.storage.redis.connection: # class: Credis_Client - # factory: [Pimcore\Storage\Redis\ConnectionFactory, createConnection] + # factory: [OpenDxp\Storage\Redis\ConnectionFactory, createConnection] # arguments: # - { server: 127.0.0.1, database: 7 } - # Pimcore\Bundle\PersonalizationBundle\Targeting\Storage\RedisStorage: + # OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\RedisStorage: # arguments: - # $redis: '@pimcore_personalization.targeting.storage.redis.connection' + # $redis: '@opendxp_personalization.targeting.storage.redis.connection' # Example for fallback - # Pimcore\Bundle\PersonalizationBundle\Targeting\Storage\FallbackStorage: + # OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\FallbackStorage: # arguments: - # $primaryStorage: '@Pimcore\Bundle\PersonalizationBundle\Targeting\Storage\DbStorage' - # $fallbackStorage: '@Pimcore\Bundle\PersonalizationBundle\Targeting\Storage\CookieStorage' + # $primaryStorage: '@OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\DbStorage' + # $fallbackStorage: '@OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\CookieStorage' # diff --git a/doc/01_Usage/03_How_to_Personalize_Content/03_Visitor_Profiling.md b/doc/01_Usage/03_How_to_Personalize_Content/03_Visitor_Profiling.md index 5cd8c1a..eb1d03e 100644 --- a/doc/01_Usage/03_How_to_Personalize_Content/03_Visitor_Profiling.md +++ b/doc/01_Usage/03_How_to_Personalize_Content/03_Visitor_Profiling.md @@ -34,6 +34,6 @@ When assigning a target group via global targeting rules, also a assignment weig assignment count of the target group respectively. -For more fine-grained profiling possibilities see our [Customer Management Framework](https://github.com/pimcore/customer-data-framework/blob/master/README.md) -with its [Customer Segment functionality](https://github.com/pimcore/customer-data-framework/blob/master/doc/11_CustomerSegments.md) -and its [extensions to the OpenDxp targeting engine](https://github.com/pimcore/customer-data-framework/blob/master/doc/30_Personalization.md). +For more fine-grained profiling possibilities see our [Customer Management Framework](https://github.com/open-dxp/customer-data-framework/tree/1.x/README.md) +with its [Customer Segment functionality](https://github.com/open-dxp/customer-data-framework/tree/1.x/doc/11_CustomerSegments.md) +and its [extensions to the OpenDxp targeting engine](https://github.com/open-dxp/customer-data-framework/tree/1.x/doc/30_Personalization.md). diff --git a/doc/01_Usage/03_How_to_Personalize_Content/README.md b/doc/01_Usage/03_How_to_Personalize_Content/README.md index ec82450..8e7c46b 100644 --- a/doc/01_Usage/03_How_to_Personalize_Content/README.md +++ b/doc/01_Usage/03_How_to_Personalize_Content/README.md @@ -11,4 +11,4 @@ The typical workflow of personalizing content contains following steps: 3) [Create Personalized Content](./05_Create_Personalized_Content.md) 4) [Deliver Personalized Content](./07_Deliver_Personalized_Content_and_Debug.md) -For a live demo with a predefined rule set see our [Demo](https://demo.pimcore.fun). +For a live demo with a predefined rule set see our [Demo](https://demo.opendxp.io). diff --git a/doc/01_Usage/05_Examples/README.md b/doc/01_Usage/05_Examples/README.md index 28da5d1..71bbde2 100644 --- a/doc/01_Usage/05_Examples/README.md +++ b/doc/01_Usage/05_Examples/README.md @@ -3,7 +3,7 @@ The following pages show a few examples to better understand how things can be achieved with the OpenDxp targeting engine. -All mentioned rules here are configured and set up in our [demo](https://demo.pimcore.fun) and can be +All mentioned rules here are configured and set up in our [demo](https://demo.opendxp.io) and can be tested there. @@ -27,7 +27,7 @@ the target group is actually assigned to the visitors profile. ![Technical Guy Settings](../../img/user_docs/examples_technical-guy2.jpg) -For a real-life example please have a look at our [public demo instance](https://demo.pimcore.fun/en/More-Stuff/Demo-Features/Personalization). +For a real-life example please have a look at our [public demo instance](https://demo.opendxp.io/en/More-Stuff/Demo-Features/Personalization). ##### Global Targeting Rules with simple Conditions & Actions diff --git a/doc/02_Development_Documentation/03_Conditions.md b/doc/02_Development_Documentation/03_Conditions.md index d1d230d..9aa7543 100644 --- a/doc/02_Development_Documentation/03_Conditions.md +++ b/doc/02_Development_Documentation/03_Conditions.md @@ -5,17 +5,17 @@ to implement `match()` method which always returns a boolean. To implement a condition, you need to implement 2 parts: -* A PHP class implementing the [`ConditionInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/Condition/ConditionInterface.php). - Have a look at [existing implementations](https://github.com/pimcore/personalization-bundle/tree/main/src/Targeting/Condition) +* A PHP class implementing the [`ConditionInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Condition/ConditionInterface.php). + Have a look at [existing implementations](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Condition) to get an idea how to implement your own conditions. -* A frontend JS class defining the admin UI for your condition. You can have a look at [this bundle's conditions](https://github.com/pimcore/personalization-bundle/blob/main/public/js/settings/conditions.js) - for UI examples and at the [Customer Management Framework](https://github.com/pimcore/customer-data-framework/blob/master/src/Resources/public/js/pimcore/targeting/conditions.js) +* A frontend JS class defining the admin UI for your condition. You can have a look at [this bundle's conditions](https://github.com/open-dxp/personalization-bundle/tree/1.x/public/js/settings/conditions.js) + for UI examples and at the [Customer Management Framework](https://github.com/open-dxp/customer-data-framework/tree/1.x/src/Resources/public/js/opendxp/targeting/conditions.js) as example for a third-party integration. ## Implementing a Condition -As stated before, a condition needs to implement the [`ConditionInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/Condition/ConditionInterface.php). +As stated before, a condition needs to implement the [`ConditionInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Condition/ConditionInterface.php). The most important method in the interface is the `match()` method which receives the current `VisitorInfo` instance and is expected to return a boolean which indicates if the condition matches or not. @@ -88,7 +88,7 @@ opendxp_personalization: ### Building a Condition Instance -When an instance of your condition is build, by default the [`ConditionFactory`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/ConditionFactory.php) +When an instance of your condition is build, by default the [`ConditionFactory`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/ConditionFactory.php) will call the static `fromConfig()` method with the data configured in the admin UI. Avoid injecting any services or custom data into your condition and use the data provider system instead to add data to the `VisitorInfo`. However, if you need more control over how your condition is built you can either: @@ -102,19 +102,19 @@ you need more control over how your condition is built you can either: ## Condition Data -If your condition needs any outside data, implement the [`DataProviderDependentInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/DataProviderDependentInterface.php) +If your condition needs any outside data, implement the [`DataProviderDependentInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/DataProviderDependentInterface.php) and define a list of data provider keys which need to be set on the `VisitorInfo` before matching. We'll enhance our `TimeOfTheDay` -condition on the [Data Providers](./05_Data_Providers.md) chapter. For further examples, you can take a look at [existing core conditions](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/Condition). +condition on the [Data Providers](./05_Data_Providers.md) chapter. For further examples, you can take a look at [existing core conditions](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Condition). ## Condition Variables -An important part are [variable conditions](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/Condition/VariableConditionInterface.php) +An important part are [variable conditions](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Condition/VariableConditionInterface.php) which support the `session_with_variables` rule matching scope. A condition implementing this interface is expected to return an array of the variables which led to match the condition in the `getMatchedVariables()` method. This data will be used to determine if the rule was already applied with the exact same data. -You should implement this interface whenever possible. To get started, you can use the [`AbstractVariableCondition`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/Condition/AbstractVariableCondition.php) +You should implement this interface whenever possible. To get started, you can use the [`AbstractVariableCondition`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Condition/AbstractVariableCondition.php) which contains helper methods to collect variable data. Make sure you build your data in a deterministic way (e.g. using the same order of keys in an array structure or the same format when serializing data) as a hash of this data is used to compare it to previous evaluations in order to decide if a rule needs to be applied. @@ -159,8 +159,8 @@ To make your condition configurable, you need to create a JS class defining the so, create a class extending `opendxp.bundle.personalization.settings.condition.abstract` and register it to the system by calling `opendxp.bundle.personalization.settings.conditions.register()`. -Have a look at [this bundle's conditions](https://github.com/pimcore/personalization-bundle/blob/main/public/js/settings/conditions.js) -and the [Customer Management Framework](https://github.com/pimcore/customer-data-framework/blob/master/src/Resources/public/js/pimcore/targeting/conditions.js) +Have a look at [this bundle's conditions](https://github.com/open-dxp/personalization-bundle/tree/1.x/public/js/settings/conditions.js) +and the [Customer Management Framework](https://github.com/open-dxp/customer-data-framework/tree/1.x/src/Resources/public/js/opendxp/targeting/conditions.js) for examples. Start by adding a new JS file implementing the admin UI panel for your condition: @@ -223,7 +223,7 @@ Start by adding a new JS file implementing the admin UI panel for your condition }()); ``` -As soon as you [configured OpenDxp to load the newly created file](https://pimcore.com/docs/platform/Pimcore/Extending_Pimcore/Bundle_Developers_Guide/Loading_Service_Definitions) +As soon as you [configured OpenDxp to load the newly created file](https://docs.opendxp.io/docs/core-framework/Extending_OpenDxp/Bundle_Developers_Guide/Loading_Service_Definitions) you should see your new condition in the list of available conditions: ![Time of the Day Condition](../img/targeting_custom_condition_timeoftheday.png) diff --git a/doc/02_Development_Documentation/05_Data_Providers.md b/doc/02_Development_Documentation/05_Data_Providers.md index 3defccc..5282b36 100644 --- a/doc/02_Development_Documentation/05_Data_Providers.md +++ b/doc/02_Development_Documentation/05_Data_Providers.md @@ -1,14 +1,14 @@ # Data Providers -A data provider is a service implementing the [`DataProviderInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/DataProvider/DataProviderInterface.php). -Components (e.g. conditions) which implement the [`DataProviderDependentInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/DataProviderDependentInterface.php) +A data provider is a service implementing the [`DataProviderInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/DataProvider/DataProviderInterface.php). +Components (e.g. conditions) which implement the [`DataProviderDependentInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/DataProviderDependentInterface.php) can define a set of data providers they depend on, triggering the data provider to load its data before the component is used. A data provider does not directly return its value, but is expected to set it on the `VisitorInfo` instance instead. As best practice, the core data providers expose their storage key as constant. This constant is used to store and retrieve -the data from the `VisitorInfo` storage. As example: the [GeoIP](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/DataProvider/GeoIp.php) -data provider defines the [GeoIP::PROVIDER_KEY](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/DataProvider/GeoIp.php#L28) +the data from the `VisitorInfo` storage. As example: the [GeoIP](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/DataProvider/GeoIp.php) +data provider defines the [GeoIP::PROVIDER_KEY](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/DataProvider/GeoIp.php#L28) constant which is used when storing and retrieving the data. ## Implementing a Data Provider diff --git a/doc/02_Development_Documentation/07_Action_Handlers.md b/doc/02_Development_Documentation/07_Action_Handlers.md index 77faa8e..4b4fa5f 100644 --- a/doc/02_Development_Documentation/07_Action_Handlers.md +++ b/doc/02_Development_Documentation/07_Action_Handlers.md @@ -1,16 +1,16 @@ # Action Handlers After a targeting rule matched it executes one or more actions as configured in the admin UI. These actions are actually -executed by action handlers, which are services implementing the [`ActionHandlerInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/ActionHandler/ActionHandlerInterface.php). +executed by action handlers, which are services implementing the [`ActionHandlerInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/ActionHandler/ActionHandlerInterface.php). As with conditions, an action handler consists of 2 parts: -* A PHP class implementing the [`ActionHandlerInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/ActionHandler/ActionHandlerInterface.php). - Have a look at [existing implementations](https://github.com/pimcore/personalization-bundle/tree/main/src/Targeting/Targeting/ActionHandler) +* A PHP class implementing the [`ActionHandlerInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/ActionHandler/ActionHandlerInterface.php). + Have a look at [existing implementations](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Targeting/ActionHandler) to get an idea how to implement your own action handlers. * A frontend JS class defining the admin UI for your action handler as shown on the actions tab of a targeting rule. You - can have a look at [OpenDxp's core actions](https://github.com/pimcore/personalization-bundle/blob/main/public/js/settings/actions.js) - for UI examples and at the [Customer Management Framework](https://github.com/pimcore/customer-data-framework/blob/master/src/Resources/public/js/pimcore/targeting/actions.js) + can have a look at [OpenDxp's core actions](https://github.com/open-dxp/personalization-bundle/tree/1.x/public/js/settings/actions.js) + for UI examples and at the [Customer Management Framework](https://github.com/open-dxp/customer-data-framework/tree/1.x/src/Resources/public/js/opendxp/targeting/actions.js) as example for a third-party integration. @@ -92,7 +92,7 @@ If your action handler needs to apply data in a later stage of the request/respo the `VisitorInfo` which can be consumed later. Currently only the `response` action scope is defined which is executed in the `onKernelResponse` event, but more action scopes might be added in the future. -Have a look at the [CodeSnippet](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/ActionHandler/CodeSnippet.php) +Have a look at the [CodeSnippet](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/ActionHandler/CodeSnippet.php) action handler as example. It registers an action via `$visitorInfo->addAction()` and implements the `ResponseTransformingActionHandlerInterface::transformResponse()` which is called by the targeting engine for every action registered with the `response` scope. @@ -103,8 +103,8 @@ To make your action handler appear in the admin UI, you need to create and regis for your action. Create a class extending `opendxp.settings.targeting.action.abstract` and register it to the system by calling `opendxp.bundle.personalization.settings.actions.register()`. -Have a look at [this bundle's actions](https://github.com/pimcore/personalization-bundle/blob/main/public/js/settings/actions.js) -and the [Customer Management Framework](https://github.com/pimcore/customer-data-framework/blob/master/src/Resources/public/js/pimcore/targeting/actions.js) +Have a look at [this bundle's actions](https://github.com/open-dxp/personalization-bundle/tree/1.x/public/js/settings/actions.js) +and the [Customer Management Framework](https://github.com/open-dxp/customer-data-framework/tree/1.x/src/Resources/public/js/opendxp/targeting/actions.js) for examples. Start by adding a new JS file implementing the admin UI panel for your action: @@ -165,7 +165,7 @@ Start by adding a new JS file implementing the admin UI panel for your action: }()); ``` -As soon as you [configured OpenDxp to load the newly created file](https://pimcore.com/docs/platform/Pimcore/Extending_Pimcore/Bundle_Developers_Guide/Loading_Service_Definitions) +As soon as you [configured OpenDxp to load the newly created file](https://docs.opendxp.io/docs/core-framework/Extending_OpenDxp/Bundle_Developers_Guide/Loading_Service_Definitions) you should see your new action in the list of available actions: ![Log Action](../img/targeting_custom_action_log.png) diff --git a/doc/02_Development_Documentation/09_Targeting_Storage.md b/doc/02_Development_Documentation/09_Targeting_Storage.md index b0855ab..7653938 100644 --- a/doc/02_Development_Documentation/09_Targeting_Storage.md +++ b/doc/02_Development_Documentation/09_Targeting_Storage.md @@ -28,9 +28,9 @@ opendxp_personalization: ## Implement a Custom Targeting Storage -Basically, a targeting storage is a class implementing the [`TargetingStorageInterface`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/Storage/TargetingStorageInterface.php) +Basically, a targeting storage is a class implementing the [`TargetingStorageInterface`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Storage/TargetingStorageInterface.php) which is registered as service. Details how to handle data varies heavily on the underlying storage, but you can take the -[core storages](https://github.com/pimcore/personalization-bundle/tree/blob/main/src/Targeting/Storage) as starting point. +[core storages](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Storage) as starting point. ## Core Storage Implementations @@ -53,7 +53,7 @@ sure the cookie data isn't being tampered with. The cookie storage delegates the | `JWT` (default) | Stores cookie data as JWT signed JSON using the `kernel.secret` parameter to sign and verify the data. This is done to make sure the data can't be altered on the client side to inject malicious data into the targeting engine. | | | `JSON` | Stores cookie data as JSON string. | Use only for testing! | -To change the save handler, override the [service definition](https://github.com/pimcore/personalization-bundle/blob/main/config/targeting.yaml#L24) +To change the save handler, override the [service definition](https://github.com/open-dxp/personalization-bundle/tree/1.x/config/targeting.yaml#L24) and set your own handler.
@@ -96,7 +96,7 @@ Cons ### Redis Stores data in a redis DB. To use this storage, define a service using the storage implementation as class and add connection -details to the service definition. An example is shipped with the [core service definitions](https://github.com/pimcore/personalization-bundle/blob/main/config/targeting.yaml#L35). +details to the service definition. An example is shipped with the [core service definitions](https://github.com/open-dxp/personalization-bundle/tree/1.x/config/targeting.yaml#L35). Default session scope timeout: 30 minutes diff --git a/doc/02_Development_Documentation/11_Frontend_Javascript.md b/doc/02_Development_Documentation/11_Frontend_Javascript.md index f1a1d88..6141dd3 100644 --- a/doc/02_Development_Documentation/11_Frontend_Javascript.md +++ b/doc/02_Development_Documentation/11_Frontend_Javascript.md @@ -25,8 +25,8 @@ Make sure to use a unique visitor ID for each visitor! ## Change/extend the code snippet injected into the Response -The code which is injected into the response is generated by the [`TargetingCodeGenerator`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/Code/TargetingCodeGenerator.php) -which fires a [TargetingEvents::TARGETING_CODE](https://github.com/pimcore/personalization-bundle/blob/main/src/Event/TargetingEvents.php#L30) +The code which is injected into the response is generated by the [`TargetingCodeGenerator`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/Code/TargetingCodeGenerator.php) +which fires a [TargetingEvents::TARGETING_CODE](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Event/TargetingEvents.php#L30) event. This event can be used to influence data and the used template which is used to render the code snippet: @@ -90,7 +90,7 @@ call `$visitorInfo->addFrontendDataProvider()` during the matching process to in a specific provider. These frontend data providers need to be implemented and registered to the frontend JS and are expected to deliver their data to the backend in some way (e.g. by storing data in a cookie or by sending it through an async request). -Currently, this feature is only sparsely used, but the [`GeoLocation`](https://github.com/pimcore/personalization-bundle/blob/main/src/Targeting/DataProvider/GeoLocation.php) +Currently, this feature is only sparsely used, but the [`GeoLocation`](https://github.com/open-dxp/personalization-bundle/tree/1.x/src/Targeting/DataProvider/GeoLocation.php) data provider which can read the visitor location from browser geolocation data informs the frontend that it needs data from the `geolocation` frontend data provider. This information is added to the browser response, triggering the `targeting.js` to execute this frontend data provider. The data provider in turn stores its data as cookie which is consumed by the (backend) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1339890..9a7d097 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,2 +1,13 @@ parameters: - ignoreErrors: \ No newline at end of file + ignoreErrors: + - identifier: missingType.iterableValue + - identifier: missingType.generics + + - + path: src/Targeting/Document/DocumentTargetingConfigurator.php + identifier: varTag.nativeType + count: 1 + - + path: src/Model/Document/Targeting/TargetingDocumentDaoTrait.php + identifier: varTag.nativeType + count: 4 diff --git a/phpstan.neon b/phpstan.neon index cc80590..2adb0bf 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -10,9 +10,7 @@ parameters: - src/Tests/* ignoreErrors: - '~^Unsafe usage of new static\(\)~' - checkGenericClassInNonGenericObjectType: false - checkMissingIterableValueType: false includes: - vendor/phpstan/phpstan-symfony/extension.neon - - phpstan-baseline.neon \ No newline at end of file + - phpstan-baseline.neon diff --git a/public/js/settings/targetingtoolbar.js b/public/js/settings/targetingtoolbar.js index 2539a05..eebf239 100644 --- a/public/js/settings/targetingtoolbar.js +++ b/public/js/settings/targetingtoolbar.js @@ -52,7 +52,7 @@ opendxp.bundle.personalization.settings.targetingtoolbar = Class.create({ bodyStyle: "padding: 20px; font-size: 14px;", html: t("targeting_toolbar_browser_note", null, { - targetingLink: 'https://pimcore.com/docs/pimcore/11.0/Development_Documentation/Tools_and_Features/Targeting_and_Personalization/index.html#page_Debugging-Targeting-Data' + targetingLink: 'https://docs.opendxp.io/docs/core-framework/Development_Documentation/Tools_and_Features/Targeting_and_Personalization/index.html#page_Debugging-Targeting-Data' }) }], buttons: buttons diff --git a/src/Controller/Admin/TargetingController.php b/src/Controller/Admin/TargetingController.php index d0d3eb1..e9331e6 100644 --- a/src/Controller/Admin/TargetingController.php +++ b/src/Controller/Admin/TargetingController.php @@ -161,7 +161,6 @@ public function targetGroupListAction(Request $request): JsonResponse { $targetGroups = []; - /** @var TargetGroup\Listing|TargetGroup\Listing\Dao $list */ $list = new TargetGroup\Listing(); if ($request->get('add-default')) { @@ -188,7 +187,6 @@ public function targetGroupListAction(Request $request): JsonResponse #[Route('/target-group/add', name: 'opendxp_bundle_personalization_targeting_targetgroupadd', methods: ['POST'])] public function targetGroupAddAction(Request $request, CoreCacheHandler $cache): JsonResponse { - /** @var TargetGroup|TargetGroup\Dao $targetGroup */ $targetGroup = new TargetGroup(); $targetGroup->setName($this->correctName($request->get('name'))); $targetGroup->save(); diff --git a/src/Debug/Traits/StopwatchTrait.php b/src/Debug/Traits/StopwatchTrait.php index 6e81d50..8411d1e 100644 --- a/src/Debug/Traits/StopwatchTrait.php +++ b/src/Debug/Traits/StopwatchTrait.php @@ -35,7 +35,7 @@ trait StopwatchTrait { private ?Stopwatch $stopwatch = null; - public function setStopwatch(Stopwatch $stopwatch = null): void + public function setStopwatch(?Stopwatch $stopwatch = null): void { $this->stopwatch = $stopwatch; } diff --git a/src/Document/Newsletter/AddressSourceAdapter/DefaultAdapter.php b/src/Document/Newsletter/AddressSourceAdapter/DefaultAdapter.php index 73cbce2..522cffc 100644 --- a/src/Document/Newsletter/AddressSourceAdapter/DefaultAdapter.php +++ b/src/Document/Newsletter/AddressSourceAdapter/DefaultAdapter.php @@ -37,7 +37,7 @@ public function __construct(array $params) parent::__construct($params); } - protected function getListing(): ?Listing + protected function getListing(): Listing { if (empty($this->list)) { $objectList = '\\OpenDxp\\Model\\DataObject\\' . ucfirst($this->class) . '\\Listing'; diff --git a/src/Event/TargetGroupEvents.php b/src/Event/TargetGroupEvents.php index 64b14c8..7186e8a 100644 --- a/src/Event/TargetGroupEvents.php +++ b/src/Event/TargetGroupEvents.php @@ -19,21 +19,21 @@ final class TargetGroupEvents { /** - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Model\TargetGroupEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Model\TargetGroupEvent") * * @var string */ const POST_ADD = 'opendxp.targetgroup.postAdd'; /** - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Model\TargetGroupEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Model\TargetGroupEvent") * * @var string */ const POST_UPDATE = 'opendxp.targetgroup.postUpdate'; /** - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Model\TargetGroupEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Model\TargetGroupEvent") * * @var string */ diff --git a/src/Event/TargetingEvents.php b/src/Event/TargetingEvents.php index f55df39..3623f32 100644 --- a/src/Event/TargetingEvents.php +++ b/src/Event/TargetingEvents.php @@ -23,7 +23,7 @@ final class TargetingEvents * Fired when the targeting code is rendered. Allows to add data to the targeting * code or to change the template completely. * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\TargetingCodeEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\TargetingCodeEvent") * * @var string */ @@ -33,7 +33,7 @@ final class TargetingEvents * Fired when the VisitorInfo object was built for a request before * any matching and action handling is applied. * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\TargetingEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\TargetingEvent") * * @var string */ @@ -42,7 +42,7 @@ final class TargetingEvents /** * Fired after all targeting rules were matched and applied * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\TargetingEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\TargetingEvent") * * @var string */ @@ -51,7 +51,7 @@ final class TargetingEvents /** * Fired when a rule matches before any actions are applied * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\TargetingRuleEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\TargetingRuleEvent") * * @var string */ @@ -60,7 +60,7 @@ final class TargetingEvents /** * Fired when a rule matches after all actions were applied * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\TargetingRuleEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\TargetingRuleEvent") * * @var string */ @@ -71,7 +71,7 @@ final class TargetingEvents * build the condition in a custom manner instead of relying on the * default factory. * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\BuildConditionEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\BuildConditionEvent") * * @var string */ @@ -81,7 +81,7 @@ final class TargetingEvents * Fired when a target group which is configured on document settings * is assigned to a visitor info. * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\AssignDocumentTargetGroupEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\AssignDocumentTargetGroupEvent") * * @var string */ @@ -101,7 +101,7 @@ final class TargetingEvents /** * Fired before the targeting debug toolbar is rendered * - * @Event("Pimcore\Bundle\PersonalizationBundle\Event\Targeting\RenderToolbarEvent") + * @Event("OpenDxp\Bundle\PersonalizationBundle\Event\Targeting\RenderToolbarEvent") * * @var string */ diff --git a/src/Model/Document/Page.php b/src/Model/Document/Page.php index 6487574..35499e7 100644 --- a/src/Model/Document/Page.php +++ b/src/Model/Document/Page.php @@ -21,7 +21,7 @@ use OpenDxp\Bundle\PersonalizationBundle\Model\Tool\Targeting\TargetGroup; /** - * @method \Pimcore\Bundle\PersonalizationBundle\Model\Document\Page\Dao getDao() + * @method \OpenDxp\Bundle\PersonalizationBundle\Model\Document\Page\Dao getDao() */ class Page extends \OpenDxp\Model\Document\Page implements TargetingDocumentInterface { @@ -95,19 +95,18 @@ public function setTargetGroups(array $targetGroups): void public function getTargetGroups(): array { $ids = explode(',', $this->targetGroupIds); - - $targetGroups = array_map(function ($id) { + $targetGroups = array_map(static function ($id) { $id = trim($id); if (!empty($id)) { $targetGroup = TargetGroup::getById((int)$id); - if ($targetGroup) { + if ($targetGroup instanceof TargetGroup) { return $targetGroup; } } - }, $ids); - $targetGroups = array_filter($targetGroups); + return null; + }, $ids); - return $targetGroups; + return array_filter($targetGroups, static fn (?TargetGroup $targetGroup) => $targetGroup !== null); } } diff --git a/src/Model/Document/Page/Dao.php b/src/Model/Document/Page/Dao.php index c494544..6f8fce0 100644 --- a/src/Model/Document/Page/Dao.php +++ b/src/Model/Document/Page/Dao.php @@ -22,7 +22,7 @@ /** * @internal * - * @property \Pimcore\Bundle\PersonalizationBundle\Model\Document\Page $model + * @property \OpenDxp\Bundle\PersonalizationBundle\Model\Document\Page $model */ class Dao extends Model\Document\Page\Dao implements TargetingDocumentDaoInterface { diff --git a/src/Model/Document/Snippet.php b/src/Model/Document/Snippet.php index a8d7e27..93991c1 100644 --- a/src/Model/Document/Snippet.php +++ b/src/Model/Document/Snippet.php @@ -20,7 +20,7 @@ use OpenDxp\Bundle\PersonalizationBundle\Model\Document\Traits\TargetDocumentTrait; /** - * @method \Pimcore\Bundle\PersonalizationBundle\Model\Document\Snippet\Dao getDao() + * @method \OpenDxp\Bundle\PersonalizationBundle\Model\Document\Snippet\Dao getDao() */ class Snippet extends \OpenDxp\Model\Document\Snippet implements TargetingDocumentInterface { diff --git a/src/Model/Document/Snippet/Dao.php b/src/Model/Document/Snippet/Dao.php index 429f497..961a74a 100644 --- a/src/Model/Document/Snippet/Dao.php +++ b/src/Model/Document/Snippet/Dao.php @@ -22,7 +22,7 @@ /** * @internal * - * @property \Pimcore\Bundle\PersonalizationBundle\Model\Document\Snippet $model + * @property \OpenDxp\Bundle\PersonalizationBundle\Model\Document\Snippet $model */ class Dao extends Model\Document\Snippet\Dao implements TargetingDocumentDaoInterface { diff --git a/src/Model/Document/Targeting/TargetingDocumentInterface.php b/src/Model/Document/Targeting/TargetingDocumentInterface.php index 413f803..14f6c30 100644 --- a/src/Model/Document/Targeting/TargetingDocumentInterface.php +++ b/src/Model/Document/Targeting/TargetingDocumentInterface.php @@ -32,7 +32,7 @@ interface TargetingDocumentInterface extends ElementInterface * * */ - public function getTargetGroupEditablePrefix(int $targetGroupId = null): string; + public function getTargetGroupEditablePrefix(?int $targetGroupId = null): string; /** * Adds target group prefix to element name if it is not already prefixed and @@ -46,7 +46,7 @@ public function getTargetGroupEditableName(string $name): string; * Sets the target group to use * */ - public function setUseTargetGroup(int $useTargetGroup = null): void; + public function setUseTargetGroup(?int $useTargetGroup = null): void; /** * Returns the target group to use diff --git a/src/Model/Document/Traits/TargetDocumentTrait.php b/src/Model/Document/Traits/TargetDocumentTrait.php index 12d281b..b63ba01 100644 --- a/src/Model/Document/Traits/TargetDocumentTrait.php +++ b/src/Model/Document/Traits/TargetDocumentTrait.php @@ -31,7 +31,7 @@ trait TargetDocumentTrait */ private ?int $useTargetGroup = null; - public function setUseTargetGroup(int $useTargetGroup = null): void + public function setUseTargetGroup(?int $useTargetGroup = null): void { $this->useTargetGroup = $useTargetGroup; } @@ -41,7 +41,7 @@ public function getUseTargetGroup(): ?int return $this->useTargetGroup; } - public function getTargetGroupEditablePrefix(int $targetGroupId = null): string + public function getTargetGroupEditablePrefix(?int $targetGroupId = null): string { $prefix = ''; diff --git a/src/Model/Tool/Targeting/Rule/Dao.php b/src/Model/Tool/Targeting/Rule/Dao.php index 154c2ab..eb86d39 100644 --- a/src/Model/Tool/Targeting/Rule/Dao.php +++ b/src/Model/Tool/Targeting/Rule/Dao.php @@ -30,7 +30,7 @@ class Dao extends Model\Dao\AbstractDao * * @throws Model\Exception\NotFoundException */ - public function getById(int $id = null): void + public function getById(?int $id = null): void { if ($id != null) { $this->model->setId($id); @@ -52,7 +52,7 @@ public function getById(int $id = null): void * * @throws \Exception */ - public function getByName(string $name = null): void + public function getByName(?string $name = null): void { if ($name != null) { $this->model->setName($name); diff --git a/src/Model/Tool/Targeting/TargetGroup/Dao.php b/src/Model/Tool/Targeting/TargetGroup/Dao.php index 8f9f047..33d59ef 100644 --- a/src/Model/Tool/Targeting/TargetGroup/Dao.php +++ b/src/Model/Tool/Targeting/TargetGroup/Dao.php @@ -30,7 +30,7 @@ class Dao extends Model\Dao\AbstractDao * * @throws Model\Exception\NotFoundException */ - public function getById(int $id = null): void + public function getById(?int $id = null): void { if (null !== $id) { $this->model->setId($id); @@ -51,7 +51,7 @@ public function getById(int $id = null): void * * @throws Model\Exception\NotFoundException */ - public function getByName(string $name = null): void + public function getByName(?string $name = null): void { if (null !== $name) { $this->model->setName($name); diff --git a/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroup.php b/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroup.php index b1b8e1a..d9acd0d 100644 --- a/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroup.php +++ b/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroup.php @@ -31,7 +31,7 @@ class TargetGroup extends Model\DataObject\ClassDefinition\Data\Select */ public function getDataFromResource( mixed $data, - Dataobject\Concrete $object = null, + ?Dataobject\Concrete $object = null, array $params = [] ): null|string|int { if (!empty($data)) { @@ -52,7 +52,7 @@ public function getDataFromResource( */ public function getDataForResource( mixed $data, - DataObject\Concrete $object = null, + ?DataObject\Concrete $object = null, array $params = [] ): null|string|int { $this->init(); @@ -72,7 +72,6 @@ public function getDataForResource( */ public function configureOptions(): void { - /** @var Tool\Targeting\TargetGroup\Listing|Tool\Targeting\TargetGroup\Listing\Dao $list */ $list = new Tool\Targeting\TargetGroup\Listing(); $list->setOrder('asc'); $list->setOrderKey('name'); diff --git a/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroupMultiselect.php b/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroupMultiselect.php index 5aed674..4b283d5 100644 --- a/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroupMultiselect.php +++ b/src/OpenDxp/Model/DataObject/ClassDefinition/Data/TargetGroupMultiselect.php @@ -28,7 +28,6 @@ class TargetGroupMultiselect extends Model\DataObject\ClassDefinition\Data\Multi */ public function configureOptions(): void { - /** @var Tool\Targeting\TargetGroup\Listing|Tool\Targeting\TargetGroup\Listing\Dao $list */ $list = new Tool\Targeting\TargetGroup\Listing(); $list->setOrder('asc'); $list->setOrderKey('name'); diff --git a/src/OpenDxpPersonalizationBundle.php b/src/OpenDxpPersonalizationBundle.php index 722f198..23e616e 100644 --- a/src/OpenDxpPersonalizationBundle.php +++ b/src/OpenDxpPersonalizationBundle.php @@ -38,7 +38,7 @@ class OpenDxpPersonalizationBundle extends AbstractOpenDxpBundle implements Open /*public function getComposerPackageName(): string { - return 'pimcore/personalization-bundle'; + return 'open-dxp/personalization-bundle'; }*/ public function getContainerExtension(): ?ExtensionInterface diff --git a/src/Targeting/ActionHandler/ActionHandlerInterface.php b/src/Targeting/ActionHandler/ActionHandlerInterface.php index 904de4b..a006dff 100644 --- a/src/Targeting/ActionHandler/ActionHandlerInterface.php +++ b/src/Targeting/ActionHandler/ActionHandlerInterface.php @@ -25,5 +25,5 @@ interface ActionHandlerInterface /** * Applies the action */ - public function apply(VisitorInfo $visitorInfo, array $action, Rule $rule = null): void; + public function apply(VisitorInfo $visitorInfo, array $action, ?Rule $rule = null): void; } diff --git a/src/Targeting/ActionHandler/AssignTargetGroup.php b/src/Targeting/ActionHandler/AssignTargetGroup.php index 8b9b224..b1230e6 100644 --- a/src/Targeting/ActionHandler/AssignTargetGroup.php +++ b/src/Targeting/ActionHandler/AssignTargetGroup.php @@ -31,7 +31,7 @@ public function __construct( ) { } - public function apply(VisitorInfo $visitorInfo, array $action, Rule $rule = null): void + public function apply(VisitorInfo $visitorInfo, array $action, ?Rule $rule = null): void { $targetGroupId = $action['targetGroup'] ?? null; if (!$targetGroupId) { diff --git a/src/Targeting/ActionHandler/CodeSnippet.php b/src/Targeting/ActionHandler/CodeSnippet.php index 753cb21..9d046e3 100644 --- a/src/Targeting/ActionHandler/CodeSnippet.php +++ b/src/Targeting/ActionHandler/CodeSnippet.php @@ -31,7 +31,7 @@ public function __construct(CodeInjector $codeInjector) $this->codeInjector = $codeInjector; } - public function apply(VisitorInfo $visitorInfo, array $action, Rule $rule = null): void + public function apply(VisitorInfo $visitorInfo, array $action, ?Rule $rule = null): void { $code = $action['code'] ?? ''; $selector = $action['selector'] ?? ''; diff --git a/src/Targeting/ActionHandler/DelegatingActionHandler.php b/src/Targeting/ActionHandler/DelegatingActionHandler.php index bb4beaf..fb74d9e 100644 --- a/src/Targeting/ActionHandler/DelegatingActionHandler.php +++ b/src/Targeting/ActionHandler/DelegatingActionHandler.php @@ -37,7 +37,7 @@ public function __construct( $this->dataLoader = $dataLoader; } - public function apply(VisitorInfo $visitorInfo, array $action, Rule $rule = null): void + public function apply(VisitorInfo $visitorInfo, array $action, ?Rule $rule = null): void { /** @var string $type */ $type = $action['type'] ?? null; diff --git a/src/Targeting/ActionHandler/Redirect.php b/src/Targeting/ActionHandler/Redirect.php index 963959a..b276383 100644 --- a/src/Targeting/ActionHandler/Redirect.php +++ b/src/Targeting/ActionHandler/Redirect.php @@ -24,7 +24,7 @@ class Redirect implements ActionHandlerInterface { - public function apply(VisitorInfo $visitorInfo, array $action, Rule $rule = null): void + public function apply(VisitorInfo $visitorInfo, array $action, ?Rule $rule = null): void { $url = $action['url'] ?? null; if (!$url) { diff --git a/src/Targeting/Condition/Browser.php b/src/Targeting/Condition/Browser.php index b6a2a8d..243dbff 100644 --- a/src/Targeting/Condition/Browser.php +++ b/src/Targeting/Condition/Browser.php @@ -25,7 +25,7 @@ class Browser extends AbstractVariableCondition implements DataProviderDependent { private ?string $browser = null; - public function __construct(string $browser = null) + public function __construct(?string $browser = null) { $this->browser = $browser; } diff --git a/src/Targeting/Condition/Country.php b/src/Targeting/Condition/Country.php index b76d034..9681b4f 100644 --- a/src/Targeting/Condition/Country.php +++ b/src/Targeting/Condition/Country.php @@ -25,7 +25,7 @@ class Country extends AbstractVariableCondition implements DataProviderDependent { private ?string $country = null; - public function __construct(string $country = null) + public function __construct(?string $country = null) { $this->country = $country; } diff --git a/src/Targeting/Condition/GeoPoint.php b/src/Targeting/Condition/GeoPoint.php index 4fec82a..684831a 100644 --- a/src/Targeting/Condition/GeoPoint.php +++ b/src/Targeting/Condition/GeoPoint.php @@ -32,7 +32,7 @@ class GeoPoint extends AbstractVariableCondition implements DataProviderDependen private ?int $radius = null; - public function __construct(float $latitude = null, float $longitude = null, int $radius = null) + public function __construct(?float $latitude = null, ?float $longitude = null, ?int $radius = null) { $this->latitude = $latitude; $this->longitude = $longitude; diff --git a/src/Targeting/Condition/HardwarePlatform.php b/src/Targeting/Condition/HardwarePlatform.php index f029591..4a5090f 100644 --- a/src/Targeting/Condition/HardwarePlatform.php +++ b/src/Targeting/Condition/HardwarePlatform.php @@ -36,7 +36,7 @@ class HardwarePlatform extends AbstractVariableCondition implements DataProvider 'feature phone' => 'mobile', ]; - public function __construct(string $platform = null) + public function __construct(?string $platform = null) { $this->platform = $platform; } @@ -83,7 +83,7 @@ public function match(VisitorInfo $visitorInfo): bool return false; } - private function matchesPlatform(string $platform = null): bool + private function matchesPlatform(?string $platform = null): bool { if (empty($platform)) { return false; diff --git a/src/Targeting/Condition/Language.php b/src/Targeting/Condition/Language.php index 5cd78d4..290e08e 100644 --- a/src/Targeting/Condition/Language.php +++ b/src/Targeting/Condition/Language.php @@ -25,7 +25,7 @@ class Language extends AbstractVariableCondition implements ConditionInterface { private ?string $language = null; - public function __construct(string $language = null) + public function __construct(?string $language = null) { $this->language = $language; } diff --git a/src/Targeting/Condition/OperatingSystem.php b/src/Targeting/Condition/OperatingSystem.php index fa3d464..9d48e1a 100644 --- a/src/Targeting/Condition/OperatingSystem.php +++ b/src/Targeting/Condition/OperatingSystem.php @@ -37,7 +37,7 @@ class OperatingSystem extends AbstractVariableCondition implements DataProviderD 'IOS' => 'ios', ]; - public function __construct(string $system = null) + public function __construct(?string $system = null) { $this->system = $system; } @@ -84,7 +84,7 @@ public function match(VisitorInfo $visitorInfo): bool return false; } - private function matchesOperatingSystem(string $os = null): bool + private function matchesOperatingSystem(?string $os = null): bool { if (empty($os)) { return false; diff --git a/src/Targeting/Condition/ReferringSite.php b/src/Targeting/Condition/ReferringSite.php index 71508d3..6d79dea 100644 --- a/src/Targeting/Condition/ReferringSite.php +++ b/src/Targeting/Condition/ReferringSite.php @@ -23,7 +23,7 @@ class ReferringSite extends AbstractVariableCondition implements ConditionInterf { private ?string $pattern = null; - public function __construct(string $pattern = null) + public function __construct(?string $pattern = null) { $this->pattern = $pattern; } diff --git a/src/Targeting/Condition/SearchEngine.php b/src/Targeting/Condition/SearchEngine.php index c76afa9..9414dd9 100644 --- a/src/Targeting/Condition/SearchEngine.php +++ b/src/Targeting/Condition/SearchEngine.php @@ -28,7 +28,7 @@ class SearchEngine extends AbstractVariableCondition implements ConditionInterfa private array $validEngines = ['google', 'bing', 'yahoo']; - public function __construct(string $engine = null) + public function __construct(?string $engine = null) { if (!empty($engine)) { $validEngines = array_merge(['all'], $this->validEngines); diff --git a/src/Targeting/Condition/Url.php b/src/Targeting/Condition/Url.php index f71ed5e..d4e3070 100644 --- a/src/Targeting/Condition/Url.php +++ b/src/Targeting/Condition/Url.php @@ -23,7 +23,7 @@ class Url extends AbstractVariableCondition implements ConditionInterface { private ?string $pattern = null; - public function __construct(string $pattern = null) + public function __construct(?string $pattern = null) { $this->pattern = $pattern; } diff --git a/src/Targeting/ConditionMatcher/ExpressionBuilder.php b/src/Targeting/ConditionMatcher/ExpressionBuilder.php index a882539..076edee 100644 --- a/src/Targeting/ConditionMatcher/ExpressionBuilder.php +++ b/src/Targeting/ConditionMatcher/ExpressionBuilder.php @@ -55,7 +55,7 @@ public function addCondition(array $config, bool $result): void } } - private function normalizeOperator(string $operator = null): string + private function normalizeOperator(?string $operator = null): string { if (empty($operator)) { $operator = 'and'; diff --git a/src/Targeting/DataProvider/Device.php b/src/Targeting/DataProvider/Device.php index 8d72f47..d6adf12 100644 --- a/src/Targeting/DataProvider/Device.php +++ b/src/Targeting/DataProvider/Device.php @@ -45,7 +45,7 @@ class Device implements DataProviderInterface * The cache pool which is passed to the DeviceDetector * */ - private TagAwareAdapterInterface $cachePool; + private ?TagAwareAdapterInterface $cachePool = null; public function __construct(LoggerInterface $logger) { @@ -79,7 +79,7 @@ public function load(VisitorInfo $visitorInfo): void ); } - private function handleOverrides(Request $request, array $result = null): ?array + private function handleOverrides(Request $request, ?array $result = null): ?array { $overrides = OverrideAttributeResolver::getOverrideValue($request, 'device'); if (empty($overrides)) { diff --git a/src/Targeting/DataProvider/GeoIp.php b/src/Targeting/DataProvider/GeoIp.php index 934cde3..c1b18ce 100644 --- a/src/Targeting/DataProvider/GeoIp.php +++ b/src/Targeting/DataProvider/GeoIp.php @@ -81,7 +81,7 @@ public function loadData(VisitorInfo $visitorInfo): ?array return $result; } - private function handleOverrides(Request $request, array $result = null): ?array + private function handleOverrides(Request $request, ?array $result = null): ?array { $overrides = OverrideAttributeResolver::getOverrideValue($request, 'location'); if (empty($overrides)) { diff --git a/src/Targeting/DataProvider/GeoLocation.php b/src/Targeting/DataProvider/GeoLocation.php index a899d03..2415594 100644 --- a/src/Targeting/DataProvider/GeoLocation.php +++ b/src/Targeting/DataProvider/GeoLocation.php @@ -56,7 +56,7 @@ public function load(VisitorInfo $visitorInfo): void ); } - private function handleOverrides(Request $request, GeoLocationModel $location = null): ?GeoLocationModel + private function handleOverrides(Request $request, ?GeoLocationModel $location = null): ?GeoLocationModel { $overrides = OverrideAttributeResolver::getOverrideValue($request, 'location'); if (empty($overrides)) { diff --git a/src/Targeting/Debug/Override/DocumentTargetingOverrideHandler.php b/src/Targeting/Debug/Override/DocumentTargetingOverrideHandler.php index 43d7b21..e3b2882 100644 --- a/src/Targeting/Debug/Override/DocumentTargetingOverrideHandler.php +++ b/src/Targeting/Debug/Override/DocumentTargetingOverrideHandler.php @@ -42,10 +42,10 @@ public function buildOverrideForm(FormBuilderInterface $form, Request $request): 'choice_loader' => new CallbackChoiceLoader(function () { return (new TargetGroup\Listing())->load(); }), - 'choice_value' => function (TargetGroup $targetGroup = null) { + 'choice_value' => function (?TargetGroup $targetGroup = null) { return $targetGroup ? $targetGroup->getId() : ''; }, - 'choice_label' => function (TargetGroup $targetGroup = null, $key, $index) { + 'choice_label' => function (?TargetGroup $targetGroup = null) { return $targetGroup ? $targetGroup->getName() : ''; }, ]); diff --git a/src/Targeting/Debug/TargetingDataCollector.php b/src/Targeting/Debug/TargetingDataCollector.php index 4eb70e9..0691356 100644 --- a/src/Targeting/Debug/TargetingDataCollector.php +++ b/src/Targeting/Debug/TargetingDataCollector.php @@ -143,7 +143,7 @@ public function collectTargetGroups(VisitorInfo $visitorInfo): array return $targetGroups; } - public function collectDocumentTargetGroup(Document $document = null): ?array + public function collectDocumentTargetGroup(?Document $document = null): ?array { if (!$document instanceof TargetingDocumentInterface) { return null; diff --git a/src/Targeting/Document/DocumentTargetingConfigurator.php b/src/Targeting/Document/DocumentTargetingConfigurator.php index da413e2..46d6260 100644 --- a/src/Targeting/Document/DocumentTargetingConfigurator.php +++ b/src/Targeting/Document/DocumentTargetingConfigurator.php @@ -108,7 +108,7 @@ private function isConfiguredByAdminParam(TargetingDocumentInterface $document): return false; } - // ptg = pimcore target group = will be used from the admin UI to show target specific data + // ptg = opendxp target group = will be used from the admin UI to show target specific data // in editmode if ($ptg = $request->get('_ptg')) { $targetGroup = TargetGroup::getById((int)$ptg); @@ -217,7 +217,7 @@ public function getTargetGroupsForDocument(Document $document): array return $targetGroups; } - public function setOverrideTargetGroup(TargetGroup $overrideTargetGroup = null): void + public function setOverrideTargetGroup(?TargetGroup $overrideTargetGroup = null): void { $this->overrideTargetGroup = $overrideTargetGroup; } diff --git a/src/Targeting/EventListener/ToolbarListener.php b/src/Targeting/EventListener/ToolbarListener.php index fa7a9a1..48c2432 100644 --- a/src/Targeting/EventListener/ToolbarListener.php +++ b/src/Targeting/EventListener/ToolbarListener.php @@ -159,7 +159,7 @@ private function requestCanDebug(Request $request): bool return true; } - private function collectTemplateData(VisitorInfo $visitorInfo, Document $document = null): array + private function collectTemplateData(VisitorInfo $visitorInfo, ?Document $document = null): array { $token = substr(hash('sha256', uniqid((string)mt_rand(), true)), 0, 6); diff --git a/src/Targeting/Model/GeoLocation.php b/src/Targeting/Model/GeoLocation.php index d663041..0972b94 100644 --- a/src/Targeting/Model/GeoLocation.php +++ b/src/Targeting/Model/GeoLocation.php @@ -25,7 +25,7 @@ class GeoLocation private ?float $altitude = null; - public function __construct(float $latitude, float $longitude, float $altitude = null) + public function __construct(float $latitude, float $longitude, ?float $altitude = null) { if (!($latitude >= -90 && $latitude <= 90)) { throw new \InvalidArgumentException('Latitude is invalid'); @@ -40,7 +40,7 @@ public function __construct(float $latitude, float $longitude, float $altitude = $this->altitude = $altitude; } - public static function build(float $latitude, float $longitude, float $altitude = null): self + public static function build(float $latitude, float $longitude, ?float $altitude = null): self { return new self( (float)$latitude, diff --git a/src/Targeting/Model/VisitorInfo.php b/src/Targeting/Model/VisitorInfo.php index 97db8c4..5a1a868 100644 --- a/src/Targeting/Model/VisitorInfo.php +++ b/src/Targeting/Model/VisitorInfo.php @@ -76,7 +76,7 @@ class VisitorInfo implements \IteratorAggregate private ?Response $response = null; - public function __construct(Request $request, string $visitorId = null, string $sessionId = null) + public function __construct(Request $request, ?string $visitorId = null, ?string $sessionId = null) { $this->request = $request; $this->visitorId = $visitorId; diff --git a/src/Targeting/Storage/Cookie/JWTCookieSaveHandler.php b/src/Targeting/Storage/Cookie/JWTCookieSaveHandler.php index fc32648..4671492 100644 --- a/src/Targeting/Storage/Cookie/JWTCookieSaveHandler.php +++ b/src/Targeting/Storage/Cookie/JWTCookieSaveHandler.php @@ -41,8 +41,8 @@ class JWTCookieSaveHandler extends AbstractCookieSaveHandler public function __construct( string $secret, array $options = [], - Signer $signer = null, - LoggerInterface $logger = null + ?Signer $signer = null, + ?LoggerInterface $logger = null ) { parent::__construct($options); diff --git a/src/Targeting/Storage/CookieStorage.php b/src/Targeting/Storage/CookieStorage.php index 6d15516..be51265 100644 --- a/src/Targeting/Storage/CookieStorage.php +++ b/src/Targeting/Storage/CookieStorage.php @@ -17,6 +17,7 @@ namespace OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage; +use DateTimeInterface; use OpenDxp\Bundle\PersonalizationBundle\Targeting\Model\VisitorInfo; use OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\Cookie\CookieSaveHandlerInterface; use OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\Traits\TimestampsTrait; @@ -34,13 +35,13 @@ class CookieStorage implements TargetingStorageInterface { use TimestampsTrait; - const COOKIE_NAME_SESSION = '_pc_tss'; // tss = targeting session storage + const string COOKIE_NAME_SESSION = '_pc_tss'; // tss = targeting session storage - const COOKIE_NAME_VISITOR = '_pc_tvs'; // tvs = targeting visitor storage + const string COOKIE_NAME_VISITOR = '_pc_tvs'; // tvs = targeting visitor storage - const STORAGE_KEY_CREATED_AT = '_c'; + const string STORAGE_KEY_CREATED_AT = '_c'; - const STORAGE_KEY_UPDATED_AT = '_u'; + const string STORAGE_KEY_UPDATED_AT = '_u'; private CookieSaveHandlerInterface $saveHandler; @@ -74,7 +75,7 @@ public function all(VisitorInfo $visitorInfo, string $scope): array ]; // filter internal values - $result = array_filter($this->data[$scope], function ($key) use ($blocklist) { + $result = array_filter($this->data[$scope], static function ($key) use ($blocklist) { return !in_array($key, $blocklist, true); }, ARRAY_FILTER_USE_KEY); @@ -112,14 +113,12 @@ public function set(VisitorInfo $visitorInfo, string $scope, string $name, mixed /** * {@inheritdoc } */ - public function clear(VisitorInfo $visitorInfo, string $scope = null): void + public function clear(VisitorInfo $visitorInfo, ?string $scope = null): void { if (null === $scope) { $this->data = []; - } else { - if (isset($this->data[$scope])) { - unset($this->data[$scope]); - } + } elseif (isset($this->data[$scope])) { + unset($this->data[$scope]); } $this->addSaveListener($visitorInfo); @@ -173,7 +172,7 @@ private function loadData(VisitorInfo $visitorInfo, string $scope): array throw new \InvalidArgumentException(sprintf('Scope "%s" is not supported', $scope)); } - if (isset($this->data[$scope]) && null !== $this->data[$scope]) { + if (isset($this->data[$scope])) { return $this->data[$scope]; } @@ -216,17 +215,16 @@ private function addSaveListener(VisitorInfo $visitorInfo): void private function updateTimestamps( string $scope, - \DateTimeInterface $createdAt = null, - \DateTimeInterface $updatedAt = null + ?DateTimeInterface $createdAt = null, + ?DateTimeInterface $updatedAt = null ): void { $timestamps = $this->normalizeTimestamps($createdAt, $updatedAt); if (!isset($this->data[$scope][self::STORAGE_KEY_CREATED_AT])) { $this->data[$scope][self::STORAGE_KEY_CREATED_AT] = $timestamps['createdAt']->getTimestamp(); - $this->data[$scope][self::STORAGE_KEY_UPDATED_AT] = $timestamps['updatedAt']->getTimestamp(); - } else { - $this->data[$scope][self::STORAGE_KEY_UPDATED_AT] = $timestamps['updatedAt']->getTimestamp(); } + + $this->data[$scope][self::STORAGE_KEY_UPDATED_AT] = $timestamps['updatedAt']->getTimestamp(); } protected function expiryFor(string $scope): \DateTime|int diff --git a/src/Targeting/Storage/DbStorage.php b/src/Targeting/Storage/DbStorage.php index e4b8e6d..532e00f 100644 --- a/src/Targeting/Storage/DbStorage.php +++ b/src/Targeting/Storage/DbStorage.php @@ -17,6 +17,7 @@ namespace OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage; +use DateTimeInterface; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\Result; use Doctrine\DBAL\Query\QueryBuilder; @@ -198,7 +199,7 @@ public function get(VisitorInfo $visitorInfo, string $scope, string $name, mixed /** * {@inheritdoc } */ - public function clear(VisitorInfo $visitorInfo, string $scope = null): void + public function clear(VisitorInfo $visitorInfo, ?string $scope = null): void { if (!$visitorInfo->hasVisitorId()) { return; @@ -324,8 +325,8 @@ private function convertToDateTime(mixed $result = null): ?\DateTimeImmutable private function updateTimestamps( VisitorInfo $visitorInfo, string $scope, - \DateTimeInterface $createdAt = null, - \DateTimeInterface $updatedAt = null + ?DateTimeInterface $createdAt = null, + ?DateTimeInterface $updatedAt = null ): void { $timestamps = $this->normalizeTimestamps($createdAt, $updatedAt); diff --git a/src/Targeting/Storage/FallbackStorage.php b/src/Targeting/Storage/FallbackStorage.php index 5cebbb0..64bef0c 100644 --- a/src/Targeting/Storage/FallbackStorage.php +++ b/src/Targeting/Storage/FallbackStorage.php @@ -74,9 +74,9 @@ public function all(VisitorInfo $visitorInfo, string $scope): array $this->migrateFromFallback($visitorInfo, $scope); return $this->primaryStorage->all($visitorInfo, $scope); - } else { - return $this->fallbackStorage->all($visitorInfo, $scope); } + + return $this->fallbackStorage->all($visitorInfo, $scope); } public function has(VisitorInfo $visitorInfo, string $scope, string $name): bool @@ -87,9 +87,9 @@ public function has(VisitorInfo $visitorInfo, string $scope, string $name): bool } return $this->primaryStorage->has($visitorInfo, $scope, $name); - } else { - return $this->fallbackStorage->has($visitorInfo, $scope, $name); } + + return $this->fallbackStorage->has($visitorInfo, $scope, $name); } public function set(VisitorInfo $visitorInfo, string $scope, string $name, mixed $value): void @@ -112,15 +112,15 @@ public function get(VisitorInfo $visitorInfo, string $scope, string $name, mixed } return $this->primaryStorage->get($visitorInfo, $scope, $name, $default); - } else { - return $this->fallbackStorage->get($visitorInfo, $scope, $name, $default); } + + return $this->fallbackStorage->get($visitorInfo, $scope, $name, $default); } /** * {@inheritdoc } */ - public function clear(VisitorInfo $visitorInfo, string $scope = null): void + public function clear(VisitorInfo $visitorInfo, ?string $scope = null): void { $this->fallbackStorage->clear($visitorInfo, $scope); @@ -138,18 +138,18 @@ public function getCreatedAt(VisitorInfo $visitorInfo, string $scope): ?\DateTim { if ($visitorInfo->hasVisitorId()) { return $this->primaryStorage->getCreatedAt($visitorInfo, $scope); - } else { - return $this->fallbackStorage->getCreatedAt($visitorInfo, $scope); } + + return $this->fallbackStorage->getCreatedAt($visitorInfo, $scope); } public function getUpdatedAt(VisitorInfo $visitorInfo, string $scope): ?\DateTimeImmutable { if ($visitorInfo->hasVisitorId()) { return $this->primaryStorage->getUpdatedAt($visitorInfo, $scope); - } else { - return $this->fallbackStorage->getUpdatedAt($visitorInfo, $scope); } + + return $this->fallbackStorage->getUpdatedAt($visitorInfo, $scope); } private function migrateFromFallback(VisitorInfo $visitorInfo, string $scope): void diff --git a/src/Targeting/Storage/RedisStorage.php b/src/Targeting/Storage/RedisStorage.php index f269a9c..d886628 100644 --- a/src/Targeting/Storage/RedisStorage.php +++ b/src/Targeting/Storage/RedisStorage.php @@ -17,6 +17,7 @@ namespace OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage; +use DateTimeInterface; use OpenDxp\Bundle\PersonalizationBundle\Targeting\Model\VisitorInfo; use OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\Traits\TimestampsTrait; @@ -24,9 +25,9 @@ class RedisStorage implements TargetingStorageInterface { use TimestampsTrait; - const STORAGE_KEY_CREATED_AT = '_c'; + const string STORAGE_KEY_CREATED_AT = '_c'; - const STORAGE_KEY_UPDATED_AT = '_u'; + const string STORAGE_KEY_UPDATED_AT = '_u'; private \Credis_Client $redis; @@ -123,7 +124,7 @@ public function get(VisitorInfo $visitorInfo, string $scope, string $name, mixed /** * {@inheritdoc } */ - public function clear(VisitorInfo $visitorInfo, string $scope = null): void + public function clear(VisitorInfo $visitorInfo, ?string $scope = null): void { $scopes = []; if (null !== $scope) { @@ -224,8 +225,8 @@ private function updateTimestamps( \Credis_Client $multi, string $key, int $currentCreatedAt, - \DateTimeInterface $createdAt = null, - \DateTimeInterface $updatedAt = null + ?DateTimeInterface $createdAt = null, + ?DateTimeInterface $updatedAt = null ): void { $timestamps = $this->normalizeTimestamps($createdAt, $updatedAt); diff --git a/src/Targeting/Storage/SessionStorage.php b/src/Targeting/Storage/SessionStorage.php index 12b95d2..bd0ff22 100644 --- a/src/Targeting/Storage/SessionStorage.php +++ b/src/Targeting/Storage/SessionStorage.php @@ -17,6 +17,7 @@ namespace OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage; +use DateTimeInterface; use OpenDxp\Bundle\PersonalizationBundle\Targeting\EventListener\TargetingSessionBagListener; use OpenDxp\Bundle\PersonalizationBundle\Targeting\Model\VisitorInfo; use OpenDxp\Bundle\PersonalizationBundle\Targeting\Storage\Traits\TimestampsTrait; @@ -26,9 +27,9 @@ class SessionStorage implements TargetingStorageInterface { use TimestampsTrait; - const STORAGE_KEY_CREATED_AT = '_c'; + const string STORAGE_KEY_CREATED_AT = '_c'; - const STORAGE_KEY_UPDATED_AT = '_u'; + const string STORAGE_KEY_UPDATED_AT = '_u'; public function all(VisitorInfo $visitorInfo, string $scope): array { @@ -89,7 +90,7 @@ public function get(VisitorInfo $visitorInfo, string $scope, string $name, mixed /** * {@inheritdoc } */ - public function clear(VisitorInfo $visitorInfo, string $scope = null): void + public function clear(VisitorInfo $visitorInfo, ?string $scope = null): void { if (null !== $scope) { $bag = $this->getSessionBag($visitorInfo, $scope, true); @@ -195,16 +196,14 @@ private function getSessionBag(VisitorInfo $visitorInfo, string $scope, bool $ch private function updateTimestamps( AttributeBag $bag, - \DateTimeInterface $createdAt = null, - \DateTimeInterface $updatedAt = null + ?DateTimeInterface $createdAt = null, + ?DateTimeInterface $updatedAt = null ): void { $timestamps = $this->normalizeTimestamps($createdAt, $updatedAt); if (!$bag->has(self::STORAGE_KEY_CREATED_AT)) { $bag->set(self::STORAGE_KEY_CREATED_AT, $timestamps['createdAt']->getTimestamp()); - $bag->set(self::STORAGE_KEY_UPDATED_AT, $timestamps['updatedAt']->getTimestamp()); - } else { - $bag->set(self::STORAGE_KEY_UPDATED_AT, $timestamps['updatedAt']->getTimestamp()); } + $bag->set(self::STORAGE_KEY_UPDATED_AT, $timestamps['updatedAt']->getTimestamp()); } } diff --git a/src/Targeting/Storage/TargetingStorageInterface.php b/src/Targeting/Storage/TargetingStorageInterface.php index 8343bad..ffd9528 100644 --- a/src/Targeting/Storage/TargetingStorageInterface.php +++ b/src/Targeting/Storage/TargetingStorageInterface.php @@ -25,11 +25,11 @@ */ interface TargetingStorageInterface { - const SCOPE_SESSION = 'session'; + const string SCOPE_SESSION = 'session'; - const SCOPE_VISITOR = 'visitor'; + const string SCOPE_VISITOR = 'visitor'; - const VALID_SCOPES = [ + const array VALID_SCOPES = [ self::SCOPE_SESSION, self::SCOPE_VISITOR, ]; @@ -40,7 +40,7 @@ interface TargetingStorageInterface * - write an entry to make sure the storage has a created/updated date * - set the entry created date to something in the past when migrating from another storage */ - const STORAGE_KEY_META_ENTRY = '_m'; + const string STORAGE_KEY_META_ENTRY = '_m'; public function all(VisitorInfo $visitorInfo, string $scope): array; @@ -50,7 +50,7 @@ public function set(VisitorInfo $visitorInfo, string $scope, string $name, mixed public function get(VisitorInfo $visitorInfo, string $scope, string $name, mixed $default = null): mixed; - public function clear(VisitorInfo $visitorInfo, string $scope = null): void; + public function clear(VisitorInfo $visitorInfo, ?string $scope = null): void; public function migrateFromStorage(TargetingStorageInterface $storage, VisitorInfo $visitorInfo, string $scope): void; diff --git a/src/Targeting/Storage/Traits/TimestampsTrait.php b/src/Targeting/Storage/Traits/TimestampsTrait.php index 7de4c7f..43a9d62 100644 --- a/src/Targeting/Storage/Traits/TimestampsTrait.php +++ b/src/Targeting/Storage/Traits/TimestampsTrait.php @@ -22,7 +22,7 @@ trait TimestampsTrait /** * @return \DateTimeInterface[] */ - private function normalizeTimestamps(\DateTimeInterface $createdAt = null, \DateTimeInterface $updatedAt = null): array + private function normalizeTimestamps(?\DateTimeInterface $createdAt = null, ?\DateTimeInterface $updatedAt = null): array { $now = new \DateTimeImmutable(); diff --git a/src/Targeting/VisitorInfoResolver.php b/src/Targeting/VisitorInfoResolver.php index 9d36c16..b5a3c98 100644 --- a/src/Targeting/VisitorInfoResolver.php +++ b/src/Targeting/VisitorInfoResolver.php @@ -189,12 +189,7 @@ private function matchTargetingRuleCondition(VisitorInfo $visitorInfo, Rule $rul private function handleTargetingRuleActions(VisitorInfo $visitorInfo, Rule $rule): void { - $actions = $rule->getActions(); - if (!$actions || !is_array($actions)) { - return; - } - - foreach ($actions as $action) { + foreach ($rule->getActions() as $action) { if (!is_array($action)) { continue; } @@ -212,7 +207,6 @@ private function getTargetingRules(): array return $this->targetingRules; } - /** @var Rule\Listing|Rule\Listing\Dao $list */ $list = new Rule\Listing(); $list->setCondition('active = 1'); $list->setOrderKey('prio'); diff --git a/templates/Targeting/toolbar/icon/advanced_features.svg.twig b/templates/Targeting/toolbar/icon/advanced_features.svg.twig index b3fb4dd..6b185de 100644 --- a/templates/Targeting/toolbar/icon/advanced_features.svg.twig +++ b/templates/Targeting/toolbar/icon/advanced_features.svg.twig @@ -1,4 +1,4 @@ -{# original file: data_configuration.svg from Pimcore's icon set #} +{# original file: data_configuration.svg from OpenDxp's icon set #} diff --git a/templates/Targeting/toolbar/icon/toolbar-collapse.svg.twig b/templates/Targeting/toolbar/icon/toolbar-collapse.svg.twig index 02bdfea..187ff4c 100644 --- a/templates/Targeting/toolbar/icon/toolbar-collapse.svg.twig +++ b/templates/Targeting/toolbar/icon/toolbar-collapse.svg.twig @@ -1,4 +1,4 @@ -{# original file: previous.svg from Pimcore's icon set #} +{# original file: previous.svg from OpenDxp's icon set #} diff --git a/templates/Targeting/toolbar/toolbar_js.html.twig b/templates/Targeting/toolbar/toolbar_js.html.twig index 1866b44..708643b 100644 --- a/templates/Targeting/toolbar/toolbar_js.html.twig +++ b/templates/Targeting/toolbar/toolbar_js.html.twig @@ -1,5 +1,5 @@ {# - CAUTION: The pimcoreassetcompress tag just blindly strips all newlines from the generated code. This means you can't + CAUTION: The opendxpassetcompress tag just blindly strips all newlines from the generated code. This means you can't use // comments here as they would break the generated code. Use /* */ comments if needed or refactor the "minifying" to use a decent JS processor such as uglify or webpack. #} diff --git a/tests/Support/Helper/Unit.php b/tests/Support/Helper/Unit.php index ef6712c..25369b3 100644 --- a/tests/Support/Helper/Unit.php +++ b/tests/Support/Helper/Unit.php @@ -27,7 +27,7 @@ class Unit extends \Codeception\Module public function _beforeSuite($settings = []) { - /** @var Pimcore $pimcoreModule */ + /** @var OpenDxp $opendxpModule */ $opendxpModule = $this->getModule('\\' . OpenDxp::class); //create migrations table in order to allow installation - needed for SettingsStoreAware Installer