diff --git a/.dockerignore b/.dockerignore index 9b7c2718b..97db49a01 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ .git .github +.phpunit.cache .phpunit.result.cache .vscode coverage diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml index 9e0d1f973..7b19abfa5 100644 --- a/.github/workflows/javascript.yml +++ b/.github/workflows/javascript.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout current revision - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 17aa67a00..05c3119ed 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -24,17 +24,17 @@ jobs: cs: uses: bedita/github-workflows/.github/workflows/php-cs.yml@v2 with: - php_versions: '["8.3"]' + php_versions: '["8.4"]' psalm: uses: bedita/github-workflows/.github/workflows/php-psalm.yml@v2 with: - php_versions: '["8.3"]' + php_versions: '["8.4"]' stan: uses: bedita/github-workflows/.github/workflows/php-stan.yml@v2 with: - php_versions: '["8.3"]' + php_versions: '["8.4"]' unit-5: uses: bedita/github-workflows/.github/workflows/php-unit.yml@v2 @@ -46,6 +46,6 @@ jobs: unit-6: uses: bedita/github-workflows/.github/workflows/php-unit.yml@v2 with: - php_versions: '["8.3"]' + php_versions: '["8.4"]' bedita_version: '6' coverage_min_percentage: 98 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2fc0be19b..f53195160 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: uses: bedita/github-workflows/.github/workflows/release.yml@v2 with: main_branch: 'master' - dist_branches: '["master", "4.x"]' + dist_branches: '["master", "4.x", "5.x"]' version_bump: ${{ inputs.releaseType }} version_ini_path: config/version.ini version_ini_prefix: "[Manager]\nversion=" @@ -32,7 +32,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Debug output version run: | diff --git a/.gitignore b/.gitignore index a266d34b0..5ad8ef14e 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,4 @@ bundle-report.*.html /webroot/js/*.js /webroot/js/vendors /webroot/manifest.json +.phpunit.cache/test-results diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 0346e0e2f..a24871136 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -14,7 +14,7 @@ build: analysis: environment: php: - version: 8.3.3 + version: 8.3.16 tests: override: - php-scrutinizer-run diff --git a/Dockerfile b/Dockerfile index de4bda280..42a16bb8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,46 +1,99 @@ -ARG PHP_VERSION=8.3 -FROM chialab/php:${PHP_VERSION}-apache +# syntax=docker/dockerfile:1 -# Install Wait-for-it and configure PHP -RUN curl -o /wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh \ - && chmod +x /wait-for-it.sh \ - && echo "[PHP]\noutput_buffering = 4096\nmemory_limit = -1" > /usr/local/etc/php/php.ini +ARG PHP_VERSION=8.4 +ARG NODE_VERSION=24.10.0 +ARG YARN_VERSION=1.22.22 + +FROM node:${NODE_VERSION}-alpine AS node + +### +### Base runtime image (kept small): PHP-FPM + nginx + required PHP extensions. +### +FROM php:${PHP_VERSION}-fpm-alpine AS runtime-base + +RUN apk add --no-cache \ + nginx \ + curl \ + icu-libs \ + libpng \ + libjpeg-turbo \ + freetype \ + libzip \ + && apk add --no-cache --virtual .build-deps \ + $PHPIZE_DEPS \ + icu-dev \ + libpng-dev \ + libjpeg-turbo-dev \ + freetype-dev \ + libzip-dev \ + && docker-php-ext-configure gd --with-freetype --with-jpeg \ + && docker-php-ext-install -j$(nproc) intl gd zip \ + && apk del .build-deps \ + && mkdir -p /run/nginx # Copy files COPY . /var/www/html # Set APP_NAME to avoid .env load -ENV APP_NAME BE-MANAGER +ENV APP_NAME=BE-MANAGER ARG DEBUG -ENV DEBUG ${DEBUG:-false} +ENV DEBUG=${DEBUG:-false} # Install libraries WORKDIR /var/www/html + +### +### Builder image: installs git + node/yarn + composer and produces vendor + built assets. +### +FROM runtime-base AS build + +RUN apk add --no-cache git + +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer + +# Bring in a recent Node.js (pinned) only for the build stage +COPY --from=node /usr/local /usr/local +RUN node -v && npm -v + +RUN rm -f /usr/local/bin/yarn /usr/local/bin/yarnpkg \ + && corepack enable \ + && corepack prepare yarn@${YARN_VERSION} --activate \ + && yarn -v + +# Build assets (includes plugin assets via yarn install:plugins) +RUN yarn install --frozen-lockfile \ + && yarn build \ + && yarn cache clean + +# Composer deps (merge-plugin includes plugins/*/composer.json) + cleanup +RUN git config --global --add safe.directory /var/www/html \ + && composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader \ + && rm -rf /root/.composer/cache + +RUN rm -rf /var/www/html/node_modules /var/www/html/config/.env + RUN chown -R www-data:www-data /var/www/html -USER www-data:www-data -RUN if [ ! "$DEBUG" = "true" ]; then export COMPOSER_ARGS='--no-dev'; fi \ - && composer install $COMPOSER_ARGS --optimize-autoloader --no-interaction --quiet +### +### Final runtime image: copy only built artifacts from builder. +### +FROM runtime-base AS runtime + +COPY --from=build /var/www/html /var/www/html + +# Docker nginx + PHP-FPM configuration +COPY deploy/docker/nginx.conf /etc/nginx/http.d/default.conf +COPY deploy/docker/www.conf /usr/local/etc/php-fpm.d/www.conf -# Restore user `root` to install node & yarn and to make sure we can bind to address 0.0.0.0:80 -USER root:root +# App configuration +COPY deploy/docker/app_local.php /var/www/html/config/app_local.php -# Install node and yarn -ENV NODE_VERSION=22.11.0 -RUN apt install -y curl -RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash -ENV NVM_DIR=/root/.nvm -RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION} -RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION} -RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION} -ENV PATH="/root/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}" -RUN npm install -g yarn -RUN yarn && yarn build +# Entrypoint +COPY deploy/docker/docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh -ENV LOG_DEBUG_URL="console:///?stream=php://stdout" \ - LOG_ERROR_URL="console:///?stream=php://stderr" +EXPOSE 80 -HEALTHCHECK --interval=30s --timeout=3s --start-period=1m \ - CMD curl -f http://localhost/login || exit 1 +HEALTHCHECK --interval=120s --timeout=5s --retries=3 CMD curl --fail http://login || exit 1 -CMD ["apache2-foreground"] +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/README.md b/README.md index a1c1caad4..a75bf1dde 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Github Actions Javascript](https://github.com/bedita/manager/workflows/javascript/badge.svg)](https://github.com/bedita/manager/actions?query=workflow%3Ajavascript) [![codecov](https://codecov.io/gh/bedita/manager/branch/master/graph/badge.svg)](https://codecov.io/gh/bedita/manager) [![phpstan](https://img.shields.io/badge/PHPStan-level%205-brightgreen.svg)](https://phpstan.org) -[![psalm](https://img.shields.io/badge/psalm-level%208-brightgreen.svg)](https://psalm.dev) +[![psalm](https://img.shields.io/badge/psalm-level%207-brightgreen.svg)](https://psalm.dev) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/bedita/manager/badges/quality-score.png)](https://scrutinizer-ci.com/g/bedita/manager/) [![Version](https://img.shields.io/packagist/v/bedita/manager.svg?label=stable)](https://packagist.org/packages/bedita/manager) [![License](https://img.shields.io/badge/License-LGPL_v3-orange.svg)](https://github.com/bedita/manager/blob/master/LICENSE.LGPL) diff --git a/composer.json b/composer.json index f017c58eb..d6baf37f4 100644 --- a/composer.json +++ b/composer.json @@ -22,10 +22,10 @@ ], "require": { "php": ">=8.3", - "bedita/i18n": "^5.1.0", - "bedita/web-tools": "^5.4.0", - "cakephp/authentication": "^2.9", - "cakephp/cakephp": "~4.5.0", + "bedita/i18n": "^6.0.0", + "bedita/web-tools": "^6.0.0", + "cakephp/authentication": "^3.0.3", + "cakephp/cakephp": "^5.0", "cakephp/plugin-installer": "^1.3", "josegonzalez/dotenv": "^4.0", "league/flysystem": "^3.16", @@ -37,17 +37,17 @@ "wikimedia/composer-merge-plugin": "^2.0.1" }, "require-dev": { - "cakephp/bake": "^2.6", - "cakephp/cakephp-codesniffer": "~4.7.0", - "cakephp/console": "^4.4", - "cakephp/debug_kit": "^4.7.1", - "cakephp/repl": "^0.1", - "dereuromark/cakephp-ide-helper": "~1.17.0", - "phpstan/extension-installer": "^1.2", - "phpstan/phpstan": "^1.10", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpunit/phpunit": "^9.6", - "vimeo/psalm": "^5.18" + "cakephp/bake": "^3.2", + "cakephp/cakephp-codesniffer": "^5.0", + "cakephp/console": "^5.0", + "cakephp/debug_kit": "^5.0", + "cakephp/repl": "^2.0", + "dereuromark/cakephp-ide-helper": "^2.6", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^1.12", + "phpstan/phpstan-deprecation-rules": "^1.2", + "phpunit/phpunit": "^11.1.3", + "vimeo/psalm": "^6.8" }, "autoload": { "psr-4": { @@ -68,6 +68,7 @@ "@test", "@cs-check" ], + "psalm": "vendor/bin/psalm", "stan": "vendor/bin/phpstan analyse", "cs-check": "vendor/bin/phpcs", "cs-fix": "vendor/bin/phpcbf", diff --git a/config/app.php b/config/app.php index 58a39ca7d..518e1402a 100644 --- a/config/app.php +++ b/config/app.php @@ -105,9 +105,9 @@ * Duration will be set to '+2 minutes' in bootstrap.php when debug = true * If you set 'className' => 'Null' core cache will be disabled. */ - '_cake_core_' => [ + '_cake_translations_' => [ 'className' => FileEngine::class, - 'prefix' => 'manager_cake_core_', + 'prefix' => 'manager_cake_translations_', 'path' => CACHE . 'persistent/', 'serialize' => true, 'duration' => '+1 years', @@ -263,7 +263,7 @@ 'path' => LOGS, 'file' => 'debug', 'url' => env('LOG_DEBUG_URL', null), - 'scopes' => false, + 'scopes' => null, 'levels' => ['notice', 'info', 'debug'], ], 'error' => [ @@ -271,7 +271,7 @@ 'path' => LOGS, 'file' => 'error', 'url' => env('LOG_ERROR_URL', null), - 'scopes' => false, + 'scopes' => null, 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], ], ], diff --git a/config/bootstrap.php b/config/bootstrap.php index 448ed4689..87a07e5e3 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -29,6 +29,8 @@ */ require CORE_PATH . 'config' . DS . 'bootstrap.php'; +require CAKE . 'functions.php'; + use Cake\Cache\Cache; use Cake\Core\Configure; use Cake\Core\Configure\Engine\IniConfig; @@ -39,6 +41,8 @@ use Cake\Log\Log; use Cake\Routing\Router; use Cake\Utility\Security; +use Detection\MobileDetect; +use josegonzalez\Dotenv\Loader; /* * See https://github.com/josegonzalez/php-dotenv for API details. @@ -55,7 +59,7 @@ * for more information for recommended practices. */ if (!env('APP_NAME') && file_exists(CONFIG . '.env')) { - $dotenv = new \josegonzalez\Dotenv\Loader([CONFIG . '.env']); + $dotenv = new Loader([CONFIG . '.env']); $dotenv->parse() ->putenv() ->toEnv() @@ -94,7 +98,7 @@ Configure::config('ini', new IniConfig()); Configure::load('version', 'ini'); Configure::load('bedita-api-version', 'ini'); -} catch (\Exception $e) { +} catch (Exception $e) { exit($e->getMessage() . "\n"); } @@ -112,7 +116,7 @@ */ if (Configure::read('debug')) { Configure::write('Cache._cake_model_.duration', '+2 minutes'); - Configure::write('Cache._cake_core_.duration', '+2 minutes'); + Configure::write('Cache._cake_translations_.duration', '+2 minutes'); Configure::write('Cache._schema_types_.duration', '+2 minutes'); Configure::write('Cache._project_config_.duration', '+2 minutes'); Configure::write('Cache._thumbs_.duration', '+2 minutes'); @@ -191,12 +195,12 @@ * and the mobiledetect package from composer.json. */ ServerRequest::addDetector('mobile', function ($request) { - $detector = new \Detection\MobileDetect(); + $detector = new MobileDetect(); return $detector->isMobile(); }); ServerRequest::addDetector('tablet', function ($request) { - $detector = new \Detection\MobileDetect(); + $detector = new MobileDetect(); return $detector->isTablet(); }); diff --git a/config/paths.php b/config/paths.php index 95e21acab..c86b360c8 100644 --- a/config/paths.php +++ b/config/paths.php @@ -28,7 +28,9 @@ /** * The full path to the directory which holds "src", WITHOUT a trailing DS. */ -define('ROOT', dirname(__DIR__)); +if (!defined('ROOT')) { + define('ROOT', dirname(__DIR__)); +} /** * The actual directory name for the application directory. Normally @@ -85,10 +87,16 @@ * * CakePHP should always be installed with composer, so look there. */ -define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'vendor' . DS . 'cakephp' . DS . 'cakephp'); +if (!defined('CAKE_CORE_INCLUDE_PATH')) { + define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'vendor' . DS . 'cakephp' . DS . 'cakephp'); +} /** * Path to the cake directory. */ -define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); -define('CAKE', CORE_PATH . 'src' . DS); +if (!defined('CORE_PATH')) { + define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); +} +if (!defined('CAKE')) { + define('CAKE', CORE_PATH . 'src' . DS); +} diff --git a/config/routes.php b/config/routes.php index e2a97b138..75dea7db1 100644 --- a/config/routes.php +++ b/config/routes.php @@ -48,83 +48,83 @@ $routes->connect( '/*', ['controller' => 'CourtesyPage', 'action' => 'index'], - ['_name' => 'courtesypage'] + ['_name' => 'courtesypage'], ); return; } -$routes->scope('/', function (RouteBuilder $routes) { +$routes->scope('/', function (RouteBuilder $routes): void { // Reset & change password $routes->connect( '/login/reset', ['controller' => 'Password', 'action' => 'reset'], - ['_name' => 'password:reset'] + ['_name' => 'password:reset'], ); $routes->connect( '/login/change', ['controller' => 'Password', 'action' => 'change'], - ['_name' => 'password:change'] + ['_name' => 'password:change'], ); // Login. $routes->connect( '/login', ['controller' => 'Login', 'action' => 'login'], - ['_name' => 'login'] + ['_name' => 'login'], ); $routes->connect( '/logout', ['controller' => 'Login', 'action' => 'logout'], - ['_name' => 'logout'] + ['_name' => 'logout'], ); $routes->connect( '/ext/login/{provider}', ['controller' => 'Login', 'action' => 'login'], - ['_name' => 'login:oauth2'] + ['_name' => 'login:oauth2'], ); // Dashboard. $routes->connect( '/', ['controller' => 'Dashboard', 'action' => 'index'], - ['_name' => 'dashboard'] + ['_name' => 'dashboard'], ); $routes->connect( '/dashboard/messages', ['controller' => 'Dashboard', 'action' => 'messages'], - ['_name' => 'dashboard:messages'] + ['_name' => 'dashboard:messages'], ); $routes->connect( '/tree', ['controller' => 'Tree', 'action' => 'get'], - ['_name' => 'tree:get'] + ['_name' => 'tree:get'], ); $routes->connect( '/tree/node/{id}', ['controller' => 'Tree', 'action' => 'node'], - ['_name' => 'tree:node', 'pass' => ['id']] + ['_name' => 'tree:node', 'pass' => ['id']], ); $routes->connect( '/tree/parent/{id}', ['controller' => 'Tree', 'action' => 'parent'], - ['_name' => 'tree:parent', 'pass' => ['id']] + ['_name' => 'tree:parent', 'pass' => ['id']], ); $routes->connect( '/tree/parents/{type}/{id}', ['controller' => 'Tree', 'action' => 'parents'], - ['_name' => 'tree:parents', 'pass' => ['type', 'id']] + ['_name' => 'tree:parents', 'pass' => ['type', 'id']], ); // Slug $routes->connect( '/tree/slug', ['controller' => 'Tree', 'action' => 'slug'], - ['_name' => 'tree:slug'] + ['_name' => 'tree:slug'], ); // Admin. - $routes->prefix('admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $routes) { + $routes->prefix('admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $routes): void { $adminRoutes = [ 'appearance', 'applications', @@ -148,31 +148,31 @@ $routes->get( "/$controller", ['controller' => $name, 'action' => 'index'], - 'list:' . $controller + 'list:' . $controller, ); $routes->get( "/$controller/view/{id}", ['controller' => $name, 'action' => 'view'], - 'view:' . $controller + 'view:' . $controller, )->setPass(['id']); $routes->post( "/$controller/save", ['controller' => $name, 'action' => 'save'], - 'save:' . $controller + 'save:' . $controller, ); $routes->post( "/$controller/remove/{id}", ['controller' => $name, 'action' => 'remove'], - 'remove:' . $controller + 'remove:' . $controller, )->setPass(['id']); } $routes->get( '/cache', ['controller' => 'Cache', 'action' => 'clear'], - 'cache:clear' + 'cache:clear', ); }); @@ -180,16 +180,16 @@ $routes->connect( '/user_profile', ['controller' => 'UserProfile', 'action' => 'view'], - ['_name' => 'user_profile:view'] + ['_name' => 'user_profile:view'], ); $routes->connect( '/user_profile/save', ['controller' => 'UserProfile', 'action' => 'save'], - ['_name' => 'user_profile:save'] + ['_name' => 'user_profile:save'], ); // Model. - $routes->prefix('model', ['_namePrefix' => 'model:'], function (RouteBuilder $routes) { + $routes->prefix('model', ['_namePrefix' => 'model:'], function (RouteBuilder $routes): void { foreach (['object_types', 'property_types', 'relations', 'categories', 'tags'] as $controller) { // Routes connected here are prefixed with '/model' @@ -197,31 +197,31 @@ $routes->get( "/$controller", ['controller' => $name, 'action' => 'index'], - 'list:' . $controller + 'list:' . $controller, ); $routes->get( "/$controller/view", ['controller' => $name, 'action' => 'create'], - 'create:' . $controller + 'create:' . $controller, ); $routes->get( "/$controller/view/{id}", ['controller' => $name, 'action' => 'view'], - 'view:' . $controller + 'view:' . $controller, )->setPass(['id']); $routes->post( "/$controller/save", ['controller' => $name, 'action' => 'save'], - 'save:' . $controller + 'save:' . $controller, ); $routes->post( "/$controller/remove/{id}", ['controller' => $name, 'action' => 'remove'], - 'remove:' . $controller + 'remove:' . $controller, )->setPass(['id']); } @@ -229,7 +229,7 @@ $routes->get( '/export', ['controller' => 'Export', 'action' => 'model'], - 'export' + 'export', ); }); @@ -237,82 +237,82 @@ $routes->connect( '/import', ['controller' => 'Import', 'action' => 'index'], - ['_name' => 'import:index'] + ['_name' => 'import:index'], ); $routes->connect( '/import/file', ['controller' => 'Import', 'action' => 'file', '_method' => 'POST'], - ['_name' => 'import:file'] + ['_name' => 'import:file'], ); $routes->connect( '/import/jobs', ['controller' => 'Import', 'action' => 'jobs'], - ['_name' => 'import:jobs'] + ['_name' => 'import:jobs'], ); // Trash. $routes->connect( '/trash', ['controller' => 'Trash', 'action' => 'index', '_method' => 'GET'], - ['_name' => 'trash:list'] + ['_name' => 'trash:list'], ); $routes->connect( '/trash/view/{id}', ['controller' => 'Trash', 'action' => 'view'], - ['pass' => ['id'], '_name' => 'trash:view'] + ['pass' => ['id'], '_name' => 'trash:view'], ); $routes->connect( '/trash/restore', ['controller' => 'Trash', 'action' => 'restore'], - ['_name' => 'trash:restore'] + ['_name' => 'trash:restore'], ); $routes->connect( '/trash/delete', ['controller' => 'Trash', 'action' => 'delete'], - ['_name' => 'trash:delete'] + ['_name' => 'trash:delete'], ); $routes->connect( '/trash/empty', ['controller' => 'Trash', 'action' => 'emptyTrash'], - ['_name' => 'trash:empty'] + ['_name' => 'trash:empty'], ); // tags $routes->connect( '/tags', ['controller' => 'Tags', 'action' => 'index'], - ['_name' => 'tags:index'] + ['_name' => 'tags:index'], ); $routes->connect( '/tags/delete/{id}', ['controller' => 'Tags', 'action' => 'delete'], - ['pass' => ['id'], '_name' => 'tags:delete'] + ['pass' => ['id'], '_name' => 'tags:delete'], ); $routes->connect( '/tags/create', ['controller' => 'Tags', 'action' => 'create'], - ['_name' => 'tags:create'] + ['_name' => 'tags:create'], ); $routes->connect( '/tags/patch/{id}', ['controller' => 'Tags', 'action' => 'patch'], - ['pass' => ['id'], '_name' => 'tags:patch'] + ['pass' => ['id'], '_name' => 'tags:patch'], ); $routes->connect( '/tags/search', ['controller' => 'Tags', 'action' => 'search'], - ['_name' => 'tags:search'] + ['_name' => 'tags:search'], ); // view resource by id / uname $routes->connect( '/view/{id}', ['controller' => 'Modules', 'action' => 'uname'], - ['pass' => ['id'], '_name' => 'modules:uname'] + ['pass' => ['id'], '_name' => 'modules:uname'], ); // API proxy - $routes->scope('/api', ['_namePrefix' => 'api:'], function (RouteBuilder $routes) { + $routes->scope('/api', ['_namePrefix' => 'api:'], function (RouteBuilder $routes): void { $routes->get('/**', ['controller' => 'Api', 'action' => 'get'], 'get'); $routes->post('/**', ['controller' => 'Api', 'action' => 'post'], 'post'); $routes->patch('/**', ['controller' => 'Api', 'action' => 'patch'], 'patch'); @@ -323,137 +323,137 @@ $routes->connect( '/{object_type}', ['controller' => 'Modules', 'action' => 'index'], - ['_name' => 'modules:list'] + ['_name' => 'modules:list'], ); $routes->connect( '/{object_type}/view', ['controller' => 'Modules', 'action' => 'create'], - ['_name' => 'modules:create'] + ['_name' => 'modules:create'], ); $routes->connect( '/{object_type}/setup', ['controller' => 'Modules', 'action' => 'setup'], - ['_name' => 'modules:setup'] + ['_name' => 'modules:setup'], ); $routes->connect( '/{object_type}/multiupload', ['controller' => 'Multiupload', 'action' => 'index'], - ['_name' => 'modules:multiupload'] + ['_name' => 'modules:multiupload'], ); $routes->connect( '/{object_type}/categories', ['controller' => 'Categories', 'action' => 'index'], - ['_name' => 'modules:categories:index'] + ['_name' => 'modules:categories:index'], ); $routes->connect( '/{object_type}/categories/save', ['controller' => 'Categories', 'action' => 'save'], - ['_name' => 'modules:categories:save'] + ['_name' => 'modules:categories:save'], ); $routes->connect( '/{object_type}/categories/remove/{id}', ['controller' => 'Categories', 'action' => 'delete'], - ['_name' => 'modules:categories:remove', 'pass' => ['id']] + ['_name' => 'modules:categories:remove', 'pass' => ['id']], ); $routes->connect( '/{object_type}/view/{id}', ['controller' => 'Modules', 'action' => 'view'], - ['pass' => ['id'], '_name' => 'modules:view'] + ['pass' => ['id'], '_name' => 'modules:view'], ); $routes->connect( '/{object_type}/view/{id}/history/{historyId}', ['controller' => 'History', 'action' => 'restore'], - ['pass' => ['id', 'historyId'], '_name' => 'history:restore'] + ['pass' => ['id', 'historyId'], '_name' => 'history:restore'], ); // Translations $routes->connect( '/translations', ['controller' => 'Translations', 'action' => 'index'], - ['_name' => 'translations:list'] + ['_name' => 'translations:list'], ); $routes->connect( '/{object_type}/translation/save', ['controller' => 'Translations', 'action' => 'save'], - ['_name' => 'translations:save'] + ['_name' => 'translations:save'], ); $routes->connect( '/{object_type}/translation/delete', ['controller' => 'Translations', 'action' => 'delete'], - ['_name' => 'translations:delete'] + ['_name' => 'translations:delete'], ); $routes->connect( '/{object_type}/translation/{id}/add', ['controller' => 'Translations', 'action' => 'add'], - ['pass' => ['id'], '_name' => 'translations:add'] + ['pass' => ['id'], '_name' => 'translations:add'], ); $routes->connect( '/{object_type}/translation/{id}/{lang}', ['controller' => 'Translations', 'action' => 'edit'], - ['pass' => ['id', 'lang'], '_name' => 'translations:edit'] + ['pass' => ['id', 'lang'], '_name' => 'translations:edit'], ); // Relations ... $routes->connect( '/{object_type}/view/{id}/related/{relation}', ['controller' => 'Modules', 'action' => 'related'], - ['pass' => ['id', 'relation'], '_name' => 'modules:related'] + ['pass' => ['id', 'relation'], '_name' => 'modules:related'], ); $routes->connect( '/{object_type}/view/{id}/relationships/{relation}', ['controller' => 'Modules', 'action' => 'relationships'], - ['pass' => ['id', 'relation'], '_name' => 'modules:relationships'] + ['pass' => ['id', 'relation'], '_name' => 'modules:relationships'], ); $routes->connect( '/{object_type}/view/{id}/resources/{relation}', ['controller' => 'Modules', 'action' => 'resources'], - ['pass' => ['id', 'relation'], '_name' => 'modules:resources'] + ['pass' => ['id', 'relation'], '_name' => 'modules:resources'], ); $routes->connect( '/{object_type}/view/{id}/relationData/{relation}', ['controller' => 'Modules', 'action' => 'relationData'], - ['pass' => ['id', 'relation'], '_name' => 'modules:relationData'] + ['pass' => ['id', 'relation'], '_name' => 'modules:relationData'], ); $routes->connect( '/{object_type}/save', ['controller' => 'Modules', 'action' => 'save'], - ['_name' => 'modules:save'] + ['_name' => 'modules:save'], ); $routes->connect( '/{object_type}/clone/{id}', ['controller' => 'Modules', 'action' => 'clone'], - ['pass' => ['id'], '_name' => 'modules:clone'] + ['pass' => ['id'], '_name' => 'modules:clone'], ); $routes->connect( '/{object_type}/clone/{id}/history/{historyId}', ['controller' => 'History', 'action' => 'clone'], - ['pass' => ['id', 'historyId'], '_name' => 'history:clone'] + ['pass' => ['id', 'historyId'], '_name' => 'history:clone'], ); $routes->connect( '/{object_type}/history/{id}/{page}', ['controller' => 'History', 'action' => 'info'], - ['pass' => ['id', 'page'], '_name' => 'history:info'] + ['pass' => ['id', 'page'], '_name' => 'history:info'], ); $routes->connect( '/{object_type}/delete', ['controller' => 'Modules', 'action' => 'delete'], - ['_name' => 'modules:delete'] + ['_name' => 'modules:delete'], ); // Export $routes->connect( '/{object_type}/export', ['controller' => 'Export', 'action' => 'export'], - ['_name' => 'export:export'] + ['_name' => 'export:export'], ); $routes->connect( '/{object_type}/export/{id}/{relation}/{format}', ['controller' => 'Export', 'action' => 'related'], - ['pass' => ['id', 'relation', 'format'], '_name' => 'export:related'] + ['pass' => ['id', 'relation', 'format'], '_name' => 'export:related'], ); $routes->connect( '/{object_type}/exportFiltered/{id}/{relation}/{format}/{query}', ['controller' => 'Export', 'action' => 'relatedFiltered'], - ['pass' => ['id', 'relation', 'format', 'query'], '_name' => 'export:related:filtered'] + ['pass' => ['id', 'relation', 'format', 'query'], '_name' => 'export:related:filtered'], ); $routes->get( @@ -487,7 +487,7 @@ $routes->get( '/download/{id}', ['controller' => 'Download', 'action' => 'download'], - 'stream:download' + 'stream:download', ) ->setPass(['id']); @@ -495,60 +495,67 @@ $routes->connect( '/{object_type}/bulkAttribute', ['controller' => 'Bulk', 'action' => 'attribute'], - ['_name' => 'modules:bulkAttribute'] + ['_name' => 'modules:bulkAttribute'], )->setMethods(['post']); $routes->connect( '/{object_type}/bulkCategories', ['controller' => 'Bulk', 'action' => 'categories'], - ['_name' => 'modules:bulkCategories'] + ['_name' => 'modules:bulkCategories'], )->setMethods(['post']); $routes->connect( '/{object_type}/bulkPosition', ['controller' => 'Bulk', 'action' => 'position'], - ['_name' => 'modules:bulkPosition'] + ['_name' => 'modules:bulkPosition'], )->setMethods(['post']); $routes->connect( '/{object_type}/bulkCustom', ['controller' => 'Bulk', 'action' => 'custom'], - ['_name' => 'modules:bulkCustom'] + ['_name' => 'modules:bulkCustom'], )->setMethods(['post']); // translator service $routes->connect( '/translate', ['controller' => 'Translator', 'action' => 'translate'], - ['_name' => 'translator:translate'] + ['_name' => 'translator:translate'], ); // lock and unlock objects $routes->connect( '/{object_type}/{id}/lock', ['controller' => 'Lock', 'action' => 'add'], - ['_name' => 'lock:add'] + ['_name' => 'lock:add'], ); $routes->connect( '/{object_type}/{id}/unlock', ['controller' => 'Lock', 'action' => 'remove'], - ['_name' => 'lock:remove'] + ['_name' => 'lock:remove'], + ); + + // SendMail + $routes->connect( + '/sendmail', + ['controller' => 'SendMail', 'action' => 'index'], + ['_name' => 'sendmail:index'], ); // Session $routes->get( '/session/{name}', ['controller' => 'Session', 'action' => 'view'], - 'session:view' + 'session:view', )->setPass(['name']); $routes->connect( '/session', ['controller' => 'Session', 'action' => 'save'], - ['_name' => 'session:save'] + ['_name' => 'session:save'], )->setMethods(['POST', 'PATCH']); $routes->delete( '/session/{name}', ['controller' => 'Session', 'action' => 'delete'], - 'session:delete' + 'session:delete', )->setPass(['name']); }); diff --git a/deploy/docker/app_local.php b/deploy/docker/app_local.php new file mode 100644 index 000000000..dcdd8306a --- /dev/null +++ b/deploy/docker/app_local.php @@ -0,0 +1,26 @@ + [ + 'locales' => [ + 'en_US' => 'en', + 'it_IT' => 'it', + ], + 'default' => 'it', + 'lang' => 'it', + 'languages' => [ + 'en' => 'English', + 'it' => 'Italiano', + ], + 'timezone' => 'UTC', + 'cookie' => [ + 'name' => 'BEM6-LANG', + 'create' => true, + ], + 'switchLangUrl' => '/lang', + ], + 'Project' => [ + 'name' => 'BEdita Manager', + ], +]; diff --git a/deploy/docker/docker-entrypoint.sh b/deploy/docker/docker-entrypoint.sh new file mode 100644 index 000000000..e5ed3d023 --- /dev/null +++ b/deploy/docker/docker-entrypoint.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +php --version >&2 + +chown -R www-data:www-data /var/www/html/tmp /var/www/html/logs + +# Start PHP-FPM in the background +php-fpm -D + +# Start nginx in the foreground +exec nginx -g 'daemon off;' diff --git a/deploy/docker/nginx.conf b/deploy/docker/nginx.conf new file mode 100644 index 000000000..85a17a030 --- /dev/null +++ b/deploy/docker/nginx.conf @@ -0,0 +1,29 @@ +log_format manager '$time_iso8601 "$request" $status'; + +access_log /dev/stdout manager; +error_log /dev/stderr warn; + +server { + listen 80; + server_name localhost; + + root /var/www/html/webroot; + index index.php; + + location / { + try_files $uri $uri/ /index.php?$args; + } + + location ~ \.php$ { + try_files $uri =404; + include fastcgi_params; + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + fastcgi_intercept_errors on; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } + + location ~ /\.ht { + deny all; + } +} diff --git a/deploy/docker/www.conf b/deploy/docker/www.conf new file mode 100644 index 000000000..5cf964b96 --- /dev/null +++ b/deploy/docker/www.conf @@ -0,0 +1,18 @@ +[www] +user = www-data +group = www-data +listen = 127.0.0.1:9000 + +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 + +access.log = /dev/null + +env[PATH] = /usr/local/bin:/usr/bin:/bin + +catch_workers_output = yes + +request_terminate_timeout = 300 diff --git a/locales/default.pot b/locales/default.pot index 9199b4de5..2d3c04601 100644 --- a/locales/default.pot +++ b/locales/default.pot @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: BEdita 4 \n" -"POT-Creation-Date: 2025-08-26 08:17:45 \n" +"POT-Creation-Date: 2025-10-29 11:08:16 \n" "MIME-Version: 1.0 \n" "Content-Transfer-Encoding: 8bit \n" "Language-Team: BEdita I18N & I10N Team \n" @@ -1765,6 +1765,9 @@ msgstr "" msgid "View original" msgstr "" +msgid "Send" +msgstr "" + msgid "Address" msgstr "" diff --git a/locales/en_US/default.po b/locales/en_US/default.po index 4fea704f5..04a352a16 100644 --- a/locales/en_US/default.po +++ b/locales/en_US/default.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: BEdita Manager \n" -"POT-Creation-Date: 2025-08-26 08:17:45 \n" +"POT-Creation-Date: 2025-10-29 11:08:16 \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: BEdita I18N & I10N Team \n" @@ -1768,6 +1768,9 @@ msgstr "" msgid "View original" msgstr "" +msgid "Send" +msgstr "" + msgid "Address" msgstr "" diff --git a/locales/it_IT/default.po b/locales/it_IT/default.po index 9ab7d401b..bf1b9d702 100644 --- a/locales/it_IT/default.po +++ b/locales/it_IT/default.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: BEdita Manager \n" -"POT-Creation-Date: 2025-08-26 08:17:45 \n" +"POT-Creation-Date: 2025-10-29 11:08:16 \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: BEdita I18N & I10N Team \n" @@ -1791,6 +1791,9 @@ msgstr "" msgid "View original" msgstr "Vedi originale" +msgid "Send" +msgstr "Invia" + msgid "Address" msgstr "Indirizzo" diff --git a/package.json b/package.json index e86d7cd62..5b76d0556 100644 --- a/package.json +++ b/package.json @@ -63,9 +63,9 @@ "eslint-plugin-vue": "^9.32.0", "gettext-parser": "^4.0.2", "json-loader": "^0.5.7", - "mini-css-extract-plugin": "^2.9.2", + "mini-css-extract-plugin": "^2.9.4", "moment-locales-webpack-plugin": "^1.0.7", - "sass": "^1.82.0", + "sass": "^1.90.0", "sass-loader": "^12.2.0", "svg-url-loader": "^7.1.1", "ttag-cli": "^1.9.2", @@ -76,4 +76,4 @@ "webpack-watch-files-plugin": "^1.2.0" }, "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610" -} \ No newline at end of file +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7bea56f59..795b482ed 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,14 +1,22 @@ - - + + - ./src/ + ./src/ - ./src/Console/Installer.php - ./src/Shell/ConsoleShell.php + ./src/Console/Installer.php + ./src/Shell/ConsoleShell.php - + diff --git a/psalm.xml b/psalm.xml index 9e239f125..4cdd8e3e6 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,16 +1,20 @@ + + + diff --git a/resources/js/app/app.js b/resources/js/app/app.js index 746b02120..23488317e 100644 --- a/resources/js/app/app.js +++ b/resources/js/app/app.js @@ -117,6 +117,7 @@ const _vueInstance = new Vue({ AddRelatedById: () => import(/* webpackChunkName: "add-related-by-id" */'app/components/add-related-by-id/add-related-by-id'), UploadedObject: () => import(/* webpackChunkName: "uploaded-object" */'app/components/uploaded-object/uploaded-object.vue'), RibbonItem: () => import(/* webpackChunkName: "ribbon-item" */'./components/ribbon-item/ribbon-item.vue'), + MailPreview: () => import(/* webpackChunkName: "mail-preview" */'./components/mail-preview/mail-preview.vue'), AppIcon, }, diff --git a/resources/js/app/components/dialog/dialog.scss b/resources/js/app/components/dialog/dialog.scss index 4cfab9a26..b47836cbf 100644 --- a/resources/js/app/components/dialog/dialog.scss +++ b/resources/js/app/components/dialog/dialog.scss @@ -1,3 +1,5 @@ +@use "../../../../styles/variables"; + .bedita-dialog { .backdrop { position: fixed; @@ -52,28 +54,28 @@ } &.warning { - border-color: $warning; + border-color: variables.$warning; } &.error { - border-color: $error; + border-color: variables.$error; } &.prompt, &.info { - border-color: $info; + border-color: variables.$info; .icon-info-1, .icon-info-circled { - color: $info; + color: variables.$info; } } &.success { - border-color: $success; + border-color: variables.$success; .icon-ok-circled-1 { - color: $success; + color: variables.$success; } } @@ -89,7 +91,7 @@ input[type=text] { width: 100%; - border: 1px solid $gray-600; + border: 1px solid variables.$gray-600; } details { @@ -101,12 +103,12 @@ width: 100%; max-height: 400px; overflow: auto; - margin-top: $gutter * .75; - padding: $gutter * .75; + margin-top: variables.$gutter * .75; + padding: variables.$gutter * .75; flex: 1; - background-color: $gray-200; + background-color: variables.$gray-200; font-family: monospace; - font-size: $font-size-sm; + font-size: variables.$font-size-sm; } } } diff --git a/resources/js/app/components/mail-preview/mail-preview.vue b/resources/js/app/components/mail-preview/mail-preview.vue new file mode 100644 index 000000000..32f41e8b6 --- /dev/null +++ b/resources/js/app/components/mail-preview/mail-preview.vue @@ -0,0 +1,122 @@ + + + diff --git a/resources/js/app/components/module/module-properties.vue b/resources/js/app/components/module/module-properties.vue index 418033fd0..f0dbded92 100644 --- a/resources/js/app/components/module/module-properties.vue +++ b/resources/js/app/components/module/module-properties.vue @@ -150,7 +150,7 @@ export default { this.$nextTick(() => { this.originalVal = JSON.stringify(this.module); this.fields.forEach((field) => { - this.map[field] = this.module[field] || ''; + this.map[field] = this.module?.[field] || ''; }); }); }, diff --git a/resources/js/app/components/object-info/object-info.vue b/resources/js/app/components/object-info/object-info.vue index eb0ce58fa..29d53459d 100644 --- a/resources/js/app/components/object-info/object-info.vue +++ b/resources/js/app/components/object-info/object-info.vue @@ -55,8 +55,7 @@ export default { }).join(' '); }, fillData() { - const source = BEDITA?.indexLists?.[this.reloadedData?.type] || {}; - this.fields = source || ['title', 'description']; + this.fields = BEDITA?.indexLists?.[this.reloadedData?.type] || ['title', 'description']; this.fields = this.fields?.filter((value, index, array) => { return array.indexOf(value) === index; }); diff --git a/resources/js/app/components/property-view/property-view.js b/resources/js/app/components/property-view/property-view.js index 101f1c6d6..ce61517e4 100644 --- a/resources/js/app/components/property-view/property-view.js +++ b/resources/js/app/components/property-view/property-view.js @@ -48,6 +48,7 @@ export default { ObjectCategories: () => import(/* webpackChunkName: "object-categories" */'app/components/object-categories/object-categories'), PlaceholderList: () => import(/* webpackChunkName: "placeholder-list" */'app/components/placeholder-list/placeholder-list'), MediaItem: () => import(/* webpackChunkName: "media-item" */'app/components/media-item/media-item'), + MailPreview: () => import(/* webpackChunkName: "mail-preview" */'app/components/mail-preview/mail-preview.vue'), }, props: { diff --git a/resources/js/app/pages/modules/view.vue b/resources/js/app/pages/modules/view.vue index a76daee3b..6695d1e6a 100644 --- a/resources/js/app/pages/modules/view.vue +++ b/resources/js/app/pages/modules/view.vue @@ -16,6 +16,7 @@ export default { KeyValueList: () => import(/* webpackChunkName: "key-value-list" */'app/components/json-fields/key-value-list'), StringList: () => import(/* webpackChunkName: "string-list" */'app/components/json-fields/string-list'), LanguageSelector:() => import(/* webpackChunkName: "language-selector" */'app/components/language-selector/language-selector'), + MailPreview: () => import(/* webpackChunkName: "mail-preview" */'app/components/mail-preview/mail-preview.vue'), }, props: { diff --git a/resources/richeditor.lazy.scss b/resources/richeditor.lazy.scss index 09057dfbe..1ec3e2408 100644 --- a/resources/richeditor.lazy.scss +++ b/resources/richeditor.lazy.scss @@ -8,14 +8,14 @@ BEdita Manager */ -@import './styles/variables'; // common variables used for color, margins, typography, media breakpoints, tag collections -@import './styles/mixins'; +@use 'styles/variables'; // common variables used for color, margins, typography, media breakpoints, tag collections +@use 'styles/mixins'; // general -@import './styles/base'; +@use 'styles/base'; // tinymce base content style -@import '~tinymce/skins/ui/oxide/content'; +@use '../node_modules/tinymce/skins/ui/oxide/content'; @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,200;0,400;1,200;1,400&family=IBM+Plex+Sans:ital,wght@0,200;0,300;0,400;0,500;1,200;1,300;1,400;1,500&family=IBM+Plex+Serif:ital,wght@0,200;0,400;0,700;1,200;1,400;1,700&display=swap"); @@ -23,9 +23,9 @@ body { padding: 1em !important; color: unset; background: unset; - font-family: $font-family-monospace; - font-size: $font-size-base; - font-weight: $font-weight-base; + font-family: variables.$font-family-monospace; + font-size: variables.$font-size-base; + font-weight: variables.$font-weight-base; } .mce-offscreen-selection { @@ -40,7 +40,7 @@ p { blockquote { padding-left:1rem; margin-left:0; - border-left: 4px solid $gray-700; + border-left: 4px solid variables.$gray-700; } a { @@ -58,7 +58,7 @@ a:link, a:hover, a:active, a:visited { [data-placeholder] { &[data-mce-selected] { - outline: solid 2px $info; + outline: solid 2px variables.$info; } } @@ -91,11 +91,11 @@ div[data-placeholder] { } details { - border: 1px solid $gray-700; + border: 1px solid variables.$gray-700; border-radius: 2px; padding: 0 4px; } summary { - border-bottom: 1px solid $gray-700; + border-bottom: 1px solid variables.$gray-700; } diff --git a/resources/style.scss b/resources/style.scss index d5a2718e7..139c58ce1 100644 --- a/resources/style.scss +++ b/resources/style.scss @@ -9,60 +9,59 @@ BEdita Manager */ - -// Google Fonts -@import 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,200;0,400;1,200;1,400&family=IBM+Plex+Sans:ital,wght@0,200;0,300;0,400;0,500;1,200;1,300;1,400;1,500&family=IBM+Plex+Serif:ital,wght@0,200;0,400;0,700;1,200;1,400;1,700&display=swap'; - -@import './styles/variables'; // common variables used for color, margins, typography, media breakpoints, tag collections -@import './styles/mixins'; +@use 'styles/variables'; // common variables used for color, margins, typography, media breakpoints, tag collections +@use 'styles/mixins'; // general -@import './styles/base_normalize'; -@import './styles/base'; -@import './styles/layout'; // main grid base layout -@import './styles/buttons'; -@import './styles/forms'; -@import './styles/forms_file'; -@import './styles/utility_classes'; -@import './styles/elements'; -@import './styles/columns'; -@import './styles/richtexteditor'; +@use 'styles/base_normalize'; +@use 'styles/base'; +@use 'styles/layout'; // main grid base layout +@use 'styles/buttons'; +@use 'styles/forms'; +@use 'styles/forms_file'; +@use 'styles/utility_classes'; +@use 'styles/elements'; +@use 'styles/columns'; +@use 'styles/richtexteditor'; // elements -@import '../templates/Element/Form/form'; -@import '../templates/Element/Form/calendar'; -@import '../templates/Element/Form/locations'; -@import '../templates/Element/Form/trees'; -@import '../templates/Element/Form/publish_properties'; -@import '../templates/Element/Form/relations'; -@import '../templates/Element/Form/map'; -@import '../templates/Element/Form/history'; -@import '../templates/Element/Form/categories'; -@import '../templates/Element/flash/flash'; -@import '../templates/Element/Menu/colophon'; -@import '../templates/Element/Menu/menu'; -@import '../templates/Element/Menu/sidebar'; -@import '../templates/Element/Modules/index_properties'; -@import '../templates/Element/FilterBox/filter_box'; -@import '../templates/Element/Panel/panel'; +@use '../templates/Element/Form/form'; +@use '../templates/Element/Form/calendar'; +@use '../templates/Element/Form/locations'; +@use '../templates/Element/Form/trees'; +@use '../templates/Element/Form/publish_properties'; +@use '../templates/Element/Form/relations'; +@use '../templates/Element/Form/map'; +@use '../templates/Element/Form/history'; +@use '../templates/Element/Form/categories'; +@use '../templates/Element/flash/flash'; +@use '../templates/Element/Menu/colophon'; +@use '../templates/Element/Menu/menu'; +@use '../templates/Element/Menu/sidebar'; +@use '../templates/Element/Modules/index_properties'; +@use '../templates/Element/FilterBox/filter_box'; +@use '../templates/Element/Panel/panel'; // components -@import './js/app/components/dialog/dialog.scss'; -@import './js/app/components/ajax-login/ajax-login.scss'; -@import './js/app/components/tag-form/tag-form.scss'; +@use 'js/app/components/dialog/dialog.scss'; +@use 'js/app/components/ajax-login/ajax-login.scss'; +@use 'js/app/components/tag-form/tag-form.scss'; // Pages -@import '../templates/Pages/Login/login'; -@import '../templates/Pages/Dashboard/dashboard'; -@import '../templates/Pages/Admin/admin'; -@import '../templates/Pages/Import/import'; -@import '../templates/Pages/Modules/modules-index'; -@import '../templates/Pages/Modules/modules-view'; -@import '../templates/Pages/Model/model-index'; -@import '../templates/Pages/Model/model-view'; -@import '../templates/Pages/Translations/view'; +@use '../templates/Pages/Login/login'; +@use '../templates/Pages/Dashboard/dashboard'; +@use '../templates/Pages/Admin/admin'; +@use '../templates/Pages/Import/import'; +@use '../templates/Pages/Modules/modules-index'; +@use '../templates/Pages/Modules/modules-view'; +@use '../templates/Pages/Model/model-index'; +@use '../templates/Pages/Model/model-view'; +@use '../templates/Pages/Translations/view'; -@import './styles/non-production'; +@use 'styles/non-production'; + +// Google Fonts +@import 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,200;0,400;1,200;1,400&family=IBM+Plex+Sans:ital,wght@0,200;0,300;0,400;0,500;1,200;1,300;1,400;1,500&family=IBM+Plex+Serif:ital,wght@0,200;0,400;0,700;1,200;1,400;1,700&display=swap'; // vue [v-cloak] { @@ -84,7 +83,7 @@ BEdita Manager border-top-color: transparent; content: ""; display: block; - height: $gutter * 2; - width: $gutter * 2; + height: variables.$gutter * 2; + width: variables.$gutter * 2; } } diff --git a/resources/styles/_base.scss b/resources/styles/_base.scss index e8c01848c..165b04bec 100644 --- a/resources/styles/_base.scss +++ b/resources/styles/_base.scss @@ -1,16 +1,18 @@ +@use "variables"; + // base body { overflow-x: hidden; - font-family: $font-family-base; - font-size: $font-size-sm; - line-height: $line-height-base; - background-color: $defaultBackground; + font-family: variables.$font-family-base; + font-size: variables.$font-size-sm; + line-height: variables.$line-height-base; + background-color: variables.$defaultBackground; // background-image: linear-gradient(160deg, $gray-900 0%, $gray-800 100%); background-attachment: fixed; background-repeat: no-repeat; - color: $white; - font-weight: $font-weight-base; + color: variables.$white; + font-weight: variables.$font-weight-base; text-align: left; // explicit initial text-align value so that we can later use `inherit` } @@ -18,11 +20,11 @@ body { *::before, *::after { box-sizing: border-box; } -h1 { margin-bottom: $gutter; } +h1 { margin-bottom: variables.$gutter; } h1, h2, h3 { margin-top: 0; line-height: 1.125em; - font-weight: $font-weight-base; + font-weight: variables.$font-weight-base; } p { margin: 0; } @@ -34,7 +36,7 @@ a:link, a:hover, a:active, a:visited { } b, strong { - font-weight: $font-weight-bold; + font-weight: variables.$font-weight-bold; } figure { margin: 0; } @@ -54,10 +56,10 @@ dl { margin: 0; dd { margin: 0; - font-weight: $font-weight-bold; + font-weight: variables.$font-weight-bold; } dd + dt { - margin-top: $gutter * .25; + margin-top: variables.$gutter * .25; } } diff --git a/resources/styles/_buttons.scss b/resources/styles/_buttons.scss index e53ad2b4f..808e394df 100644 --- a/resources/styles/_buttons.scss +++ b/resources/styles/_buttons.scss @@ -1,4 +1,6 @@ -#{$button-inputs}, +@use "variables"; + +#{variables.$button-inputs}, button, .button { display: inline-flex; justify-content: center; @@ -8,10 +10,10 @@ button, .button { vertical-align: top; position: relative; - height: $gutter * 2; - min-width: $gutter * 3; + height: variables.$gutter * 2; + min-width: variables.$gutter * 3; @media screen and (min-width: 1440px) { - min-width: $gutter * 4; + min-width: variables.$gutter * 4; } flex-shrink: 0; box-shadow: none; @@ -25,14 +27,14 @@ button, .button { border-style: solid; // -- overridden by specific utility buttons - background-color: $gray-200; - border-color: $gray-200; - color: $gray-900; + background-color: variables.$gray-200; + border-color: variables.$gray-200; + color: variables.$gray-900; // -- - font-family: $font-family-sans-serif; - font-size: $font-size-sssm; - font-weight: $font-weight-medium; + font-family: variables.$font-family-sans-serif; + font-size: variables.$font-size-sssm; + font-weight: variables.$font-weight-medium; text-transform: uppercase; line-height: 1; @@ -45,22 +47,22 @@ button, .button { // button states &:disabled, &.disabled { - color: $gray-800 !important; - background-color: $gray-600 !important; - border-color: $gray-600 !important; + color: variables.$gray-800 !important; + background-color: variables.$gray-600 !important; + border-color: variables.$gray-600 !important; pointer-events: none; } &:hover { - background-color: $gray-600; + background-color: variables.$gray-600; color: #FFF; outline: 0; } &:focus { outline: 0; - background-color: $gray-600; + background-color: variables.$gray-600; border-color: #fff; color: #FFF; } @@ -72,15 +74,15 @@ button, .button { } &.is-small { - height: $gutter * 1.5; + height: variables.$gutter * 1.5; padding-left: .5em; padding-right: .5em; - font-size: $font-size-sssm; + font-size: variables.$font-size-sssm; } &.is-dark { - background-color: $gray-700; - color: $gray-300; + background-color: variables.$gray-700; + color: variables.$gray-300; } &.is-loading-spinner { @@ -88,7 +90,7 @@ button, .button { pointer-events: none; &:after { position: absolute; - border-color: $gray-900; + border-color: variables.$gray-900; border-right-color: transparent; border-top-color: transparent; } @@ -100,7 +102,7 @@ button, .button { border: none; width: auto; min-width: initial; - color: $white; + color: variables.$white; font-size: 1rem; } } @@ -109,28 +111,28 @@ button, .button { // utility buttons .button { &-primary { - background-color: $white; - border-color: $white; - color: $black; + background-color: variables.$white; + border-color: variables.$white; + color: variables.$black; } &-secondary { - background-color: $gray-300; - border-color: $gray-300; - color: $black; + background-color: variables.$gray-300; + border-color: variables.$gray-300; + color: variables.$black; } &-outlined { background-color: transparent; - border-color: $white; - color: $white; + border-color: variables.$white; + color: variables.$white; &:disabled, &.disabled { } } &-outlined-white { background-color: transparent; - border-color: $black; - color: $black; + border-color: variables.$black; + color: variables.$black; &:hover { - border-color: $gray-600; + border-color: variables.$gray-600; } &:disabled, &.disabled { } @@ -138,14 +140,14 @@ button, .button { &-text { background-color: transparent; border-color: transparent; - color: $black; + color: variables.$black; &:disabled, &.disabled { } } &-text-white { background-color: transparent; border-color: transparent; - color: $white; + color: variables.$white; &:disabled, &.disabled { } } diff --git a/resources/styles/_columns.scss b/resources/styles/_columns.scss index 65db5dfb6..2072c0ca6 100644 --- a/resources/styles/_columns.scss +++ b/resources/styles/_columns.scss @@ -1,10 +1,12 @@ +@use "variables"; + // flex columns .columns { display: block; flex-wrap: wrap; - margin-left: -($gutter * .5); - margin-right: -($gutter * .5); - margin-top: -($gutter * .5); + margin-left: -(variables.$gutter * .5); + margin-right: -(variables.$gutter * .5); + margin-top: -(variables.$gutter * .5); @media screen and (min-width: 420px) { display: flex; } @@ -15,7 +17,7 @@ flex-basis: 0; flex-grow: 1; flex-shrink: 1; - padding: ($gutter * .5); + padding: (variables.$gutter * .5); &.is-1 { flex: none; flex-basis: 100%; diff --git a/resources/styles/_elements.scss b/resources/styles/_elements.scss index 5f5e097cf..eab63161d 100644 --- a/resources/styles/_elements.scss +++ b/resources/styles/_elements.scss @@ -1,3 +1,6 @@ +@use "variables"; +@use "utility_classes"; + // generic full size backdrop .backdrop { display: none; @@ -13,14 +16,14 @@ justify-content: center; align-items: center; height: 2em; - margin-right: $gutter * .25; - margin-bottom: $gutter * .25; + margin-right: variables.$gutter * .25; + margin-bottom: variables.$gutter * .25; padding-left: .75em; padding-right: .75em; - background-color: $gray-600; + background-color: variables.$gray-600; border-radius: 4px; - color: $white; - font-size: $font-size-sssm; + color: variables.$white; + font-size: variables.$font-size-sssm; line-height: 1.5; white-space: nowrap; user-select: none; @@ -34,13 +37,13 @@ } &.is-black { - background-color: $black; - color: $gray-100; + background-color: variables.$black; + color: variables.$gray-100; } &.is-dark { - background-color: $gray-900; - color: $gray-100; + background-color: variables.$gray-900; + color: variables.$gray-100; } &.empty { @@ -56,7 +59,7 @@ &:not(:first-child) { border-bottom-left-radius: 0; border-top-left-radius: 0; - margin-left: $gutter * .25; + margin-left: variables.$gutter * .25; } &:not(:last-child) { border-bottom-right-radius: 0; @@ -73,11 +76,11 @@ justify-content: center; align-items: center; line-height: 0; - background-color: $white; + background-color: variables.$white; border-radius: 50%; - padding: $gutter * .75; - font-size: $font-size-sssm; - font-weight: $font-weight-black; + padding: variables.$gutter * .75; + font-size: variables.$font-size-sssm; + font-weight: variables.$font-weight-black; box-shadow: 0 0 2px #000; &:after { content: ''; @@ -92,8 +95,8 @@ position: relative; display: flex; flex-direction: column; - background-color: $white; - color: $black; + background-color: variables.$white; + color: variables.$black; box-shadow: 0 2px 3px rgba(10,10,10,.1), 0 0 0 1px rgba(10,10,10,.1); .box-body { flex-grow: 1; @@ -108,11 +111,11 @@ nav.pagination { white-space: nowrap; > div { &:not(:first-child) { - margin-left: $gutter; + margin-left: variables.$gutter; } &.page-size { - select { margin-left : $gutter * .5; } + select { margin-left : variables.$gutter * .5; } } &.pagination-buttons { @@ -122,7 +125,7 @@ nav.pagination { button { min-width: 2.5em; border-radius: 4px; - margin-left: $gutter * .5; + margin-left: variables.$gutter * .5; &:first-of-type { margin-left: 0; } &.current-page { @@ -140,8 +143,8 @@ nav.pagination { &:after { content: '…'; } - margin-left: $gutter * .5; - font-size: $font-size-llg; + margin-left: variables.$gutter * .5; + font-size: variables.$font-size-llg; } } } @@ -154,13 +157,13 @@ nav.pagination { position: relative; top: 2px; left: 8px; - background-color: $black; + background-color: variables.$black; border-radius: 50%; - width: $gutter; + width: variables.$gutter; text-align: center; - height: $gutter; - font-size: $font-size-sssm; - line-height: $gutter; + height: variables.$gutter; + font-size: variables.$font-size-sssm; + line-height: variables.$gutter; overflow: hidden; &.empty { opacity: .3; @@ -213,7 +216,7 @@ nav.pagination { flex-shrink: 0; justify-content: flex-start; align-items: center; - border-bottom-color: $gray-700; + border-bottom-color: variables.$gray-700; border-bottom-style: solid; border-bottom-width: 1px; } @@ -227,27 +230,27 @@ nav.pagination { vertical-align: top; margin-bottom: -1px; padding: .5em 1em; - border-bottom-color: $gray-700; + border-bottom-color: variables.$gray-700; border-bottom-style: solid; border-bottom-width: 1px; - color: $gray-500; + color: variables.$gray-500; } &.is-active a { - border-bottom-color: $gray-100; - color: $gray-100; + border-bottom-color: variables.$gray-100; + color: variables.$gray-100; } } } .h-tabs ~ .h-tabs-contents { - margin-top: $gutter * 1.5; + margin-top: variables.$gutter * 1.5; } .hr { - background-color: $gray-700; + background-color: variables.$gray-700; border: none; display: block; height: 1px; @@ -264,17 +267,17 @@ nav.pagination { .drop-area { position: relative; width: 100%; - min-height: $gutter * 5; + min-height: variables.$gutter * 5; background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='white' stroke-width='3' stroke-dasharray='6' stroke-dashoffset='29' stroke-linecap='butt'/%3e%3c/svg%3e"); &.dragover { color: #fff; - background-color: $black; + background-color: variables.$black; font-size: 1.5em; } .upload-placeholder { - color: $gray-550; + color: variables.$gray-550; margin: auto; } @@ -289,7 +292,7 @@ nav.pagination { .upload-item { width: 100%; & ~ .upload-item { - margin-top: $gutter; + margin-top: variables.$gutter; } .upload-item-header { @@ -301,7 +304,7 @@ nav.pagination { word-break: break-word; } button { - margin-left: $gutter * .5; + margin-left: variables.$gutter * .5; } } @@ -312,30 +315,30 @@ nav.pagination { .progress-bar { width: 100%; - margin: $gutter * .75 0 $gutter * .75; + margin: variables.$gutter * .75 0 variables.$gutter * .75; .progress-bar-status { - min-width: $gutter; + min-width: variables.$gutter; height: 2px; } .progress-bar-status.in-progress { - background-color: $gray-400; + background-color: variables.$gray-400; } .progress-bar-status.done { - background-color: $info; + background-color: variables.$info; } .progress-bar-status.error { - background-color: $error; + background-color: variables.$error; } .progress-bar-status.cancelled { - background-color: $gray-700; + background-color: variables.$gray-700; } } } } } .drop-area-double { - min-height: $gutter * 16; + min-height: variables.$gutter * 16; } .module-items-counter { diff --git a/resources/styles/_forms.scss b/resources/styles/_forms.scss index 9a1eb2fce..572e2ec8c 100644 --- a/resources/styles/_forms.scss +++ b/resources/styles/_forms.scss @@ -1,28 +1,30 @@ +@use "variables"; + /* buttons, and inputs are defined in mixins.scss */ .inverted { - background: $gray-900; - color: $white; + background: variables.$gray-900; + color: variables.$white; &:hover { - background: $white !important; - color: $gray-900 !important; + background: variables.$white !important; + color: variables.$gray-900 !important; } } -#{$text-inputs} { +#{variables.$text-inputs} { padding: 0 .5em; min-width: 4rem; - height: $gutter * 2; + height: variables.$gutter * 2; border: none; border-radius: 2px; - background-color: $gray-100; - font-family: $font-family-sans-serif; - font-size: $font-size-ssm; + background-color: variables.$gray-100; + font-family: variables.$font-family-sans-serif; + font-size: variables.$font-size-ssm; line-height: 1.5em; &:focus { outline: none; - box-shadow: inset 0 0 2px $black; + box-shadow: inset 0 0 2px variables.$black; } } @@ -31,26 +33,26 @@ textarea { min-width: 5rem; border-radius: 2px; border: none; - font-family: $font-family-sans-serif; + font-family: variables.$font-family-sans-serif; } select { - height: $gutter * 2; + height: variables.$gutter * 2; border-radius: 2px; border: none; - font-family: $font-family-sans-serif; + font-family: variables.$font-family-sans-serif; } label { &:not(:empty) { - margin-right: $gutter; + margin-right: variables.$gutter; } > input { - margin-right: $gutter * .5; + margin-right: variables.$gutter * .5; } > input[type="radio"], > input[type="checkbox"] { - margin-right: $gutter * .5; + margin-right: variables.$gutter * .5; } &.disabled { pointer-events: none; @@ -104,12 +106,12 @@ form { align-items: center; width: 18px; height: 18px; - color: $gray-550; + color: variables.$gray-550; font-size: 24px; cursor: pointer; &:hover { - color: $gray-900; + color: variables.$gray-900; } } } @@ -129,7 +131,7 @@ form { width: auto !important; height: auto !important; max-width: 15rem; - min-height: $gutter * 2; + min-height: variables.$gutter * 2; padding: 0 .5em !important; color: #000 !important; border-radius: 2px !important; @@ -208,22 +210,22 @@ form { .vue-treeselect--open-below .vue-treeselect__menu { margin-top: -2px !important; - border-top: 1px solid $gray-200 !important; + border-top: 1px solid variables.$gray-200 !important; border-bottom-left-radius: 2px !important; border-bottom-right-radius: 2px !important; } .vue-treeselect--open-above .vue-treeselect__menu { margin-bottom: -2px !important; - border-bottom: 1px solid $gray-200 !important; + border-bottom: 1px solid variables.$gray-200 !important; border-top-left-radius: 2px !important; border-top-right-radius: 2px !important; } .vue-treeselect__checkbox { - border-color: $gray-600 !important; + border-color: variables.$gray-600 !important; } .vue-treeselect__checkbox--checked { - background-color: $gray-600 !important; + background-color: variables.$gray-600 !important; } diff --git a/resources/styles/_forms_file.scss b/resources/styles/_forms_file.scss index 1e524b8ee..dd9399d86 100644 --- a/resources/styles/_forms_file.scss +++ b/resources/styles/_forms_file.scss @@ -1,10 +1,13 @@ -$file-border-color: $gray-600; +@use "sass:color"; +@use "variables"; + +$file-border-color: variables.$gray-600; $file-radius: 2px; -$file-cta-background-color: $gray-100; -$file-cta-color: $gray-600; -$file-cta-hover-color: $black; -$file-cta-active-color: $black; -$file-name-border-color: $gray-600; +$file-cta-background-color: variables.$gray-100; +$file-cta-color: variables.$gray-600; +$file-cta-hover-color: variables.$black; +$file-cta-active-color: variables.$black; +$file-name-border-color: variables.$gray-600; $file-name-border-style: solid; $file-name-border-width: 1px 1px 1px 0; $file-name-max-width: 24em; @@ -47,21 +50,21 @@ $file-name-max-width: 24em; &:hover { .file-cta { - background-color: darken($file-cta-background-color, 2.5%); + background-color: color.adjust($file-cta-background-color, $lightness: -2.5%); color: $file-cta-hover-color; } .file-name { - border-color: darken($file-name-border-color, 2.5%); + border-color: color.adjust($file-name-border-color, $lightness: -2.5%); } } &:active { .file-cta { - background-color: darken($file-cta-background-color, 5%); + background-color: color.adjust($file-cta-background-color, $lightness: -5%); color: $file-cta-active-color; } .file-name { - border-color: darken($file-name-border-color, 5%); + border-color: color.adjust($file-name-border-color, $lightness: -5%); } } } @@ -83,10 +86,10 @@ $file-name-max-width: 24em; position: relative; padding-left: 1em; padding-right: 1em; - height: $gutter * 2; + height: variables.$gutter * 2; border-color: $file-border-color; border-radius: $file-radius; - font-size: $font-size-sm; + font-size: variables.$font-size-sm; text-align: left; white-space: nowrap; } @@ -113,8 +116,8 @@ $file-name-max-width: 24em; &:before { content: "-"; content: attr(data-empty-label); - font-size: $font-size-sssm; - color: $gray-600; + font-size: variables.$font-size-sssm; + color: variables.$gray-600; } } } @@ -139,9 +142,9 @@ $file-name-max-width: 24em; display: inline-block; flex-grow: 0; flex-shrink: 0; - width: $gutter * 2; - height: $gutter * 2; - margin-left: $gutter * .25; + width: variables.$gutter * 2; + height: variables.$gutter * 2; + margin-left: variables.$gutter * .25; font-size: 0; outline: 0; @@ -151,7 +154,7 @@ $file-name-max-width: 24em; &:after, &:before { content: ""; display: block; - background-color: $gray-300; + background-color: variables.$gray-300; position: absolute; left: 50%; top: 50%; diff --git a/resources/styles/_layout.scss b/resources/styles/_layout.scss index b5b6f8100..f89502134 100644 --- a/resources/styles/_layout.scss +++ b/resources/styles/_layout.scss @@ -1,18 +1,20 @@ +@use "variables"; + // main grids main.layout { position: relative; width: 100%; min-height: 100vh; min-height: calc(var(--vh, 1vh) * 100); // iOS adjust with script and fallback - padding: 0 $gutter; + padding: 0 variables.$gutter; @media (min-width: 568px) { display: grid; - grid-gap: 0 $gutter; + grid-gap: 0 variables.$gutter; grid-template-areas: "sidebar content-header" "sidebar content-body" "sidebar footer"; - grid-template-columns: $dashboard-item-width auto; + grid-template-columns: variables.$dashboard-item-width auto; .view-dashboard & { grid-template-rows: auto 1fr auto; @@ -22,7 +24,7 @@ main.layout { } @media (min-width: 1024px) { - grid-template-rows: ($dashboard-item-height + $gutter) auto; + grid-template-rows: (variables.$dashboard-item-height + variables.$gutter) auto; } > .layout-sidebar { grid-area: sidebar; } @@ -36,7 +38,7 @@ main.layout { > .layout-sidebar, > .layout-footer { max-width: 100%; overflow-x: hidden; } > .layout-content { max-width: 100%; overflow-x: hidden; } > .layout-header + .layout-content { - margin-top: $gutter; + margin-top: variables.$gutter; @media screen and (min-width: 1024px) { margin-top: 0; @@ -47,7 +49,7 @@ main.layout { // on panel show / hide -body:not(.view-login) main.layout > .layout-content { background-color: $defaultBackground; } // covers sidebar on translate +body:not(.view-login) main.layout > .layout-content { background-color: variables.$defaultBackground; } // covers sidebar on translate main.layout { > .layout-header, > .layout-content { @@ -60,7 +62,7 @@ main.layout { .panel-is-open & { > .layout-header, > .layout-content { - transform: translateX(-$dashboard-item-width - $gutter); + transform: translateX(-(variables.$dashboard-item-width) - variables.$gutter); } > .layout-sidebar { opacity: 0; diff --git a/resources/styles/_non-production.scss b/resources/styles/_non-production.scss index 375536f24..b48cd5f9a 100644 --- a/resources/styles/_non-production.scss +++ b/resources/styles/_non-production.scss @@ -1,3 +1,5 @@ +@use "variables"; + // non production environemnt .cake-error { position: relative; @@ -9,7 +11,7 @@ white-space: pre-wrap; word-wrap: break-word; background: #000; - color: $gray-300; + color: variables.$gray-300; font-size: 12px; a { diff --git a/resources/styles/_utility_classes.scss b/resources/styles/_utility_classes.scss index dd54f5642..1bae20430 100644 --- a/resources/styles/_utility_classes.scss +++ b/resources/styles/_utility_classes.scss @@ -1,3 +1,6 @@ +@use "mixins"; +@use "variables"; + // utility classes .full-size-absolute { position: absolute; top: 0; left: 0; width: 100%; height: 100%; margin: 0 !important; } @@ -8,7 +11,7 @@ .cursor-pointer { cursor: pointer; } -.is-text-hidden { @include hide-text(); } +.is-text-hidden { @include mixins.hide-text(); } .is-block { display: block;} @@ -20,17 +23,17 @@ // typography -.has-text-size-base { font-size: $font-size-base; } // 16px -.has-text-size-large { font-size: $font-size-lg; } // 18px -.has-text-size-larger { font-size: $font-size-llg; } // 20px -.has-text-size-largest { font-size: $font-size-lllg; } // 24px -.has-text-size-small { font-size: $font-size-sm; } // 14px -.has-text-size-smaller { font-size: $font-size-ssm; } // 13px -.has-text-size-smallest { font-size: $font-size-sssm; } // 12px - -.has-font-weight-light { font-weight: $font-weight-light; } -.has-font-weight-normal { font-weight: $font-weight-normal; } -.has-font-weight-bold { font-weight: $font-weight-bold; } +.has-text-size-base { font-size: variables.$font-size-base; } // 16px +.has-text-size-large { font-size: variables.$font-size-lg; } // 18px +.has-text-size-larger { font-size: variables.$font-size-llg; } // 20px +.has-text-size-largest { font-size: variables.$font-size-lllg; } // 24px +.has-text-size-small { font-size: variables.$font-size-sm; } // 14px +.has-text-size-smaller { font-size: variables.$font-size-ssm; } // 13px +.has-text-size-smallest { font-size: variables.$font-size-sssm; } // 12px + +.has-font-weight-light { font-weight: variables.$font-weight-light; } +.has-font-weight-normal { font-weight: variables.$font-weight-normal; } +.has-font-weight-bold { font-weight: variables.$font-weight-bold; } .has-text-transform-upper { text-transform: uppercase; } .has-text-transform-lower { text-transform: lowercase; } @@ -45,111 +48,111 @@ // colors .has-background-transparent { background-color: transparent !important; } -.has-background-white { background-color: $white !important; } -.has-background-black { background-color: $black !important; } -.has-background-gray-100 { background-color: $gray-100 !important; } -.has-background-gray-200 { background-color: $gray-200 !important; } -.has-background-gray-300 { background-color: $gray-300 !important; } -.has-background-gray-400 { background-color: $gray-400 !important; } -.has-background-gray-500 { background-color: $gray-500 !important; } -.has-background-gray-550 { background-color: $gray-550 !important; } -.has-background-gray-600 { background-color: $gray-600 !important; } -.has-background-gray-700 { background-color: $gray-700 !important; } -.has-background-gray-800 { background-color: $gray-800 !important; } -.has-background-gray-900 { background-color: $gray-900 !important; } -.has-background-gray-950 { background-color: $gray-950 !important; } -.has-background-danger { background-color: $danger !important; } -.has-background-light-danger { background-color: $light-danger !important; } -.has-background-info { background-color: $info !important; } +.has-background-white { background-color: variables.$white !important; } +.has-background-black { background-color: variables.$black !important; } +.has-background-gray-100 { background-color: variables.$gray-100 !important; } +.has-background-gray-200 { background-color: variables.$gray-200 !important; } +.has-background-gray-300 { background-color: variables.$gray-300 !important; } +.has-background-gray-400 { background-color: variables.$gray-400 !important; } +.has-background-gray-500 { background-color: variables.$gray-500 !important; } +.has-background-gray-550 { background-color: variables.$gray-550 !important; } +.has-background-gray-600 { background-color: variables.$gray-600 !important; } +.has-background-gray-700 { background-color: variables.$gray-700 !important; } +.has-background-gray-800 { background-color: variables.$gray-800 !important; } +.has-background-gray-900 { background-color: variables.$gray-900 !important; } +.has-background-gray-950 { background-color: variables.$gray-950 !important; } +.has-background-danger { background-color: variables.$danger !important; } +.has-background-light-danger { background-color: variables.$light-danger !important; } +.has-background-info { background-color: variables.$info !important; } .has-text-transparent { color: transparent !important; } -.has-text-white { color: $white !important; } -.has-text-black { color: $black !important; } -.has-text-gray-100 { color: $gray-100 !important; } -.has-text-gray-200 { color: $gray-200 !important; } -.has-text-gray-300 { color: $gray-300 !important; } -.has-text-gray-400 { color: $gray-400 !important; } -.has-text-gray-500 { color: $gray-500 !important; } -.has-text-gray-550 { color: $gray-550 !important; } -.has-text-gray-600 { color: $gray-600 !important; } -.has-text-gray-700 { color: $gray-700 !important; } -.has-text-gray-800 { color: $gray-800 !important; } -.has-text-gray-900 { color: $gray-900 !important; } -.has-text-danger { color: $danger !important; } -.has-text-info { color: $info !important; } +.has-text-white { color: variables.$white !important; } +.has-text-black { color: variables.$black !important; } +.has-text-gray-100 { color: variables.$gray-100 !important; } +.has-text-gray-200 { color: variables.$gray-200 !important; } +.has-text-gray-300 { color: variables.$gray-300 !important; } +.has-text-gray-400 { color: variables.$gray-400 !important; } +.has-text-gray-500 { color: variables.$gray-500 !important; } +.has-text-gray-550 { color: variables.$gray-550 !important; } +.has-text-gray-600 { color: variables.$gray-600 !important; } +.has-text-gray-700 { color: variables.$gray-700 !important; } +.has-text-gray-800 { color: variables.$gray-800 !important; } +.has-text-gray-900 { color: variables.$gray-900 !important; } +.has-text-danger { color: variables.$danger !important; } +.has-text-info { color: variables.$info !important; } .has-border-transparent { border-color: transparent !important; } -.has-border-white { border-color: $white !important; } -.has-border-black { border-color: $black !important; } -.has-border-gray-100 { border-color: $gray-100 !important; } -.has-border-gray-200 { border-color: $gray-200 !important; } -.has-border-gray-300 { border-color: $gray-300 !important; } -.has-border-gray-400 { border-color: $gray-400 !important; } -.has-border-gray-500 { border-color: $gray-500 !important; } -.has-border-gray-550 { border-color: $gray-550 !important; } -.has-border-gray-600 { border-color: $gray-600 !important; } -.has-border-gray-700 { border-color: $gray-700 !important; } -.has-border-gray-800 { border-color: $gray-800 !important; } -.has-border-gray-900 { border-color: $gray-900 !important; } -.has-border-danger { border-color: $danger !important; } -.has-border-info { border-color: $info !important; } +.has-border-white { border-color: variables.$white !important; } +.has-border-black { border-color: variables.$black !important; } +.has-border-gray-100 { border-color: variables.$gray-100 !important; } +.has-border-gray-200 { border-color: variables.$gray-200 !important; } +.has-border-gray-300 { border-color: variables.$gray-300 !important; } +.has-border-gray-400 { border-color: variables.$gray-400 !important; } +.has-border-gray-500 { border-color: variables.$gray-500 !important; } +.has-border-gray-550 { border-color: variables.$gray-550 !important; } +.has-border-gray-600 { border-color: variables.$gray-600 !important; } +.has-border-gray-700 { border-color: variables.$gray-700 !important; } +.has-border-gray-800 { border-color: variables.$gray-800 !important; } +.has-border-gray-900 { border-color: variables.$gray-900 !important; } +.has-border-danger { border-color: variables.$danger !important; } +.has-border-info { border-color: variables.$info !important; } .has-border-none { border: none !important; } // spacing .m-0 { margin: 0 !important; } -.m-1 { margin: $gutter !important; } +.m-1 { margin: variables.$gutter !important; } -.mx-025 { margin-left: $gutter * .25; margin-right: $gutter * .25; } -.mx-05 { margin-left: $gutter * .5; margin-right: $gutter * .5; } -.mx-1 { margin-left: $gutter; margin-right: $gutter; } -.mx-2 { margin-left: $gutter * 2; margin-right: $gutter * 2; } -.my-025 { margin-top: $gutter * .25; margin-bottom: $gutter * .25; } -.my-05 { margin-top: $gutter * .5; margin-bottom: $gutter * .5; } -.my-1 { margin-top: $gutter; margin-bottom: $gutter; } -.my-2 { margin-top: $gutter * 2; margin-bottom: $gutter * 2; } +.mx-025 { margin-left: variables.$gutter * .25; margin-right: variables.$gutter * .25; } +.mx-05 { margin-left: variables.$gutter * .5; margin-right: variables.$gutter * .5; } +.mx-1 { margin-left: variables.$gutter; margin-right: variables.$gutter; } +.mx-2 { margin-left: variables.$gutter * 2; margin-right: variables.$gutter * 2; } +.my-025 { margin-top: variables.$gutter * .25; margin-bottom: variables.$gutter * .25; } +.my-05 { margin-top: variables.$gutter * .5; margin-bottom: variables.$gutter * .5; } +.my-1 { margin-top: variables.$gutter; margin-bottom: variables.$gutter; } +.my-2 { margin-top: variables.$gutter * 2; margin-bottom: variables.$gutter * 2; } .mt-0 { margin-top: 0 !important; } -.mt-025 { margin-top: $gutter * .25; } -.mt-05 { margin-top: $gutter * .5; } -.mt-075 { margin-top: $gutter * .75; } -.mt-1 { margin-top: $gutter; } -.mt-15 { margin-top: $gutter * 1.5; } -.mt-2 { margin-top: $gutter * 2; } -.mt-25 { margin-top: $gutter * 2.5; } - -.mr-05 { margin-right: $gutter * .5; } -.mr-1 { margin-right: $gutter; } -.mr-2 { margin-right: $gutter * 2; } -.ml-05 { margin-left: $gutter * .5; } -.ml-1 { margin-left: $gutter; } -.ml-2 { margin-left: $gutter * 2; } +.mt-025 { margin-top: variables.$gutter * .25; } +.mt-05 { margin-top: variables.$gutter * .5; } +.mt-075 { margin-top: variables.$gutter * .75; } +.mt-1 { margin-top: variables.$gutter; } +.mt-15 { margin-top: variables.$gutter * 1.5; } +.mt-2 { margin-top: variables.$gutter * 2; } +.mt-25 { margin-top: variables.$gutter * 2.5; } + +.mr-05 { margin-right: variables.$gutter * .5; } +.mr-1 { margin-right: variables.$gutter; } +.mr-2 { margin-right: variables.$gutter * 2; } +.ml-05 { margin-left: variables.$gutter * .5; } +.ml-1 { margin-left: variables.$gutter; } +.ml-2 { margin-left: variables.$gutter * 2; } .mb-0 { margin-bottom: 0 !important; } -.mb-05 { margin-bottom: $gutter * .5; } -.mb-1 { margin-bottom: $gutter; } -.mb-15 { margin-bottom: $gutter * 1.5; } -.mb-2 { margin-bottom: $gutter * 2; } -.mb-25 { margin-bottom: $gutter * 2.5; } - -.p-025 { padding: $gutter * .25; } -.p-05 { padding: $gutter * .5; } -.p-1 { padding: $gutter; } -.px-05 { padding-left: $gutter * .5; padding-right: $gutter * .5; } -.px-1 { padding-left: $gutter; padding-right: $gutter; } -.px-2 { padding-left: $gutter * 2; padding-right: $gutter * 2; } -.py-05 { padding-top: $gutter * .5; padding-bottom: $gutter * .5; } -.py-1 { padding-top: $gutter; padding-bottom: $gutter; } -.py-2 { padding-top: $gutter * 2; padding-bottom: $gutter * 2; } - -.pt-05 { padding-top: $gutter * .5; } -.pt-1 { padding-top: $gutter; } -.pt-2 { padding-top: $gutter * 2; } -.pt-25 { padding-top: $gutter * 2.5; } -.pb-05 { padding-bottom: $gutter * .5; } -.pb-1 { padding-bottom: $gutter; } -.pb-2 { padding-bottom: $gutter * 2; } -.pb-25 { padding-bottom: $gutter * 2.5; } +.mb-05 { margin-bottom: variables.$gutter * .5; } +.mb-1 { margin-bottom: variables.$gutter; } +.mb-15 { margin-bottom: variables.$gutter * 1.5; } +.mb-2 { margin-bottom: variables.$gutter * 2; } +.mb-25 { margin-bottom: variables.$gutter * 2.5; } + +.p-025 { padding: variables.$gutter * .25; } +.p-05 { padding: variables.$gutter * .5; } +.p-1 { padding: variables.$gutter; } +.px-05 { padding-left: variables.$gutter * .5; padding-right: variables.$gutter * .5; } +.px-1 { padding-left: variables.$gutter; padding-right: variables.$gutter; } +.px-2 { padding-left: variables.$gutter * 2; padding-right: variables.$gutter * 2; } +.py-05 { padding-top: variables.$gutter * .5; padding-bottom: variables.$gutter * .5; } +.py-1 { padding-top: variables.$gutter; padding-bottom: variables.$gutter; } +.py-2 { padding-top: variables.$gutter * 2; padding-bottom: variables.$gutter * 2; } + +.pt-05 { padding-top: variables.$gutter * .5; } +.pt-1 { padding-top: variables.$gutter; } +.pt-2 { padding-top: variables.$gutter * 2; } +.pt-25 { padding-top: variables.$gutter * 2.5; } +.pb-05 { padding-bottom: variables.$gutter * .5; } +.pb-1 { padding-bottom: variables.$gutter; } +.pb-2 { padding-bottom: variables.$gutter * 2; } +.pb-25 { padding-bottom: variables.$gutter * 2.5; } // fixed height and width .hw-30 { height: 30px; width: 30px; } @@ -240,8 +243,8 @@ table.inside-bordered { border-collapse: collapse; th, td { - border: 1px solid $gray-600; - padding: $gutter * 0.5; + border: 1px solid variables.$gray-600; + padding: variables.$gutter * 0.5; } } diff --git a/resources/styles/_variables.scss b/resources/styles/_variables.scss index b2e510356..cf29d971c 100644 --- a/resources/styles/_variables.scss +++ b/resources/styles/_variables.scss @@ -1,3 +1,4 @@ +@use "sass:map"; /* ** FONTS & TYPOGRAPHY */ @@ -53,7 +54,7 @@ $gray-strange: #3E4143 !default; $black: #000 !default; $grays: () !default; -$grays: map-merge(( +$grays: map.merge(( "100": $gray-100, "200": $gray-200, "300": $gray-300, diff --git a/src/Application.php b/src/Application.php index b536e2994..ec861cf49 100644 --- a/src/Application.php +++ b/src/Application.php @@ -21,7 +21,8 @@ use Authentication\AuthenticationService; use Authentication\AuthenticationServiceInterface; use Authentication\AuthenticationServiceProviderInterface; -use Authentication\Identifier\IdentifierInterface; +use Authentication\Identifier\AbstractIdentifier; +use Authentication\Identifier\TokenIdentifier; use Authentication\Middleware\AuthenticationMiddleware; use BEdita\I18n\Middleware\I18nMiddleware; use BEdita\WebTools\Middleware\OAuth2Middleware; @@ -107,8 +108,10 @@ public function loadPluginsFromConfig(): void foreach ($plugins as $plugin => $options) { $options = array_merge(static::PLUGIN_DEFAULTS, $options); if (!$options['debugOnly'] || Configure::read('debug')) { - $this->addPlugin($plugin, $options); - $this->plugins->get($plugin)->bootstrap($this); + if (!$this->getPlugins()->has($plugin)) { + $this->addPlugin($plugin, $options); + $this->plugins->get($plugin)->bootstrap($this); + } } } } @@ -221,8 +224,13 @@ public function getAuthenticationService(ServerRequestInterface $request): Authe $query = $request->getQueryParams(); if (strpos($path, '/ext/login') === 0) { $providers = (array)Configure::read('OAuth2Providers'); - $service->loadIdentifier('BEdita/WebTools.OAuth2', compact('providers')); - $service->loadAuthenticator('BEdita/WebTools.OAuth2', compact('providers') + [ + $service->loadAuthenticator('BEdita/WebTools.OAuth2', [ + 'identifier' => [ + 'BEdita/WebTools.OAuth2' => [ + 'providers' => $providers, + ], + ], + 'providers' => $providers, 'redirect' => ['_name' => 'login:oauth2'], ]); @@ -232,22 +240,23 @@ public function getAuthenticationService(ServerRequestInterface $request): Authe } $service->loadAuthenticator('Authentication.Session', [ + 'identifier' => [ + ApiIdentifier::class => [ + 'timezoneField' => 'timezone', + ], + ], 'sessionKey' => 'BEditaManagerAuth', 'fields' => [ - IdentifierInterface::CREDENTIAL_TOKEN => 'token', + TokenIdentifier::CREDENTIAL_TOKEN => 'token', ], ]); - $service->loadIdentifier(ApiIdentifier::class, [ - 'timezoneField' => 'timezone', - ]); - if ($path === '/login') { $service->loadAuthenticator('Authentication.Form', [ 'loginUrl' => '/login', 'fields' => [ - IdentifierInterface::CREDENTIAL_USERNAME => 'username', - IdentifierInterface::CREDENTIAL_PASSWORD => 'password', + AbstractIdentifier::CREDENTIAL_USERNAME => 'username', + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password', 'timezone' => 'timezone_offset', ], ]); diff --git a/src/Console/Installer.php b/src/Console/Installer.php index e2b7762f0..da5c97c49 100644 --- a/src/Console/Installer.php +++ b/src/Console/Installer.php @@ -21,6 +21,7 @@ } use Cake\Utility\Security; +use Composer\IO\IOInterface; use Composer\Script\Event; use Exception; @@ -72,7 +73,7 @@ public static function postInstall(Event $event): void * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function createAppLocalConfig($dir, $io): void + public static function createAppLocalConfig(string $dir, IOInterface $io): void { $appLocalConfig = $dir . '/config/app_local.php'; $appLocalConfigTemplate = $dir . '/config/app_local.example.php'; @@ -89,7 +90,7 @@ public static function createAppLocalConfig($dir, $io): void * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function createDotEnvConfig($dir, $io): void + public static function createDotEnvConfig(string $dir, IOInterface $io): void { $appConfig = $dir . '/config/.env'; $defaultConfig = $dir . '/config/.env.example'; @@ -106,7 +107,7 @@ public static function createDotEnvConfig($dir, $io): void * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function createWritableDirectories($dir, $io): void + public static function createWritableDirectories(string $dir, IOInterface $io): void { foreach (static::WRITABLE_DIRS as $path) { $path = $dir . '/' . $path; @@ -126,7 +127,7 @@ public static function createWritableDirectories($dir, $io): void * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function setFolderPermissions($dir, $io): void + public static function setFolderPermissions(string $dir, IOInterface $io): void { // ask if the permissions should be changed if ($io->isInteractive()) { @@ -140,7 +141,7 @@ public static function setFolderPermissions($dir, $io): void 'Set Folder Permissions ? (Default to Y) [Y,n]? ', $validator, 10, - 'Y' + 'Y', ); if (in_array($setFolderPermissions, ['n', 'N'])) { @@ -149,7 +150,7 @@ public static function setFolderPermissions($dir, $io): void } // Change the permissions on a path and output the results. - $changePerms = function ($path) use ($io) { + $changePerms = function ($path) use ($io): void { $currentPerms = fileperms($path) & 0777; $worldWritable = $currentPerms | 0007; if ($worldWritable == $currentPerms) { @@ -164,7 +165,7 @@ public static function setFolderPermissions($dir, $io): void } }; - $walker = function ($dir) use (&$walker, $changePerms) { + $walker = function ($dir) use (&$walker, $changePerms): void { $files = array_diff(scandir($dir), ['.', '..']); foreach ($files as $file) { $path = $dir . '/' . $file; @@ -190,7 +191,7 @@ public static function setFolderPermissions($dir, $io): void * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function setSecuritySalt($dir, $io): void + public static function setSecuritySalt(string $dir, IOInterface $io): void { $newKey = hash('sha256', Security::randomBytes(64)); static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php'); @@ -205,7 +206,7 @@ public static function setSecuritySalt($dir, $io): void * @param string $file A path to a file relative to the application's root * @return void */ - public static function setSecuritySaltInFile($dir, $io, $newKey, $file): void + public static function setSecuritySaltInFile(string $dir, IOInterface $io, string $newKey, string $file): void { $config = $dir . '/config/' . $file; $content = file_get_contents($config); @@ -236,7 +237,7 @@ public static function setSecuritySaltInFile($dir, $io, $newKey, $file): void * @param string $file A path to a file relative to the application's root * @return void */ - public static function setAppNameInFile($dir, $io, $appName, $file): void + public static function setAppNameInFile(string $dir, IOInterface $io, string $appName, string $file): void { $config = $dir . '/config/' . $file; $content = file_get_contents($config); diff --git a/src/Controller/Admin/AdministrationBaseController.php b/src/Controller/Admin/AdministrationBaseController.php index fb835c4e6..2b7460c26 100644 --- a/src/Controller/Admin/AdministrationBaseController.php +++ b/src/Controller/Admin/AdministrationBaseController.php @@ -30,63 +30,63 @@ abstract class AdministrationBaseController extends AppController * * @var string */ - protected $endpoint = '/admin'; + protected string $endpoint = '/admin'; /** * Resource type in use * - * @var string + * @var string|null */ - protected $resourceType = null; + protected ?string $resourceType = null; /** * Readonly flag view. * * @var bool */ - protected $readonly = true; + protected bool $readonly = true; /** * Deleteonly flag view. * * @var bool */ - protected $deleteonly = false; + protected bool $deleteonly = false; /** * Properties to show in index columns * * @var array */ - protected $properties = []; + protected array $properties = []; /** * Properties to json decode before save * * @var array */ - protected $propertiesForceJson = []; + protected array $propertiesForceJson = []; /** * Properties that are secrets * * @var array */ - protected $propertiesSecrets = []; + protected array $propertiesSecrets = []; /** * Meta to show in index columns * * @var array */ - protected $meta = ['created', 'modified']; + protected array $meta = ['created', 'modified']; /** * Sort field * - * @var string + * @var string|null */ - protected $sortBy = null; + protected ?string $sortBy = null; /** * @inheritDoc @@ -94,7 +94,6 @@ abstract class AdministrationBaseController extends AppController public function initialize(): void { parent::initialize(); - $this->loadComponent('Properties'); } @@ -221,7 +220,6 @@ protected function endpoint(): string */ protected function loadData(): array { - $query = $this->getRequest()->getQueryParams(); $resourceEndpoint = sprintf('%s/%s', $this->endpoint, $this->resourceType); $endpoint = $this->resourceType === 'roles' ? 'roles' : $resourceEndpoint; $resultResponse = ['data' => []]; @@ -249,7 +247,7 @@ protected function loadData(): array usort($resultResponse['data'], function ($a, $b) use ($key) { return strcmp( (string)Hash::get($a, sprintf('%s.%s', $key, $this->sortBy)), - (string)Hash::get($b, sprintf('%s.%s', $key, $this->sortBy)) + (string)Hash::get($b, sprintf('%s.%s', $key, $this->sortBy)), ); }); } diff --git a/src/Controller/Admin/AppearanceController.php b/src/Controller/Admin/AppearanceController.php index b63cd713a..4039bc38b 100644 --- a/src/Controller/Admin/AppearanceController.php +++ b/src/Controller/Admin/AppearanceController.php @@ -31,14 +31,14 @@ class AppearanceController extends AdministrationBaseController /** * Resource type in use * - * @var string + * @var string|null */ - protected $resourceType = 'config'; + protected ?string $resourceType = 'config'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc @@ -47,7 +47,7 @@ public function initialize(): void { parent::initialize(); - $this->Security->setConfig('unlockedActions', ['save']); + $this->FormProtection->setConfig('unlockedActions', ['save']); } /** diff --git a/src/Controller/Admin/ApplicationsController.php b/src/Controller/Admin/ApplicationsController.php index 3c8016d4e..83a085068 100644 --- a/src/Controller/Admin/ApplicationsController.php +++ b/src/Controller/Admin/ApplicationsController.php @@ -22,17 +22,17 @@ class ApplicationsController extends AdministrationBaseController /** * @inheritDoc */ - protected $resourceType = 'applications'; + protected ?string $resourceType = 'applications'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'name' => 'string', 'description' => 'text', 'enabled' => 'bool', @@ -41,10 +41,10 @@ class ApplicationsController extends AdministrationBaseController /** * @inheritDoc */ - protected $propertiesSecrets = ['api_key', 'client_secret']; + protected array $propertiesSecrets = ['api_key', 'client_secret']; /** * @inheritDoc */ - protected $sortBy = 'name'; + protected ?string $sortBy = 'name'; } diff --git a/src/Controller/Admin/AsyncJobsController.php b/src/Controller/Admin/AsyncJobsController.php index eb4edb379..38fa3ebf6 100644 --- a/src/Controller/Admin/AsyncJobsController.php +++ b/src/Controller/Admin/AsyncJobsController.php @@ -22,19 +22,19 @@ class AsyncJobsController extends AdministrationBaseController /** * Resource type in use * - * @var string + * @var string|null */ - protected $resourceType = 'async_jobs'; + protected ?string $resourceType = 'async_jobs'; /** * @inheritDoc */ - protected $deleteonly = true; + protected bool $deleteonly = true; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'service' => 'string', 'scheduled_from' => 'date', 'expires' => 'date', @@ -45,5 +45,5 @@ class AsyncJobsController extends AdministrationBaseController /** * @inheritDoc */ - protected $meta = ['created', 'modified', 'completed']; + protected array $meta = ['created', 'modified', 'completed']; } diff --git a/src/Controller/Admin/AuthProvidersController.php b/src/Controller/Admin/AuthProvidersController.php index 3b4426a21..e3eabe89b 100644 --- a/src/Controller/Admin/AuthProvidersController.php +++ b/src/Controller/Admin/AuthProvidersController.php @@ -22,17 +22,17 @@ class AuthProvidersController extends AdministrationBaseController /** * @inheritDoc */ - protected $resourceType = 'auth_providers'; + protected ?string $resourceType = 'auth_providers'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'name' => 'string', 'auth_class' => 'string', 'url' => 'string', @@ -43,17 +43,17 @@ class AuthProvidersController extends AdministrationBaseController /** * @inheritDoc */ - protected $propertiesForceJson = [ + protected array $propertiesForceJson = [ 'params', ]; /** * @inheritDoc */ - protected $meta = []; + protected array $meta = []; /** * @inheritDoc */ - protected $sortBy = 'name'; + protected ?string $sortBy = 'name'; } diff --git a/src/Controller/Admin/ConfigController.php b/src/Controller/Admin/ConfigController.php index a51396b50..7bc14b878 100644 --- a/src/Controller/Admin/ConfigController.php +++ b/src/Controller/Admin/ConfigController.php @@ -26,19 +26,19 @@ class ConfigController extends AdministrationBaseController /** * Resource type in use * - * @var string + * @var string|null */ - protected $resourceType = 'config'; + protected ?string $resourceType = 'config'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'name' => 'string', 'context' => 'string', 'content' => 'json', @@ -48,7 +48,7 @@ class ConfigController extends AdministrationBaseController /** * @inheritDoc */ - protected $sortBy = 'name'; + protected ?string $sortBy = 'name'; /** * @inheritDoc diff --git a/src/Controller/Admin/EndpointPermissionsController.php b/src/Controller/Admin/EndpointPermissionsController.php index c3d4de758..5583755ff 100644 --- a/src/Controller/Admin/EndpointPermissionsController.php +++ b/src/Controller/Admin/EndpointPermissionsController.php @@ -25,19 +25,19 @@ class EndpointPermissionsController extends AdministrationBaseController /** * Resource type in use * - * @var string + * @var string|null */ - protected $resourceType = 'endpoint_permissions'; + protected ?string $resourceType = 'endpoint_permissions'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'endpoint_id' => 'endpoints', 'application_id' => 'applications', 'role_id' => 'roles', diff --git a/src/Controller/Admin/EndpointsController.php b/src/Controller/Admin/EndpointsController.php index d7247d036..c4470fe56 100644 --- a/src/Controller/Admin/EndpointsController.php +++ b/src/Controller/Admin/EndpointsController.php @@ -22,19 +22,19 @@ class EndpointsController extends AdministrationBaseController /** * Resource type in use * - * @var string + * @var string|null */ - protected $resourceType = 'endpoints'; + protected ?string $resourceType = 'endpoints'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'name' => 'string', 'description' => 'text', ]; @@ -42,5 +42,5 @@ class EndpointsController extends AdministrationBaseController /** * @inheritDoc */ - protected $sortBy = 'name'; + protected ?string $sortBy = 'name'; } diff --git a/src/Controller/Admin/ExternalAuthController.php b/src/Controller/Admin/ExternalAuthController.php index 40031927c..450b23d49 100644 --- a/src/Controller/Admin/ExternalAuthController.php +++ b/src/Controller/Admin/ExternalAuthController.php @@ -25,17 +25,17 @@ class ExternalAuthController extends AdministrationBaseController /** * @inheritDoc */ - protected $resourceType = 'external_auth'; + protected ?string $resourceType = 'external_auth'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'user_id' => 'string', 'auth_provider_id' => 'auth_providers', 'provider_username' => 'string', @@ -45,14 +45,19 @@ class ExternalAuthController extends AdministrationBaseController /** * @inheritDoc */ - protected $propertiesForceJson = [ + protected array $propertiesForceJson = [ 'params', ]; /** * @inheritDoc */ - protected $sortBy = 'auth_provider_id'; + protected array $meta = []; + + /** + * @inheritDoc + */ + protected ?string $sortBy = 'auth_provider_id'; /** * Index method @@ -71,9 +76,4 @@ public function index(): ?Response return null; } - - /** - * @inheritDoc - */ - protected $meta = []; } diff --git a/src/Controller/Admin/ObjectsHistoryController.php b/src/Controller/Admin/ObjectsHistoryController.php index 97ac5eb3e..8cb2846cd 100644 --- a/src/Controller/Admin/ObjectsHistoryController.php +++ b/src/Controller/Admin/ObjectsHistoryController.php @@ -20,17 +20,17 @@ class ObjectsHistoryController extends AdministrationBaseController /** * @inheritDoc */ - protected $resourceType = 'applications'; + protected ?string $resourceType = 'applications'; /** * @inheritDoc */ - protected $readonly = true; + protected bool $readonly = true; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'name' => 'string', ]; } diff --git a/src/Controller/Admin/RolesController.php b/src/Controller/Admin/RolesController.php index 525fa9cc1..91597f391 100644 --- a/src/Controller/Admin/RolesController.php +++ b/src/Controller/Admin/RolesController.php @@ -27,22 +27,22 @@ class RolesController extends AdministrationBaseController /** * @inheritDoc */ - protected $endpoint = '/roles'; + protected string $endpoint = '/roles'; /** * @inheritDoc */ - protected $resourceType = 'roles'; + protected ?string $resourceType = 'roles'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'name' => 'string', 'description' => 'text', ]; @@ -50,7 +50,7 @@ class RolesController extends AdministrationBaseController /** * @inheritDoc */ - protected $sortBy = 'name'; + protected ?string $sortBy = 'name'; /** * @inheritDoc diff --git a/src/Controller/Admin/RolesModulesController.php b/src/Controller/Admin/RolesModulesController.php index 4f977f546..190dbb56f 100644 --- a/src/Controller/Admin/RolesModulesController.php +++ b/src/Controller/Admin/RolesModulesController.php @@ -31,22 +31,22 @@ class RolesModulesController extends AdministrationBaseController /** * @inheritDoc */ - protected $endpoint = '/roles'; + protected string $endpoint = '/roles'; /** * @inheritDoc */ - protected $resourceType = 'roles'; + protected ?string $resourceType = 'roles'; /** * @inheritDoc */ - protected $readonly = false; + protected bool $readonly = false; /** * @inheritDoc */ - protected $properties = [ + protected array $properties = [ 'name' => 'string', 'description' => 'text', ]; @@ -68,7 +68,7 @@ public function index(): ?Response ]); $this->set('resources', $this->allowedRoles( $this->viewBuilder()->getVar('resources'), - (array)Hash::extract($endpointPermissions, 'data') + (array)Hash::extract($endpointPermissions, 'data'), )); } catch (BEditaClientException $e) { $this->log($e->getMessage(), 'error'); diff --git a/src/Controller/Admin/StatisticsController.php b/src/Controller/Admin/StatisticsController.php index f8ae0e968..a201a3093 100644 --- a/src/Controller/Admin/StatisticsController.php +++ b/src/Controller/Admin/StatisticsController.php @@ -19,7 +19,7 @@ use BEdita\SDK\BEditaClientException; use Cake\Cache\Cache; use Cake\Http\Response; -use Cake\I18n\FrozenDate; +use Cake\I18n\DateTime; use Cake\Utility\Hash; use Cake\Utility\Inflector; @@ -31,9 +31,9 @@ class StatisticsController extends ModelBaseController /** * Resource type currently used * - * @var string + * @var string|null */ - protected $resourceType = 'object_types'; + protected ?string $resourceType = 'object_types'; /** * @inheritDoc @@ -100,7 +100,7 @@ protected function fetch(): ?Response protected function fetchCount(string $objectType, string $from, string $to): int { // if from is in the future, return 0 - if (new FrozenDate($from) > new FrozenDate('today')) { + if (new DateTime($from) > new DateTime('today')) { return 0; } $key = CacheTools::cacheKey(sprintf('statistics-%s-%s-%s', $objectType, $from, $to)); @@ -120,11 +120,11 @@ function () use ($objectType, $from, $to) { ], 'page' => 1, 'page_size' => 1, - ] + ], ); return (int)Hash::get($response, 'meta.pagination.count', 0); - } + }, ); } catch (BEditaClientException $e) { $count = 0; @@ -147,7 +147,7 @@ protected function intervals(array $params): array $day = Hash::get($params, 'day'); // case day: return interval with just one day if ($day !== null) { - $start = new FrozenDate($day); + $start = new DateTime($day); $end = $start->addDays(1); return [['start' => $start->format('Y-m-d'), 'end' => $end->format('Y-m-d')]]; @@ -156,7 +156,7 @@ protected function intervals(array $params): array if ($week !== null) { $firstWeek = intval($week); $lastWeek = intval($week); - $start = new FrozenDate(sprintf('first day of %s', $month)); + $start = new DateTime(sprintf('first day of %s', $month)); $start = $start->addWeeks($firstWeek - 1); $end = $start->addWeeks(1)->subDays(1); $intervals = []; @@ -173,14 +173,14 @@ protected function intervals(array $params): array $firstWeek = 1; $defaultLastWeek = $month === 'february' ? 4 : 5; $lastWeek = $defaultLastWeek; - $start = new FrozenDate(sprintf('first day of %s %s', $month, $year)); + $start = new DateTime(sprintf('first day of %s %s', $month, $year)); $start = $start->addWeeks($firstWeek - 1); $end = $start->addWeeks($lastWeek)->subDays(1); $intervals = []; while ($start->lessThanOrEquals($end)) { $next = $start->addWeeks(1); if ($next->format('m') !== $start->format('m')) { - $end = new FrozenDate(sprintf('last day of %s %s', $month, $year)); + $end = new DateTime(sprintf('last day of %s %s', $month, $year)); $next = $end->addDays(1); } $intervals[] = ['start' => $start->format('Y-m-d'), 'end' => $next->format('Y-m-d')]; @@ -190,8 +190,8 @@ protected function intervals(array $params): array return $intervals; } // case year: return interval with 12 months - $start = new FrozenDate(sprintf('first day of january %s', $year)); - $end = new FrozenDate(sprintf('last day of december %s', $year)); + $start = new DateTime(sprintf('first day of january %s', $year)); + $end = new DateTime(sprintf('last day of december %s', $year)); $intervals = []; while ($start->lessThanOrEquals($end)) { $next = $start->addMonths(1); diff --git a/src/Controller/Admin/SystemInfoController.php b/src/Controller/Admin/SystemInfoController.php index 37ea48d04..736f80fbd 100644 --- a/src/Controller/Admin/SystemInfoController.php +++ b/src/Controller/Admin/SystemInfoController.php @@ -74,7 +74,7 @@ public function getApiInfo(): array try { $info = (array)Hash::get( $this->apiClient->get('/admin/sysinfo'), - 'meta.info' + 'meta.info', ); /** @var \Authentication\Identity $user */ $user = $this->Authentication->getIdentity(); diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php index 03bb8f278..6e10334be 100644 --- a/src/Controller/ApiController.php +++ b/src/Controller/ApiController.php @@ -41,7 +41,7 @@ public function beforeFilter(EventInterface $event): ?Response if (!$this->allowed()) { throw new UnauthorizedException(__('You are not authorized to access this resource')); } - $this->Security->setConfig('unlockedActions', ['post', 'patch', 'delete']); + $this->FormProtection->setConfig('unlockedActions', ['post', 'patch', 'delete']); return null; } diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index 8bc8f9fc9..7fcf4870f 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -15,9 +15,10 @@ use App\Form\Form; use App\Utility\DateRangesTools; use Authentication\Identity; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Controller\Controller; -use Cake\Controller\Exception\SecurityException; +use Cake\Controller\Exception\FormProtectionException; use Cake\Core\Configure; use Cake\Event\EventInterface; use Cake\Http\Exception\BadRequestException; @@ -39,9 +40,20 @@ class AppController extends Controller /** * BEdita4 API client * - * @var \BEdita\SDK\BEditaClient + * @var \BEdita\SDK\BEditaClient|null */ - protected $apiClient = null; + protected ?BEditaClient $apiClient = null; + + /** + * {@inheritDoc} + * + * From LocatorAwareTrait... + * Set this to empty string to avoid use of datasource and table locator. + * This way controller magic getter will not try to load a table instance and will search the property from components instead. + * + * @var string|null + */ + protected ?string $defaultTable = ''; /** * @inheritDoc @@ -50,9 +62,8 @@ public function initialize(): void { parent::initialize(); - $this->loadComponent('RequestHandler', ['enableBeforeRedirect' => false]); $this->loadComponent('App.Flash', ['clear' => true]); - $this->loadComponent('Security'); + $this->loadComponent('FormProtection'); // API config may not be set in `login` for a multi-project setup if (Configure::check('API.apiBaseUrl')) { @@ -90,7 +101,7 @@ public function beforeFilter(EventInterface $event): ?Response return $this->redirect($route); } $this->setupOutputTimezone(); - $this->Security->setConfig('blackHoleCallback', 'blackhole'); + $this->FormProtection->setConfig('blackHoleCallback', 'blackhole'); return null; } @@ -99,12 +110,12 @@ public function beforeFilter(EventInterface $event): ?Response * Handle security blackhole with logs for now * * @param string $type Exception type - * @param \Cake\Controller\Exception\SecurityException $exception Raised exception + * @param \Cake\Controller\Exception\FormProtectionException $exception Raised exception * @return void * @throws \Cake\Http\Exception\BadRequestException * @codeCoverageIgnore */ - public function blackhole(string $type, SecurityException $exception): void + public function blackhole(string $type, FormProtectionException $exception): void { // Log original exception $this->log($exception->getMessage(), 'error'); @@ -202,7 +213,7 @@ public function beforeRender(EventInterface $event): ?Response * @param string $type Object type * @return array request data */ - protected function prepareRequest($type): array + protected function prepareRequest(string $type): array { $data = (array)$this->getRequest()->getData(); @@ -328,8 +339,11 @@ protected function prepareRelations(array &$data): void * Get related ids from items array. * If items is string, it is json encoded array. * If items is array, it can be json encoded array or array of id/type data. + * + * @param mixed $items Items to parse + * @return array */ - protected function relatedIds($items): array + protected function relatedIds(mixed $items): array { if (empty($items)) { return []; @@ -342,7 +356,7 @@ protected function relatedIds($items): array function ($json) { return json_decode($json, true); }, - $items + $items, ); } @@ -376,19 +390,19 @@ function ($acc, $obj) { return $acc; }, - [] + [], ); $addRelated = array_map( function ($id) use ($replaceRelated) { return Hash::get($replaceRelated, $id); }, - $changedParents + $changedParents, ); $addRelated = array_filter( $addRelated, function ($elem) { return !empty($elem); - } + }, ); $data['relations'][$relation]['addRelated'] = $addRelated; @@ -400,7 +414,7 @@ function ($elem) { function ($id) { return ['id' => $id, 'type' => 'folders']; }, - $rem + $rem, ); } unset($data['relations'][$relation]['replaceRelated']); @@ -448,7 +462,7 @@ protected function changedAttributes(array &$data): void * @param string $key The field key * @return bool */ - protected function hasFieldChanged($oldValue, $newValue, string $key): bool + protected function hasFieldChanged(mixed $oldValue, mixed $newValue, string $key): bool { if ($oldValue === $newValue) { return false; // not changed @@ -562,7 +576,7 @@ protected function applySessionFilter(): ?Response * @param array $objects The objects to parse to set prev and next data * @return void */ - protected function setObjectNav($objects): void + protected function setObjectNav(array $objects): void { $moduleName = $this->Modules->getConfig('currentModuleName'); $total = count(array_keys($objects)); @@ -588,7 +602,7 @@ protected function setObjectNav($objects): void * @param string $id The object ID * @return array */ - protected function getObjectNav($id): array + protected function getObjectNav(string $id): array { // get objectNav from session $session = $this->getRequest()->getSession(); diff --git a/src/Controller/BulkController.php b/src/Controller/BulkController.php index 8cf8e7264..53e71871e 100644 --- a/src/Controller/BulkController.php +++ b/src/Controller/BulkController.php @@ -27,51 +27,51 @@ class BulkController extends AppController /** * Object type currently used * - * @var string + * @var string|null */ - protected $objectType = null; + protected ?string $objectType = null; /** * Object type is abstract * - * @var bool + * @var bool|null */ - protected $abstractType = null; + protected ?bool $abstractType = null; /** * Selected objects IDs * * @var array */ - protected $ids = []; + protected array $ids = []; /** * Selected objects (in the format [{id:, type:}, ...]) * - * @var array + * @var array|string */ - protected $objects = []; + protected array|string $objects = []; /** * Selected categories * * @var array|string */ - protected $categories = []; + protected array|string $categories = []; /** * Errors * * @var array */ - protected $errors = []; + protected array $errors = []; /** * Saved ids * * @var array */ - protected $saved = []; + protected array $saved = []; /** * @inheritDoc diff --git a/src/Controller/CategoriesController.php b/src/Controller/CategoriesController.php index fc5746bc6..d66686d64 100644 --- a/src/Controller/CategoriesController.php +++ b/src/Controller/CategoriesController.php @@ -28,9 +28,9 @@ class CategoriesController extends AppController /** * Object type currently used * - * @var string + * @var string|null */ - protected $objectType = null; + protected ?string $objectType = null; /** * @inheritDoc @@ -46,7 +46,7 @@ public function initialize(): void $this->Modules->setConfig('currentModuleName', $this->objectType); $this->Schema->setConfig('type', $this->objectType); } - $this->Security->setConfig('unlockedActions', ['delete', 'save']); + $this->FormProtection->setConfig('unlockedActions', ['delete', 'save']); } /** diff --git a/src/Controller/Component/CategoriesComponent.php b/src/Controller/Component/CategoriesComponent.php index 281bb6575..349c1d2d1 100644 --- a/src/Controller/Component/CategoriesComponent.php +++ b/src/Controller/Component/CategoriesComponent.php @@ -138,7 +138,7 @@ public function getAvailableRoots(?array $map): array * @param array $category The category data. * @return void */ - protected function fillRoots(array &$roots, $category): void + protected function fillRoots(array &$roots, array $category): void { if (!empty(Hash::get($category, 'attributes.parent_id'))) { return; @@ -217,7 +217,7 @@ public function save(array $data): ?array * @param string $type The object type name of the category. * @return array|null The BEdita API response for the deleted category. */ - public function delete(string $id, $type = null): ?array + public function delete(string $id, ?string $type = null): ?array { $apiClient = ApiClientProvider::getApiClient(); diff --git a/src/Controller/Component/ExportComponent.php b/src/Controller/Component/ExportComponent.php index bb9e08db9..05242a162 100644 --- a/src/Controller/Component/ExportComponent.php +++ b/src/Controller/Component/ExportComponent.php @@ -45,7 +45,7 @@ class ExportComponent extends Component * * @var array */ - protected $defaultSpreadheetProperties = [ + protected array $defaultSpreadheetProperties = [ 'creator' => 'BEdita Manager', 'lastModifiedBy' => 'BEdita Manager', 'title' => '', diff --git a/src/Controller/Component/FlashComponent.php b/src/Controller/Component/FlashComponent.php index a7e5af761..c6ac9579e 100644 --- a/src/Controller/Component/FlashComponent.php +++ b/src/Controller/Component/FlashComponent.php @@ -17,6 +17,7 @@ use Cake\Controller\Component\FlashComponent as CakeFlashComponent; use Cake\Core\Configure; use Cake\Utility\Hash; +use Exception; /** * Extends CakePHP FlashComponent setting exception attributes. @@ -29,7 +30,7 @@ class FlashComponent extends CakeFlashComponent public function set($message, array $options = []): void { $error = Hash::get($options, 'params'); - if ($error && ($error instanceof \Exception)) { + if ($error && ($error instanceof Exception)) { $options['params'] = [ 'title' => $error->getMessage(), // exception error code is HTTP status as default diff --git a/src/Controller/Component/HistoryComponent.php b/src/Controller/Component/HistoryComponent.php index 3a3aa15aa..7ab2e5b56 100644 --- a/src/Controller/Component/HistoryComponent.php +++ b/src/Controller/Component/HistoryComponent.php @@ -20,6 +20,7 @@ use Cake\Controller\Component; use Cake\Utility\Hash; use Cake\Utility\Inflector; +use Cake\View\View; /** * History component @@ -31,28 +32,28 @@ class HistoryComponent extends Component * * @var \App\View\Helper\CalendarHelper */ - protected $Calendar; + protected CalendarHelper $Calendar; /** * Categories helper * * @var \App\View\Helper\CategoriesHelper */ - protected $Categories; + protected CategoriesHelper $Categories; /** * Schema helper * * @var \App\View\Helper\SchemaHelper */ - protected $Schema; + protected SchemaHelper $Schema; /** * Key for history data to store. * * @var string */ - protected $key = 'history.%s.attributes'; + protected string $key = 'history.%s.attributes'; /** * {@inheritDoc} @@ -60,7 +61,7 @@ class HistoryComponent extends Component */ public function initialize(array $config): void { - $view = new \Cake\View\View(); + $view = new View(); $this->Calendar = new CalendarHelper($view); $this->Categories = new CategoriesHelper($view); $this->Schema = new SchemaHelper($view); @@ -76,7 +77,7 @@ public function initialize(array $config): void * @param array $object The object * @return void */ - public function load($id, array &$object): void + public function load(string|int $id, array &$object): void { if (empty($id) || empty($object)) { return; @@ -132,10 +133,10 @@ public function write(array $options): void $schema['properties'], function ($schema) { return empty($schema['readOnly']); - } - ) + }, + ), ), - '' + '', ); // rebuild attributes along history items @@ -171,7 +172,7 @@ function ($schema) { * @param array $options The options * @return array */ - public function fetch($id, array $schema, array $options): array + public function fetch(string|int $id, array $schema, array $options): array { $response = (array)ApiClientProvider::getApiClient()->get('/history', array_merge( [ @@ -179,7 +180,7 @@ public function fetch($id, array $schema, array $options): array 'include' => 'user', 'page_size' => 100, ], - $options + $options, )); $this->formatResponseData($response, $schema); @@ -239,12 +240,12 @@ public function label(string $field): string * @param mixed $value The value * @return string */ - public function content(string $field, array $schema, $value): string + public function content(string $field, array $schema, mixed $value): string { if ($field === 'date_ranges') { return sprintf( '
%s
', - $this->Calendar->list($value) + $this->Calendar->list($value), ); } if ($field === 'categories') { diff --git a/src/Controller/Component/ModulesComponent.php b/src/Controller/Component/ModulesComponent.php index c81918cb5..cd40004ab 100644 --- a/src/Controller/Component/ModulesComponent.php +++ b/src/Controller/Component/ModulesComponent.php @@ -59,12 +59,12 @@ class ModulesComponent extends Component /** * @inheritDoc */ - public $components = ['Authentication', 'Children', 'Config', 'Parents', 'Schema']; + public array $components = ['Authentication', 'Children', 'Config', 'Parents', 'Schema']; /** * @inheritDoc */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'currentModuleName' => null, 'clearHomeCache' => false, ]; @@ -74,14 +74,14 @@ class ModulesComponent extends Component * * @var array */ - protected $modules = []; + protected array $modules = []; /** * Other "logic" modules, non objects * * @var array */ - protected $otherModules = [ + protected array $otherModules = [ 'tags' => [ 'name' => 'tags', 'hints' => ['allow' => ['GET', 'POST', 'PATCH', 'DELETE']], @@ -153,23 +153,46 @@ public function getModules(): array $modules = array_intersect_key($modules, $metaModules); array_walk( $modules, - function (&$data, $key) use ($metaModules) { + function (&$data, $key) use ($metaModules): void { $data = array_merge((array)Hash::get($metaModules, $key), $data); - } + }, ); $this->modules = array_merge( $modules, array_diff_key($metaModules, $modules), - $pluginModules + $pluginModules, ); $this->modulesByAccessControl(); if (!$this->Schema->tagsInUse()) { unset($this->modules['tags']); } + $types = array_keys($this->modules); + if (isset($this->modules['translations']) && !$this->translationsEnabled($types)) { + unset($this->modules['translations']); + } return $this->modules; } + /** + * Check if translations are enabled for at least one of the given object types. + * + * @param array $types Object types to check. + * @return bool + */ + public function translationsEnabled(array $types): bool + { + foreach ($types as $objectType) { + $schema = (array)$this->Schema->getSchema($objectType); + $translatable = (array)Hash::get($schema, 'translatable'); + if (count($translatable) > 0) { + return true; + } + } + + return false; + } + /** * This filters modules and apply 'AccessControl' config by user role, if any. * Module can be "hidden": remove from modules. @@ -263,7 +286,7 @@ public function getProject(): array 'name' => (string)Hash::get( (array)Configure::read('Project'), 'name', - (string)Hash::get($api, 'project.name') + (string)Hash::get($api, 'project.name'), ), 'version' => (string)Hash::get($api, 'version'), ], @@ -354,7 +377,7 @@ public function upload(array &$requestData): void $response = $apiClient->post( sprintf('/%s/upload/%s', $type, $filename), $content, - $headers + $headers, ); $requestData['id'] = Hash::get($response, 'data.id'); unset($requestData['file'], $requestData['remote_url']); @@ -370,7 +393,7 @@ public function upload(array &$requestData): void // link stream to media $streamUuid = Hash::get($response, 'data.id'); - $response = $this->assocStreamToMedia($streamUuid, $requestData, $filename); + $this->assocStreamToMedia($streamUuid, $requestData, $filename); } unset($requestData['file'], $requestData['remote_url']); } @@ -564,7 +587,7 @@ public function skipSavePermissions(string $id, array $requestPermissions, array function ($role) { return (int)$role; }, - $requestPermissions + $requestPermissions, ); sort($requestPermissions); $query = ['filter' => ['object_id' => $id], 'page_size' => 100]; @@ -668,8 +691,8 @@ function ($r) use ($relationsSchema) { return $attributes['inverse_label']; }, - $names - ) + $names, + ), ); } @@ -758,7 +781,7 @@ public function getRelated(array $data): array } $response = ApiClientProvider::getApiClient()->save( (string)Hash::get($obj, 'type'), - (array)Hash::get($obj, 'attributes') + (array)Hash::get($obj, 'attributes'), ); $relatedObjects[] = [ 'id' => Hash::get($response, 'data.id'), diff --git a/src/Controller/Component/ObjectsEditorsComponent.php b/src/Controller/Component/ObjectsEditorsComponent.php index 578529bd9..7abdc1d56 100644 --- a/src/Controller/Component/ObjectsEditorsComponent.php +++ b/src/Controller/Component/ObjectsEditorsComponent.php @@ -15,6 +15,7 @@ use Cake\Cache\Cache; use Cake\Controller\Component; use Cake\Core\Configure; +use Cake\Utility\Hash; /** * ObjectsEditors component @@ -28,21 +29,21 @@ class ObjectsEditorsComponent extends Component * * @var array */ - protected $components = ['Authentication']; + protected array $components = ['Authentication']; /** * Objects editors. * * @var array */ - public $objectsEditors; + public array $objectsEditors; /** * Concurrent check time. * * @var int */ - public $concurrentCheckTime = 20000; + public int $concurrentCheckTime = 20000; /** * @inheritDoc @@ -108,11 +109,14 @@ public function editorName(): ?string return null; } - if (!empty($user['attributes']['name']) && !empty($user['attributes']['surname'])) { - return sprintf('%s %s', $user['attributes']['name'], $user['attributes']['surname']); + $name = (string)Hash::get($user, 'attributes.name'); + $surname = (string)Hash::get($user, 'attributes.surname'); + if (!empty($name) && !empty($surname)) { + return sprintf('%s %s', $name, $surname); } - if (!empty($user['attributes']['username'])) { - return $user['attributes']['username']; + $username = (string)Hash::get($user, 'attributes.username'); + if (!empty($username)) { + return $username; } return null; diff --git a/src/Controller/Component/ProjectConfigurationComponent.php b/src/Controller/Component/ProjectConfigurationComponent.php index a32d9dd57..f5d1ed09e 100644 --- a/src/Controller/Component/ProjectConfigurationComponent.php +++ b/src/Controller/Component/ProjectConfigurationComponent.php @@ -50,7 +50,7 @@ public function read(): array function () { return $this->fetchConfig(); }, - self::CACHE_CONFIG + self::CACHE_CONFIG, ); Configure::write('Project.config', $config); } catch (BEditaClientException $e) { @@ -80,9 +80,9 @@ protected function fetchConfig(): array $config = Hash::combine($response, 'data.{n}.attributes.name', 'data.{n}.attributes.content'); array_walk( $config, - function (&$value, $key) { + function (&$value, $key): void { $value = json_decode($value, true); - } + }, ); return $config; diff --git a/src/Controller/Component/PropertiesComponent.php b/src/Controller/Component/PropertiesComponent.php index 0b4590338..f12c1212c 100644 --- a/src/Controller/Component/PropertiesComponent.php +++ b/src/Controller/Component/PropertiesComponent.php @@ -31,14 +31,14 @@ class PropertiesComponent extends Component /** * @inheritDoc */ - protected $components = ['Config']; + protected array $components = ['Config']; /** * Default properties groups * * @var array */ - protected $defaultGroups = [ + protected array $defaultGroups = [ 'view' => [ // always open on the top 'core' => [ @@ -90,7 +90,7 @@ class PropertiesComponent extends Component * * @var array */ - protected $excluded = [ + protected array $excluded = [ 'categories', 'date_ranges', 'tags', @@ -120,15 +120,15 @@ public function startup(): void $keys = array_unique( array_merge( array_keys($properties), - array_keys($defaultProperties) - ) + array_keys($defaultProperties), + ), ); sort($keys); $config = []; foreach ($keys as $key) { $config[$key] = array_merge( (array)Hash::get($defaultProperties, $key), - (array)Hash::get($properties, $key) + (array)Hash::get($properties, $key), ); } $this->setConfig('Properties', $config); @@ -192,7 +192,7 @@ public function viewGroups(array $object, string $type): array function ($key) use ($metaKeys) { return !in_array($key, $metaKeys); }, - ARRAY_FILTER_USE_KEY + ARRAY_FILTER_USE_KEY, ); return $properties; @@ -210,7 +210,7 @@ public function indexList(string $type): array $this->getConfig(sprintf('Properties.%s.index', $type), $this->defaultGroups['index']), function ($item) { return !in_array($item, ['id', 'status', 'modified']); - } + }, ); } @@ -245,8 +245,8 @@ function (array $accumulator, string $type) { return $accumulator; }, - [] - ) + [], + ), ); } diff --git a/src/Controller/Component/QueryComponent.php b/src/Controller/Component/QueryComponent.php index 42f6e9238..15fa436fd 100644 --- a/src/Controller/Component/QueryComponent.php +++ b/src/Controller/Component/QueryComponent.php @@ -66,20 +66,20 @@ protected function handleInclude(array $query): array (array)Configure::read( sprintf( 'Properties.%s.index', - $this->getController()->getRequest()->getParam('object_type') - ) + $this->getController()->getRequest()->getParam('object_type'), + ), ), function ($value) { return is_array($value); - } + }, ); $decoded = empty($include) ? $include : array_keys(reset($include)); if ($this->getConfig('include') != null) { $decoded = array_unique( array_merge( $decoded, - explode(',', (string)$this->getConfig('include')) - ) + explode(',', (string)$this->getConfig('include')), + ), ); } if (!empty($decoded)) { diff --git a/src/Controller/Component/SchemaComponent.php b/src/Controller/Component/SchemaComponent.php index 8ac5bfe35..8e9f6cd4e 100644 --- a/src/Controller/Component/SchemaComponent.php +++ b/src/Controller/Component/SchemaComponent.php @@ -31,7 +31,7 @@ class SchemaComponent extends Component /** * @inheritDoc */ - public $components = ['Flash']; + public array $components = ['Flash']; /** * Cache config name for type schemas. @@ -43,7 +43,7 @@ class SchemaComponent extends Component /** * @inheritDoc */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'type' => null, // resource or object type name 'internalSchema' => false, // use internal schema ]; @@ -55,7 +55,7 @@ class SchemaComponent extends Component * @param string|null $revision Schema revision. * @return array|bool JSON Schema. */ - public function getSchema(?string $type = null, ?string $revision = null) + public function getSchema(?string $type = null, ?string $revision = null): array|bool { if ($type === null) { $type = $this->getConfig('type'); @@ -76,7 +76,7 @@ public function getSchema(?string $type = null, ?string $revision = null) function () use ($type) { return $this->fetchSchema($type); }, - self::CACHE_CONFIG + self::CACHE_CONFIG, ); } catch (BEditaClientException $e) { // Something bad happened. Booleans **ARE** valid JSON Schemas: returning `false` instead. @@ -136,7 +136,7 @@ protected function loadWithRevision(string $type, ?string $revision = null): ?ar * @param string $type Type to get schema for. * @return array|bool JSON Schema. */ - protected function fetchSchema(string $type) + protected function fetchSchema(string $type): array|bool { $schema = ApiClientProvider::getApiClient()->schema($type); if (empty($schema)) { @@ -197,7 +197,7 @@ protected function fetchObjectTypeMeta(string $type): array ]; $response = ApiClientProvider::getApiClient()->get( sprintf('/model/object_types/%s', $type), - $query + $query, ); return [ @@ -243,7 +243,7 @@ function ($item) { 'enabled' => Hash::get((array)$item, 'attributes.enabled'), ]; }, - $data + $data, ); } @@ -274,7 +274,7 @@ public function getRelationsSchema(): array function () { return $this->fetchRelationData(); }, - self::CACHE_CONFIG + self::CACHE_CONFIG, ); } catch (BEditaClientException $e) { // The exception is being caught _outside_ of `Cache::remember()` to avoid caching the fallback. @@ -377,7 +377,7 @@ public function customProps(string $type): array function () use ($type) { return $this->fetchCustomProps($type); }, - self::CACHE_CONFIG + self::CACHE_CONFIG, ); } @@ -424,7 +424,7 @@ public function objectTypesFeatures(): array function () { return $this->fetchObjectTypesFeatures(); }, - self::CACHE_CONFIG + self::CACHE_CONFIG, ); } catch (BEditaClientException $e) { $this->log($e->getMessage(), LogLevel::ERROR); diff --git a/src/Controller/Component/ThumbsComponent.php b/src/Controller/Component/ThumbsComponent.php index 394432a29..f7903b587 100644 --- a/src/Controller/Component/ThumbsComponent.php +++ b/src/Controller/Component/ThumbsComponent.php @@ -28,7 +28,7 @@ class ThumbsComponent extends Component /** * @inheritDoc */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'queryParams' => ['preset' => 'default'], 'objectTypes' => ['images', 'videos'], ]; @@ -38,7 +38,7 @@ class ThumbsComponent extends Component * * @var array */ - protected $components = ['Flash', 'Query']; + protected array $components = ['Flash', 'Query']; /** * Retrieve thumbnails URL of related objects in `meta.url` if present. diff --git a/src/Controller/Component/TranslatorComponent.php b/src/Controller/Component/TranslatorComponent.php index 0ef0816e4..591983955 100644 --- a/src/Controller/Component/TranslatorComponent.php +++ b/src/Controller/Component/TranslatorComponent.php @@ -26,7 +26,7 @@ class TranslatorComponent extends Component /** * @inheritDoc */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'Translators' => [], ]; @@ -35,7 +35,7 @@ class TranslatorComponent extends Component * * @var array */ - protected $registry = []; + protected array $registry = []; /** * Translate a text $text from language source $from to language target $to diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php index 2583c1d25..d98bb9975 100644 --- a/src/Controller/DashboardController.php +++ b/src/Controller/DashboardController.php @@ -16,6 +16,7 @@ use App\Utility\SchemaTrait; use Cake\Core\Configure; use Cake\Utility\Hash; +use Exception; /** * Dashboard controller. @@ -48,7 +49,7 @@ public function index(): void $user = $this->Authentication->getIdentity(); $this->set( 'jobsAllow', - (array)Hash::extract($this->getMeta($user), 'resources./async_jobs.hints.allow') + (array)Hash::extract($this->getMeta($user), 'resources./async_jobs.hints.allow'), ); // set modules counters @@ -68,7 +69,7 @@ public function index(): void try { $response = $this->apiClient->get($endpoint, $options); CacheTools::setModuleCount($response, $name); - } catch (\Exception $e) { + } catch (Exception $e) { CacheTools::setModuleCount(['meta' => ['pagination' => ['count' => '-']]], $name); } } diff --git a/src/Controller/DownloadController.php b/src/Controller/DownloadController.php index 4776a7c51..8b6e89405 100644 --- a/src/Controller/DownloadController.php +++ b/src/Controller/DownloadController.php @@ -28,7 +28,7 @@ class DownloadController extends AppController /** * @inheritDoc */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ // HTTP client configuration 'client' => [], ]; diff --git a/src/Controller/ErrorController.php b/src/Controller/ErrorController.php index 9c641cc1c..3d49968d2 100644 --- a/src/Controller/ErrorController.php +++ b/src/Controller/ErrorController.php @@ -24,17 +24,6 @@ */ class ErrorController extends AppController { - /** - * Initialization hook method. - * - * @return void - * @codeCoverageIgnore - */ - public function initialize(): void - { - $this->loadComponent('RequestHandler', ['enableBeforeRedirect' => false]); - } - /** * beforeFilter callback. * diff --git a/src/Controller/ExportController.php b/src/Controller/ExportController.php index 3da82b35f..64a2a1c08 100644 --- a/src/Controller/ExportController.php +++ b/src/Controller/ExportController.php @@ -42,7 +42,7 @@ class ExportController extends AppController * * @var array */ - public $filter = []; + public array $filter = []; /** * {@inheritDoc} @@ -53,7 +53,7 @@ public function initialize(): void parent::initialize(); $this->loadComponent('Export'); - $this->Security->setConfig('unlockedActions', ['related']); + $this->FormProtection->setConfig('unlockedActions', ['related']); } /** @@ -345,7 +345,7 @@ protected function fillDataFromResponse(array &$data, array $response, array $fi * @param array $response The response from which extract fields * @return array */ - protected function getFieldNames($response): array + protected function getFieldNames(array $response): array { $fields = (array)Hash::get($response, 'data.0.attributes'); $meta = (array)Hash::get($response, 'data.0.meta'); @@ -390,7 +390,7 @@ protected function rowFields(array $data, array $fields): array * @param mixed $value The value * @return mixed */ - protected function getValue($value) + protected function getValue(mixed $value): mixed { if (is_array($value)) { return json_encode($value); diff --git a/src/Controller/HistoryController.php b/src/Controller/HistoryController.php index 6670b6eec..dcdeb3dfc 100644 --- a/src/Controller/HistoryController.php +++ b/src/Controller/HistoryController.php @@ -55,7 +55,7 @@ public function objects(): void $this->getRequest()->allowMethod('get'); $query = array_merge( $this->getRequest()->getQueryParams(), - ['fields' => 'id,title,uname'] + ['fields' => 'id,title,uname'], ); $response = ApiTools::cleanResponse((array)$this->apiClient->get('objects', $query)); $data = $response['data']; @@ -71,7 +71,7 @@ public function objects(): void * @param int $page Page number. * @return void */ - public function info($id, int $page): void + public function info(string|int $id, int $page): void { $this->viewBuilder()->setClassName('Json'); $this->getRequest()->allowMethod('get'); @@ -90,7 +90,7 @@ public function info($id, int $page): void * @param string|int $historyId History object ID. * @return \Cake\Http\Response|null */ - public function clone($id, $historyId): ?Response + public function clone(string|int $id, string|int $historyId): ?Response { $this->setHistory($id, $historyId, false); @@ -104,7 +104,7 @@ public function clone($id, $historyId): ?Response * @param string|int $historyId History object ID. * @return \Cake\Http\Response|null */ - public function restore($id, $historyId): ?Response + public function restore(string|int $id, string|int $historyId): ?Response { $this->setHistory($id, $historyId, true); @@ -119,7 +119,7 @@ public function restore($id, $historyId): ?Response * @param bool $keepUname Keep previous uname. * @return void */ - protected function setHistory($id, $historyId, $keepUname): void + protected function setHistory(string|int $id, string|int $historyId, bool $keepUname): void { $objectType = $this->getRequest()->getParam('object_type'); $options = compact('objectType', 'id', 'historyId', 'keepUname') + [ diff --git a/src/Controller/ImportController.php b/src/Controller/ImportController.php index 426c189db..8129ab29b 100644 --- a/src/Controller/ImportController.php +++ b/src/Controller/ImportController.php @@ -35,7 +35,7 @@ public function initialize(): void { parent::initialize(); - $this->Security->setConfig('unlockedActions', ['file']); + $this->FormProtection->setConfig('unlockedActions', ['file']); } /** @@ -43,7 +43,7 @@ public function initialize(): void * * @var array */ - protected $services = []; + protected array $services = []; /** * @inheritDoc @@ -69,7 +69,7 @@ public function index(): void $user = $this->Authentication->getIdentity(); $this->set( 'jobsAllow', - (array)Hash::extract($this->getMeta($user), 'resources./async_jobs.hints.allow') + (array)Hash::extract($this->getMeta($user), 'resources./async_jobs.hints.allow'), ); } @@ -112,7 +112,7 @@ public function file(): ?Response $result = $importFilter->import( $file->getClientFileName(), $file->getStream()->getMetadata('uri'), - $this->getRequest()->getData('filter_options') + $this->getRequest()->getData('filter_options'), ); $this->getRequest()->getSession()->write(['Import.result' => $result]); } catch (Exception $e) { @@ -173,7 +173,7 @@ private function loadFilters(): void * @param string $filterClass Filter class * @return void */ - protected function updateServiceList($filterClass): void + protected function updateServiceList(string $filterClass): void { $service = call_user_func([$filterClass, 'getServiceName']); if (!empty($service) && !in_array($service, $this->services)) { diff --git a/src/Controller/LockController.php b/src/Controller/LockController.php index 38b631ab6..d90c97e06 100644 --- a/src/Controller/LockController.php +++ b/src/Controller/LockController.php @@ -62,7 +62,7 @@ protected function lock(bool $locked): bool $this->apiClient->patch( sprintf('/%s/%s', $type, $id), $payload, - ['Content-Type' => 'application/json'] + ['Content-Type' => 'application/json'], ); } catch (BEditaClientException $ex) { $this->log($ex->getMessage(), LogLevel::ERROR); diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index cb7ba0bb6..78502ad29 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -26,7 +26,7 @@ class LoginController extends AppController /** * @inheritDoc */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ // Projects configuration files base path 'projectsPath' => CONFIG . 'projects' . DS, ]; @@ -75,7 +75,7 @@ protected function authRequest(): ?Response // Load project config if `multi project` setup Application::loadProjectConfig( (string)$this->getRequest()->getData('project'), - (string)$this->getConfig('projectsPath') + (string)$this->getConfig('projectsPath'), ); $result = $this->Authentication->getResult(); diff --git a/src/Controller/Model/CategoriesController.php b/src/Controller/Model/CategoriesController.php index bd9cad63c..45afd66ab 100644 --- a/src/Controller/Model/CategoriesController.php +++ b/src/Controller/Model/CategoriesController.php @@ -26,16 +26,16 @@ class CategoriesController extends ModelBaseController /** * Resource type currently used * - * @var string + * @var string|null */ - protected $resourceType = 'categories'; + protected ?string $resourceType = 'categories'; /** * Single resource view exists * * @var bool */ - protected $singleView = false; + protected bool $singleView = false; /** * @inheritDoc diff --git a/src/Controller/Model/ModelBaseController.php b/src/Controller/Model/ModelBaseController.php index ec5d542df..4131f8bcf 100644 --- a/src/Controller/Model/ModelBaseController.php +++ b/src/Controller/Model/ModelBaseController.php @@ -30,16 +30,16 @@ abstract class ModelBaseController extends AppController /** * Resource type in use (object_types, properties, property_types) * - * @var string + * @var string|null */ - protected $resourceType = null; + protected ?string $resourceType = null; /** * Single resource view existence flag. * * @var bool */ - protected $singleView = true; + protected bool $singleView = true; /** * @inheritDoc @@ -93,7 +93,7 @@ public function index(): ?Response try { $response = $this->apiClient->get( sprintf('/model/%s', $this->resourceType), - $this->indexQuery() + $this->indexQuery(), ); } catch (BEditaClientException $e) { $this->log($e->getMessage(), 'error'); @@ -129,7 +129,7 @@ protected function indexQuery(): array * @param string|int $id Resource ID. * @return \Cake\Http\Response|null */ - public function view($id): ?Response + public function view(string|int $id): ?Response { $endpoint = sprintf('/model/%s/%s', $this->resourceType, $id); try { @@ -178,10 +178,10 @@ public function create(): ?Response $schema['properties'], function ($schema) { return empty($schema['readOnly']); - } - ) + }, + ), ), - null + null, ); $resource = [ 'type' => $this->resourceType, diff --git a/src/Controller/Model/ObjectTypesController.php b/src/Controller/Model/ObjectTypesController.php index 3f8707488..5c6d9f5f3 100644 --- a/src/Controller/Model/ObjectTypesController.php +++ b/src/Controller/Model/ObjectTypesController.php @@ -45,9 +45,9 @@ class ObjectTypesController extends ModelBaseController /** * Resource type currently used * - * @var string + * @var string|null */ - protected $resourceType = 'object_types'; + protected ?string $resourceType = 'object_types'; /** * @inheritDoc @@ -112,7 +112,7 @@ protected function propertiesData(array $filter): array while (!$done) { $response = $this->apiClient->get( '/model/properties', - compact('filter', 'page') + ['page_size' => 100] + compact('filter', 'page') + ['page_size' => 100], ); $data = array_merge($data, (array)Hash::get($response, 'data')); $pageCount = (int)Hash::get($response, 'meta.pagination.page_count'); @@ -159,14 +159,14 @@ protected function tables(array $resource): array $tables = array_unique( array_merge( self::TABLES, - (array)Configure::read('Model.objectTypesTables') - ) + (array)Configure::read('Model.objectTypesTables'), + ), ); $tables = array_unique( array_merge( $tables, - (array)Hash::get($resource, 'attributes.table') - ) + (array)Hash::get($resource, 'attributes.table'), + ), ); sort($tables); diff --git a/src/Controller/Model/PropertyTypesController.php b/src/Controller/Model/PropertyTypesController.php index 33b49952d..ecd1d160f 100644 --- a/src/Controller/Model/PropertyTypesController.php +++ b/src/Controller/Model/PropertyTypesController.php @@ -27,9 +27,9 @@ class PropertyTypesController extends ModelBaseController /** * Resource type currently used * - * @var string + * @var string|null */ - protected $resourceType = 'property_types'; + protected ?string $resourceType = 'property_types'; /** * {@inheritDoc} @@ -39,7 +39,7 @@ class PropertyTypesController extends ModelBaseController public function initialize(): void { parent::initialize(); - $this->Security->setConfig('unlockedActions', ['save']); + $this->FormProtection->setConfig('unlockedActions', ['save']); } /** diff --git a/src/Controller/Model/RelationsController.php b/src/Controller/Model/RelationsController.php index ec2e49d4d..7fc682463 100644 --- a/src/Controller/Model/RelationsController.php +++ b/src/Controller/Model/RelationsController.php @@ -26,9 +26,9 @@ class RelationsController extends ModelBaseController /** * Resource type currently used * - * @var string + * @var string|null */ - protected $resourceType = 'relations'; + protected ?string $resourceType = 'relations'; /** * @inheritDoc @@ -138,7 +138,7 @@ function ($item) { return compact('id') + ['type' => 'object_types']; }, - $types + $types, ); } diff --git a/src/Controller/Model/TagsController.php b/src/Controller/Model/TagsController.php index 3fb077c13..c950f6dfc 100644 --- a/src/Controller/Model/TagsController.php +++ b/src/Controller/Model/TagsController.php @@ -28,16 +28,16 @@ class TagsController extends ModelBaseController /** * Resource type currently used * - * @var string + * @var string|null */ - protected $resourceType = 'tags'; + protected ?string $resourceType = 'tags'; /** * Single resource view exists * * @var bool */ - protected $singleView = false; + protected bool $singleView = false; /** * @inheritDoc diff --git a/src/Controller/ModulesController.php b/src/Controller/ModulesController.php index bc7da310f..ae648a455 100644 --- a/src/Controller/ModulesController.php +++ b/src/Controller/ModulesController.php @@ -16,6 +16,7 @@ use App\Utility\CacheTools; use App\Utility\Message; use App\Utility\PermissionsTrait; +use App\Utility\Schema; use BEdita\SDK\BEditaClientException; use BEdita\WebTools\Utility\ApiTools; use Cake\Core\Configure; @@ -50,9 +51,9 @@ class ModulesController extends AppController /** * Object type currently used * - * @var string + * @var string|null */ - protected $objectType = null; + protected ?string $objectType = null; /** * @inheritDoc @@ -75,7 +76,7 @@ public function initialize(): void $this->Modules->setConfig('currentModuleName', $this->objectType); $this->Schema->setConfig('type', $this->objectType); } - $this->Security->setConfig('unlockedActions', ['save', 'setup']); + $this->FormProtection->setConfig('unlockedActions', ['save', 'setup']); } /** @@ -155,7 +156,7 @@ public function index(): ?Response * @param string|int $id Resource ID. * @return \Cake\Http\Response|null */ - public function view($id): ?Response + public function view(string|int $id): ?Response { $this->getRequest()->allowMethod(['get']); @@ -194,7 +195,7 @@ function ($acc, $relName) use ($schema) { return $acc; }, - [] + [], ); $this->setupViewRelations($computedRelations); @@ -214,7 +215,7 @@ function ($acc, $relName) use ($schema) { * @param string|int $id Resource ID. * @return \Cake\Http\Response|null */ - public function uname($id): ?Response + public function uname(string|int $id): ?Response { try { $response = $this->apiClient->get(sprintf('/objects/%s', $id)); @@ -256,10 +257,10 @@ public function create(): ?Response $schema['properties'], function ($schema) { return empty($schema['readOnly']); - } - ) + }, + ), ), - null + null, ); $object = [ 'type' => $this->objectType, @@ -330,7 +331,7 @@ public function save(): void $this->savePermissions( (array)$response, $schema, - $permissions + $permissions, ); } catch (BEditaClientException $error) { $this->handleError($error); @@ -389,7 +390,7 @@ protected function handleError(BEditaClientException $exception): void * @param string|int $id Object ID. * @return \Cake\Http\Response|null */ - public function clone($id): ?Response + public function clone(string|int $id): ?Response { $this->viewBuilder()->setTemplate('view'); $schema = $this->Schema->getSchema(); @@ -465,16 +466,16 @@ public function delete(): ?Response * @param string $relation The relation name. * @return void */ - public function related($id, string $relation): void + public function related(string|int $id, string $relation): void { + $this->getRequest()->allowMethod(['get']); + $this->viewBuilder()->setClassName('Json'); if ($id === 'new') { $this->set('data', []); $this->setSerialize(['data']); return; } - - $this->getRequest()->allowMethod(['get']); $query = $this->Query->prepare($this->getRequest()->getQueryParams()); try { $response = $this->apiClient->getRelated($id, $this->objectType, $relation, $query); @@ -484,9 +485,7 @@ public function related($id, string $relation): void return; } - $this->Thumbs->urls($response); - $this->set((array)$response); $this->setSerialize(array_keys($response)); } @@ -499,9 +498,10 @@ public function related($id, string $relation): void * @param string $type the resource type name. * @return void */ - public function resources($id, string $type): void + public function resources(string|int $id, string $type): void { $this->getRequest()->allowMethod(['get']); + $this->viewBuilder()->setClassName('Json'); $query = $this->Query->prepare($this->getRequest()->getQueryParams()); try { $response = $this->apiClient->get($type, $query); @@ -523,9 +523,10 @@ public function resources($id, string $type): void * @param string $relation The relation name. * @return void */ - public function relationships($id, string $relation): void + public function relationships(string|int $id, string $relation): void { $this->getRequest()->allowMethod(['get']); + $this->viewBuilder()->setClassName('Json'); $available = $this->availableRelationshipsUrl($relation); try { @@ -576,7 +577,7 @@ protected function availableRelationshipsUrl(string $relation): string * @param string $objectType objecte type name * @return array $schema */ - public function getSchemaForIndex($objectType): array + public function getSchemaForIndex(string $objectType): array { $schema = (array)$this->Schema->getSchema($objectType); @@ -631,12 +632,12 @@ private function setupViewRelations(array $relations): void $relations, $this->Properties->relationsList($this->objectType), $this->Properties->hiddenRelationsList($this->objectType), - $this->Properties->readonlyRelationsList($this->objectType) + $this->Properties->readonlyRelationsList($this->objectType), ); // set right types, considering the object type relations $rel = (array)$this->viewBuilder()->getVar('relationsSchema'); - $rightTypes = \App\Utility\Schema::rightTypes($rel); + $rightTypes = Schema::rightTypes($rel); $this->set('rightTypes', $rightTypes); // set schemas for relations right types @@ -656,7 +657,7 @@ public function users(): void $this->getRequest()->allowMethod('get'); $query = array_merge( $this->getRequest()->getQueryParams(), - ['fields' => 'id,title,username,name,surname,last_login'] + ['fields' => 'id,title,username,name,surname,last_login'], ); $response = (array)$this->apiClient->get('users', $query); $response = ApiTools::cleanResponse($response); @@ -681,7 +682,7 @@ public function get(string $id): void $type = (string)Hash::get($query, 'type'); $fields = array_unique(array_merge( explode(',', 'id,title,description,uname,status,media_url'), - explode(',', (string)Hash::get($query, 'fields', '')) + explode(',', (string)Hash::get($query, 'fields', '')), )); $query['fields'] = implode(',', $fields); if ($type == null) { @@ -722,6 +723,7 @@ public function setup(): ?Response } $this->getRequest()->allowMethod(['get', 'post']); if ($this->getRequest()->is('post')) { + $this->viewBuilder()->setClassName('Json'); try { $requestData = $this->getRequest()->getData(); $configurationKey = $requestData['configurationKey'] ?? null; diff --git a/src/Controller/MultiuploadController.php b/src/Controller/MultiuploadController.php index e09d72ff4..2a8057231 100644 --- a/src/Controller/MultiuploadController.php +++ b/src/Controller/MultiuploadController.php @@ -22,9 +22,9 @@ class MultiuploadController extends AppController /** * Object type currently used * - * @var string + * @var string|null */ - protected $objectType = null; + protected ?string $objectType = null; /** * @inheritDoc diff --git a/src/Controller/PasswordController.php b/src/Controller/PasswordController.php index fb6bfda70..a61866ecc 100644 --- a/src/Controller/PasswordController.php +++ b/src/Controller/PasswordController.php @@ -69,7 +69,7 @@ public function reset(): ?Response $result = $this->apiClient->post( '/auth/change', json_encode($data), - ['Content-Type' => 'application/json'] + ['Content-Type' => 'application/json'], ); $this->set(compact('result')); } catch (BEditaClientException $ex) { @@ -106,7 +106,7 @@ public function change(): ?Response $result = (array)$this->apiClient->patch( '/auth/change', json_encode($data), - ['Content-Type' => 'application/json'] + ['Content-Type' => 'application/json'], ); } catch (BEditaClientException $ex) { $this->Flash->error(__($ex->getMessage())); diff --git a/src/Controller/SendMailController.php b/src/Controller/SendMailController.php new file mode 100644 index 000000000..2abdd2ba7 --- /dev/null +++ b/src/Controller/SendMailController.php @@ -0,0 +1,48 @@ +FormProtection->setConfig('unlockedActions', ['index']); + } + + /** + * @inheritDoc + */ + public function index(): void + { + $this->getRequest()->allowMethod(['post']); + $this->viewBuilder()->setClassName('Json'); + try { + $payload = $this->getRequest()->getData(); + foreach ($payload['data'] as $key => $value) { + if (strpos($key, '.') !== false) { + unset($payload['data'][$key]); + $payload['data'] = Hash::insert($payload['data'], $key, $value); + } + } + ApiClientProvider::getApiClient()->post('/placeholders/send', (string)json_encode($payload)); + $response = ['message' => 'Email sent successfully']; + $this->set('response', $response); + $this->setSerialize(['response']); + } catch (Exception $e) { + $this->set('error', $e->getMessage()); + $this->setSerialize(['error']); + } + } +} diff --git a/src/Controller/SessionController.php b/src/Controller/SessionController.php index 635ac8428..23523dc18 100644 --- a/src/Controller/SessionController.php +++ b/src/Controller/SessionController.php @@ -23,7 +23,7 @@ public function initialize(): void { parent::initialize(); - $this->Security->setConfig('unlockedActions', ['save', 'delete']); + $this->FormProtection->setConfig('unlockedActions', ['save', 'delete']); $this->viewBuilder()->setClassName('Json'); } diff --git a/src/Controller/TagsController.php b/src/Controller/TagsController.php index 1fc174a56..463ebf9f1 100644 --- a/src/Controller/TagsController.php +++ b/src/Controller/TagsController.php @@ -23,7 +23,7 @@ public function initialize(): void { parent::initialize(); $this->loadComponent('ProjectConfiguration'); - $this->Security->setConfig('unlockedActions', ['create', 'patch', 'delete']); + $this->FormProtection->setConfig('unlockedActions', ['create', 'patch', 'delete']); } /** diff --git a/src/Controller/TranslationsController.php b/src/Controller/TranslationsController.php index 8f7fb77bd..385c2a778 100644 --- a/src/Controller/TranslationsController.php +++ b/src/Controller/TranslationsController.php @@ -18,6 +18,7 @@ use Cake\Http\Exception\NotFoundException; use Cake\Http\Response; use Cake\Utility\Hash; +use Exception; use Psr\Log\LogLevel; /** @@ -63,7 +64,7 @@ public function index(): ?Response * @param string|int $id Object ID. * @return \Cake\Http\Response|null */ - public function add($id): ?Response + public function add(string|int $id): ?Response { $this->getRequest()->allowMethod(['get']); $this->objectType = $this->typeFromUrl(); @@ -97,7 +98,7 @@ public function add($id): ?Response * @param string $lang The lang code. * @return \Cake\Http\Response|null */ - public function edit($id, $lang): ?Response + public function edit(string|int $id, string $lang): ?Response { $this->getRequest()->allowMethod(['get']); $this->objectType = $this->typeFromUrl(); @@ -117,7 +118,7 @@ public function edit($id, $lang): ?Response if (empty($translation)) { throw new NotFoundException(sprintf('Translation not found per %s %s and lang %s', $this->objectType, $id, $lang)); } - } catch (\Exception $e) { + } catch (Exception $e) { // Error! Back to index. $this->log($e->getMessage(), LogLevel::ERROR); $this->Flash->error($e->getMessage(), ['params' => $e]); @@ -199,7 +200,7 @@ protected function setupJsonKeys(): void function ($v) { return str_replace(['[', ']'], ['.', ''], $v); }, - explode(',', (string)$this->request->getData('_jsonKeys')) + explode(',', (string)$this->request->getData('_jsonKeys')), ); $this->request = $this->request->withData('_jsonKeys', implode(',', $jsonKeys)); } diff --git a/src/Controller/TranslatorController.php b/src/Controller/TranslatorController.php index 450736abc..ca0263258 100644 --- a/src/Controller/TranslatorController.php +++ b/src/Controller/TranslatorController.php @@ -13,6 +13,7 @@ namespace App\Controller; use Cake\Core\Configure; +use Exception; /** * Translator controller. @@ -28,7 +29,8 @@ public function initialize(): void { parent::initialize(); $this->loadComponent('Translator', (array)Configure::read('Translators')); - $this->Security->setConfig('unlockedActions', ['translate']); + $this->FormProtection->setConfig('unlockedActions', ['translate']); + $this->defaultTable = null; } /** @@ -47,11 +49,11 @@ public function translate(): void $texts, (string)$this->getRequest()->getData('from'), (string)$this->getRequest()->getData('to'), - (string)$this->getRequest()->getData('translator') + (string)$this->getRequest()->getData('translator'), ); $decoded = json_decode($json); $this->set('translation', $decoded->translation); - } catch (\Exception $e) { + } catch (Exception $e) { $error = $e->getMessage(); $this->set(compact('error')); } diff --git a/src/Controller/TrashController.php b/src/Controller/TrashController.php index 8b33c321e..2571af5dc 100644 --- a/src/Controller/TrashController.php +++ b/src/Controller/TrashController.php @@ -99,7 +99,7 @@ public function index(): ?Response * @return \Cake\Http\Response|null * @codeCoverageIgnore */ - public function view($id): ?Response + public function view(mixed $id): ?Response { $this->getRequest()->allowMethod(['get']); @@ -215,7 +215,7 @@ public function emptyTrash(): ?Response */ public function deleteData(string $id): void { - $response = $this->apiClient->get('/streams', ['filter' => ['object_id' => $id]]); + $this->apiClient->get('/streams', ['filter' => ['object_id' => $id]]); $this->apiClient->remove($id); } diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php index fbf6053ac..1555edf8e 100644 --- a/src/Controller/TreeController.php +++ b/src/Controller/TreeController.php @@ -33,7 +33,7 @@ public function initialize(): void { parent::initialize(); - $this->Security->setConfig('unlockedActions', ['slug']); + $this->FormProtection->setConfig('unlockedActions', ['slug']); } /** @@ -127,7 +127,7 @@ public function slug(): ?Response ]; $response = $this->apiClient->post( sprintf('/folders/%s/relationships/children', (string)Hash::get($data, 'parent')), - json_encode($body) + json_encode($body), ); // Clearing cache after successful save Cache::clearGroup('tree', TreeCacheEventHandler::CACHE_CONFIG); @@ -159,7 +159,7 @@ public function treeData(array $query): array function ($key) { return $key !== 'filter'; }, - ARRAY_FILTER_USE_KEY + ARRAY_FILTER_USE_KEY, ); $key = CacheTools::cacheKey(sprintf('tree-%s-%s', $subkey, md5(serialize($tmp)))); $data = []; @@ -169,7 +169,7 @@ function ($key) { function () use ($query) { return $this->fetchTreeData($query); }, - TreeCacheEventHandler::CACHE_CONFIG + TreeCacheEventHandler::CACHE_CONFIG, ); } catch (BEditaClientException $e) { // Something bad happened @@ -201,7 +201,7 @@ function () use ($id) { return $this->minimalData($data); }, - TreeCacheEventHandler::CACHE_CONFIG + TreeCacheEventHandler::CACHE_CONFIG, ); } catch (BEditaClientException $e) { // Something bad happened @@ -233,7 +233,7 @@ function () use ($id) { return $this->minimalDataWithMeta($data); }, - TreeCacheEventHandler::CACHE_CONFIG + TreeCacheEventHandler::CACHE_CONFIG, ); } catch (BEditaClientException $e) { // Something bad happened @@ -269,7 +269,7 @@ function () use ($id, $type) { return $included; }, - TreeCacheEventHandler::CACHE_CONFIG + TreeCacheEventHandler::CACHE_CONFIG, ); } catch (BEditaClientException $e) { // Something bad happened diff --git a/src/Core/Exception/UploadException.php b/src/Core/Exception/UploadException.php index 2ff0fa706..a99dc8dbd 100644 --- a/src/Core/Exception/UploadException.php +++ b/src/Core/Exception/UploadException.php @@ -25,7 +25,7 @@ class UploadException extends CakeException * * @var array */ - protected $messagesMap = [ + protected array $messagesMap = [ UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds current max size of {0}', UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', UPLOAD_ERR_PARTIAL => 'The uploaded file was only partially uploaded', diff --git a/src/Core/Filter/ImportFilter.php b/src/Core/Filter/ImportFilter.php index 061add253..63ad984ea 100644 --- a/src/Core/Filter/ImportFilter.php +++ b/src/Core/Filter/ImportFilter.php @@ -13,10 +13,11 @@ namespace App\Core\Filter; use App\Core\Result\ImportResult; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; -use Cake\Filesystem\File; use Cake\Log\LogTrait; use Cake\Utility\Hash; +use LogicException; /** * Import abstract class @@ -28,24 +29,24 @@ abstract class ImportFilter /** * BEdita Api client * - * @var \BEdita\SDK\BEditaClient + * @var \BEdita\SDK\BEditaClient|null */ - protected $apiClient = null; + protected ?BEditaClient $apiClient = null; /** * Filter import result * - * @var \App\Core\Result\ImportResult + * @var \App\Core\Result\ImportResult|null */ - protected $result = null; + protected ?ImportResult $result = null; /** * The service name used by async job. * If defined the import is intended as asynchronous. * - * @var string + * @var string|null */ - protected static $serviceName = null; + protected static ?string $serviceName = null; /** * Constructor @@ -78,7 +79,7 @@ public static function getServiceName(): ?string * @param array $options The import options * @return \App\Core\Result\ImportResult The result */ - abstract public function import($filename, $filepath, ?array $options = []): ImportResult; + abstract public function import(string $filename, string $filepath, ?array $options = []): ImportResult; /** * Upload file used to import data and create async job linking to it. @@ -89,15 +90,14 @@ abstract public function import($filename, $filepath, ?array $options = []): Imp * @return \App\Core\Result\ImportResult * @throws \LogicException When method is called but missing the async job service name. */ - protected function createAsyncJob($filename, $filepath, ?array $options = []): ImportResult + protected function createAsyncJob(string $filename, string $filepath, ?array $options = []): ImportResult { if (empty(static::getServiceName())) { - throw new \LogicException('Cannot create async job without service name defined.'); + throw new LogicException('Cannot create async job without service name defined.'); } // upload file to import - $file = new File($filepath); /* @phpstan-ignore-line */ - $headers = ['Content-Type' => $file->mime()]; + $headers = ['Content-Type' => mime_content_type($filepath)]; $result = $this->apiClient->upload($filename, $filepath, $headers); // create async_job diff --git a/src/Core/Filter/ReadCSVTrait.php b/src/Core/Filter/ReadCSVTrait.php index a5055fad6..d7353cb17 100644 --- a/src/Core/Filter/ReadCSVTrait.php +++ b/src/Core/Filter/ReadCSVTrait.php @@ -23,7 +23,7 @@ trait ReadCSVTrait * * @var array */ - protected $csvOptions = [ + protected array $csvOptions = [ 'delimiter' => ',', 'enclosure' => '"', 'escape' => '\\', @@ -34,14 +34,14 @@ trait ReadCSVTrait * * @var array */ - protected $csvKeys = []; + protected array $csvKeys = []; /** * CSV file data content organized as associative array with `key` => `value` * * @var array */ - protected $csvData = []; + protected array $csvData = []; /** * Read CSV file and populate `csvKeys` and `csvData` arrays diff --git a/src/Core/Result/ImportResult.php b/src/Core/Result/ImportResult.php index b3e58b61c..a2510d96d 100644 --- a/src/Core/Result/ImportResult.php +++ b/src/Core/Result/ImportResult.php @@ -14,7 +14,7 @@ class ImportResult extends Result * * @var string */ - public $filename; + public string $filename; /** * Constructor @@ -29,13 +29,13 @@ class ImportResult extends Result * @return void */ public function __construct( - $filename = '', - $created = 0, - $updated = 0, - $errors = 0, - $info = '', - $warn = '', - $error = '' + string $filename = '', + int $created = 0, + int $updated = 0, + int $errors = 0, + string $info = '', + string $warn = '', + string $error = '', ) { parent::__construct($created, $updated, $errors, $info, $warn, $error); $this->filename = $filename; diff --git a/src/Core/Result/Result.php b/src/Core/Result/Result.php index a06a7e74f..1485d4f40 100644 --- a/src/Core/Result/Result.php +++ b/src/Core/Result/Result.php @@ -19,42 +19,42 @@ class Result * * @var int */ - public $created; + public int $created; /** * Counter of updated resources * * @var int */ - public $updated; + public int $updated; /** * Counter of errors * * @var int */ - public $errors; + public int $errors; /** * Info message * * @var string */ - public $info; + public string $info; /** * Warning message * * @var string */ - public $warn; + public string $warn; /** * Error message * * @var string */ - public $error; + public string $error; /** * Constructor @@ -68,12 +68,12 @@ class Result * @return void */ public function __construct( - $created = 0, - $updated = 0, - $errors = 0, - $info = '', - $warn = '', - $error = '' + int $created = 0, + int $updated = 0, + int $errors = 0, + string $info = '', + string $warn = '', + string $error = '', ) { $this->created = $created; $this->updated = $updated; diff --git a/src/Form/Control.php b/src/Form/Control.php index 8268b2e18..4aa86c9af 100644 --- a/src/Form/Control.php +++ b/src/Form/Control.php @@ -103,7 +103,7 @@ public static function oneOf(array $schema): array (array)Hash::get($schema, 'oneOf'), function ($item) { return !empty($item) && Hash::get($item, 'type') !== 'null'; - } + }, ); return (array)Hash::get(array_values($oneOf), 0); @@ -213,7 +213,7 @@ public static function categories(array $options): array (array)Hash::get($schema, 'categories'), function ($category) { return (bool)Hash::get($category, 'enabled'); - } + }, )); $options = array_map( function ($category) { @@ -222,7 +222,7 @@ function ($category) { 'text' => empty($category['label']) ? $category['name'] : $category['label'], ]; }, - $categories + $categories, ); $checked = []; @@ -316,7 +316,7 @@ public static function oneOptions(array &$options, array $one): void function ($item) { return ['value' => $item, 'text' => Inflector::humanize($item)]; }, - (array)Hash::extract($one, 'items.enum') + (array)Hash::extract($one, 'items.enum'), ); } @@ -350,7 +350,7 @@ function (string $value) use ($objectType, $property) { return compact('text', 'value'); }, - $schema['enum'] + $schema['enum'], ), 'value' => $value, ]; diff --git a/src/Form/CustomComponentControl.php b/src/Form/CustomComponentControl.php index 47dd1bb13..c66e87903 100644 --- a/src/Form/CustomComponentControl.php +++ b/src/Form/CustomComponentControl.php @@ -54,7 +54,7 @@ public function control(string $name, $value, array $options): array * @param mixed|null $value The value * @return string */ - protected function jsonValue($value): string + protected function jsonValue(mixed $value): string { if (empty($value)) { return ''; diff --git a/src/Form/CustomHandlerInterface.php b/src/Form/CustomHandlerInterface.php index 9a655d751..93978ca43 100644 --- a/src/Form/CustomHandlerInterface.php +++ b/src/Form/CustomHandlerInterface.php @@ -23,5 +23,5 @@ interface CustomHandlerInterface * @param array $options Options array from configuration * @return array */ - public function control(string $name, $value, array $options): array; + public function control(string $name, mixed $value, array $options): array; } diff --git a/src/Form/Form.php b/src/Form/Form.php index 9f5b7ee0c..b1d694ea1 100644 --- a/src/Form/Form.php +++ b/src/Form/Form.php @@ -14,6 +14,7 @@ namespace App\Form; use Cake\Utility\Inflector; +use InvalidArgumentException; /** * Form class provides utilities for \App\Form classes. @@ -34,7 +35,7 @@ class Form * @param string|null $format The format * @return array */ - public static function getMethod(string $className, string $name, $format = ''): array + public static function getMethod(string $className, string $name, ?string $format = ''): array { $methodName = !empty($format) ? $format : Inflector::variable(str_replace('-', '_', $name)); $method = [$className, $methodName]; @@ -42,6 +43,6 @@ public static function getMethod(string $className, string $name, $format = ''): return $method; } - throw new \InvalidArgumentException(sprintf('Method "%s" is not callable', $methodName)); + throw new InvalidArgumentException(sprintf('Method "%s" is not callable', $methodName)); } } diff --git a/src/Form/Options.php b/src/Form/Options.php index c354a1b01..17f518321 100644 --- a/src/Form/Options.php +++ b/src/Form/Options.php @@ -45,7 +45,7 @@ class Options * @param mixed|null $value The field value. * @return array */ - public static function customControl(string $name, $value): array + public static function customControl(string $name, mixed $value): array { if (!in_array($name, Options::CUSTOM_CONTROLS)) { return []; @@ -64,7 +64,7 @@ public static function customControl(string $name, $value): array * @param mixed|null $value The field value. * @return array */ - public static function lang($value): array + public static function lang(mixed $value): array { $languages = Configure::read('Project.config.I18n.languages'); if (empty($languages)) { @@ -84,7 +84,7 @@ public static function lang($value): array * @param mixed|null $value The field value. * @return array */ - public static function dateRanges($value): array + public static function dateRanges(mixed $value): array { return Control::datetime(compact('value')); } @@ -95,7 +95,7 @@ public static function dateRanges($value): array * @param mixed|null $value The field value. * @return array */ - public static function startDate($value): array + public static function startDate(mixed $value): array { return Control::datetime(compact('value')); } @@ -106,7 +106,7 @@ public static function startDate($value): array * @param mixed|null $value The field value. * @return array */ - public static function endDate($value): array + public static function endDate(mixed $value): array { return Control::datetime(compact('value')); } @@ -121,7 +121,7 @@ public static function endDate($value): array * @param mixed|null $value The field value. * @return array */ - public static function status($value): array + public static function status(mixed $value): array { return compact('value') + [ 'type' => 'radio', @@ -142,7 +142,7 @@ public static function status($value): array * @param mixed|null $value The field value. * @return array */ - public static function oldPassword($value): array + public static function oldPassword(mixed $value): array { return compact('value') + [ 'class' => 'password', @@ -160,7 +160,7 @@ public static function oldPassword($value): array * @param mixed|null $value The field value. * @return array */ - public static function password($value): array + public static function password(mixed $value): array { return compact('value') + [ 'class' => 'password', @@ -176,7 +176,7 @@ public static function password($value): array * @param mixed|null $value The field value. * @return array */ - public static function confirmPassword($value): array + public static function confirmPassword(mixed $value): array { return compact('value') + [ 'label' => __('Retype password'), @@ -196,7 +196,7 @@ public static function confirmPassword($value): array * @param mixed|null $value The field value. * @return array */ - public static function title($value): array + public static function title(mixed $value): array { return compact('value') + [ 'class' => 'title', @@ -213,7 +213,7 @@ public static function title($value): array * @param mixed|null $value The field value. * @return array */ - public static function coords($value): array + public static function coords(mixed $value): array { $label = sprintf('', __('Long Lat Coordinates')); $options = json_encode((array)Configure::read('Location.google')); @@ -234,7 +234,7 @@ public static function coords($value): array * @param mixed|null $value The field value. * @return array */ - public static function childrenOrder($value): array + public static function childrenOrder(mixed $value): array { return compact('value') + [ 'type' => 'select', diff --git a/src/Identifier/ApiIdentifier.php b/src/Identifier/ApiIdentifier.php index a596d86c4..b43ab1188 100644 --- a/src/Identifier/ApiIdentifier.php +++ b/src/Identifier/ApiIdentifier.php @@ -13,8 +13,10 @@ namespace App\Identifier; use App\Identifier\Resolver\ApiResolver; +use ArrayAccess; use Authentication\Identifier\AbstractIdentifier; use Authentication\Identifier\Resolver\ResolverAwareTrait; +use Authentication\Identifier\TokenIdentifier; /** * Identifies authentication credentials through an API. @@ -30,7 +32,7 @@ class ApiIdentifier extends AbstractIdentifier * * @var array */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'timezoneField' => 'timezone', 'resolver' => ApiResolver::class, ]; @@ -38,12 +40,12 @@ class ApiIdentifier extends AbstractIdentifier /** * @inheritDoc */ - public function identify(array $credentials) + public function identify(array $credentials): array|ArrayAccess|null { if ( - empty($credentials[self::CREDENTIAL_USERNAME]) && - empty($credentials[self::CREDENTIAL_PASSWORD]) && - empty($credentials[self::CREDENTIAL_TOKEN]) + empty($credentials[AbstractIdentifier::CREDENTIAL_USERNAME]) && + empty($credentials[AbstractIdentifier::CREDENTIAL_PASSWORD]) && + empty($credentials[TokenIdentifier::CREDENTIAL_TOKEN]) ) { return null; } @@ -57,7 +59,7 @@ public function identify(array $credentials) * @param array $credentials The user credentials * @return array|\ArrayAccess|null */ - protected function findIdentity(array $credentials) + protected function findIdentity(array $credentials): array|ArrayAccess|null { $identity = $this->getResolver()->find($credentials); if (empty($identity)) { @@ -71,8 +73,8 @@ protected function findIdentity(array $credentials) } // Flatten username and renew token in identity - $identity[self::CREDENTIAL_USERNAME] = $identity['attributes']['username']; - $identity[self::CREDENTIAL_TOKEN] = $identity['tokens']['renew']; + $identity[AbstractIdentifier::CREDENTIAL_USERNAME] = $identity['attributes']['username']; + $identity[TokenIdentifier::CREDENTIAL_TOKEN] = $identity['tokens']['renew']; return $identity; } diff --git a/src/Identifier/Resolver/ApiResolver.php b/src/Identifier/Resolver/ApiResolver.php index cfc258a3f..34e82a01c 100644 --- a/src/Identifier/Resolver/ApiResolver.php +++ b/src/Identifier/Resolver/ApiResolver.php @@ -12,7 +12,7 @@ */ namespace App\Identifier\Resolver; -use Authentication\Identifier\IdentifierInterface; +use ArrayAccess; use Authentication\Identifier\Resolver\ResolverInterface; use BEdita\SDK\BEditaClientException; use BEdita\WebTools\ApiClientProvider; @@ -27,13 +27,13 @@ class ApiResolver implements ResolverInterface /** * @inheritDoc */ - public function find(array $conditions, $type = self::TYPE_AND) + public function find(array $conditions, string $type = self::TYPE_AND): ArrayAccess|array|null { $apiClient = ApiClientProvider::getApiClient(); - if (isset($conditions[IdentifierInterface::CREDENTIAL_USERNAME], $conditions[IdentifierInterface::CREDENTIAL_PASSWORD])) { + if (isset($conditions['username'], $conditions['password'])) { // Authenticate with credentials try { - $result = $apiClient->authenticate($conditions[IdentifierInterface::CREDENTIAL_USERNAME], $conditions[IdentifierInterface::CREDENTIAL_PASSWORD]); + $result = $apiClient->authenticate($conditions['username'], $conditions['password']); } catch (BEditaClientException $e) { Log::info(sprintf('Login failed - %s', $e->getMessage())); @@ -47,9 +47,9 @@ public function find(array $conditions, $type = self::TYPE_AND) } $apiClient->setupTokens($result['meta']); - } elseif (isset($conditions[IdentifierInterface::CREDENTIAL_TOKEN])) { + } elseif (isset($conditions['token'])) { // Authenticate with renew token - $apiClient->setupTokens(['renew' => $conditions[IdentifierInterface::CREDENTIAL_TOKEN]]); + $apiClient->setupTokens(['renew' => $conditions['token']]); try { $apiClient->refreshTokens(); } catch (BEditaClientException $e) { diff --git a/src/Middleware/ProjectMiddleware.php b/src/Middleware/ProjectMiddleware.php index ccea80151..0d9fa6607 100644 --- a/src/Middleware/ProjectMiddleware.php +++ b/src/Middleware/ProjectMiddleware.php @@ -32,14 +32,14 @@ class ProjectMiddleware implements MiddlewareInterface * * @var \App\Application */ - protected $Application; + protected Application $Application; /** * Projects config base path * * @var string */ - protected $projectsConfigPath = CONFIG . 'projects' . DS; + protected string $projectsConfigPath = CONFIG . 'projects' . DS; /** * Constructor diff --git a/src/Middleware/RecoveryMiddleware.php b/src/Middleware/RecoveryMiddleware.php index d60717033..c7d3e4755 100644 --- a/src/Middleware/RecoveryMiddleware.php +++ b/src/Middleware/RecoveryMiddleware.php @@ -4,6 +4,7 @@ namespace App\Middleware; use Authentication\AuthenticationServiceInterface; +use Authentication\Authenticator\UnauthenticatedException; use Cake\Core\Configure; use Cake\Http\Client\Response; use Psr\Http\Message\ResponseInterface; @@ -55,7 +56,7 @@ private function check(ServerRequestInterface $request): ServerRequestInterface $service->clearIdentity($request, new Response()); /** @var \Cake\Http\ServerRequest $sr */ $sr = $request; - $ex = new \Authentication\Authenticator\UnauthenticatedException(); + $ex = new UnauthenticatedException(); $sr->getFlash()->setExceptionMessage($ex); throw $ex; diff --git a/src/Utility/ApiClientTrait.php b/src/Utility/ApiClientTrait.php index ac646abad..e1e799ca2 100644 --- a/src/Utility/ApiClientTrait.php +++ b/src/Utility/ApiClientTrait.php @@ -27,7 +27,7 @@ trait ApiClientTrait * * @var \BEdita\SDK\BEditaClient|null */ - protected $apiClient = null; + protected ?BEditaClient $apiClient = null; /** * Get API client. diff --git a/src/Utility/ApiConfigTrait.php b/src/Utility/ApiConfigTrait.php index 812f9eabc..d52872d47 100644 --- a/src/Utility/ApiConfigTrait.php +++ b/src/Utility/ApiConfigTrait.php @@ -33,14 +33,14 @@ trait ApiConfigTrait * * @var string */ - protected static $cacheKey = 'api_config'; + protected static string $cacheKey = 'api_config'; /** * Allowed configuration keys from API * * @var array */ - protected static $configKeys = [ + protected static array $configKeys = [ 'AccessControl', 'AlertMessage', 'AlertMessageByArea', @@ -64,7 +64,7 @@ protected function readApiConfig(): void CacheTools::cacheKey(static::$cacheKey), function () { return $this->fetchConfig(); - } + }, ); } catch (BEditaClientException $e) { Log::error($e->getMessage()); @@ -82,7 +82,7 @@ function () { /** * Fetch configurations from API * - * @param null|string $key Configuration key to fetch, fetch all keys if null. + * @param string|null $key Configuration key to fetch, fetch all keys if null. * @return array */ protected function fetchConfig(?string $key = null): array diff --git a/src/Utility/Applications.php b/src/Utility/Applications.php index 601858cbc..c0ae4ce23 100644 --- a/src/Utility/Applications.php +++ b/src/Utility/Applications.php @@ -26,9 +26,9 @@ class Applications /** * Applications * - * @var array + * @var array|null */ - public static $applications = null; + public static ?array $applications = null; /** * Get application name by application ID @@ -59,7 +59,7 @@ function () { $response = (array)ApiClientProvider::getApiClient()->get('applications'); return Hash::combine($response, 'data.{n}.id', 'data.{n}.attributes.name'); - } + }, ); } catch (BEditaClientException $e) { return []; diff --git a/src/Utility/DateRangesTools.php b/src/Utility/DateRangesTools.php index 2c351cb95..45f8744a4 100644 --- a/src/Utility/DateRangesTools.php +++ b/src/Utility/DateRangesTools.php @@ -38,7 +38,7 @@ function ($item) { $ed = (string)Hash::get($item, 'end_date'); return !empty($sd) || !empty($ed); - } + }, ); $dateRanges = array_map( function ($item) { @@ -50,7 +50,7 @@ function ($item) { return $item; }, - $dateRanges + $dateRanges, ); foreach ($dateRanges as &$item) { if (empty(Hash::get($item, 'params'))) { @@ -161,7 +161,7 @@ public static function toString(array $dateRanges): string '%s-%s-%s', $startDate, $endDate, - $params + $params, ); } diff --git a/src/Utility/Message.php b/src/Utility/Message.php index 7c4b71157..3c85f534d 100644 --- a/src/Utility/Message.php +++ b/src/Utility/Message.php @@ -28,21 +28,21 @@ class Message * * @var string */ - protected $title; + protected string $title; /** * Message detail text. * * @var string */ - protected $detail; + protected string $detail; /** * Remap of error messages. * * @var array */ - protected $remap; + protected array $remap; /** * Constructor diff --git a/src/Utility/OEmbed.php b/src/Utility/OEmbed.php index 5d939a389..cd7900f95 100644 --- a/src/Utility/OEmbed.php +++ b/src/Utility/OEmbed.php @@ -29,7 +29,7 @@ class OEmbed * @param string $url Media remote URL * @return array Media metadata, empty array if no data is found */ - public function readMetadata($url): array + public function readMetadata(string $url): array { $parsed = parse_url($url); $host = Hash::get($parsed, 'host', ''); diff --git a/src/Utility/PermissionsTrait.php b/src/Utility/PermissionsTrait.php index 6f845114a..16162a870 100644 --- a/src/Utility/PermissionsTrait.php +++ b/src/Utility/PermissionsTrait.php @@ -62,7 +62,7 @@ public function addPermissions(string $objectId, array $roleIds): void foreach ($roleIds as $roleId) { ApiClientProvider::getApiClient()->save( 'object_permissions', - ['object_id' => $objectId, 'role_id' => $roleId] + ['object_id' => $objectId, 'role_id' => $roleId], ); } } @@ -110,7 +110,7 @@ public function roles(): array return Hash::combine( (array)ApiClientProvider::getApiClient()->get('/roles'), 'data.{n}.id', - 'data.{n}.attributes.name' + 'data.{n}.attributes.name', ); }); } diff --git a/src/Utility/RelationsTools.php b/src/Utility/RelationsTools.php index 23201f327..390425b51 100644 --- a/src/Utility/RelationsTools.php +++ b/src/Utility/RelationsTools.php @@ -40,7 +40,7 @@ public static function toString(array $relations): string '%s-%s-%s', $id, $type, - $meta + $meta, ); } diff --git a/src/Utility/SchemaTrait.php b/src/Utility/SchemaTrait.php index c89e0f485..9ab468bd7 100644 --- a/src/Utility/SchemaTrait.php +++ b/src/Utility/SchemaTrait.php @@ -41,7 +41,7 @@ function () { $client = ApiClientProvider::getApiClient(); return $client->get('/home'); - } + }, ); } catch (BEditaClientException $e) { // Something bad happened. Returning an empty array instead. diff --git a/src/View/AjaxView.php b/src/View/AjaxView.php index cdec85194..aca391eef 100644 --- a/src/View/AjaxView.php +++ b/src/View/AjaxView.php @@ -26,7 +26,7 @@ class AjaxView extends AppView * * @var string */ - public $layout = 'ajax'; + public string $layout = 'ajax'; /** * Initialization hook method. diff --git a/src/View/Helper/AdminHelper.php b/src/View/Helper/AdminHelper.php index 7d713d98d..547e8b475 100644 --- a/src/View/Helper/AdminHelper.php +++ b/src/View/Helper/AdminHelper.php @@ -30,21 +30,21 @@ class AdminHelper extends Helper * * @var array */ - public $helpers = ['Form', 'Property', 'Schema']; + public array $helpers = ['Form', 'Property', 'Schema']; /** * Object containing i18n strings * * @var array */ - protected $dictionary = []; + protected array $dictionary = []; /** * Options * * @var array */ - protected $options = []; + protected array $options = []; /** * @inheritDoc @@ -89,7 +89,7 @@ public function initialize(array $config): void * @param mixed $value The value * @return string */ - public function control(string $type, string $property, $value): string + public function control(string $type, string $property, mixed $value): string { $readonly = (bool)$this->_View->get('readonly'); $resource = (array)$this->_View->get('resource'); diff --git a/src/View/Helper/ArrayHelper.php b/src/View/Helper/ArrayHelper.php index 5f292c2c5..6d502afbf 100644 --- a/src/View/Helper/ArrayHelper.php +++ b/src/View/Helper/ArrayHelper.php @@ -77,7 +77,7 @@ public function onlyKeys(array $arr, array $keys): array * @param string $path The path expression * @return array The result array */ - public function extract($data, $path): array + public function extract(array $data, string $path): array { return (array)Hash::extract($data, $path); } diff --git a/src/View/Helper/CalendarHelper.php b/src/View/Helper/CalendarHelper.php index ff0c20668..1789cb795 100644 --- a/src/View/Helper/CalendarHelper.php +++ b/src/View/Helper/CalendarHelper.php @@ -27,7 +27,7 @@ class CalendarHelper extends Helper * * @var array */ - public $helpers = ['Time']; + public array $helpers = ['Time']; /** * Get calendar date ranges list html diff --git a/src/View/Helper/CategoriesHelper.php b/src/View/Helper/CategoriesHelper.php index 4b22e8970..30fd1dc13 100644 --- a/src/View/Helper/CategoriesHelper.php +++ b/src/View/Helper/CategoriesHelper.php @@ -23,7 +23,12 @@ */ class CategoriesHelper extends Helper { - public $helpers = ['Form', 'Property']; + /** + * Helpers + * + * @var array + */ + public array $helpers = ['Form', 'Property']; /** * Control for categories @@ -32,14 +37,14 @@ class CategoriesHelper extends Helper * @param mixed|null $value The value * @return string */ - public function control(string $name, $value): string + public function control(string $name, mixed $value): string { $options = ['label' => false]; if (!$this->isTree()) { return sprintf( '

%s

%s
', __('Global'), - $this->Property->control($name, $value, $options) + $this->Property->control($name, $value, $options), ); } @@ -54,7 +59,7 @@ public function control(string $name, $value): string * @param array $options The options * @return string */ - public function html(string $name, $value, array $options): string + public function html(string $name, mixed $value, array $options): string { $html = ''; $tree = $this->tree(); @@ -76,7 +81,7 @@ public function html(string $name, $value, array $options): string * @param bool $hiddenField The hiddenField flag * @return string */ - public function node(array $node, string $name, $value, array $options, bool &$hiddenField): string + public function node(array $node, string $name, mixed $value, array $options, bool &$hiddenField): string { $title = sprintf('

%s

', $node['label'] = $node['label'] ?: $node['name']); $controlOptions = $this->controlOptions($node, $value, $options, $hiddenField); @@ -84,7 +89,7 @@ public function node(array $node, string $name, $value, array $options, bool &$h return sprintf( '
%s%s
', $title, - $this->Form->control($name, $controlOptions) + $this->Form->control($name, $controlOptions), ); } @@ -97,7 +102,7 @@ public function node(array $node, string $name, $value, array $options, bool &$h * @param bool $hiddenField The hiddenField flag * @return array */ - public function controlOptions(array $node, $value, array $options, bool &$hiddenField): array + public function controlOptions(array $node, mixed $value, array $options, bool &$hiddenField): array { $controlOptions = $options + [ 'type' => 'select', @@ -180,7 +185,7 @@ public function sortRoots(array $a, array $b): int { return strcmp( strtolower((string)Hash::get($a, 'name')), - strtolower((string)Hash::get($b, 'name')) + strtolower((string)Hash::get($b, 'name')), ); } diff --git a/src/View/Helper/LayoutHelper.php b/src/View/Helper/LayoutHelper.php index 44c89e7c3..e67e0245b 100644 --- a/src/View/Helper/LayoutHelper.php +++ b/src/View/Helper/LayoutHelper.php @@ -12,10 +12,12 @@ */ namespace App\View\Helper; +use App\Plugin; use App\Utility\CacheTools; use App\Utility\Translate; use Cake\Cache\Cache; use Cake\Core\Configure; +use Cake\I18n\I18n; use Cake\Utility\Hash; use Cake\View\Helper; @@ -36,7 +38,7 @@ class LayoutHelper extends Helper * * @var array */ - public $helpers = ['Editors', 'Html', 'Link', 'Perms', 'System', 'Url']; + public array $helpers = ['Editors', 'Html', 'Link', 'Perms', 'System', 'Url']; /** * Is Dashboard @@ -138,7 +140,7 @@ public function dashboardModuleLink(string $name, array $module): string sprintf('dashboard-item has-background-module-%s %s', $name, Hash::get($module, 'class', '')), $this->tr($label), $this->moduleIcon($name, $module), - $count + $count, ); } @@ -257,7 +259,7 @@ public function moduleLink(): string sprintf('module-item has-background-module-%s', $name), $this->tr($label), $this->moduleIcon($name, $currentModule), - $count + $count, ); } @@ -265,7 +267,7 @@ public function moduleLink(): string return $this->Html->link( $this->tr($this->getView()->getName()), (array)$this->getView()->get('moduleLink'), - ['class' => $this->commandLinkClass()] + ['class' => $this->commandLinkClass()], ); } @@ -363,9 +365,9 @@ public function metaConfig(): array 'currentModule' => $this->getView()->get('currentModule', ['name' => 'home']), 'template' => $this->getView()->getTemplate(), 'modules' => array_keys($this->getView()->get('modules', [])), - 'plugins' => \App\Plugin::loadedAppPlugins(), + 'plugins' => Plugin::loadedAppPlugins(), 'uploadable' => $this->getView()->get('uploadable', []), - 'locale' => \Cake\I18n\I18n::getLocale(), + 'locale' => I18n::getLocale(), 'csrfToken' => $this->getCsrfToken(), 'maxFileSize' => $this->System->getMaxFileSize(), 'canReadUsers' => $this->Perms->canRead('users'), @@ -448,7 +450,7 @@ public function trashLink(?string $type): string return $this->Html->link( sprintf('%s', __('Trash')), ['_name' => 'trash:list', '?' => compact('filter')], - ['class' => $classes, 'title' => $title, 'escape' => false] + ['class' => $classes, 'title' => $title, 'escape' => false], ); } diff --git a/src/View/Helper/LinkHelper.php b/src/View/Helper/LinkHelper.php index 98fcf3787..d26e88d3d 100644 --- a/src/View/Helper/LinkHelper.php +++ b/src/View/Helper/LinkHelper.php @@ -30,7 +30,7 @@ class LinkHelper extends Helper * * @var array */ - public $helpers = ['Html']; + public array $helpers = ['Html']; /** * {@inheritDoc} @@ -43,7 +43,7 @@ class LinkHelper extends Helper * - 'manifestPath': Manifest file path * - 'manifest': Manifest content (array) */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'apiBaseUrl' => '', 'webBaseUrl' => '', 'query' => [], @@ -95,7 +95,7 @@ public function baseUrl(): string * @param string $apiUrl Api url * @return void */ - public function fromAPI($apiUrl): void + public function fromAPI(string $apiUrl): void { echo str_replace($this->getConfig('apiBaseUrl'), $this->getConfig('webBaseUrl'), $apiUrl); } @@ -107,7 +107,7 @@ public function fromAPI($apiUrl): void * @param bool $resetPage flag to reset pagination. * @return string */ - public function sortUrl($field, $resetPage = true): string + public function sortUrl(string $field, bool $resetPage = true): string { $sort = (string)Hash::get($this->getConfig('query'), 'sort'); $sort = $this->sortValue($field, $sort); @@ -182,7 +182,7 @@ public function sortClass(string $field): string * @param int $page destination page. * @return void */ - public function page($page): void + public function page(int $page): void { echo $this->replaceQueryParams(['page' => $page]); } @@ -193,7 +193,7 @@ public function page($page): void * @param int $pageSize new page size. * @return void */ - public function pageSize($pageSize): void + public function pageSize(int $pageSize): void { echo $this->replaceQueryParams(['page_size' => $pageSize]); } @@ -204,13 +204,13 @@ public function pageSize($pageSize): void * @param array $options options for query * @return string url */ - public function here($options = []): string + public function here(array $options = []): string { $url = (string)$this->getConfig('webBaseUrl'); $here = sprintf( '%s%s', $url, - $this->getView()->getRequest()->getAttribute('here') + $this->getView()->getRequest()->getAttribute('here'), ); $query = (array)$this->getConfig('query'); if (empty($query) || !empty($options['no-query'])) { diff --git a/src/View/Helper/PermsHelper.php b/src/View/Helper/PermsHelper.php index 5164344a3..95262bfc3 100644 --- a/src/View/Helper/PermsHelper.php +++ b/src/View/Helper/PermsHelper.php @@ -26,21 +26,21 @@ class PermsHelper extends Helper * * @var array */ - protected $current = []; + protected array $current = []; /** * API methods allowed in all modules * * @var array */ - protected $allowed = []; + protected array $allowed = []; /** * Permissions on folders enabled flag * * @var bool */ - protected $permissionsOnFolders = false; + protected bool $permissionsOnFolders = false; /** * {@inheritDoc} @@ -100,8 +100,8 @@ public function canCreateModules(): array $modules, function ($module) { return $this->canCreate($module); - } - ) + }, + ), ); } diff --git a/src/View/Helper/PropertyHelper.php b/src/View/Helper/PropertyHelper.php index dcd4278f1..1b6695bae 100644 --- a/src/View/Helper/PropertyHelper.php +++ b/src/View/Helper/PropertyHelper.php @@ -20,6 +20,7 @@ use Cake\Core\Configure; use Cake\Utility\Hash; use Cake\View\Helper; +use Throwable; /** * Helper class to generate properties html @@ -34,7 +35,7 @@ class PropertyHelper extends Helper * * @var array */ - public $helpers = ['Form', 'Schema']; + public array $helpers = ['Form', 'Schema']; /** * Special paths to retrieve properties from related resources @@ -69,7 +70,7 @@ class PropertyHelper extends Helper * @param string|null $type The object or resource type, for others schemas * @return string */ - public function control(string $name, $value, array $options = [], ?string $type = null): string + public function control(string $name, mixed $value, array $options = [], ?string $type = null): string { $forceReadonly = !empty(Hash::get($options, 'readonly')); $controlOptions = $this->Schema->controlOptions($name, $value, $this->schema($name, $type)); @@ -101,7 +102,7 @@ public function control(string $name, $value, array $options = [], ?string $type * @param array $options The form element options, if any * @return string */ - public function translationControl(string $name, $value, array $options = []): string + public function translationControl(string $name, mixed $value, array $options = []): string { $formControlName = sprintf('translated_fields[%s]', $name); $controlOptions = $this->Schema->controlOptions($name, $value, $this->schema($name, null)); @@ -227,7 +228,7 @@ function () { function ($val, $key) use ($removeKeys) { return is_string($val) && !in_array($key, $removeKeys); }, - ARRAY_FILTER_USE_BOTH + ARRAY_FILTER_USE_BOTH, ); return array_merge($carry, $groupKeys); @@ -257,7 +258,7 @@ function ($val, $key) use ($removeKeys) { function ($val, $key) use ($removeKeys) { return is_string($val) && !in_array($key, $removeKeys); }, - ARRAY_FILTER_USE_BOTH + ARRAY_FILTER_USE_BOTH, ); return array_merge($carry, $groupKeys); @@ -278,9 +279,9 @@ function ($val, $key) use ($removeKeys) { } return $map; - } + }, ); - } catch (\Throwable $e) { + } catch (Throwable $e) { $map = []; } diff --git a/src/View/Helper/SchemaHelper.php b/src/View/Helper/SchemaHelper.php index 5b82aa320..d481c6183 100644 --- a/src/View/Helper/SchemaHelper.php +++ b/src/View/Helper/SchemaHelper.php @@ -35,7 +35,7 @@ class SchemaHelper extends Helper * * @var array */ - public $helpers = ['Perms', 'Time']; + public array $helpers = ['Perms', 'Time']; /** * Default translatable fields to be prepended in translations @@ -59,7 +59,7 @@ class SchemaHelper extends Helper * @param array|null $schema Property schema. * @return array */ - public function controlOptions(string $name, $value, ?array $schema = null): array + public function controlOptions(string $name, mixed $value, ?array $schema = null): array { $options = Options::customControl($name, $value); $objectType = (string)$this->_View->get('objectType'); @@ -114,7 +114,7 @@ public function controlOptions(string $name, $value, ?array $schema = null): arr * @param array $options Control options * @return void */ - protected function updateRicheditorOptions(string $name, bool $placeholders, array &$options) + protected function updateRicheditorOptions(string $name, bool $placeholders, array &$options): void { $uiRichtext = (array)Configure::read(sprintf('UI.richeditor.%s.toolbar', $name)); if (empty($uiRichtext)) { @@ -136,7 +136,7 @@ protected function updateRicheditorOptions(string $name, bool $placeholders, arr * @param array $options Control options. * @return array|null */ - protected function customControl($name, $value, array $options): ?array + protected function customControl(string $name, mixed $value, array $options): ?array { $handlerClass = Hash::get($options, 'handler'); if (empty($handlerClass)) { @@ -152,10 +152,10 @@ protected function customControl($name, $value, array $options): ?array * Display a formatted property value using schema. * * @param mixed $value Property value. - * @param array $schema Property schema array. + * @param array|null $schema Property schema array. * @return string */ - public function format($value, $schema = []): string + public function format(mixed $value, ?array $schema = []): string { $type = static::typeFromSchema((array)$schema); $type = Inflector::variable(str_replace('-', '_', $type)); @@ -176,7 +176,7 @@ public function format($value, $schema = []): string * @param mixed $value Property value. * @return string */ - public function formatByte($value): string + public function formatByte(mixed $value): string { return Number::toReadableSize((int)$value); } @@ -187,7 +187,7 @@ public function formatByte($value): string * @param mixed $value Property value. * @return string */ - public function formatBoolean($value): string + public function formatBoolean(mixed $value): string { $res = filter_var($value, FILTER_VALIDATE_BOOLEAN); @@ -200,7 +200,7 @@ public function formatBoolean($value): string * @param mixed $value Property value. * @return string */ - public function formatDate($value): string + public function formatDate(mixed $value): string { if (empty($value)) { return ''; @@ -215,7 +215,7 @@ public function formatDate($value): string * @param mixed $value Property value. * @return string */ - public function formatDateTime($value): string + public function formatDateTime(mixed $value): string { return $this->formatDate($value); } @@ -273,7 +273,7 @@ public function translatableFields(array $schema): array $priorityFields = array_intersect(static::DEFAULT_TRANSLATABLE, array_keys($properties)); $otherFields = array_keys(array_filter( array_diff_key($properties, array_flip($priorityFields)), - [$this, 'translatableType'] + [$this, 'translatableType'], )); } @@ -297,7 +297,7 @@ function ($carry, $item) { } return $this->translatableType((array)$item); - } + }, ); } // accept as translatable 'string' type having text/html or tex/plain 'contentMediaType' diff --git a/src/View/Helper/SystemHelper.php b/src/View/Helper/SystemHelper.php index 0add6bf2e..1522e3347 100644 --- a/src/View/Helper/SystemHelper.php +++ b/src/View/Helper/SystemHelper.php @@ -29,7 +29,7 @@ class SystemHelper extends Helper * * @var array */ - protected $defaultPlaceholders = [ + protected array $defaultPlaceholders = [ 'audio' => ['controls' => 'boolean', 'autoplay' => 'boolean'], 'files' => ['download' => 'boolean'], 'images' => ['width' => 'integer', 'height' => 'integer', 'bearing' => 'integer', 'pitch' => 'integer', 'zoom' => 'integer'], @@ -41,7 +41,7 @@ class SystemHelper extends Helper * * @var array */ - protected $defaultUploadAccepted = [ + protected array $defaultUploadAccepted = [ 'audio' => [ 'audio/*', ], @@ -59,7 +59,7 @@ class SystemHelper extends Helper * * @var array */ - protected $defaultUploadForbidden = [ + protected array $defaultUploadForbidden = [ 'mimetypes' => [ 'application/javascript', 'application/x-cgi', @@ -105,7 +105,7 @@ class SystemHelper extends Helper * * @var string */ - protected $defaultUploadMaxResolution = '4096x2160'; // 4K + protected string $defaultUploadMaxResolution = '4096x2160'; // 4K /** * Get the minimum value between post_max_size and upload_max_filesize. diff --git a/templates/Element/FilterBox/filter_box.scss b/templates/Element/FilterBox/filter_box.scss index 7d6788973..72ecebc5c 100644 --- a/templates/Element/FilterBox/filter_box.scss +++ b/templates/Element/FilterBox/filter_box.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + .filter-box { display: flex; flex-direction: column; @@ -25,16 +27,16 @@ margin-bottom: 0 !important; > * { - margin-bottom: $gutter; + margin-bottom: variables.$gutter; } > *:not(:last-child) { - margin-right: $gutter; + margin-right: variables.$gutter; } } .more-filters { - margin-top: $gutter; + margin-top: variables.$gutter; } .filter-container { @@ -45,7 +47,7 @@ display: flex; input[type="text"] { width: 100%; - min-width: $gutter * 12; + min-width: variables.$gutter * 12; } } @@ -57,7 +59,7 @@ label { display: inline-flex; align-items: center; - margin-right: $gutter * .5; + margin-right: variables.$gutter * .5; &:first-letter { text-transform: uppercase; @@ -72,7 +74,7 @@ display: flex; > * + * { - margin-left: $gutter * .5; + margin-left: variables.$gutter * .5; } input { @@ -94,7 +96,7 @@ .descendants-filter { display: flex; align-items: center; - margin-left: $gutter; + margin-left: variables.$gutter; } } } diff --git a/templates/Element/Form/calendar.scss b/templates/Element/Form/calendar.scss index 799199fac..3bee953cc 100644 --- a/templates/Element/Form/calendar.scss +++ b/templates/Element/Form/calendar.scss @@ -1,18 +1,20 @@ +@use "../../../resources/styles/variables"; + .date-ranges-list { display: flex; flex-direction: column; - margin-bottom: $gutter; + margin-bottom: variables.$gutter; .date-ranges-item { display: grid; grid-template-columns: 250px 250px 1fr 1fr 1fr; - gap: $gutter; - margin-bottom: $gutter * .5; + gap: variables.$gutter; + margin-bottom: variables.$gutter * .5; align-items: flex-end; .weekdays { grid-column-start: 1; - grid-column-gap: $gutter * .5; + grid-column-gap: variables.$gutter * .5; grid-column-end: 5; label { diff --git a/templates/Element/Form/categories.scss b/templates/Element/Form/categories.scss index 5c3c654bf..2f2f80c86 100644 --- a/templates/Element/Form/categories.scss +++ b/templates/Element/Form/categories.scss @@ -1,6 +1,8 @@ +@use "../../../resources/styles/variables"; + .categories-container { .categories { - margin: $gutter 0; + margin: variables.$gutter 0; .select { columns: 2 auto; @@ -13,10 +15,10 @@ } + .categories { - margin-top: $gutter * 2; + margin-top: variables.$gutter * 2; &:last-child { - margin-bottom: $gutter * 4; + margin-bottom: variables.$gutter * 4; } } } diff --git a/templates/Element/Form/form.scss b/templates/Element/Form/form.scss index 5f1297a18..8562fe5af 100644 --- a/templates/Element/Form/form.scss +++ b/templates/Element/Form/form.scss @@ -1,10 +1,12 @@ +@use "../../../resources/styles/variables"; + .object-form { .fieldset > .tab-container, .fieldset > .container { - padding: $gutter 0 0 0; + padding: variables.$gutter 0 0 0; > div { - margin: $gutter 0; + margin: variables.$gutter 0; &:first-child { margin: 0; @@ -12,8 +14,8 @@ } .history-field { - border: dashed $gray-600 1px; - padding: $gutter * .5; + border: dashed variables.$gray-600 1px; + padding: variables.$gutter * .5; } .history-field > label { @@ -22,14 +24,14 @@ .input.title, .input.uri { input[type=text] { - font-size: $font-size-llg; + font-size: variables.$font-size-llg; } } @media screen and (min-width: 1024px) { grid-template-columns: repeat( auto-fit, minmax(212px, 1fr) ); display: grid; - grid-gap: $gutter * 1.5 $gutter; + grid-gap: variables.$gutter * 1.5 variables.$gutter; > div { margin: 0; @@ -45,15 +47,15 @@ } .create-media-box { - padding: $gutter * .5 $gutter $gutter * 1.25; - margin-bottom: $gutter * 1.5; - background-color: $gray-800; + padding: variables.$gutter * .5 variables.$gutter variables.$gutter * 1.25; + margin-bottom: variables.$gutter * 1.5; + background-color: variables.$gray-800; border-radius: 4px; } - #{$text-inputs}, textarea { + #{variables.$text-inputs}, textarea { width: 100%; - background-color: $gray-200; + background-color: variables.$gray-200; &:disabled { opacity: 0.65; @@ -61,9 +63,9 @@ } } - #{$text-inputs} { + #{variables.$text-inputs} { &.input-narrow { - max-width: 4 * $gutter; + max-width: 4 * variables.$gutter; } } @@ -74,7 +76,7 @@ .select { select { - min-width: 12 * $gutter; + min-width: 12 * variables.$gutter; } label { cursor: pointer; @@ -84,18 +86,18 @@ label { display: block; flex: 1 0 100%; - line-height: $gutter * 1.75; + line-height: variables.$gutter * 1.75; } .stream { display: flex; } .thumb { - background-color: $gray-400; + background-color: variables.$gray-400; display: inline-block; a { display: block; - background-image: linear-gradient(45deg, $gray-300 25%, transparent 25%), linear-gradient(-45deg, $gray-300 25%, transparent 25%), linear-gradient(45deg, transparent 75%, $gray-300 75%), linear-gradient(-45deg, transparent 75%, $gray-300 75%); + background-image: linear-gradient(45deg, variables.$gray-300 25%, transparent 25%), linear-gradient(-45deg, variables.$gray-300 25%, transparent 25%), linear-gradient(45deg, transparent 75%, variables.$gray-300 75%), linear-gradient(-45deg, transparent 75%, variables.$gray-300 75%); background-size: 20px 20px; background-position: 0 0, 0 10px, 10px -10px, -10px 0px; img { @@ -126,7 +128,7 @@ label:not(:first-child) { flex: 0 0 auto; - margin-right: $gutter; + margin-right: variables.$gutter; cursor: pointer; } } @@ -139,7 +141,7 @@ height: 2.125rem; max-width: auto; min-width: auto; - border: 1px solid $gray-900; + border: 1px solid variables.$gray-900; text-align: center; padding:0; } diff --git a/templates/Element/Form/history.scss b/templates/Element/Form/history.scss index 624e2dd3e..2ab125b01 100644 --- a/templates/Element/Form/history.scss +++ b/templates/Element/Form/history.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + .history { .history-content { $module-color: var(--module-color); @@ -42,7 +44,7 @@ &:last-of-type { padding-bottom: 1rem; - border-image: linear-gradient(to bottom, $gray-600 0 1.4rem, transparent 1.4rem 100%) 1; + border-image: linear-gradient(to bottom, variables.$gray-600 0 1.4rem, transparent 1.4rem 100%) 1; } } } diff --git a/templates/Element/Form/locations.scss b/templates/Element/Form/locations.scss index c15fbfefd..c0bdbbd70 100644 --- a/templates/Element/Form/locations.scss +++ b/templates/Element/Form/locations.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + .locations { input, .order { @@ -18,17 +20,17 @@ .get-coordinates { border-bottom-left-radius: 0; border-top-left-radius: 0; - background-color: $defaultBackground; - border-color: $white; - color: $white; + background-color: variables.$defaultBackground; + border-color: variables.$white; + color: variables.$white; } } button { text-transform: uppercase; - background-color: $defaultBackground; - border-color: $white; - color: $white; + background-color: variables.$defaultBackground; + border-color: variables.$white; + color: variables.$white; } .location-form { @@ -50,16 +52,16 @@ ul { margin: 0; - background-color: $white; + background-color: variables.$white; max-height: 15em; overflow: auto; padding: 0 0.5rem; li { list-style-type: none; - color: $defaultBackground; + color: variables.$defaultBackground; padding: 0 0.5rem; - border-bottom: 1px solid $gray-500; + border-bottom: 1px solid variables.$gray-500; } } @@ -89,7 +91,7 @@ } .autocomplete-title-result, .autocomplete-address-result { - border-top: 1px solid $white; + border-top: 1px solid variables.$white; padding: 1rem; background: transparent; } @@ -98,7 +100,7 @@ padding: 1rem; text-transform: uppercase; font-size: 0.75rem; - background: $white; + background: variables.$white; } .location-data { diff --git a/templates/Element/Form/mail_preview.twig b/templates/Element/Form/mail_preview.twig new file mode 100644 index 000000000..080d29233 --- /dev/null +++ b/templates/Element/Form/mail_preview.twig @@ -0,0 +1,2 @@ + + diff --git a/templates/Element/Form/map.scss b/templates/Element/Form/map.scss index 7e6c82c6e..f3681ac16 100644 --- a/templates/Element/Form/map.scss +++ b/templates/Element/Form/map.scss @@ -1,6 +1,8 @@ +@use "../../../resources/styles/variables"; + .map-container { - min-height: 18 * $gutter; - color: $gray-950; + min-height: 18 * variables.$gutter; + color: variables.$gray-950; user-select: none; position: relative; @@ -34,16 +36,16 @@ z-index:1; } .mapboxgl-compare .compare-swiper-vertical { - background-color: $gray-800; + background-color: variables.$gray-800; box-shadow: inset 0 0 0 2px #fff; display: inline-block; - border-radius: $gutter * .5; + border-radius: variables.$gutter * .5; position: absolute; - width: $gutter * 3; - height: $gutter * 2; + width: variables.$gutter * 3; + height: variables.$gutter * 2; bottom: 15%; - left: -$gutter * 1.5; - margin: -$gutter * 1.5 1px 0; + left: -(variables.$gutter) * 1.5; + margin: -(variables.$gutter) * 1.5 1px 0; color: #fff; cursor: ew-resize; background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjYwIiAgIGhlaWdodD0iNjAiICAgdmVyc2lvbj0iMS4xIiAgIHZpZXdCb3g9IjAgMCA2MCA2MCIgICBpZD0ic3ZnNTQzNCIgICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkxK2RldmVsK29zeG1lbnUgcjEyOTExIiAgIHNvZGlwb2RpOmRvY25hbWU9Imwtci5zdmciPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE1NDQ0Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGRlZnMgICAgIGlkPSJkZWZzNTQ0MiIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMSIgICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiICAgICBncmlkdG9sZXJhbmNlPSIxMCIgICAgIGd1aWRldG9sZXJhbmNlPSIxMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4NiIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlkPSJuYW1lZHZpZXc1NDQwIiAgICAgc2hvd2dyaWQ9InRydWUiICAgICBpbmtzY2FwZTp6b29tPSI0IiAgICAgaW5rc2NhcGU6Y3g9IjI1Ljg4OTgzMSIgICAgIGlua3NjYXBlOmN5PSIzNC4zODE4MzMiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIgICAgIGlua3NjYXBlOndpbmRvdy15PSIyMyIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmc1NDM0IiAgICAgaW5rc2NhcGU6b2JqZWN0LW5vZGVzPSJ0cnVlIiAgICAgaW5rc2NhcGU6c25hcC1zbW9vdGgtbm9kZXM9InRydWUiPiAgICA8aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkNTk4OSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPHBhdGggICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAgICAgZD0iTSAyNSAyNCBMIDE2IDMwIEwgMjUgMzYgTCAyNSAyNCB6IE0gMzUgMjQgTCAzNSAzNiBMIDQ0IDMwIEwgMzUgMjQgeiAiICAgICBpZD0icGF0aDU5OTUiIC8+PC9zdmc+); diff --git a/templates/Element/Form/relations.scss b/templates/Element/Form/relations.scss index d648e955d..2ef6ea00c 100644 --- a/templates/Element/Form/relations.scss +++ b/templates/Element/Form/relations.scss @@ -1,3 +1,6 @@ +@use "../../../resources/styles/variables"; +@use "../../../resources/styles/utility_classes"; + .relation-view { .related-list-container { .columns { @@ -172,8 +175,8 @@ } header h1 { - min-height: $font-size-lg * 2; - padding-right: $gutter * .75; + min-height: variables.$font-size-lg * 2; + padding-right: variables.$gutter * .75; word-break: break-word; line-height: 1.25em;; } @@ -184,8 +187,8 @@ .priority { position: absolute; - top: $gutter * .5; - left: $gutter * .5; + top: variables.$gutter * .5; + left: variables.$gutter * .5; z-index: 2; } @@ -194,7 +197,7 @@ width: 100%; height: 0; padding-bottom: 63%; // 16 / 9 56% - background-color: $gray-100; + background-color: variables.$gray-100; pointer-events: none; figure { @extend .full-size-absolute; @@ -225,7 +228,7 @@ article { //box-shadow: 0 0 0 3px var(--box-shadow-color); .badge { - padding: $gutter * .5; + padding: variables.$gutter * .5; border: none; letter-spacing: 1px; } @@ -233,16 +236,16 @@ } .ribbon { position: absolute; - top: $gutter * .5; - right: -$gutter * .5; + top: variables.$gutter * .5; + right: -(variables.$gutter) * .5; z-index: 2; display: block; color: #fff; background-color: #000; - font-size: $font-size-sssm; - font-weight: $font-weight-black; + font-size: variables.$font-size-sssm; + font-weight: variables.$font-weight-black; text-transform: uppercase; - padding: $gutter * 0.25 $gutter $gutter * 0.25 $gutter; + padding: variables.$gutter * 0.25 variables.$gutter variables.$gutter * 0.25 variables.$gutter; } .in-data-list { background-color: transparent !important; @@ -264,7 +267,7 @@ footer { position: sticky; - background-color: $gray-800; + background-color: variables.$gray-800; bottom: 0; left: 0; display: flex; @@ -284,7 +287,7 @@ .main-panel-container .edit-relation { - @extend %relation-panel-common; + @extend %relation-panel-common !optional; label { display: flex; flex-direction: column; @@ -295,7 +298,7 @@ } } - #{$text-inputs}, select { + #{variables.$text-inputs}, select { &:not(.input-narrow) { min-width: 12rem; } @@ -303,7 +306,7 @@ } .main-panel-container .relations-add { - @extend %relation-panel-common; + @extend %relation-panel-common !optional; .columns { &[data-list='true'] { @@ -447,15 +450,15 @@ justify-content: center; align-items: center; position: absolute; - width: $gutter * 2.25; - height: $gutter * 2.25; - top: $gutter * .5; - left: $gutter * .5; + width: variables.$gutter * 2.25; + height: variables.$gutter * 2.25; + top: variables.$gutter * .5; + left: variables.$gutter * .5; border: 2px solid white; border-radius: 50%; - background-color: $info; + background-color: variables.$info; color: #fff; - font-weight: $font-weight-black; + font-weight: variables.$font-weight-black; } } } diff --git a/templates/Element/Form/trees.scss b/templates/Element/Form/trees.scss index 18c69c9fc..19f5b6cf4 100644 --- a/templates/Element/Form/trees.scss +++ b/templates/Element/Form/trees.scss @@ -1,10 +1,12 @@ +@use "../../../resources/styles/variables"; + .tree-view-node { - color: $gray-100; - padding: 0 $gutter * .5; + color: variables.$gray-100; + padding: 0 variables.$gutter * .5; line-height: 1; &.is-root { - border-bottom: solid 1px $gray-800; + border-bottom: solid 1px variables.$gray-800; } .node-element { @@ -15,28 +17,28 @@ &[data-status='draft'], &[data-status='off'] { - color: $gray-500; + color: variables.$gray-500; } > label.node-label { flex: none !important; - margin-right: $gutter; + margin-right: variables.$gutter; color: inherit; - line-height: $gutter * 2; + line-height: variables.$gutter * 2; cursor: pointer; > input[type='checkbox'], > input[type='radio'] { - margin-top: -$gutter * .125; - margin-right: $gutter * .5; + margin-top: -(variables.$gutter) * .125; + margin-right: variables.$gutter * .5; vertical-align: middle; } } > a { display: inline-block; - padding: $gutter * .5 $gutter * 1.5; - margin-left: $gutter; + padding: variables.$gutter * .5 variables.$gutter * 1.5; + margin-left: variables.$gutter; vertical-align: middle; text-transform: uppercase; border: solid 1px currentColor; @@ -58,7 +60,7 @@ .tree-param { position: relative; - margin: $gutter * .25 $gutter * .5 $gutter * .25 0; + margin: variables.$gutter * .25 variables.$gutter * .5 variables.$gutter * .25 0; input { position: absolute; @@ -70,7 +72,7 @@ appearance: none; &:checked + label { - color: $white; + color: variables.$white; background: var(--color-module, #000); border-color: transparent; } @@ -81,7 +83,7 @@ align-items: center; margin: 0; padding: 0.25em 0.5em; - color: $gray-500; + color: variables.$gray-500; line-height: 1 !important; border-radius: 2em; border: solid 1px currentColor; @@ -91,7 +93,7 @@ > button { margin: 0; - min-width: $gutter * 2; + min-width: variables.$gutter * 2; color: currentColor; background: transparent; border: 0; @@ -115,10 +117,10 @@ .node-element ~ .node-children { &:not(:empty) { - margin-top: -$gutter; - margin-left: 3 * $gutter * .125; - padding-top: $gutter; - padding-left: $gutter * .5; + margin-top: -(variables.$gutter); + margin-left: 3 * variables.$gutter * .125; + padding-top: variables.$gutter; + padding-left: variables.$gutter * .5; border-left: solid 1px rgba(255, 255, 255, 0.25); } } diff --git a/templates/Element/Menu/colophon.scss b/templates/Element/Menu/colophon.scss index 9657e3304..de0d28728 100644 --- a/templates/Element/Menu/colophon.scss +++ b/templates/Element/Menu/colophon.scss @@ -1,7 +1,9 @@ +@use "../../../resources/styles/variables"; + .menu-colophon { - padding: $gutter * 1.5 0 0; + padding: variables.$gutter * 1.5 0 0; border-top: 1px solid #495057; - color: $gray-500; + color: variables.$gray-500; font-size: 12px; font-weight: 100; diff --git a/templates/Element/Menu/menu.scss b/templates/Element/Menu/menu.scss index 77daa985d..20977e238 100644 --- a/templates/Element/Menu/menu.scss +++ b/templates/Element/Menu/menu.scss @@ -1,18 +1,20 @@ +@use "../../../resources/styles/variables"; + .layout-header { .menu-bar { display: grid; - column-gap: $gutter; + column-gap: variables.$gutter; grid-template-columns: 1fr auto; nav[role="menu"] { display: grid; - row-gap: $gutter * .5; - grid-template-columns: repeat(auto-fill, $gutter * 2.5); + row-gap: variables.$gutter * .5; + grid-template-columns: repeat(auto-fill, variables.$gutter * 2.5); .menu-item-label { display: none; } @media screen and (min-width: 1024px) { - grid-template-columns: repeat(auto-fill, $gutter * 3); + grid-template-columns: repeat(auto-fill, variables.$gutter * 3); .menu-item-label { display: block; } .menu-item-short-label { display: none; } } @@ -20,16 +22,16 @@ .menu-item { display: flex; flex-direction: column; - padding-top: $gutter; + padding-top: variables.$gutter; &-color-bar { - height: $gutter * .625; - background-color: $gray-700; + height: variables.$gutter * .625; + background-color: variables.$gray-700; } &-label, &-short-label { - margin-top: $gutter * .25; - font-size: $font-size-smallest; + margin-top: variables.$gutter * .25; + font-size: variables.$font-size-smallest; letter-spacing: .5px; text-transform: lowercase; } @@ -37,7 +39,7 @@ &:hover, &.current { padding-top: 0; .menu-item-color-bar { - height: $gutter + $gutter * .625; + height: variables.$gutter + variables.$gutter * .625; } } } @@ -50,13 +52,13 @@ .popup { display: flex; position: absolute; - top: $gutter * 4; + top: variables.$gutter * 4; right: 0; button { min-width: 38px; - margin-left: $gutter * .5; - font-size: $font-size-ssm; + margin-left: variables.$gutter * .5; + font-size: variables.$font-size-ssm; } } } diff --git a/templates/Element/Menu/sidebar.scss b/templates/Element/Menu/sidebar.scss index 4f7e96913..d60209fe9 100644 --- a/templates/Element/Menu/sidebar.scss +++ b/templates/Element/Menu/sidebar.scss @@ -1,11 +1,13 @@ +@use "../../../resources/styles/variables"; + .app-module-box a { position: relative; display: flex; - height: $dashboard-item-height; - background-color: $gray-600; - font-size: $font-size-base; + height: variables.$dashboard-item-height; + background-color: variables.$gray-600; + font-size: variables.$font-size-base; line-height: 1; - padding: $gutter*0.875 $gutter; + padding: variables.$gutter*0.875 variables.$gutter; filter: brightness(1); transition: filter .3s; @@ -13,8 +15,8 @@ content: ''; position: absolute; bottom: 0; left: 0; - width: 100%; height: $gutter * 1.5; - background-color: $black; + width: 100%; height: variables.$gutter * 1.5; + background-color: variables.$black; opacity: .2; transition: opacity .3s; } @@ -31,7 +33,7 @@ a { position: relative; display: flex; - height: $dashboard-item-height; + height: variables.$dashboard-item-height; background-repeat:no-repeat; background-position: center center; } @@ -60,13 +62,13 @@ .app-module-box-concurrent-editors a { position: relative; display: flex; - height: $dashboard-item-height; + height: variables.$dashboard-item-height; background-image: url('/svg/concurrent-editors.svg'); background-repeat:no-repeat; background-position: center center; - font-size: $font-size-base; + font-size: variables.$font-size-base; line-height: 1; - padding: $gutter*0.875 $gutter; + padding: variables.$gutter*0.875 variables.$gutter; filter: brightness(1); transition: filter .3s; @@ -74,8 +76,8 @@ content: ''; position: absolute; bottom: 0; left: 0; - width: 100%; height: $gutter * 1.5; - background-color: $black; + width: 100%; height: variables.$gutter * 1.5; + background-color: variables.$black; opacity: .2; transition: opacity .3s; } @@ -95,7 +97,7 @@ ul.concurrent-editors { margin:0; padding:0; li { padding: .5rem 0 .5rem 0; - border-bottom: 1px solid $gray-600; + border-bottom: 1px solid variables.$gray-600; } } @@ -106,34 +108,34 @@ ul.concurrent-editors { overflow: hidden; @media (min-width: 568px) { height: 0; - padding-bottom: $dashboard-items-ratio; + padding-bottom: variables.$dashboard-items-ratio; } .app-module-box a { - background-color: $gray-strange; - font: $font-weight-normal $font-size-lg $font-family-serif; + background-color: variables.$gray-strange; + font: variables.$font-weight-normal variables.$font-size-lg variables.$font-family-serif; } } .sidebar { @media (min-width: 568px) { position: fixed; - top: 0; left: $gutter; + top: 0; left: variables.$gutter; } display: flex; flex-direction: column; min-height: 100%; - padding: $gutter 0 $gutter 0; - width: $dashboard-item-width; + padding: variables.$gutter 0 variables.$gutter 0; + width: variables.$dashboard-item-width; // > *:not(:last-child) { margin-bottom: $gutter;} button, .button { - width: $dashboard-item-width * .8; + width: variables.$dashboard-item-width * .8; } &-bedita-logo { - width: $gutter * 3; - height: $gutter * 3; + width: variables.$gutter * 3; + height: variables.$gutter * 3; background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTUwLjQgMTIxLjkiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDE1MC40IDEyMS45OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc3Qwe2ZpbGw6IzAxMDEwMTt9PC9zdHlsZT48Zz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjgsMTA3LjZjLTQuNS01LTYuOC0xMi4zLTYuOC0yMmMwLTcuMiwyLjQtMTMuMSw3LjMtMTcuOGM0LjgtNC42LDExLjgtNywyMC43LTdjMy43LDAsNi44LDAsOS4zLDAuMWMyLjUsMC4xLDQuNCwwLjIsNS43LDAuMnY0Mi45YzAsMy42LTEuNSw2LjMtNC40LDguMmMtMi45LDEuOC03LDIuNy0xMi4yLDIuN0MzOS4xLDExNS4xLDMyLjUsMTEyLjYsMjgsMTA3LjYgTTMzLjEsNDYuN2MtMi4xLTIuNS0zLjYtNS4yLTQuNC04LjFjLTAuOC0yLjktMS4yLTYuNC0xLjItMTAuNGMwLTYuNywxLjgtMTIsNS41LTE1LjhjMy43LTMuOCw5LjQtNS43LDE3LjMtNS43YzAuMiwwLDAuNSwwLDAuNywwYzUuNCwwLDguMiwxLjcsOS45LDMuMmMxLjQsMS4zLDMuMywzLjQsMy4zLDkuNXYzNC41SDUzLjNjLTQuNywwLTguNy0wLjYtMTItMS44QzM3LjksNTAuOSwzNS4yLDQ5LjEsMzMuMSw0Ni43IE0xNDQuMiw4NmMtMC44LDIuNi0yLjcsNi43LTUuNSwxMi4zYy0yLjksNS42LTUuNyw5LjctOC4zLDEyLjVjLTEsMS0yLjYsMS44LTQuOSwyLjRjLTIuMywwLjYtNC42LDEtNi43LDEuMmMtMi4xLDAuMi00LjcsMC4zLTcuOCwwLjNoLTcuNWMtNC44LDAtOC40LTAuMi0xMS0wLjVjLTIuNi0wLjMtNC42LTEtNi4xLTIuMWMtMS41LTEuMS0yLjUtMi43LTMtNC44Yy0wLjUtMi4xLTAuOC01LTAuOC04LjdWNjIuM2gxMy43YzMuNywwLDYuNywwLjMsOSwxYzIuMywwLjcsNC4zLDIuMSw2LjEsNC40YzEuMSwxLjQsMi4xLDMuNiwzLjEsNi43YzEsMy4xLDEuNiw2LDEuOCw4LjdoNi40VjM1LjNoLTYuNGMtMC4zLDIuNS0wLjksNS4xLTEuOCw3LjljLTAuOSwyLjgtMiw1LTMuMiw2LjdjLTEuNSwxLjktMy4zLDMuMy01LjQsNC4yYy0yLDAuOC01LjMsMS4yLTkuNywxLjJIODIuNVY2LjhoMTkuMmMzLjIsMCw2LDAuMSw4LjQsMC4yYzIuNSwwLjEsNC42LDAuMyw2LjQsMC41YzMuNCwwLjUsNy4xLDMuMSwxMC45LDhjMy44LDQuOSw2LjMsOS41LDcuNCwxMy45aDYuNFYwaC05OWMtNC40LDAtOC41LDAuNC0xMi41LDEuM2MtNCwwLjktNy44LDIuNC0xMS40LDQuNmMtMy40LDItNi4yLDQuNy04LjMsOC4yYy0yLjIsMy40LTMuMyw3LjYtMy4zLDEyLjVjMCw0LjMsMC44LDguMSwyLjMsMTEuNWMxLjUsMy40LDMuNyw2LjIsNi41LDguNmMyLjYsMi4zLDUuNyw0LjIsOS4xLDUuOGMzLjQsMS42LDcuMSwyLjgsMTEsMy43djAuOGMtMy41LDAuNC03LjQsMS4zLTExLjcsMi42Yy00LjMsMS4zLTguMiwzLjItMTEuNiw1LjZjLTMuNiwyLjQtNi41LDUuNi04LjgsOS40QzEuMiw3OC41LDAsODMuMiwwLDg4LjdjMCw1LjcsMS4yLDEwLjYsMy43LDE0LjhjMi41LDQuMiw1LjcsNy42LDkuNiwxMC4zYzMuOCwyLjYsOC4yLDQuNiwxMyw2YzQuOCwxLjQsOS44LDIuMSwxNSwyLjFoMTA2LjdsMi4zLTM1LjlIMTQ0LjJ6Ii8+PC9nPjwvc3ZnPg=="); background-repeat: no-repeat; background-size: 100%; @@ -148,14 +150,14 @@ ul.concurrent-editors { display: flex; flex-direction: column; - > *:not(:empty) { margin-bottom: $gutter; } + > *:not(:empty) { margin-bottom: variables.$gutter; } .app-module-buttons, .app-module-links { display: flex; flex-direction: column; overflow: auto; max-height: 400px; - > *:not(:last-child) { margin-bottom: $gutter; } + > *:not(:last-child) { margin-bottom: variables.$gutter; } } .app-module-box > a.module-item { @@ -185,20 +187,20 @@ ul.concurrent-editors { } .listobjnav { - color:$gray-600; + color:variables.$gray-600; font-size:4em; text-align: center; - width: $dashboard-item-width * .8; + width: variables.$dashboard-item-width * .8; a { background-color: transparent; - color:$gray-400; + color:variables.$gray-400; display: inline-flex; &:hover { color:white; } } > div { - color:$gray-100; + color:variables.$gray-100; font-size:0.3em; } } @@ -211,15 +213,15 @@ ul.concurrent-editors { text-decoration: underline; } > *:not(:last-child) { - margin: $gutter 0 $gutter 0; - a:hover { color: $gray-500; } + margin: variables.$gutter 0 variables.$gutter 0; + a:hover { color: variables.$gray-500; } } } // sidebar footer is in layout-footer on mobile &-footer { - margin-top: $gutter; + margin-top: variables.$gutter; display: block; // @media (min-width: 568px) { display: block; } } diff --git a/templates/Element/Modules/index_properties.scss b/templates/Element/Modules/index_properties.scss index c18797fa2..d54e687fc 100644 --- a/templates/Element/Modules/index_properties.scss +++ b/templates/Element/Modules/index_properties.scss @@ -1,9 +1,11 @@ +@use "../../../resources/styles/variables"; + .index-date-ranges { display: flex; // toggle button .show-toggle { - margin-left: $gutter; + margin-left: variables.$gutter; line-height: 1; height: 20px; cursor: cell; @@ -21,19 +23,19 @@ .date-range { display: flex; .date-range ~ .date-range { - margin-top: $gutter * .25; + margin-top: variables.$gutter * .25; } &:last-child:not(:first-child) { margin-bottom: 1px; } // adjust space when expanded .date-item { display: flex; &:first-child { - margin-right: $gutter * .5; + margin-right: variables.$gutter * .5; } .date { - margin-left: $gutter * .5; - font-weight: $font-weight-bold; + margin-left: variables.$gutter * .5; + font-weight: variables.$font-weight-bold; } } diff --git a/templates/Element/Panel/panel.scss b/templates/Element/Panel/panel.scss index 854f58090..697c0b67d 100644 --- a/templates/Element/Panel/panel.scss +++ b/templates/Element/Panel/panel.scss @@ -1,7 +1,9 @@ +@use "../../../resources/styles/variables"; + .main-panel-container { position: fixed; top: 0; right: 0; - min-width: 20 * $gutter; + min-width: 20 * variables.$gutter; width: 100%; @media screen and (min-width: 768px) { width: 60%; @@ -16,7 +18,7 @@ overflow-x: hidden; overflow-y: auto; height: 100%; - background-color: $gray-800; + background-color: variables.$gray-800; } .panel-slot { @@ -25,12 +27,12 @@ &.on { transform: translateX(0); - box-shadow: 0 0 32px $black; + box-shadow: 0 0 32px variables.$black; } } .main-panel { .fieldset:first-child { - padding-top: $gutter; + padding-top: variables.$gutter; } } diff --git a/templates/Element/flash/flash.scss b/templates/Element/flash/flash.scss index 5183e37f3..f8aab3d43 100644 --- a/templates/Element/flash/flash.scss +++ b/templates/Element/flash/flash.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + #flashMessagesContainer { position: fixed; top: 0; @@ -27,13 +29,13 @@ align-items: flex-start; flex: 1 auto; margin-top: auto; - padding: $gutter * .75 $gutter; + padding: variables.$gutter * .75 variables.$gutter; max-height: 50%; max-width: 70%; border-top: 4px solid transparent; - background-color: $gray-100; - color: $gray-900; - font-size: $font-size-sm; + background-color: variables.$gray-100; + color: variables.$gray-900; + font-size: variables.$font-size-sm; transition: transform .25s; // when parent has not class 'on' transform: translateY(100%); @@ -44,44 +46,44 @@ } // colors - &.success { border-color: $success; } - &.info { border-color: $info; } - &.error { border-color: $error; } - &.warning { border-color: $warning; } - &.success h2 [class^="icon-"] { color: $success; } - &.info h2 [class^="icon-"] { color: $info; } - &.error h2 [class^="icon-"] { color: $error; } - &.warning h2 [class^="icon-"] { color: $warning; } + &.success { border-color: variables.$success; } + &.info { border-color: variables.$info; } + &.error { border-color: variables.$error; } + &.warning { border-color: variables.$warning; } + &.success h2 [class^="icon-"] { color: variables.$success; } + &.info h2 [class^="icon-"] { color: variables.$info; } + &.error h2 [class^="icon-"] { color: variables.$error; } + &.warning h2 [class^="icon-"] { color: variables.$warning; } h2 { display: flex; align-items: center; margin: 0; - padding-right: $gutter * 1.5; - font-size: $font-size-llg; + padding-right: variables.$gutter * 1.5; + font-size: variables.$font-size-llg; [class^="icon-"] { margin-top: 2px; } } details { width: 100%; } summary { cursor: pointer; } .dump { - margin-top: $gutter * .75; - padding: $gutter * .75; + margin-top: variables.$gutter * .75; + padding: variables.$gutter * .75; width: 100%; max-height: 400px; flex: 1; overflow: auto; - background-color: $gray-200; + background-color: variables.$gray-200; font-family: monospace; - font-size: $font-size-sm; + font-size: variables.$font-size-sm; } .icon-cancel-1 { position: absolute; - top: $gutter * .5; - right: $gutter; + top: variables.$gutter * .5; + right: variables.$gutter; cursor: pointer; - color: $black; + color: variables.$black; &::before { margin: 0; diff --git a/templates/Pages/Admin/_admin.scss b/templates/Pages/Admin/_admin.scss index ab9b35ff8..98b14838b 100644 --- a/templates/Pages/Admin/_admin.scss +++ b/templates/Pages/Admin/_admin.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + body.view-admin { .filter-box-admin > .filters-container > .filter-container > span { margin-left: 15px; @@ -11,23 +13,23 @@ body.view-admin { } .table-row { &.new-record > * { - padding-top: calc($gutter * 4) !important; + padding-top: calc(variables.$gutter * 4) !important; } } } .app-module-links { a:not(.button), span { - border-bottom: 1px solid $gray-600; - padding: calc($gutter * 0.5); - padding-left: $gutter; + border-bottom: 1px solid variables.$gray-600; + padding: calc(variables.$gutter * 0.5); + padding-left: variables.$gutter; margin: 0 !important; } .button { - margin-top: calc($gutter * 2); + margin-top: calc(variables.$gutter * 2); } .active-action { - background-color: $gray-600; + background-color: variables.$gray-600; font-weight: normal !important; color: black !important; } diff --git a/templates/Pages/Dashboard/_dashboard.scss b/templates/Pages/Dashboard/_dashboard.scss index 38c538ccb..1d306b945 100644 --- a/templates/Pages/Dashboard/_dashboard.scss +++ b/templates/Pages/Dashboard/_dashboard.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + /*****************/ /*** DASHBOARD ***/ /*****************/ @@ -11,31 +13,31 @@ body.view-dashboard { width: 32px; } .dashboard { - margin-top: $gutter; + margin-top: variables.$gutter; &-section { - margin-bottom: $gutter; + margin-bottom: variables.$gutter; header { h2 { - padding-top: $gutter; - margin-bottom: $gutter; - font-size: $font-size-llg; + padding-top: variables.$gutter; + margin-bottom: variables.$gutter; + font-size: variables.$font-size-llg; } } } &-items { display: grid; - grid-gap: $gutter; + grid-gap: variables.$gutter; grid-template-columns: repeat(2, 1fr); @media (min-width: 768px) { - grid-template-columns: repeat(auto-fill, $dashboard-item-width); + grid-template-columns: repeat(auto-fill, variables.$dashboard-item-width); } } &-item { position: relative; - background-color: $gray-700; - font-size: $font-size-base; + background-color: variables.$gray-700; + font-size: variables.$font-size-base; line-height: 1; letter-spacing: .5px; display: flex; @@ -58,8 +60,8 @@ body.view-dashboard { width: 24px; } - padding: .375rem .375rem calc(#{$dashboard-items-ratio} - .375rem); - @media (min-width: 667px) { padding: $gutter*0.875 $gutter calc(#{$dashboard-items-ratio} - #{$gutter*0.875}); } + padding: .375rem .375rem calc(#{variables.$dashboard-items-ratio} - .375rem); + @media (min-width: 667px) { padding: variables.$gutter*0.875 variables.$gutter calc(#{variables.$dashboard-items-ratio} - #{variables.$gutter*0.875}); } &[class^="icon-"]:before, &[class*=" icon-"]:before { position: absolute; @@ -68,7 +70,7 @@ body.view-dashboard { // @media (min-width: 667px) { top: $gutter * .5; right: $gutter * .5; } margin-top: -1rem !important; opacity: .5; - color: $white; + color: variables.$white; font-size: 1.75rem; z-index: 1; filter: brightness(1); @@ -79,14 +81,14 @@ body.view-dashboard { content: ''; position: absolute; bottom: 0; left: 0; - width: 100%; height: $gutter * 1.5; - background-color: $black; + width: 100%; height: variables.$gutter * 1.5; + background-color: variables.$black; opacity: .2; transition: opacity .3s; } &.has-background-black:after { - background-color: $gray-600; + background-color: variables.$gray-600; } &:hover { @@ -105,10 +107,10 @@ body.view-dashboard { div[role="search"] { display: flex; - gap: $gutter * 2; + gap: variables.$gutter * 2; // @media (min-width: 568px) { width: 22 * $gutter + $gutter; } input { - margin-right: $gutter * .5; + margin-right: variables.$gutter * .5; flex-grow: 1; } } @@ -127,9 +129,9 @@ body.view-dashboard { > div { display: table-cell; - height: $gutter * 2; + height: variables.$gutter * 2; white-space: nowrap; - border-bottom: 1px solid $gray-550; + border-bottom: 1px solid variables.$gray-550; vertical-align: baseline; &:empty:not(.title-cell) { @@ -150,8 +152,8 @@ body.view-dashboard { // table header .table-header { > div { - height: $gutter * 3.25; - padding: $gutter * 1.625 $gutter 0; + height: variables.$gutter * 3.25; + padding: variables.$gutter * 1.625 variables.$gutter 0; line-height: 1; border-bottom-color: inherit; &:first-letter { text-transform: uppercase; } @@ -185,7 +187,7 @@ body.view-dashboard { // table rows .table-row { &.object-status-off, &.object-status-draft, &.object-status-deleted { - color: $gray-550; + color: variables.$gray-550; } &.object-status-deleted { @@ -193,12 +195,12 @@ body.view-dashboard { } &:hover { - background-color: $gray-800; + background-color: variables.$gray-800; } // table cells > div { - padding: $gutter $gutter $gutter 0; + padding: variables.$gutter variables.$gutter variables.$gutter 0; &.narrow { width: 1px; } @@ -208,7 +210,7 @@ body.view-dashboard { white-space: initial; &:empty:before { content: attr(untitled-label); - color: $gray-550; + color: variables.$gray-550; font-style: italic; } } @@ -219,10 +221,10 @@ body.view-dashboard { img { padding: 1px; display: inline-block; - max-height: $gutter * 2; - max-width: $gutter * 2.5; + max-height: variables.$gutter * 2; + max-width: variables.$gutter * 2.5; vertical-align: middle; - background-color: $gray-200; + background-color: variables.$gray-200; } } @@ -247,9 +249,9 @@ body.view-dashboard { .dashboard-area { @media (min-width: 1280px) { - grid-template-columns: ($dashboard-item-width * 4 + $gutter * 3) auto; + grid-template-columns: (variables.$dashboard-item-width * 4 + variables.$gutter * 3) auto; display:grid; - grid-gap: $gutter; + grid-gap: variables.$gutter; } } diff --git a/templates/Pages/Import/import.scss b/templates/Pages/Import/import.scss index 2ef7e413a..cc76c4a96 100644 --- a/templates/Pages/Import/import.scss +++ b/templates/Pages/Import/import.scss @@ -1,6 +1,8 @@ +@use "../../../resources/styles/variables"; + #data-import { .fieldset { - margin-bottom: $gutter * 1.5; + margin-bottom: variables.$gutter * 1.5; .tab { cursor: auto; @@ -12,14 +14,14 @@ display: block; cursor: pointer; & ~ label { - margin-top: $gutter * .5; + margin-top: variables.$gutter * .5; } } } button.submit { - padding-left: 3 * $gutter; - padding-right: 3 * $gutter; + padding-left: 3 * variables.$gutter; + padding-right: 3 * variables.$gutter; } } @@ -29,11 +31,11 @@ grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 50px; .table-header { - border-bottom: 1px solid $gray-700; + border-bottom: 1px solid variables.$gray-700; } > div { - padding: $gutter * .5; + padding: variables.$gutter * .5; &.job-payload { grid-column: span 7; @@ -51,19 +53,19 @@ } &.completed { - color: $success; + color: variables.$success; } &.failed { - color: $danger; + color: variables.$danger; } &.locked, &.pending { - color: $pending; + color: variables.$pending; } &.planned { - color: $info; + color: variables.$info; } } } diff --git a/templates/Pages/Login/login.scss b/templates/Pages/Login/login.scss index a287113a9..2b49f470c 100644 --- a/templates/Pages/Login/login.scss +++ b/templates/Pages/Login/login.scss @@ -1,8 +1,10 @@ +@use "../../../resources/styles/variables"; + // override default layout body.view-login { height: 100vh; - background-color: $defaultBackground; - background-image: linear-gradient(to bottom right, $gray-600 0%, $black 100%); + background-color: variables.$defaultBackground; + background-image: linear-gradient(to bottom right, variables.$gray-600 0%, variables.$black 100%); background-attachment: fixed; background-repeat: no-repeat; @@ -17,7 +19,7 @@ body.view-login { .login { position: relative; display: grid; - column-gap: $gutter * 2; + column-gap: variables.$gutter * 2; grid-template: "login-title login-form" "login-footer login-form"; .logo { @@ -28,29 +30,29 @@ body.view-login { width: 62px; height: 50px; opacity: .2; - margin-bottom:$gutter; + margin-bottom:variables.$gutter; } .login-title { grid-area: login-title; font-size:1.5em; line-height: 1.375em; width:176px; - font-family: $font-family-serif; + font-family: variables.$font-family-serif; } .login-form { width:264px; grid-area: login-form; - padding-top: $gutter * .25; - padding-bottom:$gutter; + padding-top: variables.$gutter * .25; + padding-bottom:variables.$gutter; form { display: flex; flex-direction: column; justify-content: space-between; label { - color: $white; + color: variables.$white; font-weight: normal; - margin: $gutter 0 $gutter * .25 0; + margin: variables.$gutter 0 variables.$gutter * .25 0; } label, input { @@ -58,15 +60,15 @@ body.view-login { width: 100%; &[type='submit'] { - margin-top: $gutter * 2; - margin-bottom: $gutter; + margin-top: variables.$gutter * 2; + margin-bottom: variables.$gutter; color: black; - border-color: $gray-300; + border-color: variables.$gray-300; width:96px; &:focus, &:hover { - color: $white; - background-color: $gray-900; + color: variables.$white; + background-color: variables.$gray-900; } } } @@ -75,7 +77,7 @@ body.view-login { footer { grid-area: login-footer; width:176px; - padding-top: $gutter; + padding-top: variables.$gutter; } @media screen and (max-width: 780px) { grid-template: "login-title" "login-form" "login-footer"; @@ -88,14 +90,14 @@ body.view-login { position: static; display: block; .message { - background-color: $error; + background-color: variables.$error; color: #fff; max-width: 100%; h2 { margin: 0; padding: 0; - font-family: $font-family-sans-serif; - font-size: $font-size-sm; - line-height: $line-height-base; + font-family: variables.$font-family-sans-serif; + font-size: variables.$font-size-sm; + line-height: variables.$line-height-base; } // no multiple messages display: none; diff --git a/templates/Pages/Model/ObjectTypes/view.twig b/templates/Pages/Model/ObjectTypes/view.twig index b73524e77..75caba7b3 100644 --- a/templates/Pages/Model/ObjectTypes/view.twig +++ b/templates/Pages/Model/ObjectTypes/view.twig @@ -17,6 +17,7 @@ 'url': {'_name': 'model:save:object_types'}, 'id': 'form-main', 'check-changes': 'true', + 'class': 'object-form', })|raw }} {{ Form.hidden('id', {'value': (object) ? object.id : resource.id})|raw }} diff --git a/templates/Pages/Model/Relations/view.twig b/templates/Pages/Model/Relations/view.twig index cb4706e25..a33b6eb76 100644 --- a/templates/Pages/Model/Relations/view.twig +++ b/templates/Pages/Model/Relations/view.twig @@ -16,6 +16,7 @@ 'url': {'_name': 'model:save:relations'}, 'id': 'form-main', 'check-changes': 'true', + 'class': 'object-form', })|raw }} {{ Form.hidden('id', {'value': resource.id})|raw }} diff --git a/templates/Pages/Model/_model-index.scss b/templates/Pages/Model/_model-index.scss index 3f698ddd6..d23d4cd86 100644 --- a/templates/Pages/Model/_model-index.scss +++ b/templates/Pages/Model/_model-index.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + body.view-model { // true @@ -22,12 +24,12 @@ body.view-model { .first-cell { button { - min-width: $gutter * 2; + min-width: variables.$gutter * 2; } } &.editing-property-type { - border-bottom: 1px dashed $gray-200; + border-bottom: 1px dashed variables.$gray-200; } &.delete-property-type { @@ -54,17 +56,17 @@ body.view-model { } div { - padding: $gutter * .25 $gutter * .5; + padding: variables.$gutter * .25 variables.$gutter * .5; vertical-align: middle; &.first-cell, &.action-cell { flex: 0 0 65px; i { - margin-left: $gutter * .5; + margin-left: variables.$gutter * .5; } input { - margin-right: $gutter * .5; + margin-right: variables.$gutter * .5; } } @@ -79,22 +81,22 @@ body.view-model { &.new-row div { &.primary, &.secondary, &.name-cell, &.inverse_name-cell, &.params-cell, &.enabled-cell, &.is_abstract-cell { - padding: $gutter * 0.25 $gutter * 0.5; + padding: variables.$gutter * 0.25 variables.$gutter * 0.5; } } input, textarea { background: transparent; - color: $gray-100; + color: variables.$gray-100; border: 1px solid transparent; &:hover, &:focus { - border: 1px solid $gray-100; + border: 1px solid variables.$gray-100; } } textarea { - min-height: $gutter * 2; + min-height: variables.$gutter * 2; width: 100%; // resize: none; } @@ -104,7 +106,7 @@ body.view-model { display: flex; &.table-header { - border-bottom: 1px solid $gray-700; + border-bottom: 1px solid variables.$gray-700; .first-cell, .action-cell { flex: 0 0 65px; @@ -137,10 +139,10 @@ body.view-model { width: 100%; &:hover { - background-color: $gray-700; + background-color: variables.$gray-700; .inverted { - background-color: $gray-700; + background-color: variables.$gray-700; } } } @@ -148,7 +150,7 @@ body.view-model { > nav, > .resource-status-on { div { display: flex; - padding: $gutter * .5; + padding: variables.$gutter * .5; white-space: nowrap; vertical-align: middle; @@ -166,14 +168,14 @@ body.view-model { overflow: hidden; &:empty:before { content: attr(untitled-label); - color: $gray-600; + color: variables.$gray-600; font-style: italic; } } &.thumb-cell { - max-width: $gutter * 2.5; - height: $gutter * 2; + max-width: variables.$gutter * 2.5; + height: variables.$gutter * 2; padding: 0; overflow: hidden; img { @@ -182,7 +184,7 @@ body.view-model { max-height: 100%; max-width: 100%; vertical-align: middle; - background-color: $gray-200; + background-color: variables.$gray-200; } .icon { display: inline-block; @@ -207,10 +209,10 @@ body.view-model { } .bulk-actions { - border-top: 1px solid $gray-700; + border-top: 1px solid variables.$gray-700; header { - margin: $gutter 0 $gutter * .5; + margin: variables.$gutter 0 variables.$gutter * .5; width: 100%; opacity: .3; } @@ -222,7 +224,7 @@ body.view-model { nav { display: flex; form { - margin-right: $gutter; + margin-right: variables.$gutter; &:last-of-type { margin-right: 0; margin-left: auto; diff --git a/templates/Pages/Model/_model-view.scss b/templates/Pages/Model/_model-view.scss index d89841022..e8528abae 100644 --- a/templates/Pages/Model/_model-view.scss +++ b/templates/Pages/Model/_model-view.scss @@ -1,18 +1,20 @@ +@use "../../../resources/styles/variables"; + body.view-model { .module-form form section.fieldset { input[disabled] { - background-color: $gray-700; - color: $gray-100; + background-color: variables.$gray-700; + color: variables.$gray-100; } .link-to-parent { display: block; - margin-top: -.75 * $gutter; + margin-top: -.75 * variables.$gutter; } } .modules-view section:not(:first-child) { - margin-top: $gutter * 3; + margin-top: variables.$gutter * 3; } @@ -29,7 +31,7 @@ body.view-model { .properties { &-container { display: grid; - grid-gap: $gutter; + grid-gap: variables.$gutter; grid-template-columns: repeat(1, 1fr); @media screen and (min-width: 768px) { grid-template-columns: repeat(2, 1fr); @@ -42,7 +44,7 @@ body.view-model { .buttons-container { display: flex; flex-direction: column; - button { margin-bottom: $gutter * .5; } + button { margin-bottom: variables.$gutter * .5; } } } } diff --git a/templates/Pages/Modules/_modules-index.scss b/templates/Pages/Modules/_modules-index.scss index f478ab455..9492d96cc 100644 --- a/templates/Pages/Modules/_modules-index.scss +++ b/templates/Pages/Modules/_modules-index.scss @@ -1,7 +1,9 @@ +@use "../../../resources/styles/variables"; + body.view-module { .module-header { - min-height: $dashboard-item-height - ($gutter * 3.25) - $gutter; // minus table header and margin - margin-bottom: $gutter; + min-height: variables.$dashboard-item-height - (variables.$gutter * 3.25) - variables.$gutter; // minus table header and margin + margin-bottom: variables.$gutter; } .module-index { @@ -16,9 +18,9 @@ body.view-module { > div { display: table-cell; - height: $gutter * 2; + height: variables.$gutter * 2; white-space: nowrap; - border-bottom: 1px solid $gray-550; + border-bottom: 1px solid variables.$gray-550; vertical-align: baseline; &:empty:not(.title-cell) { @@ -40,8 +42,8 @@ body.view-module { // table header .table-header { > div { - height: $gutter * 3.25; - padding: $gutter * 1.625 $gutter 0; + height: variables.$gutter * 3.25; + padding: variables.$gutter * 1.625 variables.$gutter 0; line-height: 1; border-bottom-color: inherit; &:first-letter { text-transform: uppercase; } @@ -73,26 +75,26 @@ body.view-module { } .selected { - background-color: $gray-800; + background-color: variables.$gray-800; } // table rows .table-row { &.object-status-off, &.object-status-draft { - color: $gray-550; + color: variables.$gray-550; } &:hover { - background-color: $gray-700; + background-color: variables.$gray-700; } .select-cell:after { display: none; vertical-align: bottom; content: ""; - width: $gutter * 1.5; - height: $gutter * 1.5; - margin-left: $gutter * 0.5; + width: variables.$gutter * 1.5; + height: variables.$gutter * 1.5; + margin-left: variables.$gutter * 0.5; background-repeat: no-repeat; background-position: center center; background-size: 100%; @@ -118,7 +120,7 @@ body.view-module { // table cells > div { - padding: $gutter * 1.5 $gutter $gutter * .375; + padding: variables.$gutter * 1.5 variables.$gutter variables.$gutter * .375; &.narrow { width: 1px; } @@ -128,7 +130,7 @@ body.view-module { white-space: initial; &:empty:before { content: attr(untitled-label); - color: $gray-550; + color: variables.$gray-550; font-style: italic; } } @@ -139,10 +141,10 @@ body.view-module { img { padding: 1px; display: inline-block; - max-height: $gutter * 2; - max-width: $gutter * 2.5; + max-height: variables.$gutter * 2; + max-width: variables.$gutter * 2.5; vertical-align: middle; - background-color: $gray-200; + background-color: variables.$gray-200; } } @@ -160,7 +162,7 @@ body.view-module { } button { - height: $gutter * 2; + height: variables.$gutter * 2; } } } @@ -170,12 +172,12 @@ body.view-module { .module-footer { display: flex; flex-wrap: wrap-reverse; - margin: $gutter 0; + margin: variables.$gutter 0; align-items: flex-end; @media screen and (max-width: 1023px) { > * { - margin-bottom: $gutter; + margin-bottom: variables.$gutter; } } @@ -186,10 +188,10 @@ body.view-module { .bulk-actions { .bulk-header { - font-size: $font-size-base; + font-size: variables.$font-size-base; & + * { - margin-top: $gutter; + margin-top: variables.$gutter; } } @@ -201,10 +203,10 @@ body.view-module { .fieldset { display: inline-flex; align-items: center; - margin-bottom: $gutter; + margin-bottom: variables.$gutter; & > *:not([type='hidden']) ~ *:not([type='hidden']) { - margin-left: $gutter * .5; + margin-left: variables.$gutter * .5; } &[disabled] { @@ -224,11 +226,11 @@ body.view-module { } .input label:first-of-type { - margin-right: $gutter; + margin-right: variables.$gutter; } label { - margin-right: $gutter * .5; + margin-right: variables.$gutter * .5; } } @@ -241,7 +243,7 @@ body.view-module { } .bulk-folders .folder-picker { - margin-left: $gutter !important; + margin-left: variables.$gutter !important; } } } diff --git a/templates/Pages/Modules/_modules-view.scss b/templates/Pages/Modules/_modules-view.scss index 729147d8b..fc4420e41 100644 --- a/templates/Pages/Modules/_modules-view.scss +++ b/templates/Pages/Modules/_modules-view.scss @@ -1,12 +1,14 @@ +@use "../../../resources/styles/variables"; + body.view-module, body.userprofiles-view { .modules-view { >header { - min-height: 3 * $gutter; + min-height: 3 * variables.$gutter; h1:empty { &:before { content: attr(untitled-label); - color: $gray-600; + color: variables.$gray-600; font-style: italic; } } @@ -16,7 +18,7 @@ body.view-module, body.userprofiles-view { // view .module-form { form { - @extend .object-form; + @extend .object-form !optional; } } } @@ -24,14 +26,14 @@ body.view-module, body.userprofiles-view { // tabs layout .fieldset { ~ .fieldset { - margin-top: $gutter * 1.5; + margin-top: variables.$gutter * 1.5; } .tab { display: flex; align-items: center; - padding-left: $gutter * .5; - padding-right: $gutter * .5; - border-bottom: 1px solid $gray-100; + padding-left: variables.$gutter * .5; + padding-right: variables.$gutter * .5; + border-bottom: 1px solid variables.$gray-100; // background-color: $gray-800; &.is-loading-spinner { @@ -42,8 +44,8 @@ body.view-module, body.userprofiles-view { h2 { flex-grow: 1; - margin: 0; padding: 0 $gutter 0 0; - font-size: $font-size-base; + margin: 0; padding: 0 variables.$gutter 0 0; + font-size: variables.$font-size-base; &:first-letter { text-transform: capitalize; } @@ -53,8 +55,8 @@ body.view-module, body.userprofiles-view { cursor: pointer; &:before { content: '+'; - margin-right: $gutter; - font-size: $font-size-2; + margin-right: variables.$gutter; + font-size: variables.$font-size-2; } &.open { &:before { @@ -77,7 +79,7 @@ body.view-module, body.translation-module, body.userprofiles-view { .module-form form { @media screen and (min-width: 768px) { display: grid; - grid-gap: 0 $gutter; + grid-gap: 0 variables.$gutter; grid-template-areas: "header-view header-view" "main-view side-view" "submain-view side-view" @@ -94,7 +96,7 @@ body.view-module, body.translation-module, body.userprofiles-view { } @media screen and (min-width: 1024px) { - grid-gap: 0 $gutter * 1.5; + grid-gap: 0 variables.$gutter * 1.5; grid-template-columns: 2fr 1fr; section.relations { grid-area: submain-view; } section.history { grid-area: submain-view-1; } diff --git a/templates/Pages/Modules/view.twig b/templates/Pages/Modules/view.twig index 64099fba1..ea5bcb265 100644 --- a/templates/Pages/Modules/view.twig +++ b/templates/Pages/Modules/view.twig @@ -18,6 +18,7 @@ 'id': 'form-main', 'check-changes': 'true', 'ref': 'formMain', + 'class': 'object-form', })|raw }} {{ Form.hidden('id', {'value': (object) ? object.id : resource.id})|raw }} diff --git a/templates/Pages/Translations/view.scss b/templates/Pages/Translations/view.scss index 97e0551e9..933227b3b 100644 --- a/templates/Pages/Translations/view.scss +++ b/templates/Pages/Translations/view.scss @@ -1,3 +1,5 @@ +@use "../../../resources/styles/variables"; + .lang-header { grid-column: span 3; gap: 12px; @@ -5,5 +7,5 @@ } .module-form { - margin-bottom: $gutter; + margin-bottom: variables.$gutter; } diff --git a/templates/Pages/Trash/view.twig b/templates/Pages/Trash/view.twig index 926ee204a..37cf86db0 100644 --- a/templates/Pages/Trash/view.twig +++ b/templates/Pages/Trash/view.twig @@ -12,6 +12,7 @@ {{ Form.create({'defaults': object.attributes, 'schema': {}}, { 'url': {'_name': 'trash:list'}, 'id': 'form-main', + 'class': 'object-form', })|raw }}
diff --git a/templates/Pages/UserProfile/view.twig b/templates/Pages/UserProfile/view.twig index 67fffe0e0..5fa6522d4 100644 --- a/templates/Pages/UserProfile/view.twig +++ b/templates/Pages/UserProfile/view.twig @@ -9,6 +9,7 @@ {{ Form.create({'defaults': object.attributes, 'schema': {}}, { 'url': {'_name': 'user_profile:save', 'object_type': 'users'}, 'id': 'form-main', + 'class': 'object-form', })|raw }} {{ Form.hidden('id', {'value': object.id})|raw }} diff --git a/tests/TestCase/ApplicationTest.php b/tests/TestCase/ApplicationTest.php index c7dff88b8..b0b67071d 100644 --- a/tests/TestCase/ApplicationTest.php +++ b/tests/TestCase/ApplicationTest.php @@ -13,7 +13,6 @@ namespace App\Test\TestCase; use App\Application; -use App\Identifier\ApiIdentifier; use App\Middleware\ConfigurationMiddleware; use App\Middleware\ProjectMiddleware; use App\Middleware\RecoveryMiddleware; @@ -34,23 +33,27 @@ use Cake\Routing\Middleware\AssetMiddleware; use Cake\Routing\Middleware\RoutingMiddleware; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; use ReflectionProperty; /** - * \App\Application Test Case - * - * @coversDefaultClass \App\Application + * {@see \App\Application} Test Case */ +#[CoversClass(Application::class)] +#[CoversMethod(Application::class, 'bootstrap')] +#[CoversMethod(Application::class, 'bootstrapCli')] +#[CoversMethod(Application::class, 'csrfMiddleware')] +#[CoversMethod(Application::class, 'getAuthenticationService')] +#[CoversMethod(Application::class, 'loadPluginsFromConfig')] +#[CoversMethod(Application::class, 'loadProjectConfig')] +#[CoversMethod(Application::class, 'middleware')] class ApplicationTest extends TestCase { /** * Test `middleware` method * * @return void - * @covers ::middleware() - * @covers ::csrfMiddleware() - * @covers ::bootstrap() - * @covers ::bootstrapCli() */ public function testMiddleware(): void { @@ -90,7 +93,6 @@ public function testMiddleware(): void * Test `csrfMiddleware` method * * @return void - * @covers ::csrfMiddleware() */ public function testCsrfMiddleware(): void { @@ -116,8 +118,8 @@ public function testCsrfMiddleware(): void 'username' => 'abc', 'password' => 'def', ], - ] - ) + ], + ), ); static::assertTrue($actual); } @@ -126,8 +128,6 @@ public function testCsrfMiddleware(): void * Test `bootstrap` method * * @return void - * @covers ::bootstrap() - * @covers ::bootstrapCli() */ public function testBootstrap(): void { @@ -145,7 +145,6 @@ public function testBootstrap(): void * Test `loadPluginsFromConfig` method * * @return void - * @covers ::loadPluginsFromConfig() */ public function testLoadPlugins(): void { @@ -177,7 +176,6 @@ public function testLoadPlugins(): void * Test `loadProjectConfig` method * * @return void - * @covers ::loadProjectConfig() */ public function testLoadProjectConfig(): void { @@ -197,26 +195,28 @@ public function testLoadProjectConfig(): void * Test `getAuthenticationService` method. * * @return void - * @covers ::getAuthenticationService() */ public function testGetAuthenticationService(): void { $app = new Application(CONFIG); /** @var \Authentication\AuthenticationService $authService */ $authService = $app->getAuthenticationService(new ServerRequest()); + /** @var \Authentication\Authenticator\SessionAuthenticator $sessionAuthenticator */ + $sessionAuthenticator = $authService->authenticators()->get('Session'); + /** @var \Authentication\Identifier\IdentifierCollection $identifierCollection */ + $identifierCollection = $sessionAuthenticator->getIdentifier(); /** @var \App\Identifier\ApiIdentifier $identifier */ - $identifier = $authService->identifiers()->get(ApiIdentifier::class); + $identifier = $identifierCollection->get('App\Identifier\ApiIdentifier'); static::assertInstanceOf(AuthenticationService::class, $authService); static::assertInstanceOf(IdentifierInterface::class, $identifier); static::assertInstanceOf(ResolverInterface::class, $identifier->getResolver()); - static::assertInstanceOf(AuthenticatorInterface::class, $authService->authenticators()->get('Session')); + static::assertInstanceOf(AuthenticatorInterface::class, $sessionAuthenticator); } /** * Test `getAuthenticationService` method on login requests. * * @return void - * @covers ::getAuthenticationService() */ public function testLoginGetAuthenticationService(): void { @@ -234,7 +234,6 @@ public function testLoginGetAuthenticationService(): void * Test `getAuthenticationService` method on login requests. * * @return void - * @covers ::getAuthenticationService() */ public function testOAuth2GetAuthenticationService(): void { @@ -245,8 +244,13 @@ public function testOAuth2GetAuthenticationService(): void static::assertFalse($authService->authenticators()->has('Form')); static::assertTrue($authService->authenticators()->has('OAuth2')); - static::assertInstanceOf(AuthenticatorInterface::class, $authService->authenticators()->get('OAuth2')); - static::assertTrue($authService->identifiers()->has('OAuth2')); - static::assertInstanceOf(IdentifierInterface::class, $authService->identifiers()->get('OAuth2')); + $oauth2Authenticator = $authService->authenticators()->get('OAuth2'); + /** @var \BEdita\WebTools\Authenticator\OAuth2Authenticator $oauth2Authenticator */ + static::assertInstanceOf(AuthenticatorInterface::class, $oauth2Authenticator); + /** @var \Authentication\Identifier\IdentifierCollection $identifierCollection */ + $identifierCollection = $oauth2Authenticator->getIdentifier(); + static::assertTrue($identifierCollection->has('OAuth2')); + $oauth2Identifier = $identifierCollection->get('OAuth2'); + static::assertInstanceOf(IdentifierInterface::class, $oauth2Identifier); } } diff --git a/tests/TestCase/Authentication/Identifier/ApiIdentifierTest.php b/tests/TestCase/Authentication/Identifier/ApiIdentifierTest.php index 70e6e2de2..3eaf722da 100644 --- a/tests/TestCase/Authentication/Identifier/ApiIdentifierTest.php +++ b/tests/TestCase/Authentication/Identifier/ApiIdentifierTest.php @@ -16,12 +16,17 @@ use App\Identifier\ApiIdentifier; use BEdita\WebTools\ApiClientProvider; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Identifier\ApiIdentifier} Test Case - * - * @coversDefaultClass \App\Identifier\ApiIdentifier */ +#[CoversClass(ApiIdentifier::class)] +#[CoversMethod(ApiIdentifier::class, 'findIdentity')] +#[CoversMethod(ApiIdentifier::class, 'identify')] +#[CoversMethod(ApiIdentifier::class, 'userTimezone')] class ApiIdentifierTest extends TestCase { /** @@ -29,7 +34,7 @@ class ApiIdentifierTest extends TestCase * * @return array */ - public function identifyProvider(): array + public static function identifyProvider(): array { return [ 'missing-credentials' => [ @@ -77,11 +82,8 @@ public function identifyProvider(): array * @param array $credentials Test credentials * @param array|null $expected Expected result * @return void - * @covers ::identify() - * @covers ::findIdentity() - * @covers ::userTimezone() - * @dataProvider identifyProvider() */ + #[DataProvider('identifyProvider')] public function testIdentify(array $credentials, ?array $expected): void { ApiClientProvider::getApiClient()->setupTokens([]); // reset client diff --git a/tests/TestCase/Authentication/Identifier/Resolver/ApiResolverTest.php b/tests/TestCase/Authentication/Identifier/Resolver/ApiResolverTest.php index 123bb377d..cdb154ce0 100644 --- a/tests/TestCase/Authentication/Identifier/Resolver/ApiResolverTest.php +++ b/tests/TestCase/Authentication/Identifier/Resolver/ApiResolverTest.php @@ -17,15 +17,18 @@ use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Identifier\Resolver\ApiResolver} Test Case - * - * @coversDefaultClass \App\Identifier\Resolver\ApiResolver */ +#[CoversClass(ApiResolver::class)] +#[CoversMethod(ApiResolver::class, 'find')] class ApiResolverTest extends TestCase { - public function findProvider(): array + public static function findProvider(): array { return [ 'missing-credentials' => [ @@ -96,9 +99,8 @@ public function findProvider(): array * @param array $credentials Test credentials * @param array|null $expected Expected result * @return void - * @covers ::find() - * @dataProvider findProvider() */ + #[DataProvider('findProvider')] public function testFind(array $credentials, ?array $expected): void { ApiClientProvider::getApiClient()->setupTokens([]); // reset client @@ -128,7 +130,6 @@ public function testFind(array $credentials, ?array $expected): void * Test missing meta from authentication response. * * @return void - * @covers ::find() */ public function testMissingMetaFromAuthenticationResponse(): void { diff --git a/tests/TestCase/Command/TranslateCommandTest.php b/tests/TestCase/Command/TranslateCommandTest.php index 47974be3a..4ed80de18 100644 --- a/tests/TestCase/Command/TranslateCommandTest.php +++ b/tests/TestCase/Command/TranslateCommandTest.php @@ -13,35 +13,28 @@ namespace App\Test\TestCase\Command; +use App\Command\TranslateCommand; use Cake\Command\Command; use Cake\Console\TestSuite\ConsoleIntegrationTestTrait; use Cake\Core\Configure; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Command\TranslateCommand} Test Case - * - * @coversDefaultClass \App\Command\TranslateCommand */ +#[CoversClass(TranslateCommand::class)] +#[CoversMethod(TranslateCommand::class, 'buildOptionParser')] +#[CoversMethod(TranslateCommand::class, 'execute')] class TranslateCommandTest extends TestCase { use ConsoleIntegrationTestTrait; - /** - * @inheritDoc - */ - public function setUp(): void - { - parent::setUp(); - $this->useCommandRunner(); - } - /** * Test `execute` with code error on no file * * @return void - * @covers ::buildOptionParser() - * @covers ::execute() */ public function testExecuteNoFile(): void { @@ -53,8 +46,6 @@ public function testExecuteNoFile(): void * Test `execute` with code error on no translator * * @return void - * @covers ::buildOptionParser() - * @covers ::execute() */ public function testExecuteNoTranslator(): void { @@ -67,8 +58,6 @@ public function testExecuteNoTranslator(): void * Test `execute` with code success * * @return void - * @covers ::buildOptionParser() - * @covers ::execute() */ public function testExecute(): void { diff --git a/tests/TestCase/Controller/Admin/AdministrationBaseControllerTest.php b/tests/TestCase/Controller/Admin/AdministrationBaseControllerTest.php index da64da838..143b84c3a 100644 --- a/tests/TestCase/Controller/Admin/AdministrationBaseControllerTest.php +++ b/tests/TestCase/Controller/Admin/AdministrationBaseControllerTest.php @@ -6,31 +6,42 @@ use Authentication\AuthenticationServiceInterface; use Authentication\Identity; use Authentication\IdentityInterface; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\Exception\UnauthorizedException; use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use ReflectionClass; /** * {@see \App\Controller\Admin\AdministrationBaseController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\AdministrationBaseController */ +#[CoversClass(AdministrationBaseController::class)] +#[CoversMethod(AdministrationBaseController::class, 'beforeFilter')] +#[CoversMethod(AdministrationBaseController::class, 'endpoint')] +#[CoversMethod(AdministrationBaseController::class, 'index')] +#[CoversMethod(AdministrationBaseController::class, 'initialize')] +#[CoversMethod(AdministrationBaseController::class, 'loadData')] +#[CoversMethod(AdministrationBaseController::class, 'prepareBody')] +#[CoversMethod(AdministrationBaseController::class, 'remove')] +#[CoversMethod(AdministrationBaseController::class, 'save')] class AdministrationBaseControllerTest extends TestCase { - public $AdministrationBaseController; - - public $RlsController; + public RolesController $RlsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -44,7 +55,7 @@ class AdministrationBaseControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -53,13 +64,6 @@ public function setUp(): void { parent::setUp(); $this->loadRoutes(); - - $config = array_merge($this->defaultRequestConfig, []); - $request = new ServerRequest($config); - $this->AdministrationBaseController = new class ($request) extends AdministrationBaseController - { - protected $resourceType = 'applications'; - }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); $adminPassword = getenv('BEDITA_ADMIN_PWD'); @@ -79,8 +83,8 @@ private function initRolesController(array $cfg): void $request = new ServerRequest($config); $this->RlsController = new class ($request) extends RolesController { - protected $resourceType = 'roles'; - protected $properties = ['name']; + protected ?string $resourceType = 'roles'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); @@ -116,24 +120,12 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac return $authenticationService; } - /** - * Test `initialize` method - * - * @return void - * @covers ::initialize() - */ - public function testInitialize(): void - { - $this->AdministrationBaseController->initialize(); - static::assertNotEmpty($this->AdministrationBaseController->Properties); - } - /** * Data provider for `testBeforeFilter` test case. * * @return array */ - public function beforeFilterProvider(): array + public static function beforeFilterProvider(): array { return [ 'not authorized' => [ @@ -168,25 +160,30 @@ public function beforeFilterProvider(): array * @param \Exception|string|null $expected Expected result * @param array $data setup data for test * @return void - * @covers ::beforeFilter() - * @dataProvider beforeFilterProvider() */ + #[DataProvider('beforeFilterProvider')] public function testBeforeFilter($expected, array $data): void { if (isset($data['tokens'])) { $data['tokens'] = $this->client->getTokens(); } + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends AdministrationBaseController + { + protected ?string $resourceType = 'applications'; + }; // Mock Authentication component - $this->AdministrationBaseController->setRequest($this->AdministrationBaseController->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); - $this->AdministrationBaseController->Authentication->setIdentity(new Identity($data)); + $controller->setRequest($controller->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); + $controller->Authentication->setIdentity(new Identity($data)); - if ($expected instanceof \Exception) { + if ($expected instanceof Exception) { $this->expectException(get_class($expected)); } - $event = $this->AdministrationBaseController->dispatchEvent('Controller.beforeFilter'); - $result = $this->AdministrationBaseController->beforeFilter($event); + $event = $controller->dispatchEvent('Controller.beforeFilter'); + $result = $controller->beforeFilter($event); if (is_string($expected)) { static::assertInstanceOf($expected, $result); @@ -199,11 +196,16 @@ public function testBeforeFilter($expected, array $data): void * Test `index` method * * @return void - * @covers ::index() */ public function testIndex(): void { - $this->AdministrationBaseController->index(); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends AdministrationBaseController + { + protected ?string $resourceType = 'applications'; + }; + $controller->index(); $keys = [ 'resources', 'meta', @@ -216,20 +218,20 @@ public function testIndex(): void 'readonly', 'deleteonly', ]; - $viewVars = (array)$this->AdministrationBaseController->viewBuilder()->getVars(); + $viewVars = (array)$controller->viewBuilder()->getVars(); foreach ($keys as $expectedKey) { static::assertArrayHasKey($expectedKey, $viewVars); } $config = array_merge($this->defaultRequestConfig, []); $request = new ServerRequest($config); - $this->AdministrationBaseController = new class ($request) extends AdministrationBaseController + $controller = new class ($request) extends AdministrationBaseController { - protected $resourceType = 'wrongtype'; + protected ?string $resourceType = 'wrongtype'; }; - $this->AdministrationBaseController->index(); - $viewVars = (array)$this->AdministrationBaseController->viewBuilder()->getVars(); + $controller->index(); + $viewVars = (array)$controller->viewBuilder()->getVars(); foreach ($keys as $expectedKey) { static::assertArrayNotHasKey($expectedKey, $viewVars); } @@ -240,7 +242,7 @@ public function testIndex(): void * * @return array */ - public function saveProvider(): array + public static function saveProvider(): array { return [ 'post 400' => [ @@ -275,10 +277,8 @@ public function saveProvider(): array * Test `save` method * * @return void - * @covers ::prepareBody() - * @covers ::save() - * @dataProvider saveProvider() */ + #[DataProvider('saveProvider')] public function testSave(array $config, string $expected): void { $this->initRolesController($config); @@ -294,14 +294,13 @@ public function testSave(array $config, string $expected): void * Test `prepareBody` method * * @return void - * @covers ::prepareBody() */ public function testPrepareBody(): void { - $controller = new class () extends AdministrationBaseController + $controller = new class (new ServerRequest()) extends AdministrationBaseController { - protected $resourceType = 'auth_providers'; - protected $propertiesForceJson = [ + protected ?string $resourceType = 'auth_providers'; + protected array $propertiesForceJson = [ 'params', ]; @@ -334,7 +333,6 @@ public function prepareBody(array $data): array * Test `remove` method * * @return void - * @covers ::remove() */ public function testRemove(): void { @@ -346,7 +344,7 @@ public function testRemove(): void 'params' => [ 'resource_type' => 'roles', ], - ] + ], ); $response = $this->RlsController->remove('9999999999'); static::assertEquals(302, $response->getStatusCode()); @@ -361,7 +359,6 @@ public function testRemove(): void * Test `endpoint` method * * @return void - * @covers ::endpoint() */ public function testEndpoint(): void { @@ -373,18 +370,24 @@ public function testEndpoint(): void 'params' => [ 'resource_type' => 'roles', ], - ] + ], ); - $reflectionClass = new \ReflectionClass($this->RlsController); + $reflectionClass = new ReflectionClass($this->RlsController); $method = $reflectionClass->getMethod('endpoint'); $method->setAccessible(true); $actual = $method->invokeArgs($this->RlsController, []); static::assertEquals('/roles', $actual); - $reflectionClass = new \ReflectionClass($this->AdministrationBaseController); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends AdministrationBaseController + { + protected ?string $resourceType = 'applications'; + }; + $reflectionClass = new ReflectionClass($controller); $method = $reflectionClass->getMethod('endpoint'); $method->setAccessible(true); - $actual = $method->invokeArgs($this->AdministrationBaseController, []); + $actual = $method->invokeArgs($controller, []); static::assertEquals('/admin/applications', $actual); } @@ -392,7 +395,6 @@ public function testEndpoint(): void * Test `loadData` method * * @return void - * @covers ::loadData() */ public function testLoadData(): void { @@ -408,9 +410,9 @@ public function testLoadData(): void 'page' => 1, 'page_size' => 1, ], - ] + ], ); - $reflectionClass = new \ReflectionClass($this->RlsController); + $reflectionClass = new ReflectionClass($this->RlsController); $method = $reflectionClass->getMethod('loadData'); $method->setAccessible(true); $actual = $method->invokeArgs($this->RlsController, []); diff --git a/tests/TestCase/Controller/Admin/AppearanceControllerTest.php b/tests/TestCase/Controller/Admin/AppearanceControllerTest.php index 02faf8b37..59c43e7ae 100644 --- a/tests/TestCase/Controller/Admin/AppearanceControllerTest.php +++ b/tests/TestCase/Controller/Admin/AppearanceControllerTest.php @@ -6,12 +6,16 @@ use Cake\Cache\Cache; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Admin\AppearanceController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\AppearanceController */ +#[CoversClass(AppearanceController::class)] +#[CoversMethod(AppearanceController::class, 'index')] +#[CoversMethod(AppearanceController::class, 'initialize')] +#[CoversMethod(AppearanceController::class, 'save')] class AppearanceControllerTest extends TestCase { /** @@ -19,7 +23,7 @@ class AppearanceControllerTest extends TestCase * * @var \App\Controller\Admin\AppearanceController */ - public $Appearance; + public AppearanceController $Appearance; /** * @inheritDoc @@ -47,7 +51,6 @@ public function tearDown(): void * Test index * * @return void - * @covers ::index() */ public function testIndex(): void { @@ -57,8 +60,8 @@ public function testIndex(): void 'environment' => [ 'REQUEST_METHOD' => 'GET', ], - ] - ) + ], + ), ); $this->Appearance->index(); $viewVars = (array)$this->Appearance->viewBuilder()->getVars(); @@ -76,8 +79,6 @@ public function testIndex(): void * Test save * * @return void - * @covers ::initialize() - * @covers ::save() */ public function testSave(): void { @@ -91,8 +92,8 @@ public function testSave(): void 'property_name' => 'properties', 'property_value' => '[]', ], - ] - ) + ], + ), ); $this->Appearance->save(); $viewVars = (array)$this->Appearance->viewBuilder()->getVars(); diff --git a/tests/TestCase/Controller/Admin/ApplicationsControllerTest.php b/tests/TestCase/Controller/Admin/ApplicationsControllerTest.php index 311e3a0b3..fc8ac2f4d 100644 --- a/tests/TestCase/Controller/Admin/ApplicationsControllerTest.php +++ b/tests/TestCase/Controller/Admin/ApplicationsControllerTest.php @@ -2,25 +2,26 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\ApplicationsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; /** * {@see \App\Controller\Admin\ApplicationsController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\ApplicationsController */ +#[CoversClass(ApplicationsController::class)] class ApplicationsControllerTest extends TestCase { - public $AppsController; + public ApplicationsController $AppsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -34,7 +35,7 @@ class ApplicationsControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -47,9 +48,9 @@ public function setUp(): void $request = new ServerRequest($config); $this->AppsController = new class ($request) extends ApplicationsController { - protected $resourceType = 'applications'; - protected $properties = ['name']; - protected $propertiesSecrets = ['api_key', 'client_secret']; + protected ?string $resourceType = 'applications'; + protected array $properties = ['name']; + protected array $propertiesSecrets = ['api_key', 'client_secret']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); diff --git a/tests/TestCase/Controller/Admin/AsyncJobsControllerTest.php b/tests/TestCase/Controller/Admin/AsyncJobsControllerTest.php index a23f98029..79c6ff870 100644 --- a/tests/TestCase/Controller/Admin/AsyncJobsControllerTest.php +++ b/tests/TestCase/Controller/Admin/AsyncJobsControllerTest.php @@ -2,15 +2,16 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\AsyncJobsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; /** * {@see \App\Controller\Admin\AsyncJobsController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\AsyncJobsController */ +#[CoversClass(AsyncJobsController::class)] class AsyncJobsControllerTest extends TestCase { /** @@ -18,14 +19,14 @@ class AsyncJobsControllerTest extends TestCase * * @var \App\Controller\Admin\AsyncJobsController */ - public $AsyncJobsController; + public AsyncJobsController $AsyncJobsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -39,7 +40,7 @@ class AsyncJobsControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -52,8 +53,8 @@ public function setUp(): void $request = new ServerRequest($config); $this->AsyncJobsController = new class ($request) extends AsyncJobsController { - protected $resourceType = 'async_jobs'; - protected $properties = ['name']; + protected ?string $resourceType = 'async_jobs'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); diff --git a/tests/TestCase/Controller/Admin/AuthProvidersControllerTest.php b/tests/TestCase/Controller/Admin/AuthProvidersControllerTest.php index 69650c6c0..84b104987 100644 --- a/tests/TestCase/Controller/Admin/AuthProvidersControllerTest.php +++ b/tests/TestCase/Controller/Admin/AuthProvidersControllerTest.php @@ -5,12 +5,12 @@ use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; /** * {@see \App\Controller\Admin\AuthProvidersController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\AuthProvidersController */ +#[CoversClass(AuthProvidersController::class)] class AuthProvidersControllerTest extends TestCase { /** @@ -52,8 +52,8 @@ public function setUp(): void $request = new ServerRequest($config); $this->AuthProvidersController = new class ($request) extends AuthProvidersController { - protected $resourceType = 'auth_providers'; - protected $properties = ['name']; + protected ?string $resourceType = 'auth_providers'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); diff --git a/tests/TestCase/Controller/Admin/CacheControllerTest.php b/tests/TestCase/Controller/Admin/CacheControllerTest.php index 056cf4861..17691beb5 100644 --- a/tests/TestCase/Controller/Admin/CacheControllerTest.php +++ b/tests/TestCase/Controller/Admin/CacheControllerTest.php @@ -5,20 +5,22 @@ use Cake\Cache\Cache; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Admin\CacheController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\CacheController */ +#[CoversClass(CacheController::class)] +#[CoversMethod(CacheController::class, 'clear')] class CacheControllerTest extends TestCase { /** * Test subject * - * @var CacheController + * @var \App\Controller\Admin\CacheController */ - public $Cache; + public CacheController $Cache; /** * @inheritDoc @@ -44,7 +46,6 @@ public function tearDown(): void * Test clear * * @return void - * @covers ::clear() */ public function testClear(): void { @@ -56,8 +57,8 @@ public function testClear(): void 'environment' => [ 'REQUEST_METHOD' => 'GET', ], - ] - ) + ], + ), ); $this->Cache->clear(); static::assertEmpty(Cache::read('something')); diff --git a/tests/TestCase/Controller/Admin/ConfigControllerTest.php b/tests/TestCase/Controller/Admin/ConfigControllerTest.php index a93ff28b7..6dfb63df3 100644 --- a/tests/TestCase/Controller/Admin/ConfigControllerTest.php +++ b/tests/TestCase/Controller/Admin/ConfigControllerTest.php @@ -2,25 +2,29 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\ConfigController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Admin\ConfigController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\ConfigController */ +#[CoversClass(ConfigController::class)] +#[CoversMethod(ConfigController::class, 'beforeFilter')] +#[CoversMethod(ConfigController::class, 'fetchApplications')] class ConfigControllerTest extends TestCase { - public $CfgController; + public ConfigController $CfgController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -34,7 +38,7 @@ class ConfigControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -48,8 +52,8 @@ public function setUp(): void $request = new ServerRequest($config); $this->CfgController = new class ($request) extends ConfigController { - protected $resourceType = 'config'; - protected $properties = ['name']; + protected ?string $resourceType = 'config'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); @@ -90,7 +94,6 @@ public function testBase(): void * Test `beforeFilter` * * @return void - * @covers ::beforeFilter() */ public function testBeforeFilter(): void { @@ -104,7 +107,6 @@ public function testBeforeFilter(): void * Test `fetchApplications` * * @return void - * @covers ::fetchApplications() */ public function testFetchApplications(): void { diff --git a/tests/TestCase/Controller/Admin/EndpointPermissionsControllerTest.php b/tests/TestCase/Controller/Admin/EndpointPermissionsControllerTest.php index ec3f8575b..2989d8265 100644 --- a/tests/TestCase/Controller/Admin/EndpointPermissionsControllerTest.php +++ b/tests/TestCase/Controller/Admin/EndpointPermissionsControllerTest.php @@ -2,26 +2,27 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\EndpointPermissionsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; /** * {@see \App\Controller\Admin\EndpointPermissionsController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\EndpointPermissionsController */ +#[CoversClass(EndpointPermissionsController::class)] class EndpointPermissionsControllerTest extends TestCase { - public $EndPermsController; + public EndpointPermissionsController $EndPermsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -35,7 +36,7 @@ class EndpointPermissionsControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -48,8 +49,8 @@ public function setUp(): void $request = new ServerRequest($config); $this->EndPermsController = new class ($request) extends EndpointPermissionsController { - protected $resourceType = 'endpoint_permissions'; - protected $properties = ['endpoint_id', 'application_id']; + protected ?string $resourceType = 'endpoint_permissions'; + protected array $properties = ['endpoint_id', 'application_id']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); @@ -108,8 +109,8 @@ public function testSave(): void $request = new ServerRequest($config); $this->EndPermsController = new class ($request) extends EndpointPermissionsController { - protected $resourceType = 'endpoint_permissions'; - protected $properties = ['endpoint_id', 'application_id']; + protected ?string $resourceType = 'endpoint_permissions'; + protected array $properties = ['endpoint_id', 'application_id']; }; $response = $this->EndPermsController->save(); static::assertSame(Response::class, get_class($response)); diff --git a/tests/TestCase/Controller/Admin/EndpointsControllerTest.php b/tests/TestCase/Controller/Admin/EndpointsControllerTest.php index b64292165..9e1fff558 100644 --- a/tests/TestCase/Controller/Admin/EndpointsControllerTest.php +++ b/tests/TestCase/Controller/Admin/EndpointsControllerTest.php @@ -2,25 +2,26 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\EndpointsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; /** * {@see \App\Controller\Admin\EndpointsController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\EndpointsController */ +#[CoversClass(EndpointsController::class)] class EndpointsControllerTest extends TestCase { - public $EndsController; + public EndpointsController $EndsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -34,7 +35,7 @@ class EndpointsControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -47,8 +48,8 @@ public function setUp(): void $request = new ServerRequest($config); $this->EndsController = new class ($request) extends EndpointsController { - protected $resourceType = 'endpoints'; - protected $properties = ['name']; + protected string|null $resourceType = 'endpoints'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); diff --git a/tests/TestCase/Controller/Admin/ExternalAuthControllerTest.php b/tests/TestCase/Controller/Admin/ExternalAuthControllerTest.php index d0e7865ab..67ffc1f33 100644 --- a/tests/TestCase/Controller/Admin/ExternalAuthControllerTest.php +++ b/tests/TestCase/Controller/Admin/ExternalAuthControllerTest.php @@ -5,12 +5,12 @@ use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; /** * {@see \App\Controller\Admin\ExternalAuthController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\ExternalAuthController */ +#[CoversClass(ExternalAuthController::class)] class ExternalAuthControllerTest extends TestCase { /** @@ -52,8 +52,8 @@ public function setUp(): void $request = new ServerRequest($config); $this->ExternalAuthController = new class ($request) extends ExternalAuthController { - protected $resourceType = 'external_auth'; - protected $properties = ['name']; + protected ?string $resourceType = 'external_auth'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); diff --git a/tests/TestCase/Controller/Admin/ObjectsHistoryControllerTest.php b/tests/TestCase/Controller/Admin/ObjectsHistoryControllerTest.php index 18e9eeb74..23238033d 100644 --- a/tests/TestCase/Controller/Admin/ObjectsHistoryControllerTest.php +++ b/tests/TestCase/Controller/Admin/ObjectsHistoryControllerTest.php @@ -2,25 +2,26 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\ObjectsHistoryController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; /** * {@see \App\Controller\Admin\ObjectsHistoryController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\ObjectsHistoryController */ +#[CoversClass(ObjectsHistoryController::class)] class ObjectsHistoryControllerTest extends TestCase { - public $ObjectsHistoryController; + public ObjectsHistoryController $ObjectsHistoryController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -34,7 +35,7 @@ class ObjectsHistoryControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc diff --git a/tests/TestCase/Controller/Admin/RolesControllerTest.php b/tests/TestCase/Controller/Admin/RolesControllerTest.php index 677c491f3..f059d22ef 100644 --- a/tests/TestCase/Controller/Admin/RolesControllerTest.php +++ b/tests/TestCase/Controller/Admin/RolesControllerTest.php @@ -3,25 +3,29 @@ use App\Controller\Admin\RolesController; use App\Test\TestCase\Controller\BaseControllerTest; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Cache\Cache; use Cake\Http\ServerRequest; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Admin\RolesController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\RolesController */ +#[CoversClass(RolesController::class)] +#[CoversMethod(RolesController::class, 'save')] +#[CoversMethod(RolesController::class, 'remove')] class RolesControllerTest extends BaseControllerTest { - public $RlsController; + public RolesController $RlsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -35,7 +39,7 @@ class RolesControllerTest extends BaseControllerTest * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * @inheritDoc @@ -70,8 +74,8 @@ private function init(array $requestConfig): void $request = new ServerRequest($config); $this->RlsController = new class ($request) extends RolesController { - protected $resourceType = 'roles'; - protected $properties = ['name']; + protected ?string $resourceType = 'roles'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); diff --git a/tests/TestCase/Controller/Admin/RolesModulesControllerTest.php b/tests/TestCase/Controller/Admin/RolesModulesControllerTest.php index 1598dfdd0..13c60c9a9 100644 --- a/tests/TestCase/Controller/Admin/RolesModulesControllerTest.php +++ b/tests/TestCase/Controller/Admin/RolesModulesControllerTest.php @@ -11,24 +11,29 @@ use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use ReflectionClass; /** * {@see \App\Controller\Admin\RolesModulesController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\RolesModulesController */ +#[CoversClass(RolesModulesController::class)] +#[CoversMethod(RolesModulesController::class, 'allowedRoles')] +#[CoversMethod(RolesModulesController::class, 'index')] +#[CoversMethod(RolesModulesController::class, 'save')] class RolesModulesControllerTest extends TestCase { use ApiConfigTrait; - public $RlsController; + public RolesModulesController $RlsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -42,7 +47,7 @@ class RolesModulesControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -78,8 +83,8 @@ private function init(array $requestConfig): void $request = new ServerRequest($config); $this->RlsController = new class ($request) extends RolesModulesController { - protected $resourceType = 'roles'; - protected $properties = ['name']; + protected ?string $resourceType = 'roles'; + protected array $properties = ['name']; }; $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); @@ -92,7 +97,6 @@ private function init(array $requestConfig): void * Basic test * * @return void - * @covers ::index() */ public function testIndex(): void { @@ -122,7 +126,6 @@ public function testIndex(): void * Test `index` exception * * @return void - * @covers ::index() */ public function testIndexException(): void { @@ -130,21 +133,23 @@ public function testIndexException(): void $apiClient = $this->getMockBuilder(BEditaClient::class) ->setConstructorArgs(['https://example.com']) ->getMock(); - $apiClient->method('get')->will( - $this->returnCallback( - function ($param) { - if ($param === '/roles') { - return ['data' => [], 'meta' => [], 'links' => []]; - } - if ($param === '/admin/endpoint_permissions') { - throw new BEditaClientException('My test exception'); - } + $apiClient->method('get')->willReturnCallback( + function ($param) { + if ($param === '/roles') { + return ['data' => [], 'meta' => [], 'links' => []]; } - ) + if ($param === '/admin/endpoint_permissions') { + throw new BEditaClientException('My test exception'); + } + }, ); - $this->RlsController->apiClient = $apiClient; - $this->RlsController->index(); - $flash = $this->RlsController->getRequest()->getSession()->read('Flash.flash'); + $controller = new class ($this->RlsController->getRequest()) extends RolesModulesController + { + public ?BEditaClient $apiClient; + }; + $controller->apiClient = $apiClient; + $controller->index(); + $flash = $controller->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('My test exception', Hash::get($flash, '0.message')); } @@ -152,7 +157,6 @@ function ($param) { * Test save * * @return void - * @covers ::save() */ public function testSave(): void { @@ -179,8 +183,8 @@ public function testSave(): void 'post' => [ 'roles' => $roles, ], - ] - ) + ], + ), ); $response = $this->RlsController->save(); static::assertSame(Response::class, get_class($response)); @@ -190,11 +194,10 @@ public function testSave(): void * Test `allowedRoles` * * @return void - * @covers ::allowedRoles() */ public function testAllowedRoles(): void { - $reflection = new \ReflectionClass(get_class($this->RlsController)); + $reflection = new ReflectionClass(get_class($this->RlsController)); $method = $reflection->getMethod('allowedRoles'); $method->setAccessible(true); diff --git a/tests/TestCase/Controller/Admin/StatisticsControllerTest.php b/tests/TestCase/Controller/Admin/StatisticsControllerTest.php index fa6ed8d38..7a5248143 100644 --- a/tests/TestCase/Controller/Admin/StatisticsControllerTest.php +++ b/tests/TestCase/Controller/Admin/StatisticsControllerTest.php @@ -3,25 +3,32 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\StatisticsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Admin\StatisticsController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\StatisticsController */ +#[CoversClass(StatisticsController::class)] +#[CoversMethod(StatisticsController::class, 'fetch')] +#[CoversMethod(StatisticsController::class, 'fetchCount')] +#[CoversMethod(StatisticsController::class, 'index')] +#[CoversMethod(StatisticsController::class, 'intervals')] class StatisticsControllerTest extends TestCase { - public $StatisticsController; + public StatisticsController $StatisticsController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -32,7 +39,7 @@ class StatisticsControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -55,10 +62,6 @@ public function setUp(): void * Test `index` method * * @return void - * @covers ::index() - * @covers ::fetch() - * @covers ::intervals() - * @covers ::fetchCount() */ public function testIndex(): void { @@ -100,14 +103,13 @@ public function testIndex(): void * Test `fetchCount` method * * @return void - * @covers ::fetchCount() */ public function testFetchCountZero(): void { - $controller = new class () extends StatisticsController { - public function fetchCount(string $objectType, string $start, string $end): int + $controller = new class (new ServerRequest()) extends StatisticsController { + public function fetchCount(string $objectType, string $from, string $to): int { - return parent::fetchCount($objectType, $start, $end); + return parent::fetchCount($objectType, $from, $to); } }; $actual = $controller->fetchCount('documents', '2999-01-01', '2999-12-31'); @@ -118,8 +120,6 @@ public function fetchCount(string $objectType, string $start, string $end): int * Test `fetchCount` method when exception is thrown * * @return void - * @covers ::index() - * @covers ::fetchCount() */ public function testFetchCountException(): void { @@ -150,7 +150,7 @@ public function testFetchCountException(): void * * @return array */ - public function intervalsProvider(): array + public static function intervalsProvider(): array { return [ 'case day: return interval with just one day' => [ @@ -192,10 +192,8 @@ public function intervalsProvider(): array * Test `intervals` method * * @return void - * @covers ::index() - * @covers ::intervals() - * @dataProvider intervalsProvider() */ + #[DataProvider('intervalsProvider')] public function testIntervals(array $query, array $expected): void { $request = new ServerRequest([ diff --git a/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php b/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php index 5c3292ad1..be667cced 100644 --- a/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php +++ b/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php @@ -8,22 +8,26 @@ use BEdita\SDK\BEditaClientException; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Admin\SystemInfoController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\SystemInfoController */ +#[CoversClass(SystemInfoController::class)] +#[CoversMethod(SystemInfoController::class, 'getApiInfo')] +#[CoversMethod(SystemInfoController::class, 'getSystemInfo')] +#[CoversMethod(SystemInfoController::class, 'index')] class SystemInfoControllerTest extends AppControllerTest { - public $SystemInfoController; + public SystemInfoController $SystemInfoController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -37,7 +41,7 @@ class SystemInfoControllerTest extends AppControllerTest * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -60,7 +64,6 @@ public function setUp(): void * Test `index` method * * @return void - * @covers ::index() */ public function testIndex(): void { @@ -86,7 +89,6 @@ public function testIndex(): void * Test `getSystemInfo` method * * @return void - * @covers ::getSystemInfo() */ public function testGetSystemInfo(): void { @@ -114,7 +116,6 @@ public function testGetSystemInfo(): void * Test `getApiInfo` method * * @return void - * @covers ::getApiInfo() */ public function testGetApiInfo(): void { @@ -140,7 +141,6 @@ public function testGetApiInfo(): void * Test `getApiInfo` method with exception * * @return void - * @covers ::getApiInfo() */ public function testGetApiInfoException(): void { @@ -153,7 +153,7 @@ public function testGetApiInfoException(): void 'Url' => getenv('BEDITA_API'), 'Version' => '', ]; - $controller = new class () extends SystemInfoController { + $controller = new class (new ServerRequest()) extends SystemInfoController { public function setApiClient($client): void { $this->apiClient = $client; diff --git a/tests/TestCase/Controller/Admin/UserAccessesControllerTest.php b/tests/TestCase/Controller/Admin/UserAccessesControllerTest.php index 9e62ec602..511f87b05 100644 --- a/tests/TestCase/Controller/Admin/UserAccessesControllerTest.php +++ b/tests/TestCase/Controller/Admin/UserAccessesControllerTest.php @@ -2,25 +2,28 @@ namespace App\Test\TestCase\Controller\Admin; use App\Controller\Admin\UserAccessesController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Admin\UserAccessesController} Test Case - * - * @coversDefaultClass \App\Controller\Admin\UserAccessesController */ +#[CoversClass(UserAccessesController::class)] +#[CoversMethod(UserAccessesController::class, 'index')] class UserAccessesControllerTest extends TestCase { - public $UserAccessesController; + public UserAccessesController $UserAccessesController; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -34,7 +37,7 @@ class UserAccessesControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -57,7 +60,6 @@ public function setUp(): void * Basic test * * @return void - * @covers ::index() */ public function testIndex(): void { diff --git a/tests/TestCase/Controller/ApiControllerTest.php b/tests/TestCase/Controller/ApiControllerTest.php index 035d6d49e..44ba149a7 100644 --- a/tests/TestCase/Controller/ApiControllerTest.php +++ b/tests/TestCase/Controller/ApiControllerTest.php @@ -23,15 +23,18 @@ use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * {@see \App\Controller\ApiController} Test Case - * - * @coversDefaultClass \App\Controller\ApiController - * @uses \App\Controller\ApiController */ +#[CoversClass(ApiController::class)] +#[CoversMethod(ApiController::class, 'allowed')] +#[CoversMethod(ApiController::class, 'beforeFilter')] class ApiControllerTest extends TestCase { /** @@ -75,7 +78,7 @@ protected function setupController($config = null): void * * @return array */ - public function unauthorizedExceptionProvider(): array + public static function unauthorizedExceptionProvider(): array { return [ 'no same origin' => [ @@ -117,10 +120,8 @@ public function unauthorizedExceptionProvider(): array * * @param array $config Request configuration. * @return void - * @dataProvider unauthorizedExceptionProvider - * @covers ::beforeFilter() - * @covers ::allowed() */ + #[DataProvider('unauthorizedExceptionProvider')] public function testUnauthorizedException(array $config): void { $expected = new UnauthorizedException(__('You are not authorized to access this resource')); @@ -136,8 +137,6 @@ public function testUnauthorizedException(array $config): void * Test unauthorized role * * @return void - * @covers ::beforeFilter() - * @covers ::allowed() */ public function testUnauthorizedRole(): void { @@ -165,8 +164,6 @@ public function testUnauthorizedRole(): void * Test for authorized admin * * @return void - * @covers ::beforeFilter() - * @covers ::allowed() */ public function testAuthorizeAdmin(): void { @@ -184,7 +181,7 @@ public function testAuthorizeAdmin(): void $this->ApiController->setRequest($this->ApiController->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); $this->ApiController->Authentication->setIdentity($user); $this->ApiController->dispatchEvent('Controller.initialize'); - $actual = $this->ApiController->Security->getConfig('unlockedActions'); + $actual = $this->ApiController->FormProtection->getConfig('unlockedActions'); $expected = ['post', 'patch', 'delete']; static::assertEquals($expected, $actual); } @@ -193,8 +190,6 @@ public function testAuthorizeAdmin(): void * Test for authorized user * * @return void - * @covers ::beforeFilter() - * @covers ::allowed() */ public function testUserAllowed(): void { @@ -213,7 +208,7 @@ public function testUserAllowed(): void $this->ApiController->setRequest($this->ApiController->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); $this->ApiController->Authentication->setIdentity($user); $this->ApiController->dispatchEvent('Controller.initialize'); - $actual = $this->ApiController->Security->getConfig('unlockedActions'); + $actual = $this->ApiController->FormProtection->getConfig('unlockedActions'); $expected = ['post', 'patch', 'delete']; static::assertEquals($expected, $actual); } diff --git a/tests/TestCase/Controller/AppControllerTest.php b/tests/TestCase/Controller/AppControllerTest.php index 3dc064a37..5aac3b56c 100644 --- a/tests/TestCase/Controller/AppControllerTest.php +++ b/tests/TestCase/Controller/AppControllerTest.php @@ -18,7 +18,7 @@ use App\Identifier\ApiIdentifier; use Authentication\AuthenticationService; use Authentication\AuthenticationServiceInterface; -use Authentication\Identifier\IdentifierInterface; +use Authentication\Identifier\AbstractIdentifier; use Authentication\Identity; use Authentication\IdentityInterface; use BEdita\SDK\BEditaClient; @@ -28,15 +28,39 @@ use Cake\Http\Exception\MethodNotAllowedException; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use DateTime; +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use ReflectionClass; +use ReflectionProperty; +use stdClass; /** * {@see \App\Controller\AppController} Test Case - * - * @coversDefaultClass \App\Controller\AppController - * @uses \App\Controller\AppController */ +#[CoversClass(AppController::class)] +#[CoversMethod(AppController::class, 'applySessionFilter')] +#[CoversMethod(AppController::class, 'beforeFilter')] +#[CoversMethod(AppController::class, 'beforeRender')] +#[CoversMethod(AppController::class, 'changedAttributes')] +#[CoversMethod(AppController::class, 'checkRequest')] +#[CoversMethod(AppController::class, 'decodeJsonAttributes')] +#[CoversMethod(AppController::class, 'filterEmpty')] +#[CoversMethod(AppController::class, 'getObjectNav')] +#[CoversMethod(AppController::class, 'hasFieldChanged')] +#[CoversMethod(AppController::class, 'initialize')] +#[CoversMethod(AppController::class, 'loginRedirectRoute')] +#[CoversMethod(AppController::class, 'prepareRequest')] +#[CoversMethod(AppController::class, 'prepareDateRanges')] +#[CoversMethod(AppController::class, 'prepareRelations')] +#[CoversMethod(AppController::class, 'relatedIds')] +#[CoversMethod(AppController::class, 'setupOutputTimezone')] +#[CoversMethod(AppController::class, 'setObjectNav')] +#[CoversMethod(AppController::class, 'specialAttributes')] class AppControllerTest extends TestCase { /** @@ -63,7 +87,7 @@ public function setUp(): void */ protected function setupController($config = null): void { - $request = null; + $request = new ServerRequest(); if ($config != null) { $request = new ServerRequest($config); if (!empty($config['?'])) { @@ -94,11 +118,11 @@ protected function setupControllerAndLogin(): ?array // Mock Authentication component ApiClientProvider::getApiClient()->setupTokens([]); // reset client $service = new AuthenticationService(); - $service->loadIdentifier(ApiIdentifier::class); $service->loadAuthenticator('Authentication.Form', [ + 'identifier' => ApiIdentifier::class, 'fields' => [ - IdentifierInterface::CREDENTIAL_USERNAME => 'username', - IdentifierInterface::CREDENTIAL_PASSWORD => 'password', + AbstractIdentifier::CREDENTIAL_USERNAME => 'username', + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password', ], ]); $this->AppController->setRequest($this->AppController->getRequest()->withAttribute('authentication', $service)); @@ -143,15 +167,13 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac * test `initialize` function * * @return void - * @covers ::initialize() */ public function testInitialize(): void { $this->setupController(); - static::assertNotEmpty($this->AppController->{'RequestHandler'}); static::assertNotEmpty($this->AppController->{'Flash'}); - static::assertNotEmpty($this->AppController->{'Security'}); + static::assertNotEmpty($this->AppController->{'FormProtection'}); static::assertNotEmpty($this->AppController->{'Authentication'}); static::assertNotEmpty($this->AppController->{'Modules'}); static::assertNotEmpty($this->AppController->{'Schema'}); @@ -160,7 +182,6 @@ public function testInitialize(): void /** * test `beforeFilter` not logged error * - * @covers ::beforeFilter() * @return void */ public function testBeforeFilterLoginError(): void @@ -170,7 +191,7 @@ public function testBeforeFilterLoginError(): void // Mock Authentication component $this->AppController->setRequest($this->AppController->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); - $event = $this->AppController->dispatchEvent('Controller.initialize'); + $this->AppController->dispatchEvent('Controller.initialize'); $flash = $this->AppController->getRequest()->getSession()->read('Flash'); @@ -184,8 +205,6 @@ public function testBeforeFilterLoginError(): void * test 'initialize' and 'beforeFilter' for correct apiClient token setup * * @return void - * @covers ::beforeFilter() - * @covers ::initialize() */ public function testCorrectTokens(): void { @@ -217,7 +236,7 @@ public function testCorrectTokens(): void * * @return array */ - public function loginRedirectRouteProvider(): array + public static function loginRedirectRouteProvider(): array { return [ 'request is not a get' => [ @@ -238,14 +257,13 @@ public function loginRedirectRouteProvider(): array /** * test 'loginRedirectRoute'. * - * @covers ::loginRedirectRoute() - * @dataProvider loginRedirectRouteProvider() * @return void */ + #[DataProvider('loginRedirectRouteProvider')] public function testLoginRedirectRoute($config, $expected): void { $this->setupController($config); - $reflectionClass = new \ReflectionClass($this->AppController); + $reflectionClass = new ReflectionClass($this->AppController); $method = $reflectionClass->getMethod('loginRedirectRoute'); $method->setAccessible(true); $actual = $method->invokeArgs($this->AppController, []); @@ -255,7 +273,6 @@ public function testLoginRedirectRoute($config, $expected): void /** * test `setupOutputTimezone` * - * @covers ::setupOutputTimezone * @return void */ public function testSetupOutputTimezone(): void @@ -284,14 +301,13 @@ public function testSetupOutputTimezone(): void /** * Test `beforeRender` method for correct user object in Controller viewVars * - * @covers ::beforeRender() * @return void */ public function testBeforeRender(): void { $user = $this->setupControllerAndLogin(); - $event = $this->AppController->dispatchEvent('Controller.beforeRender'); + $this->AppController->dispatchEvent('Controller.beforeRender'); static::assertArrayHasKey('user', $this->AppController->viewBuilder()->getVars()); $user = $this->AppController->viewBuilder()->getVar('user'); @@ -303,7 +319,6 @@ public function testBeforeRender(): void /** * Test `beforeRender` method, when updating tokens in session * - * @covers ::beforeRender() * @return void */ public function testBeforeRenderUpdateTokens(): void @@ -325,7 +340,7 @@ public function testBeforeRenderUpdateTokens(): void ->willReturn($updatedToken); // set $this->AppController->apiClient - $property = new \ReflectionProperty(AppController::class, 'apiClient'); + $property = new ReflectionProperty(AppController::class, 'apiClient'); $property->setAccessible(true); $property->setValue($this->AppController, $apiClient); @@ -342,7 +357,7 @@ public function testBeforeRenderUpdateTokens(): void * * @return array */ - public function prepareRequestProvider(): array + public static function prepareRequestProvider(): array { return [ 'documents' => [ // test _jsonKeys json_decode @@ -634,7 +649,7 @@ public function prepareRequestProvider(): array 'empty json' => [ 'documents', [ - 'json_prop' => new \stdClass(), + 'json_prop' => new stdClass(), 'json_prop2' => [ 'gin' => 'vodka', ], @@ -700,17 +715,9 @@ public function prepareRequestProvider(): array * @param string $objectType The object type * @param array $expected The expected request data * @param array $data The payload data - * @covers ::prepareRequest() - * @covers ::specialAttributes() - * @covers ::decodeJsonAttributes() - * @covers ::prepareDateRanges() - * @covers ::prepareRelations() - * @covers ::setupParentsRelation() - * @covers ::changedAttributes() - * @covers ::filterEmpty() - * @dataProvider prepareRequestProvider() * @return void */ + #[DataProvider('prepareRequestProvider')] public function testPrepareRequest($objectType, $expected, $data): void { $config = [ @@ -735,7 +742,7 @@ public function testPrepareRequest($objectType, $expected, $data): void * * @return array */ - public function changedAttributesProvider(): array + public static function changedAttributesProvider(): array { return [ 'missing _actualAttributes' => [ @@ -771,12 +778,11 @@ public function changedAttributesProvider(): array * @param array $data The data * @param array $expected The expected data * @return void - * @covers ::changedAttributes() - * @dataProvider changedAttributesProvider() */ + #[DataProvider('changedAttributesProvider')] public function testChangedAttributes(array $data, array $expected): void { - $controller = new class extends AppController { + $controller = new class (new ServerRequest()) extends AppController { /** * Wrapper for changedAttributes() method. * @@ -799,10 +805,10 @@ public function myChangedAttributes(array $data): array * * @return array */ - public function hasFieldChangedProvider(): array + public static function hasFieldChangedProvider(): array { - $d1 = new \DateTime('2019-01-01T15:03:01.012345Z'); - $d2 = new \DateTime('2019-01-01T16:03:01.012345Z'); + $d1 = new DateTime('2019-01-01T15:03:01.012345Z'); + $d2 = new DateTime('2019-01-01T16:03:01.012345Z'); return [ 'null and empty | unchanged' => [ null, '', 'null_and_empty', false ], @@ -832,11 +838,11 @@ public function hasFieldChangedProvider(): array * * @param mixed $val1 The first value * @param mixed $val2 The second value + * @param string $key The field key * @param bool $expected The expected result from function hasFieldChanged - * @covers ::hasFieldChanged() - * @dataProvider hasFieldChangedProvider() * @return void */ + #[DataProvider('hasFieldChangedProvider')] public function testHasFieldChanged($val1, $val2, $key, $expected): void { $this->setupController(); @@ -849,7 +855,7 @@ public function testHasFieldChanged($val1, $val2, $key, $expected): void * * @return array */ - public function checkRequestProvider(): array + public static function checkRequestProvider(): array { return [ 'methodNotAllowed' => [ @@ -888,15 +894,14 @@ public function checkRequestProvider(): array /** * Test `checkRequest` method * - * @covers ::checkRequest() - * @dataProvider checkRequestProvider() * @return void */ + #[DataProvider('checkRequestProvider')] public function testCheckRequest($expected, $params, $config): void { $this->setupController($config); - if ($expected instanceof \Exception) { + if ($expected instanceof Exception) { $this->expectException(get_class($expected)); } @@ -913,9 +918,9 @@ public function testCheckRequest($expected, $params, $config): void * @param array $parameters Array of parameters to pass into method. * @return mixed Method return. */ - public function invokeMethod(&$object, $methodName, array $parameters = []) + public function invokeMethod(&$object, string $methodName, array $parameters = []) { - $reflection = new \ReflectionClass(get_class($object)); + $reflection = new ReflectionClass(get_class($object)); $method = $reflection->getMethod($methodName); $method->setAccessible(true); @@ -929,9 +934,9 @@ public function invokeMethod(&$object, $methodName, array $parameters = []) * @param string $propertyName Property name to access * @return mixed Method return. */ - public function accessProperty(&$object, $propertyName) + public function accessProperty(&$object, string $propertyName) { - $reflection = new \ReflectionClass(get_class($object)); + $reflection = new ReflectionClass(get_class($object)); $property = $reflection->getProperty($propertyName); $property->setAccessible(true); @@ -943,7 +948,7 @@ public function accessProperty(&$object, $propertyName) * * @return array */ - public function applySessionFilterProvider(): array + public static function applySessionFilterProvider(): array { return [ 'reset' => [ // expected remove of session filter and redirect @@ -1015,8 +1020,6 @@ public function applySessionFilterProvider(): array /** * Test `applySessionFilter` method * - * @covers ::applySessionFilter() - * @dataProvider applySessionFilterProvider() * @param array $requestConfig * @param string $sessionKey * @param mixed|null $sessionValue @@ -1025,6 +1028,7 @@ public function applySessionFilterProvider(): array * @param string|null $expectedResultType * @return void */ + #[DataProvider('applySessionFilterProvider')] public function testApplySessionFilter($requestConfig, $sessionKey, $sessionValue, $expectedSessionValue, $expectedHttpStatusCode, $expectedResultType): void { // Setup controller for test @@ -1035,7 +1039,7 @@ public function testApplySessionFilter($requestConfig, $sessionKey, $sessionValu $session->write($sessionKey, $sessionValue); // do controller call - $reflectionClass = new \ReflectionClass($this->AppController); + $reflectionClass = new ReflectionClass($this->AppController); $method = $reflectionClass->getMethod('applySessionFilter'); $method->setAccessible(true); $result = $method->invokeArgs($this->AppController, []); @@ -1058,7 +1062,7 @@ public function testApplySessionFilter($requestConfig, $sessionKey, $sessionValu * * @return array */ - public function setObjectNavProvider(): array + public static function setObjectNavProvider(): array { return [ 'animals' => [ @@ -1139,10 +1143,9 @@ public function setObjectNavProvider(): array * @param array $objects The objects to filter to set object nav * @param array $expectedObjectNav The object nav array expected * @param string $expectedObjectNavModule The object type string type expected - * @covers ::setObjectNav() - * @dataProvider setObjectNavProvider() * @return void */ + #[DataProvider('setObjectNavProvider')] public function testSetObjectNav(string $moduleName, array $objects, array $expectedObjectNav, string $expectedObjectNavModule): void { // Setup controller for test @@ -1150,7 +1153,7 @@ public function testSetObjectNav(string $moduleName, array $objects, array $expe $this->AppController->Modules->setConfig('currentModuleName', $moduleName); // do controller call - $reflectionClass = new \ReflectionClass($this->AppController); + $reflectionClass = new ReflectionClass($this->AppController); $method = $reflectionClass->getMethod('setObjectNav'); $method->setAccessible(true); $method->invokeArgs($this->AppController, [ $objects ]); @@ -1166,7 +1169,7 @@ public function testSetObjectNav(string $moduleName, array $objects, array $expe * * @return array */ - public function getObjectNavProvider(): array + public static function getObjectNavProvider(): array { return [ 'empty' => [ @@ -1197,10 +1200,9 @@ public function getObjectNavProvider(): array * * @param string $moduleName The module name for the test * @param array $objects The objects to filter to set object nav - * @covers ::getObjectNav() - * @dataProvider getObjectNavProvider() * @return void */ + #[DataProvider('getObjectNavProvider')] public function testGetObjectNav(string $moduleName, array $objects): void { // Setup controller for test @@ -1208,7 +1210,7 @@ public function testGetObjectNav(string $moduleName, array $objects): void $this->AppController->Modules->setConfig('currentModuleName', $moduleName); // set objectNav data - $reflectionClass = new \ReflectionClass($this->AppController); + $reflectionClass = new ReflectionClass($this->AppController); $method = $reflectionClass->getMethod('setObjectNav'); $method->setAccessible(true); $method->invokeArgs($this->AppController, [ $objects ]); @@ -1235,7 +1237,6 @@ public function testGetObjectNav(string $moduleName, array $objects): void * Test `getObjectNav`, when empty * * @return void - * @covers ::getObjectNav() */ public function testGetObjectNavEmpty(): void { @@ -1243,7 +1244,7 @@ public function testGetObjectNavEmpty(): void $this->setupController(); // set objectNav data to empty array - $reflectionClass = new \ReflectionClass($this->AppController); + $reflectionClass = new ReflectionClass($this->AppController); $method = $reflectionClass->getMethod('setObjectNav'); $method->setAccessible(true); $method->invokeArgs($this->AppController, [ [] ]); @@ -1263,7 +1264,7 @@ public function testGetObjectNavEmpty(): void /** * Data provider for `testRelatedIds` test case. */ - public function relatedIdsProvider(): array + public static function relatedIdsProvider(): array { return [ 'empty items' => [ @@ -1311,13 +1312,12 @@ public function relatedIdsProvider(): array * @param mixed $items The items to test * @param array $expected The expected result * @return void - * @covers ::relatedIds() - * @dataProvider relatedIdsProvider() */ + #[DataProvider('relatedIdsProvider')] public function testRelatedIds($items, array $expected): void { $this->setupController(); - $reflectionClass = new \ReflectionClass($this->AppController); + $reflectionClass = new ReflectionClass($this->AppController); $method = $reflectionClass->getMethod('relatedIds'); $method->setAccessible(true); $actual = $method->invokeArgs($this->AppController, [$items]); diff --git a/tests/TestCase/Controller/BaseControllerTest.php b/tests/TestCase/Controller/BaseControllerTest.php index 8abbd9bb4..3620f12a4 100644 --- a/tests/TestCase/Controller/BaseControllerTest.php +++ b/tests/TestCase/Controller/BaseControllerTest.php @@ -1,6 +1,7 @@ [ 'REQUEST_METHOD' => 'GET', ], diff --git a/tests/TestCase/Controller/BulkControllerTest.php b/tests/TestCase/Controller/BulkControllerTest.php index 1205abf25..36ea577dc 100644 --- a/tests/TestCase/Controller/BulkControllerTest.php +++ b/tests/TestCase/Controller/BulkControllerTest.php @@ -8,17 +8,34 @@ use Authentication\Identity; use Authentication\IdentityInterface; use Cake\Cache\Cache; +use Cake\Controller\ComponentRegistry; use Cake\Http\ServerRequest; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use ReflectionClass; use ReflectionProperty; /** * {@see \App\Controller\BulkController} Test Case - * - * @coversDefaultClass \App\Controller\BulkController - * @uses \App\Controller\BulkController */ +#[CoversClass(BulkController::class)] +#[CoversMethod(BulkController::class, 'attribute')] +#[CoversMethod(BulkController::class, 'categories')] +#[CoversMethod(BulkController::class, 'copyToPosition')] +#[CoversMethod(BulkController::class, 'custom')] +#[CoversMethod(BulkController::class, 'getType')] +#[CoversMethod(BulkController::class, 'initialize')] +#[CoversMethod(BulkController::class, 'loadCategories')] +#[CoversMethod(BulkController::class, 'modulesListRedirect')] +#[CoversMethod(BulkController::class, 'moveToPosition')] +#[CoversMethod(BulkController::class, 'performCustomAction')] +#[CoversMethod(BulkController::class, 'position')] +#[CoversMethod(BulkController::class, 'remapCategories')] +#[CoversMethod(BulkController::class, 'saveAttribute')] +#[CoversMethod(BulkController::class, 'saveCategories')] +#[CoversMethod(BulkController::class, 'showResult')] class BulkControllerTest extends BaseControllerTest { /** @@ -26,7 +43,7 @@ class BulkControllerTest extends BaseControllerTest * * @var \App\Controller\BulkController */ - public $controller; + public BulkController $controller; /** * @inheritDoc @@ -107,7 +124,6 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac * Test `initialize` method * * @return void - * @covers ::initialize() */ public function testInitialize(): void { @@ -122,7 +138,6 @@ public function testInitialize(): void * Test `attribute` method * * @return void - * @covers ::attribute() */ public function testAttribute(): void { @@ -138,7 +153,7 @@ public function testAttribute(): void 'REQUEST_METHOD' => 'POST', ], 'post' => [ - 'ids' => $o['id'], + 'objects' => [['type' => $o['type'], 'id' => $o['id']]], 'attributes' => [ 'status' => $o['attributes']['status'], ], @@ -160,7 +175,6 @@ public function testAttribute(): void * Test `categories` method * * @return void - * @covers ::categories() */ public function testCategories(): void { @@ -198,14 +212,13 @@ public function testCategories(): void * Test `remapCategories` method * * @return void - * @covers ::remapCategories() */ public function testRemapCategories(): void { // Setup controller for test $this->setupController(); - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('remapCategories'); $method->setAccessible(true); $input = ['Category 1', 'Category 2']; @@ -221,7 +234,6 @@ public function testRemapCategories(): void * Test `position` method * * @return void - * @covers ::position() */ public function testPosition(): void { @@ -286,7 +298,6 @@ public function testPosition(): void * Test `saveAttribute` method * * @return void - * @covers ::saveAttribute() */ public function testSaveAttribute(): void { @@ -296,13 +307,13 @@ public function testSaveAttribute(): void // get object for test $o = $this->getTestObject(); // set $this->controller->objects - $property = new \ReflectionProperty(BulkController::class, 'objects'); + $property = new ReflectionProperty(BulkController::class, 'objects'); $property->setAccessible(true); $property->setValue($this->controller, [['id' => $o['id'], 'type' => $o['type']]]); $attributes = ['status' => 'draft']; // do controller call - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('saveAttribute'); $method->setAccessible(true); $method->invokeArgs($this->controller, [$attributes]); @@ -312,7 +323,7 @@ public function testSaveAttribute(): void // do controller call // set $this->controller->objects - $property = new \ReflectionProperty(BulkController::class, 'objects'); + $property = new ReflectionProperty(BulkController::class, 'objects'); $property->setAccessible(true); $property->setValue($this->controller, [['id' => 1, 'type' => 'users']]); $method->invokeArgs($this->controller, [$attributes]); @@ -325,41 +336,52 @@ public function testSaveAttribute(): void * Test `loadCategories` method * * @return void - * @covers ::loadCategories() */ public function testLoadCategories(): void { // Setup controller for test $this->setupController(); + $controller = new class ($this->controller->getRequest()) extends BulkController { + public SchemaComponent $Schema; + public function initialize(): void + { + $this->Schema = new SchemaComponent(new ComponentRegistry($this)); + parent::initialize(); + } + }; + // set $this->controller->categories - $property = new \ReflectionProperty(BulkController::class, 'categories'); + $property = new ReflectionProperty(BulkController::class, 'categories'); $property->setAccessible(true); - $property->setValue($this->controller, '123,456,789'); + $property->setValue($controller, '123,456,789'); // mock schema component - $mockResponse = [ - 'categories' => [ - ['id' => '123', 'name' => 'Cat 1'], - ['id' => '456', 'name' => 'Cat 2'], - ['id' => '789', 'name' => 'Cat 3'], - ['id' => '999', 'name' => 'Cat 4'], - ], - ]; - $this->controller->Schema = $this->createMock(SchemaComponent::class); - $this->controller->Schema->method('getSchema') - ->with('documents') - ->willReturn($mockResponse); + $controller->Schema = new class (new ComponentRegistry($controller)) extends SchemaComponent { + public function getSchema(?string $type = null, ?string $revision = null): array|bool + { + $mockResponse = [ + 'categories' => [ + ['id' => '123', 'name' => 'Cat 1'], + ['id' => '456', 'name' => 'Cat 2'], + ['id' => '789', 'name' => 'Cat 3'], + ['id' => '999', 'name' => 'Cat 4'], + ], + ]; + + return $type === 'documents' ? $mockResponse : []; + } + }; // do controller call - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($controller); $method = $reflectionClass->getMethod('loadCategories'); $method->setAccessible(true); - $method->invokeArgs($this->controller, []); - $property = new ReflectionProperty($this->controller, 'categories'); + $method->invokeArgs($controller, []); + $property = new ReflectionProperty($controller, 'categories'); $property->setAccessible(true); $expected = ['Cat 1', 'Cat 2', 'Cat 3']; - $actual = $property->getValue($this->controller); + $actual = $property->getValue($controller); static::assertEquals($expected, $actual); } @@ -367,7 +389,6 @@ public function testLoadCategories(): void * Test `saveCategories` method * * @return void - * @covers ::saveCategories() */ public function testSaveCategories(): void { @@ -376,12 +397,12 @@ public function testSaveCategories(): void // get object for test $o = $this->getTestObject(); - $property = new \ReflectionProperty(BulkController::class, 'ids'); + $property = new ReflectionProperty(BulkController::class, 'ids'); $property->setAccessible(true); $property->setValue($this->controller, [$o['id']]); // do controller call - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('saveCategories'); $method->setAccessible(true); $method->invokeArgs($this->controller, []); @@ -391,7 +412,7 @@ public function testSaveCategories(): void // do controller call // set $this->controller->ids - $property = new \ReflectionProperty(BulkController::class, 'ids'); + $property = new ReflectionProperty(BulkController::class, 'ids'); $property->setAccessible(true); $property->setValue($this->controller, ['123456789']); $method->invokeArgs($this->controller, []); @@ -404,7 +425,6 @@ public function testSaveCategories(): void * Test `copyToPosition` method * * @return void - * @covers ::copyToPosition() */ public function testCopyToPosition(): void { @@ -414,7 +434,7 @@ public function testCopyToPosition(): void // get object for test $o = $this->getTestObject(); // set $this->controller->ids - $property = new \ReflectionProperty(BulkController::class, 'ids'); + $property = new ReflectionProperty(BulkController::class, 'ids'); $property->setAccessible(true); $property->setValue($this->controller, [$o['id']]); @@ -422,7 +442,7 @@ public function testCopyToPosition(): void $f = $this->createTestFolder(); // do controller call - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('copyToPosition'); $method->setAccessible(true); $method->invokeArgs($this->controller, [$f['id']]); @@ -441,7 +461,6 @@ public function testCopyToPosition(): void * Test `moveToPosition` method * * @return void - * @covers ::moveToPosition() */ public function testMoveToPosition(): void { @@ -451,7 +470,7 @@ public function testMoveToPosition(): void // get object for test $o = $this->getTestObject(); // set $this->controller->ids - $property = new \ReflectionProperty(BulkController::class, 'ids'); + $property = new ReflectionProperty(BulkController::class, 'ids'); $property->setAccessible(true); $property->setValue($this->controller, [$o['id']]); @@ -459,7 +478,7 @@ public function testMoveToPosition(): void $f = $this->createTestFolder(); // do controller call - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('moveToPosition'); $method->setAccessible(true); $method->invokeArgs($this->controller, [$f['id']]); @@ -478,9 +497,6 @@ public function testMoveToPosition(): void * Test `custom` method with missing custom action * * @return void - * @covers ::custom() - * @covers ::performCustomAction - * @covers ::modulesListRedirect() */ public function testCustomMissing(): void { @@ -510,8 +526,6 @@ public function testCustomMissing(): void * Test `custom` method with custom action * * @return void - * @covers ::custom() - * @covers ::performCustomAction */ public function testCustomAction(): void { @@ -538,8 +552,6 @@ public function testCustomAction(): void * Test `custom` method with bad custom action class * * @return void - * @covers ::custom() - * @covers ::performCustomAction */ public function testCustomWrong(): void { @@ -563,7 +575,6 @@ public function testCustomWrong(): void * Test `errors` method * * @return void - * @covers ::showResult() */ public function testShowResult(): void { @@ -572,10 +583,10 @@ public function testShowResult(): void // empty // set $this->controller->errors - $property = new \ReflectionProperty(BulkController::class, 'errors'); + $property = new ReflectionProperty(BulkController::class, 'errors'); $property->setAccessible(true); $property->setValue($this->controller, []); - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('showResult'); $method->setAccessible(true); $method->invokeArgs($this->controller, []); @@ -586,7 +597,7 @@ public function testShowResult(): void // not empty // set $this->controller->errors - $property = new \ReflectionProperty(BulkController::class, 'errors'); + $property = new ReflectionProperty(BulkController::class, 'errors'); $property->setAccessible(true); $property->setValue($this->controller, ['something bad happened']); $method->invokeArgs($this->controller, []); @@ -600,7 +611,6 @@ public function testShowResult(): void * Test `getType` method * * @return void - * @covers ::getType() */ public function testGetType(): void { @@ -613,7 +623,7 @@ public function testGetType(): void 'object_type' => 'media', ], ]); - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('getType'); $method->setAccessible(true); $media = $this->getTestMedia(); @@ -631,7 +641,7 @@ public function testGetType(): void 'object_type' => 'files', ], ]); - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('getType'); $method->setAccessible(true); $media = $this->getTestMedia(); diff --git a/tests/TestCase/Controller/CategoriesControllerTest.php b/tests/TestCase/Controller/CategoriesControllerTest.php index adba2a907..9f262a1a8 100644 --- a/tests/TestCase/Controller/CategoriesControllerTest.php +++ b/tests/TestCase/Controller/CategoriesControllerTest.php @@ -4,31 +4,27 @@ use App\Controller\CategoriesController; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\CategoriesController} Test Case - * - * @coversDefaultClass \App\Controller\CategoriesController - * @uses \App\Controller\CategoriesController */ +#[CoversClass(CategoriesController::class)] +#[CoversMethod(CategoriesController::class, 'delete')] +#[CoversMethod(CategoriesController::class, 'index')] +#[CoversMethod(CategoriesController::class, 'initialize')] +#[CoversMethod(CategoriesController::class, 'save')] class CategoriesControllerTest extends TestCase { - /** - * Test subject - * - * @var \App\Controller\CategoriesController - */ - protected $CategoriesController; - /** * Test `initialize` * * @return void - * @covers ::initialize() */ public function testInitialize(): void { - $this->CategoriesController = new CategoriesController(new ServerRequest([ + $request = new ServerRequest([ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -36,20 +32,26 @@ public function testInitialize(): void 'params' => [ 'object_type' => 'documents', ], - ])); - static::assertNotEmpty($this->CategoriesController->{'Categories'}); - static::assertNotEmpty($this->CategoriesController->{'Properties'}); + ]); + $controller = new class ($request) extends CategoriesController { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Categories'); + } + }; + static::assertNotEmpty($controller->{'Categories'}); + static::assertNotEmpty($controller->{'Properties'}); } /** * Test `index` * * @return void - * @covers ::index() */ public function testIndex(): void { - $this->CategoriesController = new CategoriesController(new ServerRequest([ + $request = new ServerRequest([ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -57,30 +59,38 @@ public function testIndex(): void 'params' => [ 'object_type' => 'documents', ], - ])); - $this->CategoriesController->viewBuilder()->setVar('project', ['version' => '5.26.0']); - $result = $this->CategoriesController->index(); + ]); + $controller = new class ($request) extends CategoriesController { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Categories'); + } + }; + $controller->viewBuilder()->setVar('project', ['version' => '5.26.0']); + $result = $controller->index(); // verify response status code and type static::assertNull($result); - static::assertEquals(200, $this->CategoriesController->getResponse()->getStatusCode()); - static::assertEquals('text/html', $this->CategoriesController->getResponse()->getType()); + static::assertEquals(200, $controller->getResponse()->getStatusCode()); + static::assertEquals('text/html', $controller->getResponse()->getType()); // verify expected vars in view $expected = ['resources', 'roots', 'categoriesTree', 'names', 'meta', 'links', 'schema', 'properties', 'filter', 'object_types', 'objectType']; - $this->assertExpectedViewVars($expected); + foreach ($expected as $varName) { + static::assertArrayHasKey($varName, $controller->viewBuilder()->getVars()); + } } /** * Test `save` * * @return void - * @covers ::save() */ public function testSave(): void { // Setup controller for test - $this->CategoriesController = new CategoriesController(new ServerRequest([ + $request = new ServerRequest([ 'environment' => [ 'REQUEST_METHOD' => 'POST', ], @@ -88,26 +98,32 @@ public function testSave(): void 'params' => [ 'object_type' => 'documents', ], - ])); + ]); + $controller = new class ($request) extends CategoriesController { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Categories'); + } + }; - $result = $this->CategoriesController->save(); + $result = $controller->save(); // verify response status code and type static::assertNull($result); - static::assertEquals(200, $this->CategoriesController->getResponse()->getStatusCode()); - static::assertEquals('text/html', $this->CategoriesController->getResponse()->getType()); + static::assertEquals(200, $controller->getResponse()->getStatusCode()); + static::assertEquals('text/html', $controller->getResponse()->getType()); } /** * Test `delete` * * @return void - * @covers ::delete() */ public function testDelete(): void { // Setup controller for test - $this->CategoriesController = new CategoriesController(new ServerRequest([ + $request = new ServerRequest([ 'environment' => [ 'REQUEST_METHOD' => 'POST', ], @@ -115,26 +131,20 @@ public function testDelete(): void 'params' => [ 'object_type' => 'documents', ], - ])); + ]); + $controller = new class ($request) extends CategoriesController { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Categories'); + } + }; - $result = $this->CategoriesController->delete('999'); + $result = $controller->delete('999'); // verify response status code and type static::assertNull($result); - static::assertEquals(200, $this->CategoriesController->getResponse()->getStatusCode()); - static::assertEquals('text/html', $this->CategoriesController->getResponse()->getType()); - } - - /** - * Verify existence of vars in controller view - * - * @param array $expected The expected vars in view - * @return void - */ - private function assertExpectedViewVars($expected): void - { - foreach ($expected as $varName) { - static::assertArrayHasKey($varName, $this->CategoriesController->viewBuilder()->getVars()); - } + static::assertEquals(200, $controller->getResponse()->getStatusCode()); + static::assertEquals('text/html', $controller->getResponse()->getType()); } } diff --git a/tests/TestCase/Controller/Component/CategoriesComponentTest.php b/tests/TestCase/Controller/Component/CategoriesComponentTest.php index 323850ca8..f5e25ed2a 100644 --- a/tests/TestCase/Controller/Component/CategoriesComponentTest.php +++ b/tests/TestCase/Controller/Component/CategoriesComponentTest.php @@ -20,15 +20,28 @@ use BEdita\WebTools\ApiClientProvider; use Cake\Cache\Cache; use Cake\Controller\ComponentRegistry; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Component\CategoriesComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\CategoriesComponent - * @uses \App\Controller\Component\CategoriesComponent */ +#[CoversClass(CategoriesComponent::class)] +#[CoversMethod(CategoriesComponent::class, 'delete')] +#[CoversMethod(CategoriesComponent::class, 'fillRoots')] +#[CoversMethod(CategoriesComponent::class, 'getAllAvailableRoots')] +#[CoversMethod(CategoriesComponent::class, 'getAvailableRoots')] +#[CoversMethod(CategoriesComponent::class, 'hasChanged')] +#[CoversMethod(CategoriesComponent::class, 'index')] +#[CoversMethod(CategoriesComponent::class, 'invalidateSchemaCache')] +#[CoversMethod(CategoriesComponent::class, 'map')] +#[CoversMethod(CategoriesComponent::class, 'names')] +#[CoversMethod(CategoriesComponent::class, 'save')] +#[CoversMethod(CategoriesComponent::class, 'tree')] class CategoriesComponentTest extends TestCase { /** @@ -36,7 +49,7 @@ class CategoriesComponentTest extends TestCase * * @var \App\Controller\Component\CategoriesComponent */ - public $Categories; + public CategoriesComponent $Categories; /** * @inheritDoc @@ -44,7 +57,7 @@ class CategoriesComponentTest extends TestCase public function setUp(): void { parent::setUp(); - $controller = new CategoriesController(); + $controller = new CategoriesController(new ServerRequest()); $registry = new ComponentRegistry($controller); $this->Categories = new CategoriesComponent($registry); } @@ -63,7 +76,6 @@ public function tearDown(): void * Test `index` * * @return void - * @covers ::index() */ public function testIndex(): void { @@ -75,11 +87,11 @@ public function testIndex(): void ->getMock(); $apiClient->method('get') ->with('/model/categories') - ->will($this->returnCallback(function () { + ->willReturnCallback(function () { $args = func_get_args(); return $args[1]; // options - })); + }); ApiClientProvider::setApiClient($apiClient); // test, default options, no type @@ -101,7 +113,6 @@ public function testIndex(): void * Test `names` * * @return void - * @covers ::names() */ public function testNames(): void { @@ -113,7 +124,6 @@ public function testNames(): void * Test `map` * * @return void - * @covers ::map() */ public function testMap(): void { @@ -142,7 +152,6 @@ public function testMap(): void * Test `tree`. * * @return void - * @covers ::tree() */ public function testTree(): void { @@ -171,8 +180,6 @@ public function testTree(): void * Test `getAvailableRoots`. * * @return void - * @covers ::getAvailableRoots() - * @covers ::fillRoots() */ public function testGetAvailableRoots(): void { @@ -201,8 +208,6 @@ public function testGetAvailableRoots(): void * Test `getAllAvailableRoots`. * * @return void - * @covers ::getAllAvailableRoots() - * @covers ::fillRoots() */ public function testGetAllAvailableRoots(): void { @@ -235,8 +240,6 @@ public function testGetAllAvailableRoots(): void * Test `save`. * * @return void - * @covers ::save() - * @covers ::invalidateSchemaCache() */ public function testSave(): void { @@ -289,7 +292,6 @@ public function testSave(): void * Test `delete`. * * @return void - * @covers ::delete() */ public function testDelete(): void { @@ -326,7 +328,7 @@ public function testDelete(): void * * @return array */ - public function hasChangedProvider(): array + public static function hasChangedProvider(): array { return [ 'empty' => [ @@ -351,9 +353,8 @@ public function hasChangedProvider(): array * Test `hasChanged`. * * @return void - * @dataProvider hasChangedProvider() - * @covers ::hasChanged() */ + #[DataProvider('hasChangedProvider')] public function testHasChanged(array $oldValue, array $newValue, bool $expected): void { $actual = $this->Categories->hasChanged($oldValue, $newValue); diff --git a/tests/TestCase/Controller/Component/ChildrenComponentTest.php b/tests/TestCase/Controller/Component/ChildrenComponentTest.php index 7f9979212..a2aa0d1d1 100644 --- a/tests/TestCase/Controller/Component/ChildrenComponentTest.php +++ b/tests/TestCase/Controller/Component/ChildrenComponentTest.php @@ -8,12 +8,16 @@ use BEdita\WebTools\ApiClientProvider; use Cake\Controller\ComponentRegistry; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Component\ChildrenComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\ChildrenComponent */ +#[CoversClass(ChildrenComponent::class)] +#[CoversMethod(ChildrenComponent::class, 'addRelated')] +#[CoversMethod(ChildrenComponent::class, 'removeRelated')] +#[CoversMethod(ChildrenComponent::class, 'removeRelatedChild')] class ChildrenComponentTest extends TestCase { /** @@ -34,7 +38,6 @@ protected function tearDown(): void * Test addRelated method with valid data. * * @return void - * @covers ::addRelated() */ public function testAddRelated(): void { @@ -62,7 +65,6 @@ public function testAddRelated(): void * Test addRelated method with valid data and reorder. * * @return void - * @covers ::addRelated() */ public function testAddRelatedReorder(): void { @@ -97,8 +99,6 @@ public function testAddRelatedReorder(): void * Test removeRelated method with valid data. * * @return void - * @covers ::removeRelated() - * @covers ::removeRelatedChild() */ public function testRemoveRelated(): void { diff --git a/tests/TestCase/Controller/Component/ExportComponentTest.php b/tests/TestCase/Controller/Component/ExportComponentTest.php index c313fc588..09752076f 100644 --- a/tests/TestCase/Controller/Component/ExportComponentTest.php +++ b/tests/TestCase/Controller/Component/ExportComponentTest.php @@ -5,12 +5,21 @@ use App\Test\TestCase\Controller\AppControllerTest; use Cake\Controller\ComponentRegistry; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Component\ExportComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\ExportComponent */ +#[CoversClass(ExportComponent::class)] +#[CoversMethod(ExportComponent::class, 'checkFormat')] +#[CoversMethod(ExportComponent::class, 'column')] +#[CoversMethod(ExportComponent::class, 'csv')] +#[CoversMethod(ExportComponent::class, 'download')] +#[CoversMethod(ExportComponent::class, 'format')] +#[CoversMethod(ExportComponent::class, 'ods')] +#[CoversMethod(ExportComponent::class, 'xlsx')] class ExportComponentTest extends TestCase { /** @@ -18,7 +27,7 @@ class ExportComponentTest extends TestCase * * @var \App\Controller\Component\ExportComponent */ - public $Export; + public ExportComponent $Export; /** * @inheritDoc @@ -45,7 +54,7 @@ public function tearDown(): void * * @return array */ - public function checkFormatProvider(): array + public static function checkFormatProvider(): array { return [ 'false' => [ @@ -63,9 +72,8 @@ public function checkFormatProvider(): array * Test `checkFormat` method * * @return void - * @covers ::checkFormat() - * @dataProvider checkFormatProvider() */ + #[DataProvider('checkFormatProvider')] public function testCheckFormat(string $format, bool $expected): void { $actual = $this->Export->checkFormat($format); @@ -77,7 +85,7 @@ public function testCheckFormat(string $format, bool $expected): void * * @return array */ - public function formatProvider(): array + public static function formatProvider(): array { return [ '1 A' => [ @@ -97,10 +105,8 @@ public function formatProvider(): array * Test `format` method * * @return void - * @covers ::format() - * @covers ::csv() - * @dataProvider formatProvider() */ + #[DataProvider('formatProvider')] public function testFormat(string $format, array $rows, string $filename, array $properties, array $expected): void { $actual = $this->Export->format($format, $rows, $filename, $properties); @@ -112,7 +118,7 @@ public function testFormat(string $format, array $rows, string $filename, array * * @return array */ - public function columnProvider(): array + public static function columnProvider(): array { return [ '1 A' => [ @@ -144,13 +150,12 @@ public function columnProvider(): array * @param int $number The column number * @param string $expected The column string * @return void - * @covers ::column() - * @dataProvider columnProvider() */ + #[DataProvider('columnProvider')] public function testColumn(int $number, string $expected): void { // call protected method using AppControllerTest->invokeMethod - $test = new AppControllerTest(); + $test = new AppControllerTest('test'); $actual = $test->invokeMethod($this->Export, 'column', [$number]); static::assertEquals($expected, $actual); } @@ -160,7 +165,7 @@ public function testColumn(int $number, string $expected): void * * @return array */ - public function formatsProvider(): array + public static function formatsProvider(): array { return [ 'csv' => [ @@ -184,17 +189,12 @@ public function formatsProvider(): array * @param string $format The content type format * @param string $contentType The content type * @return void - * @covers ::csv() - * @covers ::ods() - * @covers ::xlsx() - * @covers ::download() - * @dataProvider formatsProvider() */ + #[DataProvider('formatsProvider')] public function testFormats(string $format, string $contentType): void { $filename = sprintf('test.%s', $format); $actual = $this->Export->format($format, [], $filename, []); - $options = compact('filename', 'format'); static::assertEquals($contentType, $actual['contentType']); } } diff --git a/tests/TestCase/Controller/Component/FlashComponentTest.php b/tests/TestCase/Controller/Component/FlashComponentTest.php index 7bef69626..dfb40515e 100644 --- a/tests/TestCase/Controller/Component/FlashComponentTest.php +++ b/tests/TestCase/Controller/Component/FlashComponentTest.php @@ -15,13 +15,16 @@ use App\Controller\AppController; use App\Controller\Component\FlashComponent; use BEdita\SDK\BEditaClientException; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Component\FlashComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\FlashComponent */ +#[CoversClass(FlashComponent::class)] +#[CoversMethod(FlashComponent::class, 'set')] class FlashComponentTest extends TestCase { /** @@ -29,21 +32,21 @@ class FlashComponentTest extends TestCase * * @var \App\Controller\Component\FlashComponent */ - public $Flash; + public FlashComponent $Flash; /** * Test controller * * @var \App\Controller\AppController */ - public $controller; + public AppController $controller; /** * @inheritDoc */ public function setUp(): void { - $this->controller = new AppController(); + $this->controller = new AppController(new ServerRequest()); $registry = $this->controller->components(); /** @var \App\Controller\Component\FlashComponent $component */ $component = $registry->load(FlashComponent::class); @@ -66,7 +69,6 @@ public function tearDown(): void * Test `set()` method. * * @return void - * @covers ::set() */ public function testSet(): void { diff --git a/tests/TestCase/Controller/Component/HistoryComponentTest.php b/tests/TestCase/Controller/Component/HistoryComponentTest.php index 32a738f52..c33480b1e 100644 --- a/tests/TestCase/Controller/Component/HistoryComponentTest.php +++ b/tests/TestCase/Controller/Component/HistoryComponentTest.php @@ -10,12 +10,20 @@ use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Component\HistoryComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\HistoryComponent */ +#[CoversClass(HistoryComponent::class)] +#[CoversMethod(HistoryComponent::class, 'content')] +#[CoversMethod(HistoryComponent::class, 'fetch')] +#[CoversMethod(HistoryComponent::class, 'formatResponseData')] +#[CoversMethod(HistoryComponent::class, 'label')] +#[CoversMethod(HistoryComponent::class, 'load')] +#[CoversMethod(HistoryComponent::class, 'write')] class HistoryComponentTest extends TestCase { /** @@ -23,35 +31,35 @@ class HistoryComponentTest extends TestCase * * @var \App\Controller\Component\HistoryComponent */ - public $HistoryComponent; + public HistoryComponent $HistoryComponent; /** * Http Request * - * @var \Cake\Http\ServerRequest + * @var \Cake\Http\ServerRequest|null */ - private $Request = null; + private ?ServerRequest $Request = null; /** * Schema component * * @var \App\Controller\Component\SchemaComponent */ - public $SchemaComponent; + public SchemaComponent $SchemaComponent; /** * Client class * - * @var \BEdita\SDK\BEditaClient + * @var \BEdita\SDK\BEditaClient|null */ - private $ApiClient = null; + private ?BEditaClient $ApiClient = null; /** * Document ID * - * @var string + * @var string|null */ - private $documentId = null; + private ?string $documentId = null; /** * @inheritDoc @@ -60,7 +68,7 @@ public function setUp(): void { parent::setUp(); - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); /** @var \App\Controller\Component\HistoryComponent $historyComponent */ $historyComponent = $registry->load(HistoryComponent::class); @@ -101,7 +109,7 @@ public function tearDown(): void * * @return array */ - public function loadProvider(): array + public static function loadProvider(): array { return [ 'empty object' => [ @@ -128,12 +136,11 @@ public function loadProvider(): array /** * Test `load` method * - * @covers ::load() - * @dataProvider loadProvider() * @param array $object The object for test * @param string $expected The expected object * @return void */ + #[DataProvider('loadProvider')] public function testLoad(array $object, string $expected): void { $session = $this->HistoryComponent->getController()->getRequest()->getSession(); @@ -155,13 +162,12 @@ public function testLoad(array $object, string $expected): void * * @return array */ - public function writeProvider(): array + public static function writeProvider(): array { return [ 'test document, keepUname false' => [ [ 'objectType' => 'documents', - 'id' => $this->documentId, 'historyId' => 1, 'keepUname' => false, ], @@ -170,7 +176,6 @@ public function writeProvider(): array 'test document, keepUname true' => [ [ 'objectType' => 'documents', - 'id' => $this->documentId, 'historyId' => 1, 'keepUname' => true, ], @@ -185,9 +190,8 @@ public function writeProvider(): array * @param array $options The options for test * @param string $expected The expected serialized data * @return void - * @covers ::write() - * @dataProvider writeProvider() */ + #[DataProvider('writeProvider')] public function testWrite(array $options, string $expected): void { // mock api /history @@ -210,6 +214,7 @@ public function testWrite(array $options, string $expected): void ->willReturn($response); // set options $options += [ + 'id' => $this->documentId, 'ApiClient' => $apiClient, 'Schema' => $this->SchemaComponent, 'Request' => $this->Request->withQueryParams(['title' => 'a new title']), @@ -225,7 +230,7 @@ public function testWrite(array $options, string $expected): void * * @return array */ - public function fetchProvider(): array + public static function fetchProvider(): array { return [ 'a document history' => [ @@ -251,12 +256,11 @@ public function fetchProvider(): array /** * Test `fetch` method * - * @covers ::fetch() - * @dataProvider fetchProvider() * @param array $data The data for test * @param mixed $expected The expected value * @return void */ + #[DataProvider('fetchProvider')] public function testFetch(array $data, $expected): void { $response = $this->HistoryComponent->fetch($this->documentId, $data, ['page_size' => 100, 'page' => 1]); @@ -269,7 +273,7 @@ public function testFetch(array $data, $expected): void * * @return array */ - public function formatResponseDataProvider(): array + public static function formatResponseDataProvider(): array { return [ 'empty response data' => [ @@ -327,16 +331,15 @@ public function formatResponseDataProvider(): array /** * Test `formatResponseData` method * - * @covers ::formatResponseData() - * @dataProvider formatResponseDataProvider() * @param array $data The data for test * @param mixed $expected The expected value * @return void */ + #[DataProvider('formatResponseDataProvider')] public function testFormatResponseData(array $data, $expected): void { // call private method using AppControllerTest->invokeMethod - $test = new AppControllerTest(); + $test = new AppControllerTest('test'); $test->invokeMethod($this->HistoryComponent, 'formatResponseData', [&$data[0], $data[1]]); $actual = $data[0]; static::assertEquals($expected, $actual); @@ -347,7 +350,7 @@ public function testFormatResponseData(array $data, $expected): void * * @return array */ - public function contentDataProvider(): array + public static function contentDataProvider(): array { return [ 'empty content' => [ @@ -408,9 +411,8 @@ public function contentDataProvider(): array * @param mixed $value The value * @param string $expected The expected content * @return void - * @covers ::content() - * @dataProvider contentDataProvider() */ + #[DataProvider('contentDataProvider')] public function testContent(string $field, array $schema, $value, string $expected): void { $actual = $this->HistoryComponent->content($field, $schema, $value); @@ -422,7 +424,7 @@ public function testContent(string $field, array $schema, $value, string $expect * * @return array */ - public function labelDataProvider(): array + public static function labelDataProvider(): array { return [ 'empty label' => [ @@ -446,9 +448,8 @@ public function labelDataProvider(): array * @param string $field The field * @param string $expected The expected label * @return void - * @covers ::label() - * @dataProvider labelDataProvider() */ + #[DataProvider('labelDataProvider')] public function testLabel(string $field, string $expected): void { $actual = $this->HistoryComponent->label($field); diff --git a/tests/TestCase/Controller/Component/ModulesComponentTest.php b/tests/TestCase/Controller/Component/ModulesComponentTest.php index b1bb778bd..45ccdae32 100644 --- a/tests/TestCase/Controller/Component/ModulesComponentTest.php +++ b/tests/TestCase/Controller/Component/ModulesComponentTest.php @@ -31,18 +31,49 @@ use Cake\Event\Event; use Cake\Http\Exception\BadRequestException; use Cake\Http\Exception\InternalErrorException; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use Exception; use Laminas\Diactoros\Stream; use Laminas\Diactoros\UploadedFile; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use ReflectionClass; +use ReflectionProperty; +use RuntimeException; /** * {@see \App\Controller\Component\ModulesComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\ModulesComponent */ +#[CoversClass(ModulesComponent::class)] +#[CoversMethod(ModulesComponent::class, 'assocStreamToMedia')] +#[CoversMethod(ModulesComponent::class, 'beforeFilter')] +#[CoversMethod(ModulesComponent::class, 'checkRequestForUpload')] +#[CoversMethod(ModulesComponent::class, 'getModules')] +#[CoversMethod(ModulesComponent::class, 'getProject')] +#[CoversMethod(ModulesComponent::class, 'getRelated')] +#[CoversMethod(ModulesComponent::class, 'isAbstract')] +#[CoversMethod(ModulesComponent::class, 'modulesByAccessControl')] +#[CoversMethod(ModulesComponent::class, 'modulesFromMeta')] +#[CoversMethod(ModulesComponent::class, 'objectTypes')] +#[CoversMethod(ModulesComponent::class, 'relatedTypes')] +#[CoversMethod(ModulesComponent::class, 'relationLabels')] +#[CoversMethod(ModulesComponent::class, 'relationsSchema')] +#[CoversMethod(ModulesComponent::class, 'removeStream')] +#[CoversMethod(ModulesComponent::class, 'saveRelated')] +#[CoversMethod(ModulesComponent::class, 'saveRelatedObjects')] +#[CoversMethod(ModulesComponent::class, 'setupAttributes')] +#[CoversMethod(ModulesComponent::class, 'setupRelationsMeta')] +#[CoversMethod(ModulesComponent::class, 'skipSaveObject')] +#[CoversMethod(ModulesComponent::class, 'skipSavePermissions')] +#[CoversMethod(ModulesComponent::class, 'skipSaveRelated')] +#[CoversMethod(ModulesComponent::class, 'startup')] +#[CoversMethod(ModulesComponent::class, 'translationsEnabled')] +#[CoversMethod(ModulesComponent::class, 'upload')] class ModulesComponentTest extends TestCase { /** @@ -50,23 +81,23 @@ class ModulesComponentTest extends TestCase * * @var \App\Controller\Component\ModulesComponent */ - public $Modules; + public ModulesComponent $Modules; /** * Authentication component * * @var \Authentication\Controller\Component\AuthenticationComponent; */ - public $Authentication; + public AuthenticationComponent $Authentication; - public $MyModules; + public ModulesComponent $MyModules; /** * Test api client * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * @inheritDoc @@ -75,7 +106,7 @@ public function setUp(): void { parent::setUp(); - $controller = new AppController(); + $controller = new AppController(new ServerRequest()); $registry = $controller->components(); $registry->load('Authentication.Authentication'); /** @var \App\Controller\Component\ModulesComponent $modulesComponent */ @@ -86,7 +117,7 @@ public function setUp(): void $this->Authentication = $authenticationComponent; $this->MyModules = new class ($registry) extends ModulesComponent { - public $meta = []; + public array $meta = []; protected function oEmbedMeta(string $url): ?array { @@ -144,7 +175,7 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac * * @return array */ - public function getProjectProvider(): array + public static function getProjectProvider(): array { return [ 'ok' => [ @@ -189,8 +220,8 @@ public function getProjectProvider(): array new BEditaClientException('I am a client exception'), ], 'other exception' => [ - new \RuntimeException('I am some other kind of exception', 999), - new \RuntimeException('I am some other kind of exception', 999), + new RuntimeException('I am some other kind of exception', 999), + new RuntimeException('I am some other kind of exception', 999), ], 'config' => [ [ @@ -219,16 +250,15 @@ public function getProjectProvider(): array * @param array|\Exception $meta Response to `/home` endpoint. * @param array $config Project config to set. * @return void - * @dataProvider getProjectProvider() - * @covers ::getProject() */ + #[DataProvider('getProjectProvider')] public function testGetProject($expected, $meta, $config = []): void { // Mock Authentication component $this->Modules->getController()->setRequest($this->Modules->getController()->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); $this->Modules->Authentication->setIdentity(new Identity([])); - if ($expected instanceof \Exception) { + if ($expected instanceof Exception) { $this->expectException(get_class($expected)); $this->expectExceptionCode($expected->getCode()); $this->expectExceptionMessage($expected->getMessage()); @@ -238,7 +268,7 @@ public function testGetProject($expected, $meta, $config = []): void $apiClient = $this->getMockBuilder(BEditaClient::class) ->setConstructorArgs(['https://api.example.org']) ->getMock(); - if ($meta instanceof \Exception) { + if ($meta instanceof Exception) { $apiClient->method('get') ->with('/home') ->willThrowException($meta); @@ -260,7 +290,7 @@ public function testGetProject($expected, $meta, $config = []): void * * @return array */ - public function isAbstractProvider(): array + public static function isAbstractProvider(): array { return [ 'isAbstractTrue' => [ @@ -279,10 +309,9 @@ public function isAbstractProvider(): array * * @param bool $expected expected results from test * @param string $data setup data for test, object type - * @dataProvider isAbstractProvider() - * @covers ::isAbstract() * @return void */ + #[DataProvider('isAbstractProvider')] public function testIsAbstract($expected, $data): void { /** @var \App\Controller\ModulesController $controller */ @@ -309,7 +338,7 @@ public function testIsAbstract($expected, $data): void * * @return array */ - public function objectTypesProvider(): array + public static function objectTypesProvider(): array { return [ 'empty' => [ @@ -349,10 +378,9 @@ public function objectTypesProvider(): array * * @param array $expected expected results from test * @param bool|null $data setup data for test - * @dataProvider objectTypesProvider() - * @covers ::objectTypes() * @return void */ + #[DataProvider('objectTypesProvider')] public function testObjectTypes($expected, $data): void { /** @var \App\Controller\ModulesController $controller */ @@ -384,7 +412,7 @@ public function testObjectTypes($expected, $data): void * * @return array */ - public function getModulesProvider(): array + public static function getModulesProvider(): array { return [ 'ok' => [ @@ -503,8 +531,8 @@ public function getModulesProvider(): array new BEditaClientException('I am a client exception'), ], 'other exception' => [ - new \RuntimeException('I am some other kind of exception', 999), - new \RuntimeException('I am some other kind of exception', 999), + new RuntimeException('I am some other kind of exception', 999), + new RuntimeException('I am some other kind of exception', 999), ], ]; } @@ -516,10 +544,8 @@ public function getModulesProvider(): array * @param array|\Exception $meta Response to `/home` endpoint. * @param array $modules Modules configuration. * @return void - * @dataProvider getModulesProvider() - * @covers ::modulesFromMeta() - * @covers ::getModules() */ + #[DataProvider('getModulesProvider')] public function testGetModules($expected, $meta, array $modules = []): void { // Setup mock API client. @@ -538,7 +564,7 @@ public function testGetModules($expected, $meta, array $modules = []): void Configure::write('Modules', $modules); - if ($expected instanceof \Exception) { + if ($expected instanceof Exception) { $this->expectException(get_class($expected)); $this->expectExceptionCode($expected->getCode()); $this->expectExceptionMessage($expected->getMessage()); @@ -548,12 +574,12 @@ public function testGetModules($expected, $meta, array $modules = []): void $apiClient = $this->getMockBuilder(BEditaClient::class) ->setConstructorArgs(['https://api.example.org']) ->getMock(); - if ($meta instanceof \Exception) { + if ($meta instanceof Exception) { $apiClient->method('get') ->willThrowException($meta); } else { $apiClient->method('get') - ->will($this->returnCallback( + ->willReturnCallback( function ($param) use ($meta, $modules) { $args = func_get_args(); if ($args[0] === '/model/object_types') { @@ -561,8 +587,20 @@ function ($param) use ($meta, $modules) { } return compact('meta'); - } - )); + }, + ); + $apiClient->method('schema') + ->willReturnCallback( + function ($type) { + if ($type === 'bedita') { + return [ + 'translatable' => ['title', 'body'], + ]; + } + + return []; + }, + ); } ApiClientProvider::setApiClient($apiClient); @@ -576,7 +614,7 @@ function ($param) use ($meta, $modules) { * * @return array */ - public function modulesByAccessControlProvider(): array + public static function modulesByAccessControlProvider(): array { return [ 'empty access control' => [ @@ -658,29 +696,28 @@ public function modulesByAccessControlProvider(): array * @param array $user The user * @param array $expected The expected modules * @return void - * @dataProvider modulesByAccessControlProvider() - * @cover ::modulesByAccessControl() */ + #[DataProvider('modulesByAccessControlProvider')] public function testModulesByAccessControl(array $modules, array $accessControl, array $user, array $expected): void { // Mock Authentication component $this->Modules->getController()->setRequest($this->Modules->getController()->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); // set $this->Modules->modules - $property = new \ReflectionProperty(ModulesComponent::class, 'modules'); + $property = new ReflectionProperty(ModulesComponent::class, 'modules'); $property->setAccessible(true); $property->setValue($this->Modules, $modules); // set AccessControl Configure::write('AccessControl', $accessControl); // call modulesByAccessControl - $reflectionClass = new \ReflectionClass($this->Modules); + $reflectionClass = new ReflectionClass($this->Modules); $method = $reflectionClass->getMethod('modulesByAccessControl'); $method->setAccessible(true); $this->Modules->Authentication->setIdentity(new Identity($user)); $method->invokeArgs($this->Modules, []); // get $this->Modules->modules - $property = new \ReflectionProperty(ModulesComponent::class, 'modules'); + $property = new ReflectionProperty(ModulesComponent::class, 'modules'); $property->setAccessible(true); $actual = $property->getValue($this->Modules); static::assertEquals($expected, $actual); @@ -691,7 +728,7 @@ public function testModulesByAccessControl(array $modules, array $accessControl, * * @return array */ - public function startupProvider(): array + public static function startupProvider(): array { return [ 'without current module' => [ @@ -798,10 +835,8 @@ public function startupProvider(): array * @param string[] $config Modules configuration. * @param string|null $currentModuleName Current module. * @return void - * @dataProvider startupProvider() - * @covers ::startup() - * @covers ::beforeFilter() */ + #[DataProvider('startupProvider')] public function testBeforeRender($userId, $modules, ?string $currentModule, array $project, array $meta, array $config = [], ?string $currentModuleName = null): void { /** @var \App\Controller\ModulesController $controller */ @@ -855,7 +890,7 @@ public function testBeforeRender($userId, $modules, ?string $currentModule, arra * * @return array */ - public function uploadProvider(): array + public static function uploadProvider(): array { $filename = sprintf('%s/tests/files/%s', getcwd(), 'test.png'); $file = new UploadedFile($filename, filesize($filename), 0, $filename, 'image/png'); @@ -945,12 +980,8 @@ public function uploadProvider(): array * @param array|bool $uploaded The upload result (boolean or expected requestdata) * @param string|null $contentType The content type of the uploaded file * @return void - * @covers ::upload() - * @covers ::assocStreamToMedia() - * @covers ::removeStream() - * @covers ::checkRequestForUpload() - * @dataProvider uploadProvider() */ + #[DataProvider('uploadProvider')] public function testUpload(array $requestData, $expectedException, $uploaded, ?string $contentType): void { // if upload failed, verify exception @@ -971,11 +1002,11 @@ public function testUpload(array $requestData, $expectedException, $uploaded, ?s $this->Modules->upload($requestData); } else { // mock for ModulesComponent - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); $myModules = new class ($registry) extends ModulesComponent { - public $meta = []; + public array $meta = []; protected function oEmbedMeta(string $url): ?array { @@ -1020,8 +1051,6 @@ public function objectTypes(?bool $abstract = null): array * Test `upload` method for InternalErrorException 'Invalid form data: file.name' * * @return void - * @covers ::upload() - * @covers ::checkRequestForUpload() */ public function testUploadInvalidFormDataFileName(): void { @@ -1047,8 +1076,6 @@ public function testUploadInvalidFormDataFileName(): void * Test `upload` method for InternalErrorException 'Invalid form data: file.tmp_name' * * @return void - * @covers ::upload() - * @covers ::checkRequestForUpload() */ public function testUploadInvalidFormDataFileTmpName(): void { @@ -1082,7 +1109,6 @@ public function testUploadInvalidFormDataFileTmpName(): void * Test `removeStream` method * * @return void - * @covers ::removeStream() */ public function testRemoveStreamWhenThereIsNoStream(): void { @@ -1124,7 +1150,7 @@ private function setupApi(): void * * @return array */ - public function setupRelationsProvider(): array + public static function setupRelationsProvider(): array { return [ 'simple' => [ @@ -1351,9 +1377,6 @@ public function setupRelationsProvider(): array /** * Test `setupRelationsMeta` method * - * @dataProvider setupRelationsProvider - * @covers ::setupRelationsMeta() - * @covers ::relationLabels() * @param array $expected Expected result. * @param array $schema Schema array. * @param array $relationships Relationships array. @@ -1362,6 +1385,7 @@ public function setupRelationsProvider(): array * @param array $readonly Readonly array. * @return void */ + #[DataProvider('setupRelationsProvider')] public function testSetupRelationsMeta(array $expected, array $schema, array $relationships, array $order = [], array $hidden = [], array $readonly = []): void { $this->Modules->setupRelationsMeta($schema, $relationships, $order, $hidden, $readonly); @@ -1379,7 +1403,6 @@ public function testSetupRelationsMeta(array $expected, array $schema, array $re * Test `relatedTypes` method * * @return void - * @covers ::relatedTypes() */ public function testRelatedTypes(): void { @@ -1413,7 +1436,7 @@ public function testRelatedTypes(): void * * @return array */ - public function relationsSchemaProvider(): array + public static function relationsSchemaProvider(): array { return [ 'empty data' => [ @@ -1508,13 +1531,12 @@ public function relationsSchemaProvider(): array * @param array $relationships The relationships * @param array $expected The expected result * @return void - * @dataProvider relationsSchemaProvider() - * @covers ::relationsSchema() */ + #[DataProvider('relationsSchemaProvider')] public function testRelationsSchema(array $schema, array $relationships, array $expected): void { // call private method using AppControllerTest->invokeMethod - $test = new AppControllerTest(); + $test = new AppControllerTest('test'); $actual = $test->invokeMethod($this->MyModules, 'relationsSchema', [$schema, $relationships]); static::assertEquals($expected, $actual); } @@ -1524,7 +1546,7 @@ public function testRelationsSchema(array $schema, array $relationships, array $ * * @return array */ - public function saveRelatedProvider(): array + public static function saveRelatedProvider(): array { $dummy = ['id' => 123, 'type' => 'dummies']; @@ -1659,13 +1681,11 @@ public function saveRelatedProvider(): array * @param array $relatedData Related objects data * @param mixed $expected The expected result * @return void - * @dataProvider saveRelatedProvider - * @covers ::saveRelated() - * @covers ::saveRelatedObjects() */ + #[DataProvider('saveRelatedProvider')] public function testSaveRelated(int $id, string $type, array $relatedData, $expected): void { - if ($expected instanceof \Exception) { + if ($expected instanceof Exception) { $this->expectException(get_class($expected)); $this->expectExceptionCode($expected->getCode()); $this->expectExceptionMessage($expected->getMessage()); @@ -1676,23 +1696,23 @@ public function testSaveRelated(int $id, string $type, array $relatedData, $expe ->setConstructorArgs(['https://media.example.org']) ->getMock(); $apiClient->method('addRelated') - ->will($this->returnCallback(function () use (&$actual) { + ->willReturnCallback(function () use (&$actual) { $actual = 'addRelated'; return ['response addRelated']; - })); + }); $apiClient->method('removeRelated') - ->will($this->returnCallback(function () use (&$actual) { + ->willReturnCallback(function () use (&$actual) { $actual = 'removeRelated'; return ['response removeRelated']; - })); + }); $apiClient->method('replaceRelated') - ->will($this->returnCallback(function () use (&$actual) { + ->willReturnCallback(function () use (&$actual) { $actual = 'replaceRelated'; return ['response replaceRelated']; - })); + }); ApiClientProvider::setApiClient($apiClient); $this->Modules->saveRelated((string)$id, $type, $relatedData); static::assertEquals($expected, $actual); @@ -1702,7 +1722,6 @@ public function testSaveRelated(int $id, string $type, array $relatedData, $expe * Test `getRelated` method on empty relatedIds. * * @return void - * @covers ::getRelated() */ public function testGetRelatedEmpty(): void { @@ -1715,7 +1734,6 @@ public function testGetRelatedEmpty(): void * Test `getRelated` method on non-empty relatedIds. * * @return void - * @covers ::getRelated() */ public function testGetRelated(): void { @@ -1745,7 +1763,6 @@ public function testGetRelated(): void * Test `setupAttributes` method * * @return void - * @covers ::setupAttributes() */ public function testSetupAttributes(): void { @@ -1760,7 +1777,6 @@ public function testSetupAttributes(): void * Test `skipSaveObject` method * * @return void - * @covers ::skipSaveObject() */ public function testSkipSaveObject(): void { @@ -1855,7 +1871,6 @@ public function getObject(string|int $id, string $type = 'objects', ?array $quer * Test `skipSaveRelated` method * * @return void - * @covers ::skipSaveRelated() */ public function testSkipSaveRelated(): void { @@ -1933,7 +1948,6 @@ public function getRelated(string|int $id, string $type, string $relation, ?arra * Test `skipSavePermissions` method * * @return void - * @covers ::skipSavePermissions() */ public function testSkipSavePermissions(): void { @@ -1954,7 +1968,7 @@ public function getObjects(string $type = 'objects', ?array $query = null, ?arra }; $safeClient = ApiClientProvider::getApiClient(); ApiClientProvider::setApiClient($apiClient); - $controller = new AppController(); + $controller = new AppController(new ServerRequest()); $registry = $controller->components(); $registry->load('Authentication.Authentication'); /** @var \App\Controller\Component\ModulesComponent $modulesComponent */ diff --git a/tests/TestCase/Controller/Component/ObjectsEditorsComponentTest.php b/tests/TestCase/Controller/Component/ObjectsEditorsComponentTest.php index 47aebbf56..3ec79a6ff 100644 --- a/tests/TestCase/Controller/Component/ObjectsEditorsComponentTest.php +++ b/tests/TestCase/Controller/Component/ObjectsEditorsComponentTest.php @@ -9,16 +9,23 @@ use Cake\Cache\Cache; use Cake\Controller\Controller; use Cake\Core\Configure; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * {@see \App\Controller\Component\ObjectsEditorsComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\ObjectsEditorsComponent */ +#[CoversClass(ObjectsEditorsComponent::class)] +#[CoversMethod(ObjectsEditorsComponent::class, 'cleanup')] +#[CoversMethod(ObjectsEditorsComponent::class, 'editorName')] +#[CoversMethod(ObjectsEditorsComponent::class, 'getEditors')] +#[CoversMethod(ObjectsEditorsComponent::class, 'initialize')] +#[CoversMethod(ObjectsEditorsComponent::class, 'update')] class ObjectsEditorsComponentTest extends TestCase { /** @@ -26,14 +33,14 @@ class ObjectsEditorsComponentTest extends TestCase * * @var \App\Controller\Component\ObjectsEditorsComponent */ - public $ObjectsEditors; + public ObjectsEditorsComponent $ObjectsEditors; /** * Authentication component * * @var \Authentication\Controller\Component\AuthenticationComponent; */ - public $Authentication; + public AuthenticationComponent $Authentication; /** * @inheritDoc @@ -42,7 +49,7 @@ public function setUp(): void { Cache::enable(); parent::setUp(); - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); $registry->load('Authentication.Authentication'); /** @var \App\Controller\Component\ObjectsEditorsComponent $objectsEditorsComponent */ @@ -95,7 +102,6 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac * Test initial setup * * @return void - * @covers ::initialize() */ public function testInitialize(): void { @@ -120,7 +126,6 @@ public function testInitialize(): void * Test `update` method * * @return void - * @covers ::update() */ public function testUpdate(): void { @@ -169,7 +174,6 @@ public function testUpdate(): void * Test `editorName` method * * @return void - * @covers ::editorName() */ public function testEditorName(): void { @@ -210,7 +214,6 @@ public function testEditorName(): void * Test `getEditors` method * * @return void - * @covers ::getEditors() */ public function testGetEditors(): void { @@ -239,7 +242,6 @@ public function testGetEditors(): void * Test `cleanup` method * * @return void - * @covers ::cleanup() */ public function testCleanup(): void { diff --git a/tests/TestCase/Controller/Component/ParentsComponentTest.php b/tests/TestCase/Controller/Component/ParentsComponentTest.php index 8dbe231fa..d385f7b52 100644 --- a/tests/TestCase/Controller/Component/ParentsComponentTest.php +++ b/tests/TestCase/Controller/Component/ParentsComponentTest.php @@ -8,12 +8,14 @@ use BEdita\WebTools\ApiClientProvider; use Cake\Controller\ComponentRegistry; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Component\ParentsComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\ParentsComponent */ +#[CoversClass(ParentsComponent::class)] +#[CoversMethod(ParentsComponent::class, 'addRelated')] class ParentsComponentTest extends TestCase { /** @@ -34,7 +36,6 @@ protected function tearDown(): void * Test addRelated method with valid data. * * @return void - * @covers ::addRelated() */ public function testAddRelated(): void { diff --git a/tests/TestCase/Controller/Component/ProjectConfigurationComponentTest.php b/tests/TestCase/Controller/Component/ProjectConfigurationComponentTest.php index efdbe32fa..f18ae99db 100644 --- a/tests/TestCase/Controller/Component/ProjectConfigurationComponentTest.php +++ b/tests/TestCase/Controller/Component/ProjectConfigurationComponentTest.php @@ -8,13 +8,18 @@ use Cake\Cache\Cache; use Cake\Controller\Controller; use Cake\Core\Configure; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Component\ProjectConfigurationComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\ProjectConfigurationComponent */ +#[CoversClass(ProjectConfigurationComponent::class)] +#[CoversMethod(ProjectConfigurationComponent::class, 'fetchConfig')] +#[CoversMethod(ProjectConfigurationComponent::class, 'read')] class ProjectConfigurationComponentTest extends TestCase { /** @@ -22,7 +27,7 @@ class ProjectConfigurationComponentTest extends TestCase * * @var \App\Controller\Component\ProjectConfigurationComponent */ - public $ProjectConfiguration; + public ProjectConfigurationComponent $ProjectConfiguration; /** * @inheritDoc @@ -31,9 +36,8 @@ public function setUp(): void { parent::setUp(); - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); - $registry->load('Auth'); /** @var \App\Controller\Component\ProjectConfigurationComponent $projectConfigurationComponent */ $projectConfigurationComponent = $registry->load(ProjectConfigurationComponent::class); $this->ProjectConfiguration = $projectConfigurationComponent; @@ -56,7 +60,7 @@ public function tearDown(): void * * @return array */ - public function readProvider(): array + public static function readProvider(): array { return [ 'simple conf' => [ @@ -81,11 +85,9 @@ public function readProvider(): array * @param array $expected Expected result. * @param array $config Response from `/config` endpoint. * @return void - * @dataProvider readProvider() - * @covers ::read() - * @covers ::fetchConfig() */ - public function testRead($expected, $config): void + #[DataProvider('readProvider')] + public function testRead(array $expected, array $config): void { Configure::write('Project.config', null); // Setup mock API client. @@ -107,7 +109,6 @@ public function testRead($expected, $config): void /** * Test `read()` method with configured data * - * @covers ::read() * @return void */ public function testReadFromConf(): void @@ -121,7 +122,6 @@ public function testReadFromConf(): void /** * Test `read()` method with API Error * - * @covers ::read() * @return void */ public function testReadError(): void diff --git a/tests/TestCase/Controller/Component/PropertiesComponentTest.php b/tests/TestCase/Controller/Component/PropertiesComponentTest.php index 4eb0cba66..e68dd4225 100644 --- a/tests/TestCase/Controller/Component/PropertiesComponentTest.php +++ b/tests/TestCase/Controller/Component/PropertiesComponentTest.php @@ -17,13 +17,28 @@ use App\Utility\CacheTools; use Cake\Cache\Cache; use Cake\Core\Configure; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Component\PropertiesComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\PropertiesComponent */ +#[CoversClass(PropertiesComponent::class)] +#[CoversMethod(PropertiesComponent::class, 'associationsOptions')] +#[CoversMethod(PropertiesComponent::class, 'bulkList')] +#[CoversMethod(PropertiesComponent::class, 'filterList')] +#[CoversMethod(PropertiesComponent::class, 'filtersByType')] +#[CoversMethod(PropertiesComponent::class, 'hiddenRelationsList')] +#[CoversMethod(PropertiesComponent::class, 'indexList')] +#[CoversMethod(PropertiesComponent::class, 'initialize')] +#[CoversMethod(PropertiesComponent::class, 'readonlyRelationsList')] +#[CoversMethod(PropertiesComponent::class, 'relationsList')] +#[CoversMethod(PropertiesComponent::class, 'startup')] +#[CoversMethod(PropertiesComponent::class, 'typesOptions')] +#[CoversMethod(PropertiesComponent::class, 'viewGroups')] class PropertiesComponentTest extends TestCase { /** @@ -31,7 +46,7 @@ class PropertiesComponentTest extends TestCase * * @var \App\Controller\Component\PropertiesComponent */ - public $Properties; + public PropertiesComponent $Properties; /** * @inheritDoc @@ -61,7 +76,7 @@ public function tearDown(): void */ protected function createComponent(): void { - $controller = new ModulesController(); + $controller = new ModulesController(new ServerRequest()); $registry = $controller->components(); // Mock GET /config using cache Cache::write(CacheTools::cacheKey('config.Modules'), []); @@ -76,7 +91,6 @@ protected function createComponent(): void * Test `startup()` method. * * @return void - * @covers ::startup() */ public function testStartup(): void { @@ -108,7 +122,6 @@ public function testStartup(): void * Test `indexList()` method. * * @return void - * @covers ::indexList() */ public function testIndexList(): void { @@ -127,7 +140,6 @@ public function testIndexList(): void * Test `filterList()` method. * * @return void - * @covers ::filterList() */ public function testFilterList(): void { @@ -148,7 +160,6 @@ public function testFilterList(): void * Test `filtersByType()` method. * * @return void - * @covers ::filtersByType() */ public function testFiltersByType(): void { @@ -177,7 +188,6 @@ public function testFiltersByType(): void * Test `bulkList()` method. * * @return void - * @covers ::bulkList() */ public function testBulkList(): void { @@ -193,7 +203,6 @@ public function testBulkList(): void * Test `relationsList()` method. * * @return void - * @covers ::relationsList() */ public function testRelationsList(): void { @@ -212,7 +221,6 @@ public function testRelationsList(): void * Test `hiddenRelationsList()` method. * * @return void - * @covers ::hiddenRelationsList() */ public function testHiddenRelationsList(): void { @@ -231,7 +239,6 @@ public function testHiddenRelationsList(): void * Test `readonlyRelationsList()` method. * * @return void - * @covers ::readonlyRelationsList() */ public function testReadonlyRelationsList(): void { @@ -251,7 +258,7 @@ public function testReadonlyRelationsList(): void * * @return array */ - public function viewGroupsProvider(): array + public static function viewGroupsProvider(): array { return [ 'minimal' => [ @@ -490,10 +497,8 @@ public function viewGroupsProvider(): array * @param string $type Object type. * @param array $config Properties configuration to write for $type * @return void - * @dataProvider viewGroupsProvider() - * @covers ::viewGroups() - * @covers ::initialize() */ + #[DataProvider('viewGroupsProvider')] public function testViewGroups($expected, $object, string $type, array $config = []): void { Cache::clear(); @@ -518,7 +523,6 @@ public function testViewGroups($expected, $object, string $type, array $config = * Test `typesOptions`. * * @return void - * @covers ::typesOptions() */ public function testTypesOptions(): void { @@ -534,7 +538,6 @@ public function testTypesOptions(): void * Test `associationsOptions` * * @return void - * @covers ::associationsOptions() */ public function testAssociationsOptions(): void { diff --git a/tests/TestCase/Controller/Component/QueryComponentTest.php b/tests/TestCase/Controller/Component/QueryComponentTest.php index 08020b3e6..c682d29b8 100644 --- a/tests/TestCase/Controller/Component/QueryComponentTest.php +++ b/tests/TestCase/Controller/Component/QueryComponentTest.php @@ -6,12 +6,18 @@ use Cake\Core\Configure; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Component\QueryComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\QueryComponent */ +#[CoversClass(QueryComponent::class)] +#[CoversMethod(QueryComponent::class, 'handleInclude')] +#[CoversMethod(QueryComponent::class, 'handleSort')] +#[CoversMethod(QueryComponent::class, 'index')] +#[CoversMethod(QueryComponent::class, 'prepare')] class QueryComponentTest extends TestCase { /** @@ -19,7 +25,7 @@ class QueryComponentTest extends TestCase * * @var \App\Controller\Component\QueryComponent */ - public $Query; + public QueryComponent $Query; /** * @inheritDoc @@ -27,7 +33,7 @@ class QueryComponentTest extends TestCase public function setUp(): void { parent::setUp(); - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); /** @var \App\Controller\Component\QueryComponent $queryComponent */ $queryComponent = $registry->load(QueryComponent::class); @@ -49,7 +55,7 @@ public function tearDown(): void * * @return array */ - public function indexProvider(): array + public static function indexProvider(): array { return [ 'query filter' => [ @@ -89,11 +95,8 @@ public function indexProvider(): array * Test `index` method * * @return void - * @covers ::index() - * @covers ::handleSort() - * @covers ::handleInclude() - * @dataProvider indexProvider() */ + #[DataProvider('indexProvider')] public function testIndex(array $queryParams, array $config, array $expected): void { $controller = new Controller( @@ -103,8 +106,8 @@ public function testIndex(array $queryParams, array $config, array $expected): v 'environment' => [ 'REQUEST_METHOD' => 'GET', ], - ] - ) + ], + ), ); $registry = $controller->components(); /** @var \App\Controller\Component\QueryComponent $Query */ @@ -120,7 +123,6 @@ public function testIndex(array $queryParams, array $config, array $expected): v * Test `handleInclude` method. * * @return void - * @covers ::handleInclude() */ public function testHandleInclude(): void { @@ -134,8 +136,8 @@ public function testHandleInclude(): void 'params' => [ 'object_type' => 'test', ], - ] - ) + ], + ), ); $registry = $controller->components(); $component = new class ($registry) extends QueryComponent { @@ -165,7 +167,7 @@ public function handleInclude(array $query): array * * @return array */ - public function prepareProvider(): array + public static function prepareProvider(): array { return [ 'simple' => [ @@ -211,9 +213,8 @@ public function prepareProvider(): array * Test `prepare` method. * * @return void - * @dataProvider prepareProvider - * @covers ::prepare() */ + #[DataProvider('prepareProvider')] public function testPrepare(array $expected, array $query): void { $actual = $this->Query->prepare($query); diff --git a/tests/TestCase/Controller/Component/SchemaComponentTest.php b/tests/TestCase/Controller/Component/SchemaComponentTest.php index 8d53135cc..9e938828e 100644 --- a/tests/TestCase/Controller/Component/SchemaComponentTest.php +++ b/tests/TestCase/Controller/Component/SchemaComponentTest.php @@ -3,20 +3,46 @@ use App\Controller\Component\SchemaComponent; use App\Utility\CacheTools; +use Authentication\Controller\Component\AuthenticationComponent; use BEdita\SDK\BEditaClient; use BEdita\SDK\BEditaClientException; use BEdita\WebTools\ApiClientProvider; use Cake\Cache\Cache; use Cake\Controller\Controller; use Cake\Core\Configure; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use ReflectionClass; +use RuntimeException; /** * {@see \App\Controller\Component\SchemaComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\SchemaComponent */ +#[CoversClass(SchemaComponent::class)] +#[CoversMethod(SchemaComponent::class, 'abstractTypes')] +#[CoversMethod(SchemaComponent::class, 'concreteTypes')] +#[CoversMethod(SchemaComponent::class, 'customProps')] +#[CoversMethod(SchemaComponent::class, 'descendants')] +#[CoversMethod(SchemaComponent::class, 'fetchCategories')] +#[CoversMethod(SchemaComponent::class, 'fetchCustomProps')] +#[CoversMethod(SchemaComponent::class, 'fetchObjectTypeMeta')] +#[CoversMethod(SchemaComponent::class, 'fetchObjectTypesFeatures')] +#[CoversMethod(SchemaComponent::class, 'fetchRelationData')] +#[CoversMethod(SchemaComponent::class, 'fetchRoles')] +#[CoversMethod(SchemaComponent::class, 'fetchSchema')] +#[CoversMethod(SchemaComponent::class, 'getRelationsSchema')] +#[CoversMethod(SchemaComponent::class, 'getSchema')] +#[CoversMethod(SchemaComponent::class, 'getSchemasByType')] +#[CoversMethod(SchemaComponent::class, 'loadInternalSchema')] +#[CoversMethod(SchemaComponent::class, 'loadWithRevision')] +#[CoversMethod(SchemaComponent::class, 'objectTypesFeatures')] +#[CoversMethod(SchemaComponent::class, 'setDescendant')] +#[CoversMethod(SchemaComponent::class, 'tagsInUse')] class SchemaComponentTest extends TestCase { /** @@ -24,7 +50,7 @@ class SchemaComponentTest extends TestCase * * @var \App\Controller\Component\SchemaComponent */ - public $Schema; + public SchemaComponent $Schema; /** * @inheritDoc @@ -33,9 +59,9 @@ public function setUp(): void { parent::setUp(); - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); - $registry->load('Auth'); + $registry->load(AuthenticationComponent::class); /** @var \App\Controller\Component\SchemaComponent $schemaComponent */ $schemaComponent = $registry->load(SchemaComponent::class); $this->Schema = $schemaComponent; @@ -58,7 +84,7 @@ public function tearDown(): void * * @return array */ - public function getSchemaProvider(): array + public static function getSchemaProvider(): array { return [ 'type as argument' => [ @@ -92,8 +118,8 @@ public function getSchemaProvider(): array 'you-are-not-my-type', ], 'other exception' => [ - new \RuntimeException('I am some other kind of exception', 999), - new \RuntimeException('I am some other kind of exception', 999), + new RuntimeException('I am some other kind of exception', 999), + new RuntimeException('I am some other kind of exception', 999), 'you-are-not-my-type', ], 'no schema' => [ @@ -107,19 +133,16 @@ public function getSchemaProvider(): array /** * Test `getSchema()` method. * - * @param array|\Exception $expected Expected result. + * @param array|\Exception|bool $expected Expected result. * @param array|\Exception $schema Response to `/schema/:type` endpoint. * @param string|null $type Type to get schema for. * @param array $config Component configuration. * @return void - * @dataProvider getSchemaProvider() - * @covers ::fetchSchema() - * @covers ::getSchema() - * @covers ::loadWithRevision() */ - public function testGetSchema($expected, $schema, ?string $type, array $config = []): void + #[DataProvider('getSchemaProvider')] + public function testGetSchema(array|Exception|bool $expected, array|Exception $schema, ?string $type, array $config = []): void { - if ($expected instanceof \Exception) { + if ($expected instanceof Exception) { $this->expectException(get_class($expected)); $this->expectExceptionCode($expected->getCode()); $this->expectExceptionMessage($expected->getMessage()); @@ -129,7 +152,7 @@ public function testGetSchema($expected, $schema, ?string $type, array $config = $apiClient = $this->getMockBuilder(BEditaClient::class) ->setConstructorArgs(['https://api.example.org']) ->getMock(); - if ($schema instanceof \Exception) { + if ($schema instanceof Exception) { $apiClient->method('schema') ->with($type ?: $config['type']) ->willThrowException($schema); @@ -151,7 +174,6 @@ public function testGetSchema($expected, $schema, ?string $type, array $config = * Test `getSchema`, cache case. * * @return void - * @covers ::getSchema() */ public function testGetSchemaFromCache(): void { @@ -161,7 +183,7 @@ public function testGetSchemaFromCache(): void // from cache Cache::enable(); - $reflectionClass = new \ReflectionClass($this->Schema); + $reflectionClass = new ReflectionClass($this->Schema); $key = CacheTools::cacheKey($type); Cache::write($key, $schema, SchemaComponent::CACHE_CONFIG); @@ -176,7 +198,7 @@ public function testGetSchemaFromCache(): void * * @return array */ - public function getSchemasByTypeProvider(): array + public static function getSchemasByTypeProvider(): array { return [ 'empty' => [ @@ -204,9 +226,8 @@ public function getSchemasByTypeProvider(): array * Test `getSchemasByType`. * * @return void - * @dataProvider getSchemasByTypeProvider() - * @covers ::getSchemasByType() */ + #[DataProvider('getSchemasByTypeProvider')] public function testGetSchemasByType(array $types, array $expected): void { $schemasByType = $this->Schema->getSchemasByType($types); @@ -224,7 +245,6 @@ public function testGetSchemasByType(array $types, array $expected): void * Test `loadWithRevision` * * @return void - * @covers ::loadWithRevision() */ public function testLoadWithRevision(): void { @@ -233,7 +253,7 @@ public function testLoadWithRevision(): void $revision = $schema['revision']; // null - $reflectionClass = new \ReflectionClass($this->Schema); + $reflectionClass = new ReflectionClass($this->Schema); $method = $reflectionClass->getMethod('loadWithRevision'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Schema, [$type, $revision]); @@ -259,11 +279,9 @@ public function testLoadWithRevision(): void } /** - * Test load internal schema from configuration. + * Test `loadInternalSchema` method: load internal schema from configuration. * * @return void - * @covers ::getSchema() - * @covers ::loadInternalSchema */ public function testInternalSchema(): void { @@ -281,9 +299,6 @@ public function testInternalSchema(): void * Test load relations schema. * * @return void - * @covers ::getRelationsSchema() - * @covers ::fetchRelationData() - * @covers ::concreteTypes() */ public function testRelationMethods(): void { @@ -375,8 +390,6 @@ public function testRelationMethods(): void * Test load internal schema from configuration. * * @return void - * @covers ::getRelationsSchema() - * @covers ::fetchRelationData() */ public function testFailRelationsSchema(): void { @@ -401,7 +414,7 @@ public function testFailRelationsSchema(): void * * @return array */ - public function concreteTypesProvider(): array + public static function concreteTypesProvider(): array { return [ 'empty' => [ @@ -429,12 +442,11 @@ public function concreteTypesProvider(): array * @param array $descendants The descendants * @param array $expected The expected result * @return void - * @dataProvider concreteTypesProvider() - * @covers ::concreteTypes() */ + #[DataProvider('concreteTypesProvider')] public function testConcreteTypes(array $types, array $descendants, array $expected): void { - $reflectionClass = new \ReflectionClass($this->Schema); + $reflectionClass = new ReflectionClass($this->Schema); $method = $reflectionClass->getMethod('concreteTypes'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Schema, [$types, $descendants]); @@ -445,8 +457,6 @@ public function testConcreteTypes(array $types, array $descendants, array $expec * Test `fetchSchema` for `users`. * * @return void - * @covers ::fetchSchema() - * @covers ::fetchRoles() */ public function testFetchRoles(): void { @@ -491,8 +501,6 @@ public function testFetchRoles(): void * Test `fetchSchema` for `categories`. * * @return void - * @covers ::fetchSchema() - * @covers ::fetchCategories() */ public function testFetchCategories(): void { @@ -553,7 +561,6 @@ public function testFetchCategories(): void * Test `fetchCategories` with API error. * * @return void - * @covers ::fetchCategories() */ public function testFetchCategoriesFail(): void { @@ -562,7 +569,7 @@ public function testFetchCategoriesFail(): void ->setConstructorArgs(['https://api.example.org']) ->getMock(); $apiClient->method('get') - ->will($this->returnCallback([$this, 'mockApiCallback'])); + ->willReturnCallback([$this, 'mockApiCallback']); $apiClient->method('schema') ->willReturn(['type' => 'object']); @@ -596,7 +603,6 @@ public function mockApiCallback(): array * Test `fetchObjectTypeMeta` method. * * @return void - * @covers ::fetchObjectTypeMeta() */ public function testFetchObjectTypeMeta(): void { @@ -629,7 +635,6 @@ public function testFetchObjectTypeMeta(): void /** * Test `descendants` method on abstract type * - * @covers ::descendants() * @return void */ public function testDescendants(): void @@ -645,9 +650,6 @@ public function testDescendants(): void * Test `objectTypesFeatures` method. * * @return void - * @covers ::objectTypesFeatures() - * @covers ::fetchObjectTypesFeatures() - * @covers ::setDescendant() */ public function testObjectTypesFeatures(): void { @@ -722,7 +724,6 @@ public function testObjectTypesFeatures(): void * Test `objectTypesFeatures` with API error. * * @return void - * @covers ::objectTypesFeatures() */ public function testObjectTypesFeaturesFail(): void { @@ -743,8 +744,6 @@ public function testObjectTypesFeaturesFail(): void * Test `customProps` method. * * @return void - * @covers ::customProps() - * @covers ::fetchCustomProps() */ public function testCustomProps(): void { @@ -791,7 +790,6 @@ public function testCustomProps(): void * Test `abstractTypes` * * @return void - * @covers ::abstractTypes() */ public function testAbstractTypes(): void { @@ -803,7 +801,6 @@ public function testAbstractTypes(): void * Test `tagsInUse` * * @return void - * @covers ::tagsInUse() */ public function testTagsInUse(): void { diff --git a/tests/TestCase/Controller/Component/ThumbsComponentTest.php b/tests/TestCase/Controller/Component/ThumbsComponentTest.php index 60ec267f5..ed5cf46ec 100644 --- a/tests/TestCase/Controller/Component/ThumbsComponentTest.php +++ b/tests/TestCase/Controller/Component/ThumbsComponentTest.php @@ -9,12 +9,16 @@ use Cake\Controller\Controller; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Controller\Component\ThumbsComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\ThumbsComponent */ +#[CoversClass(ThumbsComponent::class)] +#[CoversMethod(ThumbsComponent::class, 'getThumbs')] +#[CoversMethod(ThumbsComponent::class, 'urls')] class ThumbsComponentTest extends TestCase { /** @@ -22,14 +26,14 @@ class ThumbsComponentTest extends TestCase * * @var \App\Controller\Component\ThumbsComponent */ - public $Thumbs; + public ThumbsComponent $Thumbs; /** * BEdita client * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * @inheritDoc @@ -37,7 +41,7 @@ class ThumbsComponentTest extends TestCase public function setUp(): void { parent::setUp(); - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); /** @var \App\Controller\Component\ThumbsComponent $thumbsComponent */ $thumbsComponent = $registry->load(ThumbsComponent::class); @@ -61,7 +65,7 @@ public function tearDown(): void * * @return array */ - public function urlsProvider(): array + public static function urlsProvider(): array { return [ // test with empty object @@ -144,10 +148,8 @@ public function urlsProvider(): array * @param array $data The data to process * @param ?mixed $mockResponse The mock response, if any * @return void - * @dataProvider urlsProvider() - * @covers ::urls() - * @covers ::getThumbs() */ + #[DataProvider('urlsProvider')] public function testUrls(array $expected, array $data, $mockResponse = null): void { $controller = new Controller(new ServerRequest([])); @@ -171,8 +173,6 @@ public function testUrls(array $expected, array $data, $mockResponse = null): vo * Test `urls` method, with errors from thumbnail generation API. * * @return void - * @covers ::urls() - * @covers ::getThumbs() */ public function testUrlsThumbErrors(): void { @@ -232,8 +232,6 @@ public function testUrlsThumbErrors(): void /** * Test `urls` method, exception case * - * @covers ::urls() - * @covers ::getThumbs() * @return void */ public function testUrlsException(): void diff --git a/tests/TestCase/Controller/Component/TranslatorComponentTest.php b/tests/TestCase/Controller/Component/TranslatorComponentTest.php index ddaf43cae..7ea3729fb 100644 --- a/tests/TestCase/Controller/Component/TranslatorComponentTest.php +++ b/tests/TestCase/Controller/Component/TranslatorComponentTest.php @@ -17,13 +17,17 @@ use Cake\Controller\Controller; use Cake\Core\Configure; use Cake\Http\Exception\InternalErrorException; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Component\TranslatorComponent} Test Case - * - * @coversDefaultClass \App\Controller\Component\TranslatorComponent */ +#[CoversClass(TranslatorComponent::class)] +#[CoversMethod(TranslatorComponent::class, 'initialize')] +#[CoversMethod(TranslatorComponent::class, 'translate')] class TranslatorComponentTest extends TestCase { /** @@ -31,7 +35,7 @@ class TranslatorComponentTest extends TestCase * * @var \App\Controller\Component\TranslatorComponent */ - public $Translator; + public TranslatorComponent $Translator; /** * @inheritDoc @@ -50,7 +54,7 @@ public function tearDown(): void */ protected function createComponent(): void { - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $registry = $controller->components(); /** @var \App\Controller\Component\TranslatorComponent $translatorComponent */ $translatorComponent = $registry->load(TranslatorComponent::class); @@ -61,8 +65,6 @@ protected function createComponent(): void * Test `translate()` method. * * @return void - * @covers ::translate() - * @covers ::initialize() */ public function testTranslateInternalErrorException(): void { @@ -75,8 +77,6 @@ public function testTranslateInternalErrorException(): void * Test `translate()` method. * * @return void - * @covers ::translate() - * @covers ::initialize() */ public function testTranslate(): void { diff --git a/tests/TestCase/Controller/CourtesyPageControllerTest.php b/tests/TestCase/Controller/CourtesyPageControllerTest.php index 554439ddf..7c6a24b57 100644 --- a/tests/TestCase/Controller/CourtesyPageControllerTest.php +++ b/tests/TestCase/Controller/CourtesyPageControllerTest.php @@ -5,20 +5,20 @@ use Cake\Core\Configure; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\CourtesyPageController} Test Case - * - * @coversDefaultClass \App\Controller\CourtesyPageController - * @uses \App\Controller\CourtesyPageController */ +#[CoversClass(CourtesyPageController::class)] +#[CoversMethod(CourtesyPageController::class, 'index')] class CourtesyPageControllerTest extends TestCase { /** * Test `index` method * * @return void - * @covers ::index() */ public function testIndex(): void { diff --git a/tests/TestCase/Controller/DashboardControllerTest.php b/tests/TestCase/Controller/DashboardControllerTest.php index 0322c28d6..a496abddb 100644 --- a/tests/TestCase/Controller/DashboardControllerTest.php +++ b/tests/TestCase/Controller/DashboardControllerTest.php @@ -17,7 +17,7 @@ use App\Utility\CacheTools; use Authentication\AuthenticationService; use Authentication\AuthenticationServiceInterface; -use Authentication\Identifier\IdentifierInterface; +use Authentication\Identifier\AbstractIdentifier; use Authentication\Identity; use Authentication\IdentityInterface; use BEdita\WebTools\ApiClientProvider; @@ -27,15 +27,19 @@ use Cake\Http\Exception\MethodNotAllowedException; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * {@see \App\Controller\DashboardController} Test Case - * - * @coversDefaultClass \App\Controller\DashboardController - * @uses \App\Controller\DashboardController */ +#[CoversClass(DashboardController::class)] +#[CoversMethod(DashboardController::class, 'index')] +#[CoversMethod(DashboardController::class, 'initialize')] +#[CoversMethod(DashboardController::class, 'messages')] class DashboardControllerTest extends TestCase { /** @@ -43,7 +47,7 @@ class DashboardControllerTest extends TestCase * * @var \App\Controller\DashboardController */ - public $Dashboard; + public DashboardController $Dashboard; /** * {@inheritDoc} @@ -69,9 +73,9 @@ public function tearDown(): void * @param ?array $config The config * @return void */ - protected function setupController($config = null): void + protected function setupController(?array $config = null): void { - $request = null; + $request = new ServerRequest(); if ($config != null) { $request = new ServerRequest($config); } @@ -96,11 +100,11 @@ protected function setupControllerAndLogin(array $requestConfig): ?array // Mock Authentication component ApiClientProvider::getApiClient()->setupTokens([]); // reset client $service = new AuthenticationService(); - $service->loadIdentifier(ApiIdentifier::class); $service->loadAuthenticator('Authentication.Form', [ + 'identifier' => ApiIdentifier::class, 'fields' => [ - IdentifierInterface::CREDENTIAL_USERNAME => 'username', - IdentifierInterface::CREDENTIAL_PASSWORD => 'password', + AbstractIdentifier::CREDENTIAL_USERNAME => 'username', + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password', ], ]); $this->Dashboard->setRequest($this->Dashboard->getRequest()->withAttribute('authentication', $service)); @@ -144,7 +148,6 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac /** * Test `initialize` method * - * @covers ::initialize() * @return void */ public function testInitialize(): void @@ -160,7 +163,7 @@ public function testInitialize(): void * * @return array */ - public function indexProvider(): array + public static function indexProvider(): array { return [ 'post' => [ @@ -187,10 +190,9 @@ public function indexProvider(): array * * @param MethodNotAllowedException|null $expected The expected exception or null * @param string $method The request method, can be 'GET', 'PATCH', 'POST', 'DELETE' - * @covers ::index() - * @dataProvider indexProvider() * @return void */ + #[DataProvider('indexProvider')] public function testIndex($expected, $method): void { $requestConfig = [ @@ -252,7 +254,6 @@ public function testIndex($expected, $method): void /** * Test `messages` method * - * @covers ::messages() * @return void */ public function testMessages(): void @@ -270,7 +271,6 @@ public function testMessages(): void /** * Test `messages` method for "MethodNotAllowed" case * - * @covers ::messages() * @return void */ public function testMessagesMethodNotAllowed(): void diff --git a/tests/TestCase/Controller/DownloadControllerTest.php b/tests/TestCase/Controller/DownloadControllerTest.php index 49c35a1aa..78500afc8 100644 --- a/tests/TestCase/Controller/DownloadControllerTest.php +++ b/tests/TestCase/Controller/DownloadControllerTest.php @@ -8,21 +8,24 @@ use Cake\Http\Client\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\DownloadController} Test Case - * - * @coversDefaultClass \App\Controller\DownloadController - * @uses \App\Controller\DownloadController */ +#[CoversClass(DownloadController::class)] +#[CoversMethod(DownloadController::class, 'content')] +#[CoversMethod(DownloadController::class, 'download')] +#[CoversMethod(DownloadController::class, 'streamDownload')] class DownloadControllerTest extends TestCase { /** * The original API client (not mocked). * - * @var \BEdita\SDK\BEditaClient + * @var \BEdita\SDK\BEditaClient|null */ - protected $apiClient = null; + protected ?BEditaClient $apiClient = null; /** * @inheritDoc @@ -44,8 +47,6 @@ public function tearDown(): void * Test download from URL * * @return void - * @covers ::download() - * @covers ::content() */ public function testDownloadUrl(): void { @@ -78,7 +79,7 @@ public function testDownloadUrl(): void 'params' => [ 'id' => $uuid, ], - ]) + ]), ); $response = $controller->download($uuid); @@ -94,9 +95,6 @@ public function testDownloadUrl(): void * Test download from stream * * @return void - * @covers ::download() - * @covers ::content() - * @covers ::streamDownload() */ public function testDownloadStream(): void { @@ -131,7 +129,7 @@ public function testDownloadStream(): void 'params' => [ 'id' => $uuid, ], - ]) + ]), ); $response = new Response([], 'test'); diff --git a/tests/TestCase/Controller/ErrorControllerTest.php b/tests/TestCase/Controller/ErrorControllerTest.php index 656297447..1f74e9464 100644 --- a/tests/TestCase/Controller/ErrorControllerTest.php +++ b/tests/TestCase/Controller/ErrorControllerTest.php @@ -14,14 +14,20 @@ namespace App\Test\TestCase\Controller; use App\Controller\ErrorController; +use Cake\Event\Event; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\ErrorController} Test Case * - * @coversDefaultClass \App\Controller\ErrorController * @uses \App\Controller\ErrorController */ +#[CoversClass(ErrorController::class)] +#[CoversMethod(ErrorController::class, 'beforeFilter')] +#[CoversMethod(ErrorController::class, 'beforeRender')] class ErrorControllerTest extends TestCase { /** @@ -38,19 +44,32 @@ class ErrorControllerTest extends TestCase */ protected function setupController(): void { - $this->ErrorController = new ErrorController(); + $this->ErrorController = new ErrorController(new ServerRequest()); } /** - * test `initialize` function + * Test `beforeFiler` method * - * @covers ::initialize() * @return void */ - public function testInitialize(): void + public function testBeforeFilter(): void { $this->setupController(); + $event = new Event('Controller.beforeFilter'); + $this->assertNull($this->ErrorController->beforeFilter($event)); + } - static::assertNotEmpty($this->ErrorController->{'RequestHandler'}); + /** + * Test `beforeRender` method + * + * @return void + */ + public function testBeforeRender(): void + { + $this->setupController(); + $event = new Event('Controller.beforeRender'); + $this->assertNull($this->ErrorController->beforeRender($event)); + $this->assertSame('App\View\AppView', $this->ErrorController->viewBuilder()->getClassName()); + $this->assertSame('Error', $this->ErrorController->viewBuilder()->getTemplatePath()); } } diff --git a/tests/TestCase/Controller/ExportControllerTest.php b/tests/TestCase/Controller/ExportControllerTest.php index 0a286c50c..4773d92ee 100644 --- a/tests/TestCase/Controller/ExportControllerTest.php +++ b/tests/TestCase/Controller/ExportControllerTest.php @@ -13,6 +13,7 @@ namespace App\Test\TestCase\Controller; +use App\Controller\Component\ExportComponent; use App\Controller\ExportController; use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; @@ -21,13 +22,31 @@ use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use ReflectionClass; +use ReflectionProperty; /** * {@see \App\Controller\ExportController} Test Case - * - * @coversDefaultClass \App\Controller\ExportController - * @uses \App\Controller\ExportController */ +#[CoversClass(ExportController::class)] +#[CoversMethod(ExportController::class, 'apiPath')] +#[CoversMethod(ExportController::class, 'export')] +#[CoversMethod(ExportController::class, 'fillDataFromResponse')] +#[CoversMethod(ExportController::class, 'getFieldNames')] +#[CoversMethod(ExportController::class, 'getFileName')] +#[CoversMethod(ExportController::class, 'getRelatedFileName')] +#[CoversMethod(ExportController::class, 'getValue')] +#[CoversMethod(ExportController::class, 'limit')] +#[CoversMethod(ExportController::class, 'prepareQuery')] +#[CoversMethod(ExportController::class, 'related')] +#[CoversMethod(ExportController::class, 'relatedFiltered')] +#[CoversMethod(ExportController::class, 'rows')] +#[CoversMethod(ExportController::class, 'rowsAll')] +#[CoversMethod(ExportController::class, 'rowsAllRelated')] +#[CoversMethod(ExportController::class, 'rowFields')] class ExportControllerTest extends TestCase { /** @@ -35,21 +54,21 @@ class ExportControllerTest extends TestCase * * @var \App\Controller\ExportController */ - public $Export; + public ExportController $Export; /** * The api client (not mocked). * - * @var BEditaClient + * @var BEditaClient|null */ - protected $apiClient = null; + protected ?BEditaClient $apiClient = null; /** * Test data. * * @var array */ - protected $testdata = [ + public static array $testdata = [ 'input' => [ 'gustavo' => [ 'id' => 999, @@ -91,7 +110,7 @@ public function setUp(): void 'environment' => [ 'REQUEST_METHOD' => 'GET', ], - ]) + ]), ); $this->apiClient = ApiClientProvider::getApiClient(); @@ -111,19 +130,23 @@ public function tearDown(): void /** * test 'export'. * - * @covers ::export() - * @covers ::getFileName() * @return void */ public function testExport(): void { - $this->Export = new ExportController( - new ServerRequest([ - 'environment' => ['REQUEST_METHOD' => 'POST'], - 'params' => ['objectType' => 'users'], - 'post' => ['ids' => '888,999', 'objectType' => 'users', 'format' => 'csv'], - ]) - ); + $request = new ServerRequest([ + 'environment' => ['REQUEST_METHOD' => 'POST'], + 'params' => ['objectType' => 'users'], + 'post' => ['ids' => '888,999', 'objectType' => 'users', 'format' => 'csv'], + ]); + $controller = new class ($request) extends ExportController { + public ?BEditaClient $apiClient; + public function initialize(): void + { + parent::initialize(); + $this->loadComponent(ExportComponent::class); + } + }; // mock api getObjects. $apiClient = $this->getMockBuilder(BEditaClient::class) @@ -132,8 +155,8 @@ public function testExport(): void $apiClient->method('get') ->willReturn([ 'data' => [ - 0 => $this->testdata['input']['gustavo'], - 1 => $this->testdata['input']['johndoe'], + 0 => self::$testdata['input']['gustavo'], + 1 => self::$testdata['input']['johndoe'], ], 'meta' => [ 'pagination' => [ @@ -143,10 +166,7 @@ public function testExport(): void ], ]); ApiClientProvider::setApiClient($apiClient); - // set $this->Export->apiClient - $property = new \ReflectionProperty(ExportController::class, 'apiClient'); - $property->setAccessible(true); - $property->setValue($this->Export, $apiClient); + $controller->apiClient = $apiClient; // expected csv. $fields = '"id","name","skills","category","prop"'; @@ -155,7 +175,7 @@ public function testExport(): void $expected = sprintf('%s%s%s%s%s%s', $fields, "\n", $row1, "\n", $row2, "\n"); // call export. - $response = $this->Export->export(); + $response = $controller->export(); $content = $response->getBody()->__toString(); static::assertInstanceOf('Cake\Http\Response', $response); static::assertEquals($expected, $content); @@ -171,18 +191,25 @@ public function testExport(): void * Test `related`. * * @return void - * @covers ::related() - * @covers ::rowsAllRelated() */ public function testRelated(): void { - $this->Export = new ExportController( - new ServerRequest([ - 'environment' => ['REQUEST_METHOD' => 'GET'], - 'params' => ['object_type' => 'users'], - 'get' => ['id' => '888', 'objectType' => 'users', 'format' => 'csv'], - ]) - ); + $request = new ServerRequest([ + 'environment' => ['REQUEST_METHOD' => 'GET'], + 'params' => ['object_type' => 'users'], + 'get' => ['id' => '888', 'objectType' => 'users', 'format' => 'csv'], + ]); + $controller = new class ($request) extends ExportController { + public ExportComponent $Export; + public ?BEditaClient $apiClient; + public function initialize(): void + { + parent::initialize(); + /** @var \App\Controller\Component\ExportComponent $component */ + $component = $this->loadComponent(ExportComponent::class); + $this->Export = $component; + } + }; // mock api getObjects. $apiClient = $this->getMockBuilder(BEditaClient::class) @@ -191,7 +218,7 @@ public function testRelated(): void $apiClient->method('get') ->willReturn([ 'data' => [ - 0 => $this->testdata['input']['gustavo'], + 0 => self::$testdata['input']['gustavo'], ], 'meta' => [ 'pagination' => [ @@ -200,11 +227,7 @@ public function testRelated(): void ], ], ]); - ApiClientProvider::setApiClient($apiClient); - // set $this->Export->apiClient - $property = new \ReflectionProperty(ExportController::class, 'apiClient'); - $property->setAccessible(true); - $property->setValue($this->Export, $apiClient); + $controller->apiClient = $apiClient; // expected csv. $fields = '"id","name","skills","category","prop"'; @@ -213,7 +236,7 @@ public function testRelated(): void // call export. $this->setLimit(500); - $response = $this->Export->related('999', 'seealso', 'csv'); + $response = $controller->related('999', 'seealso', 'csv'); $content = $response->getBody()->__toString(); static::assertInstanceOf('Cake\Http\Response', $response); static::assertEquals($expected, $content); @@ -228,46 +251,62 @@ public function testRelated(): void /** * Test case of export of format not allowed FAIL METHOD * - * @covers ::export() * @return void */ public function testExportFormatNotAllowed(): void { - $this->Export = new ExportController( - new ServerRequest([ - 'environment' => ['REQUEST_METHOD' => 'POST'], - 'params' => ['objectType' => 'proms'], - 'post' => ['ids' => '655', 'objectType' => 'proms', 'format' => ''], - ]) - ); + $request = new ServerRequest([ + 'environment' => ['REQUEST_METHOD' => 'POST'], + 'params' => ['objectType' => 'proms'], + 'post' => ['ids' => '655', 'objectType' => 'proms', 'format' => ''], + ]); + $controller = new class ($request) extends ExportController { + public ExportComponent $Export; + public ?BEditaClient $apiClient; + public function initialize(): void + { + parent::initialize(); + /** @var \App\Controller\Component\ExportComponent $component */ + $component = $this->loadComponent(ExportComponent::class); + $this->Export = $component; + } + }; // call export. - $response = $this->Export->export(); + $response = $controller->export(); static::assertEquals(302, $response->getStatusCode()); - $flash = (array)$this->Export->getRequest()->getSession()->read('Flash.flash'); + $flash = (array)$controller->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('Format choosen is not available', Hash::get($flash, '0.message')); } /** * Test case of related of format not allowed FAIL METHOD * - * @covers ::related() * @return void */ public function testRelatedFormatNotAllowed(): void { - $this->Export = new ExportController( - new ServerRequest([ - 'environment' => ['REQUEST_METHOD' => 'GET'], - 'params' => ['objectType' => 'proms'], - 'get' => ['id' => '655', 'relation' => 'dummy', 'format' => 'abcde'], - ]) - ); + $request = new ServerRequest([ + 'environment' => ['REQUEST_METHOD' => 'GET'], + 'params' => ['objectType' => 'proms'], + 'get' => ['id' => '655', 'relation' => 'dummy', 'format' => 'abcde'], + ]); + $controller = new class ($request) extends ExportController { + public ExportComponent $Export; + public ?BEditaClient $apiClient; + public function initialize(): void + { + parent::initialize(); + /** @var \App\Controller\Component\ExportComponent $component */ + $component = $this->loadComponent(ExportComponent::class); + $this->Export = $component; + } + }; // call export. - $response = $this->Export->related('655', 'proms', ''); + $response = $controller->related('655', 'proms', ''); static::assertEquals(302, $response->getStatusCode()); - $flash = (array)$this->Export->getRequest()->getSession()->read('Flash.flash'); + $flash = (array)$controller->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('Format choosen is not available', Hash::get($flash, '0.message')); } @@ -276,22 +315,22 @@ public function testRelatedFormatNotAllowed(): void * * @return array */ - public function rowsProvider(): array + public static function rowsProvider(): array { return [ 'documents, all' => [ [ ['id', 'name', 'skills', 'category', 'prop'], - $this->testdata['expected']['gustavo'], - $this->testdata['expected']['johndoe'], + ExportControllerTest::$testdata['expected']['gustavo'], + ExportControllerTest::$testdata['expected']['johndoe'], ], [ 'documents', ], [ 'data' => [ - $this->testdata['input']['gustavo'], - $this->testdata['input']['johndoe'], + ExportControllerTest::$testdata['input']['gustavo'], + ExportControllerTest::$testdata['input']['johndoe'], ], 'meta' => [ 'pagination' => [ @@ -304,7 +343,7 @@ public function rowsProvider(): array 'documents with ids' => [ [ ['id', 'name', 'skills', 'category', 'prop'], - $this->testdata['expected']['gustavo'], + ExportControllerTest::$testdata['expected']['gustavo'], ], [ 'documents', @@ -312,7 +351,7 @@ public function rowsProvider(): array ], [ 'data' => [ - $this->testdata['input']['gustavo'], + ExportControllerTest::$testdata['input']['gustavo'], ], 'meta' => [ 'pagination' => [ @@ -325,14 +364,14 @@ public function rowsProvider(): array 'query' => [ [ ['id', 'name', 'skills', 'category', 'prop'], - $this->testdata['expected']['gustavo'], + ExportControllerTest::$testdata['expected']['gustavo'], ], [ 'documents', ], [ 'data' => [ - $this->testdata['input']['gustavo'], + ExportControllerTest::$testdata['input']['gustavo'], ], 'meta' => [ 'pagination' => [ @@ -357,12 +396,8 @@ public function rowsProvider(): array * @param array $response API response. * @param array $post Post data. * @return void - * @covers ::rows() - * @covers ::rowsAll() - * @covers ::apiPath() - * @covers ::prepareQuery() - * @dataProvider rowsProvider() */ + #[DataProvider('rowsProvider')] public function testRows(array $expected, array $arguments, array $response, array $post = []): void { $this->setLimit(500); @@ -381,16 +416,16 @@ public function testRows(array $expected, array $arguments, array $response, arr 'environment' => [ 'REQUEST_METHOD' => 'GET', ], - ]) + ]), ); } // set $this->Export->apiClient - $property = new \ReflectionProperty(ExportController::class, 'apiClient'); + $property = new ReflectionProperty(ExportController::class, 'apiClient'); $property->setAccessible(true); $property->setValue($this->Export, $apiClient); - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('rows'); $method->setAccessible(true); @@ -403,7 +438,7 @@ public function testRows(array $expected, array $arguments, array $response, arr * * @return array */ - public function fillDataFromResponseProvider(): array + public static function fillDataFromResponseProvider(): array { return [ 'empty data' => [ @@ -420,14 +455,14 @@ public function fillDataFromResponseProvider(): array 'fields' => ['id', 'name', 'skills', 'category', 'prop'], 'response' => [ 'data' => [ - 0 => $this->testdata['input']['gustavo'], - 1 => $this->testdata['input']['johndoe'], + 0 => ExportControllerTest::$testdata['input']['gustavo'], + 1 => ExportControllerTest::$testdata['input']['johndoe'], ], ], ], // input [ - 0 => $this->testdata['expected']['gustavo'], - 1 => $this->testdata['expected']['johndoe'], + 0 => ExportControllerTest::$testdata['expected']['gustavo'], + 1 => ExportControllerTest::$testdata['expected']['johndoe'], ], // expected ], ]; @@ -439,12 +474,11 @@ public function fillDataFromResponseProvider(): array * @param string|array $input The input for the function. * @param string|array $expected The expected value. * @return void - * @covers ::fillDataFromResponse() - * @dataProvider fillDataFromResponseProvider() */ + #[DataProvider('fillDataFromResponseProvider')] public function testFillDataFromResponse($input, $expected): void { - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('fillDataFromResponse'); $method->setAccessible(true); $data = []; @@ -459,13 +493,13 @@ public function testFillDataFromResponse($input, $expected): void * * @return array */ - public function getFieldNamesProvider(): array + public static function getFieldNamesProvider(): array { return [ 'full data, default key' => [ [ 'data' => [ - 0 => $this->testdata['input']['gustavo'], + 0 => ExportControllerTest::$testdata['input']['gustavo'], ], ], // input [ @@ -502,12 +536,11 @@ public function getFieldNamesProvider(): array * @param string|array $response The response. * @param string|array $expected The expected value. * @return void - * @covers ::getFieldNames() - * @dataProvider getFieldNamesProvider() */ + #[DataProvider('getFieldNamesProvider')] public function testGetFields($response, $expected): void { - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('getFieldNames'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Export, [$response]); @@ -519,7 +552,7 @@ public function testGetFields($response, $expected): void * * @return array */ - public function rowFieldsProvider(): array + public static function rowFieldsProvider(): array { return [ 'empty data' => [ @@ -541,7 +574,7 @@ public function rowFieldsProvider(): array ], 'full data' => [ [ - 'data' => $this->testdata['input']['gustavo'], + 'data' => ExportControllerTest::$testdata['input']['gustavo'], 'fields' => [ 'id', 'name', @@ -567,12 +600,11 @@ public function rowFieldsProvider(): array * @param string|array $input The input for the function. * @param string|array $expected The expected value. * @return void - * @covers ::rowFields() - * @dataProvider rowFieldsProvider() */ + #[DataProvider('rowFieldsProvider')] public function testRowFields($input, $expected): void { - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('rowFields'); $method->setAccessible(true); $data = $input['data']; @@ -586,7 +618,7 @@ public function testRowFields($input, $expected): void * * @return array */ - public function getValueProvider(): array + public static function getValueProvider(): array { return [ 'value array' => [ @@ -606,12 +638,11 @@ public function getValueProvider(): array * @param string|array $input The input for the function. * @param string|array $expected The expected value. * @return void - * @covers ::getValue() - * @dataProvider getValueProvider() */ + #[DataProvider('getValueProvider')] public function testGetValue($input, $expected): void { - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('getValue'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Export, [ $input ]); @@ -627,7 +658,7 @@ public function testLimit(): void { $expected = 123; $this->setLimit($expected); - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('limit'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Export, []); @@ -638,17 +669,26 @@ public function testLimit(): void * Test `relatedFiltered` method. * * @return void - * @covers ::relatedFiltered() */ public function testRelatedFiltered(): void { - $this->Export = new ExportController( - new ServerRequest([ - 'environment' => ['REQUEST_METHOD' => 'GET'], - 'params' => ['object_type' => 'users'], - 'get' => ['id' => '888', 'object_type' => 'users', 'format' => 'csv'], - ]) - ); + $request = new ServerRequest([ + 'environment' => ['REQUEST_METHOD' => 'GET'], + 'params' => ['object_type' => 'users'], + 'get' => ['id' => '888', 'object_type' => 'users', 'format' => 'csv'], + ]); + + $controller = new class ($request) extends ExportController { + public ExportComponent $Export; + public ?BEditaClient $apiClient; + public function initialize(): void + { + parent::initialize(); + /** @var \App\Controller\Component\ExportComponent $component */ + $component = $this->loadComponent(ExportComponent::class); + $this->Export = $component; + } + }; // mock api getObjects. $apiClient = $this->getMockBuilder(BEditaClient::class) ->setConstructorArgs(['https://api.example.org']) @@ -656,7 +696,7 @@ public function testRelatedFiltered(): void $apiClient->method('get') ->willReturn([ 'data' => [ - 0 => $this->testdata['input']['gustavo'], + 0 => self::$testdata['input']['gustavo'], ], 'meta' => [ 'pagination' => [ @@ -665,13 +705,9 @@ public function testRelatedFiltered(): void ], ], ]); - ApiClientProvider::setApiClient($apiClient); - // set $this->Export->apiClient - $property = new \ReflectionProperty(ExportController::class, 'apiClient'); - $property->setAccessible(true); - $property->setValue($this->Export, $apiClient); - $this->Export->relatedFiltered('888', 'seealso', 'csv', 'q=test&filter[type]=documents'); - static::assertEquals(['q' => 'test', 'filter' => ['type' => 'documents']], $this->Export->filter); + $controller->apiClient = $apiClient; + $controller->relatedFiltered('888', 'seealso', 'csv', 'q=test&filter[type]=documents'); + static::assertEquals(['q' => 'test', 'filter' => ['type' => 'documents']], $controller->filter); } /** @@ -690,7 +726,7 @@ private function setLimit(int $limit): void * * @return array */ - public function getRelatedFileNameProvider(): array + public static function getRelatedFileNameProvider(): array { return [ 'empty filter' => [ @@ -727,13 +763,12 @@ public function getRelatedFileNameProvider(): array * @param string $expectedPrefix The expected prefix. * @param string $expectedExtension The expected extension. * @return void - * @dataProvider getRelatedFileNameProvider() - * @covers ::getRelatedFileName() */ + #[DataProvider('getRelatedFileNameProvider')] public function testGetRelatedFileName(array $filter, string $id, string $type, string $relation, string $format, string $expectedPrefix, int $expectedDash, string $expectedExtension): void { $this->Export->filter = $filter; - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('getRelatedFileName'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Export, [$id, $type, $relation, $format]); @@ -748,7 +783,6 @@ public function testGetRelatedFileName(array $filter, string $id, string $type, * Test `prepareQuery` method. * * @return void - * @covers ::prepareQuery() */ public function testPrepareQuery(): void { @@ -763,9 +797,9 @@ public function testPrepareQuery(): void 'q' => 'gustavo', ], 'get' => ['id' => '888', 'objectType' => 'users', 'format' => 'csv'], - ]) + ]), ); - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('prepareQuery'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Export, []); @@ -782,10 +816,10 @@ public function testPrepareQuery(): void 'q' => 'gustavo', ], 'get' => ['id' => '888', 'objectType' => 'users', 'format' => 'csv'], - ]) + ]), ); $this->Export->filter = ['filter' => ['type' => 'documents'], 'q' => 'needle']; - $reflectionClass = new \ReflectionClass($this->Export); + $reflectionClass = new ReflectionClass($this->Export); $method = $reflectionClass->getMethod('prepareQuery'); $method->setAccessible(true); $actual = $method->invokeArgs($this->Export, []); diff --git a/tests/TestCase/Controller/HistoryControllerTest.php b/tests/TestCase/Controller/HistoryControllerTest.php index 2f6d40b39..597ef4075 100644 --- a/tests/TestCase/Controller/HistoryControllerTest.php +++ b/tests/TestCase/Controller/HistoryControllerTest.php @@ -1,40 +1,43 @@ loadRoutes(); - $this->HistoryController = new HistoryController( - new ServerRequest([ - 'environment' => [ - 'REQUEST_METHOD' => 'GET', - ], - 'params' => [ - 'object_type' => 'documents', - ], - ]) - ); $user = getenv('BEDITA_ADMIN_USR'); $pass = getenv('BEDITA_ADMIN_PWD'); $this->ApiClient = ApiClientProvider::getApiClient(); @@ -69,7 +62,6 @@ public function setUp(): void */ public function tearDown(): void { - unset($this->HistoryController); unset($this->ApiClient); unset($this->documentId); parent::tearDown(); @@ -80,12 +72,11 @@ public function tearDown(): void * * @return array */ - public function cloneProvider(): array + public static function cloneProvider(): array { return [ 'test document history 1' => [ [ - 'id' => $this->documentId, 'historyId' => 1, ], ], @@ -96,33 +87,64 @@ public function cloneProvider(): array * Test `info` method * * @return void - * @covers ::info() */ public function testInfo(): void { - $this->HistoryController->info($this->documentId, 1); + $request = new ServerRequest([ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'params' => [ + 'object_type' => 'documents', + ], + ]); + $controller = new class ($request) extends HistoryController { + public HistoryComponent $History; + public function __construct(ServerRequest $request) + { + $this->History = new HistoryComponent(new ComponentRegistry($this)); + parent::__construct($request); + } + }; + $controller->info($this->documentId, 1); $vars = ['data', 'meta']; foreach ($vars as $var) { - static::assertNotEmpty($this->HistoryController->viewBuilder()->getVar($var)); + static::assertNotEmpty($controller->viewBuilder()->getVar($var)); } } /** * Test `clone` method * - * @covers ::clone() - * @dataProvider cloneProvider() * @param array $data The data for test * @return void */ + #[DataProvider('cloneProvider')] public function testClone(array $data): void { + $data['id'] = $this->documentId; /** @var string $id */ $id = (string)$data['id']; /** @var string $historyId */ $historyId = (string)$data['historyId']; - $response = $this->HistoryController->clone($id, $historyId); + $request = new ServerRequest([ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'params' => [ + 'object_type' => 'documents', + ], + ]); + $controller = new class ($request) extends HistoryController { + public HistoryComponent $History; + public function __construct(ServerRequest $request) + { + $this->History = new HistoryComponent(new ComponentRegistry($this)); + parent::__construct($request); + } + }; + $response = $controller->clone($id, $historyId); static::assertEquals(302, $response->getStatusCode()); } @@ -131,12 +153,11 @@ public function testClone(array $data): void * * @return array */ - public function restoreProvider(): array + public static function restoreProvider(): array { return [ 'test document history 1' => [ [ - 'id' => $this->documentId, 'historyId' => 1, ], ], @@ -146,19 +167,34 @@ public function restoreProvider(): array /** * Test `restore` method * - * @covers ::restore() - * @dataProvider restoreProvider() * @param array $data The data for test * @return void */ + #[DataProvider('restoreProvider')] public function testRestore(array $data): void { + $data['id'] = $this->documentId; /** @var string $id */ $id = (string)$data['id']; /** @var string $historyId */ $historyId = (string)$data['historyId']; - - $response = $this->HistoryController->restore($id, $historyId); + $request = new ServerRequest([ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'params' => [ + 'object_type' => 'documents', + ], + ]); + $controller = new class ($request) extends HistoryController { + public HistoryComponent $History; + public function __construct(ServerRequest $request) + { + $this->History = new HistoryComponent(new ComponentRegistry($this)); + parent::__construct($request); + } + }; + $response = $controller->restore($id, $historyId); static::assertEquals(302, $response->getStatusCode()); } @@ -167,12 +203,11 @@ public function testRestore(array $data): void * * @return array */ - public function setHistoryProvider(): array + public static function setHistoryProvider(): array { return [ 'document keepUname false' => [ [ - 'id' => $this->documentId, 'historyId' => 1, 'keepUname' => false, ], @@ -180,7 +215,6 @@ public function setHistoryProvider(): array ], 'document keepUname true' => [ [ - 'id' => $this->documentId, 'historyId' => 1, 'keepUname' => true, ], @@ -192,14 +226,14 @@ public function setHistoryProvider(): array /** * Test `setHistory` method * - * @covers ::setHistory() - * @dataProvider setHistoryProvider() * @param array $data * @param string $expected * @return void */ + #[DataProvider('setHistoryProvider')] public function testSetHistory(array $data, string $expected): void { + $data['id'] = $this->documentId; /** @var string $id */ $id = (string)$data['id']; /** @var string $historyId */ @@ -207,10 +241,33 @@ public function testSetHistory(array $data, string $expected): void /** @var bool $keepUname */ $keepUname = (bool)$data['keepUname']; - // call protected method using AppControllerTest->invokeMethod - $test = new AppControllerTest(); - $test->invokeMethod($this->HistoryController, 'setHistory', [$id, $historyId, $keepUname]); - $actual = $this->HistoryController->getRequest()->getSession()->read(sprintf('history.%s.attributes', $id)); + $request = new ServerRequest([ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'params' => [ + 'object_type' => 'documents', + ], + ]); + $controller = new class ($request) extends HistoryController { + public HistoryComponent $History; + + public function __construct(ServerRequest $request) + { + $this->History = new HistoryComponent(new ComponentRegistry($this)); + parent::__construct($request); + } + + public function setHistory(string|int $id, string|int $historyId, bool $keepUname): void + { + parent::setHistory($id, $historyId, $keepUname); + } + }; + $controller->setHistory($id, $historyId, $keepUname); + $actual = $controller->getRequest()->getSession()->read(sprintf('history.%s.attributes', $id)); + $actual = json_decode($actual, true); + $expected = json_decode($expected, true); + $expected['uname'] = $keepUname ? $actual['uname'] : ''; static::assertEquals($actual, $expected); } @@ -218,16 +275,32 @@ public function testSetHistory(array $data, string $expected): void * Test `get` method * * @return void - * @covers ::get() */ public function testGet(): void { - $this->HistoryController->get(); + $request = new ServerRequest([ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'params' => [ + 'object_type' => 'documents', + ], + ]); + $controller = new class ($request) extends HistoryController { + public HistoryComponent $History; + + public function __construct(ServerRequest $request) + { + $this->History = new HistoryComponent(new ComponentRegistry($this)); + parent::__construct($request); + } + }; + $controller->get(); $vars = ['data', 'meta']; foreach ($vars as $var) { - static::assertNotEmpty($this->HistoryController->viewBuilder()->getVar($var)); + static::assertNotEmpty($controller->viewBuilder()->getVar($var)); } - $actual = $this->HistoryController->viewBuilder()->getVar('data')[0]; + $actual = $controller->viewBuilder()->getVar('data')[0]; $vars = [ 'id', 'type', @@ -257,16 +330,31 @@ public function testGet(): void * Test `objects` method * * @return void - * @covers ::objects() */ public function testObjects(): void { - $this->HistoryController->objects(); + $request = new ServerRequest([ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'params' => [ + 'object_type' => 'documents', + ], + ]); + $controller = new class ($request) extends HistoryController { + public HistoryComponent $History; + public function __construct(ServerRequest $request) + { + $this->History = new HistoryComponent(new ComponentRegistry($this)); + parent::__construct($request); + } + }; + $controller->objects(); $vars = ['data', 'meta']; foreach ($vars as $var) { - static::assertNotEmpty($this->HistoryController->viewBuilder()->getVar($var)); + static::assertNotEmpty($controller->viewBuilder()->getVar($var)); } - $actual = $this->HistoryController->viewBuilder()->getVar('data'); + $actual = $controller->viewBuilder()->getVar('data'); foreach ($actual as $item) { static::assertArrayHasKey('id', $item); static::assertArrayHasKey('type', $item); @@ -277,7 +365,7 @@ public function testObjects(): void static::assertArrayNotHasKey('links', $item); static::assertArrayNotHasKey('relationships', $item); } - $actual = $this->HistoryController->viewBuilder()->getVar('meta'); + $actual = $controller->viewBuilder()->getVar('meta'); static::assertArrayHasKey('pagination', $actual); static::assertArrayNotHasKey('schema', $actual); } diff --git a/tests/TestCase/Controller/ImportControllerTest.php b/tests/TestCase/Controller/ImportControllerTest.php index ee01300ff..ca8409097 100644 --- a/tests/TestCase/Controller/ImportControllerTest.php +++ b/tests/TestCase/Controller/ImportControllerTest.php @@ -15,49 +15,60 @@ use App\Controller\ImportController; use App\Core\Result\ImportResult; -use Authentication\AuthenticationService; -use Authentication\Identifier\IdentifierInterface; +use Authentication\AuthenticationServiceInterface; use Authentication\Identity; +use Authentication\IdentityInterface; use BEdita\SDK\BEditaClient; use BEdita\SDK\BEditaClientException; use BEdita\WebTools\ApiClientProvider; -use BEdita\WebTools\Identifier\ApiIdentifier; use Cake\Core\Configure; use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; use Laminas\Diactoros\UploadedFile; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use ReflectionClass; /** * {@see \App\Controller\ImportController} Test Case - * - * @coversDefaultClass \App\Controller\ImportController */ +#[CoversClass(ImportController::class)] +#[CoversMethod(ImportController::class, 'beforeRender')] +#[CoversMethod(ImportController::class, 'file')] +#[CoversMethod(ImportController::class, 'index')] +#[CoversMethod(ImportController::class, 'jobs')] +#[CoversMethod(ImportController::class, 'loadAsyncJobs')] +#[CoversMethod(ImportController::class, 'loadFilters')] +#[CoversMethod(ImportController::class, 'uploadErrorMessage')] +#[CoversMethod(ImportController::class, 'updateServiceList')] class ImportControllerTest extends TestCase { - public $Import; + public ServerRequest $request; /** * Test file name * * @var string */ - protected $filename = 'test.png'; + protected string $filename = 'test.png'; /** * Test file error * * @var int */ - protected $fileError = 0; + protected int $fileError = 0; /** * The original API client (not mocked). * - * @var \BEdita\SDK\BEditaClient + * @var \BEdita\SDK\BEditaClient|null */ - protected $apiClient = null; + protected ?BEditaClient $apiClient = null; /** * @inheritDoc @@ -96,30 +107,27 @@ public function setupController(?string $filter = null): void 'filter' => $filter, ], ]; - $request = new ServerRequest($config); - $this->Import = new class ($request) extends ImportController - { - public function render($view = null, $layout = null): Response - { - return $this->getResponse(); - } - }; + $this->request = new ServerRequest($config); } /** * Test `file` method * - * @covers ::file() - * @covers ::loadFilters() * @return void */ public function testFile(): void { $this->setupController('App\Test\Utils\ImportFilterSample'); - - $response = $this->Import->file(); + $import = new class ($this->request) extends ImportController + { + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $response = $import->file(); static::assertEquals(302, $response->getStatusCode()); - $result = $this->Import->getRequest()->getSession()->read('Import.result'); + $result = $import->getRequest()->getSession()->read('Import.result'); $expected = new ImportResult($this->filename, 10, 0, 0, 'ok', '', ''); // ($created, $updated, $errors, $info, $warn, $error) static::assertEquals($result, $expected); } @@ -128,7 +136,6 @@ public function testFile(): void * Test `loadFilters` * * @return void - * @covers ::loadFilters() */ public function testLoadFilters(): void { @@ -142,11 +149,18 @@ public function testLoadFilters(): void ]; Configure::write('Filters.import', $filters); $this->setupController('App\Test\Utils\ImportFilterSample'); - $reflectionClass = new \ReflectionClass($this->Import); + $import = new class ($this->request) extends ImportController + { + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $reflectionClass = new ReflectionClass($import); $method = $reflectionClass->getMethod('loadFilters'); $method->setAccessible(true); - $method->invokeArgs($this->Import, []); - static::assertTrue(is_array($this->Import->viewBuilder()->getVar('filters'))); + $method->invokeArgs($import, []); + static::assertTrue(is_array($import->viewBuilder()->getVar('filters'))); $expected = [ [ 'accept' => ['text/xml', 'text/csv'], @@ -156,9 +170,9 @@ public function testLoadFilters(): void 'options' => [], ], ]; - static::assertEquals($expected, $this->Import->viewBuilder()->getVar('filters')); - static::assertTrue(is_array($this->Import->viewBuilder()->getVar('services'))); - static::assertSame(['ImportFilterSampleService'], $this->Import->viewBuilder()->getVar('services')); + static::assertEquals($expected, $import->viewBuilder()->getVar('filters')); + static::assertTrue(is_array($import->viewBuilder()->getVar('services'))); + static::assertSame(['ImportFilterSampleService'], $import->viewBuilder()->getVar('services')); Configure::write('Filters.import', []); } @@ -166,18 +180,24 @@ public function testLoadFilters(): void * Test `updateServiceList` * * @return void - * @covers ::updateServiceList() */ public function testUpdateServiceList(): void { $this->setupController('App\Test\Utils\ImportFilterSample'); - $reflectionClass = new \ReflectionClass($this->Import); + $import = new class ($this->request) extends ImportController + { + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $reflectionClass = new ReflectionClass($import); $method = $reflectionClass->getMethod('updateServiceList'); $method->setAccessible(true); - $method->invokeArgs($this->Import, ['App\Test\Utils\ImportFilterSample']); + $method->invokeArgs($import, ['App\Test\Utils\ImportFilterSample']); $property = $reflectionClass->getProperty('services'); $property->setAccessible(true); - $actual = $property->getValue($this->Import); + $actual = $property->getValue($import); $expected = ['ImportFilterSampleService']; static::assertEquals($expected, $actual); } @@ -186,36 +206,43 @@ public function testUpdateServiceList(): void * Test `loadAsyncJobs` * * @return void - * @covers ::loadAsyncJobs() */ public function testLoadAsyncJobs(): void { // empty jobs $this->setupController('App\Test\Utils\ImportFilterSample'); - $reflectionClass = new \ReflectionClass($this->Import); + $import = new class ($this->request) extends ImportController + { + public ?BEditaClient $apiClient; + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $reflectionClass = new ReflectionClass($import); $method = $reflectionClass->getMethod('loadAsyncJobs'); $method->setAccessible(true); - $method->invokeArgs($this->Import, []); - $actual = $this->Import->viewBuilder()->getVar('jobs'); + $method->invokeArgs($import, []); + $actual = $import->viewBuilder()->getVar('jobs'); $expected = []; static::assertEquals($expected, $actual); // api call with exception $property = $reflectionClass->getProperty('services'); $property->setAccessible(true); - $property->setValue($this->Import, ['dummy']); + $property->setValue($import, ['dummy']); $apiClient = $this->getMockBuilder(BEditaClient::class) ->setConstructorArgs(['https://media.example.com']) ->getMock(); $apiClient->method('get') ->with('/async_jobs') ->willThrowException(new BEditaClientException('My test exception')); - $this->Import->apiClient = $apiClient; - $method->invokeArgs($this->Import, []); - $actual = $this->Import->viewBuilder()->getVar('jobs'); + $import->apiClient = $apiClient; + $method->invokeArgs($import, []); + $actual = $import->viewBuilder()->getVar('jobs'); $expected = []; static::assertEquals($expected, $actual); - $flash = $this->Import->getRequest()->getSession()->read('Flash.flash'); + $flash = $import->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('My test exception', Hash::get($flash, '0.message')); // mock api get /async_jobs @@ -226,24 +253,31 @@ public function testLoadAsyncJobs(): void $apiClient->method('get') ->with('/async_jobs') ->willReturn(['data' => $expected]); - $this->Import->apiClient = $apiClient; - $method->invokeArgs($this->Import, []); - $actual = $this->Import->viewBuilder()->getVar('jobs'); + $import->apiClient = $apiClient; + $method->invokeArgs($import, []); + $actual = $import->viewBuilder()->getVar('jobs'); static::assertEquals($expected, $actual); } /** * Test `file` fail method, missing filter * - * @covers ::file() * @return void */ public function testFileBadRequestFilter(): void { $this->setupController(); - $response = $this->Import->file(); + $import = new class ($this->request) extends ImportController + { + public ?BEditaClient $apiClient; + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $response = $import->file(); static::assertEquals(302, $response->getStatusCode()); - $flash = $this->Import->getRequest()->getSession()->read('Flash.flash'); + $flash = $import->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('Import filter not selected', Hash::get($flash, '0.message')); static::assertEquals(400, Hash::get($flash, '0.params.status')); } @@ -251,18 +285,24 @@ public function testFileBadRequestFilter(): void /** * Test `file` fail method, missing files * - * @covers ::file() - * @covers:: uploadErrorMessage() * @return void */ public function testFileBadRequestFile(): void { $this->fileError = 4; $this->setupController('App\Test\Utils\ImportFilterSample'); + $import = new class ($this->request) extends ImportController + { + public ?BEditaClient $apiClient; + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; - $response = $this->Import->file(); + $response = $import->file(); static::assertEquals(302, $response->getStatusCode()); - $flash = $this->Import->getRequest()->getSession()->read('Flash.flash'); + $flash = $import->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('Missing import file', Hash::get($flash, '0.message')); static::assertEquals(400, Hash::get($flash, '0.params.status')); } @@ -270,13 +310,20 @@ public function testFileBadRequestFile(): void /** * Test `uploadErrorMessage`. * - * @covers:: uploadErrorMessage() * @return void */ public function testUploadErrorMessage(): void { $this->setupController(); - $reflectionClass = new \ReflectionClass($this->Import); + $import = new class ($this->request) extends ImportController + { + public ?BEditaClient $apiClient; + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $reflectionClass = new ReflectionClass($import); $method = $reflectionClass->getMethod('uploadErrorMessage'); $method->setAccessible(true); $errors = [ @@ -289,26 +336,33 @@ public function testUploadErrorMessage(): void UPLOAD_ERR_EXTENSION => __('An extension stopped the file upload'), ]; foreach ($errors as $code => $expected) { - $actual = $method->invokeArgs($this->Import, [$code]); + $actual = $method->invokeArgs($import, [$code]); static::assertEquals($expected, $actual); } $expected = __('Unknown upload error'); - $actual = $method->invokeArgs($this->Import, [123456789]); + $actual = $method->invokeArgs($import, [123456789]); static::assertEquals($expected, $actual); } /** * Test `file` fail method, internal error * - * @covers ::file() * @return void */ public function testFileError(): void { $this->setupController('App\Test\Utils\ImportFilterSampleError'); - $response = $this->Import->file(); + $import = new class ($this->request) extends ImportController + { + public ?BEditaClient $apiClient; + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $response = $import->file(); static::assertEquals(302, $response->getStatusCode()); - $flash = $this->Import->getRequest()->getSession()->read('Flash.flash'); + $flash = $import->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('An expected exception', Hash::get($flash, '0.message')); static::assertEquals(500, Hash::get($flash, '0.params.status')); } @@ -317,85 +371,82 @@ public function testFileError(): void * Test `index` * * @return void - * @covers ::index() - * @covers ::beforeRender() */ public function testIndex(): void { - $this->setupControllerAndLogin(); - $this->Import->index(); - static::assertEmpty($this->Import->viewBuilder()->getVar('jobs')); - static::assertEmpty($this->Import->viewBuilder()->getVar('services')); - static::assertEmpty($this->Import->viewBuilder()->getVar('filters')); - static::assertEmpty($this->Import->viewBuilder()->getVar('result')); - static::assertArrayHasKey('jobsAllow', $this->Import->viewBuilder()->getVars()); - $this->Import->dispatchEvent('Controller.beforeRender'); - static::assertEquals(['_name' => 'import:index'], $this->Import->viewBuilder()->getVar('moduleLink')); + $this->setupController(); + $import = new class ($this->request) extends ImportController + { + public ?BEditaClient $apiClient; + public function render($template = null, $layout = null): Response + { + return $this->getResponse(); + } + }; + $user = new Identity([ + 'id' => 1, + 'username' => 'dummy', + 'roles' => ['readers'], + ]); + $import->setRequest($import->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); + $import->Authentication->setIdentity($user); + $import->index(); + static::assertEmpty($import->viewBuilder()->getVar('jobs')); + static::assertEmpty($import->viewBuilder()->getVar('services')); + static::assertEmpty($import->viewBuilder()->getVar('filters')); + static::assertEmpty($import->viewBuilder()->getVar('result')); + static::assertArrayHasKey('jobsAllow', $import->viewBuilder()->getVars()); + $import->dispatchEvent('Controller.beforeRender'); + static::assertEquals(['_name' => 'import:index'], $import->viewBuilder()->getVar('moduleLink')); } /** * Test `jobs` * * @return void - * @covers ::jobs() */ public function testJobs(): void { $this->setupController(); - $this->Import->jobs(); - static::assertNotEmpty($this->Import->viewBuilder()->getOption('serialize')); - static::assertEmpty($this->Import->viewBuilder()->getVar('jobs')); - static::assertEmpty($this->Import->viewBuilder()->getVar('services')); - static::assertEmpty($this->Import->viewBuilder()->getVar('filters')); - } - - /** - * Setup controller and manually login user - * - * @return array|null - */ - protected function setupControllerAndLogin(): ?array - { - $filename = sprintf('%s/tests/files/%s', getcwd(), $this->filename); - $file = new UploadedFile($filename, filesize($filename), $this->fileError, $this->filename); - $config = [ - 'environment' => [ - 'REQUEST_METHOD' => 'GET', - ], - 'post' => [ - 'username' => env('BEDITA_ADMIN_USR'), - 'password' => env('BEDITA_ADMIN_PWD'), - 'file' => $file, - 'filter' => 'App\Test\Utils\ImportFilterSample', - ], - ]; - $request = new ServerRequest($config); - $this->Import = new class ($request) extends ImportController + $import = new class ($this->request) extends ImportController { - public function render($view = null, $layout = null): Response + public ?BEditaClient $apiClient; + public function render($template = null, $layout = null): Response { return $this->getResponse(); } }; + $import->jobs(); + static::assertNotEmpty($import->viewBuilder()->getOption('serialize')); + static::assertEmpty($import->viewBuilder()->getVar('jobs')); + static::assertEmpty($import->viewBuilder()->getVar('services')); + static::assertEmpty($import->viewBuilder()->getVar('filters')); + } - // Mock Authentication component - ApiClientProvider::getApiClient()->setupTokens([]); // reset client - $service = new AuthenticationService(); - $service->loadIdentifier(ApiIdentifier::class); - $service->loadAuthenticator('Authentication.Form', [ - 'fields' => [ - IdentifierInterface::CREDENTIAL_USERNAME => 'username', - IdentifierInterface::CREDENTIAL_PASSWORD => 'password', - ], - ]); - $this->Import->setRequest($this->Import->getRequest()->withAttribute('authentication', $service)); - $result = $this->Import->Authentication->getAuthenticationService()->authenticate($this->Import->getRequest()); - $identity = new Identity($result->getData()); - $request = $this->Import->getRequest()->withAttribute('identity', $identity); - $this->Import->setRequest($request); - $user = $this->Import->Authentication->getIdentity() ?: new Identity([]); - $this->Import->Authentication->setIdentity($user); + /** + * Get mocked AuthenticationService. + * + * @return AuthenticationServiceInterface + */ + protected function getAuthenticationServiceMock(): AuthenticationServiceInterface + { + $authenticationService = $this->getMockBuilder(AuthenticationServiceInterface::class) + ->getMock(); + $authenticationService->method('clearIdentity') + ->willReturnCallback(function (ServerRequestInterface $request, ResponseInterface $response): array { + return [ + 'request' => $request->withoutAttribute('identity'), + 'response' => $response, + ]; + }); + $authenticationService->method('persistIdentity') + ->willReturnCallback(function (ServerRequestInterface $request, ResponseInterface $response, IdentityInterface $identity): array { + return [ + 'request' => $request->withAttribute('identity', $identity), + 'response' => $response, + ]; + }); - return $user->getOriginalData(); + return $authenticationService; } } diff --git a/tests/TestCase/Controller/LockControllerTest.php b/tests/TestCase/Controller/LockControllerTest.php index 010fbeb63..08b47b2fb 100644 --- a/tests/TestCase/Controller/LockControllerTest.php +++ b/tests/TestCase/Controller/LockControllerTest.php @@ -2,17 +2,22 @@ namespace App\Test\TestCase\Controller; use App\Controller\LockController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use ReflectionClass; /** * {@see \App\Controller\LockController} Test Case - * - * @coversDefaultClass \App\Controller\LockController - * @uses \App\Controller\LockController */ +#[CoversClass(LockController::class)] +#[CoversMethod(LockController::class, 'add')] +#[CoversMethod(LockController::class, 'lock')] +#[CoversMethod(LockController::class, 'remove')] class LockControllerTest extends TestCase { /** @@ -20,21 +25,21 @@ class LockControllerTest extends TestCase * * @var \App\Controller\LockController */ - public $LockController; + public LockController $LockController; /** * Client class * - * @var \BEdita\SDK\BEditaClient + * @var \BEdita\SDK\BEditaClient|null */ - private $ApiClient = null; + private ?BEditaClient $ApiClient = null; /** * Document ID * - * @var string + * @var string|null */ - private $documentId = null; + private ?string $documentId = null; /** * @inheritDoc @@ -60,7 +65,7 @@ public function setUp(): void 'object_type' => 'documents', 'id' => $this->documentId, ], - ]) + ]), ); } @@ -77,7 +82,6 @@ public function tearDown(): void * Test `add` method * * @return void - * @covers ::add() */ public function testAdd(): void { @@ -92,7 +96,6 @@ public function testAdd(): void * Test `remove` method * * @return void - * @covers ::remove() */ public function testRemove(): void { @@ -107,11 +110,10 @@ public function testRemove(): void * Test `lock` method * * @return void - * @covers ::lock() */ public function testLock(): void { - $reflectionClass = new \ReflectionClass($this->LockController); + $reflectionClass = new ReflectionClass($this->LockController); $method = $reflectionClass->getMethod('lock'); $method->setAccessible(true); $method->invokeArgs($this->LockController, [true]); @@ -125,7 +127,6 @@ public function testLock(): void * Test `lock` method, on exception * * @return void - * @covers ::lock() */ public function testLockException(): void { @@ -138,9 +139,9 @@ public function testLockException(): void 'object_type' => 'documents', 'id' => 999999999, ], - ]) + ]), ); - $reflectionClass = new \ReflectionClass($this->LockController); + $reflectionClass = new ReflectionClass($this->LockController); $method = $reflectionClass->getMethod('lock'); $method->setAccessible(true); $actual = $method->invokeArgs($this->LockController, [true]); diff --git a/tests/TestCase/Controller/LoginControllerTest.php b/tests/TestCase/Controller/LoginControllerTest.php index 9ad11569f..36cc02f79 100644 --- a/tests/TestCase/Controller/LoginControllerTest.php +++ b/tests/TestCase/Controller/LoginControllerTest.php @@ -17,20 +17,28 @@ use App\Identifier\ApiIdentifier; use Authentication\AuthenticationService; use Authentication\AuthenticationServiceInterface; -use Authentication\Identifier\IdentifierInterface; +use Authentication\Identifier\AbstractIdentifier; use Authentication\Identity; use Authentication\IdentityInterface; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversNothing; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * {@see \App\Controller\LoginController} Test Case - * - * @coversDefaultClass \App\Controller\LoginController - * @uses \App\Controller\LoginController */ +#[CoversClass(LoginController::class)] +#[CoversMethod(LoginController::class, 'authRequest')] +#[CoversMethod(LoginController::class, 'handleFlashMessages')] +#[CoversMethod(LoginController::class, 'initialize')] +#[CoversMethod(LoginController::class, 'loadAvailableProjects')] +#[CoversMethod(LoginController::class, 'login')] +#[CoversMethod(LoginController::class, 'logout')] +#[CoversMethod(LoginController::class, 'setupCurrentProject')] class LoginControllerTest extends TestCase { /** @@ -38,14 +46,14 @@ class LoginControllerTest extends TestCase * * @var \App\Controller\LoginController */ - public $Login; + public LoginController $Login; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'POST', ], @@ -78,11 +86,11 @@ protected function setupController(array $requestConfig): void // Mock Authentication component and prepare for "real" login $service = new AuthenticationService(); - $service->loadIdentifier(ApiIdentifier::class); $service->loadAuthenticator('Authentication.Form', [ + 'identifier' => ApiIdentifier::class, 'fields' => [ - IdentifierInterface::CREDENTIAL_USERNAME => 'username', - IdentifierInterface::CREDENTIAL_PASSWORD => 'password', + AbstractIdentifier::CREDENTIAL_USERNAME => 'username', + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password', ], ]); $this->Login->setRequest($this->Login->getRequest()->withAttribute('authentication', $service)); @@ -121,7 +129,6 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac /** * Test `initialize` method. * - * @covers ::initialize() * @return void */ public function testInitialize(): void @@ -138,8 +145,6 @@ public function testInitialize(): void /** * Test `authRequest` method, no user timezone set * - * @covers ::authRequest() - * @covers ::setupCurrentProject() * @return void */ public function testLogin(): void @@ -159,9 +164,9 @@ public function testLogin(): void /** * Test `login` with HTTP HEAD method * - * @coversNothing * @return void */ + #[CoversNothing()] public function testHeadLogin(): void { $this->setupController([ @@ -177,7 +182,6 @@ public function testHeadLogin(): void /** * Test `login` fail method * - * @covers ::authRequest() * @return void */ public function testLoginFailed(): void @@ -196,7 +200,6 @@ public function testLoginFailed(): void /** * Test `login` method with GET * - * @covers ::login() * @return void */ public function testLoginForm(): void @@ -215,7 +218,6 @@ public function testLoginForm(): void * Test `login` method with POST * * @return void - * @covers ::login() */ public function testLoginPost(): void { @@ -231,7 +233,6 @@ public function testLoginPost(): void /** * Test `loadAvailableProjects` method with GET * - * @covers ::loadAvailableProjects() * @return void */ public function testLoadAvailableProjects(): void @@ -260,7 +261,6 @@ public function testLoadAvailableProjects(): void /** * Test `setupCurrentProject` method * - * @covers ::setupCurrentProject() * @return void */ public function testSetupCurrentProject(): void @@ -281,7 +281,6 @@ public function testSetupCurrentProject(): void /** * Test `logout` method * - * @covers ::logout() * @return void */ public function testLogout(): void @@ -302,7 +301,6 @@ public function testLogout(): void /** * Test `handleFlashMessages` method * - * @covers ::handleFlashMessages() * @return void */ public function testHandleFlashMessages(): void diff --git a/tests/TestCase/Controller/Model/CategoriesControllerTest.php b/tests/TestCase/Controller/Model/CategoriesControllerTest.php index b225a1c61..76cd2bab2 100644 --- a/tests/TestCase/Controller/Model/CategoriesControllerTest.php +++ b/tests/TestCase/Controller/Model/CategoriesControllerTest.php @@ -15,17 +15,21 @@ use App\Controller\Component\SchemaComponent; use App\Controller\Model\CategoriesController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; +use Cake\Controller\ComponentRegistry; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Model\CategoriesController} Test Case - * - * @coversDefaultClass \App\Controller\Model\CategoriesController - * @uses \App\Controller\Model\CategoriesController */ +#[CoversClass(CategoriesController::class)] +#[CoversMethod(CategoriesController::class, 'index')] +#[CoversMethod(CategoriesController::class, 'initialize')] class CategoriesControllerTest extends TestCase { /** @@ -33,21 +37,21 @@ class CategoriesControllerTest extends TestCase * * @var \App\Controller\Model\CategoriesController */ - public $Categories; + public CategoriesController $Categories; /** * Client API * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -59,6 +63,15 @@ class CategoriesControllerTest extends TestCase ], ]; + /** + * @inheritDoc + */ + public function tearDown(): void + { + unset($this->Categories); + parent::tearDown(); + } + /** * Setup api client and auth * @@ -85,42 +98,36 @@ protected function setupController(array $requestConfig = []): void { $config = array_merge($this->defaultRequestConfig, $requestConfig); $request = new ServerRequest($config); - $this->Categories = new CategoriesController($request); + $this->Categories = new class ($request) extends CategoriesController { + public SchemaComponent $Schema; + public function initialize(): void + { + $this->Schema = new class (new ComponentRegistry($this)) extends SchemaComponent { + public function objectTypesFeatures(): array + { + return [ + 'categorized' => [ + 'cats', + 'dogs', + 'horses', + ], + ]; + } + }; + parent::initialize(); + } + }; $this->setupApi(); } - /** - * @inheritDoc - */ - public function tearDown(): void - { - unset($this->Categories); - - parent::tearDown(); - } - /** * Test `index` method * - * @covers ::initialize() - * @covers ::index() * @return void */ public function testIndex(): void { $this->setupController(); - // mock objectTypesFeatures() - // mock schema component - $mockResponse = [ - 'categorized' => [ - 'cats', - 'dogs', - 'horses', - ], - ]; - $this->Categories->Schema = $this->createMock(SchemaComponent::class); - $this->Categories->Schema->method('objectTypesFeatures') - ->willReturn($mockResponse); $beditaApiVersion = (string)Hash::get((array)ApiClientProvider::getApiClient()->get('/home'), 'meta.version'); $this->Categories->viewBuilder()->setVar('project', ['version' => $beditaApiVersion]); $this->Categories->index(); diff --git a/tests/TestCase/Controller/Model/ExportControllerTest.php b/tests/TestCase/Controller/Model/ExportControllerTest.php index 6f5325493..3cf068fc5 100644 --- a/tests/TestCase/Controller/Model/ExportControllerTest.php +++ b/tests/TestCase/Controller/Model/ExportControllerTest.php @@ -19,13 +19,14 @@ use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Model\ExportController} Test Case - * - * @coversDefaultClass \App\Controller\Model\ExportController - * @uses \App\Controller\Model\ExportController */ +#[CoversClass(ExportController::class)] +#[CoversMethod(ExportController::class, 'model')] class ExportControllerTest extends TestCase { /** @@ -33,14 +34,14 @@ class ExportControllerTest extends TestCase * * @var \App\Controller\Model\ExportController */ - public $Export; + public ExportController $Export; /** * Client API * * @var \BEdita\SDK\BEditaClient */ - public $apiClient; + public BEditaClient $apiClient; /** * @inheritDoc @@ -61,7 +62,6 @@ public function tearDown(): void /** * Test `model` method * - * @covers ::model() * @return void */ public function testModel(): void @@ -87,7 +87,7 @@ public function testModel(): void 'environment' => [ 'REQUEST_METHOD' => 'GET', ], - ]) + ]), ); $result = $this->Export->model(); diff --git a/tests/TestCase/Controller/Model/ModelBaseControllerTest.php b/tests/TestCase/Controller/Model/ModelBaseControllerTest.php index c84bd143e..0818d0049 100644 --- a/tests/TestCase/Controller/Model/ModelBaseControllerTest.php +++ b/tests/TestCase/Controller/Model/ModelBaseControllerTest.php @@ -17,29 +17,40 @@ use Authentication\AuthenticationServiceInterface; use Authentication\Identity; use Authentication\IdentityInterface; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\Exception\UnauthorizedException; use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * {@see \App\Controller\Model\ModelBaseController} Test Case - * - * @coversDefaultClass \App\Controller\Model\ModelBaseController */ +#[CoversClass(ModelBaseController::class)] +#[CoversMethod(ModelBaseController::class, 'beforeFilter')] +#[CoversMethod(ModelBaseController::class, 'beforeRender')] +#[CoversMethod(ModelBaseController::class, 'create')] +#[CoversMethod(ModelBaseController::class, 'doSave')] +#[CoversMethod(ModelBaseController::class, 'index')] +#[CoversMethod(ModelBaseController::class, 'indexQuery')] +#[CoversMethod(ModelBaseController::class, 'remove')] +#[CoversMethod(ModelBaseController::class, 'save')] +#[CoversMethod(ModelBaseController::class, 'view')] class ModelBaseControllerTest extends TestCase { - public $ModelController; - /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -53,7 +64,7 @@ class ModelBaseControllerTest extends TestCase * * @var \BEdita\SDK\BEditaClient */ - protected $client; + protected BEditaClient $client; /** * @inheritDoc @@ -63,23 +74,6 @@ public function setUp(): void parent::setUp(); $this->loadRoutes(); - $config = array_merge($this->defaultRequestConfig, []); - $request = new ServerRequest($config); - $this->ModelController = new class ($request) extends ModelBaseController - { - protected $resourceType = 'object_types'; - - public function setResourceType(string $type): void - { - $this->resourceType = $type; - } - - public function setSingleView(bool $view): void - { - $this->singleView = $view; - } - }; - $this->client = ApiClientProvider::getApiClient(); $adminUser = getenv('BEDITA_ADMIN_USR'); $adminPassword = getenv('BEDITA_ADMIN_PWD'); @@ -119,7 +113,7 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac * * @return array */ - public function beforeFilterProvider(): array + public static function beforeFilterProvider(): array { return [ 'not authorized' => [ @@ -153,26 +147,41 @@ public function beforeFilterProvider(): array * * @param \Exception|string|null $expected Expected result * @param array $data setup data for test - * @covers ::beforeFilter() - * @dataProvider beforeFilterProvider() * @return void */ + #[DataProvider('beforeFilterProvider')] public function testBeforeFilter($expected, array $data): void { + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; // Mock Authentication component - $this->ModelController->setRequest($this->ModelController->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); + $controller->setRequest($controller->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); if (isset($data['tokens'])) { $data['tokens'] = $this->client->getTokens(); } - $this->ModelController->Authentication->setIdentity(new Identity($data)); + $controller->Authentication->setIdentity(new Identity($data)); - if ($expected instanceof \Exception) { + if ($expected instanceof Exception) { $this->expectException(get_class($expected)); } - $event = $this->ModelController->dispatchEvent('Controller.beforeFilter'); - $result = $this->ModelController->beforeFilter($event); + $event = $controller->dispatchEvent('Controller.beforeFilter'); + $result = $controller->beforeFilter($event); if (is_string($expected)) { static::assertInstanceOf($expected, $result); @@ -184,72 +193,143 @@ public function testBeforeFilter($expected, array $data): void /** * Test `beforeRender` method * - * @covers ::beforeRender() * @return void */ public function testBeforeRender(): void { - $this->ModelController->dispatchEvent('Controller.beforeRender'); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; - static::assertNotEmpty($this->ModelController->viewBuilder()->getVar('resourceType')); - static::assertNotEmpty($this->ModelController->viewBuilder()->getVar('moduleLink')); + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $controller->dispatchEvent('Controller.beforeRender'); + static::assertNotEmpty($controller->viewBuilder()->getVar('resourceType')); + static::assertNotEmpty($controller->viewBuilder()->getVar('moduleLink')); } /** * Test `index` method * - * @covers ::index() - * @covers ::indexQuery() - * @covers ::initialize() - * @covers ::beforeFilter() * @return void */ public function testIndex(): void { - $this->ModelController->index(); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $controller->index(); $vars = ['resources', 'meta', 'links', 'properties']; foreach ($vars as $var) { - static::assertNotEmpty($this->ModelController->viewBuilder()->getVar($var)); + static::assertNotEmpty($controller->viewBuilder()->getVar($var)); } } /** * Test `index` failure method * - * @covers ::index() * @return void */ public function testIndexFail(): void { - $this->ModelController->setResourceType('elements'); - $result = $this->ModelController->index(); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $controller->setResourceType('elements'); + $result = $controller->index(); static::assertTrue(($result instanceof Response)); } /** * Test `view` method * - * @covers ::view() * @return void */ public function testView(): void { - $this->ModelController->view(1); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $controller->view(1); $vars = ['resource', 'schema', 'properties']; foreach ($vars as $var) { - static::assertNotEmpty($this->ModelController->viewBuilder()->getVar($var)); + static::assertNotEmpty($controller->viewBuilder()->getVar($var)); } } /** * Test `view` failure method * - * @covers ::view() * @return void */ public function testViewFail(): void { - $result = $this->ModelController->view(0); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $result = $controller->view(0); static::assertTrue(($result instanceof Response)); } @@ -258,7 +338,7 @@ public function testViewFail(): void * * @return array */ - public function saveProvider(): array + public static function saveProvider(): array { return [ 'post' => [ @@ -286,18 +366,32 @@ public function saveProvider(): array * @param string $expected Expected result * @param array $data Request data * @param bool $singleView Single view - * @covers ::save() - * @covers ::doSave() - * @dataProvider saveProvider() * @return void */ + #[DataProvider('saveProvider')] public function testSave(string $expected, array $data, bool $singleView): void { - $this->ModelController->setSingleView($singleView); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $controller->setSingleView($singleView); foreach ($data as $name => $value) { - $this->ModelController->setRequest($this->ModelController->getRequest()->withData($name, $value)); + $controller->setRequest($controller->getRequest()->withData($name, $value)); } - $result = $this->ModelController->save(); + $result = $controller->save(); static::assertInstanceOf(Response::class, $result); $location = $result->getHeaderLine('Location'); @@ -307,8 +401,6 @@ public function testSave(string $expected, array $data, bool $singleView): void /** * Test `save` failure method * - * @covers ::save() - * @covers ::doSave() * @return void */ public function testSaveFail(): void @@ -316,29 +408,59 @@ public function testSaveFail(): void $data = [ 'id' => 99999, ]; + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; foreach ($data as $name => $value) { - $this->ModelController->setRequest($this->ModelController->getRequest()->withData($name, $value)); + $controller->setRequest($controller->getRequest()->withData($name, $value)); } - $result = $this->ModelController->save(); + $result = $controller->save(); static::assertInstanceOf(Response::class, $result); - $flash = $this->ModelController->getRequest()->getSession()->read('Flash.flash.0.message'); + $flash = $controller->getRequest()->getSession()->read('Flash.flash.0.message'); static::assertEquals('[404] Not Found', $flash); } /** * Test `save` method, on redir * - * @covers ::save() - * @covers ::doSave() * @return void */ public function testSaveRedir(): void { + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; $redirTo = ['_name' => 'model:create:object_types']; - $this->ModelController->setRequest($this->ModelController->getRequest()->withData('id', 1)); - $this->ModelController->setRequest($this->ModelController->getRequest()->withData('description', 'whatever')); - $this->ModelController->setRequest($this->ModelController->getRequest()->withData('redirTo', $redirTo)); - $result = $this->ModelController->save(); + $controller->setRequest($controller->getRequest()->withData('id', 1)); + $controller->setRequest($controller->getRequest()->withData('description', 'whatever')); + $controller->setRequest($controller->getRequest()->withData('redirTo', $redirTo)); + $result = $controller->save(); static::assertInstanceOf(Response::class, $result); $location = $result->getHeaderLine('Location'); $expected = '/view'; @@ -348,7 +470,6 @@ public function testSaveRedir(): void /** * Test `remove` method * - * @covers ::remove() * @return void */ public function testRemove(): void @@ -357,42 +478,88 @@ public function testRemove(): void 'name' => 'foos', 'singular' => 'foo', ]; + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; foreach ($data as $name => $value) { - $this->ModelController->setRequest($this->ModelController->getRequest()->withData($name, $value)); + $controller->setRequest($controller->getRequest()->withData($name, $value)); } - $result = $this->ModelController->save(); + $result = $controller->save(); static::assertInstanceOf(Response::class, $result); - $result = $this->ModelController->remove('foos'); + $result = $controller->remove('foos'); static::assertInstanceOf(Response::class, $result); } /** * Test `remove` failure method * - * @covers ::remove() * @return void */ public function testRemoveFail(): void { - $result = $this->ModelController->remove(99999); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $result = $controller->remove('99999'); static::assertInstanceOf(Response::class, $result); - $flash = $this->ModelController->getRequest()->getSession()->read('Flash.flash.0.message'); + $flash = $controller->getRequest()->getSession()->read('Flash.flash.0.message'); static::assertEquals('[404] Not Found', $flash); } /** * Test `create` method * - * @covers ::create() * @return void */ public function testCreate(): void { - $this->ModelController->create(); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $controller = new class ($request) extends ModelBaseController + { + protected ?string $resourceType = 'object_types'; + + public function setResourceType(string $type): void + { + $this->resourceType = $type; + } + + public function setSingleView(bool $view): void + { + $this->singleView = $view; + } + }; + $controller->create(); $vars = ['resource', 'schema', 'properties']; foreach ($vars as $var) { - static::assertNotEmpty($this->ModelController->viewBuilder()->getVar($var)); + static::assertNotEmpty($controller->viewBuilder()->getVar($var)); } } } diff --git a/tests/TestCase/Controller/Model/ModelTagsControllerTest.php b/tests/TestCase/Controller/Model/ModelTagsControllerTest.php index 429109ec7..9173d5622 100644 --- a/tests/TestCase/Controller/Model/ModelTagsControllerTest.php +++ b/tests/TestCase/Controller/Model/ModelTagsControllerTest.php @@ -10,19 +10,22 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase\Controller; +namespace App\Test\TestCase\Controller\Model; use App\Controller\Model\TagsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Model\TagsController} Test Case - * - * @coversDefaultClass \App\Controller\Model\TagsController - * @uses \App\Controller\Model\TagsController */ +#[CoversClass(TagsController::class)] +#[CoversMethod(TagsController::class, 'index')] +#[CoversMethod(TagsController::class, 'initialize')] class ModelTagsControllerTest extends TestCase { /** @@ -30,21 +33,21 @@ class ModelTagsControllerTest extends TestCase * * @var \App\Controller\Model\TagsController */ - public $Tags; + public TagsController $Tags; /** * Client API * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -84,8 +87,6 @@ protected function setupController(array $requestConfig = []): void /** * Test `index` method * - * @covers ::initialize() - * @covers ::index() * @return void */ public function testIndex(): void diff --git a/tests/TestCase/Controller/Model/ObjectTypesControllerTest.php b/tests/TestCase/Controller/Model/ObjectTypesControllerTest.php index 0166f41b4..7ad17f2f4 100644 --- a/tests/TestCase/Controller/Model/ObjectTypesControllerTest.php +++ b/tests/TestCase/Controller/Model/ObjectTypesControllerTest.php @@ -20,60 +20,51 @@ use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use ReflectionClass; /** * {@see \App\Controller\Model\ObjectTypesController} Test Case - * - * @coversDefaultClass \App\Controller\Model\ObjectTypesController - * @uses \App\Controller\Model\ObjectTypesController */ +#[CoversClass(ObjectTypesController::class)] +#[CoversMethod(ObjectTypesController::class, 'addCustomProperties')] +#[CoversMethod(ObjectTypesController::class, 'create')] +#[CoversMethod(ObjectTypesController::class, 'prepareProperties')] +#[CoversMethod(ObjectTypesController::class, 'propertiesData')] +#[CoversMethod(ObjectTypesController::class, 'save')] +#[CoversMethod(ObjectTypesController::class, 'tables')] +#[CoversMethod(ObjectTypesController::class, 'updateSchema')] +#[CoversMethod(ObjectTypesController::class, 'view')] class ObjectTypesControllerTest extends TestCase { /** * The original API client (not mocked). * - * @var \BEdita\SDK\BEditaClient - */ - protected $apiClient = null; - - /** - * @inheritDoc + * @var \BEdita\SDK\BEditaClient|null */ - public function setUp(): void - { - parent::setUp(); - $this->apiClient = ApiClientProvider::getApiClient(); - $this->loadRoutes(); - } - - /** - * @inheritDoc - */ - public function tearDown(): void - { - ApiClientProvider::setApiClient($this->apiClient); - } + protected ?BEditaClient $apiClient = null; /** * Test subject * * @var \App\Controller\Model\ObjectTypesController */ - public $ModelController; + public ObjectTypesController $ModelController; /** * Client API * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * Test default request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -87,7 +78,7 @@ public function tearDown(): void * * @var array */ - public $saveRequestConfig = [ + public array $saveRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'POST', ], @@ -99,6 +90,24 @@ public function tearDown(): void ], ]; + /** + * @inheritDoc + */ + public function setUp(): void + { + parent::setUp(); + $this->apiClient = ApiClientProvider::getApiClient(); + $this->loadRoutes(); + } + + /** + * @inheritDoc + */ + public function tearDown(): void + { + ApiClientProvider::setApiClient($this->apiClient); + } + /** * Setup api client and auth * @@ -130,7 +139,6 @@ protected function setupController(array $requestConfig = []): void /** * Test `create` method * - * @covers ::create() * @return void */ public function testCreate(): void @@ -146,9 +154,6 @@ public function testCreate(): void /** * Test `view` method * - * @covers ::view() - * @covers ::prepareProperties() - * @covers ::propertiesData() * @return void */ public function testView(): void @@ -169,7 +174,6 @@ public function testView(): void /** * Test `view` failure method * - * @covers ::view() * @return void */ public function testViewFail(): void @@ -183,7 +187,6 @@ public function testViewFail(): void * Test `prepareProperties` method * * @return void - * @covers ::prepareProperties() */ public function testPrepareCustomProperties(): void { @@ -227,14 +230,13 @@ public function prepareProperties(array $data, string $name): array * Test `updateSchema` * * @return void - * @covers ::updateSchema() */ public function testUpdateSchema(): void { $this->setupController(); $expected = $schema = ['whatever']; $resource = ['meta' => ['core_type' => true]]; - $reflectionClass = new \ReflectionClass($this->ModelController); + $reflectionClass = new ReflectionClass($this->ModelController); $method = $reflectionClass->getMethod('updateSchema'); $method->setAccessible(true); $actual = $method->invokeArgs($this->ModelController, [$schema, $resource]); @@ -274,15 +276,13 @@ public function testUpdateSchema(): void /** * Test `save` method * - * @covers ::save() - * @covers ::addCustomProperties() * @return void */ public function testSave(): void { $this->saveApiMock(); $controller = new ObjectTypesController( - new ServerRequest($this->saveRequestConfig) + new ServerRequest($this->saveRequestConfig), ); $controller->save(); @@ -293,7 +293,6 @@ public function testSave(): void /** * Test `save` method with empty data * - * @covers ::addCustomProperties() * @return void */ public function testSaveEmpty(): void @@ -311,7 +310,6 @@ public function testSaveEmpty(): void /** * Test `save` method with empty associations * - * @covers ::save() * @return void */ public function testEmptyAssocSave(): void @@ -348,7 +346,6 @@ protected function saveApiMock(): void * Test `tables` * * @return void - * @covers ::tables() */ public function testTables(): void { @@ -360,13 +357,13 @@ public function testTables(): void [ 'objectTypesTables' => $testTables, ], - ) + ), ); $expected = array_unique(array_merge(ObjectTypesController::TABLES, $testTables)); $expected = array_unique(array_merge($expected, ['dummy'])); sort($expected); $this->setupController(); - $reflectionClass = new \ReflectionClass($this->ModelController); + $reflectionClass = new ReflectionClass($this->ModelController); $method = $reflectionClass->getMethod('tables'); $method->setAccessible(true); $actual = $method->invokeArgs($this->ModelController, [['attributes' => ['table' => 'dummy']]]); diff --git a/tests/TestCase/Controller/Model/PropertyTypesControllerTest.php b/tests/TestCase/Controller/Model/PropertyTypesControllerTest.php index 236319715..e5cb151da 100644 --- a/tests/TestCase/Controller/Model/PropertyTypesControllerTest.php +++ b/tests/TestCase/Controller/Model/PropertyTypesControllerTest.php @@ -14,18 +14,26 @@ namespace App\Test\TestCase\Controller\Model; use App\Controller\Model\PropertyTypesController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\Exception\BadRequestException; +use Cake\Http\Exception\MethodNotAllowedException; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Model\PropertyTypesController} Test Case - * - * @coversDefaultClass \App\Controller\Model\PropertyTypesController - * @uses \App\Controller\Model\PropertyTypesController */ +#[CoversClass(PropertyTypesController::class)] +#[CoversMethod(PropertyTypesController::class, 'addPropertyTypes')] +#[CoversMethod(PropertyTypesController::class, 'editPropertyTypes')] +#[CoversMethod(PropertyTypesController::class, 'getResourceType')] +#[CoversMethod(PropertyTypesController::class, 'removePropertyTypes')] +#[CoversMethod(PropertyTypesController::class, 'save')] +#[CoversMethod(PropertyTypesController::class, 'setResourceType')] class PropertyTypesControllerTest extends TestCase { /** @@ -33,21 +41,21 @@ class PropertyTypesControllerTest extends TestCase * * @var \App\Controller\Model\PropertyTypesController */ - public $ModelController; + public PropertyTypesController $ModelController; /** * Client API * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -78,162 +86,190 @@ private function setupApi(): void */ protected function setupController(array $requestConfig = []): void { + $this->setupApi(); $config = array_merge($this->defaultRequestConfig, $requestConfig); $request = new ServerRequest($config); $this->ModelController = new PropertyTypesController($request); + } + + /** + * Test `save` method on method not allowed + * + * @return void + */ + public function testSaveMethodNotAllowed(): void + { $this->setupApi(); + $config = array_merge($this->defaultRequestConfig, []); + $request = new ServerRequest($config); + $this->ModelController = new PropertyTypesController($request); + $this->expectException(MethodNotAllowedException::class); + $this->ModelController->save(); + } + + /** + * Test `save` method on request error + * + * @return void + */ + public function testSaveRequestError(): void + { + $this->setupApi(); + $config = array_merge($this->defaultRequestConfig, [ + 'environment' => [ + 'REQUEST_METHOD' => 'POST', + ], + 'params' => [ + 'resource_type' => 'property_types', + ], + 'post' => [ + 'removePropertyTypes' => [ + '12345', + ], + ], + ]); + $request = new ServerRequest($config); + $this->ModelController = new PropertyTypesController($request); + $this->ModelController->save(); + $actual = (string)Hash::get($this->ModelController->viewBuilder()->getVars(), 'error'); + $expected = '[404] Not Found'; + static::assertEquals($expected, $actual); } /** - * Data provider for `testSave` test case. + * Test `save` method on empty request * - * @return array + * @return void */ - public function saveProvider(): array + public function testSaveEmptyRequest(): void { - $nextId = $this->nextId(); + $exception = new BadRequestException('empty request'); + $this->expectException(get_class($exception)); + $this->expectExceptionCode($exception->getCode()); + $this->expectExceptionMessage($exception->getMessage()); + $this->setupApi(); + $config = array_merge($this->defaultRequestConfig, [ + 'environment' => [ + 'REQUEST_METHOD' => 'POST', + ], + 'params' => [ + 'resource_type' => 'property_types', + ], + ]); + $request = new ServerRequest($config); + $this->ModelController = new PropertyTypesController($request); + $this->ModelController->save(); + } - return [ - // test with empty object - 'emptyRequest' => [ - new BadRequestException('empty request'), - [], - '', + /** + * Test `save` method + * + * @return void + */ + public function testSaveAddEditRemovePropertyTypes(): void + { + $this->setupApi(); + $propertyName = 'mynewpropertytype'; + $config = array_merge($this->defaultRequestConfig, [ + 'environment' => [ + 'REQUEST_METHOD' => 'POST', + ], + 'params' => [ + 'resource_type' => 'property_types', ], - 'addPropertyTypesRequest' => [ - [ + 'post' => [ + 'addPropertyTypes' => [ [ - // 'id' => $nextId, - 'type' => 'property_types', - 'attributes' => [ - 'name' => 'dummyone', - 'params' => [ - 'type' => 'string', - ], - ], + 'name' => $propertyName, + 'params' => json_encode(['type' => 'string']), ], ], - [ - 'addPropertyTypes' => [ - [ - 'name' => 'dummyone', - 'params' => json_encode([ - 'type' => 'string', - ]), - ], + ], + ]); + $request = new ServerRequest($config); + $this->ModelController = new PropertyTypesController($request); + $this->ModelController->save(); + $actual = (array)Hash::get($this->ModelController->viewBuilder()->getVars(), 'saved'); + $expected = [ + [ + 'id' => $actual[0]['id'], + 'type' => 'property_types', + 'attributes' => [ + 'name' => $propertyName, + 'params' => [ + 'type' => 'string', ], ], - 'saved', + 'meta' => $actual[0]['meta'], ], - 'editPropertyTypesRequest' => [ - [ + ]; + static::assertEquals($expected, $actual); + + // edit property + $config = array_merge($this->defaultRequestConfig, [ + 'environment' => [ + 'REQUEST_METHOD' => 'POST', + ], + 'params' => [ + 'resource_type' => 'property_types', + ], + 'post' => [ + 'editPropertyTypes' => [ [ - 'id' => $nextId, - 'type' => 'property_types', + 'id' => $actual[0]['id'], 'attributes' => [ - 'name' => 'dummytwo', - 'params' => [ - 'type' => 'object', - ], + 'name' => $propertyName, + 'params' => ['type' => 'integer'], ], ], ], - [ - 'editPropertyTypes' => [ - [ - 'id' => $nextId, - 'attributes' => [ - 'name' => 'dummytwo', - 'params' => [ - 'type' => 'object', - ], - ], - ], - ], - ], - 'edited', - ], - 'removePropertyTypesRequest' => [ - [ $nextId ], - [ - 'removePropertyTypes' => [ - $nextId, - ], - ], - 'removed', ], - 'request error' => [ - [ - 'error' => '[404] Not Found', - ], - [ - 'removePropertyTypes' => [ - '12345', + ]); + $request = new ServerRequest($config); + $this->ModelController = new PropertyTypesController($request); + $this->ModelController->save(); + $actual = (array)Hash::get($this->ModelController->viewBuilder()->getVars(), 'edited'); + $expected = [ + [ + 'id' => $actual[0]['id'], + 'type' => 'property_types', + 'attributes' => [ + 'name' => $propertyName, + 'params' => [ + 'type' => 'integer', ], ], - 'removed', + 'meta' => $actual[0]['meta'], ], - ]; - } + static::assertEquals($expected, $actual); - /** - * Test `save` method - * - * @param array|\Exception $expectedResponse expected results from test - * @param bool|null $data setup data for test - * @param string $action tested action - * @dataProvider saveProvider() - * @covers ::save() - * @covers ::addPropertyTypes() - * @covers ::editPropertyTypes() - * @covers ::removePropertyTypes() - * @return void - */ - public function testSave($expectedResponse, $data, $action): void - { - $config = [ + // remove property + $expected = [$actual[0]['id']]; + $config = array_merge($this->defaultRequestConfig, [ 'environment' => [ 'REQUEST_METHOD' => 'POST', ], - 'post' => $data, - ]; - - $this->setupController($config); - $this->ModelController->setResourceType('property_types'); - - if ($expectedResponse instanceof \Exception) { - $this->expectException(get_class($expectedResponse)); - $this->expectExceptionCode($expectedResponse->getCode()); - $this->expectExceptionMessage($expectedResponse->getMessage()); - } - + 'params' => [ + 'resource_type' => 'property_types', + ], + 'post' => [ + 'removePropertyTypes' => [ + $expected[0], + ], + ], + ]); + $request = new ServerRequest($config); + $this->ModelController = new PropertyTypesController($request); $this->ModelController->save(); - - $actualResponse = (array)Hash::get($this->ModelController->viewBuilder()->getVars(), $action); - - if ($action == 'saved') { - foreach ($actualResponse as &$element) { - unset($element['id']); - } - } - if (is_array($expectedResponse)) { - $actualResponse = Hash::remove($actualResponse, '{n}.meta'); - if (!empty($expectedResponse['error'])) { - $actualResponse = Hash::get($this->ModelController->viewBuilder()->getVars(), 'error'); - $expectedResponse = $expectedResponse['error']; - } - } - - static::assertEquals($expectedResponse, $actualResponse); + $actual = (array)Hash::get($this->ModelController->viewBuilder()->getVars(), 'removed'); + static::assertEquals($expected, $actual); } /** * Test `getResourceType` and `setResourceType`. * * @return void - * @covers ::getResourceType() - * @covers ::setResourceType() */ public function testGetSetResourceType(): void { @@ -243,18 +279,4 @@ public function testGetSetResourceType(): void $actual = $this->ModelController->getResourceType(); static::assertSame($expected, $actual); } - - /** - * Next ID for test - * - * @return string - */ - private function nextId(): string - { - $this->setupController(); - $response = $this->client->get('/model/property_types'); - $maxId = (int)Hash::get($response, 'data.%d.id', count($response['data'])); - - return strval($maxId + 1); - } } diff --git a/tests/TestCase/Controller/Model/RelationsControllerTest.php b/tests/TestCase/Controller/Model/RelationsControllerTest.php index 9c2d820ff..0f5d2007b 100644 --- a/tests/TestCase/Controller/Model/RelationsControllerTest.php +++ b/tests/TestCase/Controller/Model/RelationsControllerTest.php @@ -19,13 +19,22 @@ use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\Model\RelationsController} Test Case - * - * @coversDefaultClass \App\Controller\Model\RelationsController - * @uses \App\Controller\Model\RelationsController */ +#[CoversClass(RelationsController::class)] +#[CoversMethod(RelationsController::class, 'allTypes')] +#[CoversMethod(RelationsController::class, 'index')] +#[CoversMethod(RelationsController::class, 'indexQuery')] +#[CoversMethod(RelationsController::class, 'relatedItems')] +#[CoversMethod(RelationsController::class, 'relatedTypes')] +#[CoversMethod(RelationsController::class, 'save')] +#[CoversMethod(RelationsController::class, 'updateRelatedTypes')] +#[CoversMethod(RelationsController::class, 'view')] +#[CoversMethod(RelationsController::class, 'viewQuery')] class RelationsControllerTest extends TestCase { /** @@ -33,21 +42,21 @@ class RelationsControllerTest extends TestCase * * @var \App\Controller\Model\RelationsController */ - public $Relations; + public RelationsController $Relations; /** * The original API client (not mocked). * - * @var \BEdita\SDK\BEditaClient + * @var \BEdita\SDK\BEditaClient|null */ - protected $apiClient = null; + protected ?BEditaClient $apiClient = null; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -61,7 +70,7 @@ class RelationsControllerTest extends TestCase * * @var array */ - public $testRelation = [ + public array $testRelation = [ 'id' => 999, 'type' => 'relations', 'attributes' => [ @@ -139,8 +148,6 @@ protected function indexApiMock(): void /** * Test `index` method * - * @covers ::index() - * @covers ::indexQuery() * @return void */ public function testIndex(): void @@ -158,8 +165,6 @@ public function testIndex(): void /** * Test `view` method * - * @covers ::view() - * @covers ::viewQuery() * @return void */ public function testView(): void @@ -199,7 +204,6 @@ protected function viewApiMock(): void /** * Test `relatedTypes` method * - * @covers ::relatedTypes() * @return void */ public function testRelatedTypes(): void @@ -218,7 +222,6 @@ public function testRelatedTypes(): void /** * Test `allTypes` method * - * @covers ::allTypes() * @return void */ public function testAllTypes(): void @@ -233,7 +236,6 @@ public function testAllTypes(): void /** * Test `allTypes` method, exception case * - * @covers ::allTypes() * @return void */ public function testAllTypesException(): void @@ -256,9 +258,6 @@ public function testAllTypesException(): void /** * Test `save` method * - * @covers ::save() - * @covers ::updateRelatedTypes() - * @covers ::relatedItems() * @return void */ public function testSave(): void @@ -279,7 +278,7 @@ public function testSave(): void ], ]; $controller = new RelationsController( - new ServerRequest($config) + new ServerRequest($config), ); $controller->save(); $data = $controller->getRequest()->getData(); diff --git a/tests/TestCase/Controller/ModulesControllerTest.php b/tests/TestCase/Controller/ModulesControllerTest.php index 1581c82b0..9b636a37a 100644 --- a/tests/TestCase/Controller/ModulesControllerTest.php +++ b/tests/TestCase/Controller/ModulesControllerTest.php @@ -16,6 +16,7 @@ use App\Controller\Component\ModulesComponent; use App\Controller\Component\SchemaComponent; +use App\Controller\ModulesController; use App\Test\Utils\ModulesControllerSample; use App\Utility\CacheTools; use Authentication\AuthenticationServiceInterface; @@ -24,19 +25,42 @@ use BEdita\SDK\BEditaClient; use BEdita\SDK\BEditaClientException; use Cake\Cache\Cache; +use Cake\Controller\ComponentRegistry; use Cake\Core\Configure; use Cake\Event\Event; use Cake\Http\Exception\UnauthorizedException; use Cake\Http\ServerRequest; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * {@see \App\Controller\ModulesController} Test Case - * - * @coversDefaultClass \App\Controller\ModulesController */ +#[CoversClass(ModulesController::class)] +#[CoversMethod(ModulesController::class, 'availableRelationshipsUrl')] +#[CoversMethod(ModulesController::class, 'clone')] +#[CoversMethod(ModulesController::class, 'create')] +#[CoversMethod(ModulesController::class, 'delete')] +#[CoversMethod(ModulesController::class, 'get')] +#[CoversMethod(ModulesController::class, 'getObjectType')] +#[CoversMethod(ModulesController::class, 'getSchemaForIndex')] +#[CoversMethod(ModulesController::class, 'handleError')] +#[CoversMethod(ModulesController::class, 'index')] +#[CoversMethod(ModulesController::class, 'initialize')] +#[CoversMethod(ModulesController::class, 'relationships')] +#[CoversMethod(ModulesController::class, 'related')] +#[CoversMethod(ModulesController::class, 'resources')] +#[CoversMethod(ModulesController::class, 'save')] +#[CoversMethod(ModulesController::class, 'setObjectType')] +#[CoversMethod(ModulesController::class, 'setup')] +#[CoversMethod(ModulesController::class, 'setupViewRelations')] +#[CoversMethod(ModulesController::class, 'uname')] +#[CoversMethod(ModulesController::class, 'users')] +#[CoversMethod(ModulesController::class, 'view')] class ModulesControllerTest extends BaseControllerTest { /** @@ -62,7 +86,7 @@ public function tearDown(): void * * @var \App\Test\Utils\ModulesControllerSample */ - public $controller; + public ModulesControllerSample $controller; /** * Setup controller to test with request config @@ -74,7 +98,13 @@ protected function setupController(?array $requestConfig = []): void { $config = array_merge($this->defaultRequestConfig, $requestConfig); $request = new ServerRequest($config); - $this->controller = new ModulesControllerSample($request); + $this->controller = new class ($request) extends ModulesControllerSample + { + public function setApiClient($client): void + { + $this->apiClient = $client; + } + }; // Mock Authentication component $this->controller->setRequest($this->controller->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); $this->controller->Authentication->setIdentity(new Identity(['id' => 'dummy'])); @@ -116,7 +146,6 @@ protected function getAuthenticationServiceMock(): AuthenticationServiceInterfac /** * Test `initialize` method * - * @covers ::initialize() * @return void */ public function testInitialize(): void @@ -137,7 +166,6 @@ public function testInitialize(): void * Test `index` method * * @return void - * @covers ::index() */ public function testIndex(): void { @@ -160,7 +188,6 @@ public function testIndex(): void * Test `index` method * * @return void - * @covers ::index() */ public function testIndexResetRequest(): void { @@ -190,7 +217,6 @@ public function testIndexResetRequest(): void * Test `index` method with query string error * Session filter data must be empty * - * @covers ::index() * @return void */ public function testQueryErrorSession(): void @@ -215,8 +241,6 @@ public function testQueryErrorSession(): void /** * Test `view` method * - * @covers ::view() - * @covers ::setupViewRelations() * @return void */ public function testView(): void @@ -242,7 +266,6 @@ public function testView(): void /** * Test `view` method on error * - * @covers ::view() * @return void */ public function testViewError(): void @@ -261,7 +284,6 @@ public function testViewError(): void /** * Test `uname` method * - * @covers ::uname() * @return void */ public function testUname(): void @@ -285,7 +307,6 @@ public function testUname(): void /** * Test `uname` method, case 404 Not Found * - * @covers ::uname() * @return void */ public function testUname404(): void @@ -305,8 +326,6 @@ public function testUname404(): void /** * Test `create` method * - * @covers ::create() - * @covers ::setupViewRelations() * @return void */ public function testCreate(): void @@ -324,7 +343,6 @@ public function testCreate(): void /** * Test `create` method * - * @covers ::create() * @return void */ public function testCreate302(): void @@ -351,7 +369,6 @@ public function testCreate302(): void /** * Test `clone` method * - * @covers ::clone() * @return void */ public function testClone(): void @@ -377,7 +394,6 @@ public function testClone(): void /** * Test `clone` method * - * @covers ::clone() * @return void */ public function testCloneMedia(): void @@ -401,7 +417,6 @@ public function testCloneMedia(): void /** * Test `clone` method * - * @covers ::clone() * @return void */ public function testClone302(): void @@ -443,7 +458,6 @@ public function testClone302(): void /** * Test `clone` method, on error * - * @covers ::clone() * @return void */ public function testCloneError(): void @@ -463,7 +477,6 @@ public function testCloneError(): void * Test `save` method when uname is numeric * * @return void - * @covers ::save() */ public function testSaveUnameNumeric(): void { @@ -503,7 +516,6 @@ public function testSaveUnameNumeric(): void * Test `save` method when there's only 'id' in post data * * @return void - * @covers ::save() */ public function testSkipSave(): void { @@ -542,7 +554,6 @@ public function testSkipSave(): void /** * Test `save` method, on error * - * @covers ::save() * @return void */ public function testSaveErrorNoPost(): void @@ -572,7 +583,6 @@ public function testSaveErrorNoPost(): void /** * Test `save` method, on error * - * @covers ::save() * @return void */ public function testSaveErrorPostId(): void @@ -607,7 +617,7 @@ public function testSaveErrorPostId(): void * * @return array */ - public function saveProvider(): array + public static function saveProvider(): array { return [ 'save' => [ @@ -644,10 +654,9 @@ public function saveProvider(): array /** * Test `save` method * - * @dataProvider saveProvider() - * @covers ::save() * @return void */ + #[DataProvider('saveProvider')] public function testSave($expected, $data): void { // Setup controller for test @@ -668,7 +677,7 @@ public function testSave($expected, $data): void $this->controller->save(); // verify response status code and type - $result = $this->controller->getApiClient(); + $result = $this->controller->apiClient; static::assertEquals($expected['code'], $result->getStatusCode()); static::assertEquals($expected['message'], $result->getStatusMessage()); } @@ -676,7 +685,6 @@ public function testSave($expected, $data): void /** * Test `delete` method * - * @covers ::delete() * @return void */ public function testDelete(): void @@ -714,7 +722,6 @@ public function testDelete(): void /** * Test `delete` method, ids * - * @covers ::delete() * @return void */ public function testDeleteIds(): void @@ -752,7 +759,6 @@ public function testDeleteIds(): void /** * Test `delete` method, on error * - * @covers ::delete() * @return void */ public function testDeleteError(): void @@ -774,13 +780,13 @@ public function testDeleteError(): void ]; $request = new ServerRequest($config); $this->controller = new ModulesControllerSample($request); - $apiClient = new class ('https://api.example.com') extends BEditaClient { + + $this->controller->apiClient = new class ('https://api.example.com') extends BEditaClient { public function delete(string $path, ?string $body = null, ?array $headers = null): ?array { throw new BEditaClientException('Error'); } }; - $this->controller->setApiClient($apiClient); // do controller call $result = $this->controller->delete(); @@ -815,7 +821,6 @@ public function delete(string $path, ?string $body = null, ?array $headers = nul /** * Test `related` method * - * @covers ::related() * @return void */ public function testRelated(): void @@ -837,7 +842,6 @@ public function testRelated(): void /** * Test `related` method on `new` object * - * @covers ::related() * @return void */ public function testRelatedNew(): void @@ -854,7 +858,6 @@ public function testRelatedNew(): void /** * Test `related` method, on error * - * @covers ::related() * @return void */ public function testRelatedError(): void @@ -873,7 +876,6 @@ public function testRelatedError(): void /** * Test `resources` method * - * @covers ::resources() * @return void */ public function testResources(): void @@ -895,7 +897,6 @@ public function testResources(): void /** * Test `resources` method * - * @covers ::resources() * @return void */ public function testResourcesError(): void @@ -916,7 +917,7 @@ public function testResourcesError(): void * * @return array */ - public function relationshipsProvider(): array + public static function relationshipsProvider(): array { return [ 'children' => [ @@ -943,10 +944,9 @@ public function relationshipsProvider(): array * * @param string $relation The relation to test * @param string $objectType The object type / endpoint - * @covers ::relationships() - * @dataProvider relationshipsProvider() * @return void */ + #[DataProvider('relationshipsProvider')] public function testRelationships(string $relation, string $objectType): void { // Setup controller for test @@ -973,24 +973,10 @@ public function testRelationships(string $relation, string $objectType): void /** * Test `getSchemaForIndex` method with errors * - * @covers ::getSchemaForIndex() * @return void */ public function testGetSchemaForIndex(): void { - $type = 'documents'; - $mockResponse = [ - 'properties' => [ - 'enum_prop' => [ - 'type' => 'string', - 'enum' => [ - 'enum1', - 'enum2', - 'enum3', - ], - ], - ], - ]; $expected = [ 'properties' => [ 'enum_prop' => [ @@ -1006,20 +992,37 @@ public function testGetSchemaForIndex(): void ]; $this->setupController(); - $this->controller->Schema = $this->createMock(SchemaComponent::class); - $this->controller->Schema->method('getSchema') - ->with($type) - ->willReturn($mockResponse); - - $actual = $this->controller->getSchemaForIndex($type); - + $controller = new class ($this->controller->getRequest()) extends ModulesController { + public object $Schema; + public function initialize(): void + { + $this->Schema = new class (new ComponentRegistry($this)) extends SchemaComponent { + public function getSchema(?string $type = null, ?string $revision = null): array|bool + { + return [ + 'properties' => [ + 'enum_prop' => [ + 'type' => 'string', + 'enum' => [ + 'enum1', + 'enum2', + 'enum3', + ], + ], + ], + ]; + } + }; + parent::initialize(); + } + }; + $actual = $controller->getSchemaForIndex('documents'); static::assertEquals($expected, $actual); } /** * Test `availableRelationshipsUrl` method * - * @covers ::availableRelationshipsUrl() * @return void */ public function testAvailableRelationshipsUrl(): void @@ -1027,19 +1030,58 @@ public function testAvailableRelationshipsUrl(): void $this->setupController(); $url = $this->controller->availableRelationshipsUrl('children'); static::assertEquals('/objects', $url); + $controller = new class ($this->controller->getRequest()) extends ModulesController { + public object $Modules; + + public function initialize(): void + { + $this->Modules = new class (new ComponentRegistry($this)) extends ModulesComponent { + public function relatedTypes(array $schema, string $relation): array + { + return ['documents']; + } + }; + parent::initialize(); + } - $this->controller->Modules = $this->createMock(ModulesComponent::class); - $this->controller->Modules->method('relatedTypes') - ->willReturn(['documents']); + public function availableRelationshipsUrl(string $relation): string + { + return parent::availableRelationshipsUrl($relation); + } + }; - $url = $this->controller->availableRelationshipsUrl('test_relation'); + $url = $controller->availableRelationshipsUrl('test_relation'); static::assertEquals('/documents', $url); + } - $this->controller->Modules = $this->createMock(ModulesComponent::class); - $this->controller->Modules->method('relatedTypes') - ->willReturn(['images', 'profiles']); + /** + * Test `availableRelationshipsUrl` method + * + * @return void + */ + public function testAvailableRelationshipsUrlMulti(): void + { + $this->setupController(); + $controller = new class ($this->controller->getRequest()) extends ModulesController { + public object $Modules; - $url = $this->controller->availableRelationshipsUrl('test_relation'); + public function initialize(): void + { + $this->Modules = new class (new ComponentRegistry($this)) extends ModulesComponent { + public function relatedTypes(array $schema, string $relation): array + { + return ['images', 'profiles']; + } + }; + parent::initialize(); + } + + public function availableRelationshipsUrl(string $relation): string + { + return parent::availableRelationshipsUrl($relation); + } + }; + $url = $controller->availableRelationshipsUrl('test_relation'); static::assertEquals('/objects?filter[type][]=images&filter[type][]=profiles', $url); } @@ -1060,8 +1102,6 @@ private function assertExpectedViewVars($expected): void * Test `getObjectType` and `setObjectType`. * * @return void - * @covers ::getObjectType() - * @covers ::setObjectType() */ public function testGetSetObjectType(): void { @@ -1085,7 +1125,6 @@ public function testGetSetObjectType(): void * Test list users * * @return void - * @covers ::users() */ public function testListUsers(): void { @@ -1109,7 +1148,6 @@ public function testListUsers(): void * Test get single resource minimal data * * @return void - * @covers ::get() */ public function testResourceGet(): void { @@ -1133,7 +1171,6 @@ public function testResourceGet(): void * Test setup method with an unauthorized user * * @return void - * @covers ::setup() */ public function testSetupUnauthorized(): void { @@ -1149,7 +1186,6 @@ public function testSetupUnauthorized(): void * Test setup method with an authorized user * * @return void - * @covers ::setup() */ public function testSetupAuthorized(): void { @@ -1169,7 +1205,6 @@ public function testSetupAuthorized(): void * Test setup method with an authorized user and save * * @return void - * @covers ::setup() */ public function testSetupSave(): void { @@ -1203,7 +1238,6 @@ public function testSetupSave(): void * Test setup method with an authorized user and save error * * @return void - * @covers ::setup() */ public function testSetupSaveError(): void { @@ -1237,7 +1271,6 @@ public function testSetupSaveError(): void * Test `save` method, skip save when no post data is provided * * @return void - * @covers ::save() */ public function testSkipSaveObject(): void { @@ -1257,7 +1290,13 @@ public function testSkipSaveObject(): void ]; $request = new ServerRequest($config); - $this->controller = new ModulesControllerSample($request); + $this->controller = new class ($request) extends ModulesControllerSample + { + public function setApiClient($client): void + { + $this->apiClient = $client; + } + }; // mock api client save... and check it's not called $apiClient = new class ('https://api.example.com') extends BEditaClient @@ -1302,7 +1341,6 @@ public function save(string $type, array $data, ?array $headers = null): ?array * Test `save` method when permissions are provided * * @return void - * @covers ::save() */ public function testSavePermissions(): void { @@ -1326,6 +1364,12 @@ public function testSavePermissions(): void $this->controller = new class ($request) extends ModulesControllerSample { public bool $savePerms = false; + + public function setApiClient($client): void + { + $this->apiClient = $client; + } + public function savePermissions(array $response, array $schema, array $newPermissions): bool { $this->savePerms = true; @@ -1370,7 +1414,7 @@ public function save(string $type, array $data, ?array $headers = null): ?array $registry = $this->controller->components(); $schemaComponent = new class ($registry) extends SchemaComponent { - public function getSchema(?string $type = null, ?string $revision = null) + public function getSchema(?string $type = null, ?string $revision = null): array|bool { return ['associations' => ['Permissions']]; } @@ -1389,7 +1433,6 @@ public function getSchema(?string $type = null, ?string $revision = null) * Test `save` method, when related data is provided * * @return void - * @covers ::save() */ public function testSaveRelated(): void { @@ -1411,6 +1454,10 @@ public function testSaveRelated(): void $request = new ServerRequest($config); $this->controller = new class ($request) extends ModulesControllerSample { + public function setApiClient($client): void + { + $this->apiClient = $client; + } }; $registry = $this->controller->components(); @@ -1474,7 +1521,6 @@ public function save(string $type, array $data, ?array $headers = null): ?array * Test `save` method, skip save when no post 'permissions' data is provided * * @return void - * @covers ::save() */ public function testSkipSavePermissions(): void { @@ -1499,6 +1545,12 @@ public function testSkipSavePermissions(): void $this->controller = new class ($request) extends ModulesControllerSample { public bool $savePerms = false; + + public function setApiClient($client): void + { + $this->apiClient = $client; + } + public function savePermissions(array $response, array $schema, array $newPermissions): bool { $this->savePerms = true; @@ -1551,8 +1603,6 @@ public function save(string $type, array $data, ?array $headers = null): ?array * Test errors when saving permissions and related data * * @return void - * @covers ::save() - * @covers ::handleError() */ public function testSaveErrorPermissionsAndRelatedData(): void { diff --git a/tests/TestCase/Controller/MultiuploadControllerTest.php b/tests/TestCase/Controller/MultiuploadControllerTest.php index 5d4cb9199..0cc786ee1 100644 --- a/tests/TestCase/Controller/MultiuploadControllerTest.php +++ b/tests/TestCase/Controller/MultiuploadControllerTest.php @@ -16,19 +16,20 @@ use App\Controller\MultiuploadController; use Cake\Http\ServerRequest; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\MultiuploadController} Test Case - * - * @coversDefaultClass \App\Controller\MultiuploadController */ +#[CoversClass(MultiuploadController::class)] +#[CoversMethod(MultiuploadController::class, 'initialize')] class MultiuploadControllerTest extends BaseControllerTest { /** * Test `initialize` method * * @return void - * @covers ::initialize() */ public function testInitialize(): void { diff --git a/tests/TestCase/Controller/PasswordControllerTest.php b/tests/TestCase/Controller/PasswordControllerTest.php index 7ee529d9a..8437189d4 100644 --- a/tests/TestCase/Controller/PasswordControllerTest.php +++ b/tests/TestCase/Controller/PasswordControllerTest.php @@ -21,13 +21,17 @@ use Cake\TestSuite\TestCase; use Cake\Utility\Hash; use Cake\Utility\Text; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use ReflectionProperty; /** * {@see \App\Controller\PasswordController} Test Case - * - * @coversDefaultClass \App\Controller\PasswordController - * @uses \App\Controller\PasswordController */ +#[CoversClass(PasswordController::class)] +#[CoversMethod(PasswordController::class, 'change')] +#[CoversMethod(PasswordController::class, 'reset')] class PasswordControllerTest extends TestCase { /** @@ -44,14 +48,14 @@ public function setUp(): void * * @var \App\Controller\PasswordController */ - public $Password; + public PasswordController $Password; /** * Test api client * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * Setup controller to test with request config @@ -79,7 +83,7 @@ private function setupController(array $config, array $mock): void $this->client->method($method)->with($with[0], $with[1], $with[2])->willThrowException($exception); } // set $this->Password->apiClient - $property = new \ReflectionProperty(PasswordController::class, 'apiClient'); + $property = new ReflectionProperty(PasswordController::class, 'apiClient'); $property->setAccessible(true); $property->setValue($this->Password, $this->client); } @@ -89,7 +93,7 @@ private function setupController(array $config, array $mock): void * * @return array */ - public function resetProvider(): array + public static function resetProvider(): array { $email = 'gustavo@bedita.net'; @@ -132,9 +136,8 @@ public function resetProvider(): array * @param array $config The config for controller setup * @param array $mock The parameters for api client mock * @return void - * @dataProvider resetProvider() - * @covers ::reset() */ + #[DataProvider('resetProvider')] public function testReset(array $config, array $mock): void { $this->setupController($config, $mock); @@ -146,7 +149,6 @@ public function testReset(array $config, array $mock): void * Test `reset` method, exception case * * @return void - * @covers ::reset() */ public function testResetException(): void { @@ -180,7 +182,7 @@ public function testResetException(): void * * @return array */ - public function changeProvider(): array + public static function changeProvider(): array { $uuid = Text::uuid(); @@ -227,9 +229,8 @@ public function changeProvider(): array * @param array $mock The parameters to mock api client * @param Response|null $expected The expected result * @return void - * @dataProvider changeProvider() - * @covers ::change() */ + #[DataProvider('changeProvider')] public function testChange(array $config, array $mock, ?Response $expected): void { $this->setupController($config, $mock); @@ -246,7 +247,6 @@ public function testChange(array $config, array $mock, ?Response $expected): voi * Test `change` method, exception case * * @return void - * @covers ::change() */ public function testChangeException(): void { diff --git a/tests/TestCase/Controller/RolesControllerTest.php b/tests/TestCase/Controller/RolesControllerTest.php index 9533d7471..09e78f59d 100644 --- a/tests/TestCase/Controller/RolesControllerTest.php +++ b/tests/TestCase/Controller/RolesControllerTest.php @@ -26,15 +26,19 @@ use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** - * {@see \App\Controller\RolesController} Test Case - * - * @coversDefaultClass \App\Controller\RolesController - * @uses \App\Controller\RolesController + * {@see \App\Controller\RolesController} test Case */ +#[CoversClass(RolesController::class)] +#[CoversMethod(RolesController::class, 'allowed')] +#[CoversMethod(RolesController::class, 'beforeFilter')] +#[CoversMethod(RolesController::class, 'list')] class RolesControllerTest extends TestCase { /** @@ -78,7 +82,7 @@ protected function setupController($config = null): void * * @return array */ - public function unauthorizedExceptionProvider(): array + public static function unauthorizedExceptionProvider(): array { return [ 'no same origin' => [ @@ -120,10 +124,8 @@ public function unauthorizedExceptionProvider(): array * * @param array $config Request configuration. * @return void - * @dataProvider unauthorizedExceptionProvider - * @covers ::beforeFilter() - * @covers ::allowed() */ + #[DataProvider('unauthorizedExceptionProvider')] public function testUnauthorizedException(array $config): void { $expected = new UnauthorizedException(__('You are not authorized to access this resource')); @@ -139,8 +141,6 @@ public function testUnauthorizedException(array $config): void * Test unauthorized role * * @return void - * @covers ::beforeFilter() - * @covers ::allowed() */ public function testUnauthorizedRole(): void { @@ -168,9 +168,6 @@ public function testUnauthorizedRole(): void * Test for authorized admin * * @return void - * @covers ::beforeFilter() - * @covers ::allowed() - * @covers ::list() */ public function testAuthorizeAdmin(): void { @@ -188,9 +185,6 @@ public function testAuthorizeAdmin(): void $this->RolesController->setRequest($this->RolesController->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); $this->RolesController->Authentication->setIdentity($user); $this->RolesController->dispatchEvent('Controller.initialize'); - $actual = $this->RolesController->Security->getConfig('unlockedActions'); - $expected = []; - static::assertEquals($expected, $actual); $response = $this->RolesController->list(); static::assertNull($response); $data = $this->RolesController->viewBuilder()->getVars(); @@ -206,7 +200,7 @@ public function testAuthorizeAdmin(): void $apiClient->method('get') ->withAnyParameters() ->willThrowException(new BEditaClientException('API error')); - $controller = new class () extends RolesController { + $controller = new class (new ServerRequest()) extends RolesController { public function setApiClient($client): void { $this->apiClient = $client; @@ -219,7 +213,7 @@ protected function allowed(): bool } }; $controller->setApiClient($apiClient); - $response = $controller->list(); + $controller->list(); $data = $controller->viewBuilder()->getVars(); $error = Hash::get($data, 'error'); static::assertNotEmpty($error); @@ -232,8 +226,6 @@ protected function allowed(): bool * Test for authorized user * * @return void - * @covers ::beforeFilter() - * @covers ::allowed() */ public function testUserAllowed(): void { @@ -252,9 +244,10 @@ public function testUserAllowed(): void $this->RolesController->setRequest($this->RolesController->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); $this->RolesController->Authentication->setIdentity($user); $this->RolesController->dispatchEvent('Controller.initialize'); - $actual = $this->RolesController->Security->getConfig('unlockedActions'); - $expected = []; - static::assertEquals($expected, $actual); + $response = $this->RolesController->list(); + static::assertNull($response); + $data = $this->RolesController->viewBuilder()->getVars(); + static::assertIsArray($data); } /** diff --git a/tests/TestCase/Controller/SendMailControllerTest.php b/tests/TestCase/Controller/SendMailControllerTest.php new file mode 100644 index 000000000..78c11aef0 --- /dev/null +++ b/tests/TestCase/Controller/SendMailControllerTest.php @@ -0,0 +1,60 @@ + [ + 'REQUEST_METHOD' => 'POST', + ], + 'post' => [ + 'data' => [ + 'user.name' => 'John', + 'user.surname' => 'Doe', + ], + ], + ]; + $request = new ServerRequest($config); + $controller = new SendMailController($request); + $controller->index(); + $expected = '[404] Not Found'; + $actual = $controller->viewBuilder()->getVar('error'); + static::assertEquals($expected, $actual); + + // mock /placeholders/send to simulate success response + $safeClient = ApiClientProvider::getApiClient(); + $apiClient = $this->getMockBuilder(BEditaClient::class) + ->setConstructorArgs(['https://api.example.org']) + ->getMock(); + $apiClient->method('post') + ->willReturn(null); + ApiClientProvider::setApiClient($apiClient); + $controller->index(); + $expected = 'Email sent successfully'; + $actual = $controller->viewBuilder()->getVar('response')['message']; + static::assertEquals($expected, $actual); + ApiClientProvider::setApiClient($safeClient); + } +} diff --git a/tests/TestCase/Controller/SessionControllerTest.php b/tests/TestCase/Controller/SessionControllerTest.php index 4aba588c6..173cfd0bf 100644 --- a/tests/TestCase/Controller/SessionControllerTest.php +++ b/tests/TestCase/Controller/SessionControllerTest.php @@ -15,18 +15,22 @@ use App\Controller\SessionController; use Cake\Http\ServerRequest; use Cake\Http\Session; +use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\SessionController} test case. - * - * @coversDefaultClass \App\Controller\SessionController */ -class SessionControllerTest extends \Cake\TestSuite\TestCase +#[CoversClass(SessionController::class)] +#[CoversMethod(SessionController::class, 'delete')] +#[CoversMethod(SessionController::class, 'save')] +#[CoversMethod(SessionController::class, 'view')] +class SessionControllerTest extends TestCase { /** * Test `view` method. * - * @covers ::view() * @return void */ public function testView(): void @@ -40,7 +44,7 @@ public function testView(): void ], 'url' => '/session/test', 'session' => $session, - ]) + ]), ); $controller->view('test'); static::assertEquals(200, $controller->getResponse()->getStatusCode()); @@ -55,7 +59,7 @@ public function testView(): void ], 'url' => '/session/tast', 'session' => $session, - ]) + ]), ); $controller->view('tast'); static::assertEquals(200, $controller->getResponse()->getStatusCode()); @@ -67,7 +71,6 @@ public function testView(): void /** * Test `save` method. * - * @covers ::save() * @return void */ public function testSave(): void @@ -84,7 +87,7 @@ public function testSave(): void ], 'url' => '/session', 'session' => $session, - ]) + ]), ); $controller->save(); static::assertEquals('tost', $session->read('test')); @@ -105,7 +108,7 @@ public function testSave(): void ], 'url' => '/session', 'session' => $session, - ]) + ]), ); $controller->save(); static::assertEquals('tast', $session->read('test')); @@ -119,7 +122,6 @@ public function testSave(): void /** * Test `delete` method. * - * @covers ::delete() * @return void */ public function testDelete(): void @@ -133,7 +135,7 @@ public function testDelete(): void ], 'url' => '/session/test', 'session' => $session, - ]) + ]), ); $controller->delete('test'); static::assertNull($session->read('test')); @@ -146,7 +148,7 @@ public function testDelete(): void ], 'url' => '/session/tast', 'session' => $session, - ]) + ]), ); $controller->delete('tast'); static::assertNull($session->read('tast')); diff --git a/tests/TestCase/Controller/TagsControllerTest.php b/tests/TestCase/Controller/TagsControllerTest.php index c02232428..1dd0ed5ff 100644 --- a/tests/TestCase/Controller/TagsControllerTest.php +++ b/tests/TestCase/Controller/TagsControllerTest.php @@ -4,16 +4,25 @@ namespace App\Test\TestCase\Controller; use App\Controller\TagsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\TagsController} Test Case - * - * @coversDefaultClass \App\Controller\TagsController */ +#[CoversClass(TagsController::class)] +#[CoversMethod(TagsController::class, 'beforeRender')] +#[CoversMethod(TagsController::class, 'create')] +#[CoversMethod(TagsController::class, 'delete')] +#[CoversMethod(TagsController::class, 'index')] +#[CoversMethod(TagsController::class, 'initialize')] +#[CoversMethod(TagsController::class, 'patch')] +#[CoversMethod(TagsController::class, 'search')] class TagsControllerTest extends TestCase { /** @@ -21,21 +30,21 @@ class TagsControllerTest extends TestCase * * @var \App\Controller\TagsController */ - public $controller; + public TagsController $controller; /** * Client API * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -76,20 +85,21 @@ protected function setupController(array $requestConfig = []): void * Test `initialize` method * * @return void - * @covers ::initialize() */ public function testInitialize(): void { $this->setupController(); $this->controller->index(); static::assertInstanceOf('App\Controller\Component\ProjectConfigurationComponent', $this->controller->ProjectConfiguration); + $actual = $this->controller->FormProtection->getConfig('unlockedActions'); + $expected = ['create', 'patch', 'delete']; + static::assertEquals($expected, $actual); } /** * Test `index` method * * @return void - * @covers ::index() */ public function testIndex(): void { @@ -103,7 +113,6 @@ public function testIndex(): void * Test `beforeRender` method * * @return void - * @covers ::beforeRender() */ public function testBeforeRender(): void { @@ -116,10 +125,6 @@ public function testBeforeRender(): void * Test `create`, `patch`, `delete`, `search` methods * * @return void - * @covers ::create() - * @covers ::patch() - * @covers ::delete() - * @covers ::search() */ public function testMulti(): void { diff --git a/tests/TestCase/Controller/TranslationsControllerTest.php b/tests/TestCase/Controller/TranslationsControllerTest.php index dbad02a69..cd7e99269 100644 --- a/tests/TestCase/Controller/TranslationsControllerTest.php +++ b/tests/TestCase/Controller/TranslationsControllerTest.php @@ -14,19 +14,31 @@ namespace App\Test\TestCase\Controller; use App\Controller\TranslationsController; +use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Http\Exception\BadRequestException; +use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use Exception; use Laminas\Diactoros\Uri; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use ReflectionClass; /** * {@see \App\Controller\TranslationsController} Test Case - * - * @coversDefaultClass \App\Controller\TranslationsController - * @uses \App\Controller\TranslationsController */ +#[CoversClass(TranslationsController::class)] +#[CoversMethod(TranslationsController::class, 'add')] +#[CoversMethod(TranslationsController::class, 'delete')] +#[CoversMethod(TranslationsController::class, 'edit')] +#[CoversMethod(TranslationsController::class, 'index')] +#[CoversMethod(TranslationsController::class, 'initialize')] +#[CoversMethod(TranslationsController::class, 'save')] +#[CoversMethod(TranslationsController::class, 'setupJsonKeys')] +#[CoversMethod(TranslationsController::class, 'typeFromUrl')] class TranslationsControllerTest extends TestCase { /** @@ -43,28 +55,28 @@ public function setUp(): void * * @var \App\Controller\TranslationsController */ - public $controller; + public TranslationsController $controller; /** * Test api client * * @var \BEdita\SDK\BEditaClient */ - public $client; + public BEditaClient $client; /** * Uname for test object * * @var string */ - protected $uname = 'translations-controller-test-document'; + protected string $uname = 'translations-controller-test-document'; /** * Test request config * * @var array */ - public $defaultRequestConfig = [ + public array $defaultRequestConfig = [ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -107,7 +119,6 @@ protected function setupController(?array $requestConfig = []): void /** * Test `initialize` method * - * @covers ::initialize() * @return void */ public function testInitialize(): void @@ -122,7 +133,6 @@ public function testInitialize(): void /** * Test `add` method * - * @covers ::add() * @return void */ public function testAdd(): void @@ -146,7 +156,7 @@ public function testAdd(): void // on error $result = $this->controller->add(123456789); - $expected = get_class(new \Cake\Http\Response()); + $expected = get_class(new Response()); $actual = get_class($result); static::assertEquals($expected, $actual); } @@ -154,7 +164,6 @@ public function testAdd(): void /** * Test `edit` method * - * @covers ::edit() * @return void */ public function testEdit(): void @@ -179,7 +188,7 @@ public function testEdit(): void // on error $result = $this->controller->edit(123456789, $lang); - $expected = get_class(new \Cake\Http\Response()); + $expected = get_class(new Response()); $actual = get_class($result); static::assertEquals($expected, $actual); } @@ -187,7 +196,6 @@ public function testEdit(): void /** * Test `save` method * - * @covers ::save() * @return void */ public function testSave(): void @@ -305,8 +313,6 @@ public function testSave(): void /** * Test `save` method with JSON fields * - * @covers ::save() - * @covers ::setupJsonKeys() * @return void */ public function testSaveJson(): void @@ -366,7 +372,6 @@ public function testSaveJson(): void /** * Test `delete` method * - * @covers ::delete() * @return void */ public function testDelete(): void @@ -415,7 +420,7 @@ public function testDelete(): void $this->controller = new TranslationsController($request); try { $this->controller->delete(); - } catch (\Exception $e) { + } catch (Exception $e) { $expected = get_class(new BadRequestException()); $actual = get_class($e); static::assertEquals($expected, $actual); @@ -435,7 +440,7 @@ public function testDelete(): void $this->controller = new TranslationsController($request); try { $this->controller->delete(); - } catch (\Exception $e) { + } catch (Exception $e) { $expected = get_class(new BadRequestException()); $actual = get_class($e); static::assertEquals($expected, $actual); @@ -455,7 +460,7 @@ public function testDelete(): void $this->controller = new TranslationsController($request); try { $this->controller->delete(); - } catch (\Exception $e) { + } catch (Exception $e) { $expected = get_class(new BadRequestException()); $actual = get_class($e); static::assertEquals($expected, $actual); @@ -474,7 +479,7 @@ public function testDelete(): void $request = new ServerRequest($config); $this->controller = new TranslationsController($request); $response = $this->controller->delete(); - $expected = get_class(new \Cake\Http\Response()); + $expected = get_class(new Response()); $actual = get_class($response); static::assertEquals($expected, $actual); } @@ -483,14 +488,13 @@ public function testDelete(): void * Test `typeFromUrl` method. * * @return void - * @covers ::typeFromUrl() */ public function testTypeFromUrl(): void { $uri = new Uri('/documents/1/translation/lang'); $request = new ServerRequest($this->defaultRequestConfig + compact('uri')); $this->controller = new TranslationsController($request); - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('typeFromUrl'); $method->setAccessible(true); $expected = 'documents'; @@ -500,7 +504,7 @@ public function testTypeFromUrl(): void $request = new ServerRequest($this->defaultRequestConfig); $this->controller = new TranslationsController($request); $this->controller->setObjectType('dummies'); - $reflectionClass = new \ReflectionClass($this->controller); + $reflectionClass = new ReflectionClass($this->controller); $method = $reflectionClass->getMethod('typeFromUrl'); $method->setAccessible(true); $expected = 'dummies'; @@ -595,7 +599,7 @@ private function restoreTestObject($id, $type): void { $o = $this->getTestObject(); if ($o == null) { - $response = $this->client->restoreObject($id, $type); + $this->client->restoreObject($id, $type); } } @@ -616,7 +620,6 @@ private function assertExpectedViewVars($expected): void * Test `index` method * * @return void - * @covers ::index() */ public function testIndex(): void { diff --git a/tests/TestCase/Controller/TranslatorControllerTest.php b/tests/TestCase/Controller/TranslatorControllerTest.php index 1a512e52f..1d798c455 100644 --- a/tests/TestCase/Controller/TranslatorControllerTest.php +++ b/tests/TestCase/Controller/TranslatorControllerTest.php @@ -19,13 +19,15 @@ use Cake\Http\Exception\MethodNotAllowedException; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\TranslatorController} Test Case - * - * @coversDefaultClass \App\Controller\TranslatorController - * @uses \App\Controller\TranslatorController */ +#[CoversClass(TranslatorController::class)] +#[CoversMethod(TranslatorController::class, 'initialize')] +#[CoversMethod(TranslatorController::class, 'translate')] class TranslatorControllerTest extends TestCase { /** @@ -33,12 +35,11 @@ class TranslatorControllerTest extends TestCase * * @var \App\Controller\TranslatorController */ - public $controller; + public TranslatorController $controller; /** * Test `translate` method * - * @covers ::translate() * @return void */ public function testTranslateMethodNotAllowedException(): void @@ -49,7 +50,7 @@ public function testTranslateMethodNotAllowedException(): void 'environment' => [ 'REQUEST_METHOD' => 'GET', ], - ]) + ]), ); $this->controller->translate(); } @@ -57,7 +58,6 @@ public function testTranslateMethodNotAllowedException(): void /** * Test `translate` method * - * @covers ::translate() * @return void */ public function testTranslateNoTranslatorEngine(): void @@ -73,7 +73,7 @@ public function testTranslateNoTranslatorEngine(): void 'to' => 'it', 'translator' => 'xxx', ], - ]) + ]), ); $this->controller->translate(); @@ -83,7 +83,6 @@ public function testTranslateNoTranslatorEngine(): void /** * Test `translate` method * - * @covers ::translate() * @return void */ public function testTranslate(): void @@ -110,7 +109,7 @@ public function testTranslate(): void 'to' => 'it', 'translator' => 'dummy', ], - ]) + ]), ); $this->controller->translate(); $actual = $this->controller->viewBuilder()->getVar('translation'); @@ -123,7 +122,6 @@ public function testTranslate(): void * test `initialize` function * * @return void - * @covers ::initialize() */ public function testInitialize(): void { @@ -137,7 +135,7 @@ public function testInitialize(): void 'from' => 'en', 'to' => 'it', ], - ]) + ]), ); static::assertNotEmpty($this->controller->{'Translator'}); } diff --git a/tests/TestCase/Controller/TrashControllerTest.php b/tests/TestCase/Controller/TrashControllerTest.php index 0d08707d9..405873a81 100644 --- a/tests/TestCase/Controller/TrashControllerTest.php +++ b/tests/TestCase/Controller/TrashControllerTest.php @@ -17,13 +17,19 @@ use BEdita\SDK\BEditaClientException; use Cake\Http\ServerRequest; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\TrashController} Test Case - * - * @coversDefaultClass \App\Controller\TrashController - * @uses \App\Controller\TrashController */ +#[CoversClass(TrashController::class)] +#[CoversMethod(TrashController::class, 'delete')] +#[CoversMethod(TrashController::class, 'deleteData')] +#[CoversMethod(TrashController::class, 'deleteMulti')] +#[CoversMethod(TrashController::class, 'emptyTrash')] +#[CoversMethod(TrashController::class, 'listQuery')] +#[CoversMethod(TrashController::class, 'restore')] class TrashControllerTest extends BaseControllerTest { /** @@ -40,7 +46,7 @@ public function setUp(): void * * @var \App\Controller\TrashController */ - public $Trash; + public TrashController $Trash; /** * Create an object and "soft" delete it @@ -61,7 +67,7 @@ private function createTrashObject(): int ]; $response = $this->client->post(sprintf('/%s', $type), json_encode($body)); $id = $response['data']['id']; - $response = $this->client->delete(sprintf('/%s/%s', $type, $id)); + $this->client->delete(sprintf('/%s/%s', $type, $id)); return $id; } @@ -112,7 +118,6 @@ public function setupControllerAndData($auth = true, $query = true, $multiple = * Test `restore` method * * @return void - * @covers ::restore() */ public function testRestore(): void { @@ -133,7 +138,6 @@ public function testRestore(): void * Test `restore` method when unauthorized * * @return void - * @covers ::restore() */ public function testRestoreUnauthorized(): void { @@ -149,7 +153,6 @@ public function testRestoreUnauthorized(): void * Test `restore` method with multiple items * * @return void - * @covers ::restore() */ public function testRestoreMulti(): void { @@ -164,7 +167,6 @@ public function testRestoreMulti(): void * Test `restore` method failure with multiple items * * @return void - * @covers ::restore() */ public function testRestoreMultiFailure(): void { @@ -182,8 +184,6 @@ public function testRestoreMultiFailure(): void * Test `delete` method * * @return void - * @covers ::delete() - * @covers ::deleteMulti() */ public function testDelete(): void { @@ -209,7 +209,6 @@ public function testDelete(): void * Test `deleteData` method. For coverage and retrocompatibility only. * * @return void - * @covers ::deleteData() */ public function testDeleteData(): void { @@ -235,7 +234,6 @@ public function testDeleteData(): void * Test `deleteMulti` method. * * @return void - * @covers ::deleteMulti() */ public function testDeleteMulti(): void { @@ -262,7 +260,6 @@ public function testDeleteMulti(): void * Test `deleteMulti` method with exception * * @return void - * @covers ::deleteMulti() */ public function testDeleteMultiException(): void { @@ -275,7 +272,6 @@ public function testDeleteMultiException(): void * Test `delete` method with media object * * @return void - * @covers ::delete() */ public function testDeleteMediaWithStream(): void { @@ -328,7 +324,6 @@ public function testDeleteMediaWithStream(): void * Test `delete` method when unauthorized * * @return void - * @covers ::delete() */ public function testDeleteUnauthorized(): void { @@ -346,7 +341,6 @@ public function testDeleteUnauthorized(): void * Test `delete` method passing ids in POST data * * @return void - * @covers ::delete() */ public function testDeleteByIds(): void { @@ -362,7 +356,6 @@ public function testDeleteByIds(): void * Test `delete` method failure with multiple items * * @return void - * @covers ::delete() */ public function testDeleteByIdsFailure(): void { @@ -386,9 +379,6 @@ public function testDeleteByIdsFailure(): void * Test `emptyTrash` method * * @return void - * @covers ::emptyTrash() - * @covers ::listQuery() - * @covers ::deleteMulti() */ public function testEmpty(): void { @@ -406,8 +396,6 @@ public function testEmpty(): void * Test `emptyTrash` method with query filter * * @return void - * @covers ::emptyTrash() - * @covers ::listQuery() */ public function testEmptyFilter(): void { @@ -422,7 +410,6 @@ public function testEmptyFilter(): void * Test `emptyTrash` method when unauthorized * * @return void - * @covers ::emptyTrash() */ public function testEmptyUnauthorized(): void { diff --git a/tests/TestCase/Controller/TreeControllerTest.php b/tests/TestCase/Controller/TreeControllerTest.php index c74591e96..51d0a8afd 100644 --- a/tests/TestCase/Controller/TreeControllerTest.php +++ b/tests/TestCase/Controller/TreeControllerTest.php @@ -21,13 +21,27 @@ use Cake\Cache\Cache; use Cake\Http\ServerRequest; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\TreeController} Test Case - * - * @coversDefaultClass \App\Controller\TreeController - * @uses \App\Controller\TreeController */ +#[CoversClass(TreeController::class)] +#[CoversMethod(TreeController::class, 'fetchNodeData')] +#[CoversMethod(TreeController::class, 'fetchParentData')] +#[CoversMethod(TreeController::class, 'fetchParentsData')] +#[CoversMethod(TreeController::class, 'fetchTreeData')] +#[CoversMethod(TreeController::class, 'get')] +#[CoversMethod(TreeController::class, 'initialize')] +#[CoversMethod(TreeController::class, 'minimalData')] +#[CoversMethod(TreeController::class, 'minimalDataWithMeta')] +#[CoversMethod(TreeController::class, 'node')] +#[CoversMethod(TreeController::class, 'parent')] +#[CoversMethod(TreeController::class, 'parents')] +#[CoversMethod(TreeController::class, 'slug')] +#[CoversMethod(TreeController::class, 'slugPathCompact')] +#[CoversMethod(TreeController::class, 'treeData')] class TreeControllerTest extends BaseControllerTest { /** @@ -43,9 +57,6 @@ public function setUp(): void * Test `get` method * * @return void - * @covers ::get() - * @covers ::treeData() - * @covers ::fetchTreeData() */ public function testGet(): void { @@ -72,8 +83,6 @@ public function testGet(): void * Test `treeData` method on exception * * @return void - * @covers ::get() - * @covers ::treeData() */ public function testDataException(): void { @@ -101,10 +110,6 @@ public function fetchTreeData(array $query): array * Test `node` method * * @return void - * @covers ::node() - * @covers ::fetchNodeData() - * @covers ::minimalData() - * @covers ::slugPathCompact() */ public function testNode(): void { @@ -136,8 +141,6 @@ public function testNode(): void * Test `node` method * * @return void - * @covers ::node() - * @covers ::fetchNodeData() */ public function testNodeException(): void { @@ -161,9 +164,6 @@ public function testNodeException(): void * Test `parent` method * * @return void - * @covers ::parent() - * @covers ::fetchParentData() - * @covers ::minimalDataWithMeta() */ public function testParent(): void { @@ -195,9 +195,6 @@ public function testParent(): void * Test `parent` method * * @return void - * @covers ::parent() - * @covers ::fetchParentData() - * @covers ::minimalDataWithMeta() */ public function testParentNull(): void { @@ -222,8 +219,6 @@ public function testParentNull(): void * Test `parent` method * * @return void - * @covers ::parent() - * @covers ::fetchParentData() */ public function testParentException(): void { @@ -247,9 +242,6 @@ public function testParentException(): void * Test `parents` method * * @return void - * @covers ::parents() - * @covers ::fetchParentsData() - * @covers ::minimalData() */ public function testParents(): void { @@ -297,8 +289,6 @@ public function testParents(): void * Test `parents` method on exception * * @return void - * @covers ::parents() - * @covers ::fetchParentsData() */ public function testParentsException(): void { @@ -323,7 +313,6 @@ public function testParentsException(): void * Test `minimalData` method * * @return void - * @covers ::minimalData() */ public function testMinimalDataEmpty(): void { @@ -355,8 +344,6 @@ public function minData(array $data): array * Test `slug` method * * @return void - * @covers ::initialize() - * @covers ::slug() */ public function testSlug(): void { @@ -401,8 +388,6 @@ public function testSlug(): void * Test `slug` method on exception * * @return void - * @covers ::initialize() - * @covers ::slug() */ public function testSlugException(): void { diff --git a/tests/TestCase/Controller/UserProfileControllerTest.php b/tests/TestCase/Controller/UserProfileControllerTest.php index 9a676de51..1465806aa 100644 --- a/tests/TestCase/Controller/UserProfileControllerTest.php +++ b/tests/TestCase/Controller/UserProfileControllerTest.php @@ -20,14 +20,27 @@ use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Controller\UserProfileController} Test Case - * - * @coversDefaultClass \App\Controller\UserProfileController */ +#[CoversClass(UserProfileController::class)] +#[CoversMethod(UserProfileController::class, 'changeData')] +#[CoversMethod(UserProfileController::class, 'changePassword')] +#[CoversMethod(UserProfileController::class, 'initialize')] +#[CoversMethod(UserProfileController::class, 'view')] +#[CoversMethod(UserProfileController::class, 'save')] class UserProfileControllerTest extends TestCase { + /** + * Test api client + * + * @var \BEdita\SDK\BEditaClient + */ + public BEditaClient $client; + /** * @inheritDoc */ @@ -37,15 +50,6 @@ public function setUp(): void $this->loadRoutes(); } - public $UserProfileController; - - /** - * Test api client - * - * @var \BEdita\SDK\BEditaClient - */ - public $client; - /** * Setup api client and auth * @@ -61,11 +65,11 @@ private function setupApi(): void } /** - * Setup user profile controller for test + * test `initialize` function * * @return void */ - public function setupController(): void + public function testInitialize(): void { $this->setupApi(); $config = [ @@ -75,36 +79,36 @@ public function setupController(): void 'get' => [], ]; $request = new ServerRequest($config); - $this->UserProfileController = new class ($request) extends UserProfileController + $controller = new class ($request) extends UserProfileController { + public ?BEditaClient $apiClient; }; - } - - /** - * test `initialize` function - * - * @return void - * @covers ::initialize() - */ - public function testInitialize(): void - { - $this->setupController(); - static::assertNotEmpty($this->UserProfileController->{'Properties'}); + static::assertNotEmpty($controller->{'Properties'}); } /** * Test `view` method * * @return void - * @covers ::view() */ public function testView(): void { - $this->setupController(); - $this->UserProfileController->view(); + $this->setupApi(); + $config = [ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'get' => [], + ]; + $request = new ServerRequest($config); + $controller = new class ($request) extends UserProfileController + { + public ?BEditaClient $apiClient; + }; + $controller->view(); $vars = ['schema', 'object', 'properties']; foreach ($vars as $var) { - static::assertNotEmpty($this->UserProfileController->viewBuilder()->getVar($var)); + static::assertNotEmpty($controller->viewBuilder()->getVar($var)); } } @@ -112,11 +116,21 @@ public function testView(): void * Test `view` method on exception * * @return void - * @covers ::view() */ public function testViewOnException(): void { - $this->setupController(); + $this->setupApi(); + $config = [ + 'environment' => [ + 'REQUEST_METHOD' => 'GET', + ], + 'get' => [], + ]; + $request = new ServerRequest($config); + $controller = new class ($request) extends UserProfileController + { + public ?BEditaClient $apiClient; + }; // mock api get /auth/user $apiClient = $this->getMockBuilder(BEditaClient::class) @@ -125,21 +139,18 @@ public function testViewOnException(): void $apiClient->method('get') ->with('/auth/user') ->willThrowException(new BEditaClientException('test')); - $this->UserProfileController->apiClient = $apiClient; - $this->UserProfileController->view(); + $controller->apiClient = $apiClient; + $controller->view(); - static::assertNotEmpty($this->UserProfileController->viewBuilder()->getVar('schema')); - static::assertEmpty($this->UserProfileController->viewBuilder()->getVar('object')); - static::assertNotEmpty($this->UserProfileController->viewBuilder()->getVar('properties')); + static::assertNotEmpty($controller->viewBuilder()->getVar('schema')); + static::assertEmpty($controller->viewBuilder()->getVar('object')); + static::assertNotEmpty($controller->viewBuilder()->getVar('properties')); } /** * Test `save` method on exception * * @return void - * @covers ::save() - * @covers ::changePassword() - * @covers ::changeData() */ public function testSave(): void { @@ -152,9 +163,9 @@ public function testSave(): void 'name' => 'Gustavo', ], ]); - $this->UserProfileController = new class ($request) extends UserProfileController + $controller = new class ($request) extends UserProfileController { - public $apiClient; + public ?BEditaClient $apiClient; }; // mock api patch /auth/user @@ -164,9 +175,9 @@ public function testSave(): void $apiClient->method('patch') ->with('/auth/user') ->willThrowException(new BEditaClientException('some error, whatever')); - $this->UserProfileController->apiClient = $apiClient; - $this->UserProfileController->save(); - $flash = $this->UserProfileController->getRequest()->getSession()->read('Flash.flash'); + $controller->apiClient = $apiClient; + $controller->save(); + $flash = $controller->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('some error, whatever', (string)Hash::get($flash, '0.message')); // save with password data, no other changes @@ -179,16 +190,16 @@ public function testSave(): void 'old_password' => '__p4ssw0rd__', ], ]); - $this->UserProfileController = new class ($request) extends UserProfileController + $controller = new class ($request) extends UserProfileController { - public $apiClient; + public ?BEditaClient $apiClient; }; $apiClient->method('patch') ->with('/auth/user') ->willThrowException(new BEditaClientException('some error, whatever')); - $this->UserProfileController->apiClient = $apiClient; - $this->UserProfileController->save(); - $flash = $this->UserProfileController->getRequest()->getSession()->read('Flash.flash'); + $controller->apiClient = $apiClient; + $controller->save(); + $flash = $controller->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('some error, whatever', (string)Hash::get($flash, '0.message')); // save with no data changed @@ -201,16 +212,16 @@ public function testSave(): void '_actualAttributes' => json_encode(['name' => 'Gustavo']), ], ]); - $this->UserProfileController = new class ($request) extends UserProfileController + $controller = new class ($request) extends UserProfileController { - public $apiClient; + public ?BEditaClient $apiClient; }; $apiClient->method('patch') ->with('/auth/user') ->willThrowException(new BEditaClientException('some error, whatever')); - $this->UserProfileController->apiClient = $apiClient; - $this->UserProfileController->save(); - $flash = $this->UserProfileController->getRequest()->getSession()->read('Flash.flash'); + $controller->apiClient = $apiClient; + $controller->save(); + $flash = $controller->getRequest()->getSession()->read('Flash.flash'); static::assertEquals('User profile saved', (string)Hash::get($flash, '0.message')); } } diff --git a/tests/TestCase/Core/Exception/UploadExceptionTest.php b/tests/TestCase/Core/Exception/UploadExceptionTest.php index ff01387af..e195bcc3a 100644 --- a/tests/TestCase/Core/Exception/UploadExceptionTest.php +++ b/tests/TestCase/Core/Exception/UploadExceptionTest.php @@ -15,12 +15,15 @@ use App\Core\Exception\UploadException; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Core\Exception\UploadException} Test Case - * - * @coversDefaultClass \App\Core\Exception\UploadException */ +#[CoversClass(UploadException::class)] +#[CoversMethod(UploadException::class, 'codeToMessage')] class UploadExceptionTest extends TestCase { /** @@ -28,7 +31,7 @@ class UploadExceptionTest extends TestCase * * @return array */ - public function codeToMessageProvider(): array + public static function codeToMessageProvider(): array { return [ 'UPLOAD_ERR_INI_SIZE' => [ @@ -70,9 +73,8 @@ public function codeToMessageProvider(): array * Test `codeToMessage` method. * * @return void - * @dataProvider codeToMessageProvider() - * @covers ::codeToMessage() */ + #[DataProvider('codeToMessageProvider')] public function testCodeToMessage($code, $message): void { $e = new UploadException('', $code); diff --git a/tests/TestCase/Core/Filter/ImportFilterTest.php b/tests/TestCase/Core/Filter/ImportFilterTest.php index 4bcc79519..8e5aeaff6 100644 --- a/tests/TestCase/Core/Filter/ImportFilterTest.php +++ b/tests/TestCase/Core/Filter/ImportFilterTest.php @@ -13,16 +13,21 @@ namespace App\Test\TestCase\Core\Filter; +use App\Core\Filter\ImportFilter; use App\Core\Result\ImportResult; use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\TestSuite\TestCase; +use LogicException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Core\Filter\ImportFilter} Test Case - * - * @coversDefaultClass \App\Core\Filter\ImportFilter */ +#[CoversClass(ImportFilter::class)] +#[CoversMethod(ImportFilter::class, 'createAsyncJob')] class ImportFilterTest extends TestCase { /** @@ -44,11 +49,10 @@ class ImportFilterTest extends TestCase * * @return array */ - public function createAsyncJobProvider(): array + public static function createAsyncJobProvider(): array { $result = new ImportResult(); $filename = 'import.csv'; - $result->addMessage('info', (string)__('Job {0} to import file "{1}" scheduled.', $this->asyncJobId, $filename)); // almost the same info set by ImportFilter on createAsyncJob return [ 'logic exception: service name not defined' => [ @@ -56,7 +60,7 @@ public function createAsyncJobProvider(): array '', '', [], - new \LogicException('Cannot create async job without service name defined.'), + new LogicException('Cannot create async job without service name defined.'), ], 'job to import file scheduled' => [ 'App\Test\Utils\MyDummyImportFilter', @@ -77,15 +81,16 @@ public function createAsyncJobProvider(): array * @param array $options The async job options * @param \LogicException|\App\Core\Result\ImportResult $expected The result expected * @return void - * @dataProvider createAsyncJobProvider - * @covers ::createAsyncJob() */ + #[DataProvider('createAsyncJobProvider')] public function testCreateAsyncJob($filterClassName, $filename, $filepath, $options, $expected): void { - if ($expected instanceof \LogicException) { + if ($expected instanceof LogicException) { $this->expectException(get_class($expected)); $this->expectExceptionCode($expected->getCode()); $this->expectExceptionMessage($expected->getMessage()); + } else { + $expected->addMessage('info', (string)__('Job {0} to import file "{1}" scheduled.', $this->asyncJobId, $filename)); // almost the same info set by ImportFilter on createAsyncJob } $apiClient = $this->getMockBuilder(BEditaClient::class) ->setConstructorArgs(['https://media.example.com']) diff --git a/tests/TestCase/Core/Filter/ReadCSVTraitTest.php b/tests/TestCase/Core/Filter/ReadCSVTraitTest.php index 832e71a3a..b45ddbd6d 100644 --- a/tests/TestCase/Core/Filter/ReadCSVTraitTest.php +++ b/tests/TestCase/Core/Filter/ReadCSVTraitTest.php @@ -15,12 +15,17 @@ use App\Core\Filter\ReadCSVTrait; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Core\Filter\ReadCSVTrait} Test Case - * - * @coversDefaultClass \App\Core\Filter\ReadCSVTrait */ +#[CoversClass(ReadCSVTrait::class)] +#[CoversTrait(ReadCSVTrait::class)] +#[CoversMethod(ReadCSVTrait::class, 'readCSVFile')] class ReadCSVTraitTest extends TestCase { use ReadCSVTrait; @@ -30,7 +35,7 @@ class ReadCSVTraitTest extends TestCase * * @return array */ - public function readCSVFileProvider(): array + public static function readCSVFileProvider(): array { return [ 'empty' => [ @@ -56,10 +61,9 @@ public function readCSVFileProvider(): array * @param array $data Expected data * @param string $filepath CSV File path * @param array $options CSV options - * @dataProvider readCSVFileProvider - * @covers ::readCSVFile() * @return void */ + #[DataProvider('readCSVFileProvider')] public function testReadCSVFile(array $keys, array $data, string $filepath, array $options = []): void { $this->readCSVFile($filepath, $options); diff --git a/tests/TestCase/Core/I18n/DummyTranslator.php b/tests/TestCase/Core/I18n/DummyTranslator.php index 9a57ed63c..e71973f9d 100644 --- a/tests/TestCase/Core/I18n/DummyTranslator.php +++ b/tests/TestCase/Core/I18n/DummyTranslator.php @@ -26,9 +26,9 @@ public function setup(array $options = []): void } /** - * Translate an array of texts $texts from language source $from to language target $to + * Translate an array of texts $text from language source $from to language target $to * - * @param array $texts The texts to translate + * @param array $text The texts to translate * @param string $from The source language * @param string $to The target language * @return string The translation in json format as string, i.e. @@ -41,11 +41,11 @@ public function setup(array $options = []): void * ] * } */ - public function translate(array $texts, string $from, string $to): string + public function translate(array $text, string $from, string $to): string { $translation = []; - foreach ($texts as $text) { - $translation[] = sprintf('text: %s, from: %s, to: %s', $text, $from, $to); + foreach ($text as $tt) { + $translation[] = sprintf('text: %s, from: %s, to: %s', $tt, $from, $to); } return json_encode(compact('translation')); diff --git a/tests/TestCase/Core/Result/ImportResultTest.php b/tests/TestCase/Core/Result/ImportResultTest.php index f09621162..c97613bc6 100644 --- a/tests/TestCase/Core/Result/ImportResultTest.php +++ b/tests/TestCase/Core/Result/ImportResultTest.php @@ -11,23 +11,25 @@ * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase\Core\Filter; +namespace App\Test\TestCase\Core\Result; use App\Core\Result\ImportResult; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Core\Result\ImportResult} Test Case - * - * @coversDefaultClass \App\Core\Result\ImportResult */ +#[CoversClass(ImportResult::class)] +#[CoversMethod(ImportResult::class, '__construct')] +#[CoversMethod(ImportResult::class, 'reset')] class ImportResultTest extends TestCase { /** * Test `__construct` method * * @return void - * @covers ::__construct() */ public function testConstruct(): void { @@ -45,7 +47,6 @@ public function testConstruct(): void * Test `reset` method * * @return void - * @covers ::reset() */ public function testReset(): void { diff --git a/tests/TestCase/Core/Result/ResultTest.php b/tests/TestCase/Core/Result/ResultTest.php index 677d3b7b6..3f0ec663f 100644 --- a/tests/TestCase/Core/Result/ResultTest.php +++ b/tests/TestCase/Core/Result/ResultTest.php @@ -11,16 +11,20 @@ * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase\Core\Filter; +namespace App\Test\TestCase\Core\Result; use App\Core\Result\Result; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Core\Result\Result} Test Case - * - * @covers \App\Core\Result\Result */ +#[CoversClass(Result::class)] +#[CoversMethod(Result::class, 'addMessage')] +#[CoversMethod(Result::class, 'increment')] class ResultTest extends TestCase { /** @@ -28,7 +32,7 @@ class ResultTest extends TestCase * * @return array */ - public function addMessageProvider(): array + public static function addMessageProvider(): array { return [ 'info' => [ @@ -51,8 +55,8 @@ public function addMessageProvider(): array * @param string $name Message name * @param string $msg Message string * @return void - * @dataProvider addMessageProvider */ + #[DataProvider('addMessageProvider')] public function testAddMessage($expected, string $name, string $msg): void { $result = new Result(); @@ -67,7 +71,7 @@ public function testAddMessage($expected, string $name, string $msg): void * * @return array */ - public function incrementProvider(): array + public static function incrementProvider(): array { return [ 'errors' => [ @@ -87,8 +91,8 @@ public function incrementProvider(): array * @param mixed $expected Expected value * @param string $name Counter name * @return void - * @dataProvider incrementProvider */ + #[DataProvider('incrementProvider')] public function testIncrement($expected, string $name): void { $result = new Result(); diff --git a/tests/TestCase/Event/TreeCacheEventHandlerTest.php b/tests/TestCase/Event/TreeCacheEventHandlerTest.php index e383427f3..84476be38 100644 --- a/tests/TestCase/Event/TreeCacheEventHandlerTest.php +++ b/tests/TestCase/Event/TreeCacheEventHandlerTest.php @@ -20,13 +20,19 @@ use Cake\Event\EventManager; use Cake\TestSuite\TestCase; use Cake\Utility\Text; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Event\TreeCacheEventHandler} Test Case - * - * @coversDefaultClass \App\Event\TreeCacheEventHandler - * @uses \App\Event\TreeCacheEventHandler */ +#[CoversClass(TreeCacheEventHandler::class)] +#[CoversMethod(TreeCacheEventHandler::class, 'afterDelete')] +#[CoversMethod(TreeCacheEventHandler::class, 'afterSave')] +#[CoversMethod(TreeCacheEventHandler::class, 'afterSaveRelated')] +#[CoversMethod(TreeCacheEventHandler::class, 'implementedEvents')] +#[CoversMethod(TreeCacheEventHandler::class, 'updateCache')] class TreeCacheEventHandlerTest extends TestCase { /** @@ -50,7 +56,6 @@ public function tearDown(): void /** * Test `implementedEvents` method * - * @covers ::implementedEvents() * @return void */ public function testImplementedEvents(): void @@ -69,7 +74,7 @@ public function testImplementedEvents(): void * * @return array */ - public function dataProvider(): array + public static function dataProvider(): array { return [ 'afterDelete no data' => [ @@ -181,12 +186,8 @@ public function dataProvider(): array * @param array $data Event data. * @param bool $cacheClear Expected cache action. * @return void - * @dataProvider dataProvider - * @covers ::afterDelete() - * @covers ::afterSave() - * @covers ::afterSaveRelated() - * @covers ::updateCache() */ + #[DataProvider('dataProvider')] public function testAll(string $method, array $data, bool $cacheClear): void { $randomString = Text::uuid(); diff --git a/tests/TestCase/Form/ControlTest.php b/tests/TestCase/Form/ControlTest.php index 3cb0f228a..2a0d132e5 100644 --- a/tests/TestCase/Form/ControlTest.php +++ b/tests/TestCase/Form/ControlTest.php @@ -17,12 +17,30 @@ use App\Form\Form; use Cake\Core\Configure; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Form\Control} Test Case - * - * @coversDefaultClass \App\Form\Control */ +#[CoversClass(Control::class)] +#[CoversMethod(Control::class, 'categories')] +#[CoversMethod(Control::class, 'checkbox')] +#[CoversMethod(Control::class, 'checkboxNullable')] +#[CoversMethod(Control::class, 'control')] +#[CoversMethod(Control::class, 'date')] +#[CoversMethod(Control::class, 'datetime')] +#[CoversMethod(Control::class, 'email')] +#[CoversMethod(Control::class, 'enum')] +#[CoversMethod(Control::class, 'format')] +#[CoversMethod(Control::class, 'json')] +#[CoversMethod(Control::class, 'label')] +#[CoversMethod(Control::class, 'oneOf')] +#[CoversMethod(Control::class, 'oneOptions')] +#[CoversMethod(Control::class, 'plaintext')] +#[CoversMethod(Control::class, 'richtext')] +#[CoversMethod(Control::class, 'uri')] class ControlTest extends TestCase { /** @@ -30,7 +48,7 @@ class ControlTest extends TestCase * * @return array */ - public function controlProvider(): array + public static function controlProvider(): array { $value = 'something'; @@ -362,21 +380,8 @@ public function controlProvider(): array * @param mixed|null $value Property value. * @param array $expected The expected control. * @return void - * @dataProvider controlProvider() - * @covers ::control() - * @covers ::json() - * @covers ::richtext() - * @covers ::plaintext() - * @covers ::datetime() - * @covers ::date() - * @covers ::checkbox() - * @covers ::checkboxNullable() - * @covers ::enum() - * @covers ::categories() - * @covers ::oneOptions() - * @covers ::email() - * @covers ::uri() */ + #[DataProvider('controlProvider')] public function testControl(array $schema, string $type, $value, array $expected): void { $options = [ @@ -397,7 +402,7 @@ public function testControl(array $schema, string $type, $value, array $expected * * @return array */ - public function formatProvider(): array + public static function formatProvider(): array { return [ 'empty schema' => [ @@ -449,9 +454,8 @@ public function formatProvider(): array * @param array $schema Object schema array. * @param string $expected The expected format. * @return void - * @dataProvider formatProvider() - * @covers ::format() */ + #[DataProvider('formatProvider')] public function testFormat(array $schema, string $expected): void { $actual = Control::format($schema); @@ -464,7 +468,7 @@ public function testFormat(array $schema, string $expected): void * * @return array */ - public function oneOfProvider(): array + public static function oneOfProvider(): array { return [ 'empty schema' => [ @@ -497,9 +501,8 @@ public function oneOfProvider(): array * @param array $schema Object schema array. * @param array $expected The expected val. * @return void - * @dataProvider oneOfProvider() - * @covers ::oneOf() */ + #[DataProvider('oneOfProvider')] public function testOneOf(array $schema, array $expected): void { $actual = Control::oneOf($schema); @@ -512,7 +515,7 @@ public function testOneOf(array $schema, array $expected): void * * @return array */ - public function labelProvider(): array + public static function labelProvider(): array { return [ 'no custom config' => [ @@ -555,18 +558,17 @@ public function labelProvider(): array * @param mixed|null $customConfig The custom configuration * @param string $expected The expected label * @return void - * @dataProvider labelProvider() - * @covers ::label() */ + #[DataProvider('labelProvider')] public function testLabel(string $type, string $property, string $value, $customConfig, string $expected): void { if (!empty($customConfig)) { Configure::write( sprintf('Properties.%s', $type), array_merge( - (array)\Cake\Core\Configure::read(sprintf('Properties.%s', $type)), - ['labels' => ['options' => [$property => $customConfig]]] - ) + (array)Configure::read(sprintf('Properties.%s', $type)), + ['labels' => ['options' => [$property => $customConfig]]], + ), ); } $actual = Control::label($type, $property, $value); @@ -577,9 +579,8 @@ public function testLabel(string $type, string $property, string $value, $custom * Test `oneOptions` * * @return void - * @dataProvider labelProvider() - * @covers ::oneOptions() */ + #[DataProvider('labelProvider')] public function testOneOptions(): void { // empty one diff --git a/tests/TestCase/Form/ControlTypeTest.php b/tests/TestCase/Form/ControlTypeTest.php index 70c289b27..309bd2d0a 100644 --- a/tests/TestCase/Form/ControlTypeTest.php +++ b/tests/TestCase/Form/ControlTypeTest.php @@ -15,12 +15,21 @@ use App\Form\ControlType; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Form\ControlType} Test Case - * - * @coversDefaultClass \App\Form\ControlType */ +#[CoversClass(ControlType::class)] +#[CoversMethod(ControlType::class, 'fromArray')] +#[CoversMethod(ControlType::class, 'fromBoolean')] +#[CoversMethod(ControlType::class, 'fromInteger')] +#[CoversMethod(ControlType::class, 'fromNumber')] +#[CoversMethod(ControlType::class, 'fromObject')] +#[CoversMethod(ControlType::class, 'fromSchema')] +#[CoversMethod(ControlType::class, 'fromString')] class ControlTypeTest extends TestCase { /** @@ -28,7 +37,7 @@ class ControlTypeTest extends TestCase * * @return array */ - public function fromSchemaProvider(): array + public static function fromSchemaProvider(): array { return [ 'string' => [ @@ -179,15 +188,8 @@ public function fromSchemaProvider(): array * @param string $expected Expected result. * @param array|null $schema Schema. * @return void - * @dataProvider fromSchemaProvider() - * @covers ::fromSchema() - * @covers ::fromString() - * @covers ::fromNumber() - * @covers ::fromInteger() - * @covers ::fromBoolean() - * @covers ::fromArray() - * @covers ::fromObject() */ + #[DataProvider('fromSchemaProvider')] public function testFromSchema(string $expected, $schema): void { $actual = ControlType::fromSchema($schema); diff --git a/tests/TestCase/Form/CustomComponentControlTest.php b/tests/TestCase/Form/CustomComponentControlTest.php index c8960c03c..324c94b93 100644 --- a/tests/TestCase/Form/CustomComponentControlTest.php +++ b/tests/TestCase/Form/CustomComponentControlTest.php @@ -15,12 +15,16 @@ use App\Form\CustomComponentControl; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Form\CustomComponentControl} Test Case - * - * @coversDefaultClass \App\Form\CustomComponentControl */ +#[CoversClass(CustomComponentControl::class)] +#[CoversMethod(CustomComponentControl::class, 'control')] +#[CoversMethod(CustomComponentControl::class, 'jsonValue')] class CustomComponentControlTest extends TestCase { /** @@ -28,7 +32,7 @@ class CustomComponentControlTest extends TestCase * * @return array */ - public function controlProvider(): array + public static function controlProvider(): array { return [ 'default simple' => [ @@ -79,10 +83,8 @@ public function controlProvider(): array * @param mixed|null $value The field value. * @param array $options Control options. * @return void - * @dataProvider controlProvider() - * @covers ::control() - * @covers ::jsonValue() */ + #[DataProvider('controlProvider')] public function testCustomControl(array $expected, string $name, $value, array $options = []): void { $control = new CustomComponentControl(); diff --git a/tests/TestCase/Form/FormTest.php b/tests/TestCase/Form/FormTest.php index 89ef815ba..63305e208 100644 --- a/tests/TestCase/Form/FormTest.php +++ b/tests/TestCase/Form/FormTest.php @@ -18,12 +18,16 @@ use App\Form\Options; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Form\Form} Test Case - * - * @coversDefaultClass \App\Form\Form */ +#[CoversClass(Form::class)] +#[CoversMethod(Form::class, 'getMethod')] class FormTest extends TestCase { /** @@ -31,7 +35,7 @@ class FormTest extends TestCase * * @return array */ - public function getMethodProvider(): array + public static function getMethodProvider(): array { return [ 'name with chars to remove 1' => [ @@ -73,9 +77,8 @@ public function getMethodProvider(): array * @param array $options The options * @param array $expected The expected method array * @return void - * @dataProvider getMethodProvider() - * @covers ::getMethod */ + #[DataProvider('getMethodProvider')] public function testGetMethod(array $options, array $expected): void { $class = (string)Hash::get($options, 'class'); @@ -94,33 +97,13 @@ public function testGetMethod(array $options, array $expected): void * Test `getMethod` method exception 'not callable' * * @return void - * @covers ::getMethod */ public function testGetMethodNotCallable(): void { $methodName = 'dummy'; - $expected = new \InvalidArgumentException(sprintf('Method "%s" is not callable', $methodName)); + $expected = new InvalidArgumentException(sprintf('Method "%s" is not callable', $methodName)); static::expectException(get_class($expected)); static::expectExceptionMessage($expected->getMessage()); Form::getMethod(Form::class, $methodName); } - - /** - * Data provider for `testLabel`. - * - * @return array - */ - public function labelProvider(): array - { - return [ - 'empty' => [ - '', - '', - ], - 'dummy' => [ - 'dummy', - 'Dummy', - ], - ]; - } } diff --git a/tests/TestCase/Form/OptionsTest.php b/tests/TestCase/Form/OptionsTest.php index bcee76b19..5ba1916e3 100644 --- a/tests/TestCase/Form/OptionsTest.php +++ b/tests/TestCase/Form/OptionsTest.php @@ -16,12 +16,26 @@ use App\Form\Options; use Cake\Core\Configure; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Form\Options} Test Case - * - * @coversDefaultClass \App\Form\Options */ +#[CoversClass(Options::class)] +#[CoversMethod(Options::class, 'childrenOrder')] +#[CoversMethod(Options::class, 'confirmPassword')] +#[CoversMethod(Options::class, 'coords')] +#[CoversMethod(Options::class, 'customControl')] +#[CoversMethod(Options::class, 'dateRanges')] +#[CoversMethod(Options::class, 'endDate')] +#[CoversMethod(Options::class, 'lang')] +#[CoversMethod(Options::class, 'password')] +#[CoversMethod(Options::class, 'oldPassword')] +#[CoversMethod(Options::class, 'startDate')] +#[CoversMethod(Options::class, 'status')] +#[CoversMethod(Options::class, 'title')] class OptionsTest extends TestCase { /** @@ -32,7 +46,7 @@ class OptionsTest extends TestCase * * @return array */ - public function customControlProvider(): array + public static function customControlProvider(): array { return [ 'not custom' => [ @@ -230,20 +244,8 @@ public function customControlProvider(): array * @param array $expected Expected result. * @param array $config Configuration. * @return void - * @dataProvider customControlProvider() - * @covers ::customControl() - * @covers ::lang - * @covers ::dateRanges(() - * @covers ::startDate() - * @covers ::endDate() - * @covers ::status - * @covers ::oldPassword - * @covers ::password - * @covers ::confirmPassword - * @covers ::title - * @covers ::coords - * @covers ::childrenOrder */ + #[DataProvider('customControlProvider')] public function testCustomControl(string $name, $value, array $expected, array $config = []): void { if (!empty($config)) { diff --git a/tests/TestCase/Middleware/ConfigurationMiddlewareTest.php b/tests/TestCase/Middleware/ConfigurationMiddlewareTest.php index 1a7c2f574..c70227aac 100644 --- a/tests/TestCase/Middleware/ConfigurationMiddlewareTest.php +++ b/tests/TestCase/Middleware/ConfigurationMiddlewareTest.php @@ -10,7 +10,7 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\Middleware; +namespace App\Test\TestCase\Middleware; use App\Middleware\ConfigurationMiddleware; use App\Utility\CacheTools; @@ -19,22 +19,23 @@ use Cake\Http\Response; use Cake\Http\ServerRequestFactory; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; /** * {@see \App\Middleware\ConfigurationMiddleware} Test Case - * - * @coversDefaultClass \App\Middleware\ConfigurationMiddleware */ +#[CoversClass(ConfigurationMiddleware::class)] +#[CoversMethod(ConfigurationMiddleware::class, 'process')] class ConfigurationMiddlewareTest extends TestCase { /** * Test `process` method. * * @return void - * @covers ::process() */ public function testProcess(): void { diff --git a/tests/TestCase/Middleware/ProjectMiddlewareTest.php b/tests/TestCase/Middleware/ProjectMiddlewareTest.php index decad591a..99cf90354 100644 --- a/tests/TestCase/Middleware/ProjectMiddlewareTest.php +++ b/tests/TestCase/Middleware/ProjectMiddlewareTest.php @@ -10,7 +10,7 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\Middleware; +namespace App\Test\TestCase\Middleware; use App\Application; use App\Middleware\ProjectMiddleware; @@ -18,15 +18,20 @@ use Cake\Http\Response; use Cake\Http\ServerRequestFactory; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; /** * {@see \App\Middleware\ProjectMiddleware} Test Case - * - * @coversDefaultClass \App\Middleware\ProjectMiddleware */ +#[CoversClass(ProjectMiddleware::class)] +#[CoversMethod(ProjectMiddleware::class, '__construct')] +#[CoversMethod(ProjectMiddleware::class, 'detectProject')] +#[CoversMethod(ProjectMiddleware::class, 'process')] class ProjectMiddlewareTest extends TestCase { /** @@ -34,7 +39,7 @@ class ProjectMiddlewareTest extends TestCase * * @return array */ - public function invokeProvider(): array + public static function invokeProvider(): array { return [ 'test session' => [ @@ -68,11 +73,8 @@ public function invokeProvider(): array * @param int $expected The HTTP status code expected * @param array $data Request session data * @return void - * @dataProvider invokeProvider - * @covers ::__construct() - * @covers ::process() - * @covers ::detectProject() */ + #[DataProvider('invokeProvider')] public function testInvoke($expected, $data): void { Configure::write('Project', null); diff --git a/tests/TestCase/Middleware/RecoveryMiddlewareTest.php b/tests/TestCase/Middleware/RecoveryMiddlewareTest.php index 211c4907b..64109f698 100644 --- a/tests/TestCase/Middleware/RecoveryMiddlewareTest.php +++ b/tests/TestCase/Middleware/RecoveryMiddlewareTest.php @@ -10,13 +10,14 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\Middleware; +namespace App\Test\TestCase\Middleware; use App\Controller\AppController; use App\Identifier\ApiIdentifier; use App\Middleware\RecoveryMiddleware; use Authentication\AuthenticationService; -use Authentication\Identifier\IdentifierInterface; +use Authentication\Authenticator\UnauthenticatedException; +use Authentication\Identifier\AbstractIdentifier; use Authentication\Identity; use BEdita\WebTools\ApiClientProvider; use Cake\Core\Configure; @@ -24,15 +25,18 @@ use Cake\Http\ServerRequest; use Cake\Http\ServerRequestFactory; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; /** * {@see \App\Middleware\RecoveryMiddleware} Test Case - * - * @coversDefaultClass \App\Middleware\RecoveryMiddleware */ +#[CoversClass(RecoveryMiddleware::class)] +#[CoversMethod(RecoveryMiddleware::class, 'process')] +#[CoversMethod(RecoveryMiddleware::class, 'check')] class RecoveryMiddlewareTest extends TestCase { /** @@ -46,8 +50,6 @@ class RecoveryMiddlewareTest extends TestCase * Test `process` method. * * @return void - * @covers ::process() - * @covers ::check() */ public function testProcessAndCheck(): void { @@ -75,7 +77,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface // user non admin $user = new Identity(['id' => 1, 'roles' => ['guest']]); $this->AppController->Authentication->setIdentity($user); - $this->expectException(\Authentication\Authenticator\UnauthenticatedException::class); + $this->expectException(UnauthenticatedException::class); $middleware->process($this->AppController->getRequest()->withAttribute('identity', $user), $handler); } @@ -95,16 +97,16 @@ protected function setupControllerAndLogin(): void 'username' => env('BEDITA_ADMIN_USR'), 'password' => env('BEDITA_ADMIN_PWD'), ], - ]) + ]), ); ApiClientProvider::getApiClient()->setupTokens([]); // reset client $service = new AuthenticationService(); - $service->loadIdentifier(ApiIdentifier::class); $service->loadAuthenticator('Authentication.Form', [ + 'identifier' => ApiIdentifier::class, 'fields' => [ - IdentifierInterface::CREDENTIAL_USERNAME => 'username', - IdentifierInterface::CREDENTIAL_PASSWORD => 'password', + AbstractIdentifier::CREDENTIAL_USERNAME => 'username', + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password', ], ]); $this->AppController->setRequest($this->AppController->getRequest()->withAttribute('authentication', $service)); diff --git a/tests/TestCase/Middleware/StatusMiddlewareTest.php b/tests/TestCase/Middleware/StatusMiddlewareTest.php index 1b76afe6a..2bb925f3b 100644 --- a/tests/TestCase/Middleware/StatusMiddlewareTest.php +++ b/tests/TestCase/Middleware/StatusMiddlewareTest.php @@ -3,6 +3,7 @@ namespace App\Test\TestCase\Middleware; +use App\Middleware\StatusMiddleware; use BEdita\WebTools\ApiClientProvider; use Cake\Core\Configure; use Cake\TestSuite\IntegrationTestTrait; @@ -10,13 +11,16 @@ use GuzzleHttp\Exception\ConnectException; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\Psr7\Response; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Http\Message\RequestInterface; /** * {@see \App\Middleware\StatusMiddleware} Test Case. - * - * @covers \App\Middleware\StatusMiddleware */ +#[CoversClass(StatusMiddleware::class)] +#[CoversMethod(StatusMiddleware::class, 'process')] class StatusMiddlewareTest extends TestCase { use IntegrationTestTrait; @@ -36,7 +40,7 @@ protected function tearDown(): void * * @return array[] */ - public function processProvider(): array + public static function processProvider(): array { $config = function (?int $status): array { return [ @@ -73,8 +77,8 @@ public function processProvider(): array * @param string $method Request method. * @param array $config Configuration. * @return void - * @dataProvider processProvider() */ + #[DataProvider('processProvider')] public function testProcess(int $expectedStatus, ?string $expectedBody, string $url, string $method = 'GET', array $config = []): void { Configure::write($config); diff --git a/tests/TestCase/PluginTest.php b/tests/TestCase/PluginTest.php index a13d8b402..9ae26bb10 100644 --- a/tests/TestCase/PluginTest.php +++ b/tests/TestCase/PluginTest.php @@ -15,19 +15,20 @@ use App\Plugin; use Cake\Core\Configure; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** - * \App\Plugin Test Case - * - * @coversDefaultClass \App\Plugin + * {@see \App\Plugin} Test Case */ +#[CoversClass(Plugin::class)] +#[CoversMethod(Plugin::class, 'loadedAppPlugins')] class PluginTest extends TestCase { /** * Test loaded app plugins * * @return void - * @covers ::loadedAppPlugins() */ public function testLoadedAppPlugins(): void { diff --git a/tests/TestCase/Utility/ApiClientTraitTest.php b/tests/TestCase/Utility/ApiClientTraitTest.php index 148815383..8a721e137 100644 --- a/tests/TestCase/Utility/ApiClientTraitTest.php +++ b/tests/TestCase/Utility/ApiClientTraitTest.php @@ -16,12 +16,14 @@ use App\Utility\ApiClientTrait; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\Utility\ApiClientTrait} Test Case - * - * @coversDefaultClass \App\Utility\ApiClientTrait */ +#[CoversClass(ApiClientTrait::class)] +#[CoversMethod(ApiClientTrait::class, 'getClient')] class ApiClientTraitTest extends TestCase { use ApiClientTrait; @@ -30,7 +32,6 @@ class ApiClientTraitTest extends TestCase * Test getClient method. * * @return void - * @covers ::getClient() */ public function testGetClient(): void { diff --git a/tests/TestCase/Utility/ApiConfigTraitTest.php b/tests/TestCase/Utility/ApiConfigTraitTest.php index ecb397340..989ce7513 100644 --- a/tests/TestCase/Utility/ApiConfigTraitTest.php +++ b/tests/TestCase/Utility/ApiConfigTraitTest.php @@ -23,12 +23,22 @@ use Cake\Core\Configure; use Cake\Http\Exception\BadRequestException; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\Utility\ApiConfigTrait} Test Case - * - * @coversDefaultClass \App\Utility\ApiConfigTrait */ +#[CoversClass(ApiConfigTrait::class)] +#[CoversTrait(ApiConfigTrait::class)] +#[CoversMethod(ApiConfigTrait::class, 'authEndpointId')] +#[CoversMethod(ApiConfigTrait::class, 'fetchConfig')] +#[CoversMethod(ApiConfigTrait::class, 'isAppConfig')] +#[CoversMethod(ApiConfigTrait::class, 'managerApplicationId')] +#[CoversMethod(ApiConfigTrait::class, 'readApiConfig')] +#[CoversMethod(ApiConfigTrait::class, 'saveApiConfig')] class ApiConfigTraitTest extends TestCase { use ApiConfigTrait; @@ -59,7 +69,7 @@ public function tearDown(): void * * @return array */ - public function readApiConfigProvider(): array + public static function readApiConfigProvider(): array { return [ 'ok' => [ @@ -86,10 +96,8 @@ public function readApiConfigProvider(): array * @param mixed $expected Expected result. * @param array $content Test cache content. * @return void - * @covers ::readApiConfig() - * @covers ::fetchConfig() - * @dataProvider readApiConfigProvider() */ + #[DataProvider('readApiConfigProvider')] public function testReadApiCache($expected, array $content): void { Configure::delete('Export'); @@ -118,8 +126,6 @@ public function testReadApiConfig(): void * Test `readApiConfig`, exception case. * * @return void - * @covers ::readApiConfig() - * @covers ::fetchConfig() */ public function testReadException(): void { @@ -142,7 +148,6 @@ public function testReadException(): void * Test `managerApplicationId`. * * @return void - * @covers ::managerApplicationId() */ public function testManagerApplicationId(): void { @@ -156,7 +161,6 @@ public function testManagerApplicationId(): void * Test `authEndpointId`. * * @return void - * @covers ::authEndpointId() */ public function testAuthEndpointId(): void { @@ -170,9 +174,6 @@ public function testAuthEndpointId(): void * Test `save`. * * @return void - * @covers ::saveApiConfig() - * @covers ::fetchConfig() - * @covers ::isAppConfig() */ public function testSave(): void { @@ -195,7 +196,6 @@ public function testSave(): void * Test bad configuration key save * * @return void - * @covers ::saveApiConfig() */ public function testSaveBadKey(): void { @@ -218,55 +218,53 @@ private function prepareClient(): void ->setConstructorArgs(['https://api.example.org']) ->getMock(); $apiClient->method('get') - ->will( - $this->returnCallback( - function ($param) { - if ($param === '/config') { - return [ - 'data' => [ - [ - 'id' => 123, - 'attributes' => [ - 'name' => 'Gustavo', - 'content' => '{}', - 'context' => 'app', - 'application_id' => 456, - ], - ], - [ - 'id' => 124, - 'attributes' => [ - 'name' => 'Export', - 'content' => '{"limit":666}', - 'context' => 'app', - 'application_id' => 456, - ], - ], - [ - 'id' => 666, - 'attributes' => [ - 'name' => 'Supporto', - ], + ->willReturnCallback( + function ($param) { + if ($param === '/config') { + return [ + 'data' => [ + [ + 'id' => 123, + 'attributes' => [ + 'name' => 'Gustavo', + 'content' => '{}', + 'context' => 'app', + 'application_id' => 456, ], ], - ]; - } - if ($param === '/admin/applications') { - return [ - 'data' => [ - ['id' => 456, 'attributes' => ['name' => 'manager']], + [ + 'id' => 124, + 'attributes' => [ + 'name' => 'Export', + 'content' => '{"limit":666}', + 'context' => 'app', + 'application_id' => 456, + ], ], - ]; - } - if ($param === '/admin/endpoints') { - return [ - 'data' => [ - ['id' => 123456789, 'attributes' => ['name' => 'auth']], + [ + 'id' => 666, + 'attributes' => [ + 'name' => 'Supporto', + ], ], - ]; - } + ], + ]; + } + if ($param === '/admin/applications') { + return [ + 'data' => [ + ['id' => 456, 'attributes' => ['name' => 'manager']], + ], + ]; + } + if ($param === '/admin/endpoints') { + return [ + 'data' => [ + ['id' => 123456789, 'attributes' => ['name' => 'auth']], + ], + ]; } - ) + }, ); $apiClient->method('post')->willReturn([]); $apiClient->method('patch')->willReturn([]); diff --git a/tests/TestCase/Utility/ApplicationsTest.php b/tests/TestCase/Utility/ApplicationsTest.php index 652299186..9a0eded6d 100644 --- a/tests/TestCase/Utility/ApplicationsTest.php +++ b/tests/TestCase/Utility/ApplicationsTest.php @@ -10,26 +10,28 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase; +namespace App\Test\TestCase\Utility; use App\Utility\Applications; use BEdita\SDK\BEditaClient; use BEdita\SDK\BEditaClientException; use BEdita\WebTools\ApiClientProvider; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** - * App\Utility\Applications Test Case - * - * @coversDefaultClass App\Utility\Applications + * {@see \App\Utility\Applications} Test Case */ +#[CoversClass(Applications::class)] +#[CoversMethod(Applications::class, 'getName')] +#[CoversMethod(Applications::class, 'list')] class ApplicationsTest extends TestCase { /** * Test `list` method. * * @return void - * @covers ::list() */ public function testList(): void { @@ -70,7 +72,6 @@ public function testList(): void * Test `list` method, exception case. * * @return void - * @covers ::list() */ public function testListException(): void { @@ -89,7 +90,6 @@ public function testListException(): void * Test `getName` method * * @return void - * @covers ::getName() */ public function testGetName(): void { diff --git a/tests/TestCase/Utility/CacheToolsTest.php b/tests/TestCase/Utility/CacheToolsTest.php index e773857c8..b1119ea48 100644 --- a/tests/TestCase/Utility/CacheToolsTest.php +++ b/tests/TestCase/Utility/CacheToolsTest.php @@ -10,18 +10,23 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase; +namespace App\Test\TestCase\Utility; use App\Utility\CacheTools; use BEdita\WebTools\ApiClientProvider; use Cake\Cache\Cache; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** - * App\Utility\CacheTools Test Case - * - * @coversDefaultClass App\Utility\CacheTools + * {@see \App\Utility\CacheTools} Test Case */ +#[CoversClass(CacheTools::class)] +#[CoversMethod(CacheTools::class, 'cacheKey')] +#[CoversMethod(CacheTools::class, 'existsCount')] +#[CoversMethod(CacheTools::class, 'getModuleCount')] +#[CoversMethod(CacheTools::class, 'setModuleCount')] class CacheToolsTest extends TestCase { /** @@ -46,7 +51,6 @@ public function tearDown(): void * Test `cacheKey` method. * * @return void - * @covers ::cacheKey() */ public function testCacheKey(): void { @@ -60,9 +64,6 @@ public function testCacheKey(): void * Test `getModuleCount` and `setModuleCount` methods. * * @return void - * @covers ::existsCount() - * @covers ::setModuleCount() - * @covers ::getModuleCount() */ public function testGetSetModuleCount(): void { diff --git a/tests/TestCase/Utility/DateRangesToolsTest.php b/tests/TestCase/Utility/DateRangesToolsTest.php index c0c12bfb0..a145182fa 100644 --- a/tests/TestCase/Utility/DateRangesToolsTest.php +++ b/tests/TestCase/Utility/DateRangesToolsTest.php @@ -1,16 +1,23 @@ [ @@ -258,12 +265,8 @@ public function prepareProvider(): array * @param array $dateRanges Date ranges to format. * @param array $expected Expected result. * @return void - * @dataProvider prepareProvider() - * @covers ::prepare() - * @covers ::parseParams() - * @covers ::cleanParams() - * @covers ::isOneDayRange() */ + #[DataProvider('prepareProvider')] public function testPrepare(array $dateRanges, array $expected): void { $actual = DateRangesTools::prepare($dateRanges); @@ -274,7 +277,6 @@ public function testPrepare(array $dateRanges, array $expected): void * Test `toString` method. * * @return void - * @covers ::toString() */ public function testToString(): void { diff --git a/tests/TestCase/Utility/MessageTest.php b/tests/TestCase/Utility/MessageTest.php index 59b0577fb..e69a368a3 100644 --- a/tests/TestCase/Utility/MessageTest.php +++ b/tests/TestCase/Utility/MessageTest.php @@ -12,17 +12,22 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase; +namespace App\Test\TestCase\Utility; use App\Utility\Message; use BEdita\SDK\BEditaClientException; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** - * App\Utility\Message Test Case - * - * @coversDefaultClass App\Utility\Message + * {@see \App\Utility\Message} Test Case */ +#[CoversClass(Message::class)] +#[CoversMethod(Message::class, '__construct')] +#[CoversMethod(Message::class, 'get')] +#[CoversMethod(Message::class, 'prepareDetail')] class MessageTest extends TestCase { /** @@ -30,7 +35,7 @@ class MessageTest extends TestCase * * @return array */ - public function getProvider(): array + public static function getProvider(): array { return [ '400 invalid data' => [ @@ -126,11 +131,8 @@ public function getProvider(): array * @param \BEdita\SDK\BEditaClientException $error The error * @param string $expected The expected result * @return void - * @covers ::get() - * @covers ::__construct() - * @covers ::prepareDetail() - * @dataProvider getProvider */ + #[DataProvider('getProvider')] public function testGet(BEditaClientException $error, string $expected): void { $message = new Message($error); diff --git a/tests/TestCase/Utility/OEmbedTest.php b/tests/TestCase/Utility/OEmbedTest.php index 180f79a80..1565a4ac4 100644 --- a/tests/TestCase/Utility/OEmbedTest.php +++ b/tests/TestCase/Utility/OEmbedTest.php @@ -10,16 +10,20 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase; +namespace App\Test\TestCase\Utility; use App\Utility\OEmbed; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** - * App\Utility\OEmbed Test Case - * - * @coversDefaultClass App\Utility\OEmbed + * {@see \App\Utility\OEmbed} Test Case */ +#[CoversClass(OEmbed::class)] +#[CoversMethod(OEmbed::class, 'findProvider')] +#[CoversMethod(OEmbed::class, 'readMetadata')] class OEmbedTest extends TestCase { /** @@ -27,7 +31,7 @@ class OEmbedTest extends TestCase * * @return array */ - public function readMetadataProvider(): array + public static function readMetadataProvider(): array { return [ 'not found' => [ @@ -74,16 +78,14 @@ public function readMetadataProvider(): array * Test `readMetadata` method * * @return void - * @covers ::readMetadata() - * @covers ::findProvider() - * @dataProvider readMetadataProvider */ + #[DataProvider('readMetadataProvider')] public function testReadMetadata(array $expected, string $url, array $oembedResponse): void { $oembed = new class () extends OEmbed { - public $json = []; - protected function fetchJson(string $oembedUrl, array $options = []): array + public array $json = []; + protected function fetchJson(string $oEmbedUrl, array $options = []): array { return $this->json; } diff --git a/tests/TestCase/Utility/PermissionsTraitTest.php b/tests/TestCase/Utility/PermissionsTraitTest.php index 81045a16d..bea442c8d 100644 --- a/tests/TestCase/Utility/PermissionsTraitTest.php +++ b/tests/TestCase/Utility/PermissionsTraitTest.php @@ -20,12 +20,22 @@ use BEdita\SDK\BEditaClient; use BEdita\WebTools\ApiClientProvider; use Cake\Cache\Cache; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversTrait; /** * {@see \App\Utility\PermissionsTrait} Test Case - * - * @coversDefaultClass \App\Utility\PermissionsTrait */ +#[CoversClass(PermissionsTrait::class)] +#[CoversTrait(PermissionsTrait::class)] +#[CoversMethod(PermissionsTrait::class, 'addPermissions')] +#[CoversMethod(PermissionsTrait::class, 'objectPermissionsIds')] +#[CoversMethod(PermissionsTrait::class, 'removePermissions')] +#[CoversMethod(PermissionsTrait::class, 'roles')] +#[CoversMethod(PermissionsTrait::class, 'rolesByIds')] +#[CoversMethod(PermissionsTrait::class, 'rolesByNames')] +#[CoversMethod(PermissionsTrait::class, 'savePermissions')] class PermissionsTraitTest extends BaseControllerTest { use PermissionsTrait; @@ -52,7 +62,6 @@ public function tearDown(): void * Test `savePermission` method. * * @return void - * @covers ::savePermissions() */ public function testSavePermissions(): void { @@ -84,7 +93,6 @@ public function testSavePermissions(): void * Test `addPermissions` method * * @return void - * @covers ::addPermissions() */ public function testAddPermissions(): void { @@ -101,7 +109,6 @@ public function testAddPermissions(): void * Test `removePermissions` method * * @return void - * @covers ::removePermissions() */ public function testRemovePermissions(): void { @@ -118,7 +125,6 @@ public function testRemovePermissions(): void * Test `objectPermissionsIds` method * * @return void - * @covers ::objectPermissionsIds() */ public function testObjectPermissionsIds(): void { @@ -151,7 +157,6 @@ public function testObjectPermissionsIds(): void * Test `roles` method * * @return void - * @covers ::roles() */ public function testRoles(): void { @@ -164,7 +169,6 @@ public function testRoles(): void * Test `rolesByNames` method * * @return void - * @covers ::rolesByNames() */ public function testRolesByNames(): void { @@ -183,7 +187,6 @@ public function testRolesByNames(): void * Test `rolesByIds` method * * @return void - * @covers ::rolesByIds() */ public function testRolesByIds(): void { diff --git a/tests/TestCase/Utility/RelationsToolsTest.php b/tests/TestCase/Utility/RelationsToolsTest.php index 5381189ce..279c7a7be 100644 --- a/tests/TestCase/Utility/RelationsToolsTest.php +++ b/tests/TestCase/Utility/RelationsToolsTest.php @@ -5,19 +5,20 @@ use App\Utility\RelationsTools; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * App\Utility\RelationsTools Test Case - * - * @coversDefaultClass App\Utility\RelationsTools */ +#[CoversClass(RelationsTools::class)] +#[CoversMethod(RelationsTools::class, 'toString')] class RelationsToolsTest extends TestCase { /** * Test `toString` method. * * @return void - * @covers ::toString() */ public function testToString(): void { diff --git a/tests/TestCase/Utility/SchemaTest.php b/tests/TestCase/Utility/SchemaTest.php index 1a37364f6..bc552203e 100644 --- a/tests/TestCase/Utility/SchemaTest.php +++ b/tests/TestCase/Utility/SchemaTest.php @@ -10,23 +10,24 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase; +namespace App\Test\TestCase\Utility; use App\Utility\Schema; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * App\Utility\Schema Test Case - * - * @coversDefaultClass App\Utility\Schema */ +#[CoversClass(Schema::class)] +#[CoversMethod(Schema::class, 'rightTypes')] class SchemaTest extends TestCase { /** * Test `rightTypes` method * * @return void - * @covers ::rightTypes() */ public function testRightTypes(): void { diff --git a/tests/TestCase/Utility/SchemaTraitTest.php b/tests/TestCase/Utility/SchemaTraitTest.php index f45ee16e8..e8249df69 100644 --- a/tests/TestCase/Utility/SchemaTraitTest.php +++ b/tests/TestCase/Utility/SchemaTraitTest.php @@ -26,15 +26,20 @@ use BEdita\WebTools\ApiClientProvider; use Cake\Cache\Cache; use Cake\Controller\Controller; +use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversTrait; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * {@see \App\Utility\SchemaTrait} Test Case - * - * @coversDefaultClass \App\Utility\SchemaTrait */ +#[CoversClass(SchemaTrait::class)] +#[CoversTrait(SchemaTrait::class)] +#[CoversMethod(SchemaTrait::class, 'getMeta')] class SchemaTraitTest extends TestCase { use SchemaTrait; @@ -48,7 +53,7 @@ public function setUp(): void { Cache::enable(); Cache::clearAll(); - $controller = new Controller(); + $controller = new Controller(new ServerRequest()); $controller->setRequest($controller->getRequest()->withAttribute('authentication', $this->getAuthenticationServiceMock())); $registry = $controller->components(); $registry->load('Authentication.Authentication'); @@ -75,7 +80,6 @@ public function tearDown(): void * Test `getMeta`. * * @return void - * @covers ::getMeta() */ public function testGetMeta(): void { @@ -105,17 +109,19 @@ public function testGetMeta(): void * Test `getMeta` with exception. * * @return void - * @covers ::getMeta() */ public function testGetMetaException(): void { - $expectedException = new BEditaClientException('test'); - $apiClient = $this->getMockBuilder(BEditaClient::class) - ->setConstructorArgs(['https://api.example.org']) - ->getMock(); - $apiClient->method('get') - ->with('/home') - ->willThrowException($expectedException); + $apiClient = new class ('https://api.example.org') extends BEditaClient { + public function get(string $path, ?array $query = null, ?array $headers = null): ?array + { + if ($path === 'home') { + throw new BEditaClientException('test'); + } + + return []; + } + }; ApiClientProvider::setApiClient($apiClient); /** @var \Authentication\Identity $user */ $user = $this->Authentication->getIdentity(); diff --git a/tests/TestCase/Utility/SystemTest.php b/tests/TestCase/Utility/SystemTest.php index dfa8d8964..11438d32c 100644 --- a/tests/TestCase/Utility/SystemTest.php +++ b/tests/TestCase/Utility/SystemTest.php @@ -13,16 +13,19 @@ * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase; +namespace App\Test\TestCase\Utility; use App\Utility\System; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * App\Utility\System Test Case - * - * @coversDefaultClass App\Utility\System */ +#[CoversClass(System::class)] +#[CoversMethod(System::class, 'compareBEditaApiVersion')] class SystemTest extends TestCase { /** @@ -30,7 +33,7 @@ class SystemTest extends TestCase * * @return array */ - public function compareBEditaApiVersionProvider(): array + public static function compareBEditaApiVersionProvider(): array { return [ 'same version' => ['4.0.0', '4.0.0', true], @@ -47,9 +50,8 @@ public function compareBEditaApiVersionProvider(): array * @param string $v2 The version to compare against * @param bool $expected The expected result * @return void - * @covers ::compareBEditaApiVersion() - * @dataProvider compareBEditaApiVersionProvider */ + #[DataProvider('compareBEditaApiVersionProvider')] public function testCompareBEditaApiVersion(string $v1, string $v2, bool $expected): void { $actual = System::compareBEditaApiVersion($v1, $v2); diff --git a/tests/TestCase/Utility/TranslateTest.php b/tests/TestCase/Utility/TranslateTest.php index aaad06180..b98c94537 100644 --- a/tests/TestCase/Utility/TranslateTest.php +++ b/tests/TestCase/Utility/TranslateTest.php @@ -10,17 +10,20 @@ * * See LICENSE.LGPL or for more details. */ -namespace App\Test\TestCase; +namespace App\Test\TestCase\Utility; use App\Utility\Translate; use Cake\Core\Configure; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * App\Utility\Translate Test Case - * - * @coversDefaultClass App\Utility\Translate */ +#[CoversClass(Translate::class)] +#[CoversMethod(Translate::class, 'get')] class TranslateTest extends TestCase { /** @@ -28,7 +31,7 @@ class TranslateTest extends TestCase * * @return array */ - public function translateProvider(): array + public static function translateProvider(): array { return [ 'empty' => [ @@ -52,9 +55,8 @@ public function translateProvider(): array * @param string $name The field name * @param string|null $expected The expected result * @return void - * @dataProvider translateProvider() - * @covers ::get() */ + #[DataProvider('translateProvider')] public function testTranslate(string $name, ?string $expected): void { $actual = Translate::get($name); @@ -65,7 +67,6 @@ public function testTranslate(string $name, ?string $expected): void * Test `get` method, plugin case * * @return void - * @covers ::get() */ public function testPlugin(): void { diff --git a/tests/TestCase/View/AppViewTest.php b/tests/TestCase/View/AppViewTest.php index bf2b62550..80d4b3058 100644 --- a/tests/TestCase/View/AppViewTest.php +++ b/tests/TestCase/View/AppViewTest.php @@ -16,19 +16,21 @@ use App\View\AppView; use Cake\Core\Configure; use Cake\TestSuite\TestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\View\AppView} Test Case - * - * @coversDefaultClass \App\View\AppView */ +#[CoversClass(AppView::class)] +#[CoversMethod(AppView::class, 'initialize')] +#[CoversMethod(AppView::class, '_getElementFileName')] class AppViewTest extends TestCase { /** * Test `initialize` method * * @return void - * @covers ::initialize() */ public function testInitialize(): void { @@ -42,7 +44,6 @@ public function testInitialize(): void * Test `_getElementFileName` method * * @return void - * @covers ::_getElementFileName() */ public function testCustomElement(): void { diff --git a/tests/TestCase/View/Helper/AdminHelperTest.php b/tests/TestCase/View/Helper/AdminHelperTest.php index bd0699946..857826194 100644 --- a/tests/TestCase/View/Helper/AdminHelperTest.php +++ b/tests/TestCase/View/Helper/AdminHelperTest.php @@ -16,12 +16,18 @@ use App\View\Helper\AdminHelper; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\AdminHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\AdminHelper */ +#[CoversClass(AdminHelper::class)] +#[CoversMethod(AdminHelper::class, 'control')] +#[CoversMethod(AdminHelper::class, 'getDictionary')] +#[CoversMethod(AdminHelper::class, 'initialize')] +#[CoversMethod(AdminHelper::class, 'setDictionary')] class AdminHelperTest extends TestCase { /** @@ -29,7 +35,7 @@ class AdminHelperTest extends TestCase * * @return array */ - public function controlProvider(): array + public static function controlProvider(): array { return [ 'text value null' => [ @@ -103,10 +109,8 @@ public function controlProvider(): array * @param mixed $value The value * @param string $expected The expected result * @return void - * @dataProvider controlProvider() - * @covers ::control() - * @covers ::initialize() */ + #[DataProvider('controlProvider')] public function testControl(string $type, string $property, $value, string $expected = ''): void { $view = new View(null, null, null, []); @@ -121,7 +125,7 @@ public function testControl(string $type, string $property, $value, string $expe * * @return array */ - public function controlProviderReadonly(): array + public static function controlProviderReadonly(): array { return [ 'readonly' => [ @@ -150,9 +154,8 @@ public function controlProviderReadonly(): array * @param mixed $value The value * @param string $expected The expected result * @return void - * @dataProvider controlProviderReadonly() - * @covers ::control() */ + #[DataProvider('controlProviderReadonly')] public function testControlReadonly(bool $readonly, array $resource, string $property, $value, string $expected = ''): void { $view = new View(null, null, null, []); @@ -171,8 +174,6 @@ public function testControlReadonly(bool $readonly, array $resource, string $pro * Test `getDictionary` and `setDictionary` methods. * * @return void - * @covers ::getDictionary() - * @covers ::setDictionary() */ public function testDictionary(): void { diff --git a/tests/TestCase/View/Helper/ArrayHelperTest.php b/tests/TestCase/View/Helper/ArrayHelperTest.php index ce3fc5233..fb7e88380 100644 --- a/tests/TestCase/View/Helper/ArrayHelperTest.php +++ b/tests/TestCase/View/Helper/ArrayHelperTest.php @@ -16,12 +16,19 @@ use App\View\Helper\ArrayHelper; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\ArrayHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\ArrayHelper */ +#[CoversClass(ArrayHelper::class)] +#[CoversMethod(ArrayHelper::class, 'combine')] +#[CoversMethod(ArrayHelper::class, 'extract')] +#[CoversMethod(ArrayHelper::class, 'intersect')] +#[CoversMethod(ArrayHelper::class, 'onlyKeys')] +#[CoversMethod(ArrayHelper::class, 'removeKeys')] class ArrayHelperTest extends TestCase { /** @@ -29,7 +36,7 @@ class ArrayHelperTest extends TestCase * * @var \App\View\Helper\ArrayHelper */ - public $Array; + public ArrayHelper $Array; /** * @inheritDoc @@ -57,10 +64,8 @@ public function tearDown(): void * * @return array */ - public function getCombineSchemaProvider(): array + public static function getCombineSchemaProvider(): array { - $arr = [10, 20, 50, 100]; - return [ 'combine arrays' => [ [ @@ -77,12 +82,11 @@ public function getCombineSchemaProvider(): array /** * Test `combine()` method. * - * @dataProvider getCombineSchemaProvider() - * @covers ::combine() * @param array $expected The expected array. * @param array $arr The array. * @return void */ + #[DataProvider('getCombineSchemaProvider')] public function testCombine(array $expected, array $arr): void { $actual = $this->Array->combine($arr); @@ -95,7 +99,7 @@ public function testCombine(array $expected, array $arr): void * * @return array */ - public function getRemoveKeysSchemaProvider(): array + public static function getRemoveKeysSchemaProvider(): array { return [ 'basic data' => [ @@ -122,13 +126,12 @@ public function getRemoveKeysSchemaProvider(): array /** * Test `removeKeys()` method. * - * @dataProvider getRemoveKeysSchemaProvider() - * @covers ::removeKeys() * @param array $expected The expected array. * @param array $arr The array. * @param array $keys The keys to remove. * @return void */ + #[DataProvider('getRemoveKeysSchemaProvider')] public function testRemoveKeys(array $expected, array $arr, array $keys): void { $actual = $this->Array->removeKeys($arr, $keys); @@ -141,7 +144,7 @@ public function testRemoveKeys(array $expected, array $arr, array $keys): void * * @return array */ - public function onlyKeysProvider(): array + public static function onlyKeysProvider(): array { return [ 'basic' => [ @@ -167,13 +170,12 @@ public function onlyKeysProvider(): array /** * Test `onlyKeys()` method. * - * @dataProvider onlyKeysProvider() - * @covers ::onlyKeys() * @param array $expected The expected array. * @param array $arr The array. * @param array $keys The keys to keep. * @return void */ + #[DataProvider('onlyKeysProvider')] public function testOnlyKeys(array $expected, array $arr, array $keys): void { $actual = $this->Array->onlyKeys($arr, $keys); @@ -184,7 +186,6 @@ public function testOnlyKeys(array $expected, array $arr, array $keys): void /** * Test `extract()` method. * - * @covers ::extract() * @return void */ public function testExtract(): void @@ -204,7 +205,6 @@ public function testExtract(): void * Test `intersect()` method. * * @return void - * @covers ::intersect() */ public function testIntersect(): void { diff --git a/tests/TestCase/View/Helper/CalendarHelperTest.php b/tests/TestCase/View/Helper/CalendarHelperTest.php index 88e8077c5..0cf1b1dfc 100644 --- a/tests/TestCase/View/Helper/CalendarHelperTest.php +++ b/tests/TestCase/View/Helper/CalendarHelperTest.php @@ -16,12 +16,16 @@ use App\View\Helper\CalendarHelper; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\CalendarHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\CalendarHelper */ +#[CoversClass(CalendarHelper::class)] +#[CoversMethod(CalendarHelper::class, 'dateRange')] +#[CoversMethod(CalendarHelper::class, 'list')] class CalendarHelperTest extends TestCase { /** @@ -29,7 +33,7 @@ class CalendarHelperTest extends TestCase * * @var \App\View\Helper\CalendarHelper */ - public $Calendar; + public CalendarHelper $Calendar; /** * @inheritDoc @@ -57,7 +61,7 @@ public function tearDown(): void * * @return array */ - public function listProvider(): array + public static function listProvider(): array { return [ 'empty date ranges' => [ @@ -85,9 +89,8 @@ public function listProvider(): array * @param array|null $dateRanges The array. * @param string $expected The expected string. * @return void - * @dataProvider listProvider() - * @covers ::list() */ + #[DataProvider('listProvider')] public function testList(?array $dateRanges, string $expected): void { $actual = $this->Calendar->list($dateRanges); @@ -99,7 +102,7 @@ public function testList(?array $dateRanges, string $expected): void * * @return array */ - public function dateRangeProvider(): array + public static function dateRangeProvider(): array { return [ 'empty date range' => [ @@ -127,9 +130,8 @@ public function dateRangeProvider(): array * @param array $dateRange The date range. * @param string $expected The expected string. * @return void - * @dataProvider dateRangeProvider() - * @covers ::dateRange() */ + #[DataProvider('dateRangeProvider')] public function testDateRange(array $dateRange, string $expected): void { $actual = $this->Calendar->dateRange($dateRange); diff --git a/tests/TestCase/View/Helper/CategoriesHelperTest.php b/tests/TestCase/View/Helper/CategoriesHelperTest.php index 3d52b2b1c..420236213 100644 --- a/tests/TestCase/View/Helper/CategoriesHelperTest.php +++ b/tests/TestCase/View/Helper/CategoriesHelperTest.php @@ -15,12 +15,21 @@ use App\View\Helper\CategoriesHelper; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\CategoriesHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\CategoriesHelper */ +#[CoversClass(CategoriesHelper::class)] +#[CoversMethod(CategoriesHelper::class, 'control')] +#[CoversMethod(CategoriesHelper::class, 'controlOptions')] +#[CoversMethod(CategoriesHelper::class, 'html')] +#[CoversMethod(CategoriesHelper::class, 'isTree')] +#[CoversMethod(CategoriesHelper::class, 'node')] +#[CoversMethod(CategoriesHelper::class, 'sortRoots')] +#[CoversMethod(CategoriesHelper::class, 'tree')] class CategoriesHelperTest extends TestCase { /** @@ -28,7 +37,7 @@ class CategoriesHelperTest extends TestCase * * @var \App\View\Helper\CategoriesHelper */ - public $Categories; + public CategoriesHelper $Categories; /** * @inheritDoc @@ -54,7 +63,7 @@ public function tearDown(): void * * @return array */ - public function controlProvider(): array + public static function controlProvider(): array { return [ 'is not tree' => [ @@ -102,9 +111,8 @@ public function controlProvider(): array * @param mixed|null $value The value * @param string $expected The expected result * @return void - * @dataProvider controlProvider() - * @covers ::control() */ + #[DataProvider('controlProvider')] public function testControl(array $schema, string $name, $value, string $expected): void { $view = new View(null, null, null, []); @@ -119,7 +127,7 @@ public function testControl(array $schema, string $name, $value, string $expecte * * @return array */ - public function htmlProvider(): array + public static function htmlProvider(): array { return [ 'multiple nodes' => [ @@ -152,9 +160,8 @@ public function htmlProvider(): array * @param array $options The options * @param string $expected The expected result * @return void - * @dataProvider htmlProvider() - * @covers ::html() */ + #[DataProvider('htmlProvider')] public function testHtml(array $schema, string $name, $value, array $options, string $expected): void { $view = new View(null, null, null, []); @@ -169,7 +176,7 @@ public function testHtml(array $schema, string $name, $value, array $options, st * * @return array */ - public function nodeProvider(): array + public static function nodeProvider(): array { return [ 'no children' => [ @@ -209,9 +216,8 @@ public function nodeProvider(): array * @param array $options The options * @param string $expected The expected result * @return void - * @dataProvider nodeProvider() - * @covers ::node() */ + #[DataProvider('nodeProvider')] public function testNode(array $node, string $name, $value, array $options, string $expected): void { $hiddenField = false; @@ -220,7 +226,7 @@ public function testNode(array $node, string $name, $value, array $options, stri $name, $value, $options, - $hiddenField + $hiddenField, ); static::assertEquals($expected, $actual); @@ -231,7 +237,7 @@ public function testNode(array $node, string $name, $value, array $options, stri * * @return array */ - public function controlOptionsProvider(): array + public static function controlOptionsProvider(): array { return [ 'empty node children, empty categories' => [ @@ -297,9 +303,8 @@ public function controlOptionsProvider(): array * @param array $options The options * @param array $expected The expected result * @return void - * @dataProvider controlOptionsProvider() - * @covers ::controlOptions() */ + #[DataProvider('controlOptionsProvider')] public function testControlOptions(array $node, $value, array $options, array $expected): void { $hiddenField = false; @@ -307,7 +312,7 @@ public function testControlOptions(array $node, $value, array $options, array $e $node, $value, $options, - $hiddenField + $hiddenField, ); static::assertEquals($expected, $actual); @@ -318,7 +323,7 @@ public function testControlOptions(array $node, $value, array $options, array $e * * @return array */ - public function treeProvider(): array + public static function treeProvider(): array { return [ 'empty schema' => [ @@ -430,11 +435,8 @@ public function treeProvider(): array * @param bool $expectedIsTree The expected for isTree * @param array $expectedTree The expected for Tree * @return void - * @dataProvider treeProvider() - * @covers ::sortRoots() - * @covers ::tree() - * @covers ::isTree() */ + #[DataProvider('treeProvider')] public function testTree(array $schema, bool $expectedIsTree, array $expectedTree): void { $view = new View(null, null, null, []); diff --git a/tests/TestCase/View/Helper/DatesHelperTest.php b/tests/TestCase/View/Helper/DatesHelperTest.php index eece22e3c..c5770fadd 100644 --- a/tests/TestCase/View/Helper/DatesHelperTest.php +++ b/tests/TestCase/View/Helper/DatesHelperTest.php @@ -6,19 +6,21 @@ use App\View\Helper\DatesHelper; use Cake\TestSuite\TestCase; use Cake\View\View; +use DateTime; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * App\View\Helper\DatesHelper Test Case - * - * @coversDefaultClass \App\View\Helper\DatesHelper */ +#[CoversClass(DatesHelper::class)] +#[CoversMethod(DatesHelper::class, 'daysAgo')] class DatesHelperTest extends TestCase { /** * Test `daysAgo` method. * * @return void - * @covers ::daysAgo() */ public function testDaysAgo(): void { @@ -26,17 +28,17 @@ public function testDaysAgo(): void $helper = new DatesHelper($view); // Test with a date 5 days ago - $date = (new \DateTime())->modify('-5 days')->format('Y-m-d'); + $date = (new DateTime())->modify('-5 days')->format('Y-m-d'); $result = $helper->daysAgo($date); $this->assertEquals(5, $result); // Test with a date 10 days ago - $date = (new \DateTime())->modify('-10 days')->format('Y-m-d'); + $date = (new DateTime())->modify('-10 days')->format('Y-m-d'); $result = $helper->daysAgo($date); $this->assertEquals(10, $result); // Test with today's date - $date = (new \DateTime())->format('Y-m-d'); + $date = (new DateTime())->format('Y-m-d'); $result = $helper->daysAgo($date); $this->assertEquals(0, $result); } diff --git a/tests/TestCase/View/Helper/EditorsHelperTest.php b/tests/TestCase/View/Helper/EditorsHelperTest.php index 19dec5e3f..61b5d6f68 100644 --- a/tests/TestCase/View/Helper/EditorsHelperTest.php +++ b/tests/TestCase/View/Helper/EditorsHelperTest.php @@ -17,12 +17,14 @@ use Cake\Cache\Cache; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see \App\View\Helper\EditorsHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\EditorsHelper */ +#[CoversClass(EditorsHelper::class)] +#[CoversMethod(EditorsHelper::class, 'list')] class EditorsHelperTest extends TestCase { /** @@ -30,7 +32,7 @@ class EditorsHelperTest extends TestCase * * @var \App\View\Helper\EditorsHelper */ - public $EditorsHelper; + public EditorsHelper $EditorsHelper; /** * @inheritDoc @@ -58,7 +60,6 @@ public function tearDown(): void * Test `list` method * * @return void - * @covers ::list() */ public function testlist(): void { diff --git a/tests/TestCase/View/Helper/ElementHelperTest.php b/tests/TestCase/View/Helper/ElementHelperTest.php index 8a9bf0083..2fbda4447 100644 --- a/tests/TestCase/View/Helper/ElementHelperTest.php +++ b/tests/TestCase/View/Helper/ElementHelperTest.php @@ -8,19 +8,25 @@ use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\ElementHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\ElementHelper */ +#[CoversClass(ElementHelper::class)] +#[CoversMethod(ElementHelper::class, 'categories')] +#[CoversMethod(ElementHelper::class, 'custom')] +#[CoversMethod(ElementHelper::class, 'dropupload')] +#[CoversMethod(ElementHelper::class, 'multiupload')] +#[CoversMethod(ElementHelper::class, 'sidebar')] class ElementHelperTest extends TestCase { /** * Test `categories` method * * @return void - * @covers ::categories() */ public function testCategories(): void { @@ -43,7 +49,7 @@ public function testCategories(): void * * @return array */ - public function customProvider(): array + public static function customProvider(): array { return [ 'empty' => [ @@ -83,9 +89,8 @@ public function customProvider(): array * @param string $type The item type * @param array $conf Configuration to use * @return void - * @dataProvider customProvider() - * @covers ::custom() */ + #[DataProvider('customProvider')] public function testCustom(string $expected, string $item, string $type = 'relation', array $conf = []): void { Configure::write('Properties.documents', $conf); @@ -100,7 +105,6 @@ public function testCustom(string $expected, string $item, string $type = 'relat * Test `sidebar` method * * @return void - * @covers ::sidebar() */ public function testSidebar(): void { @@ -122,7 +126,6 @@ public function testSidebar(): void * Test `dropupload` method * * @return void - * @covers ::dropupload() */ public function testDropupload(): void { @@ -144,7 +147,6 @@ public function testDropupload(): void * Test `multiupload` method * * @return void - * @covers ::multiupload() */ public function testMultiupload(): void { diff --git a/tests/TestCase/View/Helper/LayoutHelperTest.php b/tests/TestCase/View/Helper/LayoutHelperTest.php index 16abb2e33..12202c6bf 100644 --- a/tests/TestCase/View/Helper/LayoutHelperTest.php +++ b/tests/TestCase/View/Helper/LayoutHelperTest.php @@ -13,6 +13,7 @@ namespace App\Test\TestCase\View\Helper; +use App\Plugin; use App\Utility\CacheTools; use App\View\Helper\EditorsHelper; use App\View\Helper\LayoutHelper; @@ -23,15 +24,40 @@ use Cake\Http\Cookie\Cookie; use Cake\Http\Cookie\CookieCollection; use Cake\Http\ServerRequest; +use Cake\I18n\I18n; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\LayoutHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\LayoutHelper */ +#[CoversClass(LayoutHelper::class)] +#[CoversMethod(LayoutHelper::class, 'commandLinkClass')] +#[CoversMethod(LayoutHelper::class, 'dashboardModuleLink')] +#[CoversMethod(LayoutHelper::class, 'getCsrfToken')] +#[CoversMethod(LayoutHelper::class, 'indexLists')] +#[CoversMethod(LayoutHelper::class, 'isDashboard')] +#[CoversMethod(LayoutHelper::class, 'isLogin')] +#[CoversMethod(LayoutHelper::class, 'messages')] +#[CoversMethod(LayoutHelper::class, 'metaConfig')] +#[CoversMethod(LayoutHelper::class, 'moduleClass')] +#[CoversMethod(LayoutHelper::class, 'moduleCount')] +#[CoversMethod(LayoutHelper::class, 'moduleIcon')] +#[CoversMethod(LayoutHelper::class, 'moduleLink')] +#[CoversMethod(LayoutHelper::class, 'moduleIndexDefaultViewType')] +#[CoversMethod(LayoutHelper::class, 'moduleIndexViewType')] +#[CoversMethod(LayoutHelper::class, 'moduleIndexViewTypes')] +#[CoversMethod(LayoutHelper::class, 'propertyGroup')] +#[CoversMethod(LayoutHelper::class, 'publishStatus')] +#[CoversMethod(LayoutHelper::class, 'showCounter')] +#[CoversMethod(LayoutHelper::class, 'title')] +#[CoversMethod(LayoutHelper::class, 'tr')] +#[CoversMethod(LayoutHelper::class, 'trashLink')] +#[CoversMethod(LayoutHelper::class, 'uiRicheditorConfig')] class LayoutHelperTest extends TestCase { /** @@ -48,7 +74,7 @@ public function setUp(): void * * @return array */ - public function isDashboardProvider(): array + public static function isDashboardProvider(): array { return [ 'dashboard' => [ @@ -63,10 +89,9 @@ public function isDashboardProvider(): array * * @param string $name The view name * @param bool $expected The expected result - * @dataProvider isDashboardProvider() - * @covers ::isDashboard() */ - public function testIsDashboard($name, $expected): void + #[DataProvider('isDashboardProvider')] + public function testIsDashboard(string $name, bool $expected): void { $request = $response = $events = null; $data = ['name' => $name]; @@ -80,7 +105,7 @@ public function testIsDashboard($name, $expected): void * * @return array */ - public function isLoginProvider(): array + public static function isLoginProvider(): array { return [ 'login' => [ @@ -99,10 +124,9 @@ public function isLoginProvider(): array * * @param string $name The view name * @param bool $expected The expected result - * @dataProvider isLoginProvider() - * @covers ::isLogin() */ - public function testIsLogin($name, $expected): void + #[DataProvider('isLoginProvider')] + public function testIsLogin(string $name, bool $expected): void { $request = $response = $events = null; $data = ['name' => $name]; @@ -116,7 +140,7 @@ public function testIsLogin($name, $expected): void * * @return array */ - public function messagesProvider(): array + public static function messagesProvider(): array { return [ 'login' => [ @@ -135,10 +159,9 @@ public function messagesProvider(): array * * @param string $name The view name * @param bool $expected The expected result - * @dataProvider messagesProvider() - * @covers ::messages() */ - public function testMessages($name, $expected): void + #[DataProvider('messagesProvider')] + public function testMessages(string $name, bool $expected): void { $request = $response = $events = null; $data = ['name' => $name]; @@ -152,7 +175,7 @@ public function testMessages($name, $expected): void * * @return array */ - public function moduleClassProvider(): array + public static function moduleClassProvider(): array { return [ 'app-module-box locked' => [ @@ -180,42 +203,60 @@ public function moduleClassProvider(): array * @param bool $concurrent The concurrent editors flag * @param string $expected The expected class * @return void - * @dataProvider moduleClassProvider() - * @covers ::moduleClass() */ + #[DataProvider('moduleClassProvider')] public function testModuleClass(bool $locked, bool $concurrent, string $expected): void { $request = $response = $events = null; $view = new View($request, $response, $events, ['name' => 'Objects']); $view->set('object', ['id' => 999]); - $layout = new LayoutHelper($view); + + $layout = new class ($view) extends LayoutHelper { + public PermsHelper $Perms; + public EditorsHelper $Editors; + }; if ($locked) { - $mock = $this->createPartialMock(PermsHelper::class, ['isLockedByParents']); - $mock->method('isLockedByParents')->willReturn(true); - $layout->Perms = $mock; + $layout->Perms = new class ($view) extends PermsHelper { + public function isLockedByParents(string $id): bool + { + return true; + } + }; } elseif ($concurrent) { - $mock = $this->createPartialMock(PermsHelper::class, ['isLockedByParents']); - $mock->method('isLockedByParents')->willReturn(false); - $layout->Perms = $mock; - $mock = $this->createPartialMock(EditorsHelper::class, ['list']); - $mock->method('list')->willReturn([ - [ - 'id' => 1, - 'username' => 'first', - ], - [ - 'id' => 2, - 'username' => 'second', - ], - ]); - $layout->Editors = $mock; + $layout->Perms = new class ($view) extends PermsHelper { + public function isLockedByParents(string $id): bool + { + return false; + } + }; + $layout->Editors = new class ($view) extends EditorsHelper { + public function list(): array + { + return [ + [ + 'id' => 1, + 'username' => 'first', + ], + [ + 'id' => 2, + 'username' => 'second', + ], + ]; + } + }; } else { - $mock = $this->createPartialMock(PermsHelper::class, ['isLockedByParents']); - $mock->method('isLockedByParents')->willReturn(false); - $layout->Perms = $mock; - $mock = $this->createPartialMock(EditorsHelper::class, ['list']); - $mock->method('list')->willReturn([]); - $layout->Editors = $mock; + $layout->Perms = new class ($view) extends PermsHelper { + public function isLockedByParents(string $id): bool + { + return false; + } + }; + $layout->Editors = new class ($view) extends EditorsHelper { + public function list(): array + { + return []; + } + }; } $actual = $layout->moduleClass(); static::assertSame($expected, $actual); @@ -226,7 +267,7 @@ public function testModuleClass(bool $locked, bool $concurrent, string $expected * * @return array */ - public function moduleLinkProvider(): array + public static function moduleLinkProvider(): array { return [ 'user profile' => [ @@ -259,11 +300,9 @@ public function moduleLinkProvider(): array * @param string $expected The expected link * @param string $name The view name * @param array $viewVars The view vars - * @dataProvider moduleLinkProvider() - * @covers ::moduleLink() - * @covers ::commandLinkClass() */ - public function testModuleLink($expected, $name, array $viewVars = []): void + #[DataProvider('moduleLinkProvider')] + public function testModuleLink(string $expected, string $name, array $viewVars = []): void { $request = $response = $events = null; $data = ['name' => $name]; @@ -281,7 +320,7 @@ public function testModuleLink($expected, $name, array $viewVars = []): void * * @return array */ - public function moduleIndexDefaultViewTypeProvider(): array + public static function moduleIndexDefaultViewTypeProvider(): array { return [ 'documents' => [ @@ -301,9 +340,8 @@ public function moduleIndexDefaultViewTypeProvider(): array * @param array $viewVars The view vars * @param string $expected The expected result * @return void - * @dataProvider moduleIndexDefaultViewTypeProvider() - * @covers ::moduleIndexDefaultViewType() */ + #[DataProvider('moduleIndexDefaultViewTypeProvider')] public function testModuleIndexDefaultViewType(array $viewVars, string $expected): void { $request = $response = $events = null; @@ -323,7 +361,7 @@ public function testModuleIndexDefaultViewType(array $viewVars, string $expected * * @return array */ - public function moduleIndexViewTypeProvider(): array + public static function moduleIndexViewTypeProvider(): array { return [ 'documents list' => [ @@ -351,10 +389,8 @@ public function moduleIndexViewTypeProvider(): array * @param array $query The query params * @param string $expected The expected result * @return void - * @dataProvider moduleIndexViewTypeProvider() - * @covers ::moduleIndexViewType() - * @covers ::moduleIndexDefaultViewType() */ + #[DataProvider('moduleIndexViewTypeProvider')] public function testModuleIndexViewType(array $viewVars, array $query, string $expected): void { $request = new ServerRequest(['query' => $query]); @@ -375,7 +411,7 @@ public function testModuleIndexViewType(array $viewVars, array $query, string $e * * @return array */ - public function moduleIndexViewTypesProvider(): array + public static function moduleIndexViewTypesProvider(): array { return [ 'documents' => [ @@ -392,13 +428,11 @@ public function moduleIndexViewTypesProvider(): array /** * Test `moduleIndexViewTypes * - * @param array $viewVars - * @param array $expected + * @param array $viewVars The view vars + * @param array $expected The expected result * @return void - * @dataProvider moduleIndexViewTypesProvider() - * @covers ::moduleIndexViewTypes() - * @covers ::moduleIndexDefaultViewType() */ + #[DataProvider('moduleIndexViewTypesProvider')] public function testModuleIndexViewTypes(array $viewVars, array $expected): void { $request = $response = $events = null; @@ -418,7 +452,7 @@ public function testModuleIndexViewTypes(array $viewVars, array $expected): void * * @return array */ - public function titleProvider(): array + public static function titleProvider(): array { return [ 'empty' => [ @@ -478,9 +512,8 @@ public function titleProvider(): array * @param string $expected The expected title * @param string $name The view name * @param array $viewVars The view vars - * @dataProvider titleProvider() - * @covers ::title() */ + #[DataProvider('titleProvider')] public function testTitle(string $expected, string $name, array $viewVars = []): void { $request = $response = $events = null; @@ -498,7 +531,6 @@ public function testTitle(string $expected, string $name, array $viewVars = []): * Test `tr` method * * @return void - * @covers ::tr() */ public function testTranslation(): void { @@ -515,7 +547,7 @@ public function testTranslation(): void static::assertSame($expected, $actual); } - public function publishStatusProvider(): array + public static function publishStatusProvider(): array { return [ 'empty object' => [ @@ -549,9 +581,8 @@ public function publishStatusProvider(): array * Test `publishStatus` method * * @return void - * @dataProvider publishStatusProvider() - * @covers ::publishStatus() */ + #[DataProvider('publishStatusProvider')] public function testPublishStatus(array $object, string $expected): void { $view = new View(); @@ -564,7 +595,6 @@ public function testPublishStatus(array $object, string $expected): void * Test `metaConfig` method * * @return void - * @covers ::metaConfig() */ public function testMetaConfig(): void { @@ -585,9 +615,9 @@ public function testMetaConfig(): void 'currentModule' => ['name' => 'home'], 'template' => '', 'modules' => ['documents', 'images'], - 'plugins' => \App\Plugin::loadedAppPlugins(), + 'plugins' => Plugin::loadedAppPlugins(), 'uploadable' => ['images'], - 'locale' => \Cake\I18n\I18n::getLocale(), + 'locale' => I18n::getLocale(), 'csrfToken' => 'my-token', 'maxFileSize' => $system->getMaxFileSize(), 'canReadUsers' => false, @@ -608,7 +638,6 @@ public function testMetaConfig(): void * Test `metaConfig` method * * @return void - * @covers ::metaConfig() */ public function testMetaConfigToken(): void { @@ -625,7 +654,7 @@ public function testMetaConfigToken(): void * * @return array */ - public function csrfTokenProvider(): array + public static function csrfTokenProvider(): array { $request = new ServerRequest(); @@ -659,9 +688,8 @@ public function csrfTokenProvider(): array * @param string|null $expected The expected result * @param \App\View\Helper\LayoutHelper $layout The layout helper * @return void - * @dataProvider csrfTokenProvider() - * @covers ::getCsrfToken() */ + #[DataProvider('csrfTokenProvider')] public function testGetCsrfToken(?string $expected, LayoutHelper $layout): void { $actual = $layout->getCsrfToken(); @@ -673,7 +701,7 @@ public function testGetCsrfToken(?string $expected, LayoutHelper $layout): void * * @return array */ - public function trashLinkProvider(): array + public static function trashLinkProvider(): array { return [ 'null' => [ @@ -709,9 +737,8 @@ public function trashLinkProvider(): array * @param string|null $input The input * @param string $expected The expected result * @return void - * @dataProvider trashLinkProvider() - * @covers ::trashLink() */ + #[DataProvider('trashLinkProvider')] public function testTrashLink(?string $input, string $expected): void { $viewVars = [ @@ -735,7 +762,7 @@ public function testTrashLink(?string $input, string $expected): void * * @return array */ - public function dashboardModuleLinkProvider(): array + public static function dashboardModuleLinkProvider(): array { return [ 'trash' => [ @@ -760,10 +787,8 @@ public function dashboardModuleLinkProvider(): array * Test `dashboardModuleLink`. * * @return void - * @dataProvider dashboardModuleLinkProvider() - * @covers ::dashboardModuleLink() - * @covers ::moduleIcon() */ + #[DataProvider('dashboardModuleLinkProvider')] public function testDashboardModuleLink(string $name, array $module, string $expected): void { $modules = (array)Configure::read('Modules', []); @@ -782,7 +807,7 @@ public function testDashboardModuleLink(string $name, array $module, string $exp * * @return array */ - public function moduleIconProvider(): array + public static function moduleIconProvider(): array { return [ 'hints multiple types' => [ @@ -825,9 +850,8 @@ public function moduleIconProvider(): array * @param array $module The module configuration * @param string $expected The expected result * @return void - * @dataProvider moduleIconProvider() - * @covers ::moduleIcon() */ + #[DataProvider('moduleIconProvider')] public function testModuleIcon(string $name, array $module, string $expected): void { $modules = (array)Configure::read('Modules', []); @@ -845,8 +869,6 @@ public function testModuleIcon(string $name, array $module, string $expected): v * Test `moduleCount` method. * * @return void - * @covers ::moduleCount() - * @covers ::showCounter() */ public function testModuleCount(): void { @@ -866,6 +888,7 @@ public function testModuleCount(): void static::assertEquals($expected, $actual); $actual = $layout->moduleCount($moduleName, 'my-dummy-css-class'); $expected = sprintf('%s', $count); + static::assertEquals($expected, $actual); Cache::disable(); } @@ -873,7 +896,6 @@ public function testModuleCount(): void * Test `showCounter` method. * * @return void - * @covers ::showCounter() */ public function testShowCounter(): void { @@ -895,7 +917,6 @@ public function testShowCounter(): void * Test `propertyGroup` method. * * @return void - * @covers ::propertyGroup() */ public function testPropertyGroup(): void { @@ -918,7 +939,6 @@ public function testPropertyGroup(): void * Test `indexLists` method. * * @return void - * @covers ::indexLists() */ public function testIndexLists(): void { @@ -964,7 +984,6 @@ public function testIndexLists(): void * Test `uiRicheditorConfig` method. * * @return void - * @covers ::uiRicheditorConfig() */ public function testUiRicheditorConfig(): void { diff --git a/tests/TestCase/View/Helper/LinkHelperTest.php b/tests/TestCase/View/Helper/LinkHelperTest.php index 7401c78b0..044fc3f94 100644 --- a/tests/TestCase/View/Helper/LinkHelperTest.php +++ b/tests/TestCase/View/Helper/LinkHelperTest.php @@ -19,14 +19,31 @@ use Cake\Core\Configure; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; -use Cake\View\Helper\HtmlHelper; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\LinkHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\LinkHelper */ +#[CoversClass(LinkHelper::class)] +#[CoversMethod(LinkHelper::class, 'baseUrl')] +#[CoversMethod(LinkHelper::class, 'cssBundle')] +#[CoversMethod(LinkHelper::class, 'findFiles')] +#[CoversMethod(LinkHelper::class, 'fromAPI')] +#[CoversMethod(LinkHelper::class, 'here')] +#[CoversMethod(LinkHelper::class, 'initialize')] +#[CoversMethod(LinkHelper::class, 'jsBundle')] +#[CoversMethod(LinkHelper::class, 'page')] +#[CoversMethod(LinkHelper::class, 'pageSize')] +#[CoversMethod(LinkHelper::class, 'pluginsBundle')] +#[CoversMethod(LinkHelper::class, 'pluginAsset')] +#[CoversMethod(LinkHelper::class, 'replaceQueryParams')] +#[CoversMethod(LinkHelper::class, 'sortClass')] +#[CoversMethod(LinkHelper::class, 'sortField')] +#[CoversMethod(LinkHelper::class, 'sortUrl')] +#[CoversMethod(LinkHelper::class, 'sortValue')] class LinkHelperTest extends TestCase { /** @@ -52,7 +69,6 @@ public function tearDown(): void * Test `baseUrl` * * @return void - * @covers ::baseUrl() */ public function testBaseUrl(): void { @@ -73,7 +89,7 @@ public function testBaseUrl(): void * * @return array */ - public function fromAPIProvider(): array + public static function fromAPIProvider(): array { return [ 'empty url' => [ @@ -99,9 +115,8 @@ public function fromAPIProvider(): array * @param string $apiUrl The api url * @param string $expected The url expected * @return void - * @dataProvider fromAPIProvider() - * @covers ::fromAPI() */ + #[DataProvider('fromAPIProvider')] public function testFromAPI($apiBaseUrl, $webBaseUrl, $apiUrl, $expected): void { $link = new LinkHelper(new View(null, null, null, [])); @@ -116,7 +131,7 @@ public function testFromAPI($apiBaseUrl, $webBaseUrl, $apiUrl, $expected): void * * @return array */ - public function sortUrlProvider(): array + public static function sortUrlProvider(): array { $request = new ServerRequest([ 'environment' => [ @@ -169,12 +184,8 @@ public function sortUrlProvider(): array * @param bool $resetPage The reset page flag * @param string $expected The expected output * @return void - * @dataProvider sortUrlProvider() - * @covers ::sortUrl - * @covers ::sortValue - * @covers ::sortField - * @covers ::replaceQueryParams */ + #[DataProvider('sortUrlProvider')] public function testSortUrl(ServerRequest $request, string $field, bool $resetPage, string $expected): void { $link = new LinkHelper(new View($request, null, null, [])); @@ -187,7 +198,7 @@ public function testSortUrl(ServerRequest $request, string $field, bool $resetPa * * @return array */ - public function sortClassProvider(): array + public static function sortClassProvider(): array { $request = new ServerRequest([ 'environment' => [ @@ -229,9 +240,8 @@ public function sortClassProvider(): array * @param string $field The field to sort by * @param string $expected The expected output * @return void - * @dataProvider sortClassProvider() - * @covers ::sortClass */ + #[DataProvider('sortClassProvider')] public function testSortClass(ServerRequest $request, string $field, string $expected): void { $link = new LinkHelper(new View($request, null, null, [])); @@ -244,7 +254,7 @@ public function testSortClass(ServerRequest $request, string $field, string $exp * * @return array */ - public function pageProvider(): array + public static function pageProvider(): array { return [ 'zero' => [0], @@ -257,10 +267,8 @@ public function pageProvider(): array * * @param int $page The page number * @return void - * @dataProvider pageProvider() - * @covers ::page - * @covers ::replaceQueryParams */ + #[DataProvider('pageProvider')] public function testPage(int $page): void { $request = new ServerRequest([ @@ -273,7 +281,7 @@ public function testPage(int $page): void ]); $link = new LinkHelper(new View($request, null, null, [])); // call private method using AppControllerTest->invokeMethod - $test = new AppControllerTest(); + $test = new AppControllerTest('test'); $expected = $test->invokeMethod($link, 'replaceQueryParams', [compact('page')]); $this->expectOutputString($expected); // call page method @@ -285,7 +293,7 @@ public function testPage(int $page): void * * @return array */ - public function pageSizeProvider(): array + public static function pageSizeProvider(): array { return [ '1' => [1], @@ -300,10 +308,8 @@ public function pageSizeProvider(): array * * @param int $pageSize The page size * @return void - * @dataProvider pageSizeProvider() - * @covers ::pageSize - * @covers ::replaceQueryParams */ + #[DataProvider('pageSizeProvider')] public function testPageSize(int $pageSize): void { $request = new ServerRequest([ @@ -316,7 +322,7 @@ public function testPageSize(int $pageSize): void ]); $link = new LinkHelper(new View($request, null, null, [])); // call private method using AppControllerTest->invokeMethod - $test = new AppControllerTest(); + $test = new AppControllerTest('test'); $expected = $test->invokeMethod($link, 'replaceQueryParams', [['page_size' => $pageSize]]); $this->expectOutputString($expected); // call page method @@ -328,7 +334,7 @@ public function testPageSize(int $pageSize): void * * @return array */ - public function hereProvider(): array + public static function hereProvider(): array { $request = new ServerRequest([ 'environment' => [ @@ -370,9 +376,8 @@ public function hereProvider(): array * @param array $options The options * @param string $expected The expected url string * @return void - * @dataProvider hereProvider() - * @covers ::here */ + #[DataProvider('hereProvider')] public function testHere(ServerRequest $request, array $options, string $expected): void { $link = new LinkHelper(new View($request, null, null, [])); @@ -385,7 +390,7 @@ public function testHere(ServerRequest $request, array $options, string $expecte * * @return array */ - public function replaceQueryParamsProvider(): array + public static function replaceQueryParamsProvider(): array { $request = new ServerRequest([ 'environment' => [ @@ -417,14 +422,13 @@ public function replaceQueryParamsProvider(): array * @param array $queryParams The query params * @param string $expected The expected url string * @return void - * @dataProvider replaceQueryParamsProvider() - * @covers ::replaceQueryParams */ + #[DataProvider('replaceQueryParamsProvider')] public function testReplaceQueryParams(ServerRequest $request, array $queryParams, string $expected): void { $link = new LinkHelper(new View($request, null, null, [])); // call private method using AppControllerTest->invokeMethod - $test = new AppControllerTest(); + $test = new AppControllerTest('test'); $actual = $test->invokeMethod($link, 'replaceQueryParams', [$queryParams]); static::assertEquals($expected, $actual); } @@ -433,14 +437,12 @@ public function testReplaceQueryParams(ServerRequest $request, array $queryParam * Test `pluginsBundle` * * @return void - * @covers ::pluginsBundle */ public function testPluginsBundle(): void { // load plugins from config for test $app = new Application(CONFIG); $app->bootstrap(); - $debug = Configure::read('debug'); $pluginsConfig = [ 'DebugKit' => ['debugOnly' => true], 'Bake' => ['debugOnly' => false], @@ -457,7 +459,6 @@ public function testPluginsBundle(): void * Test `pluginAsset` * * @return void - * @covers ::pluginAsset */ public function testPluginAsset(): void { @@ -499,7 +500,7 @@ public function testPluginAsset(): void * * @return array */ - public function jsBundleProvider(): array + public static function jsBundleProvider(): array { return [ 'non existing js' => [ @@ -515,15 +516,13 @@ public function jsBundleProvider(): array * @param array $filter The filter param * @param string $expected The expected string * @return void - * @dataProvider jsBundleProvider() - * @covers ::jsBundle - * @covers ::findFiles */ + #[DataProvider('jsBundleProvider')] public function testJsBundle(array $filter, string $expected): void { $link = new LinkHelper(new View(new ServerRequest(), null, null, [])); $link->jsBundle($filter); - $actual = $this->getActualOutput(); + $actual = $this->output(); static::assertEquals($expected, $actual); } @@ -531,19 +530,26 @@ public function testJsBundle(array $filter, string $expected): void * Test `jsBundle`, `cssBundle` * * @return void - * @covers ::jsBundle() - * @covers ::cssBundle() */ public function testBundlesWithMockFindFiles(): void { - $mock = $this->createPartialMock(LinkHelper::class, ['findFiles']); - $mock->method('findFiles')->willReturn(['app.bundle.js']); - $mock->Html = new HtmlHelper(new View(new ServerRequest(), null, null, [])); + $view = new View(new ServerRequest(), null, null, []); + $mock = new class ($view) extends LinkHelper { + public function findFiles(array $filter, string $type): array + { + return ['app.bundle.js']; + } + }; $mock->jsBundle(['timezone']); - $mock->method('findFiles')->willReturn(['app.css']); + $mock = new class ($view) extends LinkHelper { + public function findFiles(array $filter, string $type): array + { + return ['app.bundle.css']; + } + }; $mock->cssBundle(['timezone']); - $actual = $this->getActualOutput(); - static::assertEquals('', $actual); + $actual = $this->output(); + static::assertEquals('', $actual); } /** @@ -551,7 +557,7 @@ public function testBundlesWithMockFindFiles(): void * * @return array */ - public function cssBundleProvider(): array + public static function cssBundleProvider(): array { return [ 'non existing css' => [ @@ -567,15 +573,13 @@ public function cssBundleProvider(): array * @param array $filter The filter param * @param string $expected The expected string * @return void - * @dataProvider cssBundleProvider() - * @covers ::cssBundle - * @covers ::findFiles */ + #[DataProvider('cssBundleProvider')] public function testCssBundle(array $filter, string $expected): void { $link = new LinkHelper(new View(new ServerRequest(), null, null, [])); $link->cssBundle($filter); - $actual = $this->getActualOutput(); + $actual = $this->output(); static::assertEquals($expected, $actual); } @@ -584,7 +588,7 @@ public function testCssBundle(array $filter, string $expected): void * * @return array */ - public function findFilesProvider(): array + public static function findFilesProvider(): array { return [ 'non existing file' => [ @@ -613,11 +617,12 @@ public function findFilesProvider(): array /** * Test `findFiles` * + * @param array $filter The filter param + * @param string $extension The extension param + * @param string $expected The expected string * @return void - * @dataProvider findFilesProvider() - * @covers ::findFiles - * @covers ::initialize */ + #[DataProvider('findFilesProvider')] public function testFindFiles(array $filter, string $extension, string $expected): void { $config = ['manifestPath' => TESTS . 'files' . DS . 'manifest.json']; diff --git a/tests/TestCase/View/Helper/PermsHelperTest.php b/tests/TestCase/View/Helper/PermsHelperTest.php index 095b44b7b..a24fe76f1 100644 --- a/tests/TestCase/View/Helper/PermsHelperTest.php +++ b/tests/TestCase/View/Helper/PermsHelperTest.php @@ -19,12 +19,27 @@ use BEdita\WebTools\ApiClientProvider; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\ArrayHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\PermsHelper */ +#[CoversClass(PermsHelper::class)] +#[CoversMethod(PermsHelper::class, 'access')] +#[CoversMethod(PermsHelper::class, 'canCreate')] +#[CoversMethod(PermsHelper::class, 'canCreateModules')] +#[CoversMethod(PermsHelper::class, 'canDelete')] +#[CoversMethod(PermsHelper::class, 'canLock')] +#[CoversMethod(PermsHelper::class, 'canRead')] +#[CoversMethod(PermsHelper::class, 'canSave')] +#[CoversMethod(PermsHelper::class, 'initialize')] +#[CoversMethod(PermsHelper::class, 'isAllowed')] +#[CoversMethod(PermsHelper::class, 'isLockedByParents')] +#[CoversMethod(PermsHelper::class, 'userIsAdmin')] +#[CoversMethod(PermsHelper::class, 'userIsAllowed')] +#[CoversMethod(PermsHelper::class, 'userRoles')] class PermsHelperTest extends TestCase { /** @@ -32,7 +47,7 @@ class PermsHelperTest extends TestCase * * @var \App\View\Helper\PermsHelper */ - public $Perms; + public PermsHelper $Perms; /** * @inheritDoc @@ -63,7 +78,7 @@ public function setUp(): void * * @return array */ - public function isAllowedProvider(): array + public static function isAllowedProvider(): array { return [ [ @@ -95,14 +110,8 @@ public function isAllowedProvider(): array * @param string $method Helper method * @param array|string $arg The argument for function * @return void - * @dataProvider isAllowedProvider() - * @covers ::isAllowed() - * @covers ::initialize() - * @covers ::canDelete() - * @covers ::canRead() - * @covers ::canCreate() - * @covers ::canSave() */ + #[DataProvider('isAllowedProvider')] public function testIsAllowed(bool $expected, string $method, $arg = null): void { $result = $this->Perms->{$method}($arg); @@ -113,7 +122,6 @@ public function testIsAllowed(bool $expected, string $method, $arg = null): void * Test `isAllowed` method with no current module perms. * * @return void - * @covers ::isAllowed() */ public function testIsAllowedNoCurrent(): void { @@ -127,7 +135,6 @@ public function testIsAllowedNoCurrent(): void * Test `canLock` method. * * @return void - * @covers ::canLock() */ public function testCanLock(): void { @@ -144,43 +151,36 @@ public function testCanLock(): void * Test `canCreate` method * * @return void - * @covers ::canCreate() */ public function testCanCreate(): void { - $result = $this->Perms->canCreate(); - static::assertFalse($result); + static::assertFalse($this->Perms->canCreate()); } /** * Test `canRead` method * * @return void - * @covers ::canRead() */ public function testCanRead(): void { - $result = $this->Perms->canRead(); - static::assertTrue($result); + static::assertTrue($this->Perms->canRead()); } /** * Test `canSave` method * * @return void - * @covers ::canSave() */ public function testCanSave(): void { - $result = $this->Perms->canSave(); - static::assertFalse($result); + static::assertFalse($this->Perms->canSave()); } /** * Test `canDelete` method * * @return void - * @covers ::canDelete() */ public function testCanDelete(): void { @@ -188,8 +188,7 @@ public function testCanDelete(): void 'type' => 'documents', 'meta' => ['locked' => true], ]; - $result = $this->Perms->canDelete($document); - static::assertFalse($result); + static::assertFalse($this->Perms->canDelete($document)); // locked by parents $mock = $this->createPartialMock(PermsHelper::class, ['isLockedByParents']); @@ -199,8 +198,7 @@ public function testCanDelete(): void 'type' => 'documents', 'meta' => ['locked' => false], ]; - $result = $this->Perms->canDelete($document); - static::assertFalse($result); + static::assertFalse($this->Perms->canDelete($document)); } /** @@ -208,7 +206,7 @@ public function testCanDelete(): void * * @return array */ - public function accessProvider(): array + public static function accessProvider(): array { return [ 'write' => [ @@ -249,9 +247,8 @@ public function accessProvider(): array * @param string $moduleName The module name * @param string $expected The expected value * @return void - * @covers ::access() - * @dataProvider accessProvider() */ + #[DataProvider('accessProvider')] public function testAccess(array $accessControl, string $roleName, string $moduleName, string $expected): void { $actual = $this->Perms->access($accessControl, $roleName, $moduleName); @@ -262,24 +259,20 @@ public function testAccess(array $accessControl, string $roleName, string $modul * Test `userIsAdmin` * * @return void - * @covers ::userIsAdmin() */ public function testUserIsAdmin(): void { $this->Perms->getView()->set('user', new Identity([])); - $actual = $this->Perms->userIsAdmin(); - static::assertFalse($actual); + static::assertFalse($this->Perms->userIsAdmin()); $this->Perms->getView()->set('user', new Identity(['roles' => ['admin']])); - $actual = $this->Perms->userIsAdmin(); - static::assertTrue($actual); + static::assertTrue($this->Perms->userIsAdmin()); } /** * Test `userIsAllowed * * @return void - * @covers ::userIsAllowed() */ public function testUserIsAllowed(): void { @@ -324,7 +317,6 @@ public function testUserIsAllowed(): void * Test `userRoles` * * @return void - * @covers ::userRoles() */ public function testUserRoles(): void { @@ -338,7 +330,6 @@ public function testUserRoles(): void * Test `isLockedByParents` method. * * @return void - * @covers ::isLockedByParents() */ public function testIsLockedByParents(): void { @@ -532,7 +523,6 @@ public function testIsLockedByParents(): void * Test `canCreateModules` method * * @return void - * @covers ::canCreateModules() */ public function testCanCreateModules(): void { diff --git a/tests/TestCase/View/Helper/PropertyHelperTest.php b/tests/TestCase/View/Helper/PropertyHelperTest.php index 9188673cc..8441e2bbf 100644 --- a/tests/TestCase/View/Helper/PropertyHelperTest.php +++ b/tests/TestCase/View/Helper/PropertyHelperTest.php @@ -18,12 +18,24 @@ use Cake\Core\Configure; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\PropertyHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\PropertyHelper */ +#[CoversClass(PropertyHelper::class)] +#[CoversMethod(PropertyHelper::class, 'control')] +#[CoversMethod(PropertyHelper::class, 'dateRange')] +#[CoversMethod(PropertyHelper::class, 'fastCreateFields')] +#[CoversMethod(PropertyHelper::class, 'fastCreateFieldsMap')] +#[CoversMethod(PropertyHelper::class, 'fieldLabel')] +#[CoversMethod(PropertyHelper::class, 'prepareFieldOptions')] +#[CoversMethod(PropertyHelper::class, 'schema')] +#[CoversMethod(PropertyHelper::class, 'translationControl')] +#[CoversMethod(PropertyHelper::class, 'translationsMap')] +#[CoversMethod(PropertyHelper::class, 'value')] class PropertyHelperTest extends TestCase { /** @@ -49,7 +61,7 @@ public function setUp(): void * * @return array */ - public function controlProvider(): array + public static function controlProvider(): array { return [ 'text' => [ @@ -181,11 +193,8 @@ public function controlProvider(): array * @param string $expected The expected result * @param string $expectedTranslation The expected translation result * @return void - * @dataProvider controlProvider() - * @covers ::control() - * @covers ::translationControl() - * @covers ::schema() */ + #[DataProvider('controlProvider')] public function testControl(string $key, $value, array $options = [], array $schema = [], string $expected = '', string $expectedTranslation = ''): void { if (array_key_exists('readonly', $options)) { @@ -213,7 +222,7 @@ public function testControl(string $key, $value, array $options = [], array $sch * * @return array */ - public function schemaProvider(): array + public static function schemaProvider(): array { return [ 'string' => [ @@ -272,9 +281,8 @@ public function schemaProvider(): array * @param string $name Property name * @param array|null $schema Object schema * @return void - * @dataProvider schemaProvider() - * @covers ::schema() */ + #[DataProvider('schemaProvider')] public function testSchema(?array $expected, string $name, ?array $schema = null): void { $view = new View(null, null, null, []); @@ -288,8 +296,6 @@ public function testSchema(?array $expected, string $name, ?array $schema = null * Test `control` with parameter type, for "other" types schema controls * * @return void - * @covers ::control() - * @covers ::schema() */ public function testControlOtherType(): void { @@ -325,7 +331,7 @@ public function testControlOtherType(): void * * @return array */ - public function valueProvider(): array + public static function valueProvider(): array { return [ 'object attribute' => [ @@ -387,9 +393,8 @@ public function valueProvider(): array * @param string $property The property * @param string $expected The expected value * @return void - * @dataProvider valueProvider() - * @covers ::value() */ + #[DataProvider('valueProvider')] public function testValue(array $object, string $property, string $expected): void { $view = new View(null, null, null, []); @@ -413,7 +418,6 @@ public static function dummy($value): array * Test `fieldLabel`. * * @return void - * @covers ::fieldLabel() */ public function testFieldLabel(): void { @@ -434,9 +438,9 @@ public function testFieldLabel(): void Configure::write( 'Properties.dummies', array_merge( - (array)\Cake\Core\Configure::read('Properties.dummies'), - ['options' => ['about' => ['label' => $expected]]] - ) + (array)Configure::read('Properties.dummies'), + ['options' => ['about' => ['label' => $expected]]], + ), ); $actual = $helper->fieldLabel('about', 'dummies'); static::assertEquals($expected, $actual); @@ -446,7 +450,6 @@ public function testFieldLabel(): void * Test `fastCreateFields`. * @return void - * @covers ::fastCreateFields() */ public function testFastCreateFields(): void { @@ -465,7 +468,6 @@ public function testFastCreateFields(): void * Test `fastCreateFieldsMap`. * @return void - * @covers ::fastCreateFieldsMap() */ public function testFastCreateFieldsMap(): void { @@ -495,7 +497,6 @@ public function testFastCreateFieldsMap(): void * Test `prepareFieldOptions`. * @return void - * @covers ::prepareFieldOptions() */ public function testPrepareFieldOptions(): void { @@ -518,7 +519,6 @@ public function testPrepareFieldOptions(): void * Test `dateRange`. * @return void - * @covers ::dateRange() */ public function testDateRange(): void { @@ -534,7 +534,6 @@ public function testDateRange(): void * Test `translationsMap`. * * @return void - * @covers ::translationsMap() */ public function testTranslationsMap(): void { @@ -574,7 +573,6 @@ public function testTranslationsMap(): void * Test `translationsMap` with exception. * * @return void - * @covers ::translationsMap() */ public function testTranslationsMapExpection(): void { diff --git a/tests/TestCase/View/Helper/SchemaHelperTest.php b/tests/TestCase/View/Helper/SchemaHelperTest.php index cbfcb27ce..8050fab80 100644 --- a/tests/TestCase/View/Helper/SchemaHelperTest.php +++ b/tests/TestCase/View/Helper/SchemaHelperTest.php @@ -17,16 +17,33 @@ use App\View\Helper\SchemaHelper; use Cake\Core\Configure; use Cake\Http\ServerRequest; -use Cake\I18n\FrozenTime; +use Cake\I18n\DateTime; use Cake\TestSuite\TestCase; use Cake\Utility\Hash; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; /** * {@see \App\View\Helper\SchemaHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\SchemaHelper */ +#[CoversClass(SchemaHelper::class)] +#[CoversMethod(SchemaHelper::class, 'controlOptions')] +#[CoversMethod(SchemaHelper::class, 'customControl')] +#[CoversMethod(SchemaHelper::class, 'format')] +#[CoversMethod(SchemaHelper::class, 'formatByte')] +#[CoversMethod(SchemaHelper::class, 'formatBoolean')] +#[CoversMethod(SchemaHelper::class, 'formatDate')] +#[CoversMethod(SchemaHelper::class, 'formatDateTime')] +#[CoversMethod(SchemaHelper::class, 'filterList')] +#[CoversMethod(SchemaHelper::class, 'filterListByType')] +#[CoversMethod(SchemaHelper::class, 'minimalObjectsList')] +#[CoversMethod(SchemaHelper::class, 'sortable')] +#[CoversMethod(SchemaHelper::class, 'translatableFields')] +#[CoversMethod(SchemaHelper::class, 'translatableType')] +#[CoversMethod(SchemaHelper::class, 'typeFromSchema')] +#[CoversMethod(SchemaHelper::class, 'updateRicheditorOptions')] class SchemaHelperTest extends TestCase { /** @@ -34,7 +51,7 @@ class SchemaHelperTest extends TestCase * * @var \App\View\Helper\SchemaHelper */ - public $Schema; + public SchemaHelper $Schema; /** * @inheritDoc @@ -82,7 +99,7 @@ public function tearDown(): void * * @return array */ - public function controlOptionsSchemaProvider(): array + public static function controlOptionsSchemaProvider(): array { return [ 'text' => [ @@ -399,10 +416,8 @@ public function controlOptionsSchemaProvider(): array * @param string $name The field name. * @param mixed $value The field value. * @return void - * @dataProvider controlOptionsSchemaProvider() - * @covers ::controlOptions() - * @covers ::customControl() */ + #[DataProvider('controlOptionsSchemaProvider')] public function testControlOptions(array $expected, array $schema, string $name, $value): void { $actual = $this->Schema->controlOptions($name, $value, $schema); @@ -415,7 +430,7 @@ public function testControlOptions(array $expected, array $schema, string $name, * * @return array */ - public function updateRicheditorOptionsProvider(): array + public static function updateRicheditorOptionsProvider(): array { return [ 'empty UI.richeditor.title.toolbar' => [ @@ -472,9 +487,8 @@ public function updateRicheditorOptionsProvider(): array * @param array $options The options * @param array $expected The expected result * @return void - * @dataProvider updateRicheditorOptionsProvider() - * @covers ::updateRicheditorOptions() */ + #[DataProvider('updateRicheditorOptionsProvider')] public function testUpdateRicheditorOptions(array $uiConf, string $name, bool $placeholders, array $options, array $expected): void { Configure::write('UI.richeditor.title.toolbar', $uiConf); @@ -504,7 +518,6 @@ public function updateREopts(string $name, bool $placeholders, array &$options): * Test `updateRicheditorOptions` method for admin users. * * @return void - * @covers ::updateRicheditorOptions() */ public function testUpdateRicheditorOptionsAdmin(): void { @@ -551,7 +564,6 @@ public function userIsAdmin(): bool * Test `lang` property * * @return void - * @covers ::controlOptions() */ public function testLang(): void { @@ -598,7 +610,7 @@ public function testLang(): void * * @return array */ - public function translatableFieldsProvider(): array + public static function translatableFieldsProvider(): array { return [ 'empty translatable' => [ @@ -680,10 +692,8 @@ public function translatableFieldsProvider(): array * @param array $schema The object schema * @param array $expected Expected result * @return void - * @dataProvider translatableFieldsProvider() - * @covers ::translatableFields() - * @covers ::translatableType() */ + #[DataProvider('translatableFieldsProvider')] public function testTranslatableFields(array $schema, array $expected): void { $actual = $this->Schema->translatableFields($schema); @@ -695,11 +705,11 @@ public function testTranslatableFields(array $schema, array $expected): void * * @return array */ - public function formatProvider(): array + public static function formatProvider(): array { - $d = new FrozenTime('2019-09-08'); + $d = new DateTime('2019-09-08'); $dateExpected = $d->i18nFormat(); - $d = new FrozenTime('2019-09-08T16:35:15+00'); + $d = new DateTime('2019-09-08T16:35:15+00'); $dateTimeExpected = $d->i18nFormat(); return [ @@ -791,14 +801,8 @@ public function formatProvider(): array * @param mixed $value The value * @param array $schema The schema * @return void - * @dataProvider formatProvider() - * @covers ::format() - * @covers ::formatByte() - * @covers ::formatBoolean() - * @covers ::formatDate() - * @covers ::formatDateTime() - * @covers ::typeFromSchema() */ + #[DataProvider('formatProvider')] public function testFormat($expected, $value, array $schema): void { $actual = $this->Schema->format($value, $schema); @@ -810,7 +814,7 @@ public function testFormat($expected, $value, array $schema): void * * @return array */ - public function sortableProvider(): array + public static function sortableProvider(): array { return [ 'no schema, default not sortable' => [ @@ -918,9 +922,8 @@ public function sortableProvider(): array * @param array $schema The property schema * @param bool $expected Expected result * @return void - * @dataProvider sortableProvider() - * @covers ::sortable() */ + #[DataProvider('sortableProvider')] public function testSortable(string $field, array $schema, bool $expected): void { $view = $this->Schema->getView(); @@ -939,7 +942,7 @@ public function testSortable(string $field, array $schema, bool $expected): void * * @return array */ - public function filterListProvider(): array + public static function filterListProvider(): array { return [ 'parent string' => [ @@ -982,10 +985,8 @@ public function filterListProvider(): array * @param array|null $properties The properties * @param array $expected The expected result * @return void - * @dataProvider filterListProvider() - * @covers ::filterList() - * @covers ::controlOptions() */ + #[DataProvider('filterListProvider')] public function testFilterList(array $filters, ?array $properties, array $expected): void { $view = $this->Schema->getView(); @@ -1003,7 +1004,7 @@ public function testFilterList(array $filters, ?array $properties, array $expect * * @return array */ - public function filterListByTypeProvider(): array + public static function filterListByTypeProvider(): array { return [ 'schema null' => [ @@ -1100,11 +1101,8 @@ public function filterListByTypeProvider(): array * Test `filterListByType`. * * @return void - * @dataProvider filterListByTypeProvider() - * @covers ::filterListByType() - * @covers ::filterList() - * @covers ::controlOptions() */ + #[DataProvider('filterListByTypeProvider')] public function testfilterListByType(array $filtersByType, ?array $schemasByType, array $expected): void { $view = $this->Schema->getView(); @@ -1117,7 +1115,6 @@ public function testfilterListByType(array $filtersByType, ?array $schemasByType * Test `minimalObjectsList` method. * * @return void - * @covers ::minimalObjectsList() */ public function testMinimalObjectsList(): void { diff --git a/tests/TestCase/View/Helper/SystemHelperTest.php b/tests/TestCase/View/Helper/SystemHelperTest.php index 5a8edcb3d..45e35eec9 100644 --- a/tests/TestCase/View/Helper/SystemHelperTest.php +++ b/tests/TestCase/View/Helper/SystemHelperTest.php @@ -19,12 +19,21 @@ use Cake\Core\Configure; use Cake\TestSuite\TestCase; use Cake\View\View; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use ReflectionClass; /** * {@see \App\View\Helper\SystemHelper} Test Case - * - * @coversDefaultClass \App\View\Helper\SystemHelper */ +#[CoversClass(SystemHelper::class)] +#[CoversMethod(SystemHelper::class, 'alertBgColor')] +#[CoversMethod(SystemHelper::class, 'alertMsg')] +#[CoversMethod(SystemHelper::class, 'checkBeditaApiVersion')] +#[CoversMethod(SystemHelper::class, 'getMaxFileSize')] +#[CoversMethod(SystemHelper::class, 'isBEditaApiVersionGte')] +#[CoversMethod(SystemHelper::class, 'placeholdersConfig')] +#[CoversMethod(SystemHelper::class, 'uploadConfig')] class SystemHelperTest extends TestCase { /** @@ -61,7 +70,6 @@ public function tearDown(): void * Test `getMaxFileSize` * * @return void - * @covers ::getMaxFileSize() */ public function testGetMaxFileSize(): void { @@ -82,7 +90,6 @@ public function testGetMaxFileSize(): void * Test `checkBeditaApiVersion` * * @return void - * @covers ::checkBeditaApiVersion() */ public function testCheckBeditaApiVersion(): void { @@ -120,7 +127,6 @@ public function testCheckBeditaApiVersion(): void * Test `isBEditaApiVersionGte` * * @return void - * @covers ::isBEditaApiVersionGte() */ public function testIsBEditaApiVersionGte(): void { @@ -150,12 +156,11 @@ public function testIsBEditaApiVersionGte(): void * Test `placeholdersConfig` * * @return void - * @covers ::placeholdersConfig() */ public function testPlaceholdersConfig(): void { // empty config, defaultUploadAccepted - $reflectionClass = new \ReflectionClass($this->System); + $reflectionClass = new ReflectionClass($this->System); $property = $reflectionClass->getProperty('defaultPlaceholders'); $property->setAccessible(true); $expected = $property->getValue($this->System); @@ -167,12 +172,11 @@ public function testPlaceholdersConfig(): void * Test `uploadConfig` * * @return void - * @covers ::uploadConfig() */ public function testUploadConfig(): void { // empty config, defaultUploadAccepted - $reflectionClass = new \ReflectionClass($this->System); + $reflectionClass = new ReflectionClass($this->System); $property = $reflectionClass->getProperty('defaultUploadAccepted'); $property->setAccessible(true); $accepted = $property->getValue($this->System); @@ -197,7 +201,6 @@ public function testUploadConfig(): void * Test `alertBgColor` * * @return void - * @covers ::alertBgColor() */ public function testAlertBgColor(): void { @@ -215,7 +218,6 @@ public function testAlertBgColor(): void * Test `alertMsg` * * @return void - * @covers ::alertMsg() */ public function testAlertMsg(): void { diff --git a/tests/Utils/DummyImportFilter.php b/tests/Utils/DummyImportFilter.php index 87592fae8..a1ecb073a 100644 --- a/tests/Utils/DummyImportFilter.php +++ b/tests/Utils/DummyImportFilter.php @@ -14,10 +14,11 @@ class DummyImportFilter extends ImportFilter /** * @inheritDoc */ - protected static $serviceName = ''; + protected static ?string $serviceName = ''; /** - * @inheritDoc + * {@inheritDoc} + * * @param string $filename The file name * @param string $filepath The file path * @param array $options The import options diff --git a/tests/Utils/ModulesControllerSample.php b/tests/Utils/ModulesControllerSample.php index e4c85aeac..aabdf6a31 100644 --- a/tests/Utils/ModulesControllerSample.php +++ b/tests/Utils/ModulesControllerSample.php @@ -11,6 +11,8 @@ */ class ModulesControllerSample extends ModulesController { + public ?BEditaClient $apiClient; + /** * Public version of parent function (protected) descendants * @@ -31,27 +33,6 @@ public function availableRelationshipsUrl(string $relation): string return parent::availableRelationshipsUrl($relation); } - /** - * Get api client. - * - * @return \BEdita\SDK\BEditaClient - */ - public function getApiClient(): BEditaClient - { - return $this->apiClient; - } - - /** - * Set api client. - * - * @param \BEdita\SDK\BEditaClient|null $client Api client. - * @return void - */ - public function setApiClient(?BEditaClient $client = null): void - { - $this->apiClient = $client; - } - /** * Create new object from ajax request. * diff --git a/tests/Utils/MyDummyImportFilter.php b/tests/Utils/MyDummyImportFilter.php index a1d4a25a7..57f146935 100644 --- a/tests/Utils/MyDummyImportFilter.php +++ b/tests/Utils/MyDummyImportFilter.php @@ -11,5 +11,5 @@ class MyDummyImportFilter extends DummyImportFilter /** * @inheritDoc */ - protected static $serviceName = 'My.Dummy.Import.Service.Class'; + protected static ?string $serviceName = 'My.Dummy.Import.Service.Class'; } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 1ee42f11c..6a3f3cdb1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,4 +1,10 @@ parse() ->putenv() ->toEnv() ->toServer(); } -\Cake\Cache\Cache::disable(); +Cache::disable(); -if (empty(\Cake\Core\Configure::read('API'))) { - \Cake\Core\Configure::write('API', [ +if (empty(Configure::read('API'))) { + Configure::write('API', [ 'apiBaseUrl' => env('BEDITA_API'), 'apiKey' => env('BEDITA_API_KEY'), ]); diff --git a/webpack.config.js b/webpack.config.js index 1bc2792ae..6ae390c2d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -38,6 +38,29 @@ if (devMode) { // Print env infos bundler.printMessage(message, separator); +// loaders options +const cssFileLoaderOptions = { + loader: 'file-loader', + options: { + name: `${BUNDLE.cssDir}/[name].css`, + }, +}; +const cssLoaderOptions = { + loader: 'css-loader', + options: { + sourceMap: devMode, + url: false, + } +}; +const sassLoaderOptions = { + loader: 'sass-loader', + options: { + api: 'modern', + sassOptions: { quietDeps: true, silenceDeprecations: ['mixed-decls'] }, + sourceMap: devMode, + } +}; + // Create webpack plugins list // Common Plugins let webpackPlugins = [ @@ -278,18 +301,8 @@ module.exports = { ], use: [ - { - loader: 'file-loader', - options: { - name: `${BUNDLE.cssDir}/[name].css`, - }, - }, - { - loader: 'sass-loader', - options: { - sourceMap: devMode, - } - }, + cssFileLoaderOptions, + sassLoaderOptions, ] }, { @@ -299,18 +312,8 @@ module.exports = { ], use: [ - { - loader: 'file-loader', - options: { - name: `${BUNDLE.cssDir}/[name].css`, - }, - }, - { - loader: 'sass-loader', - options: { - sourceMap: devMode, - } - }, + cssFileLoaderOptions, + sassLoaderOptions, ] }, { @@ -324,19 +327,8 @@ module.exports = { use: [ MiniCssExtractPlugin.loader, - { - loader: 'css-loader', - options: { - sourceMap: devMode, - url:false, - } - }, - { - loader: 'sass-loader', - options: { - sourceMap: devMode, - } - } + cssLoaderOptions, + sassLoaderOptions ] }, { @@ -350,19 +342,8 @@ module.exports = { use: [ MiniCssExtractPlugin.loader, - { - loader: 'css-loader', - options: { - sourceMap: devMode, - url:false, - } - }, - { - loader: 'sass-loader', - options: { - sourceMap: devMode, - } - } + cssLoaderOptions, + sassLoaderOptions ] }, { @@ -372,19 +353,8 @@ module.exports = { ], use: [ MiniCssExtractPlugin.loader, - { - loader: 'css-loader', - options: { - sourceMap: devMode, - url:false, - } - }, - { - loader: 'sass-loader', - options: { - sourceMap: devMode - } - } + cssLoaderOptions, + sassLoaderOptions ], }, { diff --git a/webpack.config.plugin.js b/webpack.config.plugin.js index d105e224b..1f59434c8 100644 --- a/webpack.config.plugin.js +++ b/webpack.config.plugin.js @@ -27,6 +27,8 @@ pluginsFound.forEach(plugin => { aliases[plugin] = path.resolve(__dirname, `${BUNDLE.beditaPluginsRoot}/${plugin}/node_modules`); }); +let sassOptions = { quietDeps: true, silenceDeprecations: ['mixed-decls'] }; + module.exports = { entry: entries, output: { @@ -88,7 +90,9 @@ module.exports = { { loader: 'sass-loader', options: { - sourceMap: devMode + sourceMap: devMode, + api: 'modern', + sassOptions: sassOptions, } } ], diff --git a/yarn.lock b/yarn.lock index 3b97be744..c50b64683 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3947,10 +3947,10 @@ mimic-fn@^1.0.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mini-css-extract-plugin@^2.9.2: - version "2.9.2" - resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz#966031b468917a5446f4c24a80854b2947503c5b" - integrity sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w== +mini-css-extract-plugin@^2.9.4: + version "2.9.4" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.4.tgz#cafa1a42f8c71357f49cd1566810d74ff1cb0200" + integrity sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ== dependencies: schema-utils "^4.0.0" tapable "^2.2.1" @@ -4851,10 +4851,10 @@ sass-loader@^12.2.0: klona "^2.0.4" neo-async "^2.6.2" -sass@^1.82.0: - version "1.84.0" - resolved "https://registry.npmjs.org/sass/-/sass-1.84.0.tgz#da9154cbccb2d2eac7a9486091b6d9ba93ef5bad" - integrity sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg== +sass@^1.90.0: + version "1.90.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.90.0.tgz#d6fc2be49c7c086ce86ea0b231a35bf9e33cb84b" + integrity sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q== dependencies: chokidar "^4.0.0" immutable "^5.0.2"