├── .editorconfig
├── .github
├── oxid-esales
│ └── graphql-configuration-access_light.yaml
└── workflows
│ ├── dispatch_module.yaml
│ ├── sbom.yaml
│ ├── schema_trigger.yaml
│ └── trigger.yaml
├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── assets
└── logo.png
├── composer.json
├── dependencies.yaml
├── deptrac.yaml
├── git-hooks
└── init.sh
├── metadata.php
├── module_blocklist.yaml
├── recipes
└── setup-development.sh
├── services.yaml
├── src
├── Module
│ ├── Controller
│ │ ├── ModuleActivationController.php
│ │ ├── ModuleListController.php
│ │ └── ModuleSettingController.php
│ ├── DataType
│ │ ├── ModuleDataType.php
│ │ ├── ModuleDataTypeFactory.php
│ │ ├── ModuleDataTypeFactoryInterface.php
│ │ └── ModuleDataTypeInterface.php
│ ├── Exception
│ │ ├── ModuleActivationBlockedException.php
│ │ ├── ModuleActivationException.php
│ │ ├── ModuleDeactivationBlockedException.php
│ │ ├── ModuleDeactivationException.php
│ │ └── ModulesNotFoundException.php
│ ├── Infrastructure
│ │ ├── ModuleListInfrastructure.php
│ │ └── ModuleListInfrastructureInterface.php
│ ├── Service
│ │ ├── ModuleActivationService.php
│ │ ├── ModuleActivationServiceInterface.php
│ │ ├── ModuleBlocklistService.php
│ │ ├── ModuleBlocklistServiceInterface.php
│ │ ├── ModuleListService.php
│ │ ├── ModuleListServiceInterface.php
│ │ ├── ModuleSettingService.php
│ │ └── ModuleSettingServiceInterface.php
│ └── services.yaml
├── Shared
│ ├── DataType
│ │ ├── AbstractComponentDataType.php
│ │ ├── BooleanSetting.php
│ │ ├── ComponentDataTypeInterface.php
│ │ ├── ComponentFilters.php
│ │ ├── ComponentFiltersInterface.php
│ │ ├── FloatSetting.php
│ │ ├── IntegerSetting.php
│ │ ├── SettingType.php
│ │ └── StringSetting.php
│ ├── Enum
│ │ └── FieldType.php
│ ├── Exception
│ │ ├── CollectionEncodingException.php
│ │ ├── InvalidCollectionException.php
│ │ ├── NoSettingsFoundException.php
│ │ └── WrongSettingValueException.php
│ ├── Infrastructure
│ │ ├── LanguageWrapper.php
│ │ ├── LanguageWrapperInterface.php
│ │ └── services.yaml
│ ├── Service
│ │ ├── CollectionEncodingServiceInterface.php
│ │ ├── ComponentFilterService.php
│ │ ├── ComponentFilterServiceInterface.php
│ │ ├── JsonCollectionEncodingService.php
│ │ ├── LanguageService.php
│ │ ├── LanguageServiceInterface.php
│ │ ├── NamespaceMapper.php
│ │ └── PermissionProvider.php
│ └── services.yaml
├── Shop
│ ├── Controller
│ │ └── ShopSettingController.php
│ ├── Exception
│ │ ├── NoSettingsFoundForShopException.php
│ │ └── WrongSettingTypeException.php
│ ├── Infrastructure
│ │ ├── ShopSettingRepository.php
│ │ └── ShopSettingRepositoryInterface.php
│ ├── Service
│ │ ├── ShopSettingService.php
│ │ └── ShopSettingServiceInterface.php
│ └── services.yaml
└── Theme
│ ├── Controller
│ ├── ThemeListController.php
│ ├── ThemeSettingController.php
│ └── ThemeSwitchController.php
│ ├── DataType
│ ├── ThemeDataType.php
│ ├── ThemeDataTypeFactory.php
│ ├── ThemeDataTypeFactoryInterface.php
│ └── ThemeDataTypeInterface.php
│ ├── Exception
│ ├── NoSettingsFoundForThemeException.php
│ ├── ThemeActivationException.php
│ └── ThemesNotFound.php
│ ├── Infrastructure
│ ├── CoreThemeFactory.php
│ ├── CoreThemeFactoryInterface.php
│ ├── ThemeListInfrastructure.php
│ ├── ThemeListInfrastructureInterface.php
│ ├── ThemeSettingRepository.php
│ ├── ThemeSettingRepositoryInterface.php
│ ├── ThemeSwitchInfrastructure.php
│ └── ThemeSwitchInfrastructureInterface.php
│ ├── Service
│ ├── ThemeListService.php
│ ├── ThemeListServiceInterface.php
│ ├── ThemeSettingService.php
│ ├── ThemeSettingServiceInterface.php
│ ├── ThemeSwitchService.php
│ └── ThemeSwitchServiceInterface.php
│ └── services.yaml
└── tests
├── Codeception
├── Acceptance.suite.yml
├── Acceptance
│ ├── BaseCest.php
│ ├── Module
│ │ ├── ModuleActivationCest.php
│ │ ├── ModuleListCest.php
│ │ ├── ModuleSettingBaseCest.php
│ │ ├── ModuleSettingGettersCest.php
│ │ ├── ModuleSettingListCest.php
│ │ ├── ModuleSettingMutationsCest.php
│ │ └── ModuleSwitchCest.php
│ ├── NotAuthorizedAccessCest.php
│ ├── Shop
│ │ ├── ShopSettingGettersCest.php
│ │ ├── ShopSettingListCest.php
│ │ └── ShopSettingMutationsCest.php
│ └── Theme
│ │ ├── ThemeListCest.php
│ │ ├── ThemeSettingGettersCest.php
│ │ ├── ThemeSettingListCest.php
│ │ ├── ThemeSettingMutationsCest.php
│ │ └── ThemeSwitchCest.php
├── Config
│ └── params.php
├── Data
│ └── testdata.sql
├── Support
│ ├── AcceptanceTester.php
│ └── _generated
│ │ └── .gitignore
└── _output
│ └── .gitignore
├── Fixtures
├── testdemodata_ce.sql
└── testdemodata_ee.sql
├── Integration
├── Infrastructure
│ ├── CoreThemeFactoryTest.php
│ ├── ModuleListInfrastructureTest.php
│ ├── ShopSettingRepositoryTest.php
│ ├── ThemeListInfrastructureTest.php
│ └── ThemeSettingRepositoryTest.php
└── Service
│ └── ModuleBlockListServiceTest.php
├── PhpMd
├── exclude-ruleset.xml
└── standard.xml
├── PhpStan
├── phpstan-bootstrap.php
└── phpstan.neon
├── Reports
└── .gitkeep
├── Unit
├── Module
│ ├── Controller
│ │ ├── ModuleActivationControllerTest.php
│ │ ├── ModuleListControllerTest.php
│ │ └── ModuleSettingControllerTest.php
│ ├── DataType
│ │ ├── ModuleDataTypeFactoryTest.php
│ │ └── ModuleDataTypeTest.php
│ ├── Exception
│ │ ├── ModuleActivationBlockedExceptionTest.php
│ │ ├── ModuleActivationExceptionTest.php
│ │ ├── ModuleDeactivationBlockedExceptionTest.php
│ │ ├── ModuleDeactivationExceptionTest.php
│ │ └── ModulesNotFoundExceptionTest.php
│ ├── Infrastructure
│ │ └── ModuleListInfrastructureTest.php
│ └── Service
│ │ ├── ModuleActivationsServiceTest.php
│ │ ├── ModuleBlocklistServiceTest.php
│ │ ├── ModuleListServiceTest.php
│ │ └── ModuleSettingServiceTest.php
├── Shared
│ ├── DataType
│ │ ├── AbstractComponentDataTypeTest.php
│ │ ├── BooleanSettingTest.php
│ │ ├── ComponentFiltersTest.php
│ │ ├── FloatSettingTest.php
│ │ ├── IntegerSettingTest.php
│ │ ├── SettingTypeTest.php
│ │ └── StringSettingTest.php
│ ├── Enum
│ │ └── FieldTypeTest.php
│ ├── Exception
│ │ ├── CollectionEncodingExceptionTest.php
│ │ ├── InvalidCollectionExceptionTest.php
│ │ └── WrongSettingValueExceptionTest.php
│ ├── Infrastructure
│ │ ├── AbstractDatabaseSettingsRepositoryTestCase.php
│ │ └── LanguageWrapperTest.php
│ └── Service
│ │ ├── ComponentFilterServiceTest.php
│ │ ├── JsonCollectionEncodingServiceTest.php
│ │ ├── LanguageServiceTest.php
│ │ ├── NamespaceMapperTest.php
│ │ └── PermissionProviderTest.php
├── Shop
│ ├── Controller
│ │ └── ShopSettingControllerTest.php
│ ├── Exception
│ │ ├── NoSettingsFoundForShopExceptionTest.php
│ │ └── WrongSettingTypeExceptionTest.php
│ ├── Infrastructure
│ │ ├── AbstractShopSettingRepositoryTestCase.php
│ │ ├── ShopSettingRepositoryGettersTest.php
│ │ └── ShopSettingRepositorySettersTest.php
│ └── Service
│ │ └── ShopSettingServiceTest.php
├── Theme
│ ├── Controller
│ │ ├── ThemeListControllerTest.php
│ │ ├── ThemeSettingControllerTest.php
│ │ └── ThemeSwitchControllerTest.php
│ ├── DataType
│ │ ├── ThemeDataTypeFactoryTest.php
│ │ └── ThemeDataTypeTest.php
│ ├── Exception
│ │ ├── NoSettingsFoundForThemeExceptionTest.php
│ │ ├── ThemeActivationExceptionTest.php
│ │ └── ThemesNotFoundTest.php
│ ├── Infrastructure
│ │ ├── AbstractThemeSettingRepositoryTestCase.php
│ │ ├── ThemeListInfrastructureTest.php
│ │ ├── ThemeSettingRepositoryGettersTest.php
│ │ ├── ThemeSettingRepositorySettersTest.php
│ │ └── ThemeSwitchInfrastructureTest.php
│ └── Service
│ │ ├── ThemeListServiceTest.php
│ │ ├── ThemeSettingServiceTest.php
│ │ └── ThemeSwitchServiceTest.php
└── UnitTestCase.php
├── codeception.yml
├── phpcs.xml
└── phpunit.xml
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | charset = utf-8
11 | indent_style = space
12 | indent_size = 4
13 | trim_trailing_whitespace = true
14 |
15 | # Unix-style newlines with a newline ending every file
16 | [{*.yml,*.yaml}]
17 | indent_size = 2
18 |
19 | # Tab indentation (no size specified)
20 | [Makefile]
21 | indent_style = tab
22 |
--------------------------------------------------------------------------------
/.github/oxid-esales/graphql-configuration-access_light.yaml:
--------------------------------------------------------------------------------
1 | install:
2 | cache:
3 | prepared_shop: false
4 | git:
5 | repository: 'OXID-eSales/graphql-configuration-access'
6 | ref: &ref '{{ .Github.RefName }}'
7 | shop_url: 'https://github.com/OXID-eSales/graphql-configuration-access.git'
8 | shop_ref: *ref
9 | composer:
10 | transform: |
11 | {
12 | "require": {
13 | "oxid-esales/oxideshop-ce": "{{ .Data.global.composer.dev_ref }}",
14 | "oxid-esales/twig-component": "{{ .Data.global.composer.dev_ref }}",
15 | "oxid-esales/twig-admin-theme": "{{ .Data.global.composer.dev_ref }}",
16 | "oxid-esales/apex-theme": "{{ .Data.global.composer.dev_ref }}",
17 | "oxid-esales/developer-tools": "{{ .Data.global.composer.dev_ref }}"
18 | }
19 | }
20 | custom_script_container: |
21 | perl -pi -e 'print "SetEnvIf Authorization \"(.*)\" HTTP_AUTHORIZATION=\$1\n\n" if $. == 1' source/.htaccess
22 |
23 | vendor/bin/oe-console oe:database:reset --db-host=mysql --db-port=3306 --db-name=example --db-user=root --db-password=root --force
24 | vendor/bin/oe-console oe:module:install ./
25 | vendor/bin/oe-eshop-doctrine_migration migrations:migrate
26 | vendor/bin/oe-eshop-db_views_generate
27 |
28 | vendor/bin/oe-console oe:module:activate oe_graphql_base
29 | vendor/bin/oe-console oe:module:activate oe_graphql_configuration_access
30 | vendor/bin/oe-console oe:theme:activate apex
31 |
32 | install_shop_with_modules:
33 | composer:
34 | root_url: ''
35 |
36 | runscript: &runscript
37 | matrix:
38 | script: |
39 | [
40 | "configuration_module:phpunit",
41 | "configuration_module:phpintegration",
42 | "configuration_module:codeception"
43 | ]
44 | composer:
45 | early: true
46 | configuration_module:
47 | path: ''
48 |
49 | runslim:
50 | <<: *runscript
51 | matrix:
52 | script: |
53 | [
54 | "configuration_module:phpcs-report",
55 | "configuration_module:phpstan-report",
56 | "configuration_module:phpmd-report",
57 | "configuration_module:deptrac",
58 | ]
59 |
60 | sonarcloud:
61 | matrix:
62 | testplan: '["-"]'
63 | strip_path: '/var/www/'
64 | project_key: 'OXID-eSales_graphql-configuration-access'
65 | project_name: 'oxid-esales/graphql-configuration-access'
66 | parameters: |
67 | -Dsonar.language=php \
68 | -Dsonar.scm.provider=git \
69 | -Dsonar.sources=src \
70 | -Dsonar.tests=tests \
71 | -Dsonar.php.phpstan.reportPaths=coverage-reports/phpstan.report.json
72 |
73 | finish:
74 | slack_title: 'Configuration Access module ({{ .Data.global.git.shop_ref }}) by {{ .Github.Actor }}'
75 |
--------------------------------------------------------------------------------
/.github/workflows/dispatch_module.yaml:
--------------------------------------------------------------------------------
1 | name: Manual trigger for testing github actions development
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | limit:
7 | type: choice
8 | options:
9 | - 'no'
10 | - 'PHP8.2/MySQL5.7'
11 | - 'PHP8.2/MySQL8.0'
12 | - 'PHP8.2/MariaDb11'
13 | - 'PHP8.3/MySQL5.7'
14 | - 'PHP8.3/MySQL8.0'
15 | - 'PHP8.3/MariaDb11'
16 | - 'PHP8.4/MySQL8.0'
17 | - 'PHP8.4/MariaDb11'
18 | default: 'PHP8.2/MySQL5.7'
19 | description: 'Limit to one PHP/MySQL combination'
20 |
21 | jobs:
22 | build_testplan:
23 | runs-on: ubuntu-latest
24 | outputs:
25 | testplan: '${{ steps.build.outputs.testplan }}'
26 | steps:
27 | - name: 'Build testplan'
28 | id: build
29 | run: |
30 | # Build testplan
31 | # shellcheck disable=SC2088 # Tilde expansion happens in the workflow and not by bash
32 | case '${{inputs.limit}}' in
33 | "no") LIMIT='';;
34 | "PHP8.2/MySQL5.7") LIMIT='~/defaults/php8.2_mysql5.7_only.yaml,' ;;
35 | "PHP8.2/MySQL8.0") LIMIT='~/defaults/php8.2_mysql8.0_only.yaml,' ;;
36 | "PHP8.2/MariaDb11") LIMIT='~/defaults/php8.2_mariadb11_only.yaml,' ;;
37 | "PHP8.3/MySQL5.7") LIMIT='~/defaults/php8.3_mysql5.7_only.yaml,' ;;
38 | "PHP8.3/MySQL8.0") LIMIT='~/defaults/php8.3_mysql8.0_only.yaml,' ;;
39 | "PHP8.3/MariaDb11") LIMIT='~/defaults/php8.3_mariadb11_only.yaml,' ;;
40 | "PHP8.4/MySQL8.0") LIMIT='~/defaults/php8.4_mysql8.0_only.yaml,' ;;
41 | "PHP8.4/MariaDb11") LIMIT='~/defaults/php8.4_mariadb11_only.yaml,' ;;
42 | *) echo "Illegal choice, fix the workflow"
43 | exit 1
44 | ;;
45 | esac
46 | # shellcheck disable=SC2088
47 | TESTPLAN="~/defaults/7.3.x.yaml,${LIMIT}~/graphql-configuration-access_light.yaml"
48 | echo "testplan=${TESTPLAN}" | tee -a "${GITHUB_OUTPUT}"
49 |
50 | dispatch_stable:
51 | needs: build_testplan
52 | uses: oxid-eSales/github-actions/.github/workflows/universal_workflow_light.yaml@v4
53 | with:
54 | testplan: ${{ needs.build_testplan.outputs.testplan }}
55 | runs_on: '"ubuntu-latest"'
56 | defaults: 'v4'
57 | plan_folder: '.github/oxid-esales'
58 | secrets:
59 | DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }}
60 | DOCKER_HUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
61 | CACHE_ENDPOINT: ${{ secrets.CACHE_ENDPOINT }}
62 | CACHE_ACCESS_KEY: ${{ secrets.CACHE_ACCESS_KEY }}
63 | CACHE_SECRET_KEY: ${{ secrets.CACHE_SECRET_KEY }}
64 | enterprise_github_token: ${{ secrets.enterprise_github_token }}
65 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
66 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
67 |
--------------------------------------------------------------------------------
/.github/workflows/sbom.yaml:
--------------------------------------------------------------------------------
1 | name: SBOM generation
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 |
7 | jobs:
8 | generate_sbom:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: checkout
12 | uses: actions/checkout@v4
13 |
14 | - name: generate sbom
15 | uses: CycloneDX/gh-php-composer-generate-sbom@v1
16 |
--------------------------------------------------------------------------------
/.github/workflows/schema_trigger.yaml:
--------------------------------------------------------------------------------
1 | name: Trigger schema workflow
2 |
3 | on:
4 | push:
5 | tags: [v2.1.*]
6 |
7 | jobs:
8 | documentation_schema:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Trigger schema generation in documentation
12 | uses: convictional/trigger-workflow-and-wait@v1.6.5
13 | with:
14 | owner: oxid-esales
15 | repo: oxapi-documentation
16 | github_user: ${{ secrets.CI_USER }}
17 | github_token: ${{ secrets.GH_CI_JENKINS_TOKEN }}
18 | workflow_file_name: schema.yaml
19 | ref: "11.0-en"
20 |
--------------------------------------------------------------------------------
/.github/workflows/trigger.yaml:
--------------------------------------------------------------------------------
1 | name: Auto trigger on push or pull requests
2 |
3 | on:
4 | pull_request: {}
5 | push: {}
6 |
7 | jobs:
8 | configuration_module_php82_mysql80:
9 | uses: oxid-eSales/github-actions/.github/workflows/universal_workflow_light.yaml@v4
10 | with:
11 | testplan: '~/defaults/7.3.x.yaml,~/defaults/php8.2_mysql8.0_only.yaml,~/graphql-configuration-access_light.yaml'
12 | runs_on: '"ubuntu-latest"'
13 | defaults: 'v4'
14 | plan_folder: '.github/oxid-esales'
15 | secrets:
16 | DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }}
17 | DOCKER_HUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
18 | CACHE_ENDPOINT: ${{ secrets.CACHE_ENDPOINT }}
19 | CACHE_ACCESS_KEY: ${{ secrets.CACHE_ACCESS_KEY }}
20 | CACHE_SECRET_KEY: ${{ secrets.CACHE_SECRET_KEY }}
21 | enterprise_github_token: ${{ secrets.enterprise_github_token }}
22 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
23 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
24 |
25 | push_module_ee:
26 | runs-on: ubuntu-latest
27 | steps:
28 | - name: Trigger EE workflow and wait for results
29 | uses: convictional/trigger-workflow-and-wait@v1.6.5
30 | with:
31 | owner: oxid-esales
32 | repo: module-workflows
33 | github_user: ${{ secrets.CI_USER }}
34 | github_token: ${{ secrets.GH_CI_JENKINS_TOKEN }}
35 | workflow_file_name: configuration_access_workflow.yaml
36 | ref: "b-7.3.x"
37 | client_payload: "{\"limit\": \"PHP8.2/MySQL8.0\", \"edition\": \"ee\", \"ref\": \"${{ github.ref_name }}\"}"
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .php_cs.cache
3 | tests/.phpunit.result.cache
4 | .deptrac.cache
5 | composer.lock
6 | /vendor/
7 | tests/reports/
8 | tests/Codeception/_data/
9 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "recipes/parts"]
2 | path = recipes/parts
3 | url = https://github.com/OXID-eSales/docker-eshop-sdk-recipe-parts
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 | ## [2.1.0-rc.1] - 2025-04-28
8 |
9 | ### Added
10 | - New `parentTheme` and `parentVersions` fields in the `ThemeDataType`
11 | - PHP 8.4 support
12 |
13 | ## [2.0.0] - 2025-04-25
14 |
15 | ### Changed
16 | - Move ModuleDataType generation to Infrastructure
17 | - Move ThemeDataType generation to Infrastructure
18 |
19 | ### Removed
20 | - `OxidEsales\GraphQL\ConfigurationAccess\Shared\Subscriber\BeforeModuleDeactivation` because de/activation is already handled by shop
21 |
22 | ## [1.2.0] - 2024-11-27
23 | This is the stable release of v1.2.0. No changes have been made since v1.2.0-rc.1.
24 |
25 | ## [1.2.0-rc.1] - 2024-11-06
26 |
27 | ### Added
28 | - Theme list and filtering option on basis of theme name and status
29 | - Module list and filtering option on basis of module name and status
30 | - Activation of given theme by themeId
31 | - Mutations to de/activate a module.
32 | - Prevention of de/activation of certain modules mentioned in modules_blocklist.yaml.
33 |
34 | ## [1.1.0] - 2024-07-05
35 | This is stable release for v1.1.0. No changes have been made since v1.1.0-rc.1.
36 |
37 | ## [1.1.0-rc.1] - 2024-05-30
38 | ### Added
39 | - PHP 8.2 support
40 | - Module activation dependency on GraphQL Base module
41 |
42 | ### Changed
43 | - PHPUnit upgraded to version 10.x
44 | - Codeception tests structure updated to Codeception 5
45 |
46 | ### Removed
47 | - PHP 8.0 support
48 |
49 | ## [1.0.0] - 2024-02-07
50 |
51 | - Initial release
52 |
53 | [2.1.0-rc.1]: https://github.com/OXID-eSales/graphql-configuration-access/compare/b-7.2.x...v2.1.0-rc.1
54 | [2.0.0]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.2.0...v2.0.0
55 | [1.2.0]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.2.0-rc.1...v1.2.0
56 | [1.2.0-rc.1]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.1.0...v1.2.0-rc.1
57 | [1.1.0]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.1.0-rc.1...v1.1.0
58 | [1.1.0-rc.1]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.0.0...v1.1.0-rc.1
59 | [1.0.0]: https://github.com/OXID-eSales/graphql-configuration-access/releases/tag/v1.0.0
60 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to the OXID eSales GraphQL Configuration Access Module
2 |
3 | First off: Thank you for taking the time to contribute! 👍
4 |
5 | ## Contributor License Agreement
6 |
7 | When contributing code for the first time, you must sign our [Contributor License Agreement](https://gist.github.com/OXID-Admin/6df6ed126d074a54507d). No need to do something now, CLA Assistant will contact you after opening your first pull request. You can find more information about it on the [OXID Contribution and Contributor Agreement FAQ](https://docs.oxid-esales.com/developer/en/latest/development/modules_components_themes/contribution.html).
8 |
9 | ## How Can I Contribute?
10 |
11 | ### Reporting Bugs
12 |
13 | So, you stumbled upon a 🐛, those are tracked as [GitHub Issues](https://github.com/OXID-eSales/graphql-configuration-access/issues). Create an issue and provide all necessary information by explaining the problem and include additional details to help maintainers reproduce the problem:
14 |
15 | - **Use a clear and descriptive title** for the issue to identify the problem
16 | - **Describe the exact steps which reproduce the problem** in as many details as possible
17 | - **Describe the behavior you observed**
18 | - **Explain which behavior you expected to see instead and why**
19 | - **State the shop and module version** you used while having the problem
20 |
21 | ### Suggesting Enhancements
22 |
23 | 📈 Enhancement suggestions are tracked as [GitHub Issues](https://github.com/OXID-eSales/graphql-configuration-access/issues). Create an issue and provide all necessary information to help maintainers:
24 |
25 | - **Use a clear and descriptive title** for the issue to identify the suggestion
26 | - **Describe the current behavior** and **explain which behavior you expected to see instead**
27 | - **Explain why this enhancement would be useful**
28 | - **State if you are willing to provide a pull request for the enhancement**
29 |
30 | ### Pull Requests
31 |
32 | The basic workflow and the only way of contributing code to the project is via GitHub Pull Requests.
33 |
34 | - **Fork the project** to your account
35 | - **Make your bug fix or enhancement**
36 | - **Add tests** for your new code
37 | - **Send the Pull Request**
38 | - Make sure **CI is 💚**
39 |
40 | We recommend you to create a topic branch to work on, this will come in handy when making multiple contributions or when you need to rebase your pull request onto another branch. Also we would like to encourage you to open up an issue before making your pull request.
41 |
42 | #### What branch to send a Pull Request to?
43 |
44 | - Backwards compatibility breaks must go to the `master` branch
45 | - New Features go to the latest major version branch
46 | - Bugfixes to the latest minor version branch
47 |
48 | If in doubt, open up an issue before writing code, so we can help you settle this and possible other questions.
49 |
50 | ## I Need Help!
51 |
52 | When you need technical help on Git and GitHub, the [GitHub Help Page](https://help.github.com/) has you covered. You may additionally find [other sources with good practices](http://codeinthehole.com/writing/pull-requests-and-other-good-practices-for-teams-using-github/).
53 |
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OXID-eSales/graphql-configuration-access/eeebcc1d69a4286f1d8efb75907eaf944c7a679d/assets/logo.png
--------------------------------------------------------------------------------
/dependencies.yaml:
--------------------------------------------------------------------------------
1 | modules:
2 | - oe_graphql_base
3 |
--------------------------------------------------------------------------------
/deptrac.yaml:
--------------------------------------------------------------------------------
1 | deptrac:
2 | paths:
3 | - ./src/
4 | layers:
5 | - name: Controller
6 | collectors:
7 | - type: classLike
8 | value: OxidEsales\\.*GraphQL.*Controller\\.*
9 | - name: Service
10 | collectors:
11 | - type: classLike
12 | value: OxidEsales\\.*GraphQL.*Service\\.*
13 | - name: Infrastructure
14 | collectors:
15 | - type: classLike
16 | value: OxidEsales\\.*GraphQL.*Repository\\.*
17 | - type: classLike
18 | value: OxidEsales\\.*GraphQL.*Infrastructure\\.*
19 | - name: InternalService
20 | collectors:
21 | - type: classLike
22 | regex: OxidEsales\\Eshop.*\\Internal\\.*
23 | - name: Core
24 | collectors:
25 | - type: classLike
26 | regex: OxidEsales\\Eshop(\w+)?\\(?!Internal)
27 |
28 | ruleset:
29 | Controller:
30 | - Service
31 | Service:
32 | - InternalService
33 | - Infrastructure
34 | Infrastructure:
35 | - Core
36 | - InternalService
37 | Core: ~
38 | InternalService: ~
39 |
40 |
--------------------------------------------------------------------------------
/git-hooks/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | function setup_git_hooks()
6 | {
7 | echo "Initialising git hooks..."
8 |
9 | MODULE_PATH=$(git rev-parse --show-toplevel)
10 | PRE_COMMIT_HOOK_FILE_PATH=$MODULE_PATH/.git/hooks/pre-commit
11 |
12 | git config --local core.hooksPath .git/hooks
13 | echo "Add hook command to pre-commit file $PRE_COMMIT_HOOK_FILE_PATH"
14 |
15 | if ! [ -f "${PRE_COMMIT_HOOK_FILE_PATH}" ];then
16 | echo $'#!/bin/bash\n' >> $PRE_COMMIT_HOOK_FILE_PATH
17 | fi
18 |
19 | COMPOSER_STATIC_COMMAND="docker compose exec -T --workdir $MODULE_PATH php composer static"
20 |
21 | if grep -q "$COMPOSER_STATIC_COMMAND" "$PRE_COMMIT_HOOK_FILE_PATH"; then
22 | echo "Command has already been added"
23 | return
24 | fi
25 |
26 | echo "$COMPOSER_STATIC_COMMAND" >> $PRE_COMMIT_HOOK_FILE_PATH
27 | chmod +x $PRE_COMMIT_HOOK_FILE_PATH
28 | }
29 |
30 | setup_git_hooks
31 |
--------------------------------------------------------------------------------
/metadata.php:
--------------------------------------------------------------------------------
1 | 'oe_graphql_configuration_access',
18 | 'title' => 'GraphQL Configuration Access',
19 | 'description' => 'GraphQL Configuration Access',
20 | 'thumbnail' => 'logo.png',
21 | 'version' => '2.1.0-rc.1',
22 | 'author' => 'OXID eSales AG',
23 | 'url' => 'https://github.com/OXID-eSales/graphql-configuration-access',
24 | 'email' => 'info@oxid-esales.com',
25 | 'extend' => [
26 | ],
27 | 'controllers' => [
28 | ],
29 | 'templates' => [
30 | ],
31 | 'events' => [
32 | ],
33 | 'blocks' => [
34 | ],
35 | 'settings' => [
36 | ],
37 | ];
38 |
--------------------------------------------------------------------------------
/module_blocklist.yaml:
--------------------------------------------------------------------------------
1 | modules:
2 | - oe_graphql_base
3 | - oe_graphql_configuration_access
4 |
--------------------------------------------------------------------------------
/recipes/setup-development.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Flags possible:
3 | # -e for shop edition. Possible values: CE/EE
4 |
5 | edition='EE'
6 | while getopts e: flag; do
7 | case "${flag}" in
8 | e) edition=${OPTARG} ;;
9 | *) ;;
10 | esac
11 | done
12 |
13 | SCRIPT_PATH=$(dirname ${BASH_SOURCE[0]})
14 |
15 | cd $SCRIPT_PATH/../../ || exit
16 |
17 | # Prepare services configuration
18 | make setup
19 | make addbasicservices
20 | make file=services/adminer.yml addservice
21 | make file=services/selenium-chrome.yml addservice
22 | make file=services/node.yml addservice
23 |
24 | # Configure containers
25 | perl -pi\
26 | -e 's#error_reporting = .*#error_reporting = E_ALL ^ E_WARNING ^ E_DEPRECATED#g;'\
27 | containers/php/custom.ini
28 |
29 | perl -pi\
30 | -e 's#/var/www/#/var/www/source/#g;'\
31 | containers/httpd/project.conf
32 |
33 | perl -pi\
34 | -e 's#PHP_VERSION=.*#PHP_VERSION=8.2#g;'\
35 | .env
36 |
37 | docker compose up --build -d php
38 |
39 | docker compose exec -T php git config --global --add safe.directory /var/www
40 |
41 | $SCRIPT_PATH/parts/shared/require_shop_edition_packages.sh -e"${edition}" -v"dev-b-7.3.x"
42 | $SCRIPT_PATH/parts/shared/require_twig_components.sh -e"${edition}" -b"b-7.3.x"
43 | $SCRIPT_PATH/parts/shared/require.sh -n"oxid-esales/graphql-base" -g"https://github.com/OXID-eSales/graphql-base-module.git" -v"dev-b-7.3.x"
44 | $SCRIPT_PATH/parts/shared/require.sh -n"oxid-esales/developer-tools" -v"dev-b-7.3.x"
45 | $SCRIPT_PATH/parts/shared/require.sh -n"oxid-esales/oxideshop-doctrine-migration-wrapper" -v"dev-b-7.3.x"
46 | $SCRIPT_PATH/parts/shared/require_demodata_package.sh -e"${edition}" -b"master"
47 | $SCRIPT_PATH/parts/shared/require_theme.sh -t"apex" -b"b-7.3.x"
48 |
49 | docker compose exec -T php composer update --no-interaction
50 |
51 | make up
52 |
53 | perl -pi\
54 | -e 'print "SetEnvIf Authorization \"(.*)\" HTTP_AUTHORIZATION=\$1\n\n" if $. == 1'\
55 | source/source/.htaccess
56 |
57 | $SCRIPT_PATH/parts/shared/setup_database.sh
58 |
59 | docker compose exec -T php vendor/bin/oe-console oe:module:install ./
60 | docker compose exec -T php vendor/bin/oe-eshop-doctrine_migration migrations:migrate
61 | docker compose exec -T php vendor/bin/oe-eshop-db_views_generate
62 | docker compose exec -T php vendor/bin/oe-console oe:module:activate oe_graphql_base
63 | docker compose exec -T php vendor/bin/oe-console oe:module:activate oe_graphql_configuration_access
64 | docker compose exec -T php vendor/bin/oe-console oe:theme:activate apex
65 |
66 | $SCRIPT_PATH/parts/shared/create_admin.sh
67 |
68 | # Register all related project packages git repositories
69 | mkdir -p .idea; mkdir -p source/.idea; cp "${SCRIPT_PATH}/parts/bases/vcs.xml.base" .idea/vcs.xml
70 | perl -pi\
71 | -e 's##\n #g;'\
72 | -e 's##\n #g;'\
73 | -e 's##\n #g;'\
74 | -e 's##\n #g;'\
75 | -e 's##\n #g;'\
76 | .idea/vcs.xml
77 |
--------------------------------------------------------------------------------
/services.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: src/Shared/services.yaml }
3 | - { resource: src/Module/services.yaml }
4 | - { resource: src/Shop/services.yaml }
5 | - { resource: src/Theme/services.yaml }
6 |
7 | services:
8 |
9 | _defaults:
10 | public: false
11 | autowire: true
12 |
13 | OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\NamespaceMapper:
14 | class: OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\NamespaceMapper
15 | tags: [ 'graphql_namespace_mapper' ]
16 |
17 | OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\PermissionProvider:
18 | class: OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\PermissionProvider
19 | tags: [ 'graphql_permission_provider' ]
20 |
21 | OxidEsales\GraphQL\ConfigurationAccess\DependencyCheckTrigger:
22 | alias: OxidEsales\GraphQL\Base\Framework\GraphQLQueryHandler
23 | public: true
24 |
--------------------------------------------------------------------------------
/src/Module/Controller/ModuleActivationController.php:
--------------------------------------------------------------------------------
1 | moduleActivationService->activateModule(moduleId: $moduleId);
35 | }
36 |
37 | /**
38 | * Mutation of Configuration Access Module
39 | * @param string $moduleId
40 | * @return bool
41 | */
42 | #[Mutation]
43 | #[Logged]
44 | #[Right('ACTIVATE_MODULE')]
45 | public function deactivateModule(string $moduleId): bool
46 | {
47 | return $this->moduleActivationService->deactivateModule(moduleId: $moduleId);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Module/Controller/ModuleListController.php:
--------------------------------------------------------------------------------
1 | moduleListService->getModuleList($filters ?? new ComponentFilters());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Module/DataType/ModuleDataType.php:
--------------------------------------------------------------------------------
1 | thumbnail;
41 | }
42 |
43 | #[Field]
44 | public function getAuthor(): string
45 | {
46 | return $this->author;
47 | }
48 |
49 | #[Field]
50 | public function getUrl(): string
51 | {
52 | return $this->url;
53 | }
54 |
55 | #[Field]
56 | public function getEmail(): string
57 | {
58 | return $this->email;
59 | }
60 |
61 | #[Field]
62 | public function getLang(): string
63 | {
64 | return $this->lang;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Module/DataType/ModuleDataTypeFactory.php:
--------------------------------------------------------------------------------
1 | getTitle();
26 | $translatedTitle = $this->languageService->filterByLanguageAbbreviation(
27 | data: $titlesData,
28 | defaultLang: $moduleConfig->getLang()
29 | );
30 |
31 | $description = $moduleConfig->getDescription();
32 | $translatedDescription = $this->languageService->filterByLanguageAbbreviation(
33 | data: $description,
34 | defaultLang: $moduleConfig->getLang()
35 | );
36 |
37 | return new ModuleDataType(
38 | id: $moduleConfig->getId(),
39 | title: $translatedTitle,
40 | version: $moduleConfig->getVersion(),
41 | description: $translatedDescription,
42 | active: $moduleConfig->isActivated(),
43 | thumbnail: $moduleConfig->getThumbnail(),
44 | author: $moduleConfig->getAuthor(),
45 | url: $moduleConfig->getUrl(),
46 | email: $moduleConfig->getEmail(),
47 | lang: $moduleConfig->getLang()
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Module/DataType/ModuleDataTypeFactoryInterface.php:
--------------------------------------------------------------------------------
1 | shopConfigurationDaoBridge->get();
27 | $moduleConfigurations = $shopConfiguration->getModuleConfigurations();
28 |
29 | if (empty($moduleConfigurations)) {
30 | throw new ModulesNotFoundException();
31 | }
32 |
33 | $moduleDatatypes = [];
34 | foreach ($moduleConfigurations as $moduleConfig) {
35 | $moduleDatatypes[] = $this->moduleDataTypeFactory->createFromModuleConfiguration($moduleConfig);
36 | }
37 | return $moduleDatatypes;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Module/Infrastructure/ModuleListInfrastructureInterface.php:
--------------------------------------------------------------------------------
1 |
18 | */
19 | public function getModuleList(): array;
20 | }
21 |
--------------------------------------------------------------------------------
/src/Module/Service/ModuleActivationService.php:
--------------------------------------------------------------------------------
1 | moduleBlocklistService->isModuleBlocked($moduleId)) {
34 | throw new ModuleActivationBlockedException($moduleId);
35 | }
36 |
37 | $shopId = $this->context->getCurrentShopId();
38 |
39 | try {
40 | $this->moduleActivationBridge->activate(moduleId: $moduleId, shopId: $shopId);
41 | } catch (\Exception $exception) {
42 | throw new ModuleActivationException();
43 | }
44 |
45 | return true;
46 | }
47 |
48 | /**
49 | * @inheritDoc
50 | */
51 | public function deactivateModule(string $moduleId): bool
52 | {
53 | if ($this->moduleBlocklistService->isModuleBlocked($moduleId)) {
54 | throw new ModuleDeactivationBlockedException($moduleId);
55 | }
56 |
57 | $shopId = $this->context->getCurrentShopId();
58 |
59 | try {
60 | $this->moduleActivationBridge->deactivate(moduleId: $moduleId, shopId: $shopId);
61 | } catch (\Exception $exception) {
62 | throw new ModuleDeactivationException();
63 | }
64 |
65 | return true;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Module/Service/ModuleActivationServiceInterface.php:
--------------------------------------------------------------------------------
1 | moduleBlocklistPath;
25 | $configWrapper = $this->projectYamlDao->loadDIConfigFile($resolvedPath);
26 | $blocklistData = $configWrapper->getConfigAsArray();
27 |
28 | return in_array($moduleId, $blocklistData['modules'], true);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Module/Service/ModuleBlocklistServiceInterface.php:
--------------------------------------------------------------------------------
1 | moduleListInfrastructure->getModuleList();
27 |
28 | return $this->componentFilterService->filterComponents($moduleConfigurations, $filters);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Module/Service/ModuleListServiceInterface.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | public function getModuleList(ComponentFiltersInterface $filters): array;
19 | }
20 |
--------------------------------------------------------------------------------
/src/Module/Service/ModuleSettingServiceInterface.php:
--------------------------------------------------------------------------------
1 | id;
31 | }
32 |
33 | #[Field]
34 | public function getTitle(): string
35 | {
36 | return $this->title;
37 | }
38 |
39 | #[Field]
40 | public function getVersion(): string
41 | {
42 | return $this->version;
43 | }
44 |
45 | #[Field]
46 | public function getDescription(): string
47 | {
48 | return $this->description;
49 | }
50 |
51 | #[Field]
52 | public function isActive(): bool
53 | {
54 | return $this->active;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Shared/DataType/BooleanSetting.php:
--------------------------------------------------------------------------------
1 | name;
31 | }
32 |
33 | /**
34 | * Field of Configuration Access module's BooleanSetting-Type
35 | */
36 | #[Field]
37 | public function getValue(): bool
38 | {
39 | return $this->value;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Shared/DataType/ComponentDataTypeInterface.php:
--------------------------------------------------------------------------------
1 | titleFilter;
33 | if ($titleFilter !== null) {
34 | return $titleFilter->matches($title);
35 | }
36 |
37 | return true;
38 | }
39 |
40 | /**
41 | * TODO: This method can be refactored after the chain-of-responsibility-pattern
42 | * Therefore classes like TitleFilter or ActiveFilter with the Component as argument can check if a specific
43 | * property of the Component fits to a specific filter (String and BoolFilter). As a result we have an iterable list
44 | * with filters which checks different fields.
45 | */
46 | private function filterComponentByStatus(bool $status): bool
47 | {
48 | $statusFilter = $this->activeFilter;
49 | if ($statusFilter !== null && $status !== $statusFilter->equals()) {
50 | return false;
51 | }
52 |
53 | return true;
54 | }
55 |
56 | public function filterComponent(ComponentDataTypeInterface $component): bool
57 | {
58 | return $this->filterComponentByTitle($component->getTitle())
59 | && $this->filterComponentByStatus($component->isActive());
60 | }
61 |
62 | /**
63 | * @Factory(name="ComponentFilters", default=true)
64 | */
65 | public static function createComponentFilters(
66 | ?StringFilter $title = null,
67 | ?BoolFilter $active = null
68 | ): self {
69 | return new self(titleFilter: $title, activeFilter: $active);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Shared/DataType/ComponentFiltersInterface.php:
--------------------------------------------------------------------------------
1 | name;
31 | }
32 |
33 | /**
34 | * Field of Configuration Access module's FloatSetting-Type
35 | */
36 | #[Field]
37 | public function getValue(): float
38 | {
39 | return $this->value;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Shared/DataType/IntegerSetting.php:
--------------------------------------------------------------------------------
1 | name;
31 | }
32 |
33 | /**
34 | * Field of Configuration Access module's IntegerSetting-Type
35 | */
36 | #[Field]
37 | public function getValue(): int
38 | {
39 | return $this->value;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Shared/DataType/SettingType.php:
--------------------------------------------------------------------------------
1 | name;
35 | }
36 |
37 | /**
38 | * Field of Configuration Access module's SettingType-Type.
39 | * Indicates if the type is supported by our queries and mutations.
40 | * @SuppressWarnings(PHPMD.StaticAccess)
41 | */
42 | #[Field]
43 | public function isSupported(): bool
44 | {
45 | return FieldType::validateFieldType($this->getType());
46 | }
47 |
48 | /**
49 | * Field of Configuration Access module's StringSetting-Type
50 | */
51 | #[Field]
52 | public function getType(): string
53 | {
54 | return $this->type;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Shared/DataType/StringSetting.php:
--------------------------------------------------------------------------------
1 | name;
31 | }
32 |
33 | /**
34 | * Field of Configuration Access module's StringSetting-Type
35 | */
36 | #[Field]
37 | public function getValue(): string
38 | {
39 | return $this->value;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Shared/Enum/FieldType.php:
--------------------------------------------------------------------------------
1 | language->getLanguageAbbr();
24 | return $this->language->getLanguageAbbr();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/LanguageWrapperInterface.php:
--------------------------------------------------------------------------------
1 | filterComponent($module);
21 | });
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Shared/Service/ComponentFilterServiceInterface.php:
--------------------------------------------------------------------------------
1 | $components
13 | *
14 | * @return array
15 | */
16 | public function filterComponents(array $components, ComponentFiltersInterface $filterList): array;
17 | }
18 |
--------------------------------------------------------------------------------
/src/Shared/Service/JsonCollectionEncodingService.php:
--------------------------------------------------------------------------------
1 | language->getCurrentLanguageAbbr();
24 |
25 | if (isset($data[$languageAbbr])) {
26 | return $data[$languageAbbr];
27 | }
28 |
29 | if (isset($data[$defaultLang])) {
30 | return $data[$defaultLang];
31 | }
32 |
33 | $dataReversed = array_reverse($data);
34 | return array_pop($dataReversed);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Shared/Service/LanguageServiceInterface.php:
--------------------------------------------------------------------------------
1 | __DIR__ . '/../../Module/Controller/',
22 | self::SPACE . 'Shop\\Controller' => __DIR__ . '/../../Shop/Controller/',
23 | self::SPACE . 'Theme\\Controller' => __DIR__ . '/../../Theme/Controller/',
24 | ];
25 | }
26 |
27 | public function getTypeNamespaceMapping(): array
28 | {
29 | return [
30 | self::SPACE . 'Shared\\DataType' => __DIR__ . '/../../Shared/DataType/',
31 | self::SPACE . 'Theme\\DataType' => __DIR__ . '/../../Theme/DataType/',
32 | self::SPACE . 'Module\\DataType' => __DIR__ . '/../../Module/DataType/',
33 | ];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Shared/Service/PermissionProvider.php:
--------------------------------------------------------------------------------
1 | [
20 | 'CHANGE_CONFIGURATION',
21 | 'LIST_THEMES',
22 | 'LIST_MODULES',
23 | 'ACTIVATE_MODULE'
24 | ],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Shared/services.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: Infrastructure/services.yaml }
3 |
4 | services:
5 | _defaults:
6 | public: false
7 | autowire: true
8 |
9 | OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\:
10 | resource: 'Service/'
11 | public: true
12 |
13 | OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\CollectionEncodingServiceInterface:
14 | class: OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\JsonCollectionEncodingService
15 |
16 | OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\LanguageServiceInterface:
17 | class: \OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\LanguageService
18 |
19 | OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\ComponentFilterServiceInterface:
20 | class: \OxidEsales\GraphQL\ConfigurationAccess\Shared\Service\ComponentFilterService
21 |
--------------------------------------------------------------------------------
/src/Shop/Exception/NoSettingsFoundForShopException.php:
--------------------------------------------------------------------------------
1 |
61 | */
62 | public function getSettingsList(): array;
63 |
64 | /**
65 | * @throws WrongSettingTypeException
66 | */
67 | public function saveIntegerSetting(string $name, int $value): void;
68 |
69 | /**
70 | * @throws WrongSettingTypeException
71 | */
72 | public function saveFloatSetting(string $name, float $value): void;
73 |
74 | /**
75 | * @throws WrongSettingTypeException
76 | */
77 | public function saveBooleanSetting(string $name, bool $value): void;
78 |
79 | /**
80 | * @throws WrongSettingTypeException
81 | */
82 | public function saveStringSetting(string $name, string $value): void;
83 |
84 | /**
85 | * @throws WrongSettingTypeException
86 | */
87 | public function saveSelectSetting(string $name, string $value): void;
88 |
89 | /**
90 | * @throws WrongSettingTypeException
91 | */
92 | public function saveCollectionSetting(string $name, array $value): void;
93 |
94 | /**
95 | * @throws WrongSettingTypeException
96 | */
97 | public function saveAssocCollectionSetting(string $name, array $value): void;
98 | }
99 |
--------------------------------------------------------------------------------
/src/Shop/Service/ShopSettingServiceInterface.php:
--------------------------------------------------------------------------------
1 | themeListService->getThemeList($filters ?? new ComponentFilters());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Theme/Controller/ThemeSwitchController.php:
--------------------------------------------------------------------------------
1 | themeSwitchService->switchTheme($themeId);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Theme/DataType/ThemeDataType.php:
--------------------------------------------------------------------------------
1 | parentTheme;
35 | }
36 |
37 | /**
38 | * @return ?string[]
39 | */
40 | #[Field]
41 | public function getParentVersions(): ?array
42 | {
43 | return $this->parentVersions;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Theme/DataType/ThemeDataTypeFactory.php:
--------------------------------------------------------------------------------
1 | getInfo('id'),
21 | title: $theme->getInfo('title'),
22 | version: $theme->getInfo('version'),
23 | description: $theme->getInfo('description'),
24 | active: $theme->getInfo('active'),
25 | parentTheme: $theme->getInfo('parentTheme'),
26 | parentVersions: $theme->getInfo('parentVersions'),
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Theme/DataType/ThemeDataTypeFactoryInterface.php:
--------------------------------------------------------------------------------
1 | coreThemeFactory->create();
29 | $themesList = $coreThemeService->getList();
30 |
31 | if (empty($themesList)) {
32 | throw new ThemesNotFound();
33 | }
34 |
35 | $themeDataTypes = [];
36 | foreach ($themesList as $theme) {
37 | $themeDataTypes[] = $this->themeDataTypeFactory->createFromCoreTheme(theme: $theme);
38 | }
39 |
40 | return $themeDataTypes;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Theme/Infrastructure/ThemeListInfrastructureInterface.php:
--------------------------------------------------------------------------------
1 |
60 | */
61 | public function getSettingsList(string $themeId): array;
62 |
63 | /**
64 | * @throws NoSettingsFoundForThemeException
65 | */
66 | public function saveIntegerSetting(string $name, int $value, string $themeId): void;
67 |
68 | /**
69 | * @throws NoSettingsFoundForThemeException
70 | */
71 | public function saveFloatSetting(string $name, float $value, string $themeId): void;
72 |
73 | /**
74 | * @throws NoSettingsFoundForThemeException
75 | */
76 | public function saveBooleanSetting(string $name, bool $value, string $themeId): void;
77 |
78 | /**
79 | * @throws NoSettingsFoundForThemeException
80 | */
81 | public function saveStringSetting(string $name, string $value, string $themeId): void;
82 |
83 | /**
84 | * @throws NoSettingsFoundForThemeException
85 | */
86 | public function saveSelectSetting(string $name, string $value, string $themeId): void;
87 |
88 | /**
89 | * @throws NoSettingsFoundForThemeException
90 | */
91 | public function saveCollectionSetting(string $name, array $value, string $themeId): void;
92 |
93 | /**
94 | * @throws NoSettingsFoundForThemeException
95 | */
96 | public function saveAssocCollectionSetting(string $name, array $value, string $themeId): void;
97 | }
98 |
--------------------------------------------------------------------------------
/src/Theme/Infrastructure/ThemeSwitchInfrastructure.php:
--------------------------------------------------------------------------------
1 | coreThemeFactory->create();
28 | if (!$coreThemeService->load($themeId)) {
29 | throw new ThemeActivationException(self::THEME_NOT_EXIST);
30 | }
31 | $coreThemeService->activate();
32 |
33 | return true;
34 | } catch (ThemeActivationException | StandardException $e) {
35 | throw new ThemeActivationException($e->getMessage());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Theme/Infrastructure/ThemeSwitchInfrastructureInterface.php:
--------------------------------------------------------------------------------
1 | themeListInfrastructure->getThemes();
27 |
28 | return $this->componentFilterService->filterComponents($themeDataTypes, $filters);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Theme/Service/ThemeListServiceInterface.php:
--------------------------------------------------------------------------------
1 | themeSwitchInfrastructure->switchTheme(themeId: $themeId);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Theme/Service/ThemeSwitchServiceInterface.php:
--------------------------------------------------------------------------------
1 |
22 | mysql --defaults-file=$mysql_config --default-character-set=utf8 $dbname < $module_dump
23 | - \OxidEsales\Codeception\Module\Database:
24 | config_key: 'fq45QS09_fqyx09239QQ'
25 | depends: Db
26 | - \OxidEsales\Codeception\Module\SelectTheme:
27 | theme_id: '%THEME_ID%'
28 | depends:
29 | - \OxidEsales\Codeception\Module\Database
30 | - Db
31 | - REST:
32 | url: '%SHOP_URL%'
33 | depends: PhpBrowser
34 | part: Json
35 | - PhpBrowser:
36 | url: '%SHOP_URL%'
37 | - \OxidEsales\GraphQL\Base\Tests\Codeception\Module\AcceptanceHelper:
38 | depends:
39 | - REST
40 | step_decorators:
41 | - \Codeception\Step\Retry
42 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/BaseCest.php:
--------------------------------------------------------------------------------
1 | logout();
33 | }
34 |
35 | protected function getTestThemeName(): string
36 | {
37 | return self::TEST_THEME_ID;
38 | }
39 |
40 | protected function getAgentUsername(): string
41 | {
42 | return self::AGENT_USERNAME;
43 | }
44 |
45 | protected function getAgentPassword(): string
46 | {
47 | return self::AGENT_PASSWORD;
48 | }
49 |
50 | protected function getAdminUsername(): string
51 | {
52 | return self::ADMIN_USERNAME;
53 | }
54 |
55 | protected function getAdminPassword(): string
56 | {
57 | return self::ADMIN_PASSWORD;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Module/ModuleActivationCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
28 |
29 | $result = $this->runModuleMutation(
30 | I: $I,
31 | queryName: $example['queryName'],
32 | field: $example['field']
33 | );
34 |
35 | $I->assertNotSame('You do not have sufficient rights to access this field', $result['errors'][0]['message']);
36 | }
37 |
38 | private function runModuleMutation(
39 | AcceptanceTester $I,
40 | string $queryName,
41 | string $field
42 | ): array {
43 | $I->login($this->getAdminUsername(), $this->getAdminPassword());
44 | $I->sendGQLQuery(
45 | 'mutation {
46 | ' . $queryName . '(' . $field . ': "' . self::TEST_MODULE_ID . '")
47 | }'
48 | );
49 |
50 | $I->seeResponseIsJson();
51 | return $I->grabJsonResponseAsArray();
52 | }
53 |
54 | protected function moduleDeActivationDataProvider(): \Generator
55 | {
56 | yield ['queryName' => 'activateModule', 'field' => 'moduleId'];
57 | yield ['queryName' => 'deactivateModule', 'field' => 'moduleId'];
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Module/ModuleListCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
24 |
25 | $result = $this->runModuleListQuery($I);
26 | $I->assertArrayNotHasKey('errors', $result);
27 | }
28 |
29 | public function runModuleListQuery(AcceptanceTester $I): array
30 | {
31 | $I->sendGQLQuery(
32 | 'query modulesList {
33 | modules(
34 | filters: {
35 | title: {
36 | contains: "' . self::TEST_MODULE_TITLE . '"
37 | }
38 | active: {
39 | equals: true
40 | }
41 | }
42 | ) {
43 | id
44 | version
45 | title
46 | description
47 | thumbnail
48 | author
49 | url
50 | email
51 | active
52 | }
53 | }'
54 | );
55 |
56 | $I->seeResponseIsJson();
57 | return $I->grabJsonResponseAsArray();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Module/ModuleSettingGettersCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
26 |
27 | $result = $this->runSettingGetterQuery($I, $example['queryName'], $example['settingName']);
28 |
29 | $I->assertArrayNotHasKey('errors', $result);
30 |
31 | $setting = $result['data'][$example['queryName']];
32 | $I->assertSame($example['settingName'], $setting['name']);
33 | $I->assertSame($example['expectedValue'], $setting['value']);
34 | }
35 |
36 | protected function queryMethodsDataProvider(): \Generator
37 | {
38 | yield [
39 | 'queryName' => 'moduleSettingInteger',
40 | 'settingName' => 'intSetting',
41 | 'expectedValue' => 123
42 | ];
43 |
44 | yield [
45 | 'queryName' => 'moduleSettingFloat',
46 | 'settingName' => 'floatSetting',
47 | 'expectedValue' => 1.23
48 | ];
49 |
50 | yield [
51 | 'queryName' => 'moduleSettingBoolean',
52 | 'settingName' => 'boolSetting',
53 | 'expectedValue' => false
54 | ];
55 |
56 | yield [
57 | 'queryName' => 'moduleSettingString',
58 | 'settingName' => 'stringSetting',
59 | 'expectedValue' => 'default'
60 | ];
61 |
62 | yield [
63 | 'queryName' => 'moduleSettingCollection',
64 | 'settingName' => 'arraySetting',
65 | 'expectedValue' => '["nice","values"]'
66 | ];
67 | }
68 |
69 | private function runSettingGetterQuery(AcceptanceTester $I, string $queryName, string $settingName): array
70 | {
71 | $I->sendGQLQuery(
72 | 'query q($name: String!, $moduleId: String!){
73 | ' . $queryName . '(name: $name, moduleId: $moduleId) {
74 | name
75 | value
76 | }
77 | }',
78 | [
79 | 'name' => $settingName,
80 | 'moduleId' => self::TEST_MODULE_ID
81 | ]
82 | );
83 |
84 | $I->seeResponseIsJson();
85 |
86 | return $I->grabJsonResponseAsArray();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Module/ModuleSettingListCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
25 |
26 | $I->sendGQLQuery(
27 | 'query getSettings($moduleId: String!){
28 | moduleSettings(moduleId: $moduleId) {
29 | name
30 | type
31 | supported
32 | }
33 | }',
34 | ['moduleId' => self::TEST_MODULE_ID]
35 | );
36 |
37 | $I->seeResponseIsJson();
38 |
39 | $result = $I->grabJsonResponseAsArray();
40 | $I->assertArrayNotHasKey('errors', $result);
41 |
42 | $settingsList = $result['data']['moduleSettings'];
43 | $I->assertCount(5, $settingsList);
44 | $I->assertContains(
45 | ['name' => 'intSetting', 'type' => FieldType::NUMBER, 'supported' => true],
46 | $settingsList
47 | );
48 | $I->assertContains(
49 | ['name' => 'floatSetting', 'type' => FieldType::NUMBER, 'supported' => true],
50 | $settingsList
51 | );
52 | $I->assertContains(
53 | ['name' => 'boolSetting', 'type' => FieldType::BOOLEAN, 'supported' => true],
54 | $settingsList
55 | );
56 | $I->assertContains(
57 | ['name' => 'stringSetting', 'type' => FieldType::STRING, 'supported' => true],
58 | $settingsList
59 | );
60 | $I->assertContains(
61 | ['name' => 'arraySetting', 'type' => FieldType::ARRAY, 'supported' => true],
62 | $settingsList
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Module/ModuleSwitchCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
27 |
28 | $result = $this->runModuleMutation(
29 | I: $I,
30 | queryName: $example['queryName'],
31 | field: $example['field']
32 | );
33 |
34 | $I->assertArrayNotHasKey('errors', $result);
35 | $response = $result['data'][$example['queryName']];
36 | $I->assertTrue($response);
37 | }
38 |
39 | private function runModuleMutation(
40 | AcceptanceTester $I,
41 | string $queryName,
42 | string $field
43 | ): array {
44 | $I->login($this->getAdminUsername(), $this->getAdminPassword());
45 | $I->sendGQLQuery(
46 | 'mutation {
47 | ' . $queryName . '(' . $field . ': "' . self::TEST_MODULE_ID . '")
48 | }'
49 | );
50 |
51 | $I->seeResponseIsJson();
52 | return $I->grabJsonResponseAsArray();
53 | }
54 |
55 | protected function moduleSwitchDataProvider(): \Generator
56 | {
57 | yield ['queryName' => 'activateModule', 'field' => 'moduleId'];
58 | yield ['queryName' => 'deactivateModule', 'field' => 'moduleId'];
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Shop/ShopSettingGettersCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
27 |
28 | $result = $this->runSettingGetterQuery($I, $example['queryName'], $example['settingName']);
29 |
30 | $I->assertArrayNotHasKey('errors', $result);
31 |
32 | $setting = $result['data'][$example['queryName']];
33 | $I->assertSame($example['settingName'], $setting['name']);
34 | $I->assertSame($example['expectedValue'], $setting['value']);
35 | }
36 |
37 | protected function queryMethodsDataProvider(): \Generator
38 | {
39 | yield [
40 | 'queryName' => 'shopSettingInteger',
41 | 'settingName' => 'intSetting',
42 | 'expectedValue' => 123
43 | ];
44 |
45 | yield [
46 | 'queryName' => 'shopSettingFloat',
47 | 'settingName' => 'floatSetting',
48 | 'expectedValue' => 1.23
49 | ];
50 |
51 | yield [
52 | 'queryName' => 'shopSettingBoolean',
53 | 'settingName' => 'boolSetting',
54 | 'expectedValue' => false
55 | ];
56 |
57 | yield [
58 | 'queryName' => 'shopSettingString',
59 | 'settingName' => 'stringSetting',
60 | 'expectedValue' => 'default'
61 | ];
62 |
63 | yield [
64 | 'queryName' => 'shopSettingSelect',
65 | 'settingName' => 'selectSetting',
66 | 'expectedValue' => 'selectString'
67 | ];
68 |
69 | yield [
70 | 'queryName' => 'shopSettingCollection',
71 | 'settingName' => 'arraySetting',
72 | 'expectedValue' => '["10","20","50","100"]'
73 | ];
74 |
75 | yield [
76 | 'queryName' => 'shopSettingAssocCollection',
77 | 'settingName' => 'aarraySetting',
78 | 'expectedValue' => '{"first":"10","second":"20","third":"50"}'
79 | ];
80 | }
81 |
82 | private function runSettingGetterQuery(AcceptanceTester $I, string $queryName, string $settingName): array
83 | {
84 | $I->sendGQLQuery(
85 | 'query q($name: String!){
86 | ' . $queryName . '(name: $name) {
87 | name
88 | value
89 | }
90 | }',
91 | [
92 | 'name' => $settingName
93 | ]
94 | );
95 |
96 | $I->seeResponseIsJson();
97 |
98 | return $I->grabJsonResponseAsArray();
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Shop/ShopSettingListCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
26 |
27 | $I->sendGQLQuery(
28 | 'query{
29 | shopSettings {
30 | name
31 | type
32 | supported
33 | }
34 | }'
35 | );
36 |
37 | $I->seeResponseIsJson();
38 |
39 | $result = $I->grabJsonResponseAsArray();
40 | $I->assertArrayNotHasKey('errors', $result);
41 |
42 | $settingsList = $result['data']['shopSettings'];
43 | $I->assertContains(
44 | ['name' => 'intSetting', 'type' => FieldType::NUMBER, 'supported' => true],
45 | $settingsList
46 | );
47 | $I->assertContains(
48 | ['name' => 'floatSetting', 'type' => FieldType::NUMBER, 'supported' => true],
49 | $settingsList
50 | );
51 | $I->assertContains(
52 | ['name' => 'boolSetting', 'type' => FieldType::BOOLEAN, 'supported' => true],
53 | $settingsList
54 | );
55 | $I->assertContains(
56 | ['name' => 'stringSetting', 'type' => FieldType::STRING, 'supported' => true],
57 | $settingsList
58 | );
59 | $I->assertContains(
60 | ['name' => 'selectSetting', 'type' => FieldType::SELECT, 'supported' => true],
61 | $settingsList
62 | );
63 | $I->assertContains(
64 | ['name' => 'arraySetting', 'type' => FieldType::ARRAY, 'supported' => true],
65 | $settingsList
66 | );
67 | $I->assertContains(
68 | ['name' => 'aarraySetting', 'type' => FieldType::ASSOCIATIVE_ARRAY, 'supported' => true],
69 | $settingsList
70 | );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Theme/ThemeListCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
25 |
26 | $result = $this->runThemeListQuery($I);
27 | $I->assertArrayNotHasKey('errors', $result);
28 | }
29 |
30 | private function runThemeListQuery(AcceptanceTester $I): array
31 | {
32 | $I->sendGQLQuery(
33 | 'query themeList {
34 | themesList(
35 | filters: null
36 | ) {
37 | title
38 | id
39 | version
40 | description
41 | active
42 | parentTheme
43 | parentVersions
44 | }
45 | }'
46 | );
47 |
48 | $I->seeResponseIsJson();
49 | return $I->grabJsonResponseAsArray();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/Codeception/Acceptance/Theme/ThemeSwitchCest.php:
--------------------------------------------------------------------------------
1 | login($this->getAdminUsername(), $this->getAdminPassword());
25 |
26 | $result = $this->runThemeSwitchMutation($I);
27 |
28 | $I->assertArrayNotHasKey('errors', $result);
29 | }
30 |
31 | private function runThemeSwitchMutation(AcceptanceTester $I): array
32 | {
33 | $themeId = $this->getCurrentThemeId();
34 |
35 | $I->sendGQLQuery(
36 | 'mutation switchThemeCest{
37 | switchTheme(themeId: "' . $themeId . '")
38 | }'
39 | );
40 |
41 | $I->seeResponseIsJson();
42 | return $I->grabJsonResponseAsArray();
43 | }
44 |
45 | private function getCurrentThemeId(): string
46 | {
47 | $theme = new Theme();
48 | return $theme->getActiveThemeId();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/Codeception/Config/params.php:
--------------------------------------------------------------------------------
1 | $facts->getShopUrl(),
22 | 'SHOP_SOURCE_PATH' => $facts->getSourcePath(),
23 | 'VENDOR_PATH' => $facts->getVendorPath(),
24 | 'DB_NAME' => $facts->getDatabaseName(),
25 | 'DB_USERNAME' => $facts->getDatabaseUserName(),
26 | 'DB_PASSWORD' => $facts->getDatabasePassword(),
27 | 'DB_HOST' => $facts->getDatabaseHost(),
28 | 'DB_PORT' => $facts->getDatabasePort(),
29 | 'DUMP_PATH' => getTestDataDumpFilePath(),
30 | 'MODULE_DUMP_PATH' => getModuleTestDataDumpFilePath(),
31 | 'FIXTURES_PATH' => getTestFixtureSqlFilePath(),
32 | 'MYSQL_CONFIG_PATH' => getMysqlConfigPath(),
33 | 'SELENIUM_SERVER_PORT' => getenv('SELENIUM_SERVER_PORT') ?: '4444',
34 | 'SELENIUM_SERVER_HOST' => getenv('SELENIUM_SERVER_HOST') ?: 'selenium',
35 | 'BROWSER_NAME' => getenv('BROWSER_NAME') ?: 'chrome',
36 | 'PHP_BIN' => getenv('PHPBIN') ?: 'php',
37 | 'SCREEN_SHOT_URL' => getenv('CC_SCREEN_SHOTS_PATH') ?: '',
38 | 'THEME_ID' => getenv('THEME_ID') ?: 'apex',
39 | ];
40 |
41 | function getTestDataDumpFilePath(): string
42 | {
43 | return Path::join(__DIR__, '/../', 'Data', 'generated', 'dump.sql');
44 | }
45 |
46 | function getModuleTestDataDumpFilePath()
47 | {
48 | return Path::join(__DIR__, '/../', 'Data', 'testdata.sql');
49 | }
50 |
51 | function getTestFixtureSqlFilePath(): string
52 | {
53 | $facts = new Facts();
54 |
55 | $path = Path::join(__DIR__, '/../../', 'Fixtures', 'testdemodata_ce.sql');
56 |
57 | if ($facts->getEdition() == 'EE') {
58 | $path = Path::join(__DIR__, '/../../', 'Fixtures', 'testdemodata_ee.sql');
59 | }
60 |
61 | return $path;
62 | }
63 |
64 | function getMysqlConfigPath()
65 | {
66 | $facts = new Facts();
67 | $configFilePath = Path::join($facts->getSourcePath(), 'config.inc.php');
68 | $configFile = new ConfigFile($configFilePath);
69 | $generator = new DatabaseDefaultsFileGenerator($configFile);
70 |
71 | return $generator->generate();
72 | }
73 |
--------------------------------------------------------------------------------
/tests/Codeception/Data/testdata.sql:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OXID-eSales/graphql-configuration-access/eeebcc1d69a4286f1d8efb75907eaf944c7a679d/tests/Codeception/Data/testdata.sql
--------------------------------------------------------------------------------
/tests/Codeception/Support/AcceptanceTester.php:
--------------------------------------------------------------------------------
1 | create();
25 | $this->assertEquals(new Theme(), $theme);
26 |
27 | $anotherTheme = $coreThemeFactory->create();
28 | $this->assertNotSame($theme, $anotherTheme);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Integration/Infrastructure/ModuleListInfrastructureTest.php:
--------------------------------------------------------------------------------
1 | get(ShopConfigurationDaoBridgeInterface::class);
25 | $shopConfiguration = $shopConfigurationDaoBridge->get();
26 |
27 | $moduleConfiguration1 = new ModuleConfiguration();
28 | $moduleConfiguration1->setId('firstModule');
29 | $moduleConfiguration1->setTitle(['en' => 'Module 1']);
30 | $moduleConfiguration1->setDescription(['en' => 'Module 1 description']);
31 | $moduleConfiguration1->setLang('en');
32 | $moduleConfiguration1->setModuleSource('test');
33 |
34 | $moduleConfiguration2 = new ModuleConfiguration();
35 | $moduleConfiguration2->setId('secondModule');
36 | $moduleConfiguration2->setTitle(['en' => 'Module 2']);
37 | $moduleConfiguration2->setDescription(['en' => 'Module 2 description']);
38 | $moduleConfiguration2->setLang('en');
39 | $moduleConfiguration2->setModuleSource('test1');
40 |
41 | $shopConfiguration
42 | ->addModuleConfiguration($moduleConfiguration1)
43 | ->addModuleConfiguration($moduleConfiguration2);
44 | $shopConfigurationDaoBridge->save($shopConfiguration);
45 |
46 | $sut = $this->getSut();
47 | $modulesList = $sut->getModuleList();
48 | $this->assertCount(2, $modulesList);
49 | $this->assertInstanceOf(ModuleDataTypeInterface::class, $modulesList[0]);
50 | $this->assertInstanceOf(ModuleDataTypeInterface::class, $modulesList[1]);
51 | $this->assertSame($modulesList[0]->getId(), $moduleConfiguration1->getId());
52 | $this->assertSame($modulesList[1]->getId(), $moduleConfiguration2->getId());
53 | }
54 |
55 | public function getSut(): ModuleListInfrastructure
56 | {
57 | return new ModuleListInfrastructure(
58 | $this->get(ShopConfigurationDaoBridgeInterface::class),
59 | $this->get(ModuleDataTypeFactoryInterface::class)
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tests/Integration/Infrastructure/ThemeListInfrastructureTest.php:
--------------------------------------------------------------------------------
1 | getSut();
26 |
27 | $themesArray = $sut->getThemes();
28 | $this->assertNotEmpty($themesArray);
29 | $this->assertIsArray($themesArray);
30 |
31 | foreach ($themesArray as $theme) {
32 | $this->assertInstanceOf(ThemeDataTypeInterface::class, $theme);
33 | }
34 | }
35 |
36 | public function getSut(): ThemeListInfrastructure
37 | {
38 | return new ThemeListInfrastructure(
39 | $this->get(CoreThemeFactoryInterface::class),
40 | $this->get(ThemeDataTypeFactoryInterface::class)
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Integration/Service/ModuleBlockListServiceTest.php:
--------------------------------------------------------------------------------
1 | get(ProjectYamlDaoInterface::class)
28 | );
29 |
30 | $this->assertTrue($sut->isModuleBlocked('oe_graphql_base'));
31 | $this->assertTrue($sut->isModuleBlocked('oe_graphql_configuration_access'));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/PhpMd/exclude-ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 | Exclude Static Access Rule
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/tests/PhpMd/standard.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 | Standard OXID Ruleset
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tests/PhpStan/phpstan-bootstrap.php:
--------------------------------------------------------------------------------
1 | createMock(ModuleActivationServiceInterface::class);
26 | $moduleActivationServiceMock
27 | ->method('activateModule')
28 | ->with($moduleId)
29 | ->willReturn(true);
30 |
31 | $sut = $this->getSut(moduleActivationService: $moduleActivationServiceMock);
32 |
33 | $result = $sut->activateModule($moduleId);
34 | $this->assertTrue($result);
35 | }
36 |
37 | public function testDeactivateModule(): void
38 | {
39 | $moduleId = 'testModuleId';
40 |
41 | $moduleActivationServiceMock = $this->createMock(ModuleActivationServiceInterface::class);
42 | $moduleActivationServiceMock
43 | ->method('deactivateModule')
44 | ->with($moduleId)
45 | ->willReturn(true);
46 |
47 | $sut = $this->getSut(moduleActivationService: $moduleActivationServiceMock);
48 |
49 | $result = $sut->deactivateModule($moduleId);
50 | $this->assertTrue($result);
51 | }
52 |
53 | public function getSut(
54 | ModuleActivationServiceInterface $moduleActivationService = null
55 | ): ModuleActivationController {
56 | return new ModuleActivationController(
57 | moduleActivationService: $moduleActivationService
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Controller/ModuleListControllerTest.php:
--------------------------------------------------------------------------------
1 | createStub(ComponentFilters::class);
26 | $moduleStub1 = $this->createStub(ModuleDataTypeInterface::class);
27 | $moduleStub2 = $this->createStub(ModuleDataTypeInterface::class);
28 | $filteredModules = [$moduleStub1, $moduleStub2];
29 |
30 | $moduleListServiceMock = $this->createMock(ModuleListServiceInterface::class);
31 | $moduleListServiceMock->expects($this->once())
32 | ->method('getModuleList')
33 | ->with($filtersStub)
34 | ->willReturn($filteredModules);
35 |
36 | $sut = new ModuleListController($moduleListServiceMock);
37 | $actualModules = $sut->modules($filtersStub);
38 |
39 | $this->assertSame($filteredModules, $actualModules);
40 | }
41 |
42 | public function testModulesListWithoutFilters(): void
43 | {
44 | $moduleStub = $this->createStub(ModuleDataTypeInterface::class);
45 | $componentFilters = new ComponentFilters();
46 |
47 | $moduleListServiceSpy = $this->createMock(ModuleListServiceInterface::class);
48 | $moduleListServiceSpy->method('getModuleList')
49 | ->with($componentFilters)
50 | ->willReturn([$moduleStub]);
51 |
52 | $sut = new ModuleListController($moduleListServiceSpy);
53 | $resultModuleList = $sut->modules(null);
54 |
55 | $this->assertSame($resultModuleList, [$moduleStub]);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/Unit/Module/DataType/ModuleDataTypeFactoryTest.php:
--------------------------------------------------------------------------------
1 | uniqid(),
26 | 'en' => uniqid(),
27 | ];
28 | $descriptionData = [
29 | 'de' => uniqid(),
30 | 'en' => uniqid(),
31 | ];
32 | $expectedId = uniqid();
33 | $expectedVersion = uniqid();
34 | $expectedThumbnail = uniqid();
35 | $expectedAuthor = uniqid();
36 | $expectedUrl = uniqid();
37 | $expectedEmail = uniqid();
38 | $expectedLang = uniqid();
39 | $expectedIsActivated = (bool)random_int(0, 1);
40 |
41 | $moduleConfigMock = $this->createConfiguredStub(ModuleConfiguration::class, [
42 | 'getId' => $expectedId,
43 | 'getVersion' => $expectedVersion,
44 | 'getTitle' => $titlesData,
45 | 'getDescription' => $descriptionData,
46 | 'getThumbnail' => $expectedThumbnail,
47 | 'getAuthor' => $expectedAuthor,
48 | 'getUrl' => $expectedUrl,
49 | 'getEmail' => $expectedEmail,
50 | 'isActivated' => $expectedIsActivated,
51 | 'getLang' => $expectedLang
52 | ]);
53 |
54 | $languageServiceMock = $this->createMock(LanguageService::class);
55 | $languageServiceMock
56 | ->expects($this->exactly(2))
57 | ->method('filterByLanguageAbbreviation')
58 | ->willReturnMap([
59 | [$titlesData, $expectedLang, $titlesData['de']],
60 | [$descriptionData, $expectedLang, $descriptionData['de']]
61 | ]);
62 |
63 | $moduleDataTypeFactory = new ModuleDataTypeFactory($languageServiceMock);
64 | $moduleDataType = $moduleDataTypeFactory->createFromModuleConfiguration(moduleConfig: $moduleConfigMock);
65 |
66 | $this->assertSame($expectedId, $moduleDataType->getId());
67 | $this->assertSame($expectedVersion, $moduleDataType->getVersion());
68 | $this->assertSame($titlesData['de'], $moduleDataType->getTitle());
69 | $this->assertSame($descriptionData['de'], $moduleDataType->getDescription());
70 | $this->assertSame($expectedThumbnail, $moduleDataType->getThumbnail());
71 | $this->assertSame($expectedAuthor, $moduleDataType->getAuthor());
72 | $this->assertSame($expectedUrl, $moduleDataType->getUrl());
73 | $this->assertSame($expectedEmail, $moduleDataType->getEmail());
74 | $this->assertSame($expectedIsActivated, $moduleDataType->isActive());
75 | $this->assertSame($expectedLang, $moduleDataType->getLang());
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/Unit/Module/DataType/ModuleDataTypeTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ComponentDataTypeInterface::class, $moduleDataType);
44 | $this->assertSame($thumbnail, $moduleDataType->getThumbnail());
45 | $this->assertSame($author, $moduleDataType->getAuthor());
46 | $this->assertSame($url, $moduleDataType->getUrl());
47 | $this->assertSame($email, $moduleDataType->getEmail());
48 | $this->assertSame($lang, $moduleDataType->getLang());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Exception/ModuleActivationBlockedExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ModuleActivationBlockedException::class, $exception);
26 | $this->assertSame(
27 | sprintf('Module "%s" is in the blocklist and cannot be activated.', $moduleId),
28 | $exception->getMessage()
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Exception/ModuleActivationExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ModuleActivationException::class, $exception);
25 | $this->assertSame('An error occurred while activating the module.', $exception->getMessage());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Exception/ModuleDeactivationBlockedExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ModuleDeactivationBlockedException::class, $exception);
26 | $this->assertSame(
27 | sprintf('Module "%s" is in the blocklist and cannot be deactivated.', $moduleId),
28 | $exception->getMessage()
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Exception/ModuleDeactivationExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ModuleDeactivationException::class, $exception);
25 | $this->assertSame('An error occurred while deactivating the module.', $exception->getMessage());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Exception/ModulesNotFoundExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ModulesNotFoundException::class, $exception);
25 | $this->assertSame('Modules were not found.', $exception->getMessage());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Service/ModuleBlocklistServiceTest.php:
--------------------------------------------------------------------------------
1 | getFileName())['dirname'];
31 | $filePath = 'testFilePath.yaml';
32 | $expectedData = ['modules' => ['module1', 'module2']];
33 |
34 | $configWrapperMock = $this->createMock(DIConfigWrapper::class);
35 | $configWrapperMock
36 | ->method('getConfigAsArray')
37 | ->willReturn($expectedData);
38 |
39 | $projectYamlDaoMock = $this->createMock(ProjectYamlDaoInterface::class);
40 | $projectYamlDaoMock
41 | ->method('loadDIConfigFile')
42 | ->with($classFilePath . '/../' . $filePath)
43 | ->willReturn($configWrapperMock);
44 |
45 | $sut = $this->getSut(moduleBlockListPath: $filePath, projectYamlDao: $projectYamlDaoMock);
46 | $actualResult = $sut->isModuleBlocked(moduleId: $moduleId);
47 |
48 | $this->assertSame($expectedResult, $actualResult);
49 | }
50 |
51 | public static function blockListDataProvider(): \Generator
52 | {
53 | yield 'isModuleBlocked returns true if Module is in the BlockList' => [
54 | 'moduleId' => 'module1',
55 | 'expectedResult' => true
56 | ];
57 |
58 | yield 'isModuleBlocked returns false if Module is not in the BlockList' => [
59 | 'moduleId' => 'unknownModuleId',
60 | 'expectedResult' => false
61 | ];
62 | }
63 |
64 | private function getSut(
65 | string $moduleBlockListPath,
66 | ProjectYamlDaoInterface $projectYamlDao
67 | ): ModuleBlocklistService {
68 | return new ModuleBlocklistService(
69 | moduleBlocklistPath: $moduleBlockListPath,
70 | projectYamlDao: $projectYamlDao
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tests/Unit/Module/Service/ModuleListServiceTest.php:
--------------------------------------------------------------------------------
1 | createStub(ComponentFiltersInterface::class);
29 | $moduleStub1 = $this->createStub(ModuleDataTypeInterface::class);
30 | $moduleStub2 = $this->createStub(ModuleDataTypeInterface::class);
31 | $filteredModules = [$moduleStub1];
32 |
33 | $modulesConfigurations = [$moduleStub1, $moduleStub2];
34 |
35 | $moduleListInfrastructureMock = $this->createMock(ModuleListInfrastructureInterface::class);
36 | $moduleListInfrastructureMock->method('getModuleList')
37 | ->willReturn($modulesConfigurations);
38 |
39 | $componentFilterServiceMock = $this->createMock(ComponentFilterServiceInterface::class);
40 | $componentFilterServiceMock->method('filterComponents')
41 | ->with($modulesConfigurations, $filtersStub)
42 | ->willReturn($filteredModules);
43 |
44 | $sut = new ModuleListService(
45 | moduleListInfrastructure: $moduleListInfrastructureMock,
46 | componentFilterService: $componentFilterServiceMock,
47 | );
48 |
49 | $actualModules = $sut->getModuleList($filtersStub);
50 | $this->assertSame($filteredModules, $actualModules);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/DataType/AbstractComponentDataTypeTest.php:
--------------------------------------------------------------------------------
1 | assertSame($id, $component->getId());
32 | $this->assertSame($title, $component->getTitle());
33 | $this->assertSame($version, $component->getVersion());
34 | $this->assertSame($description, $component->getDescription());
35 | $this->assertSame($isActive, $component->isActive());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/DataType/BooleanSettingTest.php:
--------------------------------------------------------------------------------
1 | assertSame($name, $sut->getName());
26 | $this->assertSame($value, $sut->getValue());
27 | }
28 |
29 | public static function booleanSettingDataProvider(): \Generator
30 | {
31 | yield [uniqid(), true];
32 | yield [uniqid(), false];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/DataType/FloatSettingTest.php:
--------------------------------------------------------------------------------
1 | assertSame($name, $sut->getName());
26 | $this->assertSame($value, $sut->getValue());
27 | }
28 |
29 | public static function floatSettingDataProvider(): \Generator
30 | {
31 | yield "random float" => [uniqid(), rand(1, 100) / 10];
32 | yield "random integer" => [uniqid(), rand(1, 100)];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/DataType/IntegerSettingTest.php:
--------------------------------------------------------------------------------
1 | assertSame($name, $sut->getName());
26 | $this->assertSame($value, $sut->getValue());
27 | }
28 |
29 | public static function integerSettingDataProvider(): \Generator
30 | {
31 | yield "random integer" => [uniqid(), rand(1, 100)];
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/DataType/SettingTypeTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($settingIdentifier, $sut->getName());
32 | $this->assertEquals($settingType, $sut->getType());
33 | }
34 |
35 | /** @dataProvider isSupportedDataProvider */
36 | public function testIsSupported(string $settingType, bool $expectation): void
37 | {
38 | $sut = new SettingType(
39 | 'someSettingName',
40 | $settingType
41 | );
42 |
43 | $this->assertSame($expectation, $sut->isSupported());
44 | }
45 |
46 | public static function isSupportedDataProvider(): \Generator
47 | {
48 | yield 'not supported case' => ['settingType' => 'someRandomSettingId', 'expectation' => false];
49 | yield 'supported case' => ['settingType' => FieldType::ARRAY, 'expectation' => true];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/DataType/StringSettingTest.php:
--------------------------------------------------------------------------------
1 | assertSame($name, $sut->getName());
26 | $this->assertSame($value, $sut->getValue());
27 | }
28 |
29 | public static function stringSettingDataProvider(): \Generator
30 | {
31 | yield "random strings" => [uniqid(), uniqid()];
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Enum/FieldTypeTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(FieldType::validateFieldType($type));
24 | }
25 |
26 | public function testInvalidType(): void
27 | {
28 | $this->assertFalse(FieldType::validateFieldType('INVALID_FIELDTYPE'));
29 | }
30 |
31 | /** @dataProvider fieldTypesDataProvider */
32 | public function testGetEnums(string $type): void
33 | {
34 | $enums = FieldType::getEnums();
35 |
36 | $this->assertContains($type, $enums);
37 | }
38 |
39 | public static function fieldTypesDataProvider(): \Generator
40 | {
41 | yield [FieldType::ASSOCIATIVE_ARRAY];
42 | yield [FieldType::NUMBER];
43 | yield [FieldType::ARRAY];
44 | yield [FieldType::STRING];
45 | yield [FieldType::BOOLEAN];
46 | yield [FieldType::SELECT];
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Exception/CollectionEncodingExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertSame('Error encountered while encoding collection data', $sut->getMessage());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Exception/InvalidCollectionExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertSame(sprintf('%s is not a valid collection string.', $value), $sut->getMessage());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Exception/WrongSettingValueExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertSame('Wrong setting value', $sut->getMessage());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Infrastructure/LanguageWrapperTest.php:
--------------------------------------------------------------------------------
1 | createConfiguredStub(Language::class, [
25 | 'getLanguageAbbr' => $langAbbr,
26 | ]);
27 |
28 | $languageWrapper = new LanguageWrapper($languageMock);
29 | $actualLangAbbr = $languageWrapper->getCurrentLanguageAbbr();
30 |
31 | $this->assertSame($langAbbr, $actualLangAbbr);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Service/ComponentFilterServiceTest.php:
--------------------------------------------------------------------------------
1 | createMock(ComponentFiltersInterface::class);
29 | $componentFiltersMock->method('filterComponent')
30 | ->willReturnCallback(function (ComponentDataTypeInterface $component) use (&$filterResults) {
31 | return array_shift($filterResults);
32 | });
33 |
34 | $themeFilterService = new ComponentFilterService();
35 | $componentListResult = $themeFilterService->filterComponents($componentList, $componentFiltersMock);
36 | $this->assertSame($expectedComponentListResult, array_values($componentListResult));
37 | }
38 |
39 | public static function componentFilterResultProvider(): \Generator
40 | {
41 | $theme1 = self::createStub(ComponentDataTypeInterface::class);
42 | $theme2 = self::createStub(ComponentDataTypeInterface::class);
43 |
44 | yield "filter with filter results are both false" => [
45 | 'componentList' => [$theme1, $theme2],
46 | 'filterResults' => [false, false],
47 | 'expectedComponentListResult' => []
48 | ];
49 |
50 | yield "filter with only first filter result is true" => [
51 | 'componentList' => [$theme1, $theme2],
52 | 'filterResults' => [true, false],
53 | 'expectedComponentListResult' => [$theme1]
54 | ];
55 |
56 | yield "filter with only second filter result is true" => [
57 | 'componentList' => [$theme1, $theme2],
58 | 'filterResults' => [false, true],
59 | 'expectedComponentListResult' => [$theme2]
60 | ];
61 |
62 | yield "filter with both filter results are true" => [
63 | 'componentList' => [$theme1, $theme2],
64 | 'filterResults' => [true, true],
65 | 'expectedComponentListResult' => [$theme1, $theme2]
66 | ];
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Service/JsonCollectionEncodingServiceTest.php:
--------------------------------------------------------------------------------
1 | 'value'];
26 |
27 | $this->assertSame('{"some":"value"}', $sut->encodeArrayToString($value));
28 | }
29 |
30 | public function testJsonEncodeArrayException(): void
31 | {
32 | $sut = new JsonCollectionEncodingService();
33 | $value = [&$value];
34 |
35 | $this->expectException(CollectionEncodingException::class);
36 | $sut->encodeArrayToString($value);
37 | }
38 |
39 | /** @dataProvider jsonDecodeCollectionDataProvider */
40 | public function testJsonDecodeCollection(string $value, array $expectedResult): void
41 | {
42 | $sut = new JsonCollectionEncodingService();
43 |
44 | $this->assertEquals($expectedResult, $sut->decodeStringCollectionToArray($value));
45 | }
46 |
47 | public static function jsonDecodeCollectionDataProvider(): \Generator
48 | {
49 | yield [
50 | 'value' => '',
51 | 'expectedResult' => []
52 | ];
53 |
54 | yield [
55 | 'value' => '["apple","banana"]',
56 | 'expectedResult' => ["apple", "banana"]
57 | ];
58 |
59 | yield [
60 | 'value' => '{"name":"John","age":30}',
61 | 'expectedResult' => ["name" => "John", "age" => 30]
62 | ];
63 | }
64 |
65 | public function testJsonDecodeCollectionException(): void
66 | {
67 | $sut = new JsonCollectionEncodingService();
68 | $value = '[2, "values"';
69 |
70 | $this->expectException(InvalidCollectionException::class);
71 | $sut->decodeStringCollectionToArray($value);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Service/LanguageServiceTest.php:
--------------------------------------------------------------------------------
1 | 'Title in de language',
25 | 'en' => 'Title in en language',
26 | ];
27 | $expectedExistingLanguageAbbreviation = 'de';
28 |
29 | $languageWrapperMock = $this->createMock(LanguageWrapperInterface::class);
30 | $languageWrapperMock->method('getCurrentLanguageAbbr')
31 | ->willReturn($expectedExistingLanguageAbbreviation);
32 |
33 | $languageService = new LanguageService($languageWrapperMock);
34 | $actualResult = $languageService->filterByLanguageAbbreviation($titlesData, 'en');
35 |
36 | $this->assertSame($titlesData[$expectedExistingLanguageAbbreviation], $actualResult);
37 | }
38 |
39 | public function testFilterByLanguageAbbreviationDefaultedToEnglish()
40 | {
41 | $titlesData = [
42 | 'de' => 'Title in de language',
43 | 'en' => 'Title in en language',
44 | ];
45 | $defaultLangAbbr = 'en';
46 |
47 | $languageWrapperMock = $this->createMock(LanguageWrapperInterface::class);
48 | $languageWrapperMock->method('getCurrentLanguageAbbr')->willReturn('fr');
49 |
50 | $languageService = new LanguageService($languageWrapperMock);
51 | $actualResult = $languageService->filterByLanguageAbbreviation($titlesData, $defaultLangAbbr);
52 |
53 | $this->assertSame($titlesData[$defaultLangAbbr], $actualResult);
54 | }
55 |
56 | public function testFilterByLanguageAbbreviationDefaultedToFirstInArray()
57 | {
58 | $titlesData = [
59 | 'de' => 'Title in de language',
60 | 'en' => 'Title in en language',
61 | ];
62 |
63 | $languageWrapperMock = $this->createMock(LanguageWrapperInterface::class);
64 | $languageWrapperMock->expects($this->once())
65 | ->method('getCurrentLanguageAbbr')->willReturn('pl');
66 |
67 | $languageService = new LanguageService($languageWrapperMock);
68 | $actualResult = $languageService->filterByLanguageAbbreviation($titlesData, 'fr');
69 |
70 | $this->assertSame($titlesData['de'], $actualResult);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Service/NamespaceMapperTest.php:
--------------------------------------------------------------------------------
1 |
30 | self::$srcPath . '/Shared/Service/../../Module/Controller/',
31 | self::NAMESPACE_PREFIX . '\\Shop\\Controller' =>
32 | self::$srcPath . '/Shared/Service/../../Shop/Controller/',
33 | self::NAMESPACE_PREFIX . '\\Theme\\Controller' =>
34 | self::$srcPath . '/Shared/Service/../../Theme/Controller/',
35 | ];
36 |
37 | $sut = $this->getSut();
38 | $actualMapping = $sut->getControllerNamespaceMapping();
39 |
40 | $this->assertSame($expectedMapping, $actualMapping);
41 | }
42 |
43 | public function testGetTypeNamespaceMapping(): void
44 | {
45 | $expectedMapping = [
46 | self::NAMESPACE_PREFIX . '\\Shared\\DataType' =>
47 | self::$srcPath . '/Shared/Service/../../Shared/DataType/',
48 | self::NAMESPACE_PREFIX . '\\Theme\\DataType' =>
49 | self::$srcPath . '/Shared/Service/../../Theme/DataType/',
50 | self::NAMESPACE_PREFIX . '\\Module\\DataType' =>
51 | self::$srcPath . '/Shared/Service/../../Module/DataType/',
52 | ];
53 |
54 | $sut = $this->getSut();
55 | $actualMapping = $sut->getTypeNamespaceMapping();
56 |
57 | $this->assertSame($expectedMapping, $actualMapping);
58 | }
59 |
60 | private static function getSrcDirectoryPath(): string
61 | {
62 | $testsDir = 'tests';
63 | $currentPath = __DIR__;
64 | $testsPos = strpos($currentPath, $testsDir);
65 |
66 | if ($testsPos === false) {
67 | return $currentPath;
68 | }
69 |
70 | return substr($currentPath, 0, $testsPos) . 'src';
71 | }
72 |
73 | private function getSut(): NamespaceMapper
74 | {
75 | return new NamespaceMapper();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/Unit/Shared/Service/PermissionProviderTest.php:
--------------------------------------------------------------------------------
1 | [
21 | 'CHANGE_CONFIGURATION',
22 | 'LIST_THEMES',
23 | 'LIST_MODULES',
24 | 'ACTIVATE_MODULE'
25 | ],
26 | ];
27 |
28 | $permissionProvider = new PermissionProvider();
29 | $actualPermissions = $permissionProvider->getPermissions();
30 |
31 | $this->assertSame($expectedPermissions, $actualPermissions);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Unit/Shop/Exception/NoSettingsFoundForShopExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertMatchesRegularExpression("/for shop: 5$/", $sut->getMessage());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Unit/Shop/Exception/WrongSettingTypeExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertSame('Wrong setting type', $sut->getMessage());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Unit/Shop/Infrastructure/AbstractShopSettingRepositoryTestCase.php:
--------------------------------------------------------------------------------
1 | createStub(ContextInterface::class),
28 | queryBuilderFactory: $queryBuilderFactory ?? $this->createStub(QueryBuilderFactoryInterface::class),
29 | configurationSettingDao: $shopSettingDao ?? $this->createStub(ShopConfigurationSettingDaoInterface::class),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Controller/ThemeListControllerTest.php:
--------------------------------------------------------------------------------
1 | createStub(ThemeDataTypeInterface::class);
26 | $themeFilters = $this->createStub(ComponentFilters::class);
27 |
28 | $themeListServiceMock = $this->createMock(ThemeListServiceInterface::class);
29 | $themeListServiceMock->expects($this->once())
30 | ->method('getThemeList')
31 | ->with($themeFilters)
32 | ->willReturn([$theme]);
33 |
34 | $themeListController = new ThemeListController($themeListServiceMock);
35 | $resultedThemeList = $themeListController->themesList($themeFilters);
36 |
37 | $this->assertSame([$theme], $resultedThemeList);
38 | }
39 |
40 | public function testThemesListWithoutFilter(): void
41 | {
42 | $theme = $this->createStub(ThemeDataTypeInterface::class);
43 | $themeFilters = new ComponentFilters();
44 |
45 | $themeListServiceMock = $this->createMock(ThemeListServiceInterface::class);
46 | $themeListServiceMock->expects($this->once())
47 | ->method('getThemeList')
48 | ->with($themeFilters)
49 | ->willReturn([$theme]);
50 |
51 | $themeListController = new ThemeListController($themeListServiceMock);
52 | $resultedThemeList = $themeListController->themesList(null);
53 |
54 | $this->assertSame($resultedThemeList, [$theme]);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Controller/ThemeSwitchControllerTest.php:
--------------------------------------------------------------------------------
1 | createMock(ThemeSwitchServiceInterface::class);
27 | $themeSwitchServiceMock
28 | ->method('switchTheme')
29 | ->with($themeId)
30 | ->willReturn($expectedResult);
31 |
32 | $themeSwitchController = new ThemeSwitchController($themeSwitchServiceMock);
33 | $response = $themeSwitchController->switchTheme($themeId);
34 |
35 | $this->assertSame($expectedResult, $response);
36 | }
37 |
38 | public static function switchThemeProvider(): \Generator
39 | {
40 | yield 'test switch theme successful case' => [
41 | 'themeId' => 'validThemeId',
42 | 'expectedResult' => true
43 | ];
44 |
45 | yield 'test switch theme failure case' => [
46 | 'themeId' => 'invalidThemeId',
47 | 'expectedResult' => false
48 | ];
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/DataType/ThemeDataTypeFactoryTest.php:
--------------------------------------------------------------------------------
1 | createMock(Theme::class);
25 |
26 | $expectedTitle = uniqid();
27 | $expectedId = uniqid();
28 | $expectedVersion = uniqid();
29 | $expectedDescription = uniqid();
30 | $expectedActive = true;
31 | $expectedParentTheme = uniqid();
32 | $expectedParentVersions = [uniqid(), uniqid()];
33 |
34 | $themeMock->method('getInfo')
35 | ->willReturnMap([
36 | ['title', $expectedTitle],
37 | ['id', $expectedId],
38 | ['version', $expectedVersion],
39 | ['description', $expectedDescription],
40 | ['active', $expectedActive],
41 | ['parentTheme', $expectedParentTheme],
42 | ['parentVersions', $expectedParentVersions],
43 | ]);
44 |
45 | $factory = new ThemeDataTypeFactory();
46 | $themeDataType = $factory->createFromCoreTheme($themeMock);
47 |
48 | $this->assertInstanceOf(ThemeDataType::class, $themeDataType);
49 | $this->assertEquals($expectedTitle, $themeDataType->getTitle());
50 | $this->assertEquals($expectedId, $themeDataType->getId());
51 | $this->assertEquals($expectedVersion, $themeDataType->getVersion());
52 | $this->assertEquals($expectedDescription, $themeDataType->getDescription());
53 | $this->assertTrue($themeDataType->isActive());
54 | $this->assertEquals($expectedParentTheme, $themeDataType->getParentTheme());
55 | $this->assertEquals($expectedParentVersions, $themeDataType->getParentVersions());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/DataType/ThemeDataTypeTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ComponentDataTypeInterface::class, $sut);
35 | $this->assertSame($name, $sut->getTitle());
36 | $this->assertSame($id, $sut->getId());
37 | $this->assertSame($version, $sut->getVersion());
38 | $this->assertSame($description, $sut->getDescription());
39 | $this->assertSame($active, $sut->isActive());
40 | $this->assertSame($parentTheme, $sut->getParentTheme());
41 | $this->assertSame($parentVersions, $sut->getParentVersions());
42 | }
43 |
44 | public function testThemeDataTypeWithNullableValues(): void
45 | {
46 | $name = uniqid();
47 | $id = uniqid();
48 | $version = uniqid();
49 | $description = uniqid();
50 | $active = (bool)random_int(0, 1);
51 | $parentTheme = null;
52 | $parentVersions = null;
53 |
54 | $sut = new ThemeDataType($id, $name, $version, $description, $active, $parentTheme, $parentVersions);
55 |
56 | $this->assertNull($sut->getParentTheme());
57 | $this->assertNull($sut->getParentVersions());
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Exception/NoSettingsFoundForThemeExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertMatchesRegularExpression("/for theme: someTheme$/", $sut->getMessage());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Exception/ThemeActivationExceptionTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ThemeActivationException::class, $exception);
28 | $this->assertSame(self::THEME_NOT_ACTIVATED_MESSAGE, $exception->getMessage());
29 | }
30 |
31 | public function testThemeActivationExceptionWithMessage()
32 | {
33 | $message = uniqid();
34 | $exception = new ThemeActivationException($message);
35 |
36 | $this->assertInstanceOf(ThemeActivationException::class, $exception);
37 | $this->assertSame($message, $exception->getMessage());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Exception/ThemesNotFoundTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ThemesNotFound::class, $exception);
25 | $this->assertSame('No themes were found.', $exception->getMessage());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Infrastructure/AbstractThemeSettingRepositoryTestCase.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(ThemeSettingRepository::class)
30 | ->setConstructorArgs([
31 | $context ?? $this->createMock(ContextInterface::class),
32 | $eventDispatcher ?? $this->createMock(EventDispatcherInterface::class),
33 | $queryBuilderFactory ?? $this->createMock(QueryBuilderFactoryInterface::class),
34 | $settingEncoder ?? $this->createMock(ShopSettingEncoderInterface::class)
35 | ])
36 | ->onlyMethods($methods ?? [])
37 | ->getMock();
38 | return $repository;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Infrastructure/ThemeListInfrastructureTest.php:
--------------------------------------------------------------------------------
1 | createStub(Theme::class);
28 | $theme2 = $this->createStub(Theme::class);
29 | $themeDataType1 = $this->createStub(ThemeDataType::class);
30 | $themeDataType2 = $this->createStub(ThemeDataType::class);
31 |
32 | $coreThemeMock = $this->createMock(Theme::class);
33 | $coreThemeMock->method('getList')->willReturn([$theme1, $theme2]);
34 | $coreThemeFactoryMock = $this->getCoreThemeFactoryMock(returnValue: $coreThemeMock);
35 |
36 | $themeDataTypeFactory = $this->createMock(ThemeDataTypeFactoryInterface::class);
37 | $themeDataTypeFactory->method('createFromCoreTheme')->willReturnMap([
38 | [$theme1, $themeDataType1],
39 | [$theme2, $themeDataType2]
40 | ]);
41 |
42 | $sut = $this->getSut(coreThemeFactory: $coreThemeFactoryMock, themeDataTypeFactory: $themeDataTypeFactory);
43 | $actualThemesArray = $sut->getThemes();
44 | $this->assertSame([$themeDataType1, $themeDataType2], $actualThemesArray);
45 | }
46 |
47 | public function testGetThemesThrowsException(): void
48 | {
49 | $coreThemeMock = $this->createMock(Theme::class);
50 | $coreThemeMock->method('getList')->willReturn([]);
51 | $coreThemeFactoryMock = $this->getCoreThemeFactoryMock(returnValue: $coreThemeMock);
52 |
53 | $sut = $this->getSut(coreThemeFactory: $coreThemeFactoryMock);
54 |
55 | $this->expectException(ThemesNotFound::class);
56 | $sut->getThemes();
57 | }
58 |
59 | private function getSut(
60 | CoreThemeFactoryInterface $coreThemeFactory = null,
61 | ThemeDataTypeFactoryInterface $themeDataTypeFactory = null
62 | ): ThemeListInfrastructure {
63 | return new ThemeListInfrastructure(
64 | coreThemeFactory: $coreThemeFactory ?? $this->createStub(CoreThemeFactoryInterface::class),
65 | themeDataTypeFactory: $themeDataTypeFactory ?? $this->createStub(ThemeDataTypeFactoryInterface::class)
66 | );
67 | }
68 |
69 | private function getCoreThemeFactoryMock(Theme $returnValue): CoreThemeFactoryInterface
70 | {
71 | $coreThemeFactoryMock = $this->createMock(CoreThemeFactoryInterface::class);
72 | $coreThemeFactoryMock->method('create')
73 | ->willReturn($returnValue);
74 |
75 | return $coreThemeFactoryMock;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Infrastructure/ThemeSettingRepositorySettersTest.php:
--------------------------------------------------------------------------------
1 | getSut(methods: ['getSettingValue', 'saveSettingValue']);
31 | $sut->method('getSettingValue')
32 | ->with($name, $this->logicalOr(...FieldType::getEnums()), $themeId)
33 | ->willThrowException(new NoSettingsFoundForThemeException($themeId));
34 | $sut->expects($this->never())
35 | ->method('saveSettingValue');
36 |
37 | $this->expectException(NoSettingsFoundForThemeException::class);
38 |
39 | $sut->$repositoryMethod($name, $value, $themeId);
40 | }
41 |
42 | public static function notExistingSettingCheckTriggerDataProvider(): \Generator
43 | {
44 | yield "saveIntegerSetting" => [
45 | 'repositoryMethod' => 'saveIntegerSetting',
46 | 'value' => 1234
47 | ];
48 | yield "saveFloatSetting" => [
49 | 'repositoryMethod' => 'saveFloatSetting',
50 | 'value' => 1.23
51 | ];
52 | yield "saveBooleanSetting" => [
53 | 'repositoryMethod' => 'saveBooleanSetting',
54 | 'value' => true
55 | ];
56 | yield "saveStringSetting" => [
57 | 'repositoryMethod' => 'saveStringSetting',
58 | 'value' => 'some string'
59 | ];
60 | yield "saveSelectSetting" => [
61 | 'repositoryMethod' => 'saveSelectSetting',
62 | 'value' => 'some select'
63 | ];
64 | yield "saveCollectionSetting" => [
65 | 'repositoryMethod' => 'saveCollectionSetting',
66 | 'value' => ['collection']
67 | ];
68 | yield "saveAssocCollectionSetting" => [
69 | 'repositoryMethod' => 'saveAssocCollectionSetting',
70 | 'value' => ['collection']
71 | ];
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Service/ThemeListServiceTest.php:
--------------------------------------------------------------------------------
1 | createStub(ThemeDataTypeInterface::class);
29 | $themeDataType2 = $this->createStub(ThemeDataTypeInterface::class);
30 | $themes = [$themeDataType1, $themeDataType2];
31 | $filteredThemeList = [$themeDataType1];
32 |
33 | $themeListInfrastructureMock = $this->createMock(ThemeListInfrastructureInterface::class);
34 | $themeListInfrastructureMock->method('getThemes')->willReturn($themes);
35 |
36 | $componentFiltersStub = $this->createStub(ComponentFiltersInterface::class);
37 |
38 | $componentFilterServiceMock = $this->createMock(ComponentFilterServiceInterface::class);
39 | $componentFilterServiceMock->method('filterComponents')
40 | ->with($themes, $componentFiltersStub)
41 | ->willReturn($filteredThemeList);
42 |
43 | $themeListService = new ThemeListService(
44 | themeListInfrastructure: $themeListInfrastructureMock,
45 | componentFilterService: $componentFilterServiceMock,
46 | );
47 | $actualThemes = $themeListService->getThemeList($componentFiltersStub);
48 | $this->assertSame($filteredThemeList, $actualThemes);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/Unit/Theme/Service/ThemeSwitchServiceTest.php:
--------------------------------------------------------------------------------
1 | createMock(ThemeSwitchInfrastructureInterface::class);
27 | $themeSwitchInfrastructureMock
28 | ->method('switchTheme')
29 | ->with($themeId)
30 | ->willReturn($expectedResult);
31 |
32 | $themeSwitchInfrastructure = new ThemeSwitchService($themeSwitchInfrastructureMock);
33 | $response = $themeSwitchInfrastructure->switchTheme($themeId);
34 |
35 | $this->assertSame($expectedResult, $response);
36 | }
37 |
38 | public static function switchThemeProvider(): \Generator
39 | {
40 | yield 'test switch theme successful case' => [
41 | 'expectedResult' => true
42 | ];
43 |
44 | yield 'test switch theme failure case' => [
45 | 'expectedResult' => false
46 | ];
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Unit/UnitTestCase.php:
--------------------------------------------------------------------------------
1 | createMock(ContextInterface::class);
34 | $context->method('getCurrentShopId')->willReturn($shopId);
35 |
36 | return $context;
37 | }
38 |
39 | protected function getJsonEncodeServiceMock(
40 | array $repositoryResult,
41 | string $collectionEncodingResult
42 | ): CollectionEncodingServiceInterface {
43 | $jsonService = $this->createMock(CollectionEncodingServiceInterface::class);
44 | $jsonService->method('encodeArrayToString')
45 | ->with($repositoryResult)
46 | ->willReturn($collectionEncodingResult);
47 | return $jsonService;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/codeception.yml:
--------------------------------------------------------------------------------
1 | namespace: OxidEsales\GraphQL\ConfigurationAccess\Tests\Codeception
2 | params:
3 | - Codeception/Config/params.php
4 | paths:
5 | tests: Codeception
6 | output: Codeception/_output
7 | data: Codeception/Data
8 | support: Codeception/Support
9 | envs: Codeception/_envs
10 | actor_suffix: Tester
11 |
12 | settings:
13 | colors: true
14 | log: true
15 | memory_limit: 4096M
16 |
17 | extensions:
18 | enabled:
19 | - Codeception\Extension\RunFailed
20 |
21 | coverage:
22 | enabled: true
23 | remote: false
24 | local: true
25 | c3_url: '%SHOP_URL%'
26 | remote_config: 'vendor/oxid-esales/graphql-configuration-access/tests/codeception.yml'
27 | include:
28 | - ../src/*
29 |
--------------------------------------------------------------------------------
/tests/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Oxid Coding Standard
4 |
5 |
6 | ../src/
7 | ./
8 | ./tests/Codeception/Config
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ./migration
21 |
22 |
23 |
24 |
25 | ./tests
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 | Unit/
22 |
23 |
24 | Integration
25 |
26 |
27 |
28 |
29 | ../src
30 |
31 |
32 | ../tests
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------