diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 8ceba8c..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: CI - -on: [push, pull_request] - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - typo3: [^10.4, ^9.5] - php: ['7.4', '7.3'] - os: [ubuntu-latest] - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up PHP Version ${{ matrix.php }} - run: | - sudo update-alternatives --set php /usr/bin/php${{ matrix.php }} - php -v - - name: Validate composer.json and composer.lock - run: composer validate - - - name: Cache dependencies - uses: actions/cache@v1 - with: - path: ~/.composer/cache - key: dependencies-composer-${{ hashFiles('composer.json') }} - - - name: Install dependencies with typo3/cms-core:${{ matrix.typo3 }} - run: | - composer require typo3/cms-core:${{ matrix.typo3 }} --no-progress - composer require typo3/cms-backend:${{ matrix.typo3 }} --no-progress - composer require typo3/cms-frontend:${{ matrix.typo3 }} --no-progress - git checkout composer.json - - - name: php-cs-fixer - run: composer ci:php:fixer - - - name: Lint PHP - run: composer ci:php:lint - - - name: Unit Tests - run: | - composer ci:tests:unit - -# - name: Functional Tests -# env: -# typo3DatabaseName: test -# typo3DatabaseUsername: root -# typo3DatabasePassword: root -# typo3DatabaseHost: 127.0.0.1 -# run: | -# sudo systemctl start mysql.service -# composer ci:tests:functional diff --git a/.github/workflows/core12.yml b/.github/workflows/core12.yml new file mode 100644 index 0000000..ae2c42f --- /dev/null +++ b/.github/workflows/core12.yml @@ -0,0 +1,30 @@ +name: core 12 + +on: [ push, pull_request ] + +jobs: + tests: + name: v12 + runs-on: ubuntu-20.04 + strategy: + # This prevents cancellation of matrix job runs, if one/two already failed and let the + # rest matrix jobs be executed anyway. + fail-fast: false + matrix: + php: [ '8.1', '8.2' ] + composerInstall: [ 'composerInstallLowest', 'composerInstallHighest' ] + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install testing system + run: Build/Scripts/runTests.sh -t 12 -p ${{ matrix.php }} -s ${{ matrix.composerInstall }} + + - name: Lint PHP + run: Build/Scripts/runTests.sh -t 12 -p ${{ matrix.php }} -s lint + + - name: Validate code against CGL + run: PHP_CS_FIXER_IGNORE_ENV=1 Build/Scripts/runTests.sh -t 12 -p 8.1 -s cgl -n + +# - name: Unit Tests +# run: Build/Scripts/runTests.sh -t 12 -p ${{ matrix.php }} -s unit \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1c1b0b6..cfbb31e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ Todos.md .php_cs.cache /Documentation-GENERATED-temp +.build/ +Build/.phpunit.result.cache +composer.lock +/.php-cs-fixer.cache +/var \ No newline at end of file diff --git a/.php_cs.dist b/.php_cs.dist deleted file mode 100644 index e92a844..0000000 --- a/.php_cs.dist +++ /dev/null @@ -1,61 +0,0 @@ -setRiskyAllowed(true) - ->setRules([ - '@PSR2' => true, - - 'general_phpdoc_annotation_remove' => [ - 'author' - ], - 'no_leading_import_slash' => true, - 'no_trailing_comma_in_singleline_array' => true, - 'no_singleline_whitespace_before_semicolons' => true, - 'no_unused_imports' => true, - 'concat_space' => ['spacing' => 'one'], - 'no_whitespace_in_blank_line' => true, - 'ordered_imports' => true, - 'single_quote' => true, - 'no_empty_statement' => true, - 'no_extra_consecutive_blank_lines' => true, - 'phpdoc_no_package' => true, - 'phpdoc_scalar' => true, - 'no_blank_lines_after_phpdoc' => true, - 'array_syntax' => ['syntax' => 'short'], - 'whitespace_after_comma_in_array' => true, - 'function_typehint_space' => true, - 'hash_to_slash_comment' => true, - 'no_alias_functions' => true, - 'lowercase_cast' => true, - 'no_leading_namespace_whitespace' => true, - 'native_function_casing' => true, - 'self_accessor' => true, - 'no_short_bool_cast' => true, - 'no_unneeded_control_parentheses' => true - ]) - ->setFinder( - PhpCsFixer\Finder::create() - ->exclude('.build') - ->exclude('var') - ->in(__DIR__) - ); diff --git a/.phplint.yml b/.phplint.yml deleted file mode 100644 index 2576d5b..0000000 --- a/.phplint.yml +++ /dev/null @@ -1,7 +0,0 @@ -path: ./ -jobs: 10 -cache: .phplint.cache -extensions: - - php -exclude: - - .build diff --git a/Build/FunctionalTests.xml b/Build/FunctionalTests.xml deleted file mode 100644 index 593e514..0000000 --- a/Build/FunctionalTests.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - ../Tests/Functional - - - - - - - - - - ../Classes/ - - - diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh new file mode 100755 index 0000000..e69fa03 --- /dev/null +++ b/Build/Scripts/runTests.sh @@ -0,0 +1,481 @@ +#!/usr/bin/env bash + +# +# TYPO3 core test runner based on docker and docker-compose. +# +IMAGE_PREFIX="ghcr.io/typo3/" + +# Function to write a .env file in Build/testing-docker +# This is read by docker-compose and vars defined here are +# used in Build/testing-docker/docker-compose.yml +setUpDockerComposeDotEnv() { + # Delete possibly existing local .env file if exists + [ -e .env ] && rm .env + # Set up a new .env file for docker-compose + { + echo "COMPOSE_PROJECT_NAME=${PROJECT_NAME}" + # To prevent access rights of files created by the testing, the docker image later + # runs with the same user that is currently executing the script. docker-compose can't + # use $UID directly itself since it is a shell variable and not an env variable, so + # we have to set it explicitly here. + echo "HOST_UID=`id -u`" + # Your local user + echo "ROOT_DIR=${ROOT_DIR}" + echo "HOST_USER=${USER}" + echo "TEST_FILE=${TEST_FILE}" + echo "TYPO3_VERSION=${TYPO3_VERSION}" + echo "PHP_XDEBUG_ON=${PHP_XDEBUG_ON}" + echo "PHP_XDEBUG_PORT=${PHP_XDEBUG_PORT}" + echo "DOCKER_PHP_IMAGE=${DOCKER_PHP_IMAGE}" + echo "EXTRA_TEST_OPTIONS=${EXTRA_TEST_OPTIONS}" + echo "SCRIPT_VERBOSE=${SCRIPT_VERBOSE}" + echo "CGLCHECK_DRY_RUN=${CGLCHECK_DRY_RUN}" + echo "DATABASE_DRIVER=${DATABASE_DRIVER}" + echo "MARIADB_VERSION=${MARIADB_VERSION}" + echo "MYSQL_VERSION=${MYSQL_VERSION}" + echo "POSTGRES_VERSION=${POSTGRES_VERSION}" + echo "USED_XDEBUG_MODES=${USED_XDEBUG_MODES}" + echo "IMAGE_PREFIX=${IMAGE_PREFIX}" + } > .env +} + +# Options -a and -d depend on each other. The function +# validates input combinations and sets defaults. +handleDbmsAndDriverOptions() { + case ${DBMS} in + mysql|mariadb) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid option -a ${DATABASE_DRIVER} with -d ${DBMS}" >&2 + echo >&2 + echo "call \"./Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + postgres|sqlite) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid option -a ${DATABASE_DRIVER} with -d ${DBMS}" >&2 + echo >&2 + echo "call \"./Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + esac +} + +# Load help text into $HELP +read -r -d '' HELP <=20.10 for xdebug break pointing to work reliably, and +a recent docker-compose (tested >=1.21.2) is needed. + +Usage: $0 [options] [file] + +No arguments: Run all unit tests with PHP 7.4 + +Options: + -s <...> + Specifies which test suite to run + - cgl: cgl test and fix all php files + - clean: clean up build and testing related files + - composer: Execute "composer" command, using -e for command arguments pass-through, ex. -e "ci:php:stan" + - composerInstall: "composer update", handy if host has no PHP + - composerInstallLowest: "composer update", handy if host has no PHP + - composerInstallHighest: "composer update", handy if host has no PHP + - functional: functional tests + - lint: PHP linting + - unit: PHP unit tests + + -a + Only with -s acceptance,functional + Specifies to use another driver, following combinations are available: + - mysql + - mysqli (default) + - pdo_mysql + - mariadb + - mysqli (default) + - pdo_mysql + + -d + Only with -s acceptance,functional + Specifies on which DBMS tests are performed + - sqlite: (default) use sqlite + - mariadb: use mariadb + - mysql: use mysql + - postgres: use postgres + + -i <10.2|10.3|10.4|10.5|10.6|10.7> + Only with -d mariadb + Specifies on which version of mariadb tests are performed + - 10.2 (default) + - 10.3 + - 10.4 + - 10.5 + - 10.6 + - 10.7 + + -j <5.5|5.6|5.7|8.0> + Only with -d mysql + Specifies on which version of mysql tests are performed + - 5.5 (default) + - 5.6 + - 5.7 + - 8.0 + + -k <10|11|12|13|14> + Only with -d postgres + Specifies on which version of postgres tests are performed + - 10 (default) + - 11 + - 12 + - 13 + - 14 + + -p <7.4|8.0|8.1|8.2> + Specifies the PHP minor version to be used + - 7.4 (default): use PHP 7.4 + - 8.0: use PHP 8.0 + - 8.1: use PHP 8.1 + - 8.2: use PHP 8.2 + + -t <11|12> + Only with -s composerUpdate + Specifies the TYPO3 core major version to be used + - 11 (default): use TYPO3 core v11 + - 12: use TYPO3 core v12 + + -e "" + Only with -s functional|unit|composer + Additional options to send to phpunit (unit & functional tests) or codeception (acceptance + tests). For phpunit, options starting with "--" must be added after options starting with "-". + Example -e "-v --filter canRetrieveValueWithGP" to enable verbose output AND filter tests + named "canRetrieveValueWithGP" + + -x + Only with -s functional|unit + Send information to host instance for test or system under test break points. This is especially + useful if a local PhpStorm instance is listening on default xdebug port 9003. A different port + can be selected with -y + + -y + Send xdebug information to a different port than default 9003 if an IDE like PhpStorm + is not listening on default port. + + -z + Only with -x and -s functional|unit|acceptance + This sets the used xdebug modes. Defaults to 'debug,develop' + + -n + Only with -s cgl + Activate dry-run in CGL check that does not actively change files and only prints broken ones. + + -u + Update existing ${IMAGE_PREFIX}core-testing-*:latest docker images. Maintenance call to docker pull latest + versions of the main php images. The images are updated once in a while and only the youngest + ones are supported by core testing. Use this if weird test errors occur. Also removes obsolete + image versions of ${IMAGE_PREFIX}core-testing-*. + + -v + Enable verbose script output. Shows variables and docker commands. + + -h + Show this help. + +Examples: + # Run unit tests using PHP 7.4 + ./Build/Scripts/runTests.sh -s unit +EOF + +# Test if docker-compose exists, else exit out with error +if ! type "docker-compose" > /dev/null; then + echo "This script relies on docker and docker-compose. Please install" >&2 + exit 1 +fi + +# Go to the directory this script is located, so everything else is relative +# to this dir, no matter from where this script is called. +THIS_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +cd "$THIS_SCRIPT_DIR" || exit 1 + +# Go to directory that contains the local docker-compose.yml file +cd ../testing-docker || exit 1 + +# Option defaults +if ! command -v realpath &> /dev/null; then + echo "This script works best with realpath installed" >&2 + ROOT_DIR="${PWD}/../../" +else + ROOT_DIR=`realpath ${PWD}/../../` +fi +TEST_SUITE="" +DBMS="sqlite" +PHP_VERSION="7.4" +TYPO3_VERSION="11" +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +EXTRA_TEST_OPTIONS="" +SCRIPT_VERBOSE=0 +CGLCHECK_DRY_RUN="" +DATABASE_DRIVER="" +MARIADB_VERSION="10.2" +MYSQL_VERSION="5.5" +POSTGRES_VERSION="10" +USED_XDEBUG_MODES="debug,develop" +#@todo the $$ would add the current process id to the name, keeping as plan b +#PROJECT_NAME="runTests-$(basename $(dirname $ROOT_DIR))-$(basename $ROOT_DIR)-$$" +PROJECT_NAME="runtestsriddle" +PROJECT_NAME="${PROJECT_NAME//[[:blank:]]/}" +echo $PROJECT_NAME + +# Option parsing +# Reset in case getopts has been used previously in the shell +OPTIND=1 +# Array for invalid options +INVALID_OPTIONS=(); +# Simple option parsing based on getopts (! not getopt) +while getopts ":s:a:d:i:j:k:p:t:e:xy:z:nhuv" OPT; do + case ${OPT} in + s) + TEST_SUITE=${OPTARG} + ;; + a) + DATABASE_DRIVER=${OPTARG} + ;; + d) + DBMS=${OPTARG} + ;; + i) + MARIADB_VERSION=${OPTARG} + if ! [[ ${MARIADB_VERSION} =~ ^(10.2|10.3|10.4|10.5|10.6|10.7)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + j) + MYSQL_VERSION=${OPTARG} + if ! [[ ${MYSQL_VERSION} =~ ^(5.5|5.6|5.7|8.0)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + k) + POSTGRES_VERSION=${OPTARG} + if ! [[ ${POSTGRES_VERSION} =~ ^(10|11|12|13|14)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(7.4|8.0|8.1|8.2)$ ]]; then + INVALID_OPTIONS+=("p ${OPTARG}") + fi + ;; + t) + TYPO3_VERSION=${OPTARG} + if ! [[ ${TYPO3_VERSION} =~ ^(11|12)$ ]]; then + INVALID_OPTIONS+=("p ${OPTARG}") + fi + ;; + e) + EXTRA_TEST_OPTIONS=${OPTARG} + ;; + x) + PHP_XDEBUG_ON=1 + ;; + y) + PHP_XDEBUG_PORT=${OPTARG} + ;; + z) + USED_XDEBUG_MODES=${OPTARG} + ;; + h) + echo "${HELP}" + exit 0 + ;; + n) + CGLCHECK_DRY_RUN="-n" + ;; + u) + TEST_SUITE=update + ;; + v) + SCRIPT_VERBOSE=1 + ;; + \?) + INVALID_OPTIONS+=(${OPTARG}) + ;; + :) + INVALID_OPTIONS+=(${OPTARG}) + ;; + esac +done + +# Exit on invalid options +if [ ${#INVALID_OPTIONS[@]} -ne 0 ]; then + echo "Invalid option(s):" >&2 + for I in "${INVALID_OPTIONS[@]}"; do + echo "-"${I} >&2 + done + echo >&2 + echo "${HELP}" >&2 + exit 1 +fi + +# Move "7.2" to "php72", the latter is the docker container name +DOCKER_PHP_IMAGE=`echo "php${PHP_VERSION}" | sed -e 's/\.//'` + +# Set $1 to first mass argument, this is the optional test file or test directory to execute +shift $((OPTIND - 1)) +TEST_FILE=${1} + +if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x +fi + +if [ -z ${TEST_SUITE} ]; then + echo "${HELP}" + exit 0 +fi + +# Suite execution +case ${TEST_SUITE} in + cgl) + # Active dry-run for cgl needs not "-n" but specific options + if [[ ! -z ${CGLCHECK_DRY_RUN} ]]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + setUpDockerComposeDotEnv + docker-compose run cgl + SUITE_EXIT_CODE=$? + docker-compose down + ;; + clean) + rm -rf \ + ../../var/ \ + ../../.cache \ + ../../composer.lock \ + ../../.Build/ \ + ../../Tests/Acceptance/Support/_generated/ \ + ../../composer.json.testing + ;; + composer) + setUpDockerComposeDotEnv + docker-compose run composer + SUITE_EXIT_CODE=$? + docker-compose down + ;; + composerInstall) + setUpDockerComposeDotEnv + cp ../../composer.json ../../composer.json.orig + if [ -f "../../composer.json.testing" ]; then + cp ../../composer.json ../../composer.json.orig + fi + docker-compose run composer_install + cp ../../composer.json ../../composer.json.testing + mv ../../composer.json.orig ../../composer.json + SUITE_EXIT_CODE=$? + docker-compose down + ;; + composerInstallLowest) + setUpDockerComposeDotEnv + cp ../../composer.json ../../composer.json.orig + if [ -f "../../composer.json.testing" ]; then + cp ../../composer.json ../../composer.json.orig + fi + docker-compose run composer_install_lowest + cp ../../composer.json ../../composer.json.testing + mv ../../composer.json.orig ../../composer.json + SUITE_EXIT_CODE=$? + docker-compose down + ;; + composerInstallHighest) + setUpDockerComposeDotEnv + cp ../../composer.json ../../composer.json.orig + if [ -f "../../composer.json.testing" ]; then + cp ../../composer.json ../../composer.json.orig + fi + docker-compose run composer_install_highest + cp ../../composer.json ../../composer.json.testing + mv ../../composer.json.orig ../../composer.json + SUITE_EXIT_CODE=$? + docker-compose down + ;; + coveralls) + setUpDockerComposeDotEnv + docker-compose run coveralls + SUITE_EXIT_CODE=$? + docker-compose down + ;; + functional) + handleDbmsAndDriverOptions + setUpDockerComposeDotEnv + case ${DBMS} in + mariadb) + echo "Using driver: ${DATABASE_DRIVER}" + docker-compose run functional_mariadb + SUITE_EXIT_CODE=$? + ;; + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + docker-compose run functional_mysql + SUITE_EXIT_CODE=$? + ;; + postgres) + docker-compose run functional_postgres + SUITE_EXIT_CODE=$? + ;; + sqlite) + # sqlite has a tmpfs as Web/typo3temp/var/tests/functional-sqlite-dbs/ + # Since docker is executed as root (yay!), the path to this dir is owned by + # root if docker creates it. Thank you, docker. We create the path beforehand + # to avoid permission issues. + mkdir -p ${ROOT_DIR}/Web/typo3temp/var/tests/functional-sqlite-dbs/ + docker-compose run functional_sqlite + SUITE_EXIT_CODE=$? + ;; + *) + echo "Invalid -d option argument ${DBMS}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 + esac + docker-compose down + ;; + lint) + setUpDockerComposeDotEnv + docker-compose run lint + SUITE_EXIT_CODE=$? + docker-compose down + ;; + phpstan) + setUpDockerComposeDotEnv + docker-compose run phpstan + SUITE_EXIT_CODE=$? + docker-compose down + ;; + phpstanGenerateBaseline) + setUpDockerComposeDotEnv + docker-compose run phpstan_generate_baseline + SUITE_EXIT_CODE=$? + docker-compose down + ;; + unit) + setUpDockerComposeDotEnv + docker-compose run unit + SUITE_EXIT_CODE=$? + docker-compose down + ;; + update) + # pull ${IMAGE_PREFIX}core-testing-*:latest versions of those ones that exist locally + docker images ${IMAGE_PREFIX}core-testing-*:latest --format "{{.Repository}}:latest" | xargs -I {} docker pull {} + # remove "dangling" ${IMAGE_PREFIX}core-testing-* images (those tagged as ) + docker images ${IMAGE_PREFIX}core-testing-* --filter "dangling=true" --format "{{.ID}}" | xargs -I {} docker rmi {} + ;; + *) + echo "Invalid -s option argument ${TEST_SUITE}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 +esac + +exit $SUITE_EXIT_CODE diff --git a/Build/UnitTests.xml b/Build/UnitTests.xml deleted file mode 100644 index 252baba..0000000 --- a/Build/UnitTests.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - ../Tests/Unit - - - - - ../Classes/ - - - diff --git a/Build/php-cs-fixer/php-cs-fixer.php b/Build/php-cs-fixer/php-cs-fixer.php new file mode 100644 index 0000000..9533bde --- /dev/null +++ b/Build/php-cs-fixer/php-cs-fixer.php @@ -0,0 +1,76 @@ +setHeader( + 'This file is part of the "riddle" Extension for TYPO3 CMS. + +For the full copyright and license information, please read the +LICENSE.txt file that was distributed with this source code.', + true +); +$config->setFinder( + (new PhpCsFixer\Finder()) + ->in(realpath(__DIR__ . '/../../')) + ->ignoreVCSIgnored(true) + ->notPath('/^.Build\//') + ->notPath('/^Build\/php-cs-fixer\/php-cs-fixer.php/') + ->notPath('/^Build\/phpunit\/(UnitTestsBootstrap|FunctionalTestsBootstrap).php/') + ->notPath('/^Configuration\//') + ->notPath('/^Documentation\//') + ->notName('/^ext_(emconf|localconf|tables).php/') +) + ->setRiskyAllowed(true) + ->setRules([ + '@DoctrineAnnotation' => true, + '@PER' => true, + 'array_syntax' => ['syntax' => 'short'], + 'blank_line_after_opening_tag' => true, + 'braces' => ['allow_single_line_closure' => true], + 'cast_spaces' => ['space' => 'none'], + 'compact_nullable_typehint' => true, + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => ['space' => 'none'], + 'dir_constant' => true, + 'function_typehint_space' => true, + 'lowercase_cast' => true, + 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'], + 'modernize_types_casting' => true, + 'native_function_casing' => true, + 'new_with_braces' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_null_property_initialization' => true, + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_superfluous_elseif' => true, + 'no_trailing_comma_in_singleline' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_nullsafe_operator' => true, + 'no_whitespace_in_blank_line' => true, + 'ordered_imports' => true, + 'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']], + 'php_unit_mock_short_will_return' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'phpdoc_no_access' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_scalar' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'return_type_declaration' => ['space_before' => 'none'], + 'single_quote' => true, + 'single_line_comment_style' => ['comment_types' => ['hash']], + 'single_trait_insert_per_statement' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + 'whitespace_after_comma_in_array' => ['ensure_single_space' => true], + 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], + ]); +return $config; diff --git a/Build/phpunit/FunctionalTests.xml b/Build/phpunit/FunctionalTests.xml new file mode 100644 index 0000000..80156d2 --- /dev/null +++ b/Build/phpunit/FunctionalTests.xml @@ -0,0 +1,52 @@ + + + + + + ../../Tests/Functional/ + + + + + + + + + + diff --git a/Build/phpunit/FunctionalTestsBootstrap.php b/Build/phpunit/FunctionalTestsBootstrap.php new file mode 100644 index 0000000..a95bc52 --- /dev/null +++ b/Build/phpunit/FunctionalTestsBootstrap.php @@ -0,0 +1,30 @@ +defineOriginalRootPath(); + $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests'); + $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/transient'); +})(); diff --git a/Build/phpunit/UnitTests.xml b/Build/phpunit/UnitTests.xml new file mode 100644 index 0000000..d09d8ef --- /dev/null +++ b/Build/phpunit/UnitTests.xml @@ -0,0 +1,45 @@ + + + + + + ../../Tests/Unit/ + + + + + + + diff --git a/Build/phpunit/UnitTestsBootstrap.php b/Build/phpunit/UnitTestsBootstrap.php new file mode 100644 index 0000000..8b4ead3 --- /dev/null +++ b/Build/phpunit/UnitTestsBootstrap.php @@ -0,0 +1,85 @@ +getWebRoot(), '/')); + } + if (!getenv('TYPO3_PATH_WEB')) { + putenv('TYPO3_PATH_WEB=' . rtrim($testbase->getWebRoot(), '/')); + } + + $testbase->defineSitePath(); + + $composerMode = defined('TYPO3_COMPOSER_MODE') && TYPO3_COMPOSER_MODE === true; + $requestType = \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::REQUESTTYPE_BE | \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::REQUESTTYPE_CLI; + \TYPO3\TestingFramework\Core\SystemEnvironmentBuilder::run(0, $requestType, $composerMode); + + $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3conf/ext'); + $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/assets'); + $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/var/tests'); + $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/var/transient'); + + // Retrieve an instance of class loader and inject to core bootstrap + $classLoader = require $testbase->getPackagesPath() . '/autoload.php'; + \TYPO3\CMS\Core\Core\Bootstrap::initializeClassLoader($classLoader); + + // Initialize default TYPO3_CONF_VARS + $configurationManager = new \TYPO3\CMS\Core\Configuration\ConfigurationManager(); + $GLOBALS['TYPO3_CONF_VARS'] = $configurationManager->getDefaultConfiguration(); + + $cache = new \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend( + 'core', + new \TYPO3\CMS\Core\Cache\Backend\NullBackend('production', []) + ); + + // Set all packages to active + if (interface_exists(\TYPO3\CMS\Core\Package\Cache\PackageCacheInterface::class)) { + $packageManager = \TYPO3\CMS\Core\Core\Bootstrap::createPackageManager(\TYPO3\CMS\Core\Package\UnitTestPackageManager::class, \TYPO3\CMS\Core\Core\Bootstrap::createPackageCache($cache)); + } else { + // v10 compatibility layer + // @deprecated Will be removed when v10 compat is dropped from testing-framework + $packageManager = \TYPO3\CMS\Core\Core\Bootstrap::createPackageManager(\TYPO3\CMS\Core\Package\UnitTestPackageManager::class, $cache); + } + + \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance(\TYPO3\CMS\Core\Package\PackageManager::class, $packageManager); + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::setPackageManager($packageManager); + + $testbase->dumpClassLoadingInformation(); + + \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances(); +})(); diff --git a/Build/testing-docker/.env b/Build/testing-docker/.env new file mode 100644 index 0000000..5381120 --- /dev/null +++ b/Build/testing-docker/.env @@ -0,0 +1,18 @@ +COMPOSE_PROJECT_NAME=runtestsriddle +HOST_UID=502 +ROOT_DIR=/Users/georg.ringer/projects/priv/t3-12/packages/riddle +HOST_USER=georg.ringer +TEST_FILE= +TYPO3_VERSION=12 +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +DOCKER_PHP_IMAGE=php82 +EXTRA_TEST_OPTIONS= +SCRIPT_VERBOSE=0 +CGLCHECK_DRY_RUN= +DATABASE_DRIVER= +MARIADB_VERSION=10.2 +MYSQL_VERSION=5.5 +POSTGRES_VERSION=10 +USED_XDEBUG_MODES=debug,develop +IMAGE_PREFIX=ghcr.io/typo3/ diff --git a/Build/testing-docker/docker-compose.yml b/Build/testing-docker/docker-compose.yml new file mode 100644 index 0000000..8fcbd83 --- /dev/null +++ b/Build/testing-docker/docker-compose.yml @@ -0,0 +1,427 @@ +version: '2.3' +services: + #--------------------------------------------------------------------------------------------------------------------- + # additional services needed for functional tests to be linked, e.g. databases + #--------------------------------------------------------------------------------------------------------------------- + mysql: + image: mysql:${MYSQL_VERSION} + environment: + MYSQL_ROOT_PASSWORD: funcp + tmpfs: + - /var/lib/mysql/:rw,noexec,nosuid + + mariadb: + image: mariadb:${MARIADB_VERSION} + environment: + MYSQL_ROOT_PASSWORD: funcp + tmpfs: + - /var/lib/mysql/:rw,noexec,nosuid + + postgres: + image: postgres:${POSTGRES_VERSION}-alpine + environment: + POSTGRES_PASSWORD: funcp + POSTGRES_USER: funcu + tmpfs: + - /var/lib/postgresql/data:rw,noexec,nosuid + + #--------------------------------------------------------------------------------------------------------------------- + # composer related services + #--------------------------------------------------------------------------------------------------------------------- + composer: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + composer ${EXTRA_TEST_OPTIONS}; + " + + composer_install: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${TYPO3_VERSION} -eq 11 ]; then + composer require --no-ansi --no-interaction --no-progress --no-install \ + typo3/cms-core:^11.5.24 + fi + if [ ${TYPO3_VERSION} -eq 12 ]; then + composer require --no-ansi --no-interaction --no-progress --no-install \ + typo3/cms-core:^12.2 + fi + composer install --no-progress; + " + + composer_install_lowest: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${TYPO3_VERSION} -eq 11 ]; then + composer require --no-ansi --no-interaction --no-progress --no-install \ + typo3/cms-core:^11.5.24 + fi + if [ ${TYPO3_VERSION} -eq 12 ]; then + composer require --no-ansi --no-interaction --no-progress --no-install \ + typo3/cms-core:^12.0 + fi + composer update --no-ansi --no-interaction --no-progress --with-dependencies --prefer-lowest; + composer show; + " + + composer_install_highest: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + if [ ${TYPO3_VERSION} -eq 11 ]; then + composer require --no-ansi --no-interaction --no-progress --no-install \ + typo3/cms-core:^11.5.24 + fi + if [ ${TYPO3_VERSION} -eq 12 ]; then + composer require --no-ansi --no-interaction --no-progress --no-install \ + typo3/cms-core:^12.2 + fi + composer update --no-progress --no-interaction; + composer show; + " + + #--------------------------------------------------------------------------------------------------------------------- + # unit tests + #--------------------------------------------------------------------------------------------------------------------- + unit: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + XDEBUG_MODE=\"${USED_XDEBUG_MODES}\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_host=host.docker.internal\" \ + .Build/bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " + + lint: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + find . -name \\*.php ! -path "./.Build/\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null + " + + #--------------------------------------------------------------------------------------------------------------------- + # functional tests against different dbms + #--------------------------------------------------------------------------------------------------------------------- + functional_sqlite: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + tmpfs: + - ${ROOT_DIR}/public/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid,uid=${HOST_UID} + environment: + typo3DatabaseDriver: pdo_sqlite + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + else + XDEBUG_MODE=\"${USED_XDEBUG_MODES}\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + fi + " + + functional_postgres: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + links: + - postgres + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: pdo_pgsql + typo3DatabaseName: bamboo + typo3DatabaseUsername: funcu + typo3DatabaseHost: postgres + typo3DatabasePassword: funcp + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z postgres 5432; do + sleep 1; + done; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + else + XDEBUG_MODE=\"${USED_XDEBUG_MODES}\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + fi + " + + functional_mysql: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + links: + - mysql + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: "${DATABASE_DRIVER}" + typo3DatabaseName: func_test + typo3DatabaseUsername: root + typo3DatabasePassword: funcp + typo3DatabaseHost: mysql + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z mysql 3306; do + sleep 1; + done; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + XDEBUG_MODE=\"${USED_XDEBUG_MODES}\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " + + functional_mariadb: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + links: + - mariadb + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: "${DATABASE_DRIVER}" + typo3DatabaseName: func_test + typo3DatabaseUsername: root + typo3DatabasePassword: funcp + typo3DatabaseHost: mariadb + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z mariadb 3306; do + sleep 1; + done; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + XDEBUG_MODE=\"${USED_XDEBUG_MODES}\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " + + #--------------------------------------------------------------------------------------------------------------------- + # code quality tools + #--------------------------------------------------------------------------------------------------------------------- + cgl: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + php -dxdebug.mode=off \ + .Build/bin/php-cs-fixer fix \ + -v \ + ${CGLCHECK_DRY_RUN} \ + --config=Build/php-cs-fixer/php-cs-fixer.php \ + --using-cache=no . + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + PHP_CS_FIXER_ALLOW_XDEBUG=1 \ + .Build/bin/php-cs-fixer fix \ + -v \ + ${CGLCHECK_DRY_RUN} \ + --config=Build/php-cs-fixer/php-cs-fixer.php \ + --using-cache=no . + fi + " + + coveralls: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + XDEBUG_MODE=\"coverage\" \ + php -dxdebug.mode=off ./.Build/bin/php-coveralls --coverage_clover=./.Build/logs/clover.xml --json_path=./.Build/logs/coveralls-upload.json -v + " + + phpstan: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + mkdir -p .cache + php -dxdebug.mode=off .Build/bin/phpstan analyze -c ./phpstan.neon --no-progress + " + + phpstan_generate_baseline: + image: ${IMAGE_PREFIX}core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + COMPOSER_HOME: ".cache/composer-home" + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + mkdir -p .cache + php -dxdebug.mode=off .Build/bin/phpstan analyze -c ./phpstan.neon --generate-baseline=./phpstan-baseline.neon --allow-empty-baseline + " diff --git a/Classes/Api/RiddleApi.php b/Classes/Api/RiddleApi.php index b6a6911..e5c2554 100644 --- a/Classes/Api/RiddleApi.php +++ b/Classes/Api/RiddleApi.php @@ -16,12 +16,10 @@ use GuzzleHttp\HandlerStack; use StudioMitte\Riddle\ExtensionConfiguration; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\StringUtility; class RiddleApi { - private const ENDPOINT = 'https://www.riddle.com/api/v2/'; - private const ENDPOINTV2 = 'https://www.riddle.com/creator/v2/api/'; + private const ENDPOINT = 'https://www.riddle.com/api/v3/'; /** @var ExtensionConfiguration */ protected $extensionConfiguration; @@ -33,81 +31,50 @@ public function __construct(ExtensionConfiguration $extensionConfiguration = nul public function getRiddleList(): array { - if (!$this->extensionConfiguration->isV1Enabled()) { - return []; - } - return $this->request('riddle/get/list'); - } - - public function getRiddleListV2(): array - { - if (!$this->extensionConfiguration->isV2Enabled()) { - return []; - } - return $this->request('riddle/list', 'POST', true); + return $this->request('riddle/list'); } - public function getRiddleItem(int $id): array + public function getRiddleItem(string $id): array { - $all = $this->getRiddleList(); - foreach ($all['response']['items'] as $item) { - if ((int)$item['id'] === $id) { + foreach ($this->getRiddleList() as $item) { + if ($item['UUID'] === $id) { return $item; } } return []; } - public function getRiddleItemV2(string $id): array - { - $data = $this->request('riddle/' . $id, 'GET', true); - return $data['data'] ?? []; - } - - public function getEmbedCode(int $id): ?array + public function getEmbedCode(string $id): ?string { - return $this->request('riddle/get/embed-code?riddleId=' . $id); - } - - public function getEmbedCodeV2(string $id): string - { - return (string)$this->request('riddle/embed-code/' . $id, 'GET', true); + return $this->request('riddle/embed-code/' . $id, 'GET'); } /** * @return array|string */ - protected function request(string $action, $method = 'GET', $isV2 = false) + protected function request(string $action, $method = 'POST') { $client = $this->getClient(); $headers = [ 'Accept' => 'application/json', ]; - if ($isV2) { - $uri = self::ENDPOINTV2 . trim($action, '/'); - $headers['X-RIDDLE-BEARER'] = 'Bearer ' . $this->extensionConfiguration->getApiTokenV2(); - } else { - $uri = self::ENDPOINT . trim($action, '/'); - $headers['Authorization'] = 'Bearer ' . $this->extensionConfiguration->getApiToken(); - $headers['Key'] = $this->extensionConfiguration->getApiKey(); - } + + $uri = self::ENDPOINT . trim($action, '/'); + $headers['X-RIDDLE-BEARER'] = 'Bearer ' . $this->extensionConfiguration->getApiKey(); $options['headers'] = $headers; $response = $client->request($method, $uri, $options); if ($response->getStatusCode() === 200) { - if ($isV2 && StringUtility::beginsWith($action, 'riddle/embed-code')) { + if (\str_starts_with($action, 'riddle/embed-code')) { return $response->getBody()->getContents(); - } else { - return json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); } - return json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); + return json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR)['data']; } throw new \UnexpectedValueException('Error for riddle request: ' . $response->getStatusCode(), 1597956586); } - /** * Creates the client to do requests * @return ClientInterface @@ -126,4 +93,3 @@ private function getClient(): ClientInterface return GeneralUtility::makeInstance(Client::class, $httpOptions); } } - diff --git a/Classes/Backend/Element/SelectSingleElementWithNoIcon.php b/Classes/Backend/Element/SelectSingleElementWithNoIcon.php index e005714..e41f016 100644 --- a/Classes/Backend/Element/SelectSingleElementWithNoIcon.php +++ b/Classes/Backend/Element/SelectSingleElementWithNoIcon.php @@ -18,7 +18,6 @@ */ class SelectSingleElementWithNoIcon extends SelectSingleElement { - /** * @inheritDoc */ diff --git a/Classes/Backend/EventListener/BackendPreviewEventListener.php b/Classes/Backend/EventListener/BackendPreviewEventListener.php new file mode 100644 index 0000000..3ba1faf --- /dev/null +++ b/Classes/Backend/EventListener/BackendPreviewEventListener.php @@ -0,0 +1,67 @@ +getTable() !== 'tt_content') { + return; + } + + if ($event->getRecord()['CType'] === 'list' && $event->getRecord()['list_type'] === 'riddle_riddle') { + $riddleId = RiddleUtility::getRiddleId($event->getRecord()['pi_flexform']); + + $standaloneView = $this->getView(); + try { + $standaloneView->assignMultiple([ + 'riddleId' => $riddleId, + 'riddle' => $this->getRiddleData($riddleId), + ]); + } catch (ApiConfigurationMissingException $exception) { + $standaloneView->assign('apiNotConfigured', true); + } + + $event->setPreviewContent($standaloneView->render()); + } + } + + protected function getView(): StandaloneView + { + $standaloneView = GeneralUtility::makeInstance(StandaloneView::class); + $standaloneView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->template)); + $standaloneView->assignMultiple([ + 'dateTime' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], + 'lll' => 'LLL:EXT:riddle/Resources/Private/Language/locallang.xlf:', + ]); + return $standaloneView; + } + + /** + * @param string|int $id + * @return array + */ + protected function getRiddleData($id): array + { + $api = GeneralUtility::makeInstance(RiddleApi::class); + $item = $api->getRiddleItem($id); + return RiddleUtility::enrichRiddleData($item); + } +} diff --git a/Classes/Backend/FieldWizard/ExternalIcons.php b/Classes/Backend/FieldWizard/ExternalIcons.php index 3ef8724..4de7368 100644 --- a/Classes/Backend/FieldWizard/ExternalIcons.php +++ b/Classes/Backend/FieldWizard/ExternalIcons.php @@ -32,17 +32,17 @@ public function render(): array $selectItems = $parameterArray['fieldConf']['config']['items']; $selectItemCounter = 0; foreach ($selectItems as $item) { - if ($item[1] === '--div--') { + if ($item['value'] === '') { continue; } - $icon = $item[2] ?? ''; + $icon = $item['icon'] ?? ''; if ($icon) { - $fieldValue = $this->data['databaseRow'][$this->data['fieldName']]; + $fieldValue = $this->data['databaseRow'][$this->data['fieldName']]['data']['sDEF']['lDEF']['riddle']['vDEF'][0] ?? ''; $selectIcons[] = [ - 'title' => $item[0], - 'active' => ($fieldValue[0] === (string)$item[1]) ? true : false, + 'title' => $item['label'], + 'active' => ($fieldValue === (string)$item['value']) ? true : false, 'icon' => $icon, - 'index' => $selectItemCounter, + 'index' => $selectItemCounter + 1, ]; } $selectItemCounter++; @@ -50,20 +50,18 @@ public function render(): array $html = []; if (!empty($selectIcons)) { - $html[] = '
'; - $html[] = '
'; + $html[] = '
'; foreach ($selectIcons as $i => $selectIcon) { $active = $selectIcon['active'] ? ' active' : ''; - $html[] = '
'; + $html[] = '
'; if (is_array($selectIcon)) { - $html[] = ''; + $html[] = ''; $html[] = sprintf('', $selectIcon['icon']); $html[] = ''; } $html[] = '
'; } $html[] = '
'; - $html[] = '
'; } $result['html'] = implode(LF, $html); diff --git a/Classes/Controller/ManagementController.php b/Classes/Controller/ManagementController.php index 4835105..7efd57e 100644 --- a/Classes/Controller/ManagementController.php +++ b/Classes/Controller/ManagementController.php @@ -12,6 +12,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Http\HtmlResponse; use TYPO3\CMS\Core\Localization\LanguageService; +use TYPO3\CMS\Core\Page\PageRenderer; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Fluid\View\StandaloneView; use TYPO3Fluid\Fluid\View\ViewInterface; @@ -38,10 +39,10 @@ class ManagementController /** @var LogRepository */ protected $logRepository; - public function __construct() + public function __construct(private PageRenderer $pageRenderer) { $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class); - $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Modal'); + $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal'); $this->getLanguageService()->includeLLFile('EXT:riddle/Resources/Private/Language/locallang.xlf'); $this->logRepository = GeneralUtility::makeInstance(LogRepository::class); } @@ -85,7 +86,6 @@ protected function exportLogs(LogDemand $demand) ->setPage(1); $riddles = $this->logRepository->findByDemandForExport($demand); - $fp = fopen('php://output', 'wb'); header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="export.csv"'); @@ -94,7 +94,7 @@ protected function exportLogs(LogDemand $demand) fputcsv($fp, array_keys($riddles[0])); foreach ($riddles as $row) { fputcsv($fp, array_values($row)); - }; + } fclose($fp); die; } @@ -113,7 +113,7 @@ protected function preparePagination(LogDemand $demand, int $count): array 'hasLessPages' => $demand->getPage() > 1, 'hasMorePages' => $demand->getPage() < $numberOfPages, 'startRecord' => $demand->getOffset() + 1, - 'endRecord' => $endRecord + 'endRecord' => $endRecord, ]; if ($pagination['current'] < $pagination['numberOfPages']) { $pagination['nextPage'] = $pagination['current'] + 1; diff --git a/Classes/Controller/PluginController.php b/Classes/Controller/PluginController.php index c58f275..aa7d1e3 100644 --- a/Classes/Controller/PluginController.php +++ b/Classes/Controller/PluginController.php @@ -14,14 +14,16 @@ use StudioMitte\Riddle\Api\RiddleApi; use StudioMitte\Riddle\Utility\RiddleUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; class PluginController extends ContentObjectRenderer { + protected ContentObjectRenderer $cObj; - /** @var ContentObjectRenderer */ - protected $cObj; + public function setContentObjectRenderer(ContentObjectRenderer $cObj): void + { + $this->cObj = $cObj; + } public function run(): string { @@ -34,20 +36,11 @@ public function run(): string return ''; } - if (MathUtility::canBeInterpretedAsInteger($riddleId)) { - return $this->getRiddleHtml((int)$riddleId); - } - return $this->getRiddleHtmlV2($riddleId); - } - - protected function getRiddleHtml(int $id): string - { - $response = GeneralUtility::makeInstance(RiddleApi::class)->getEmbedCode($id); - return (string)($response['response'] ?? ''); + return $this->getRiddleHtml($riddleId); } - protected function getRiddleHtmlV2(string $id): string + protected function getRiddleHtml(string $id): string { - return GeneralUtility::makeInstance(RiddleApi::class)->getEmbedCodeV2($id); + return GeneralUtility::makeInstance(RiddleApi::class)->getEmbedCode($id); } } diff --git a/Classes/Domain/Dto/LogDemand.php b/Classes/Domain/Dto/LogDemand.php index ccb5644..6413031 100644 --- a/Classes/Domain/Dto/LogDemand.php +++ b/Classes/Domain/Dto/LogDemand.php @@ -8,7 +8,6 @@ class LogDemand { - /** @var string */ protected $type = ''; @@ -51,7 +50,6 @@ public function getId(): int return $this->id; } - /** * The current Page of the paginated redirects * @@ -107,8 +105,4 @@ public function setPage(int $page): LogDemand $this->page = $page; return $this; } - - - - } diff --git a/Classes/Domain/LogItem.php b/Classes/Domain/LogItem.php index 3c3ebde..ba49775 100644 --- a/Classes/Domain/LogItem.php +++ b/Classes/Domain/LogItem.php @@ -6,7 +6,6 @@ class LogItem { - public static function convert(array $raw): array { $raw = $raw['data']; @@ -25,7 +24,7 @@ public static function convert(array $raw): array 'result_id' => $raw['resultData']['resultId'] ?? '', 'lead_name' => $raw['lead2']['Name']['value'] ?? '', 'lead_email' => $raw['lead2']['Email']['value'] ?? '', - 'full_json' => json_encode($raw, JSON_THROW_ON_ERROR) + 'full_json' => json_encode($raw, JSON_THROW_ON_ERROR), ]; return $data; diff --git a/Classes/Domain/Repository/LogRepository.php b/Classes/Domain/Repository/LogRepository.php index 84c2911..233329b 100644 --- a/Classes/Domain/Repository/LogRepository.php +++ b/Classes/Domain/Repository/LogRepository.php @@ -12,7 +12,6 @@ class LogRepository { - private const TABLE = 'tx_riddle_log'; public function add(array $item): void @@ -98,9 +97,7 @@ public function getGroupingInformation(): array $rows = $queryBuilder ->select($field) - ->from(self::TABLE) - ->groupBy($field) - ->execute() + ->from(self::TABLE)->groupBy($field)->executeQuery() ->fetchAll(); foreach ($rows as $row) { @@ -115,5 +112,4 @@ protected function getConnection(): Connection { return GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(self::TABLE); } - } diff --git a/Classes/ExtensionConfiguration.php b/Classes/ExtensionConfiguration.php index 7287e8e..f351b6f 100644 --- a/Classes/ExtensionConfiguration.php +++ b/Classes/ExtensionConfiguration.php @@ -16,10 +16,7 @@ class ExtensionConfiguration implements SingletonInterface { - protected string $apiKey = ''; - protected string $apiToken = ''; - protected string $apiTokenV2 = ''; public function __construct() { @@ -28,8 +25,6 @@ public function __construct() if (is_array($configuration)) { $this->apiKey = (string)($configuration['apiKey'] ?? ''); - $this->apiToken = (string)($configuration['apiToken'] ?? ''); - $this->apiTokenV2 = (string)($configuration['apiTokenV2'] ?? ''); } } catch (\Exception $e) { } @@ -39,25 +34,4 @@ public function getApiKey(): string { return $this->apiKey; } - - public function getApiToken(): string - { - return $this->apiToken; - } - - public function getApiTokenV2(): string - { - return $this->apiTokenV2; - } - - public function isV1Enabled(): bool - { - return $this->apiKey && $this->apiToken; - } - - public function isV2Enabled(): bool - { - return (bool)$this->apiTokenV2; - } - } diff --git a/Classes/Hooks/ItemsProcFunc.php b/Classes/Hooks/ItemsProcFunc.php index 3690fa7..74a1fea 100644 --- a/Classes/Hooks/ItemsProcFunc.php +++ b/Classes/Hooks/ItemsProcFunc.php @@ -10,10 +10,10 @@ * For the full copyright and license information, please read the * LICENSE.txt file that was distributed with this source code. */ - use StudioMitte\Riddle\Api\RiddleApi; use StudioMitte\Riddle\Utility\RiddleUtility; use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\Messaging\AbstractMessage; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -26,18 +26,7 @@ class ItemsProcFunc public function riddleList(array &$config): void { try { - $riddles2 = $this->getAllRiddlesV2(); - if ($riddles2) { - $config['items'][] = ['V2', '--div--']; - } - foreach ($riddles2 as $item) { - $config['items'][] = $this->getSelectItem($item); - } - $riddles = $this->getAllRiddles(); - if ($riddles) { - $config['items'][] = ['V1', '--div--']; - } foreach ($riddles as $item) { $config['items'][] = $this->getSelectItem($item, false); } @@ -47,7 +36,7 @@ public function riddleList(array &$config): void FlashMessage::class, $e->getMessage(), '', - FlashMessage::ERROR + AbstractMessage::ERROR ); GeneralUtility::makeInstance(FlashMessageService::class) ->getMessageQueueByIdentifier() @@ -58,39 +47,18 @@ public function riddleList(array &$config): void protected function getSelectItem(array $item, bool $isV2 = true): array { - if ($isV2) { - $item = RiddleUtility::enrichRiddleData($item); - $date = $item['_enriched']['datepublished'] ? BackendUtility::date($item['_enriched']['datepublished']) : $item['created']['at'] ?? ''; - return [ - sprintf('%s [%s] - %s', $item['title'], $item['type'] ?? '-', $date), - $item['UUID'], - $item['image'] ?? '', - ]; - } - $item = RiddleUtility::enrichRiddleData($item); - - $date = $item['_enriched']['datepublished'] ? BackendUtility::date($item['_enriched']['datepublished']) : $item['datepublished']; + $date = $item['_enriched']['datepublished'] ? BackendUtility::date($item['_enriched']['datepublished']) : $item['created']['at'] ?? ''; return [ sprintf('%s [%s] - %s', $item['title'], $item['type'] ?? '-', $date), - $item['id'], - $item['thumb'] ?? '', + $item['UUID'], + $item['image'] ?? '', ]; } protected function getAllRiddles(): array { $api = GeneralUtility::makeInstance(RiddleApi::class); - $response = $api->getRiddleList(); - - return $response['response']['items'] ?? []; - } - - protected function getAllRiddlesV2(): array - { - $api = GeneralUtility::makeInstance(RiddleApi::class); - $response = $api->getRiddleListV2(); - - return $response['data'] ?? []; + return $api->getRiddleList(); } } diff --git a/Classes/Hooks/PageLayoutView.php b/Classes/Hooks/PageLayoutView.php deleted file mode 100644 index 4b7afa0..0000000 --- a/Classes/Hooks/PageLayoutView.php +++ /dev/null @@ -1,74 +0,0 @@ -getView(); - try { - $standaloneView->assignMultiple([ - 'riddleId' => $riddleId, - 'riddle' => $this->getRiddleData($riddleId), - 'riddleV2' => !MathUtility::canBeInterpretedAsInteger($riddleId) - ]); - } catch (ApiConfigurationMissingException $exception) { - $standaloneView->assign('apiNotConfigured', true); - } - return $standaloneView->render(); - } - - protected function getView(): StandaloneView - { - $standaloneView = GeneralUtility::makeInstance(StandaloneView::class); - $standaloneView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->template)); - $standaloneView->assignMultiple([ - 'dateTime' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], - 'lll' => 'LLL:EXT:riddle/Resources/Private/Language/locallang.xlf:', - ]); - return $standaloneView; - } - - /** - * @param string|int $id - * @return array - */ - protected function getRiddleData($id): array - { - $api = GeneralUtility::makeInstance(RiddleApi::class); - if (MathUtility::canBeInterpretedAsInteger($id)) { - $item = $api->getRiddleItem((int)$id); - } else { - $item = $api->getRiddleItemV2($id); - } - return RiddleUtility::enrichRiddleData($item); - } -} diff --git a/Classes/Middleware/WebhookEndpoint.php b/Classes/Middleware/WebhookEndpoint.php index 2de6220..3ff9bc6 100644 --- a/Classes/Middleware/WebhookEndpoint.php +++ b/Classes/Middleware/WebhookEndpoint.php @@ -1,4 +1,5 @@ getUri()->getPath(), self::ENDPOINT)) { + ): ResponseInterface { + if (!\str_starts_with($request->getUri()->getPath(), self::ENDPOINT)) { return $handler->handle($request); } $json = $request->getParsedBody()['data'] ?? ''; @@ -44,5 +42,4 @@ public function process( } return new JsonResponse(['status' => 'ok']); } - } diff --git a/Classes/Utility/RiddleUtility.php b/Classes/Utility/RiddleUtility.php index de63c0a..e55bd14 100644 --- a/Classes/Utility/RiddleUtility.php +++ b/Classes/Utility/RiddleUtility.php @@ -16,7 +16,6 @@ class RiddleUtility { - /** * Enrich the API riddle response * @@ -61,6 +60,6 @@ public static function getRiddleId(string $flexforms) return ''; } $data = GeneralUtility::makeInstance(FlexFormService::class)->convertFlexFormContentToArray($flexforms); - return ($data['riddle'] ?? ''); + return $data['riddle'] ?? ''; } } diff --git a/Configuration/FlexForms/flexform_riddle.xml b/Configuration/FlexForms/flexform_riddle.xml index 629a61b..ec829f5 100644 --- a/Configuration/FlexForms/flexform_riddle.xml +++ b/Configuration/FlexForms/flexform_riddle.xml @@ -22,10 +22,10 @@ - + ExternalIcons 0 - + diff --git a/Configuration/RequestMiddlewares.php b/Configuration/RequestMiddlewares.php index 032497e..a658e40 100644 --- a/Configuration/RequestMiddlewares.php +++ b/Configuration/RequestMiddlewares.php @@ -5,11 +5,11 @@ 'studiomitte/riddle/router' => [ 'target' => \StudioMitte\Riddle\Middleware\WebhookEndpoint::class, 'after' => [ - 'typo3/cms-frontend/site' + 'typo3/cms-frontend/site', ], 'before' => [ - 'typo3/cms-frontend/static-route-resolver' - ] + 'typo3/cms-frontend/static-route-resolver', + ], ], ], ]; diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml new file mode 100644 index 0000000..532edd0 --- /dev/null +++ b/Configuration/Services.yaml @@ -0,0 +1,12 @@ +services: + _defaults: + autowire: true + autoconfigure: true + + StudioMitte\Riddle\: + resource: '../Classes/*' + + StudioMitte\Riddle\Backend\EventListener\BackendPreviewEventListener: + tags: + - name: event.listener + identifier: 'riddle/riddle' \ No newline at end of file diff --git a/Configuration/TCA/tx_riddle_log.php b/Configuration/TCA/tx_riddle_log.php index e5dbbf6..b8a044e 100644 --- a/Configuration/TCA/tx_riddle_log.php +++ b/Configuration/TCA/tx_riddle_log.php @@ -5,17 +5,16 @@ 'title' => 'LLL:EXT:plain_faq/Resources/Private/Language/locallang_db.xlf:tx_plainfaq_domain_model_faq', 'label' => 'uid', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'sortby' => 'sorting', 'searchFields' => 'question,answer,keywords,images,files', 'typeicon_classes' => [ - 'default' => 'ext-plainfaq-faq' + 'default' => 'ext-plainfaq-faq', ], - 'readOnly' => true + 'readOnly' => true, ], 'types' => [ '1' => ['showitem' => ' - question, slug, answer, keywords,' + question, slug, answer, keywords,', ], ], 'palettes' => [ @@ -23,6 +22,5 @@ ], 'columns' => [ - ], ]; diff --git a/Resources/Private/Templates/BackendPreview.html b/Resources/Private/Templates/BackendPreview.html index 4e62484..26a92cf 100644 --- a/Resources/Private/Templates/BackendPreview.html +++ b/Resources/Private/Templates/BackendPreview.html @@ -8,7 +8,7 @@

{riddle.title}

- {riddle.title} + {riddle.title} @@ -18,7 +18,7 @@

{riddle.title}

- + @@ -28,13 +28,13 @@

{riddle.title}

@@ -53,29 +53,14 @@

{riddle.title}

{f:translate(key:'{lll}riddle.id')}{f:if(condition: riddleV2, then:riddle.UUID, else: riddle.id)}{riddle.UUID}
{f:translate(key:'{lll}riddle.type')} {f:translate(key:'{lll}riddle.created')} {riddle._enriched.dateCreated -> f:format.date(format:dateTime)}
- + {riddle.created.by}
{f:translate(key:'{lll}riddle.published')} {riddle._enriched.datepublished -> f:format.date(format:dateTime)}
- + {riddle.published.by}
@@ -96,12 +81,4 @@

{riddle.title}

- - - - {user.name} ({user.email}) - {by} - - - diff --git a/Tests/Unit/Api/RiddleApiTest.php b/Tests/Unit/Api/RiddleApiTest.php index 233890c..16c4b55 100644 --- a/Tests/Unit/Api/RiddleApiTest.php +++ b/Tests/Unit/Api/RiddleApiTest.php @@ -20,7 +20,6 @@ class RiddleApiTest extends BaseTestCase { - private $listOfRiddles = [ [ 'title' => 'riddle 1', @@ -28,7 +27,7 @@ class RiddleApiTest extends BaseTestCase ], [ 'title' => 'riddle 2', - 'id' => 456 + 'id' => 456, ], ]; @@ -38,12 +37,11 @@ class RiddleApiTest extends BaseTestCase public function riddleListReturnsResult(): void { $mockedRiddleApi = $this->getAccessibleMock(RiddleApi::class, ['request'], [], '', false); - $mockedRiddleApi->expects(self::once())->method('request')->with('riddle/get/list')->willReturn($this->listOfRiddles); + $mockedRiddleApi->expects(self::once())->method('request')->with('riddle/list')->willReturn($this->listOfRiddles); /** @var ExtensionConfiguration $extensionConfiguration */ $extensionConfiguration = $this->prophesize(ExtensionConfiguration::class); $extensionConfiguration->getApiKey()->willReturn('abc'); - $extensionConfiguration->getApiToken()->willReturn('def'); $mockedRiddleApi->_set('extensionConfiguration', $extensionConfiguration->reveal()); $riddles = $mockedRiddleApi->getRiddleList(); @@ -60,11 +58,10 @@ public function riddleIdReturnsResult(int $id, array $expectedResult): void { $response = ['response' => ['items' => $this->listOfRiddles]]; $mockedRiddleApi = $this->getAccessibleMock(RiddleApi::class, ['request'], [], '', false); - $mockedRiddleApi->expects(self::once())->method('request')->with('riddle/get/list')->willReturn($response); + $mockedRiddleApi->expects(self::once())->method('request')->with('riddle/list')->willReturn($response); $extensionConfiguration = $this->prophesize(ExtensionConfiguration::class); $extensionConfiguration->getApiKey()->willReturn('abc'); - $extensionConfiguration->getApiToken()->willReturn('def'); $mockedRiddleApi->_set('extensionConfiguration', $extensionConfiguration->reveal()); $riddle = $mockedRiddleApi->getRiddleItem($id); @@ -77,16 +74,15 @@ public function riddleIdReturnsResultDataProvider(): array 'riddle found' => [ 456, [ 'title' => 'riddle 2', - 'id' => 456 - ] + 'id' => 456, + ], ], 'no riddle found' => [ - 123456, [] - ] + 123456, [], + ], ]; } - /** * @test */ @@ -94,11 +90,10 @@ public function embedCodeReturnsResult(): void { $response = ['response' => 'some html']; $mockedRiddleApi = $this->getAccessibleMock(RiddleApi::class, ['request'], [], '', false); - $mockedRiddleApi->expects(self::once())->method('request')->with('riddle/get/embed-code?riddleId=123')->willReturn($response); + $mockedRiddleApi->expects(self::once())->method('request')->with('riddle/embed-code/123')->willReturn($response); $extensionConfiguration = $this->prophesize(ExtensionConfiguration::class); $extensionConfiguration->getApiKey()->willReturn('abc'); - $extensionConfiguration->getApiToken()->willReturn('def'); $mockedRiddleApi->_set('extensionConfiguration', $extensionConfiguration->reveal()); self::assertEquals($response, $mockedRiddleApi->getEmbedCode(123)); @@ -109,14 +104,14 @@ public function embedCodeReturnsResult(): void */ public function constructorSetsExtensionConfiguration(): void { - $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['riddle'] = ['apiKey' => '123', 'apiToken' => 456]; + $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['riddle'] = ['apiKey' => '123']; $configuration = new ExtensionConfiguration(); $mockedRiddleApi = $this->getAccessibleMock(RiddleApi::class, ['request'], [], '', true); /** @var ExtensionConfiguration $extensionConfigurationFromApi */ $extensionConfigurationFromApi = $mockedRiddleApi->_get('extensionConfiguration'); - self::assertEquals(456, $configuration->getApiToken()); + self::assertEquals(123, $configuration->getApiKey()); } /** @@ -161,6 +156,5 @@ public function requestErrorThrowsException(): void $mockedRiddleApi = $this->getAccessibleMock(RiddleApi::class, ['dummy'], [], '', true); self::assertEquals($expected, $mockedRiddleApi->_call('request', 'action')); - } } diff --git a/Tests/Unit/Backend/Element/SelectSingleElementWithNoIconTest.php b/Tests/Unit/Backend/Element/SelectSingleElementWithNoIconTest.php index 91ce545..2e3a785 100644 --- a/Tests/Unit/Backend/Element/SelectSingleElementWithNoIconTest.php +++ b/Tests/Unit/Backend/Element/SelectSingleElementWithNoIconTest.php @@ -21,7 +21,6 @@ class SelectSingleElementWithNoIconTest extends BaseTestCase { - /** * @test */ @@ -34,7 +33,7 @@ public function hiddenClassIsAdded(): void 'tableName' => 'tt_content', 'fieldName' => 'field', 'databaseRow' => [ - 'uid' => 123 + 'uid' => 123, ], 'parameterArray' => [ 'itemFormElName' => 'itemFormElName', @@ -47,19 +46,21 @@ public function hiddenClassIsAdded(): void [ 0 => 'label', 1 => '--div--', - 'icon' => 'some-icon'], + 'icon' => 'some-icon', + ], [ 0 => 'label 2', 1 => 'fo', - 2 => 'another-icon'] - ] - ] - ] + 2 => 'another-icon', + ], + ], + ], + ], ], 'inlineStructure' => [], 'isInlineChild' => false, 'inlineParentUid' => false, - 'size' => 1 + 'size' => 1, ]; $iconFactoryProphecy = $this->prophesize(IconFactory::class); GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal()); diff --git a/Tests/Unit/Backend/FieldWizard/ExternalIconsTest.php b/Tests/Unit/Backend/FieldWizard/ExternalIconsTest.php index 3bb663d..e68a503 100644 --- a/Tests/Unit/Backend/FieldWizard/ExternalIconsTest.php +++ b/Tests/Unit/Backend/FieldWizard/ExternalIconsTest.php @@ -16,7 +16,6 @@ class ExternalIconsTest extends BaseTestCase { - /** * @test */ @@ -27,7 +26,7 @@ public function hiddenClassIsAdded(): void 'fieldName' => 'field', 'databaseRow' => [ 'uid' => 123, - 'field' => ['fo'] + 'field' => ['fo'], ], 'parameterArray' => [ 'itemFormElName' => 'itemFormElName', @@ -40,19 +39,21 @@ public function hiddenClassIsAdded(): void [ 0 => 'label', 1 => '--div--', - 'icon' => 'some-icon'], + 'icon' => 'some-icon', + ], [ 0 => 'label 2', 1 => 'fo', - 2 => 'https://some-external.icon.com'] - ] - ] - ] + 2 => 'https://some-external.icon.com', + ], + ], + ], + ], ], 'inlineStructure' => [], 'isInlineChild' => false, 'inlineParentUid' => false, - 'size' => 1 + 'size' => 1, ]; /** @var ExternalIcons $externalIcons */ diff --git a/Tests/Unit/ExtensionConfigurationTest.php b/Tests/Unit/ExtensionConfigurationTest.php index 4faf6c6..b6b67a0 100644 --- a/Tests/Unit/ExtensionConfigurationTest.php +++ b/Tests/Unit/ExtensionConfigurationTest.php @@ -11,17 +11,14 @@ * LICENSE.txt file that was distributed with this source code. */ -use StudioMitte\Riddle\Api\RiddleApi; use StudioMitte\Riddle\Exception\ApiConfigurationMissingException; use StudioMitte\Riddle\ExtensionConfiguration; -use StudioMitte\Riddle\Hooks\PageLayoutView; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration as ExtensionConfigurationCore; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\BaseTestCase; class ExtensionConfigurationTest extends BaseTestCase { - /** * @test * @dataProvider configurationCanBeRetrievedDataProvider @@ -29,22 +26,21 @@ class ExtensionConfigurationTest extends BaseTestCase * @param mixed $expectedKey * @param mixed $expectedToken */ - public function configurationCanBeRetrieved(array $configuration, $expectedKey, $expectedToken): void + public function configurationCanBeRetrieved(array $configuration, $expectedKey): void { $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['riddle'] = $configuration; $configuration = new ExtensionConfiguration(); self::assertEquals($expectedKey, $configuration->getApiKey()); - self::assertEquals($expectedToken, $configuration->getApiToken()); } public function configurationCanBeRetrievedDataProvider(): array { return [ 'working api' => [ - ['apiKey' => '123', 'apiToken' => 456], 123, 456 - ] + ['apiKey' => '123'], 123, + ], ]; } @@ -63,7 +59,8 @@ public function emptyConfigurationThrowsException(): void /** * @test */ - public function exceptionsAreHandledInConstructor(): void { + public function exceptionsAreHandledInConstructor(): void + { $mockedCoreExtensionConfiguration = $this->getAccessibleMock(ExtensionConfigurationCore::class, ['get'], [], '', false); $mockedCoreExtensionConfiguration->expects(self::once())->method('get')->with('riddle')->willThrowException(new \RuntimeException('faked exception')); GeneralUtility::addInstance(ExtensionConfigurationCore::class, $mockedCoreExtensionConfiguration); diff --git a/Tests/Unit/Hooks/ItemsProcFuncTest.php b/Tests/Unit/Hooks/ItemsProcFuncTest.php index a0796d3..28ae391 100644 --- a/Tests/Unit/Hooks/ItemsProcFuncTest.php +++ b/Tests/Unit/Hooks/ItemsProcFuncTest.php @@ -26,7 +26,7 @@ class ItemsProcFuncTest extends BaseTestCase 'title' => 'A riddle', 'dateCreated' => '2020-08-21 19:21:07', 'datepublished' => '2020-09-21 19:21:07', - 'thumb' => 'https://cdn.riddle.com/img1.png' + 'thumb' => 'https://cdn.riddle.com/img1.png', ], [ 'id' => 456, @@ -34,7 +34,7 @@ class ItemsProcFuncTest extends BaseTestCase 'type' => 'Quiz', 'dateCreated' => '2019-08-21 19:21:07', 'datepublished' => '2019-09-21 19:21:07', - ] + ], ]; /** @@ -65,8 +65,8 @@ public function allRiddlesAreReturned(): void 'items' => [ ['title' => 'riddle 1'], ['title' => 'riddle 2'], - ] - ] + ], + ], ]; /** @var RiddleApi $riddleApiProphecy */ $riddleApiProphecy = $this->prophesize(RiddleApi::class); diff --git a/Tests/Unit/Hooks/PageLayoutViewTest.php b/Tests/Unit/Hooks/PageLayoutViewTest.php index 464b748..d1749f1 100644 --- a/Tests/Unit/Hooks/PageLayoutViewTest.php +++ b/Tests/Unit/Hooks/PageLayoutViewTest.php @@ -20,7 +20,6 @@ class PageLayoutViewTest extends BaseTestCase { - /** * @test */ @@ -53,8 +52,8 @@ public function extensionSummaryReturnsViewContent(): void $params = [ 'row' => [ - 'pi_flexform' => '' - ] + 'pi_flexform' => '', + ], ]; self::assertEquals('some html', $mockedPageLayoutView->getExtensionSummary($params)); } @@ -74,8 +73,8 @@ public function extensionSummaryTransformsExceptionIntoVariable(): void $params = [ 'row' => [ - 'pi_flexform' => '' - ] + 'pi_flexform' => '', + ], ]; self::assertEquals('some html', $mockedPageLayoutView->getExtensionSummary($params)); } diff --git a/Tests/Unit/Plugin/RiddlePluginTest.php b/Tests/Unit/Plugin/RiddlePluginTest.php index 499872f..6b02caa 100644 --- a/Tests/Unit/Plugin/RiddlePluginTest.php +++ b/Tests/Unit/Plugin/RiddlePluginTest.php @@ -22,7 +22,6 @@ class RiddlePluginTest extends BaseTestCase { - /** * @test * @dataProvider htmlCodeIsDeliveredDataProvider @@ -51,7 +50,7 @@ public function htmlCodeIsDelivered(int $id, string $html): void -' +', ]); $mockedProvider = $this->getAccessibleMock(PluginController::class, ['getRiddleHtml'], [], '', false); $mockedProvider->_set('cObj', $mockedContentObjectRenderer); @@ -67,11 +66,11 @@ public function htmlCodeIsDeliveredDataProvider(): array { return [ 'working flexforms' => [ - 456, 'some html string' + 456, 'some html string', ], 'non working flexforms' => [ - 0, '' - ] + 0, '', + ], ]; } diff --git a/Tests/Unit/Utility/RiddleUtilityTest.php b/Tests/Unit/Utility/RiddleUtilityTest.php index 9e2ea2d..07407bd 100644 --- a/Tests/Unit/Utility/RiddleUtilityTest.php +++ b/Tests/Unit/Utility/RiddleUtilityTest.php @@ -20,7 +20,6 @@ class RiddleUtilityTest extends BaseTestCase { - /** * @test * @dataProvider apiDataIsEnrichedDataProvider @@ -46,9 +45,9 @@ public function apiDataIsEnrichedDataProvider(): array 'datepublished' => '2020-09-21 19:21:07', '_enriched' => [ 'dateCreated' => 1598030467, - 'datepublished' => 1600708867 - ] - ] + 'datepublished' => 1600708867, + ], + ], ], 'invalid dates given' => [ [ @@ -58,8 +57,8 @@ public function apiDataIsEnrichedDataProvider(): array [ 'dateCreated' => '08-21 19:21:07', 'datepublished' => '09-21 19:21:07', - ] - ] + ], + ], ]; } @@ -69,7 +68,7 @@ public function apiDataIsEnrichedDataProvider(): array * @param int $expectedId * @param string $flexforms */ - public function idCanBeRetrievedFromFlexforms(int $expectedId, string $flexforms): void + public function idCanBeRetrievedFromFlexforms(string $expectedId, string $flexforms): void { $cacheFrontendProphecy = $this->prophesize(PhpFrontend::class); $cacheFrontendProphecy->require(Argument::any())->willReturn(false); @@ -86,7 +85,7 @@ public function idCanBeRetrievedFromFlexformsDataProvider(): array { return [ 'working flexform' => [ - 264528, + '264528', ' @@ -98,10 +97,10 @@ public function idCanBeRetrievedFromFlexformsDataProvider(): array -' +', ], 'non working flexform' => [ - 0, + '', ' @@ -113,12 +112,12 @@ public function idCanBeRetrievedFromFlexformsDataProvider(): array -' +', ], 'empty flexform' => [ - 0, - '' - ] + '', + '', + ], ]; } } diff --git a/composer.json b/composer.json index 753b476..e43fe86 100644 --- a/composer.json +++ b/composer.json @@ -24,16 +24,20 @@ "GPL-2.0-or-later" ], "require": { - "typo3/cms-backend": "^9 || ^10 || ^11", - "typo3/cms-core": "^9 || ^10 || ^11", - "typo3/cms-frontend": "^9 || ^10 || ^11", - "typo3/cms-fluid": "^9 || ^10 || ^11" + "typo3/cms-backend": "^12", + "typo3/cms-core": "^12", + "typo3/cms-frontend": "^12", + "typo3/cms-fluid": "^12" }, "require-dev": { - "phpspec/prophecy-phpunit": "^1", - "typo3/testing-framework": "^6.4 || ^4 || ^5", - "phpunit/phpunit": "^8 || ^7", - "friendsofphp/php-cs-fixer": "^2.16" + "typo3/cms-composer-installers": "^3.1.3 || 4.0.0-RC1 || ^5.0", + "typo3/testing-framework": "^7.0.1", + "typo3/cms-form": "^12.4.5", + "phpunit/phpunit": "^9", + "typo3/coding-standards": "^0.5.3", + "friendsofphp/php-cs-fixer": "^3.13.0", + "webmozart/assert": "^1.11.0", + "phpspec/prophecy": "^1.17" }, "autoload": { "psr-4": { @@ -45,31 +49,27 @@ "StudioMitte\\Riddle\\Tests\\": "Tests" } }, - "replace": { - "typo3-ter/riddle": "self.version" - }, "config": { - "bin-dir": ".build/bin", - "discard-changes": true, - "optimize-autoloader": true, - "vendor-dir": ".build/vendor" - }, - "extra": { - "typo3/cms": { - "web-dir": ".build/web", - "app-dir": ".build", - "extension-key": "riddle" + "vendor-dir": ".Build/vendor", + "bin-dir": ".Build/bin", + "allow-plugins": { + "typo3/class-alias-loader": true, + "typo3/cms-composer-installers": true, + "sbuerk/typo3-cmscomposerinstallers-testingframework-bridge": true } }, "scripts": { - "php:fix": ".build/vendor/bin/php-cs-fixer --config=Build/.php_cs.php fix Classes Tests", - "ci:php:lint": "find *.php Classes Configuration Tests -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l", - "ci:php:fixer": "php-cs-fixer --diff -v fix", - "ci:tests:unit": "phpunit -c Build/UnitTests.xml", - "ci:tests:functional": "find 'Tests/Functional' -wholename '*Test.php' | parallel --gnu 'echo; echo \"Running functional test suite {}\"; php -d date.timezone=Europe/Berlin .build/vendor/bin/phpunit -c .build/vendor/nimut/testing-framework/res/Configuration/FunctionalTests.xml {}';", + "cs": "php ./.Build/bin/php-cs-fixer fix --dry-run -v --config ./Build/php-cs-fixer/php-cs-fixer.php ./", + "csfix": "php ./.Build/bin/php-cs-fixer fix -v --config ./Build/php-cs-fixer/php-cs-fixer.php ./", "post-autoload-dump": [ - "mkdir -p .build/web/typo3conf/ext/", - "[ -L .build/web/typo3conf/ext/riddle ] || ln -snvf ../../../../. .build/web/typo3conf/ext/riddle" + "TYPO3\\TestingFramework\\Composer\\ExtensionTestEnvironment::prepare" ] + }, + "extra": { + "typo3/cms": { + "extension-key": "riddle", + "app-dir": ".Build", + "web-dir": ".Build/Web" + } } } diff --git a/ext_conf_template.txt b/ext_conf_template.txt index 78542d9..480bfdd 100644 --- a/ext_conf_template.txt +++ b/ext_conf_template.txt @@ -4,8 +4,3 @@ # cat=enable/10; type=string; label=API key apiKey = -# cat=enable/10; type=string; label=API token -apiToken = - -# cat=enable/10; type=string; label=API token v2 -apiTokenV2 = diff --git a/ext_emconf.php b/ext_emconf.php index aad328c..e7a93e2 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -1,4 +1,5 @@ 'riddle.com Integration', 'description' => 'Embed riddles from riddle.com', @@ -7,13 +8,12 @@ 'author_email' => 'gr@studiomitte.com', 'author_company' => 'studiomitte.com', 'state' => 'stable', - 'clearCacheOnLoad' => true, - 'version' => '1.2.0', + 'version' => '2.0.0', 'constraints' => [ 'depends' => [ - 'typo3' => '9.5.0-11.5.99' + 'typo3' => '12.4.0-12.4.99', ], ], 'autoload' => @@ -22,5 +22,5 @@ [ 'StudioMitte\\Riddle\\' => 'Classes', ], - ] + ], ]; diff --git a/ext_localconf.php b/ext_localconf.php index 7187de7..eec0c18 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -5,26 +5,21 @@ '); - if (TYPO3_MODE === 'BE') { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1598116730] = [ - 'nodeName' => 'ExternalIcons', - 'priority' => 70, - 'class' => \StudioMitte\Riddle\Backend\FieldWizard\ExternalIcons::class - ]; - $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1598116731] = [ - 'nodeName' => 'selectSingleWithNoIconPrefix', - 'priority' => 70, - 'class' => \StudioMitte\Riddle\Backend\Element\SelectSingleElementWithNoIcon::class - ]; + $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1598116730] = [ + 'nodeName' => 'ExternalIcons', + 'priority' => 70, + 'class' => \StudioMitte\Riddle\Backend\FieldWizard\ExternalIcons::class, + ]; + $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1598116731] = [ + 'nodeName' => 'selectSingleWithNoIconPrefix', + 'priority' => 70, + 'class' => \StudioMitte\Riddle\Backend\Element\SelectSingleElementWithNoIcon::class, + ]; - $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); - $iconRegistry->registerIcon( - 'ext-riddle-plugin', - \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class, - ['source' => 'EXT:riddle/Resources/Public/Icons/Plugin.png'] - ); - - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['list_type_Info']['riddle_riddle']['riddle'] = - \StudioMitte\Riddle\Hooks\PageLayoutView::class . '->getExtensionSummary'; - } + $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); + $iconRegistry->registerIcon( + 'ext-riddle-plugin', + \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class, + ['source' => 'EXT:riddle/Resources/Public/Icons/Plugin.png'] + ); }); diff --git a/ext_tables.php b/ext_tables.php index f0896f4..e087ce9 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -1,7 +1,5 @@ 'group,user', 'name' => 'site_riddle', 'icon' => 'EXT:riddle/Resources/Public/Icons/Extension.png', - 'labels' => 'LLL:EXT:riddle/Resources/Private/Language/locallang.xlf' + 'labels' => 'LLL:EXT:riddle/Resources/Private/Language/locallang.xlf', ] );