diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7d3c6f6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +--- +name: CI +on: + push: +jobs: + code-quality: + name: "Code quality checks" + runs-on: ubuntu-22.04 + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install Composer dependencies" + run: "composer ci:install" + - name: "Run command" + run: "composer ci:php:stan" + + unit-tests: + name: Unit Tests + runs-on: ubuntu-22.04 + needs: [ code-quality ] + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install Composer dependencies" + run: "composer ci:install" + - name: "Run the tests" + run: "composer ci:tests:unit" + + functional-tests: + name: Functional Tests + runs-on: ubuntu-22.04 + needs: [ code-quality ] + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install Composer dependencies" + run: "composer update --no-progress" + - name: "Run the tests" + run: "composer ci:tests:functional" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0421545 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.Build/ +.idea/ +.cache/ +Build/testing-docker/.env +bin/ +public/ +typo3temp/ +vendor/ +composer.lock diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh new file mode 100755 index 0000000..af4723c --- /dev/null +++ b/Build/Scripts/runTests.sh @@ -0,0 +1,1036 @@ +#!/usr/bin/env bash + +# +# TYPO3 core test runner based on docker or podman +# + +waitFor() { + local HOST=${1} + local PORT=${2} + local TESTCOMMAND=" + COUNT=0; + while ! nc -z ${HOST} ${PORT}; do + if [ \"\${COUNT}\" -gt 10 ]; then + echo \"Can not connect to ${HOST} port ${PORT}. Aborting.\"; + exit 1; + fi; + sleep 1; + COUNT=\$((COUNT + 1)); + done; + " + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name wait-for-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_ALPINE} /bin/sh -c "${TESTCOMMAND}" +} + +cleanUp() { + ATTACHED_CONTAINERS=$(${CONTAINER_BIN} ps --filter network=${NETWORK} --format='{{.Names}}') + for ATTACHED_CONTAINER in ${ATTACHED_CONTAINERS}; do + ${CONTAINER_BIN} kill ${ATTACHED_CONTAINER} >/dev/null + done + ${CONTAINER_BIN} network rm ${NETWORK} >/dev/null +} + +handleDbmsOptions() { + # -a, -d, -i depend on each other. Validate input combinations and set defaults. + case ${DBMS} in + mariadb) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.4" + if ! [[ ${DBMS_VERSION} =~ ^(10.4|10.5|10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + mysql) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="8.0" + if ! [[ ${DBMS_VERSION} =~ ^(8.0|8.1|8.2|8.3)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + postgres) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10" + if ! [[ ${DBMS_VERSION} =~ ^(10|11|12|13|14|15|16)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + sqlite) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + if [ -n "${DBMS_VERSION}" ]; then + echo "Invalid combination -d ${DBMS} -i ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + *) + echo "Invalid option -d ${DBMS}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + ;; + esac +} + +cleanBuildFiles() { + echo -n "Clean builds ... " + rm -rf \ + Build/JavaScript \ + Build/node_modules + echo "done" +} + +cleanCacheFiles() { + echo -n "Clean caches ... " + rm -rf \ + .cache \ + Build/.cache \ + Build/composer/.cache/ \ + .php-cs-fixer.cache + echo "done" +} + +cleanTestFiles() { + # composer distribution test + echo -n "Clean composer distribution test ... " + rm -rf \ + Build/composer/composer.json \ + Build/composer/composer.lock \ + Build/composer/public/index.php \ + Build/composer/public/typo3 \ + Build/composer/public/typo3conf/ext \ + Build/composer/var/ \ + Build/composer/vendor/ + echo "done" + + # test related + echo -n "Clean test related files ... " + rm -rf \ + Build/phpunit/FunctionalTests-Job-*.xml \ + typo3/sysext/core/Tests/AcceptanceTests-Job-* \ + typo3/sysext/core/Tests/Acceptance/Support/_generated \ + typo3temp/var/tests/ + echo "done" +} + +cleanRenderedDocumentationFiles() { + echo -n "Clean rendered documentation files ... " + rm -rf \ + ../../../typo3/sysext/*/Documentation-GENERATED-temp + echo "done" +} + +getPhpImageVersion() { + case ${1} in + 8.2) + echo -n "1.11" + ;; + 8.3) + echo -n "1.12" + ;; + esac +} + +loadHelp() { + # Load help text into $HELP + read -r -d '' HELP < + Specifies the test suite to run + - acceptance: main application acceptance tests + - acceptanceInstall: installation acceptance tests, only with -d mariadb|postgres|sqlite + - buildCss: execute scss to css builder + - buildJavascript: execute typescript to javascript builder + - cgl: test and fix all core php files + - cglGit: test and fix latest committed patch for CGL compliance + - cglHeader: test and fix file header for all core php files + - cglHeaderGit: test and fix latest committed patch for CGL file header compliance + - checkAnnotations: check php code for allowed annotations + - checkBom: check UTF-8 files do not contain BOM + - checkComposer: check composer.json files for version integrity + - checkExceptionCodes: test core for duplicate exception codes + - checkExtensionScannerRst: test all .rst files referenced by extension scanner exist + - checkFilePathLength: test core file paths do not exceed maximum length + - checkGitSubmodule: test core git has no sub modules defined + - checkGruntClean: Verify "grunt build" is clean. Warning: Executes git commands! Usually used in CI only. + - checkIsoDatabase: Verify "updateIsoDatabase.php" does not change anything. + - checkNamespaceIntegrity: Verify namespace integrity in class and test code files are in good shape. + - checkPermissions: test some core files for correct executable bits + - checkRst: test .rst files for integrity + - checkTestClassFinal: check test case classes are final + - checkTestMethodsPrefix: check tests methods do not start with "test" + - clean: clean up build, cache and testing related files and folders + - cleanBuild: clean up build related files and folders + - cleanCache: clean up cache related files and folders + - cleanRenderedDocumentation: clean up rendered documentation files and folders (Documentation-GENERATED-temp) + - cleanTests: clean up test related files and folders + - composer: "composer" command dispatcher, to execute various composer commands + - composerInstall: "composer install" + - composerInstallMax: "composer update", with no platform.php config. + - composerInstallMin: "composer update --prefer-lowest", with platform.php set to PHP version x.x.0. + - composerTestDistribution: "composer update" in Build/composer to verify core dependencies + - composerValidate: "composer validate" + - functional: PHP functional tests + - functionalDeprecated: deprecated PHP functional tests + - lintPhp: PHP linting + - lintScss: SCSS linting + - lintTypescript: TS linting + - lintHtml: HTML linting + - listExceptionCodes: list core exception codes in JSON format + - phpstan: phpstan tests + - phpstanGenerateBaseline: regenerate phpstan baseline, handy after phpstan updates + - unit (default): PHP unit tests + - unitDeprecated: deprecated PHP unit tests + - unitJavascript: JavaScript unit tests + - unitRandom: PHP unit tests in random order, add -o to use specific seed + + -b + Container environment: + - podman (default) + - docker + + -a + Only with -s functional|functionalDeprecated + Specifies to use another driver, following combinations are available: + - mysql + - mysqli (default) + - pdo_mysql + - mariadb + - mysqli (default) + - pdo_mysql + + -d + Only with -s functional|functionalDeprecated|acceptance|acceptanceInstall + Specifies on which DBMS tests are performed + - sqlite: (default): use sqlite + - mariadb: use mariadb + - mysql: use MySQL + - postgres: use postgres + + -i version + Specify a specific database version + With "-d mariadb": + - 10.4 short-term, maintained until 2024-06-18 (default) + - 10.5 short-term, maintained until 2025-06-24 + - 10.6 long-term, maintained until 2026-06 + - 10.7 short-term, no longer maintained + - 10.8 short-term, maintained until 2023-05 + - 10.9 short-term, maintained until 2023-08 + - 10.10 short-term, maintained until 2023-11 + - 10.11 long-term, maintained until 2028-02 + - 11.0 development series + - 11.1 short-term development series + With "-d mysql": + - 8.0 maintained until 2026-04 (default) LTS + - 8.1 unmaintained since 2023-10 + - 8.2 unmaintained since 2024-01 + - 8.3 maintained until 2024-04 + With "-d postgres": + - 10 unmaintained since 2022-11-10 (default) + - 11 unmaintained since 2023-11-09 + - 12 maintained until 2024-11-14 + - 13 maintained until 2025-11-13 + - 14 maintained until 2026-11-12 + - 15 maintained until 2027-11-11 + - 16 maintained until 2028-11-09 + + -c + Only with -s functional|acceptance + Hack functional or acceptance tests into #numberOfChunks pieces and run tests of #chunk. + Example -c 3/13 + + -p <8.2|8.3> + Specifies the PHP minor version to be used + - 8.2 (default): use PHP 8.2 + - 8.3: use PHP 8.3 + + -e "" (DEPRECATED). + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance + 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 "-d memory_limit=-1 --filter filterByValueRecursiveCorrectlyFiltersArray" to enable verbose output AND filter tests + named "canRetrieveValueWithGP" + + DEPRECATED - pass arguments after the `--` separator directly. For example, instead of + Build/Scripts/runTests.sh -s unit -e "--filter filterByValueRecursiveCorrectlyFiltersArray" + use + Build/Scripts/runTests.sh -s unit -- --filter filterByValueRecursiveCorrectlyFiltersArray + + -g + Only with -s acceptance|acceptanceInstall + Activate selenium grid as local port to watch browser clicking around. Can be surfed using + http://localhost:7900/. A browser tab is opened automatically if xdg-open is installed. + + -x + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance|acceptanceInstall + 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. + + -o + Only with -s unitRandom + Set specific random seed to replay a random run in this order again. The phpunit randomizer + outputs the used seed at the end (in gitlab core testing logs, too). Use that number to + replay the unit tests in that order. + + -n + Only with -s cgl|cglGit|cglHeader|cglHeaderGit + Activate dry-run in CGL check that does not actively change files and only prints broken ones. + + -u + Update existing typo3/core-testing-* container images and remove obsolete dangling image versions. + Use this if weird test errors occur. + + -h + Show this help. + +Examples: + # Run all core unit tests using PHP 8.2 + ./Build/Scripts/runTests.sh + ./Build/Scripts/runTests.sh -s unit + + # Run all core units tests and enable xdebug (have a PhpStorm listening on port 9003!) + ./Build/Scripts/runTests.sh -x + + # Run unit tests in phpunit with xdebug on PHP 8.3 and filter for test filterByValueRecursiveCorrectlyFiltersArray + ./Build/Scripts/runTests.sh -x -p 8.3 -- --filter filterByValueRecursiveCorrectlyFiltersArray + + # Run functional tests in phpunit with a filtered test method name in a specified file + # example will currently execute two tests, both of which start with the search term + ./Build/Scripts/runTests.sh -s functional -- \ + --filter datetimeInstanceCanBePersistedToDatabaseIfTypeIsExplicitlySpecified \ + typo3/sysext/core/Tests/Functional/Database/ConnectionTest.php + + # Run functional tests on postgres with xdebug, php 8.3 and execute a restricted set of tests + ./Build/Scripts/runTests.sh -x -p 8.3 -s functional -d postgres typo3/sysext/core/Tests/Functional/Authentication + + # Run functional tests on postgres 11 + ./Build/Scripts/runTests.sh -s functional -d postgres -i 11 + + # Run restricted set of application acceptance tests + ./Build/Scripts/runTests.sh -s acceptance typo3/sysext/core/Tests/Acceptance/Application/Login/BackendLoginCest.php:loginButtonMouseOver + + # Run installer tests of a new instance on sqlite + ./Build/Scripts/runTests.sh -s acceptanceInstall -d sqlite + + # Run composer require to require a dependency + ./Build/Scripts/runTests.sh -s composer -- require --dev typo3/testing-framework:dev-main + + # Some composer command examples + ./Build/Scripts/runTests.sh -s composer -- dumpautoload + ./Build/Scripts/runTests.sh -s composer -- info | grep "symfony" +EOF +} + +# Test if docker exists, else exit out with error +if ! type "docker" >/dev/null 2>&1 && ! type "podman" >/dev/null 2>&1; then + echo "This script relies on docker or podman. 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, then go up two dirs. +THIS_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$THIS_SCRIPT_DIR" || exit 1 +cd ../../ || exit 1 +CORE_ROOT="${PWD}" + +# Default variables +TEST_SUITE="unit" +DBMS="sqlite" +DBMS_VERSION="" +PHP_VERSION="8.2" +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +ACCEPTANCE_HEADLESS=1 +EXTRA_TEST_OPTIONS="" +PHPUNIT_RANDOM="" +CGLCHECK_DRY_RUN="" +DATABASE_DRIVER="" +CHUNKS=0 +THISCHUNK=0 +CONTAINER_BIN="" +COMPOSER_ROOT_VERSION="13.1.x-dev" +PHPSTAN_CONFIG_FILE="phpstan.local.neon" +CONTAINER_INTERACTIVE="-it --init" +HOST_UID=$(id -u) +HOST_PID=$(id -g) +USERSET="" +SUFFIX=$(echo $RANDOM) +NETWORK="typo3-core-${SUFFIX}" +CI_PARAMS="" +CONTAINER_HOST="host.docker.internal" + +# Option parsing updates above default vars +# 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 ":a:b:s:c:d:i:p:e:xy:o:nhug" OPT; do + case ${OPT} in + s) + TEST_SUITE=${OPTARG} + ;; + b) + if ! [[ ${OPTARG} =~ ^(docker|podman)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + CONTAINER_BIN=${OPTARG} + ;; + a) + DATABASE_DRIVER=${OPTARG} + ;; + c) + if ! [[ ${OPTARG} =~ ^([0-9]+\/[0-9]+)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + else + # Split "2/13" - run chunk 2 of 13 chunks + THISCHUNK=$(echo "${OPTARG}" | cut -d '/' -f1) + CHUNKS=$(echo "${OPTARG}" | cut -d '/' -f2) + fi + ;; + d) + DBMS=${OPTARG} + ;; + i) + DBMS_VERSION=${OPTARG} + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(8.2|8.3)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + e) + EXTRA_TEST_OPTIONS=${OPTARG} + ;; + g) + ACCEPTANCE_HEADLESS=0 + ;; + x) + PHP_XDEBUG_ON=1 + ;; + y) + PHP_XDEBUG_PORT=${OPTARG} + ;; + o) + PHPUNIT_RANDOM="--random-order-seed=${OPTARG}" + ;; + n) + CGLCHECK_DRY_RUN="-n" + ;; + h) + loadHelp + echo "${HELP}" + exit 0 + ;; + u) + TEST_SUITE=update + ;; + \?) + 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 "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 +fi + +handleDbmsOptions + +# ENV var "CI" is set by gitlab-ci. Use it to force some CI details. +if [ "${CI}" == "true" ]; then + PHPSTAN_CONFIG_FILE="phpstan.ci.neon" + CONTAINER_INTERACTIVE="" + CI_PARAMS="--pull=never" +fi + +# determine default container binary to use: 1. podman 2. docker +if [[ -z "${CONTAINER_BIN}" ]]; then + if type "podman" >/dev/null 2>&1; then + CONTAINER_BIN="podman" + elif type "docker" >/dev/null 2>&1; then + CONTAINER_BIN="docker" + fi +fi + +if [ $(uname) != "Darwin" ] && [ ${CONTAINER_BIN} = "docker" ]; then + # Run docker jobs as current user to prevent permission issues. Not needed with podman. + USERSET="--user $HOST_UID" +fi + +if ! type ${CONTAINER_BIN} >/dev/null 2>&1; then + echo "Selected container environment \"${CONTAINER_BIN}\" not found. Please install or use -b option to select one." >&2 + exit 1 +fi + +IMAGE_APACHE="ghcr.io/typo3/core-testing-apache24:1.3" +IMAGE_PHP="ghcr.io/typo3/core-testing-$(echo "php${PHP_VERSION}" | sed -e 's/\.//'):$(getPhpImageVersion $PHP_VERSION)" + +IMAGE_NODEJS="ghcr.io/typo3/core-testing-nodejs18:1.2" +IMAGE_NODEJS_CHROME="ghcr.io/typo3/core-testing-nodejs18-chrome:1.2" +IMAGE_ALPINE="docker.io/alpine:3.8" +IMAGE_SELENIUM="docker.io/selenium/standalone-chrome:4.11.0-20230801" +IMAGE_REDIS="docker.io/redis:4-alpine" +IMAGE_MEMCACHED="docker.io/memcached:1.5-alpine" +IMAGE_MARIADB="docker.io/mariadb:${DBMS_VERSION}" +IMAGE_MYSQL="docker.io/mysql:${DBMS_VERSION}" +IMAGE_POSTGRES="docker.io/postgres:${DBMS_VERSION}-alpine" + +# Detect arm64 to use seleniarm image. +ARCH=$(uname -m) +if [ ${ARCH} = "arm64" ]; then + IMAGE_SELENIUM="docker.io/seleniarm/standalone-chromium:4.10.0-20230615" +fi + +# Remove handled options and leaving the rest in the line, so it can be passed raw to commands +shift $((OPTIND - 1)) + +# Create .cache dir: composer and various npm jobs need this. +mkdir -p .cache +mkdir -p typo3temp/var/tests + +${CONTAINER_BIN} network create ${NETWORK} >/dev/null + +if [ ${CONTAINER_BIN} = "docker" ]; then + # docker needs the add-host for xdebug remote debugging. podman has host.container.internal built in + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} --rm --network ${NETWORK} --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" +else + # podman + CONTAINER_HOST="host.containers.internal" + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} ${CI_PARAMS} --rm --network ${NETWORK} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" +fi + +if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE="-e XDEBUG_MODE=off" + XDEBUG_CONFIG=" " + PHP_FPM_OPTIONS="-d xdebug.mode=off" +else + XDEBUG_MODE="-e XDEBUG_MODE=debug -e XDEBUG_TRIGGER=foo" + XDEBUG_CONFIG="client_port=${PHP_XDEBUG_PORT} client_host=${CONTAINER_HOST}" + PHP_FPM_OPTIONS="-d xdebug.mode=debug -d xdebug.start_with_request=yes -d xdebug.client_host=${CONTAINER_HOST} -d xdebug.client_port=${PHP_XDEBUG_PORT} -d memory_limit=256M" +fi + +# Suite execution +case ${TEST_SUITE} in + acceptance) + CODECEPION_ENV="--env ci" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,headless" + fi + if [ "${CHUNKS}" -gt 0 ]; then + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitAcceptanceTests.php -v ${CHUNKS} + COMMAND=(bin/codecept run Application -d -g AcceptanceTests-Job-${THISCHUNK} -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + else + COMMAND=(bin/codecept run Application -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + fi + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance" "${CORE_ROOT}/typo3temp/var/tests/AcceptanceReports" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance" + APACHE_OPTIONS="-e APACHE_RUN_USER=#${HOST_UID} -e APACHE_RUN_SERVERNAME=web -e APACHE_RUN_GROUP=#${HOST_PID} -e APACHE_RUN_DOCROOT=${CORE_ROOT}/typo3temp/var/tests/acceptance -e PHPFPM_HOST=phpfpm -e PHPFPM_PORT=9000" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -e PHPFPM_USER=${HOST_UID} -e PHPFPM_GROUP=${HOST_PID} -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm ${USERSET} -e PHPFPM_USER=0 -e PHPFPM_GROUP=0 -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm -R ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + fi + waitFor chrome 4444 + waitFor chrome 7900 + waitFor web 80 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + case ${DBMS} in + mariadb) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-ac-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mariadb-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mariadb ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-ac-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mysql-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mysql ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-ac-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=func_test -e typo3DatabaseUsername=funcu -e typo3DatabasePassword=funcp -e typo3DatabaseHost=postgres-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-postgres ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-sqlite ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + acceptanceInstall) + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance" "${CORE_ROOT}/typo3temp/var/tests/AcceptanceReports" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance" + APACHE_OPTIONS="-e APACHE_RUN_USER=#${HOST_UID} -e APACHE_RUN_SERVERNAME=web -e APACHE_RUN_GROUP=#${HOST_PID} -e APACHE_RUN_DOCROOT=${CORE_ROOT}/typo3temp/var/tests/acceptance -e PHPFPM_HOST=phpfpm -e PHPFPM_PORT=9000" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-istall-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm -d --name ac-install-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -e PHPFPM_USER=${HOST_UID} -e PHPFPM_GROUP=${HOST_PID} -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm -d --name ac-install-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-install-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm ${USERSET} -e PHPFPM_USER=0 -e PHPFPM_GROUP=0 -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm -R ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-install-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + fi + waitFor chrome 4444 + waitFor chrome 7900 + waitFor web 80 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + case ${DBMS} in + mariadb) + CODECEPION_ENV="--env ci,mysql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,mysql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-ac-install-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3InstallMysqlDatabaseName=func_test -e typo3InstallMysqlDatabaseUsername=root -e typo3InstallMysqlDatabasePassword=funcp -e typo3InstallMysqlDatabaseHost=mariadb-ac-install-${SUFFIX}" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-mariadb ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + mysql) + CODECEPION_ENV="--env ci,mysql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,mysql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-ac-install-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3InstallMysqlDatabaseName=func_test -e typo3InstallMysqlDatabaseUsername=root -e typo3InstallMysqlDatabasePassword=funcp -e typo3InstallMysqlDatabaseHost=mysql-ac-install-${SUFFIX}" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-mysql ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + postgres) + CODECEPION_ENV="--env ci,postgresql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,postgresql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-install-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-ac-install-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3InstallPostgresqlDatabasePort=5432 -e typo3InstallPostgresqlDatabaseName=${USER} -e typo3InstallPostgresqlDatabaseHost=postgres-ac-install-${SUFFIX} -e typo3InstallPostgresqlDatabaseUsername=funcu -e typo3InstallPostgresqlDatabasePassword=funcp" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-postgres ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + sqlite) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + CODECEPION_ENV="--env ci,sqlite" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,sqlite,headless" + fi + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-sqlite ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + esac + ;; + buildCss) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt css" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name build-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + buildJavascript) + COMMAND="cd Build/; npm ci || exit 1; node_modules/grunt/bin/grunt scripts" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name build-js-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + cgl) + # Active dry-run for cgl needs not "-n" but specific options + if [ -n "${CGLCHECK_DRY_RUN}" ]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + COMMAND="php -dxdebug.mode=off bin/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --path-mode intersection --config=Build/php-cs-fixer/config.php typo3/" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-${SUFFIX} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + cglGit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-git-${SUFFIX} ${IMAGE_PHP} Build/Scripts/cglFixMyCommit.sh ${CGLCHECK_DRY_RUN} + SUITE_EXIT_CODE=$? + ;; + cglHeader) + # Active dry-run for cgl needs not "-n" but specific options + if [ -n "${CGLCHECK_DRY_RUN}" ]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + COMMAND="php -dxdebug.mode=off bin/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --path-mode intersection --config=Build/php-cs-fixer/header-comment.php typo3/" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-header-${SUFFIX} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + cglHeaderGit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-header-git-${SUFFIX} ${IMAGE_PHP} Build/Scripts/cglFixMyCommitFileHeader.sh ${CGLCHECK_DRY_RUN} + SUITE_EXIT_CODE=$? + ;; + checkAnnotations) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-annotations-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/annotationChecker.php + SUITE_EXIT_CODE=$? + ;; + checkTestClassFinal) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-test-classes-final-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/testClassFinalChecker.php + SUITE_EXIT_CODE=$? + ;; + checkTestMethodsPrefix) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-test-methods-prefix-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/testMethodPrefixChecker.php + SUITE_EXIT_CODE=$? + ;; + checkBom) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-utf8bom-${SUFFIX} ${IMAGE_PHP} Build/Scripts/checkUtf8Bom.sh + SUITE_EXIT_CODE=$? + ;; + checkComposer) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-composer-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/checkIntegrityComposer.php + SUITE_EXIT_CODE=$? + ;; + checkExceptionCodes) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-exception-codes-${SUFFIX} ${IMAGE_PHP} Build/Scripts/duplicateExceptionCodeCheck.sh + SUITE_EXIT_CODE=$? + ;; + checkExtensionScannerRst) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-extensionscanner-rst-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/extensionScannerRstFileReferences.php + SUITE_EXIT_CODE=$? + ;; + checkFilePathLength) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-file-path-length-${SUFFIX} ${IMAGE_PHP} Build/Scripts/maxFilePathLength.sh + SUITE_EXIT_CODE=$? + ;; + checkGitSubmodule) + COMMAND="if [ \$(git submodule status 2>&1 | wc -l) -ne 0 ]; then echo \"Found a submodule definition in repository\"; exit 1; fi" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-git-submodule-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkGruntClean) + COMMAND="find 'typo3/sysext' -name '*.js' -not -path '*/Fixtures/*' -exec rm '{}' + && cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt build; cd ..; git add *; git status; git status | grep -q \"nothing to commit, working tree clean\"" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-grunt-clean-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkIsoDatabase) + COMMAND="git checkout -- composer.json; git checkout -- composer.lock; php -dxdebug.mode=off Build/Scripts/updateIsoDatabase.php; git add *; git status; git status | grep -q \"nothing to commit, working tree clean\"" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-iso-database-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkNamespaceIntegrity) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-namespaces-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/checkNamespaceIntegrity.php + SUITE_EXIT_CODE=$? + ;; + checkPermissions) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-permissions-${SUFFIX} ${IMAGE_PHP} Build/Scripts/checkFilePermissions.sh + SUITE_EXIT_CODE=$? + ;; + checkRst) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-rst-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/validateRstFiles.php + SUITE_EXIT_CODE=$? + ;; + clean) + cleanBuildFiles + cleanCacheFiles + cleanRenderedDocumentationFiles + cleanTestFiles + ;; + cleanBuild) + cleanBuildFiles + ;; + cleanCache) + cleanCacheFiles + ;; + cleanRenderedDocumentation) + cleanRenderedDocumentationFiles + ;; + cleanTests) + cleanTestFiles + ;; + composer) + COMMAND=(composer "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + composerInstall) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} composer install --no-progress --no-interaction + SUITE_EXIT_CODE=$? + ;; + composerInstallMax) + COMMAND="composer config --unset platform.php; composer update --no-progress --no-interaction; composer dumpautoload" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-max-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerInstallMin) + COMMAND="composer config platform.php ${PHP_VERSION}.0; composer update --prefer-lowest --no-progress --no-interaction; composer dumpautoload" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-min-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerTestDistribution) + COMMAND="cd Build/composer; rm -rf composer.json composer.lock public/index.php public/typo3 public/typo3conf/ext var/ vendor/; cp composer.dist.json composer.json; composer update --no-progress --no-interaction" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-test-distribution-${SUFFIX} -e COMPOSER_CACHE_DIR=${CORE_ROOT}/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerValidate) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-validate-${SUFFIX} ${IMAGE_PHP} composer validate + SUITE_EXIT_CODE=$? + ;; + functional) + if [ "${CHUNKS}" -gt 0 ]; then + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name func-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitFunctionalTests.php -v ${CHUNKS} + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTests-Job-${THISCHUNK}.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + else + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTests.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name redis-func-${SUFFIX} --network ${NETWORK} -d ${IMAGE_REDIS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name memcached-func-${SUFFIX} --network ${NETWORK} -d ${IMAGE_MEMCACHED} >/dev/null + waitFor redis-func-${SUFFIX} 6379 + waitFor memcached-func-${SUFFIX} 11211 + CONTAINER_COMMON_PARAMS="${CONTAINER_COMMON_PARAMS} -e typo3TestingRedisHost=redis-func-${SUFFIX} -e typo3TestingMemcachedHost=memcached-func-${SUFFIX}" + case ${DBMS} in + mariadb) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-func-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mariadb-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-func-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mysql-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-func-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-func-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=bamboo -e typo3DatabaseUsername=funcu -e typo3DatabaseHost=postgres-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + functionalDeprecated) + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTestsDeprecated.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name redis-func-dep-${SUFFIX} --network ${NETWORK} -d ${IMAGE_REDIS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name memcached-func-dep-${SUFFIX} --network ${NETWORK} -d ${IMAGE_MEMCACHED} >/dev/null + waitFor redis-func-dep-${SUFFIX} 6379 + waitFor memcached-func-dep-${SUFFIX} 11211 + CONTAINER_COMMON_PARAMS="${CONTAINER_COMMON_PARAMS} -e typo3TestingRedisHost=redis-func-dep-${SUFFIX} -e typo3TestingMemcachedHost=memcached-func-dep-${SUFFIX}" + case ${DBMS} in + mariadb) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-func-dep-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-func-dep-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mariadb-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-func-dep-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-func-dep-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mysql-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-func-dep-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-func-dep-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=bamboo -e typo3DatabaseUsername=funcu -e typo3DatabaseHost=postgres-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + lintPhp) + COMMAND="php -v | grep '^PHP'; find typo3/ -name \\*.php -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-php-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintScss) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt stylelint" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintTypescript) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt eslint" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-typescript-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintHtml) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt exec:lintspaces" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-html-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + listExceptionCodes) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name list-exception-codes-${SUFFIX} ${IMAGE_PHP} Build/Scripts/duplicateExceptionCodeCheck.sh -p + SUITE_EXIT_CODE=$? + ;; + phpstan) + COMMAND=(php -dxdebug.mode=off bin/phpstan analyse -c Build/phpstan/${PHPSTAN_CONFIG_FILE} --no-progress --no-interaction --memory-limit 4G "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-${SUFFIX} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + phpstanGenerateBaseline) + COMMAND="php -dxdebug.mode=off bin/phpstan analyse -c Build/phpstan/${PHPSTAN_CONFIG_FILE} --no-progress --no-interaction --memory-limit 4G --generate-baseline=Build/phpstan/phpstan-baseline.neon" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-baseline-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + unit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} "$@" + SUITE_EXIT_CODE=$? + ;; + unitDeprecated) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTestsDeprecated.xml ${EXTRA_TEST_OPTIONS} "$@" + SUITE_EXIT_CODE=$? + ;; + unitJavascript) + COMMAND="cd Build; npm ci || exit 1; CHROME_SANDBOX=false BROWSERS=chrome npm run test" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-javascript-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS_CHROME} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + unitRandom) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-random-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTests.xml --order-by=random ${EXTRA_TEST_OPTIONS} ${PHPUNIT_RANDOM} "$@" + SUITE_EXIT_CODE=$? + ;; + update) + # pull typo3/core-testing-* versions of those ones that exist locally + echo "> pull ghcr.io/typo3/core-testing-* versions of those ones that exist locally" + ${CONTAINER_BIN} images "ghcr.io/typo3/core-testing-*" --format "{{.Repository}}:{{.Tag}}" | xargs -I {} ${CONTAINER_BIN} pull {} + echo "" + # remove "dangling" typo3/core-testing-* images (those tagged as ) + echo "> remove \"dangling\" ghcr.io/typo3/core-testing-* images (those tagged as )" + ${CONTAINER_BIN} images --filter "reference=ghcr.io/typo3/core-testing-*" --filter "dangling=true" --format "{{.ID}}" | xargs -I {} ${CONTAINER_BIN} rmi -f {} + echo "" + ;; + *) + loadHelp + echo "Invalid -s option argument ${TEST_SUITE}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 + ;; +esac + +cleanUp + +# Print summary +echo "" >&2 +echo "###########################################################################" >&2 +echo "Result of ${TEST_SUITE}" >&2 +echo "Container runtime: ${CONTAINER_BIN}" >&2 +echo "PHP: ${PHP_VERSION}" >&2 +if [[ ${TEST_SUITE} =~ ^(functional|functionalDeprecated|acceptance|acceptanceInstall)$ ]]; then + case "${DBMS}" in + mariadb|mysql|postgres) + echo "DBMS: ${DBMS} version ${DBMS_VERSION} driver ${DATABASE_DRIVER}" >&2 + ;; + sqlite) + echo "DBMS: ${DBMS}" >&2 + ;; + esac +fi +if [[ -n ${EXTRA_TEST_OPTIONS} ]]; then + echo " Note: Using -e is deprecated. Simply add the options at the end of the command." + echo " Instead of: Build/Scripts/runTests.sh -s ${TEST_SUITE} -e '${EXTRA_TEST_OPTIONS}' $@" + echo " use: Build/Scripts/runTests.sh -s ${TEST_SUITE} -- ${EXTRA_TEST_OPTIONS} $@" +fi +if [[ ${SUITE_EXIT_CODE} -eq 0 ]]; then + echo "SUCCESS" >&2 +else + echo "FAILURE" >&2 +fi +echo "###########################################################################" >&2 +echo "" >&2 + +# Exit with code of test suite - This script return non-zero if the executed test failed. +exit $SUITE_EXIT_CODE diff --git a/Build/phpstan/phpstan.ci.neon b/Build/phpstan/phpstan.ci.neon new file mode 100644 index 0000000..b576235 --- /dev/null +++ b/Build/phpstan/phpstan.ci.neon @@ -0,0 +1,5 @@ +parameters: + level: 0 + paths: + - ../../Classes + - ../../Tests diff --git a/Build/phpstan/phpstan.local.neon b/Build/phpstan/phpstan.local.neon new file mode 100644 index 0000000..b576235 --- /dev/null +++ b/Build/phpstan/phpstan.local.neon @@ -0,0 +1,5 @@ +parameters: + level: 0 + paths: + - ../../Classes + - ../../Tests diff --git a/Build/phpunit/FunctionalTests.xml b/Build/phpunit/FunctionalTests.xml new file mode 100644 index 0000000..f264d10 --- /dev/null +++ b/Build/phpunit/FunctionalTests.xml @@ -0,0 +1,29 @@ + + + + + ../../Tests/Functional + + + + + + + + + + diff --git a/Build/phpunit/UnitTests.xml b/Build/phpunit/UnitTests.xml new file mode 100644 index 0000000..176969a --- /dev/null +++ b/Build/phpunit/UnitTests.xml @@ -0,0 +1,22 @@ + + + + + ../../Tests/Unit + + + + + + + + diff --git a/Build/testing-docker/docker-compose.yml b/Build/testing-docker/docker-compose.yml new file mode 100644 index 0000000..cfd6e43 --- /dev/null +++ b/Build/testing-docker/docker-compose.yml @@ -0,0 +1,188 @@ +version: '2.3' +services: + mariadb10: + image: mariadb:10 + environment: + MYSQL_ROOT_PASSWORD: funcp + tmpfs: + - /var/lib/mysql/:rw,noexec,nosuid + + postgres10: + image: postgres:10-alpine + environment: + POSTGRES_PASSWORD: funcp + POSTGRES_USER: ${HOST_USER} + tmpfs: + - /var/lib/postgresql/data:rw,noexec,nosuid + + composer_update: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + 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 req --dev --no-update \ + typo3/cms-composer-installers:^3.0 + composer req typo3/cms-core:^11.5 --no-update + fi + if [ ${TYPO3_VERSION} -eq 12 ]; then + composer req --dev --no-update \ + "typo3/cms-composer-installers:^5.0" \ + typo3/cms-backend:^12.4 \ + typo3/cms-frontend:^12.4 \ + typo3/cms-extbase:^12.4 \ + typo3/cms-fluid:^12.4 \ + typo3/cms-install:^12.4 + composer req typo3/cms-core:^12.4 -W --no-update + fi + composer update --no-progress --no-interaction; + " + + functional_mariadb10: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + links: + - mariadb10 + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseName: func_test + typo3DatabaseUsername: root + typo3DatabasePassword: funcp + typo3DatabaseHost: mariadb10 + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z mariadb10 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/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " + + functional_postgres10: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + links: + - postgres10 + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: pdo_pgsql + typo3DatabaseName: bamboo + typo3DatabaseUsername: ${HOST_USER} + typo3DatabaseHost: postgres10 + typo3DatabasePassword: funcp + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z postgres10 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/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + fi + " + + functional_sqlite: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + tmpfs: + - ${ROOT_DIR}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid,uid=${HOST_UID} + environment: + typo3DatabaseDriver: pdo_sqlite + working_dir: ${ROOT_DIR} + 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/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + fi + " + + lint: + image: typo3/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 + " + + unit: + image: typo3/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' + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " diff --git a/Classes/Command/CompleteGndWorksCommand.php b/Classes/Command/CompleteGndWorksCommand.php index 4541481..8916df2 100644 --- a/Classes/Command/CompleteGndWorksCommand.php +++ b/Classes/Command/CompleteGndWorksCommand.php @@ -4,25 +4,25 @@ * */ -namespace SLUB\MpdbCore\Command; +namespace Slub\MpdbCore\Command; +use Slub\DmNorm\Domain\Repository\GndInstrumentRepository; +use Slub\DmNorm\Domain\Repository\GndGenreRepository; +use Slub\DmNorm\Domain\Repository\GndPersonRepository; +use Slub\DmNorm\Domain\Repository\GndWorkRepository; +use Slub\MpdbCore\Lib\DbArray; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; -use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Core\Bootstrap; use TYPO3\CMS\Core\Database\ConnectionPool; -use TYPO3\CMS\Extbase\Object\ObjectManager; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManager; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; -use TYPO3\CMS\Core\Core\Bootstrap; -use SLUB\DMNorm\Domain\Repository\InstrumentRepository; -use SLUB\DMNorm\Domain\Repository\FormRepository; -use SLUB\MpdbCore\Lib\DbArray; -use SLUB\MpdbCore\Domain\Repository\PersonRepository; -use SLUB\MpdbCore\Domain\Repository\WorkRepository; -use \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; +use TYPO3\CMS\Extbase\Object\ObjectManager; +use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; /** * CompleteGndWorks Command class @@ -57,6 +57,10 @@ class CompleteGndWorksCommand extends Command */ protected $instrumentRepository = null; + protected ?SymfonyStyle $io = null; + + protected ?ExtensionConfiguration $extConf = null; + /** * formRepository * @@ -75,19 +79,8 @@ protected function initialize(InputInterface $input, OutputInterface $output) { * * @return void */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { - /* - $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); - $tmpConfiguration = $configurationManager->getConfiguration( - ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, - 'publisherDb' - ); - $configurationManager->setConfiguration($tmpConfiguration); - $om = GeneralUtility::makeInstance(ObjectManager::class); - $workRepository = $om->get(WorkRepository::class); - */ - $countWorks = $this->workRepository->findAll()->count(); $nonTitleWorks = $this->workRepository->findByTitle(''); $countNonTitleWorks = $nonTitleWorks->count(); @@ -113,7 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return Command::SUCCESS; } - protected function configure() + protected function configure(): void { $this->setHelp('Fetch GND data for new works (works without title).'); $this->setDescription('Fetching GND data for new works (works without title).'); @@ -126,19 +119,19 @@ protected function configure() * * @param int $storagePid The storage pid * - * @return bool + * @return void */ - protected function initializeRepositories() + protected function initializeRepositories(): void { $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); $frameworkConfiguration = $configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK); $frameworkConfiguration['persistence']['storagePid'] = 0; $configurationManager->setConfiguration($frameworkConfiguration); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - $this->workRepository = $objectManager->get(WorkRepository::class); - $this->personRepository = $objectManager->get(PersonRepository::class); - $this->instrumentRepository = $objectManager->get(InstrumentRepository::class); - $this->formRepository = $objectManager->get(FormRepository::class); + $this->workRepository = $objectManager->get(GndWorkRepository::class); + $this->personRepository = $objectManager->get(GndPersonRepository::class); + $this->instrumentRepository = $objectManager->get(GndInstrumentRepository::class); + $this->formRepository = $objectManager->get(GndGenreRepository::class); $this->extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('mpdb_core'); } diff --git a/Classes/Command/HealthCheckCommand.php b/Classes/Command/HealthCheckCommand.php index 56f5440..8bafdef 100644 --- a/Classes/Command/HealthCheckCommand.php +++ b/Classes/Command/HealthCheckCommand.php @@ -4,23 +4,23 @@ * */ -namespace SLUB\MpdbCore\Command; +namespace Slub\MpdbCore\Command; +use Slub\DmNorm\Domain\Repository\GndPersonRepository; +use Slub\DmNorm\Domain\Repository\GndWorkRepository; +use Slub\MpdbCore\Common\ElasticClientBuilder; +use Slub\MpdbCore\Domain\Repository\PublishedItemRepository; +use Slub\MpdbCore\Lib\DbArray; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Style\SymfonyStyle; -use SLUB\MpdbCore\Lib\DbArray; -use SLUB\MpdbCore\Common\ElasticClientBuilder; -use SLUB\MpdbCore\Domain\Repository\PublishedItemRepository; -use SLUB\MpdbCore\Domain\Repository\PersonRepository; -use SLUB\MpdbCore\Domain\Repository\WorkRepository; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManager; use TYPO3\CMS\Extbase\Object\ObjectManager; -use \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; +use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; /** * HealthCheck Command class @@ -40,7 +40,16 @@ class HealthCheckCommand extends Command const choiceRemovePersonDoubles = 'Remove double persons'; const choiceAll = 'Perform all checks'; - protected function initialize(InputInterface $input, OutputInterface $output) { + protected ?PublishedItemRepository $publishedItemRepository = null; + + protected ?GndPersonRepository $personRepository = null; + + protected ?GndWorkRepository $workRepository = null; + + protected ?SymfonyStyle $io = null; + + protected function initialize(InputInterface $input, OutputInterface $output): void + { $this->io = new SymfonyStyle($input, $output); $this->io->title($this->getDescription()); } @@ -48,9 +57,9 @@ protected function initialize(InputInterface $input, OutputInterface $output) { /** * Executes the command to build indices from Database * - * @return void + * @return int */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $helper = $this->getHelper('question'); $question = new ChoiceQuestion( @@ -79,7 +88,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return Command::SUCCESS; } - protected function checkMvdbIds() + protected function checkMvdbIds(): void { $this->io->section('Checking all MVDB IDs'); $publishedItems = $this->publishedItemRepository->findAll(); @@ -102,18 +111,18 @@ protected function checkMvdbIds() /** * Pre-Execution configuration * - * @return array + * @return void */ - protected function configure() + protected function configure(): void { $this->setHelp('Check Database Consistency'); } - protected function setFinal() + protected function setFinal(): void { } - protected function setWorkTitles() + protected function setWorkTitles(): void { $this->io->section('Checking all work titles'); $works = $this->workRepository->findAll(); @@ -134,11 +143,11 @@ protected function setWorkTitles() $this->io->progressFinish(); } - protected function setInstrumentationNames() + protected function setInstrumentationNames(): void { } - protected function removeDoubleWorks() + protected function removeDoubleWorks(): void { $this->io->section('Removing double works'); $publishedItems = $this->publishedItemRepository->findAll(); @@ -175,7 +184,7 @@ protected function removeDoubleWorks() $this->removeUnusedWorks(); } - protected function removeDoublePersons() + protected function removeDoublePersons(): void { $this->io->section('Removing double persons'); $works = $this->workRepository->findAll(); @@ -238,11 +247,11 @@ protected function removeDoublePersons() $this->removeUnusedPersons(); } - protected function removeDoublePlaces() + protected function removeDoublePlaces(): void { } - protected function removeUnusedWorks() + protected function removeUnusedWorks(): void { $this->io->section('Removing unused works'); $publishedItems = $this->publishedItemRepository->findAll(); @@ -267,7 +276,7 @@ protected function removeUnusedWorks() $this->io->progressFinish(); } - protected function removeUnusedPersons() + protected function removeUnusedPersons(): void { $this->io->section('Removing unused persons'); $works = $this->workRepository->findAll(); @@ -311,7 +320,7 @@ protected function removeUnusedPersons() $this->io->progressFinish(); } - protected function removeUnusedPlaces() + protected function removeUnusedPlaces(): void { } @@ -322,17 +331,17 @@ protected function removeUnusedPlaces() * * @param int $storagePid The storage pid * - * @return bool + * @return void */ - protected function initializeRepositories() + protected function initializeRepositories(): void { $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); $frameworkConfiguration = $configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK); $frameworkConfiguration['persistence']['storagePid'] = 0; $configurationManager->setConfiguration($frameworkConfiguration); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - $this->workRepository = $objectManager->get(WorkRepository::class); - $this->publishedItemRepository = $objectManager->get(publishedItemRepository::class); - $this->personRepository = $objectManager->get(PersonRepository::class); + $this->workRepository = $objectManager->get(GndWorkRepository::class); + $this->publishedItemRepository = $objectManager->get(PublishedItemRepository::class); + $this->personRepository = $objectManager->get(GndPersonRepository::class); } } diff --git a/Classes/Command/IndexCommand.php b/Classes/Command/IndexCommand.php index d9e7fcc..52a6057 100644 --- a/Classes/Command/IndexCommand.php +++ b/Classes/Command/IndexCommand.php @@ -2,6 +2,7 @@ namespace Slub\MpdbCore\Command; +use Elastic\Elasticsearch\Client; use Illuminate\Support\Collection; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -29,6 +30,16 @@ class IndexCommand extends Command const WORK_INDEX = 'work'; const PERSON_INDEX = 'person'; + const NAME_COLNAME = 'name'; + const SHORTHAND_COLNAME = 'shorthand'; + const PUBLIC_COLNAME = 'public'; + const PUBLISHER_TABLE_NAME = 'tx_mpdbcore_domain_model_publisher'; + const PUBLISHER_INDEX_NAME = 'publishers'; + + protected string $prefix = ''; + protected ?Client $client = null; + protected ?ExtensionConfiguration $extConf = null; + protected static $personData = [ [ 'name', '', 'string' ], [ 'gnd_id', '', 'string' ], @@ -504,7 +515,10 @@ class IndexCommand extends Command protected $indexList; - protected function initialize(InputInterface $input, OutputInterface $output) { + protected ?SymfonyStyle $io = null; + + protected function initialize(InputInterface $input, OutputInterface $output): void + { $this->dataObjectList = [ 'person' => [ 'table' => 'tx_dmnorm_domain_model_gndperson', @@ -588,19 +602,27 @@ protected function initialize(InputInterface $input, OutputInterface $output) { 'fields' => self::$genreData ] ]; + $this->indexList = [ self::PUBLISHED_ITEM_INDEX => self::$publishedItemSeq, self::PERSON_INDEX => self::$personSeq, self::WORK_INDEX => self::$workSeq ]; + + $this->extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('mpdb_core'); + $this->prefix = $this->extConf['prefix']; + + $this->client = ElasticClientBuilder::create()-> + autoconfig()-> + build(); } /** * Executes the command to build indices from Database * - * @return void + * @return int */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { //$this->initialize(); @@ -616,6 +638,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->io->section('Committing Indices'); $this->commitIndices(); + $this->io->section('Indexing Publishers'); + $this->indexPublishers(); $this->io->success('All indices built and committed.'); return 0; @@ -623,29 +647,61 @@ protected function execute(InputInterface $input, OutputInterface $output) } /** - * Commits indices to Elasticsearch + * Indexes public publishers * * @return void */ - protected function commitIndices() { - $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('mpdb_core'); - $prefix = $extConf['prefix']; - $client = ElasticClientBuilder::create()-> - autoconfig()-> - build(); + protected function indexPublishers(): void + { + $qb = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable(self::PUBLISHER_TABLE_NAME); + $qb->select( + 'uid', + self::NAME_COLNAME . ' AS name', + self::SHORTHAND_COLNAME . ' AS shorthand', + self::PUBLIC_COLNAME . ' AS public' + )-> + from(self::PUBLISHER_TABLE_NAME); + + if ($this->client->indices()->exists(['index' => $this->prefix . self::PUBLISHER_INDEX_NAME])) { + $this->client->indices()->delete(['index' => $this->prefix . self::PUBLISHER_INDEX_NAME]); + } + + Collection::wrap($qb->execute()->fetchAll())-> + filter(function ($publisher) { return self::isPublic($publisher); })-> + each(function ($publisher) { self::indexPublisher($publisher); }); + } + + private static function isPublic(array $publisher): bool { + return (bool) $publisher[self::PUBLIC_COLNAME]; + } + private function indexPublisher(array $publisher): void { + unset($publisher[self::PUBLIC_COLNAME]); + + $params = [ + 'index' => $this->prefix . self::PUBLISHER_INDEX_NAME, + 'id' => $publisher['uid'], + 'body' => $publisher ]; + + $this->client->index($params); + } + + /** + * Commits indices to Elasticsearch + * + * @return void + */ + protected function commitIndices(): void + { foreach ($this->indices as $name => $index) { $this->io->text('Committing the ' . $name . ' index'); $idField = $this->dataObjectList[$name]['key']; - //$indexName = Collection::wrap([ $extConf['prefix'], $name ]).join('_'); $params = []; $params = [ 'body' => [] ]; $bulkCount = 0; - $client = ElasticClientBuilder::create()-> - autoconfig()-> - build(); $this->io->progressStart(count($index)); foreach ($index as $document) { @@ -653,38 +709,38 @@ protected function commitIndices() { $this->io->progressAdvance(); $params['body'][] = [ 'index' => [ - '_index' => 'temp' . $prefix . $name, + '_index' => 'temp' . $this->prefix . $name, '_id' => $document[$idField] ] ]; $params['body'][] = json_encode($document); // commit bulk - if (!(++$bulkCount % $extConf['bulkSize'])) { - $client->bulk($params); + if (!(++$bulkCount % $this->extConf['bulkSize'])) { + $this->client->bulk($params); $params = [ 'body' => [] ]; } } $this->io->progressFinish(); - $client->bulk($params); + $this->client->bulk($params); - if ($client->indices()->exists(['index' => $prefix . $name])) { - $client->indices()->delete(['index' => $prefix . $name]); + if ($this->client->indices()->exists(['index' => $this->prefix . $name])) { + $this->client->indices()->delete(['index' => $this->prefix . $name]); } $params = [ - 'index' => 'temp' . $prefix . $name, + 'index' => 'temp' . $this->prefix . $name, 'body' => [ 'index.blocks.write' => TRUE ] ]; - $client->indices()->putSettings($params); + $this->client->indices()->putSettings($params); $params = [ - 'index' => 'temp' . $prefix . $name, - 'target' => $prefix . $name + 'index' => 'temp' . $this->prefix . $name, + 'target' => $this->prefix . $name ]; - $client->indices()->clone($params); - $client->indices()->delete(['index' => 'temp' . $prefix . $name]); + $this->client->indices()->clone($params); + $this->client->indices()->delete(['index' => 'temp' . $this->prefix . $name]); } } @@ -693,7 +749,8 @@ protected function commitIndices() { * * @return array */ - protected static function getSelectStmt(array $fields = null, bool $mm) { + protected static function getSelectStmt(array $fields = null, bool $mm): array + { if ($mm) { return [ 'uid_local', 'uid_foreign' ]; } @@ -715,7 +772,8 @@ protected static function getSelectStmt(array $fields = null, bool $mm) { * * @return void */ - protected function fetchObjects() { + protected function fetchObjects(): void + { foreach ($this->dataObjectList as $name => $object) { $mm = preg_match('/_mm/', $name) ? TRUE : FALSE; $fields = isset($object['fields']) ? $object['fields'] : null; @@ -744,7 +802,8 @@ protected function fetchObjects() { * * @return array */ - protected function buildIndex($indexSeq) { + protected function buildIndex($indexSeq): array + { // TODO rewrite to static function? $buffer = []; foreach ($indexSeq as $step) { @@ -786,7 +845,8 @@ protected function buildIndex($indexSeq) { * @param array $bufferedObject * @return array */ - protected function index(array $config, array $bufferedObject = null) { + protected function index(array $config, array $bufferedObject = null): array + { $indexedObjects = []; if ($config['mm']) { @@ -818,9 +878,10 @@ protected function index(array $config, array $bufferedObject = null) { /** * Builds indices * - * @return array + * @return void */ - protected function buildIndices() { + protected function buildIndices(): void + { $this->io->text('Separating Publisher Actions'); $this->dataObjects['prints'] = []; $this->dataObjects['sales'] = []; @@ -852,15 +913,15 @@ protected function buildIndices() { /** * Pre-Execution configuration * - * @return array + * @return void */ - protected function configure() + protected function configure(): void { $this->setHelp('Update elasticsearch index.'); $this->setDescription('Updating the elasticsearch index.'); } - protected function correctDatatypes(array $data, array $tables) + protected function correctDatatypes(array $data, array $tables): array { $mapper = []; foreach($tables as $key => $table) { diff --git a/Classes/Common/ElasticClientBuilder.php b/Classes/Common/ElasticClientBuilder.php index 34e1a73..d73f436 100644 --- a/Classes/Common/ElasticClientBuilder.php +++ b/Classes/Common/ElasticClientBuilder.php @@ -4,14 +4,19 @@ * This class wraps around Elasticsearch's ClientBuilder and offers an automatic configuration */ -namespace SLUB\MpdbCore\Common; +namespace Slub\MpdbCore\Common; use TYPO3\CMS\Core\Utility\GeneralUtility; -use Elasticsearch\ClientBuilder; +use Elastic\Elasticsearch\ClientBuilder; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; class ElasticClientBuilder extends ClientBuilder { + public static function create(): ElasticClientBuilder + { + return new ElasticClientBuilder(); + } + public function autoconfig () { $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('mpdb_core'); diff --git a/Classes/Controller/AbstractController.php b/Classes/Controller/AbstractController.php index 8131369..5e8f14e 100644 --- a/Classes/Controller/AbstractController.php +++ b/Classes/Controller/AbstractController.php @@ -1,19 +1,24 @@ searchService = $searchService; + } else { + throw new SearchServiceNotFoundException(); + } + + $this->searchService-> + setSize(self::RESULT_COUNT); + } + /** * @param GndGenreRepository $gndGenreRepository */ @@ -172,6 +209,14 @@ public function injectGndPersonRepository(GndPersonRepository $gndPersonReposito $this->gndPersonRepository = $gndPersonRepository; } + /** + * @param PublisherActionRepository $publisherActionRepository + */ + public function injectPublisherActionRepository(PublisherActionRepository $publisherActionRepository) + { + $this->publisherActionRepository = $publisherActionRepository; + } + /** * @param PublisherRepository $publisherRepository */ diff --git a/Classes/Controller/PublishedItemController.php b/Classes/Controller/PublishedItemController.php index a150a99..cd774c4 100644 --- a/Classes/Controller/PublishedItemController.php +++ b/Classes/Controller/PublishedItemController.php @@ -1,23 +1,24 @@ publisherRepository->findAll(); $desc = false; - $publisherMakroItems = $this->publisherMakroItemRepository-> + $publisherMakroItems = $this->publishedItemRepository-> dbListFe($publisher, $sortString, $desc, $final); $publisherMakroItemPaginator = new QueryResultPaginator($publisherMakroItems, $from, $itemsPerPage); @@ -103,47 +104,28 @@ private function makeQuickpager(int $current, SimplePagination $pagination): arr return $pages; } - private function search($level, $searchTerm, $publisher) + private function searchAction(array $config) { - $umlauts = ['ae', 'oe', 'ue', 'ss', 'ä', 'ö', 'ü', 'é']; - $purgedTerm = str_replace($umlauts, ' ', $searchTerm); - $makrosFromPersons = (new DbArray(explode(' ', $purgedTerm)))-> - filter(function ($term) { return strlen($term) != 1; })-> - map( function ($term) use ($level) { return $this->personRepository->search($term, $level)->toArray(); } )-> - merge()-> - unique()-> - map( function ($person) { return $person->getWorks()->toArray(); } )-> - merge()-> - map( function ($work) { return $work->getPublisherMakroItems()->toArray(); } )-> - merge()-> - filter( function ($makro) { return $makro->getFinal() >= $level; } ); - if ($publisher) { - $makrosFromPersons = $makrosFromPersons - ->filter( function ($makro) use ($publisher) { - return $makro->getPublisher() == $publisher; } ); - } - return (new DbArray())-> - set(explode(' ', $purgedTerm))-> - filter(function ($term) { return strlen($term) != 1; })-> - map(function ($term) use ($level, $publisher) { return $this->publisherMakroItemRepository->dbSearchFe($level, $term, $publisher)->toArray(); })-> - merge()-> - concat($makrosFromPersons->toArray())-> - group( - function ($item) { return $item; }, - function ($item) { return $item->getMvdbId(); } - )-> - map( - function ($groupedItem) use($searchTerm) { - $baseRelevance = 0; - if ($groupedItem['groupObject']->getTitle() === $searchTerm) { - $baseRelevance = 1; - } - return ['item' => $groupedItem['groupObject'], 'relevance' => count($groupedItem['group'])]; - } - )-> - sort(function ($a, $b) { return $a['relevance'] - $b['relevance']; })-> - map(function ($groupedItem) { return $groupedItem['item']; })-> - toArray(); + $publishedItems = $this->searchService-> + setPublisher($config['publisher'] ?? '')-> + setIndex(IndexCommand::PUBLISHED_ITEM_INDEX)-> + setSearchterm($config['searchTerm'] ?? '')-> + setFrom($config['from'] ?? 0)-> + search(); + $totalItems = $this->searchService->count(); + $publishers = $this->searchService-> + reset()-> + setIndex(IndexCommand::PUBLISHER_INDEX_NAME)-> + search()-> + pluck('_source'); + + $this->view->assign('entities', $publishedItems->all()); + $this->view->assign('config', $config); + $this->view->assign('totalItems', $totalItems); + $this->view->assign('publishers', $publishers->all()); + $this->view->assign('resultCount', self::RESULT_COUNT); + + return $this->htmlResponse(); } /** @@ -163,14 +145,16 @@ public function showAction(PublishedItem $publishedItem) // use dbarray! foreach ($publisherMikroItems as $publisherMikroItem) { $publisherActions = array_merge( - $publisherActions, - $this->publisherActionRepository->findByPublisherMikroItem($publisherMikroItem)->toArray() + $publisherActions, + $this->publisherActionRepository-> + findByPublisherMikroItem($publisherMikroItem)-> + toArray() ); } usort($publisherActions, $sortByDate); $document = $this->elasticClient->get([ - 'index' => PublishedItem::TABLE_INDEX_NAME, + 'index' => IndexCommand::PUBLISHED_ITEM_INDEX, 'id' => $publishedItem->getMvdbId() ]); $jsonDocument = json_encode($document['_source']); @@ -208,39 +192,6 @@ protected static function scriptWrap(string $call): string return ''; } - /** - * action lookup - * - * @param string $searchString - * @return void - */ - public function lookupAction(string $searchString) - { - $delim = substr_count($searchString, '_') ? '_' : ','; - $query = explode($delim, $searchString); - if (isset($query[1])) - $plate = trim($query[1]); - $publisherShorthand = trim($query[0]); - $publisher = $this->publisherRepository->findOneByShorthand($publisherShorthand); - - if ($publisher && $plate) { - $publisherMakroItem = $this->publisherMakroItemRepository->lookupPlateId($plate, $publisher, $this->level); - if ($publisherMakroItem) { - foreach ($publisherMakroItem->getPublisherMikroItems() as $publisherMikroItem) { - if ($publisherMikroItem->getPlateId() == $plate) break; - } - if (TYPO3_MODE === 'BE') - $this->redirect('edit', null, null, ['publisherMakroItem' => $publisherMakroItem, 'activeMikro' => $publisherMikroItem]); - else - $this->redirect('show', null, null, ['publisherMakroItem' => $publisherMakroItem]); - } else { - $this->addFlashMessage('Verlagsartikel nicht gefunden', 'Fehler', \TYPO3\CMS\Core\Messaging\AbstractMessage::ERROR); - $this->redirect('list'); - } - } - $this->redirect('search', null, null, ['term' => $searchString]); - } - /** * action getNext * @@ -249,7 +200,7 @@ public function lookupAction(string $searchString) */ public function getNextAction(PublishedItem $publisherMakroItem) { - $next = $this->publisherMakroItemRepository->findNext($publisherMakroItem); + $next = $this->publishedItemRepository->findNext($publisherMakroItem); if ($next) { $this->redirect('edit', null, null, ['publisherMakroItem' => $next]); } else { @@ -265,7 +216,7 @@ public function getNextAction(PublishedItem $publisherMakroItem) */ public function getPreviousAction(PublishedItem $publisherMakroItem) { - $previous = $this->publisherMakroItemRepository->findPrevious($publisherMakroItem); + $previous = $this->publishedItemRepository->findPrevious($publisherMakroItem); if ($previous) { $this->redirect('edit', null, null, ['publisherMakroItem' => $previous]); } else { @@ -273,118 +224,4 @@ public function getPreviousAction(PublishedItem $publisherMakroItem) } } - /** - * action lookupWork - * - * @param Slub\MpdbCore\Domain\Model\PublishedItem $publisherMakroItem - * @param string $name - * @return void - */ - public function lookupWorkAction(PublisherMakroItem $publisherMakroItem, string $name) - { - $works = $this->workRepository->lookupWork($name); - $this->view->assign('works', $works); - $this->view->assign('name', $name); - $this->view->assign('publisherMakroItem', $publisherMakroItem); - } - - /** - * action lookupForm - * - * @param Slub\MpdbCore\Domain\Model\PublishedItem $publisherMakroItem - * @param string $name - * @return void - */ - public function lookupFormAction( - PublisherMakroItem $publisherMakroItem, - string $name - ) - { - //throw away or refactor - $forms = $this->objectManager->get('SLUB\\PublisherDb\\Domain\\Repository\\FormRepository')->lookupForm($name); - $forms = Tools::elimDuplicates($forms); - $this->view->assign('forms', $forms); - $this->view->assign('publisherMakroItem', $publisherMakroItem); - } - - /** - * action lookupInstrument - * - * @param Slub\MpdbCore\Domain\Model\PublishedItem $publisherMakroItem - * @param string $name - * @return void - */ - public function lookupInstrumentAction(PublishedItem $publisherMakroItem, string $name) - { - //throw away or refactor - $instruments = $this->objectManager->get('SLUB\\PublisherDb\\Domain\\Repository\\InstrumentRepository')->lookupInstrument($name); - $instruments = Tools::elimDuplicates($instruments); - $url = 'http://sdvlodpro.slub-dresden.de:9200/gnd_marc21/_search?q=150.__.a.keyword:' . $name; - $query = json_decode(file_get_contents($url), true); - foreach ($query['hits']['hits'] as $set) { - $superWord = ''; - $flatSet = \SLUB\PublisherDb\Lib\GndLib::flattenDataSet($set['_source']); - foreach ($flatSet[550] as $row) { - if ($row['i'] == 'Oberbegriff allgemein') { - if ($superWord) { - $superWord = $superWord . ', ' . $row['a']; - } else { - $superWord = $row['a']; - } - } - } - $queryOut[] = [ - 'name' => $flatSet[150][0]['a'], - 'superWord' => $superWord, - 'id' => $flatSet['024'][0]['a'] - ]; - } - $this->view->assign('query', $queryOut); - $this->view->assign('instruments', $instruments); - $this->view->assign('publisherMakroItem', $publisherMakroItem); - } - - /** - * action search - * - * @param string $term - * @return void - */ - public function searchAction(string $term) - { - $params = [ - 'index' => 'published_item', - 'body' => [ - 'query' => [ - 'query_string' => [ - 'query' => $term - ] - ] - ] - ]; - $elasticResults = $this->elasticClient->search($params)['hits']['hits']; - - foreach ($elasticResults as $elasticResult) { - $results[] = $this->publisherMakroItemRepository->findByUid($elasticResult['_source']['uid']); - } - - $this->view->assign('publisherMakroItems', $results ?? []); - } - - /** - * action lookupPerson - * - * @param PublisherMakroItem $publisherMakroItem - * @param string $name - * @param string $role - * @return void - */ - public function lookupPersonAction(PublishedItem $publisherMakroItem, string $name, string $role) - { - $persons = $this->personRepository->lookupComposer($name); - $persons = Tools::elimDuplicates($persons); - $this->view->assign('persons', $persons); - $this->view->assign('publisherMakroItem', $publisherMakroItem); - $this->view->assign('role', $role); - } } diff --git a/Classes/Domain/Model/PublishedItem.php b/Classes/Domain/Model/PublishedItem.php index a13198d..3dd203f 100755 --- a/Classes/Domain/Model/PublishedItem.php +++ b/Classes/Domain/Model/PublishedItem.php @@ -1,8 +1,11 @@ pianoCombination = $pianoCombination; @@ -254,7 +250,7 @@ public function setPianoCombination($pianoCombination) * * @return void */ - public function getPianoCombination() + public function getPianoCombination(): string { return $this->pianoCombination; } @@ -262,9 +258,9 @@ public function getPianoCombination() /** * gets if published item is a piano reduction * - * @return boolean + * @return bool */ - public function getIsPianoReduction() + public function getIsPianoReduction(): bool { $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('mpdb_core'); @@ -283,20 +279,24 @@ public function getIsPianoReduction() * @param string $mvdbId * @return void */ - public function setMvdbId() + public function setMvdbId(): void { - $this->setPlateIds(); - $minPlateId = $this->getPlateIds() ? min($this->getPlateIds()) : ''; - $this->mvdbId = $this->publisher->getShorthand() . - '_' . $minPlateId; + $minPlateId = $this->getPlateIds()->min(); + $this->mvdbId = $this->publisher ? + $this->publisher->getShorthand() . '_' : ''; + $this->mvdbId .= $minPlateId; - foreach($this->publishedSubitems as $publishedSubitem) { - $publishedSubitem->setMvdbId( - $this->mvdbId . '_' . - $publishedSubitem->getPlateId() . '_' . - $publishedSubitem->getPart() . '_' . - $publishedSubitem->getVoice()); - } + Collection::wrap($this->publishedSubitems->toArray())-> + each( function($subitem) { $this->setSubitemMvdbId($subitem); } ); + } + + protected function setSubitemMvdbId(PublishedSubitem $subitem): void + { + $subitem->setMvdbId( + $this->mvdbId . '_' . + $subitem->getPlateId() . '_' . + $subitem->getPart() . '_' . + $subitem->getVoice()); } /** @@ -304,7 +304,7 @@ public function setMvdbId() * * @return string type */ - public function getType() + public function getType(): string { return $this->type; } @@ -315,7 +315,7 @@ public function getType() * @param int $type * @return void */ - public function setType($type) + public function setType($type): void { $this->type = $type; } @@ -325,12 +325,11 @@ public function setType($type) */ public function __construct() { - //Do not remove the next line: It would break the functionality $this->initializeObject(); } - public function initializeObject() + public function initializeObject(): void { $this->containedWorks = new ObjectStorage(); $this->editors = new ObjectStorage(); @@ -345,7 +344,7 @@ public function initializeObject() * * @return string $instrumentation */ - public function getInstrumentation() + public function getInstrumentation(): string { return $this->instrumentation; } @@ -356,7 +355,7 @@ public function getInstrumentation() * @param string $instrumentation * @return void */ - public function setInstrumentation($instrumentation) + public function setInstrumentation($instrumentation): void { $this->instrumentation = $instrumentation; } @@ -366,7 +365,7 @@ public function setInstrumentation($instrumentation) * * @return \Slub\MpdbCore\Domain\Model\Publisher $publisher */ - public function getPublisher() + public function getPublisher(): ?Publisher { return $this->publisher; } @@ -377,13 +376,10 @@ public function getPublisher() * @param \Slub\MpdbCore\Domain\Model\Publisher $publisher * @return void */ - public function setPublisher(Publisher $publisher = null) + public function setPublisher(Publisher $publisher = null): void { - $this->mvdbId = $this->getPlateIdFrom(); - if ($publisher !== null) { - $this->mvdbId = $publisher->getShorthand() . '_' . $this->mvdbId; - } $this->publisher = $publisher; + $this->setMvdbId(); } /** @@ -391,7 +387,7 @@ public function setPublisher(Publisher $publisher = null) * * @return string title */ - public function getTitle() + public function getTitle(): string { return $this->title; } @@ -402,7 +398,7 @@ public function getTitle() * @param int $title * @return void */ - public function setTitle($title) + public function setTitle($title): void { $this->title = $title; } @@ -413,11 +409,12 @@ public function setTitle($title) * @param \Slub\PublisherDb\Domain\Model\PublishedSubitem $publishedSubitem * @return void */ - public function addPublishedSubitem(PublishedSubitem $publishedSubitem = null) + public function addPublishedSubitem(PublishedSubitem $publishedSubitem = null): void { if ($publishedSubitem != null) { $this->publishedSubitems->attach($publishedSubitem); } + $this->setMvdbId(); } /** @@ -426,9 +423,10 @@ public function addPublishedSubitem(PublishedSubitem $publishedSubitem = null) * @param \Slub\MpdbCore\Domain\Model\PublishedSubitem $publishedSubitemToRemove * @return void */ - public function removePublishedSubitem(PublishedSubitem $publishedSubitemToRemove) + public function removePublishedSubitem(PublishedSubitem $publishedSubitemToRemove): void { $this->publishedSubitems->detach($publishedSubitemToRemove); + $this->setMvdbId(); } /** @@ -437,7 +435,7 @@ public function removePublishedSubitem(PublishedSubitem $publishedSubitemToRemov * @param \Slub\DmNorm\Domain\Model\GndWork $containedWork * @return void */ - public function addContainedWork(GndWork $containedWork = null) + public function addContainedWork(GndWork $containedWork = null): void { if ($containedWork != null) { $this->containedWorks->attach($containedWork); @@ -450,7 +448,7 @@ public function addContainedWork(GndWork $containedWork = null) * @param \Slub\DmNorm\Domain\Model\GndWork $containedWorkToRemove The Work to be removed * @return void */ - public function removeContainedWork(GndWork $containedWorkToRemove) + public function removeContainedWork(GndWork $containedWorkToRemove): void { $this->containedWorks->detach($containedWorkToRemove); } @@ -460,7 +458,7 @@ public function removeContainedWork(GndWork $containedWorkToRemove) * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\MpdbCore\Domain\Model\PublisherActions> publisherActions */ - public function getPublisherActions() + public function getPublisherActions(): ObjectStorage { return array_merge( ...array_map( @@ -476,9 +474,9 @@ function ($mikro) { * Returns boolean indicating if there are publisherActions pointing * to the Makro * - * @return boolean + * @return bool */ - public function getHasPublisherActions() + public function getHasPublisherActions(): bool { $mikros = $this->getPublishedSubitems()->toArray(); foreach ($mikros as $mikro) { @@ -494,9 +492,9 @@ public function getHasPublisherActions() * * @return string */ - public function getNumberOfMikroString() + public function getNumberOfMikroString(): string { - return $this->publishedSubitemRepository->getNumberOfMikroString($this); + return $this->publishedSubitems->count(); } /** @@ -504,7 +502,7 @@ public function getNumberOfMikroString() * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\MpdbCore\Domain\Model\PublishedSubitem> $publishedSubitems */ - public function getPublishedSubitems() + public function getPublishedSubitems(): ObjectStorage { return $this->publishedSubitems; } @@ -515,7 +513,7 @@ public function getPublishedSubitems() * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\MpdbCore\Domain\Model\PublishedSubitem> $publishedSubitems * @return void */ - public function setPublishedSubitems(ObjectStorage $publishedSubitems = null) + public function setPublishedSubitems(ObjectStorage $publishedSubitems = null): void { $publishedSubitems = $publishedSubitems ?? new ObjectStorage(); $this->publishedSubitems = $publishedSubitems; @@ -526,7 +524,7 @@ public function setPublishedSubitems(ObjectStorage $publishedSubitems = null) * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmNorm\Domain\Model\GndWork> $containedWorks */ - public function getContainedWorks() + public function getContainedWorks(): ObjectStorage { return $this->containedWorks; } @@ -537,111 +535,18 @@ public function getContainedWorks() * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmNorm\Domain\Model\GndWork> $containedWorks * @return void */ - public function setContainedWorks(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $containedWorks = null) + public function setContainedWorks(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $containedWorks = null): void { $containedWorks = $containedWorks ?? new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); $this->containedWorks = $containedWorks; } - /** - * Returns the plateIdFrom - * - * @return string $plateIdFrom - */ - public function getPlateIdFrom() - { - // ?? - return (new \SLUB\PublisherDb\Lib\DbArray())->set($this->getPublishedSubitems())->map( - function ($mikro) { - return $mikro->getPlateId(); - } - )->reduce( - function ($a, $b) { - return $a < $b ? $a : $b; - }, - '10000000' - ); - } - - /** - * Checks if current plateIdFrom is minimal plateId of contained Mikros - * - * @param array $mikros - * @return void - */ - public function minPlateIdFromAdd(array $mikros) - { - // throw away!! - $getPlateId = function(PublishedSubitem $publishedSubitem): string { - return $publishedSubitem->getPlateId(); - }; - - $this->plateIdFrom = (new DbArray()) - ->set( $mikros ) - ->map( $getPlateId ) - ->min(); - $this->updateIdentifier(); - } - - /** - * Checks if current plateIdFrom is minimal plateId of contained Mikros - * - * @param \TYPO3\CMS\Extbase\Persistence\Generic\QueryResult $mikros - * @param string $oldPlateId - * @return void - */ - public function minPlateIdFromRemove(\TYPO3\CMS\Extbase\Persistence\Generic\QueryResult $mikros, string $oldPlateId) - { - // throw away! - $min = '10000000'; - $encounteredSameNumber = false; - foreach ($mikros as $mikro) { - if (!$encounteredSameNumber && $mikro->getPlateId() != $oldPlateId) { - continue; - } - if ($mikro->getPlateId() < $min) { - $min = $mikro->getPlateId(); - } - } - $this->plateIdFrom = $min; - $this->updateIdentifier(); - } - - public function updateMvdbId() { - $getPlateId = function(PublishedSubitem $publishedSubitem): string { - return $publishedSubitem->getPlateId(); - }; - - $this->plateIdFrom = (new DbArray()) - ->set( $this->getPublishedSubitems()->toArray() ) - ->map( $getPlateId ) - ->min(); - - $this->mvdbId = $this->plateIdFrom; - if (!is_null($this->publisher)) { - $this->mvdbId = $this->publisher->getShorthand() . '_' . $this->plateIdFrom; - } - } - /** - * Updates Identifier according to publisher name and plateIdFrom - * - * @return void - */ - public function updateIdentifier() - { - // throw away! - $this->mvdbId = $this->plateIdFrom; - if (!is_null($this->publisher)) { - $this->mvdbId = $this->publisher->getShorthand() . '_' . $this->plateIdFrom; - } - } - /** * Returns the dataAcquisitionCertain * * @return bool $dataAcquisitionCertain */ - public function getDataAcquisitionCertain() + public function getDataAcquisitionCertain(): bool { return $this->dataAcquisitionCertain; } @@ -652,7 +557,7 @@ public function getDataAcquisitionCertain() * @param bool $dataAcquisitionCertain * @return void */ - public function setDataAcquisitionCertain($dataAcquisitionCertain) + public function setDataAcquisitionCertain($dataAcquisitionCertain): void { $this->dataAcquisitionCertain = $dataAcquisitionCertain; } @@ -662,7 +567,7 @@ public function setDataAcquisitionCertain($dataAcquisitionCertain) * * @return bool */ - public function isDataAcquisitionCertain() + public function isDataAcquisitionCertain(): bool { return $this->dataAcquisitionCertain; } @@ -672,7 +577,7 @@ public function isDataAcquisitionCertain() * * @return bool $relatedPersonsKnown */ - public function getRelatedPersonsKnown() + public function getRelatedPersonsKnown(): bool { return $this->relatedPersonsKnown; } @@ -683,7 +588,7 @@ public function getRelatedPersonsKnown() * @param bool $relatedPersonsKnown * @return void */ - public function setRelatedPersonsKnown($relatedPersonsKnown) + public function setRelatedPersonsKnown($relatedPersonsKnown): void { $this->relatedPersonsKnown = $relatedPersonsKnown; } @@ -693,7 +598,7 @@ public function setRelatedPersonsKnown($relatedPersonsKnown) * * @return bool */ - public function isRelatedPersonsKnown() + public function isRelatedPersonsKnown(): bool { return $this->relatedPersonsKnown; } @@ -703,7 +608,7 @@ public function isRelatedPersonsKnown() * * @return bool $workExamined */ - public function getWorkExamined() + public function getWorkExamined(): bool { return $this->workExamined; } @@ -714,7 +619,7 @@ public function getWorkExamined() * @param bool $workExamined * @return void */ - public function setWorkExamined($workExamined) + public function setWorkExamined($workExamined): void { $this->workExamined = $workExamined; } @@ -724,7 +629,7 @@ public function setWorkExamined($workExamined) * * @return bool */ - public function isWorkExamined() + public function isWorkExamined(): bool { return $this->workExamined; } @@ -734,7 +639,7 @@ public function isWorkExamined() * * @return bool $dataSetManuallyChecked */ - public function getDataSetManuallyChecked() + public function getDataSetManuallyChecked(): bool { return $this->dataSetManuallyChecked; } @@ -745,7 +650,7 @@ public function getDataSetManuallyChecked() * @param bool $dataSetManuallyChecked * @return void */ - public function setDataSetManuallyChecked($dataSetManuallyChecked) + public function setDataSetManuallyChecked(bool $dataSetManuallyChecked): void { $this->dataSetManuallyChecked = $dataSetManuallyChecked; } @@ -755,7 +660,7 @@ public function setDataSetManuallyChecked($dataSetManuallyChecked) * * @return bool */ - public function isDataSetManuallyChecked() + public function isDataSetManuallyChecked(): bool { return $this->dataSetManuallyChecked; } @@ -765,7 +670,7 @@ public function isDataSetManuallyChecked() * * @return bool $containedWorksIdentified */ - public function getContainedWorksIdentified() + public function getContainedWorksIdentified(): bool { return $this->containedWorksIdentified; } @@ -776,7 +681,7 @@ public function getContainedWorksIdentified() * @param bool $containedWorksIdentified * @return void */ - public function setContainedWorksIdentified($containedWorksIdentified) + public function setContainedWorksIdentified(bool $containedWorksIdentified): void { $this->containedWorksIdentified = $containedWorksIdentified; } @@ -786,7 +691,7 @@ public function setContainedWorksIdentified($containedWorksIdentified) * * @return bool */ - public function isContainedWorksIdentified() + public function isContainedWorksIdentified(): bool { return $this->containedWorksIdentified; } @@ -796,7 +701,7 @@ public function isContainedWorksIdentified() * * @return string $responsiblePerson */ - public function getResponsiblePerson() + public function getResponsiblePerson(): string { return $this->responsiblePerson; } @@ -807,38 +712,17 @@ public function getResponsiblePerson() * @param string $responsiblePerson * @return void */ - public function setResponsiblePerson($responsiblePerson) + public function setResponsiblePerson(string $responsiblePerson): void { $this->responsiblePerson = $responsiblePerson; } - /** - * Returns the dateOfPublishing - * - * @return \DateTime $dateOfPublishing - */ - public function getDateOfPublishing() - { - return $this->dateOfPublishing; - } - - /** - * Sets the dateOfPublishing - * - * @param \DateTime $dateOfPublishing - * @return void - */ - public function setDateOfPublishing(\DateTime $dateOfPublishing) - { - $this->dateOfPublishing = $dateOfPublishing; - } - /** * Returns the mvdbId * * @return string mvdbId */ - public function getMvdbId() + public function getMvdbId(): string { return $this->mvdbId; } @@ -849,7 +733,7 @@ public function getMvdbId() * @param \Slub\DmOnt\Domain\Model\Instrument $instrument * @return void */ - public function addInstrument($instrument) + public function addInstrument(Instrument $instrument): void { $this->instruments->attach($instrument); } @@ -860,7 +744,7 @@ public function addInstrument($instrument) * @param \Slub\DmOnt\Domain\Model\Instrument $instrumentToRemove The Instrument to be removed * @return void */ - public function removeInstrument($instrumentToRemove) + public function removeInstrument(Instrument $instrumentToRemove): void { $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('mpdb_core'); if ($instrumentToRemove->getGndId() == $extConf['pianoGndId']) { @@ -874,7 +758,7 @@ public function removeInstrument($instrumentToRemove) * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmOnt\Domain\Model\Instrument> instruments */ - public function getInstruments() + public function getInstruments(): ObjectStorage { return $this->instruments; } @@ -885,7 +769,7 @@ public function getInstruments() * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmOnt\Domain\Model\Instrument> $instruments * @return void */ - public function setInstruments(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $instruments) + public function setInstruments(ObjectStorage $instruments): void { $this->instruments = $instruments; } @@ -896,7 +780,7 @@ public function setInstruments(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $ins * @param \Slub\DmOnt\Domain\Model\Genre $genre * @return void */ - public function addForm($form) + public function addForm(Genre $form): void { $this->form->attach($form); } @@ -907,7 +791,7 @@ public function addForm($form) * @param \Slub\DmOnt\Domain\Model\Genre $formToRemove The Form to be removed * @return void */ - public function removeForm($formToRemove) + public function removeForm(Genre $formToRemove): void { $this->form->detach($formToRemove); } @@ -917,7 +801,7 @@ public function removeForm($formToRemove) * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmOnt\Domain\Model\Genre> form */ - public function getForm() + public function getGenre(): ObjectStorage { return $this->form; } @@ -928,7 +812,7 @@ public function getForm() * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmOnt\Domain\Model\Genre> $form * @return void */ - public function setForm(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $form) + public function setGenre(ObjectStorage $form): void { $this->form = $form; } @@ -939,7 +823,7 @@ public function setForm(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $form) * @param \Slub\DmNorm\Domain\Model\GndPerson $editor * @return void */ - public function addEditor(GndPerson $editor) + public function addEditor(GndPerson $editor): void { $this->editors->attach($editor); } @@ -950,7 +834,7 @@ public function addEditor(GndPerson $editor) * @param \Slub\DmNorm\Domain\Model\GndPerson $editorToRemove * @return void */ - public function removeEditor(GndPerson $editorToRemove) + public function removeEditor(GndPerson $editorToRemove): void { $this->editors->detach($editorToRemove); } @@ -960,7 +844,7 @@ public function removeEditor(GndPerson $editorToRemove) * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmNorm\Domain\Model\GndPerson> */ - public function getEditors() + public function getEditors(): ObjectStorage { return $this->editors; } @@ -971,7 +855,7 @@ public function getEditors() * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmNorm\Domain\Model\GndPerson> $editors * @return void */ - public function setEditors(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $editors) + public function setEditors(ObjectStorage $editors): void { $this->editors = $editors; } @@ -981,7 +865,7 @@ public function setEditors(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $editors * * @return int final */ - public function getFinal() + public function getFinal(): int { return $this->final; } @@ -989,27 +873,29 @@ public function getFinal() /** * Sets the final * - * @param bool $final + * @param int $final * @return void */ - public function setFinal($final) + public function setFinal(int $final): void { - $works = (new \SLUB\PublisherDb\Lib\DbArray())->set($this->getContainedWorks()->toArray()); - $works->each( - function ($work) use($final) { - $work->updateFinal($final, $this); - $this->gndWorkRepository->update($work); - } - ); $this->final = $final; + Collection::wrap($this->getContainedWorks()->toArray())-> + each( function($work) { $this->updateFinalWork($work); } ); + } + + protected function updateFinalWork(GndWork $work): void + { + $work->updateFinal($this->final, $this); + $this->gndWorkRepository->update($work); } + /** * Returns the language * * @return string $language */ - public function getLanguage() + public function getLanguage(): string { return $this->language; } @@ -1020,7 +906,7 @@ public function getLanguage() * @param string $language * @return void */ - public function setLanguage($language) + public function setLanguage($language): void { $this->language = $language; } @@ -1031,7 +917,7 @@ public function setLanguage($language) * @param \Slub\DmNorm\Domain\Model\GndPerson $firstComposer * @return void */ - public function addFirstComposer(GndPerson $firstComposer) + public function addFirstComposer(GndPerson $firstComposer): void { $this->firstComposer->attach($firstComposer); } @@ -1042,7 +928,7 @@ public function addFirstComposer(GndPerson $firstComposer) * @param \Slub\DmNorm\Domain\Model\GndPerson $firstComposerToRemove * @return void */ - public function removeFirstComposer(GndPerson $firstComposerToRemove) + public function removeFirstComposer(GndPerson $firstComposerToRemove): void { $this->firstComposer->detach($firstComposerToRemove); } @@ -1052,7 +938,7 @@ public function removeFirstComposer(GndPerson $firstComposerToRemove) * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmNorm\Domain\Model\GndPerson> $firstComposer */ - public function getFirstComposer() + public function getFirstComposer(): ObjectStorage { return $this->firstComposer; } @@ -1063,7 +949,7 @@ public function getFirstComposer() * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Slub\DmNorm\Domain\Model\GndPerson> $firstComposer * @return void */ - public function setFirstComposer(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $firstComposer) + public function setFirstComposer(ObjectStorage $firstComposer): void { $this->firstComposer = $firstComposer; } @@ -1073,24 +959,28 @@ public function setFirstComposer(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $f * * @return string */ - public function getComposers() + public function getComposers(): string { - if ($this->firstComposer && $this->firstComposer->toArray() != []) { - return (new \SLUB\PublisherDb\Lib\DbArray())->set($this->firstComposer)->map( - function ($composer) { - return $composer->getName(); - } - )->unique()->implode('; '); - } - return (new \SLUB\PublisherDb\Lib\DbArray())->set($this->getContainedWorks()->toArray())->map( - function ($work) { - return $work->getFirstComposer() ? $work->getFirstComposer()->getName() : ''; - } - )->filter( - function ($name) { - return $name != ''; + $composers = Collection::wrap($this->firstComposer->toArray()); + if ($composers->count() > 0) { + return $composers->map( function ($composer) { return self::getComposerName($composer); } )-> + unique()-> + join('; '); } - )->unique()->implode('; '); + return Collection::wrap($this->containedWorks->toArray())-> + map( function($work) { return self::getWorkComposerName($work); } )-> + unique()-> + join('; '); + } + + protected static function getComposerName(GndPerson $composer): string + { + return $composer->getName(); + } + + protected static function getWorkComposerName(GndWork $work): string + { + return self::getComposerName($work->getFirstComposer()); } /** @@ -1098,19 +988,25 @@ function ($name) { * * @return string $plateIds */ - public function getPlateIds() + public function getPlateIds(): Collection { - return json_decode($this->plateIds); + return Collection::wrap($this->publishedSubitems->toArray())-> + map( function($subitem) { return self::getSubitemPlateId($subitem); } ); } /** - * Returns a string for plateIds + * Returns the plateIds as a newline separated string * - * @return string $plateIdsString + * @return string $plateIds */ - public function getPlateIdsString() + public function getPlateIdsString(): string { - return implode("\n", $this->getPlateIds()); + return $this->getPlateIds()->join('\n'); + } + + protected static function getSubitemPlateId(PublishedSubitem $subitem): string + { + return $subitem->getPlateId(); } /** @@ -1118,7 +1014,7 @@ public function getPlateIdsString() * * @return string $comment */ - public function getComment() + public function getComment(): string { return $this->comment; } @@ -1129,50 +1025,31 @@ public function getComment() * @param string $comment * @return void */ - public function setComment($comment) + public function setComment(string $comment): void { $this->comment = $comment; } - /** - * Sets the plateIds - * - * @param string $plateIds - * @return void - */ - public function setPlateIds() - { - $plateIds = []; - - foreach($this->publishedSubitems as $publishedSubitem) { - if(!in_array($publishedSubitem->getPlateId(), $plateIds)) { - $plateIds[] = $publishedSubitem->getPlateId(); - } - } - - $this->plateIds = json_encode($plateIds); - } - /** * Returns bool indicating if there is a PublishedSubitem not * Linking a workRepository * * @return bool */ - public function getHasMikroWithoutWork() + public function getHasMikroWithoutWork(): bool { - $hasNoLinkedWorks = function (PublishedSubitem $mikro) { - return $mikro->getContainedWorks()->toArray() == []; - }; - $or = function (bool $a, bool $b) { - return $a || $b; - }; - return (new DbArray())->set($this->getPublishedSubitems())->map($hasNoLinkedWorks)->reduce($or, false); + return Collection::wrap($this->publishedSubitems)-> + map(function ($subitem) { return self::subitemWithoutWorks($subitem); } )-> + reduce(function ($a, $b) { return self::or($a, $b); } ); } - // TODO - public function proposeDataAcquisitionCertain() + protected static function subitemWithoutWorks(PublishedSubitem $subitem): bool { - return false; + return $subitem->getContainedWorks()->count() > 0; + } + + protected static function or(bool $a, bool $b): bool + { + return $a || $b; } } diff --git a/Classes/Domain/Model/PublishedSubitem.php b/Classes/Domain/Model/PublishedSubitem.php index a2170cd..b671229 100755 --- a/Classes/Domain/Model/PublishedSubitem.php +++ b/Classes/Domain/Model/PublishedSubitem.php @@ -1,7 +1,9 @@ + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\DmNorm\Domain\Model\GndWork> */ protected $containedWorks = null; /** * publisherActions * - * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\PublisherDb\Domain\Model\PublisherAction> + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\MpdbCore\Domain\Model\PublisherAction> */ protected $publisherActions = null; @@ -282,10 +284,10 @@ public function setComment($comment) /** * Adds a PublisherAction * - * @param \SLUB\PublisherDb\Domain\Model\PublisherAction $publisherAction + * @param \SLUB\MpdbCore\Domain\Model\PublisherAction $publisherAction * @return void */ - public function addPublisherAction(\SLUB\PublisherDb\Domain\Model\PublisherAction $publisherAction = null) + public function addPublisherAction(PublisherAction $publisherAction = null) { if ($publisherAction != null) { $this->publisherActions->attach($publisherAction); @@ -295,10 +297,10 @@ public function addPublisherAction(\SLUB\PublisherDb\Domain\Model\PublisherActio /** * Removes a PublisherAction * - * @param \SLUB\PublisherDb\Domain\Model\PublisherAction $publisherActionToRemove The PublisherAction to be removed + * @param \SLUB\MpdbCore\Domain\Model\PublisherAction $publisherActionToRemove The PublisherAction to be removed * @return void */ - public function removePublisherAction(\SLUB\PublisherDb\Domain\Model\PublisherAction $publisherActionToRemove) + public function removePublisherAction(PublisherAction $publisherActionToRemove) { $this->publisherActions->detach($publisherActionToRemove); } @@ -306,7 +308,7 @@ public function removePublisherAction(\SLUB\PublisherDb\Domain\Model\PublisherAc /** * Returns the publisherActions * - * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\PublisherDb\Domain\Model\PublisherAction> publisherActions + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\MpdCore\Domain\Model\PublisherAction> publisherActions */ public function getPublisherActions() { @@ -316,7 +318,7 @@ public function getPublisherActions() /** * Sets the publisherActions * - * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\PublisherDb\Domain\Model\PublisherAction> $publisherActions + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\MpdCore\Domain\Model\PublisherAction> $publisherActions * @return void */ public function setPublisherActions(ObjectStorage $publisherActions = null) @@ -328,10 +330,10 @@ public function setPublisherActions(ObjectStorage $publisherActions = null) /** * Adds a Work * - * @param \SLUB\PublisherDb\Domain\Model\Work $containedWork + * @param \SLUB\DmNorm\Domain\Model\GndWork $containedWork * @return void */ - public function addContainedWork(\SLUB\PublisherDb\Domain\Model\Work $containedWork = null) + public function addContainedWork(GndWork $containedWork = null) { if ($containedWork != null) { $this->containedWorks->attach($containedWork); @@ -341,10 +343,10 @@ public function addContainedWork(\SLUB\PublisherDb\Domain\Model\Work $containedW /** * Removes a Work * - * @param \SLUB\PublisherDb\Domain\Model\Work $containedWorkToRemove The Work to be removed + * @param \SLUB\DmOnt\Domain\Model\GndWork $containedWorkToRemove The Work to be removed * @return void */ - public function removeContainedWork(\SLUB\PublisherDb\Domain\Model\Work $containedWorkToRemove) + public function removeContainedWork(GndWork $containedWorkToRemove) { $this->containedWorks->detach($containedWorkToRemove); } @@ -352,7 +354,7 @@ public function removeContainedWork(\SLUB\PublisherDb\Domain\Model\Work $contain /** * Returns the containedWorks * - * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\PublisherDb\Domain\Model\Work> containedWorks + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\DmOnt\Domain\Model\GndWork> containedWorks */ public function getContainedWorks() { @@ -362,7 +364,7 @@ public function getContainedWorks() /** * Sets the containedWorks * - * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\PublisherDb\Domain\Model\Work> $containedWorks + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\DmOnt\Domain\Model\GndWork> $containedWorks * @return void */ public function setContainedWorks(ObjectStorage $containedWorks = null) @@ -590,15 +592,16 @@ public function setStartStore($startStore) */ public function getComposers() { - return (new \SLUB\PublisherDb\Lib\DbArray())->set($this->getContainedWorks()->toArray())->map( - function ($work) { - return $work->getFirstComposer() ? $work->getFirstComposer()->getName() : ''; - } - )->filter( - function ($name) { - return $name != ''; - } - )->unique()->implode(', '); + return Collection::wrap($this->containedWorks)-> + map( function($work) { return self::getWorkComposerName($work); } )-> + filter( function($name) { return $name != ''; } )-> + unique()-> + implode(', '); + } + + protected static function getWorkComposerName(GndWork $work): string + { + return $work->getFirstComposer()->getName(); } /** diff --git a/Classes/Domain/Model/Publisher.php b/Classes/Domain/Model/Publisher.php index cb3c0c7..d928a30 100755 --- a/Classes/Domain/Model/Publisher.php +++ b/Classes/Domain/Model/Publisher.php @@ -62,11 +62,18 @@ class Publisher extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity protected $activeTo = null; /** - * publisherMakroItems + * publishedItems * - * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\PublisherDb\Domain\Model\PublisherMakroItem> + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\MpdbCore\Domain\Model\PublishedItem> */ - protected $publisherMakroItems = null; + protected $publishedItems = null; + + /** + * responsiblePersons + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\DmNorm\Domain\Model\GndPerson> + */ + protected $responsiblePersons = null; /** * __construct @@ -89,7 +96,7 @@ public function __construct() protected function initStorageObjects() { $this->responsiblePersons = new ObjectStorage(); - $this->publisherMikroItems = new ObjectStorage(); + $this->publishedItems = new ObjectStorage(); } /** @@ -223,9 +230,9 @@ public function setActiveTo(\DateTime $activeTo = null) * * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\SLUB\PublisherDb\Domain\Model\PublisherMakroItem> $publisherMakroItems */ - public function getPublisherMakroItems() + public function getPublishedItems() { - return $this->publisherMakroItems; + return $this->publishedItems; } /** @@ -237,7 +244,7 @@ public function getPublisherMakroItems() public function setPublisherMakroItems(ObjectStorage $publisherMakroItems = null) { $publisherMakroItems = $publisherMakroItems ?? new ObjectStorage(); - $this->publisherMakroItems = $publisherMakroItems; + $this->publishedItems = $publisherMakroItems; } } diff --git a/Classes/Services/ElasticSearchService.php b/Classes/Services/ElasticSearchService.php new file mode 100644 index 0000000..ffbc71c --- /dev/null +++ b/Classes/Services/ElasticSearchService.php @@ -0,0 +1,206 @@ +index = ''; + } else { + $this->index = $this->prefix . $index; + } + + return $this; + } + + public function setPublisher(string $publisher = ''): SearchServiceInterface + { + if ($publisher != '' && $this->id != '') { + throw new InvalidParamsException('Attempted to restrict search for publisher while searching for id'); + } + + $this->publisher = $publisher; + + return $this; + } + + public function setSearchterm(string $searchTerm = ''): SearchServiceInterface + { + if ($searchTerm != '' && $this->id != '') { + throw new InvalidParamsException('Attempted to search for term and id simultaneously'); + } + + $this->searchTerm = $searchTerm; + + return $this; + } + + public function setId(string $id = ''): SearchServiceInterface + { + if ($id != '' && $this->searchTerm != '') { + throw new InvalidParamsException('Attempted to search for term and id simultaneously'); + } + if ($id != '' && $this->publisher != '') { + throw new InvalidParamsException('Attempted to restrict search for publisher while searching for id'); + } + + if ($id == '') { + $this->method = 'search'; + } else { + $this->method = 'get'; + } + + $this->id = $id; + + return $this; + } + + public function setFrom(int $from = 0): SearchServiceInterface + { + $this->from = $from; + + return $this; + } + + public function setSize(int $size = self::DEFAULT_RESULT_COUNT): SearchServiceInterface + { + $this->size = $size; + + return $this; + } + + public function search(): Collection + { + if ($this->id != '' && $this->index == '') { + throw new InvalidParamsException('Id specified but index unspecified'); + } + + $this->createParams(); + + switch ($this->method) { + case 'search': + $result = $this->client->search($this->params); + return Collection::wrap($result['hits']['hits']); + break; + case 'get': + $result = $this->client->get($this->params); + return Collection::wrap($result['_source']); + break; + } + + return Collection::wrap([]); + } + + public function count(): int + { + if ($this->method == 'get') { + throw new InvalidOperationException('Attempt to count a id based search'); + } + + $this->createParams(); + unset($this->params['body']['size']); + unset($this->params['body']['from']); + + return $this->client->count($this->params)['count']; + } + + public function reset(): SearchServiceInterface + { + $this->setIndex(); + $this->setPublisher(); + $this->setSearchterm(); + $this->setId(); + $this->setFrom(); + $this->setSize(); + $this->method = 'search'; + + return $this; + } + + public function init(): bool + { + $this->client = ElasticClientBuilder::create()-> + autoconfig()-> + build(); + $coreExtConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('mpdb_core'); + $this->prefix = $coreExtConf['prefix']; + + return true; + } + + private function createParams(): void + { + $this->params = []; + + if ($this->index != '') { + $this->params['index'] = $this->index; + } else { + $this->params['index'] = Collection::wrap([ + $this->prefix . IndexCommand::PUBLISHED_ITEM_INDEX, + $this->prefix . IndexCommand::WORK_INDEX, + $this->prefix . IndexCommand::PERSON_INDEX])-> + join(','); + } + + if ($this->id != '') { + $this->params['id'] = $this->id; + } + + if ($this->method == 'search') { + $this->params['body'] = [ 'query' => [] ]; + $this->params['body']['size'] = $this->size; + $this->params['body']['from'] = $this->from; + + if ($this->searchTerm == '') { + $this->params['body']['query'] = [ + 'bool' => [ + 'must' => [ [ + 'match_all' => new \stdClass() + ] ] + ] + ]; + } else { + $this->params['body']['query'] = [ + 'bool' => [ + 'must' => [ [ + 'query_string' => [ + 'query' => $this->searchTerm + ] + ] ] + ] + ]; + } + + if ($this->publisher != '') { + $this->params['body']['query']['bool']['must'][] = + [ 'query_string' => [ + 'query' => $this->publisher . '_*', + 'fields' => [ 'mvdb_id', 'published_items.mvdb_id', 'works.published_items.mvdb_id' ] + ] + ]; + } + } + } +} diff --git a/Classes/Services/InvalidOperationException.php b/Classes/Services/InvalidOperationException.php new file mode 100644 index 0000000..9b0fcf1 --- /dev/null +++ b/Classes/Services/InvalidOperationException.php @@ -0,0 +1,8 @@ + [ ['', 0], ], - 'foreign_table' => 'tx_mpdbcore_domain_model_publishermakroitem', - 'foreign_table_where' => 'AND {#tx_mpdbcore_domain_model_publishermakroitem}.{#pid}=###CURRENT_PID### AND {#tx_mpdbcore_domain_model_publishermakroitem}.{#sys_language_uid} IN (-1,0)', + 'foreign_table' => 'tx_mpdbcore_domain_model_publisheditem', + 'foreign_table_where' => 'AND {#tx_mpdbcore_domain_model_publisheditem}.{#pid}=###CURRENT_PID### AND {#tx_mpdbcore_domain_model_publisheditem}.{#sys_language_uid} IN (-1,0)', ], ], 'l10n_diffsource' => [ @@ -420,7 +420,7 @@ 'config' => [ 'type' => 'inline', 'foreign_table' => 'tx_mpdbcore_domain_model_publishedsubitem', - 'foreign_field' => 'published_item', + 'foreign_field' => 'publisheditem', 'foreign_sortby' => 'sorting', 'maxitems' => 9999, 'appearance' => [ diff --git a/Configuration/TCA/tx_mpdbcore_domain_model_publishedsubitem.php b/Configuration/TCA/tx_mpdbcore_domain_model_publishedsubitem.php index 43210d2..5126928 100755 --- a/Configuration/TCA/tx_mpdbcore_domain_model_publishedsubitem.php +++ b/Configuration/TCA/tx_mpdbcore_domain_model_publishedsubitem.php @@ -256,7 +256,7 @@ 'config' => [ 'type' => 'select', 'renderType' => 'selectMultipleSideBySide', - 'foreign_table' => 'tx_dmnorm_domain_model_work', + 'foreign_table' => 'tx_dmnorm_domain_model_gndwork', 'MM' => 'tx_mpdbcore_publishedsubitem_work_mm', 'size' => 10, 'autoSizeMax' => 30, @@ -282,7 +282,7 @@ 'config' => [ 'type' => 'inline', 'foreign_table' => 'tx_mpdbcore_domain_model_publisheraction', - 'foreign_field' => 'published_subitem', + 'foreign_field' => 'publishedsubitem', 'foreign_sortby' => 'sorting', 'maxitems' => 9999, 'appearance' => [ diff --git a/Configuration/TCA/tx_mpdbcore_domain_model_publisher.php b/Configuration/TCA/tx_mpdbcore_domain_model_publisher.php index 43a2be0..55a47ed 100755 --- a/Configuration/TCA/tx_mpdbcore_domain_model_publisher.php +++ b/Configuration/TCA/tx_mpdbcore_domain_model_publisher.php @@ -176,32 +176,5 @@ 'default' => null, ], ], - 'responsible_persons' => [ - 'exclude' => true, - 'label' => 'LLL:EXT:mpdb_core/Resources/Private/Language/locallang_db.xlf:tx_mpdbcore_domain_model_publisher.responsible_persons', - 'config' => [ - 'type' => 'select', - 'renderType' => 'selectMultipleSideBySide', - 'foreign_table' => 'tx_mpdbcore_domain_model_role', - 'MM' => 'tx_mpdbcore_publisher_role_mm', - 'size' => 10, - 'autoSizeMax' => 30, - 'maxitems' => 9999, - 'multiple' => 0, - 'fieldControl' => [ - 'editPopup' => [ - 'disabled' => false, - ], - 'addRecord' => [ - 'disabled' => false, - ], - 'listModule' => [ - 'disabled' => true, - ], - ], - ], - - ], - ], ]; diff --git a/Configuration/TCA/tx_mpdbcore_domain_model_publisheraction.php b/Configuration/TCA/tx_mpdbcore_domain_model_publisheraction.php index 0ec07e9..c201f6d 100755 --- a/Configuration/TCA/tx_mpdbcore_domain_model_publisheraction.php +++ b/Configuration/TCA/tx_mpdbcore_domain_model_publisheraction.php @@ -186,8 +186,7 @@ 'default' => 0, ] ], - - 'publishermikroitem' => [ + 'publishedsubitem' => [ 'config' => [ 'type' => 'passthrough', ], diff --git a/Tests/Functional/Domain/Model/Fixtures/empty_persons.csv b/Tests/Functional/Domain/Model/Fixtures/empty_persons.csv new file mode 100644 index 0000000..42601cc --- /dev/null +++ b/Tests/Functional/Domain/Model/Fixtures/empty_persons.csv @@ -0,0 +1,3 @@ +"tx_dmnorm_domain_model_gndperson" +,"uid" +,1 diff --git a/Tests/Functional/Domain/Model/Fixtures/empty_works.csv b/Tests/Functional/Domain/Model/Fixtures/empty_works.csv new file mode 100644 index 0000000..41126ed --- /dev/null +++ b/Tests/Functional/Domain/Model/Fixtures/empty_works.csv @@ -0,0 +1,3 @@ +"tx_dmnorm_domain_model_gndwork" +,"uid","alt_instrumentation" +,1,"" diff --git a/Tests/Functional/Domain/Model/PublishedItemComposerNameTest.php b/Tests/Functional/Domain/Model/PublishedItemComposerNameTest.php new file mode 100644 index 0000000..d2cd9f5 --- /dev/null +++ b/Tests/Functional/Domain/Model/PublishedItemComposerNameTest.php @@ -0,0 +1,234 @@ + + */ +class PublishedItemComposerNameTest extends FunctionalTestCase +{ + /** + * @var \Slub\PublisherDb\Domain\Model\PublishedItem + */ + protected ?PublishedItem $subject = null; + + /** + * @var \Slub\DmNorm\Domain\Model\GndWork + */ + protected ?GndWork $work1 = null; + + /** + * @var \Slub\DmNorm\Domain\Model\GndWork + */ + protected ?GndWork $work2 = null; + + /** + * @var \Slub\DmNorm\Domain\Model\GndWork + */ + protected ?GndWork $work3 = null; + + /** + * @var \Slub\DmNorm\Domain\Model\GndPerson + */ + protected ?GndPerson $composer1 = null; + + /** + * @var \Slub\DmNorm\Domain\Model\GndPerson + */ + protected ?GndPerson $composer2 = null; + + /** + * @var \Slub\DmNorm\Domain\Model\GndPerson + */ + protected ?GndPerson $composer3 = null; + + /** + * @var string + */ + protected string $nameComposer1 = ''; + + /** + * @var string + */ + protected string $nameComposer2 = ''; + + /** + * @var string + */ + protected string $nameComposer3 = ''; + + /** + * Musik für Orgel; J. S. Bach + * @var string + */ + protected string $gndId1 = '300568517'; + + /** + * Gesänge, op. 43; J. Brahms + * @var string + */ + protected string $gndId2 = '107761277X'; + + /** + * Six trio sonatas; J. S. Bach + * @var string + */ + protected string $gndId3 = '300011040'; + + protected array $testExtensionsToLoad = [ + 'typo3conf/ext/dm-norm' + ]; + + protected function setUp(): void + { + parent::setUp(); + $this->subject = new PublishedItem(); + + $this->work1 = new GndWork(); + $this->work2 = new GndWork(); + $this->work3 = new GndWork(); + + $this->importCSVDataSet(__DIR__ . '/Fixtures/empty_persons.csv'); + $this->importCSVDataSet(__DIR__ . '/Fixtures/empty_works.csv'); + + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + $persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class); + $workRepository = GeneralUtility::makeInstance(GndWorkRepository::class, $objectManager); + $workRepository->injectPersistenceManager($persistenceManager); + $personRepository = GeneralUtility::makeInstance(GndPersonRepository::class, $objectManager); + $personRepository->injectPersistenceManager($persistenceManager); + $instrumentRepository = GeneralUtility::makeInstance(GndInstrumentRepository::class, $objectManager); + $instrumentRepository->injectPersistenceManager($persistenceManager); + $genreRepository = GeneralUtility::makeInstance(GndGenreRepository::class, $objectManager); + $genreRepository->injectPersistenceManager($persistenceManager); + + $this->work1->setGndId($this->gndId1)->pullGndInfo( + $workRepository, + $personRepository, + $instrumentRepository, + $genreRepository + ); + $this->work2->setGndId($this->gndId2)->pullGndInfo( + $workRepository, + $personRepository, + $instrumentRepository, + $genreRepository + ); + $this->work3->setGndId($this->gndId3)->pullGndInfo( + $workRepository, + $personRepository, + $instrumentRepository, + $genreRepository + ); + + $this->composer1 = $this->work1->getFirstComposer(); + $this->composer2 = $this->work2->getFirstComposer(); + $this->composer3 = $this->work3->getFirstComposer(); + + $this->nameComposer1 = $this->composer1->getName(); + $this->nameComposer2 = $this->composer2->getName(); + $this->nameComposer3 = $this->composer3->getName(); + } + + protected function tearDown(): void + { + parent::tearDown(); + } + + /** + * @test + */ + public function publishedItemWithOneComposerReturnsComposer() + { + $this->subject->addFirstComposer($this->composer1); + + self::assertSame( + $this->nameComposer1, + $this->subject->getComposers() + ); + } + + /** + * @test + */ + public function publishedItemWithManyComposersReturnsComposers() + { + $this->subject->addFirstComposer($this->composer1); + $this->subject->addFirstComposer($this->composer2); + $namesString = implode('; ', [$this->nameComposer1, $this->nameComposer2]); + + self::assertSame( + $namesString, + $this->subject->getComposers() + ); + } + + /** + * @test + */ + public function publishedItemWithoutComposersReturnsOneWorkComposer() + { + $this->subject->addContainedWork($this->work1); + + self::assertSame( + $this->nameComposer1, + $this->subject->getComposers() + ); + } + + /** + * @test + */ + public function publishedItemWithoutComposerReturnsManyWorkComposers() + { + $this->subject->addContainedWork($this->work1); + $this->subject->addContainedWork($this->work2); + $namesString = implode('; ', [$this->nameComposer1, $this->nameComposer2]); + + self::assertSame( + $namesString, + $this->subject->getComposers() + ); + } + + /** + * @test + */ + public function publishedItemWithoutComposerWithoutWorkcomposersReturnsString() + { + self::assertSame( + '', + $this->subject->getComposers() + ); + } + + /** + * @test + */ + public function identicalComposersAreUniquedOut() + { + $this->subject->addContainedWork($this->work1); + $this->subject->addContainedWork($this->work3); + + self::assertSame( + $this->nameComposer1, + $this->subject->getComposers() + ); + } + +} diff --git a/Tests/Functional/Domain/Model/PublishedItemMvdbIdTest.php b/Tests/Functional/Domain/Model/PublishedItemMvdbIdTest.php new file mode 100644 index 0000000..b5034d7 --- /dev/null +++ b/Tests/Functional/Domain/Model/PublishedItemMvdbIdTest.php @@ -0,0 +1,327 @@ + + */ +class PublishedItemMvdbIdTest extends FunctionalTestCase +{ + /** + * @var \Slub\PublisherDb\Domain\Model\PublishedItem + */ + protected ?PublishedItem $subject = null; + + /** + * @var \Slub\MpdbCore\Domain\Model\PublishedSubitem + */ + protected ?PublishedSubitem $subitem1 = null; + + /** + * @var \Slub\MpdbCore\Domain\Model\PublishedSubitem + */ + protected ?PublishedSubitem $subitem2 = null; + + /** + * @var \Slub\MpdbCore\Domain\Model\Publisher + */ + protected ?Publisher $publisher = null; + + /** + * @var string + */ + protected string $voice1 = 'N'; + + /** + * @var string + */ + protected string $voice2 = 'Vl'; + + /** + * @var string + */ + protected string $part1 = 'NN'; + + /** + * @var string + */ + protected string $part2 = 'H1'; + + /** + * @var string + */ + protected string $plateId1 = '00001'; + + /** + * @var string + */ + protected string $plateId2 = '00002'; + + /** + * @var string + */ + protected string $partialId1 = ''; + + /** + * @var string + */ + protected string $partialId2 = ''; + + /** + * @var string + */ + protected string $shorthand = 'HO'; + + /** + * @var string + */ + protected string $separator = '_'; + + protected function setUp(): void + { + parent::setUp(); + $this->subject = new PublishedItem(); + $this->subitem1 = new PublishedSubitem(); + $this->subitem2 = new PublishedSubitem(); + $this->publisher = new Publisher(); + + $this->publisher->setShorthand($this->shorthand); + $this->subitem1->setPart($this->part1); + $this->subitem1->setPlateId($this->plateId1); + $this->subitem1->setVoice($this->voice1); + $this->subitem2->setPart($this->part2); + $this->subitem2->setPlateId($this->plateId2); + $this->subitem2->setVoice($this->voice2); + + $this->partialId1 = implode($this->separator, [ $this->plateId1, $this->part1, $this->voice1 ]); + $this->partialId2 = implode($this->separator, [ $this->plateId2, $this->part2, $this->voice2 ]); + } + + protected function tearDown(): void + { + parent::tearDown(); + } + + /** + * @test + */ + public function newPublishedItemHasEmptyId() + { + self::assertSame( + '', + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function publishedItemWithPublisherHasShorthand() + { + $this->subject->setPublisher($this->publisher); + $id = $this->shorthand . $this->separator; + + self::assertSame( + $id, + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function publishedItemHasNoShorthandAfterPublisherRemoved() + { + $this->subject->setPublisher($this->publisher); + $this->subject->setPublisher(); + + self::assertSame( + '', + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function publishedItemWithSubitemHasPlateId() + { + $this->subject->addPublishedSubitem($this->subitem1); + + self::assertSame( + $this->plateId1, + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function completePublishedItemHasCompleteId() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem1); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1 ]); + + self::assertSame( + $id, + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function idChangesWhenSubitemWithLowerIdIsAdded() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem2); + $this->subject->addPublishedSubitem($this->subitem1); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1 ]); + + self::assertSame( + $id, + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function idChangesWhenSubitemWithLowerIdIsRemoved() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem2); + $this->subject->addPublishedSubitem($this->subitem1); + $this->subject->removePublishedSubitem($this->subitem1); + $id = implode($this->separator, [ $this->shorthand, $this->plateId2 ]); + + self::assertSame( + $id, + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function idRemainsWhenSubitemWithHigherIdIsAdded() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem1); + $this->subject->addPublishedSubitem($this->subitem2); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1 ]); + + self::assertSame( + $id, + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function idRemainsWhenSubitemWithHigherIdIsRemoved() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem1); + $this->subject->addPublishedSubitem($this->subitem2); + $this->subject->removePublishedSubitem($this->subitem2); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1 ]); + + self::assertSame( + $id, + $this->subject->getMvdbId() + ); + } + + /** + * @test + */ + public function subitemIdsAreCalculatedCorrectly() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem1); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1, $this->partialId1 ]); + + self::assertSame( + $id, + $this->subitem1->getMvdbId() + ); + } + + /** + * @test + */ + public function subitemIdChangesWhenSubitemWithLowerIdIsAdded() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem2); + $this->subject->addPublishedSubitem($this->subitem1); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1, $this->partialId1 ]); + + self::assertSame( + $id, + $this->subitem1->getMvdbId() + ); + } + + /** + * @test + */ + public function subitemIdChangesWhenSubitemWithLowerIdIsRemoved() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem2); + $this->subject->addPublishedSubitem($this->subitem1); + $this->subject->removePublishedSubitem($this->subitem1); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1, $this->partialId1 ]); + + self::assertSame( + $id, + $this->subitem1->getMvdbId() + ); + } + + /** + * @test + */ + public function subitemIdRemainsWhenSubitemWithHigherIdIsAdded() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem1); + $this->subject->addPublishedSubitem($this->subitem2); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1, $this->partialId1 ]); + + self::assertSame( + $id, + $this->subitem1->getMvdbId() + ); + } + + /** + * @test + */ + public function subitemIdRemainsWhenSubitemWithHigherIdIsRemoved() + { + $this->subject->setPublisher($this->publisher); + $this->subject->addPublishedSubitem($this->subitem1); + $this->subject->addPublishedSubitem($this->subitem2); + $this->subject->removePublishedSubitem($this->subitem2); + $id = implode($this->separator, [ $this->shorthand, $this->plateId1, $this->partialId1 ]); + + self::assertSame( + $id, + $this->subitem1->getMvdbId() + ); + } +} diff --git a/Tests/Unit/Domain/Model/PublishedItemTest.php b/Tests/Unit/Domain/Model/PublishedItemTest.php new file mode 100755 index 0000000..154bad6 --- /dev/null +++ b/Tests/Unit/Domain/Model/PublishedItemTest.php @@ -0,0 +1,518 @@ + + */ +class PublishedItemTest extends UnitTestCase +{ + /** + * @var \SLUB\PublisherDb\Domain\Model\PublishedItem + */ + protected $subject = null; + + protected function setUp(): void + { + parent::setUp(); + $this->subject = new PublishedItem(); + } + + protected function tearDown(): void + { + parent::tearDown(); + } + + /** + * @test + */ + public function getTitleReturnsInitialValueForString() + { + self::assertSame( + '', + $this->subject->getTitle() + ); + } + + /** + * @test + */ + public function setTitleForStringSetsTitle() + { + $this->subject->setTitle('Conceived at T3CON10'); + + self::assertSame( + 'Conceived at T3CON10', + $this->subject->getTitle() + ); + } + + /** + * @test + */ + public function getTypeReturnsInitialValueForString() + { + self::assertSame( + '', + $this->subject->getType() + ); + } + + /** + * @test + */ + public function setTypeForStringSetsType() + { + $this->subject->setType('Conceived at T3CON10'); + + self::assertSame( + 'Conceived at T3CON10', + $this->subject->getType() + ); + } + + /** + * @test + */ + public function getInstrumentationReturnsInitialValueForString() + { + self::assertSame( + '', + $this->subject->getInstrumentation() + ); + } + + /** + * @test + */ + public function setInstrumentationForStringSetsInstrumentation() + { + $this->subject->setInstrumentation('Conceived at T3CON10'); + + self::assertSame( + 'Conceived at T3CON10', + $this->subject->getInstrumentation() + ); + } + + /** + * @test + */ + public function getDataAcquisitionCertainReturnsInitialValueForBool() + { + self::assertSame( + false, + $this->subject->getDataAcquisitionCertain() + ); + } + + /** + * @test + */ + public function setDataAcquisitionCertainForBoolSetsDataAcquisitionCertain() + { + $this->subject->setDataAcquisitionCertain(true); + + self::assertSame( + true, + $this->subject->getDataAcquisitionCertain() + ); + } + + /** + * @test + */ + public function getRelatedPersonsKnownReturnsInitialValueForBool() + { + self::assertSame( + false, + $this->subject->getRelatedPersonsKnown() + ); + } + + /** + * @test + */ + public function setRelatedPersonsKnownForBoolSetsRelatedPersonsKnown() + { + $this->subject->setRelatedPersonsKnown(true); + + self::assertSame( + true, + $this->subject->getRelatedPersonsKnown() + ); + } + + /** + * @test + */ + public function getWorkExaminedReturnsInitialValueForBool() + { + self::assertSame( + false, + $this->subject->getWorkExamined() + ); + } + + /** + * @test + */ + public function setWorkExaminedForBoolSetsWorkExamined() + { + $this->subject->setWorkExamined(true); + + self::assertSame( + true, + $this->subject->getWorkExamined() + ); + } + + /** + * @test + */ + public function getDataSetManuallyCheckedReturnsInitialValueForBool() + { + self::assertSame( + false, + $this->subject->getDataSetManuallyChecked() + ); + } + + /** + * @test + */ + public function setDataSetManuallyCheckedForBoolSetsDataSetManuallyChecked() + { + $this->subject->setDataSetManuallyChecked(true); + + self::assertSame( + true, + $this->subject->getDataSetManuallyChecked() + ); + } + + /** + * @test + */ + public function getContainedWorksIdentifiedReturnsInitialValueForBool() + { + self::assertSame( + false, + $this->subject->getContainedWorksIdentified() + ); + } + + /** + * @test + */ + public function setContainedWorksIdentifiedForBoolSetsContainedWorksIdentified() + { + $this->subject->setContainedWorksIdentified(true); + + self::assertSame( + true, + $this->subject->getContainedWorksIdentified() + ); + } + + /** + * @test + */ + public function getResponsiblePersonReturnsInitialValueForString() + { + self::assertSame( + '', + $this->subject->getResponsiblePerson() + ); + } + + /** + * @test + */ + public function setResponsiblePersonForStringSetsResponsiblePerson() + { + $this->subject->setResponsiblePerson('Conceived at T3CON10'); + + self::assertSame( + 'Conceived at T3CON10', + $this->subject->getResponsiblePerson() + ); + } + + /** + * @test + */ + public function getFinalReturnsInitialValueForInt() + { + self::assertSame( + 0, + $this->subject->getFinal() + ); + } + + /** + * @test + */ + public function setFinalForIntSetsFinal() + { + $this->subject->setFinal(12); + + self::assertSame( + 12, + $this->subject->getFinal() + ); + } + + /** + * @test + */ + public function getLanguageReturnsInitialValueForString() + { + self::assertSame( + '', + $this->subject->getLanguage() + ); + } + + /** + * @test + */ + public function setLanguageForStringSetsLanguage() + { + $this->subject->setLanguage('Conceived at T3CON10'); + + self::assertSame( + 'Conceived at T3CON10', + $this->subject->getLanguage() + ); + } + + /** + * @test + */ + public function getCommentReturnsInitialValueForString() + { + self::assertSame( + '', + $this->subject->getComment() + ); + } + + /** + * @test + */ + public function setCommentForStringSetsComment() + { + $this->subject->setComment('Conceived at T3CON10'); + + self::assertSame( + 'Conceived at T3CON10', + $this->subject->getComment() + ); + } + + /** + * @test + */ + public function getContainedWorksReturnsInitialValueForWork() + { + $newObjectStorage = new ObjectStorage(); + self::assertEquals( + $newObjectStorage, + $this->subject->getContainedWorks() + ); + } + + /** + * @test + */ + public function setContainedWorksForObjectStorageContainingWorkSetsContainedWorks() + { + $containedWork = new GndWork(); + $objectStorageHoldingExactlyOneContainedWorks = new ObjectStorage(); + $objectStorageHoldingExactlyOneContainedWorks->attach($containedWork); + $this->subject->setContainedWorks($objectStorageHoldingExactlyOneContainedWorks); + + self::assertSame( + $objectStorageHoldingExactlyOneContainedWorks, + $this->subject->getContainedWorks() + ); + } + + + /** + * @test + */ + public function getEditorsReturnsInitialValueForPerson() + { + $newObjectStorage = new ObjectStorage(); + self::assertEquals( + $newObjectStorage, + $this->subject->getEditors() + ); + } + + /** + * @test + */ + public function setEditorsForObjectStorageContainingPersonSetsEditors() + { + $editor = new GndPerson(); + $objectStorageHoldingExactlyOneEditors = new ObjectStorage(); + $objectStorageHoldingExactlyOneEditors->attach($editor); + $this->subject->setEditors($objectStorageHoldingExactlyOneEditors); + + self::assertSame( + $objectStorageHoldingExactlyOneEditors, + $this->subject->getEditors() + ); + } + + /** + * @test + */ + public function getInstrumentsReturnsInitialValueForInstrument() + { + $newObjectStorage = new ObjectStorage(); + self::assertEquals( + $newObjectStorage, + $this->subject->getInstruments() + ); + } + + /** + * @test + */ + public function setInstrumentsForObjectStorageContainingInstrumentSetsInstruments() + { + $instrument = new GndInstrument; + $objectStorageHoldingExactlyOneInstruments = new ObjectStorage(); + $objectStorageHoldingExactlyOneInstruments->attach($instrument); + $this->subject->setInstruments($objectStorageHoldingExactlyOneInstruments); + + self::assertSame( + $objectStorageHoldingExactlyOneInstruments, + $this->subject->getInstruments() + ); + } + + /** + * @test + */ + public function getGenreReturnsInitialValueForGenre() + { + $newObjectStorage = new ObjectStorage(); + self::assertEquals( + $newObjectStorage, + $this->subject->getGenre() + ); + } + + /** + * @test + */ + public function setGenreForObjectStorageContainingGenreSetsForm() + { + $form = new GndGenre(); + $objectStorageHoldingExactlyOneForm = new ObjectStorage(); + $objectStorageHoldingExactlyOneForm->attach($form); + $this->subject->setGenre($objectStorageHoldingExactlyOneForm); + + self::assertSame( + $objectStorageHoldingExactlyOneForm, + $this->subject->getGenre() + ); + } + + /** + * @test + */ + public function getFirstComposerReturnsInitialValueForPerson() + { + $newObjectStorage = new ObjectStorage(); + self::assertEquals( + $newObjectStorage, + $this->subject->getFirstComposer() + ); + } + + /** + * @test + */ + public function setFirstComposerForObjectStorageContainingPersonSetsFirstComposer() + { + $firstComposer = new GndPerson(); + $objectStorageHoldingExactlyOneFirstComposer = new ObjectStorage(); + $objectStorageHoldingExactlyOneFirstComposer->attach($firstComposer); + $this->subject->setFirstComposer($objectStorageHoldingExactlyOneFirstComposer); + + self::assertSame( + $objectStorageHoldingExactlyOneFirstComposer, + $this->subject->getFirstComposer() + ); + } + + /** + * @test + */ + public function getPublishedSubitemsReturnsInitialValueForPublishedSubitem() + { + $newObjectStorage = new ObjectStorage(); + self::assertEquals( + $newObjectStorage, + $this->subject->getPublishedSubitems() + ); + } + + /** + * @test + */ + public function setPublishedSubitemsForObjectStorageContainingPublishedSubitemSetsPublishedSubitems() + { + $publishedSubitem = new PublishedSubitem(); + $objectStorageHoldingExactlyOnePublishedSubitems = new ObjectStorage(); + $objectStorageHoldingExactlyOnePublishedSubitems->attach($publishedSubitem); + $this->subject->setPublishedSubitems($objectStorageHoldingExactlyOnePublishedSubitems); + + self::assertSame( + $objectStorageHoldingExactlyOnePublishedSubitems, + $this->subject->getPublishedSubitems() + ); + } + + /** + * @test + */ + public function getPublisherReturnsInitialValueForPublisher() + { + self::assertEquals( + null, + $this->subject->getPublisher() + ); + } + + /** + * @test + */ + public function setPublisherForPublisherSetsPublisher() + { + $publisherFixture = new Publisher(); + $this->subject->setPublisher($publisherFixture); + + self::assertSame( + $publisherFixture, + $this->subject->getPublisher() + ); + } +} diff --git a/composer.json b/composer.json index 708a79d..755c9be 100755 --- a/composer.json +++ b/composer.json @@ -11,18 +11,24 @@ "require": { "typo3/cms-core": "^11", "typo3/cms-reports": "^11", - "elasticsearch/elasticsearch": "^7", - "slub/dm-ont": "dev-main", + "elasticsearch/elasticsearch": "^8", + "slub/dm-ont": "dev-dev", "fluidtypo3/vhs": "^6", "illuminate/collections": "^8" }, "config": { - "vendor-dir": ".Build/vendor", - "bin-dir": ".Build/bin" + "allow-plugins": { + "typo3/class-alias-loader": true, + "typo3/cms-composer-installers": true, + "php-http/discovery": true + }, + "vendor-dir": "vendor", + "bin-dir": "bin" }, "require-dev": { - "phpunit/phpunit": "^8", - "typo3/testing-framework": "^4.11.1" + "phpunit/phpunit": "^9", + "phpstan/phpstan": "^1", + "typo3/testing-framework": "^7" }, "autoload": { "psr-4": { @@ -37,7 +43,14 @@ "scripts": { "post-autoload-dump": [ "TYPO3\\TestingFramework\\Composer\\ExtensionTestEnvironment::prepare" - ] + ], + "ci": [ "@ci:install", "@ci:php", "@ci:tests" ], + "ci:php": [ "@ci:php:stan" ], + "ci:php:stan": [ "Build/Scripts/runTests.sh -s phpstan -b docker" ], + "ci:tests": [ "@ci:tests:unit", "@ci:tests:functional" ], + "ci:tests:unit": [ "Build/Scripts/runTests.sh -s unit -b docker" ], + "ci:tests:functional": [ "Build/Scripts/runTests.sh -s functional -b docker" ], + "ci:install": [ "Build/Scripts/runTests.sh -s composerInstall -b docker -b docker" ] }, "extra": { "typo3/cms": { @@ -45,5 +58,16 @@ "ignore-as-root": false, "web-dir": ".Build/Web" } - } + }, + "repositories": { + "dmnorm": { + "type": "git", + "url": "https://github.com/dikastes/dmnorm" + }, + "dmont": { + "type": "git", + "url": "https://github.com/dikastes/dmont" + } + }, + "minimum-stability": "dev" } diff --git a/ext_localconf.php b/ext_localconf.php new file mode 100755 index 0000000..f71dd4b --- /dev/null +++ b/ext_localconf.php @@ -0,0 +1,23 @@ + 'Elasticsearch Service', + 'description' => 'Provides the frontend with a connection to elasticsearch', + 'subtype' => '', + 'available' => true, + 'priority' => 50, + 'quality' => 50, + 'os' => '', + 'exec' => '', + 'className' => ElasticSearchService::class, + ] +); diff --git a/ext_tables.sql b/ext_tables.sql index df41083..7372e64 100755 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -11,7 +11,7 @@ CREATE TABLE tx_mpdbcore_domain_model_subiteminstrument ( # CREATE TABLE tx_mpdbcore_domain_model_publishedsubitem ( - publisher_makro_item int(11) unsigned DEFAULT '0' NOT NULL, + publisheditem int(11) unsigned DEFAULT '0' NOT NULL, plate_id varchar(255) DEFAULT '' NOT NULL, part varchar(255) DEFAULT '' NOT NULL, voice varchar(255) DEFAULT '' NOT NULL, @@ -88,7 +88,6 @@ CREATE TABLE tx_mpdbcore_domain_model_publisher ( alternate_name varchar(255) DEFAULT '' NOT NULL, active_from date DEFAULT NULL, active_to date DEFAULT NULL, - responsible_persons int(11) unsigned DEFAULT '0' NOT NULL, public smallint(5) unsigned DEFAULT '0' NOT NULL );