From 24bb621ac77cf0257835a682d9d8a69a51425ea8 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 23 Oct 2025 08:21:51 +0200 Subject: [PATCH 01/11] feat: upgrade dependencies --- .github/workflows/release.yml | 2 +- composer.json | 29 ++++++++++++++++------------- tests/TestCase/ApplicationTest.php | 9 +++++---- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e9b592..7f86570 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,4 +9,4 @@ jobs: uses: bedita/github-workflows/.github/workflows/release.yml@v2 with: main_branch: 'master' - dist_branches: '["master"]' + dist_branches: '["master", "2.x"]' diff --git a/composer.json b/composer.json index 4587a0d..93f82a5 100644 --- a/composer.json +++ b/composer.json @@ -6,23 +6,25 @@ "license": "MIT", "require": { "php": ">=8.3", - "bedita/api": "^5.43", - "bedita/aws": "^3.0.5", - "bedita/core": "^5.43", - "cakephp/cakephp": "^4.5.0", - "cakephp/plugin-installer": "^1.3.1" + "bedita/api": "6.x-dev", + "bedita/aws": "5.x-dev", + "bedita/core": "6.x-dev", + "cakephp/cakephp": "~5.2.9", + "cakephp/plugin-installer": "^2.0" }, - + "minimum-stability": "dev", "require-dev": { - "bedita/dev-tools": "^2", - "cakephp/bake": "^2.8", + "bedita/dev-tools": "4.x-dev", + "cakephp/bake": "^3.5.0", "cakephp/cakephp-codesniffer": "~4.7.0", - "cakephp/debug_kit": "^4.9.3", - "cakephp/repl": "^0.1", - "dereuromark/cakephp-ide-helper": "^1.18", + "cakephp/debug_kit": "^5.3.0", + "cakephp/repl": "^2.0.1", + "dereuromark/cakephp-ide-helper": "^2.5.3", "josegonzalez/dotenv": "^3.2", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.6" + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpunit/phpunit": "^11.5 || ^12.1" }, "autoload": { "psr-4": { @@ -67,8 +69,9 @@ "config": { "sort-packages": true, "allow-plugins": { + "cakephp/plugin-installer": true, "dealerdirect/phpcodesniffer-composer-installer": true, - "cakephp/plugin-installer": true + "phpstan/extension-installer": true } } } diff --git a/tests/TestCase/ApplicationTest.php b/tests/TestCase/ApplicationTest.php index fa9b22f..6f91bd8 100644 --- a/tests/TestCase/ApplicationTest.php +++ b/tests/TestCase/ApplicationTest.php @@ -19,19 +19,21 @@ use Cake\Core\Configure; use Cake\TestSuite\TestCase; use MyApp\Application; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; /** * {@see MyApp\Application} Test Case - * - * @coversDefaultClass \MyApp\Application */ +#[CoversClass(Application::class)] +#[CoversMethod(Application::class, 'bootstrap')] +#[CoversMethod(Application::class, 'bootstrapCli')] class ApplicationTest extends TestCase { /** * Test `bootstrap` method * * @return void - * @covers ::bootstrap() */ public function testBootstrap() { @@ -47,7 +49,6 @@ public function testBootstrap() * Test `bootstrapCli` method * * @return void - * @covers ::bootstrapCli() */ public function testBootstrapCli() { From 0c5e0a9b9d868ae965f3b490bcddb606966d89c4 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 23 Oct 2025 09:01:21 +0200 Subject: [PATCH 02/11] fix: bootstrap, phpunit, php workflow, gitignore --- .github/workflows/php.yml | 6 ++--- .gitignore | 1 + phpunit.xml.dist | 55 +++++++++++++++++++-------------------- tests/bootstrap.php | 33 ++++++++++++----------- 4 files changed, 47 insertions(+), 48 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 1267b00..32df57d 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -16,12 +16,12 @@ jobs: cs: uses: bedita/github-workflows/.github/workflows/php-cs.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: name: 'Run unit tests' @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: [8.3] + php-version: [8.3, 8.4] env: PHP_VERSION: '${{ matrix.php-version }}' diff --git a/.gitignore b/.gitignore index 68780d2..184eaa5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ Thumbs.db # Tool specific files # ####################### # PHPUnit +.phpunit.cache .phpunit.result.cache tests.sqlite # vim diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bc417c5..e9e85c3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,30 +1,29 @@ - - - - ./src/ - - - src/Console/Installer.php - - - - - - - - - - tests/TestCase/ - - - - - - - - - - - + + + + ./src/ + + + src/Console/Installer.php + + + + + + + + + + ./tests/TestCase/ + + diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 6826d58..aa61206 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -26,7 +26,17 @@ */ require dirname(__DIR__) . '/vendor/autoload.php'; -require dirname(__DIR__) . '/config/bootstrap.php'; +define('ROOT', dirname(__DIR__)); +define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'vendor' . DS . 'cakephp' . DS . 'cakephp'); +define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); +define('CAKE', CORE_PATH . 'src' . DS); +define('TMP', sys_get_temp_dir() . DS); +define('LOGS', ROOT . DS . 'logs' . DS); +define('CONFIG', ROOT . DS . 'config' . DS); +define('CACHE', TMP . 'cache' . DS); + +require CORE_PATH . 'config' . DS . 'bootstrap.php'; +require CAKE . 'functions.php'; if (empty($_SERVER['HTTP_HOST']) && !Configure::read('App.fullBaseUrl')) { Configure::write('App.fullBaseUrl', 'http://localhost'); @@ -44,21 +54,10 @@ 'quoteIdentifiers' => false, ]); +//ConnectionManager::alias('test', 'default'); ConnectionManager::alias('test_debug_kit', 'debug_kit'); -// Fixate sessionid early on, as php7.2+ -// does not allow the sessionid to be set after stdout -// has been written to. -session_id('cli'); - -// Use migrations to build test database schema. -// -// Will rebuild the database if the migration state differs -// from the migration history in files. -// -// If you are not using CakePHP's migrations you can -// hook into your migration tool of choice here or -// load schema from a SQL dump file with -// use Cake\TestSuite\Fixture\SchemaLoader; -// (new SchemaLoader())->loadSqlFiles('./tests/schema.sql', 'test'); -// (new Migrator())->run(); +// (new Migrator())->runMany([ +// ['plugin' => 'BEdita/Core', 'connection' => 'test'], +// ['connection' => 'test'], // default migrations of this application +// ]); From d1f71f3d3ba7293bfa0b1deafef75ebec1f285b0 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 23 Oct 2025 10:33:15 +0200 Subject: [PATCH 03/11] refactor: update files as in latest cakephp/app --- .editorconfig | 5 +- .gitattributes | 5 +- .gitignore | 5 +- composer.json | 11 ++- config/.env.example | 2 +- config/app.php | 123 +++++++++++++++++++++++------ config/app_local.example.php | 3 + config/bootstrap.php | 123 ++++++++++++++++++++++------- config/bootstrap_cli.php | 35 -------- config/routes.php | 2 +- phpcs.xml | 3 + phpstan.neon.dist | 2 +- phpunit.xml.dist | 26 ++++-- psalm.xml | 15 ++++ src/Application.php | 8 ++ src/Console/Installer.php | 21 ++--- tests/TestCase/ApplicationTest.php | 72 ++++++++++++----- tests/bootstrap.php | 44 +++++++---- 18 files changed, 352 insertions(+), 153 deletions(-) delete mode 100644 config/bootstrap_cli.php create mode 100644 psalm.xml diff --git a/.editorconfig b/.editorconfig index 209e731..87b5178 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,5 @@ ; This file is for unifying the coding style for different editors and IDEs. -; More information at http://editorconfig.org +; More information at https://editorconfig.org root = true @@ -19,5 +19,8 @@ indent_size = 2 [*.twig] insert_final_newline = false +[*.neon] +indent_style = tab + [Makefile] indent_style = tab diff --git a/.gitattributes b/.gitattributes index b89e116..2e7fdfe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,6 @@ # Define the line ending behavior of the different file extensions # Set default behavior, in case users don't have core.autocrlf set. -* text=auto -* text eol=lf +* text text=auto eol=lf # Explicitly declare text files we want to always be normalized and converted # to native line endings on checkout. @@ -33,6 +32,7 @@ *.jpeg binary *.gif binary *.webp binary +*.avif binary *.ico binary *.mo binary *.pdf binary @@ -41,6 +41,7 @@ *.phar binary *.woff binary *.woff2 binary +*.ttc binary *.ttf binary *.otf binary *.eot binary diff --git a/.gitignore b/.gitignore index 184eaa5..502bf97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# User specific & automatically generated files # -################################################# +# CakePHP specific files # +########################## /config/app_local.php /config/.env /logs/* @@ -30,7 +30,6 @@ Thumbs.db ####################### # PHPUnit .phpunit.cache -.phpunit.result.cache tests.sqlite # vim *~ diff --git a/composer.json b/composer.json index 93f82a5..743d290 100644 --- a/composer.json +++ b/composer.json @@ -16,16 +16,19 @@ "require-dev": { "bedita/dev-tools": "4.x-dev", "cakephp/bake": "^3.5.0", - "cakephp/cakephp-codesniffer": "~4.7.0", + "cakephp/cakephp-codesniffer": "^5.0", "cakephp/debug_kit": "^5.3.0", "cakephp/repl": "^2.0.1", "dereuromark/cakephp-ide-helper": "^2.5.3", - "josegonzalez/dotenv": "^3.2", + "josegonzalez/dotenv": "^4.0", "phpstan/phpstan": "^1.10", "phpstan/extension-installer": "^1.0", "phpstan/phpstan-deprecation-rules": "^1.0", "phpunit/phpunit": "^11.5 || ^12.1" }, + "suggest": { + "markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification." + }, "autoload": { "psr-4": { "MyApp\\": "src" @@ -47,8 +50,8 @@ "@stan" ], "stan": "vendor/bin/phpstan analyse", - "cs-check": "vendor/bin/phpcs -n -p --extensions=php src/ tests/ config/*.php", - "cs-fix": "vendor/bin/phpcbf -p --extensions=php src/ tests/ config/*.php", + "cs-check": "vendor/bin/phpcs -n -p --extensions=php --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/ config/*.php", + "cs-fix": "vendor/bin/phpcbf -p --extensions=php --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/ config/*.php", "test": "vendor/bin/phpunit --colors=always", "migrate": [ "@cache-clear", diff --git a/config/.env.example b/config/.env.example index e90937b..01bf3a4 100644 --- a/config/.env.example +++ b/config/.env.example @@ -23,7 +23,7 @@ export SECURITY_SALT="__SALT__" # Uncomment these to define cache configuration via environment variables. #export CACHE_DURATION="+2 minutes" #export CACHE_DEFAULT_URL="file:///path/to/tmp/cache/?prefix=${APP_NAME}_default_&duration=${CACHE_DURATION}" -#export CACHE_CAKECORE_URL="file:///path/to/tmp/cache/persistent?prefix=${APP_NAME}_cake_core_&serialize=true&duration=${CACHE_DURATION}" +#export CACHE_CAKECORE_URL="file:///path/to/tmp/cache/persistent?prefix=${APP_NAME}_cake_translations_&serialize=true&duration=${CACHE_DURATION}" #export CACHE_CAKEMODEL_URL="file:///path/to/tmp/cache/models?prefix=${APP_NAME}_cake_model_&serialize=true&duration=${CACHE_DURATION}" # Uncomment these to define email transport configuration via environment variables. diff --git a/config/app.php b/config/app.php index 8319925..7c7b231 100644 --- a/config/app.php +++ b/config/app.php @@ -6,6 +6,7 @@ use Cake\Database\Connection; use Cake\Database\Driver\Mysql; use Cake\Log\Engine\FileLog; +use Cake\Mailer\Transport\MailTransport; return [ /** @@ -118,9 +119,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' => 'myapp_cake_core_', + 'prefix' => 'myapp_cake_translations_', 'path' => CACHE . 'persistent' . DS, 'serialize' => true, 'duration' => '+1 years', @@ -169,7 +170,7 @@ ], ], - /** + /* * Configure the Error and Exception handlers used by your application. * * By default errors are displayed using Debugger, when debug is true and logged @@ -183,11 +184,11 @@ * Options: * * - `errorLevel` - int - The level of errors you are interested in capturing. - * - `trace` - boolean - Whether or not backtraces should be included in + * - `trace` - boolean - Whether backtraces should be included in * logged errors/exceptions. - * - `log` - boolean - Whether or not you want exceptions logged. + * - `log` - boolean - Whether you want exceptions logged. * - `exceptionRenderer` - string - The class responsible for rendering uncaught exceptions. - * The chosen class will be used for for both CLI and web environments. If you want different + * The chosen class will be used for both CLI and web environments. If you want different * classes used in CLI and web environments you'll need to write that conditional logic as well. * The conventional location for custom renderers is in `src/Error`. Your exception renderer needs to * implement the `render()` method and return either a string or Http\Response. @@ -202,7 +203,7 @@ * - `extraFatalErrorMemory` - int - The number of megabytes to increase the memory limit by * when a fatal error is encountered. This allows * breathing room to complete logging or error handling. - * - `ignoredDeprecationPaths` - array - A list of glob compatible file paths that deprecations + * - `ignoredDeprecationPaths` - array - A list of glob-compatible file paths that deprecations * should be ignored in. Use this to ignore deprecations for plugins or parts of * your application that still emit deprecations. */ @@ -212,10 +213,10 @@ 'skipLog' => ['Cake\Network\Exception\NotFoundException', 'BEdita\API\Exception\ExpiredTokenException'], 'log' => true, 'trace' => true, - 'ignoredDeprecationPaths' => [], + 'ignoredDeprecationPaths' => ['vendor/cakephp/cakephp/src/Log/Engine/FileLog.php'], ], - /** + /* * Debugger configuration * * Define development error values for Cake\Error\Debugger @@ -231,7 +232,7 @@ 'editor' => 'vscode', ], - /** + /* * Email configuration. * * By defining transports separately from delivery profiles you can easily @@ -252,17 +253,32 @@ */ 'EmailTransport' => [ 'default' => [ + 'className' => MailTransport::class, + /* + * The keys host, port, timeout, username, password, client and tls + * are used in SMTP transports + */ + //'host' => 'localhost', + //'port' => 25, + //'timeout' => 30, + /* + * It is recommended to set these options through your environment or app_local.php + */ + //'username' => null, + //'password' => null, + //'client' => null, + //'tls' => false, 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), ], ], - /** + /* * Email delivery profiles * * Delivery profiles allow you to predefine various properties about email * messages from your application and give the settings a name. This saves * duplication across your application and makes maintenance and development - * easier. Each profile accepts a number of keys. See `Cake\Mailer\Email` + * easier. Each profile accepts a number of keys. See `Cake\Mailer\Mailer` * for more information. */ 'Email' => [ @@ -277,14 +293,14 @@ ], ], - /** + /* * Connection information used by the ORM to connect * to your application's datastores. * * ### Notes * - Drivers include Mysql Postgres Sqlite Sqlserver - * See vendor\cakephp\cakephp\src\Database\Driver for complete list - * - Do not use periods in database name - it may lead to error. + * See vendor\cakephp\cakephp\src\Database\Driver for the complete list + * - Do not use periods in database name - it may lead to errors. * See https://github.com/cakephp/cakephp/issues/6471 for details. * - 'encoding' is recommended to be set to full UTF-8 4-Byte support. * E.g set it to 'utf8mb4' in MariaDB and MySQL and 'utf8' for any @@ -298,8 +314,8 @@ * The values in app_local.php will override any values set here * and should be used for local and per-environment configurations. * - * Environment variable based configurations can be loaded here or - * in app_local.php depending on the applications needs. + * Environment variable-based configurations can be loaded here or + * in app_local.php depending on the application's needs. */ 'default' => [ 'className' => Connection::class, @@ -345,6 +361,16 @@ * The test connection is used during the test suite. */ 'test' => [ + // 'className' => Connection::class, + // 'driver' => Mysql::class, + // 'persistent' => false, + // 'timezone' => 'UTC', + // 'encoding' => 'utf8mb4', + // 'flags' => [], + // 'cacheMetadata' => true, + // 'quoteIdentifiers' => false, + // 'log' => false, + //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], 'url' => env('DATABASE_TEST_URL', 'sqlite:///tmp/bedita5_test.sqlite'), ], ], @@ -379,7 +405,7 @@ ], ], - /** + /* * Session configuration. * * Contains an array of settings to use for session configuration. The @@ -392,18 +418,23 @@ * Avoid using `.` in cookie names, as PHP will drop sessions from cookies with `.` in the name. * - `cookiePath` - The url path for which session cookie is set. Maps to the * `session.cookie_path` php.ini config. Defaults to base path of app. - * - `timeout` - The time in minutes the session should be valid for. - * Pass 0 to disable checking timeout. - * Please note that php.ini's session.gc_maxlifetime must be equal to or greater - * than the largest Session['timeout'] in all served websites for it to have the - * desired effect. + * - `timeout` - The time in minutes a session can be 'idle'. If no request is received in + * this duration, the session will be expired and rotated. Pass 0 to disable idle timeout checks. * - `defaults` - The default configuration set to use as a basis for your session. * There are four built-in options: php, cake, cache, database. * - `handler` - Can be used to enable a custom session handler. Expects an * array with at least the `engine` key, being the name of the Session engine * class to use for managing the session. CakePHP bundles the `CacheSession` * and `DatabaseSession` engines. - * - `ini` - An associative array of additional ini values to set. + * - `ini` - An associative array of additional 'session.*` ini values to set. + * + * Within the `ini` key, you will likely want to define: + * + * - `session.cookie_lifetime` - The number of seconds that cookies are valid for. This + * should be longer than `Session.timeout`. + * - `session.gc_maxlifetime` - The number of seconds after which a session is considered 'garbage' + * that can be deleted by PHP's session cleanup behavior. This value should be greater than both + * `Sesssion.timeout` and `session.cookie_lifetime`. * * The built-in `defaults` options are: * @@ -412,7 +443,7 @@ * - 'database' - Uses CakePHP's database sessions. * - 'cache' - Use the Cache class to save sessions. * - * To define a custom session handler, save it at src/Network/Session/.php. + * To define a custom session handler, save it at src/Http/Session/.php. * Make sure the class implements PHP's `SessionHandlerInterface` and set * Session.handler to * @@ -422,6 +453,48 @@ 'defaults' => 'php', ], + /** + * DebugKit configuration. + * + * Contains an array of configurations to apply to the DebugKit plugin, if loaded. + * Documentation: https://book.cakephp.org/debugkit/5/en/index.html#configuration + * + * ## Options + * + * - `panels` - Enable or disable panels. The key is the panel name, and the value is true to enable, + * or false to disable. + * - `includeSchemaReflection` - Set to true to enable logging of schema reflection queries. Disabled by default. + * - `safeTld` - Set an array of whitelisted TLDs for local development. + * - `forceEnable` - Force DebugKit to display. Careful with this, it is usually safer to simply whitelist + * your local TLDs. + * - `ignorePathsPattern` - Regex pattern (including delimiter) to ignore paths. + * DebugKit won’t save data for request URLs that match this regex. + * - `ignoreAuthorization` - Set to true to ignore Cake Authorization plugin for DebugKit requests. + * Disabled by default. + * - `maxDepth` - Defines how many levels of nested data should be shown in general for debug output. + * Default is 5. WARNING: Increasing the max depth level can lead to an out of memory error. + * - `variablesPanelMaxDepth` - Defines how many levels of nested data should be shown in the variables tab. + * Default is 5. WARNING: Increasing the max depth level can lead to an out of memory error. + */ + 'DebugKit' => [ + 'forceEnable' => filter_var(env('DEBUG_KIT_FORCE_ENABLE', false), FILTER_VALIDATE_BOOLEAN), + 'safeTld' => env('DEBUG_KIT_SAFE_TLD', null), + 'ignoreAuthorization' => env('DEBUG_KIT_IGNORE_AUTHORIZATION', false), + ], + + /** + * TestSuite configuration. + * + * ## Options + * + * - `errorLevel` - Defaults to `E_ALL`. Can be set to `false` to disable overwrite error level. + * - `fixtureStrategy` - Defaults to TruncateStrategy. Can be set to any class implementing FixtureStrategyInterface. + */ + 'TestSuite' => [ + 'errorLevel' => null, + 'fixtureStrategy' => null, + ], + /** * Filesystem configuration. * diff --git a/config/app_local.example.php b/config/app_local.example.php index c800880..bd59b41 100644 --- a/config/app_local.example.php +++ b/config/app_local.example.php @@ -1,4 +1,7 @@ getMessage() . "\n"); } @@ -89,19 +96,18 @@ } /* - * When debug = true the metadata cache should only last - * for a short time. + * When debug = true the metadata cache should only last for a short time. */ if (Configure::read('debug')) { Configure::write('Cache._bedita_core_.duration', '+2 minutes'); Configure::write('Cache._bedita_object_types_.duration', '+2 minutes'); - Configure::write('Cache._cake_model_.duration', '+2 minutes'); - Configure::write('Cache._cake_core_.duration', '+2 minutes'); + Configure::write('Cache._cake_model_.duration', '+1 minute'); + Configure::write('Cache._cake_translations_.duration', '+1 minute'); } /* * Set the default server timezone. Using UTC makes time calculations / conversions easier. - * Check http://php.net/manual/en/timezones.php for list of valid timezone strings. + * Check https://php.net/manual/en/timezones.php for list of valid timezone strings. */ date_default_timezone_set(Configure::read('App.defaultTimezone')); @@ -123,15 +129,26 @@ (new ExceptionTrap(Configure::read('Error')))->register(); /* - * Include the CLI bootstrap overrides. + * CLI/Command specific configuration. */ if (PHP_SAPI === 'cli') { - require CONFIG . 'bootstrap_cli.php'; + // Set the fullBaseUrl to allow URLs to be generated in commands. + // This is useful when sending email from commands. + // Configure::write('App.fullBaseUrl', php_uname('n')); + + // Set logs to different files so they don't have permission conflicts. + if (Configure::check('Log.debug')) { + Configure::write('Log.debug.file', 'cli-debug'); + } + if (Configure::check('Log.error')) { + Configure::write('Log.error.file', 'cli-error'); + } } /* * Set the full base URL. * This URL is used as the base of all absolute links. + * Can be very useful for CLI/Commandline applications. */ $fullBaseUrl = Configure::read('App.fullBaseUrl'); if (!$fullBaseUrl) { @@ -141,7 +158,7 @@ * you can enable `$trustProxy` to rely on the `X-Forwarded-Proto` * header to determine whether to generate URLs using `https`. * - * See also https://book.cakephp.org/4/en/controllers/request-response.html#trusting-proxy-headers + * See also https://book.cakephp.org/5/en/controllers/request-response.html#trusting-proxy-headers */ $trustProxy = false; @@ -151,7 +168,7 @@ } $httpHost = env('HTTP_HOST'); - if (isset($httpHost)) { + if ($httpHost) { $fullBaseUrl = 'http' . $s . '://' . $httpHost; } unset($httpHost, $s); @@ -161,9 +178,59 @@ } unset($fullBaseUrl); -Cache::setConfig(Configure::consume('Cache') ?: []); -ConnectionManager::setConfig(Configure::consume('Datasources') ?: []); -TransportFactory::setConfig(Configure::consume('EmailTransport') ?: []); -Mailer::setConfig(Configure::consume('Email') ?: []); -Log::setConfig(Configure::consume('Log') ?: []); -Security::setSalt((string)Configure::consume('Security.salt')); +/* + * Apply the loaded configuration settings to their respective systems. + * This will also remove the loaded config data from memory. + */ +Cache::setConfig(Configure::consume('Cache')); +ConnectionManager::setConfig(Configure::consume('Datasources')); +TransportFactory::setConfig(Configure::consume('EmailTransport')); +Mailer::setConfig(Configure::consume('Email')); +Log::setConfig(Configure::consume('Log')); +Security::setSalt(Configure::consume('Security.salt')); + +/* + * Setup detectors for mobile and tablet. + * If you don't use these checks you can safely remove this code + * and the mobiledetect package from composer.json. + */ +// ServerRequest::addDetector('mobile', function ($request) { +// $detector = new \Detection\MobileDetect(); + +// return $detector->isMobile(); +// }); +// ServerRequest::addDetector('tablet', function ($request) { +// $detector = new \Detection\MobileDetect(); + +// return $detector->isTablet(); +// }); + +/* + * You can enable default locale format parsing by adding calls + * to `useLocaleParser()`. This enables the automatic conversion of + * locale specific date formats when processing request data. For details see + * @link https://book.cakephp.org/5/en/core-libraries/internationalization-and-localization.html#parsing-localized-datetime-data + */ +// \Cake\Database\TypeFactory::build('time')->useLocaleParser(); +// \Cake\Database\TypeFactory::build('date')->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetime')->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestamp')->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetimefractional')->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestampfractional')->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetimetimezone')->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestamptimezone')->useLocaleParser(); + +/* + * Custom Inflector rules, can be set to correctly pluralize or singularize + * table, model, controller names or whatever other string is passed to the + * inflection functions. + */ +// \Cake\Utility\Inflector::rules('plural', ['/^(inflect)or$/i' => '\1ables']); +// \Cake\Utility\Inflector::rules('irregular', ['red' => 'redlings']); +// \Cake\Utility\Inflector::rules('uninflected', ['dontinflectme']); + +// set a custom date and time format +// see https://book.cakephp.org/5/en/core-libraries/time.html#setting-the-default-locale-and-format-string +// and https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax +// \Cake\I18n\Date::setToStringFormat('dd.MM.yyyy'); +// \Cake\I18n\Time::setToStringFormat('dd.MM.yyyy HH:mm'); diff --git a/config/bootstrap_cli.php b/config/bootstrap_cli.php deleted file mode 100644 index fc0dc30..0000000 --- a/config/bootstrap_cli.php +++ /dev/null @@ -1,35 +0,0 @@ - + + */src/Controller/* + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 40cb809..cb0d17d 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,4 +1,5 @@ parameters: + level: 9 bootstrapFiles: - tests/bootstrap.php paths: @@ -6,4 +7,3 @@ parameters: - tests excludePaths: - src/Console/Installer.php - level: 1 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e9e85c3..affe678 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -8,22 +8,32 @@ cacheDirectory=".phpunit.cache" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.1/phpunit.xsd" > - - - ./src/ - - - src/Console/Installer.php - - + ./tests/TestCase/ + + + + + + + + + + + src/ + plugins/*/src/ + + + src/Console/Installer.php + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..4e8b692 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/src/Application.php b/src/Application.php index c07afa9..e80dc88 100644 --- a/src/Application.php +++ b/src/Application.php @@ -16,6 +16,8 @@ use BEdita\API\App\BaseApplication; use Cake\Core\Configure; +use Cake\Datasource\FactoryLocator; +use Cake\ORM\Locator\TableLocator; /** * Application setup class. @@ -39,6 +41,11 @@ public function bootstrap(): void // Load other plugins via `Plugin` configuration key $this->addConfigPlugins(); + + if (PHP_SAPI !== 'cli') { + // The bake plugin requires fallback table classes to work properly + FactoryLocator::add('Table', (new TableLocator())->allowFallbackClass(false)); + } } /** @@ -49,6 +56,7 @@ protected function bootstrapCli(): void parent::bootstrapCli(); if (Configure::read('debug')) { $this->addOptionalPlugin('Cake/Repl'); + $this->addOptionalPlugin('DebugKit'); } } } diff --git a/src/Console/Installer.php b/src/Console/Installer.php index 838882b..229d86a 100644 --- a/src/Console/Installer.php +++ b/src/Console/Installer.php @@ -22,6 +22,7 @@ use Cake\Codeception\Console\Installer as CodeceptionInstaller; use Cake\Utility\Security; +use Composer\IO\IOInterface; use Composer\Script\Event; use Exception; @@ -52,7 +53,7 @@ class Installer * @throws \Exception Exception raised by validator. * @return void */ - public static function postInstall(Event $event) + public static function postInstall(Event $event): void { $io = $event->getIO(); @@ -76,7 +77,7 @@ public static function postInstall(Event $event) * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function createAppLocalConfig($dir, $io) + public static function createAppLocalConfig(string $dir, IOInterface $io): void { $appLocalConfig = $dir . '/config/app_local.php'; $appLocalConfigTemplate = $dir . '/config/app_local.example.php'; @@ -93,7 +94,7 @@ public static function createAppLocalConfig($dir, $io) * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function createWritableDirectories($dir, $io) + public static function createWritableDirectories(string $dir, IOInterface $io): void { foreach (static::WRITABLE_DIRS as $path) { $path = $dir . '/' . $path; @@ -113,7 +114,7 @@ public static function createWritableDirectories($dir, $io) * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function setFolderPermissions($dir, $io) + public static function setFolderPermissions(string $dir, IOInterface $io): void { // ask if the permissions should be changed if ($io->isInteractive()) { @@ -127,7 +128,7 @@ public static function setFolderPermissions($dir, $io) 'Set Folder Permissions ? (Default to Y) [Y,n]? ', $validator, 10, - 'Y' + 'Y', ); if (in_array($setFolderPermissions, ['n', 'N'])) { @@ -136,7 +137,7 @@ public static function setFolderPermissions($dir, $io) } // 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) { @@ -151,7 +152,7 @@ public static function setFolderPermissions($dir, $io) } }; - $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; @@ -177,7 +178,7 @@ public static function setFolderPermissions($dir, $io) * @param \Composer\IO\IOInterface $io IO interface to write to console. * @return void */ - public static function setSecuritySalt($dir, $io) + public static function setSecuritySalt(string $dir, IOInterface $io): void { $newKey = hash('sha256', Security::randomBytes(64)); static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php'); @@ -192,7 +193,7 @@ public static function setSecuritySalt($dir, $io) * @param string $file A path to a file relative to the application's root * @return void */ - public static function setSecuritySaltInFile($dir, $io, $newKey, $file) + public static function setSecuritySaltInFile(string $dir, IOInterface $io, string $newKey, string $file): void { $config = $dir . '/config/' . $file; $content = file_get_contents($config); @@ -223,7 +224,7 @@ public static function setSecuritySaltInFile($dir, $io, $newKey, $file) * @param string $file A path to a file relative to the application's root * @return void */ - public static function setAppNameInFile($dir, $io, $appName, $file) + 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/tests/TestCase/ApplicationTest.php b/tests/TestCase/ApplicationTest.php index 6f91bd8..3c00efd 100644 --- a/tests/TestCase/ApplicationTest.php +++ b/tests/TestCase/ApplicationTest.php @@ -14,49 +14,85 @@ * @since 3.3.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ + namespace MyApp\Test\TestCase; +use Authentication\Middleware\AuthenticationMiddleware; +use Authorization\Middleware\AuthorizationMiddleware; +use BEdita\API\Middleware\ApplicationMiddleware; +use BEdita\API\Middleware\BodyParserMiddleware; +use BEdita\API\Middleware\LoggedUserMiddleware; use Cake\Core\Configure; +use Cake\Error\Middleware\ErrorHandlerMiddleware; +use Cake\Http\MiddlewareQueue; +use Cake\Routing\Middleware\RoutingMiddleware; +use Cake\TestSuite\IntegrationTestTrait; use Cake\TestSuite\TestCase; use MyApp\Application; -use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\CoversMethod; /** - * {@see MyApp\Application} Test Case + * ApplicationTest class */ -#[CoversClass(Application::class)] -#[CoversMethod(Application::class, 'bootstrap')] -#[CoversMethod(Application::class, 'bootstrapCli')] class ApplicationTest extends TestCase { + use IntegrationTestTrait; + /** - * Test `bootstrap` method + * Test bootstrap in production. * * @return void */ public function testBootstrap() { - Configure::write('Plugins', []); - $app = new Application(CONFIG); + Configure::write('debug', false); + $app = new Application(dirname(__DIR__, 2) . '/config'); $app->bootstrap(); - static::assertTrue($app->getPlugins()->has('BEdita/Core')); - static::assertTrue($app->getPlugins()->has('BEdita/API')); - static::assertTrue($app->getPlugins()->has('Migrations')); + $plugins = $app->getPlugins(); + + $this->assertTrue($plugins->has('Bake'), 'plugins has Bake?'); + $this->assertFalse($plugins->has('DebugKit'), 'plugins has DebugKit?'); + $this->assertTrue($plugins->has('Migrations'), 'plugins has Migrations?'); } /** - * Test `bootstrapCli` method + * Test bootstrap add DebugKit plugin in debug mode. * * @return void */ - public function testBootstrapCli() + public function testBootstrapInDebug() { - $currDebug = Configure::read('debug'); Configure::write('debug', true); - $app = new Application(CONFIG); + $app = new Application(dirname(__DIR__, 2) . '/config'); $app->bootstrap(); - static::assertTrue($app->getPlugins()->has('Cake/Repl')); - Configure::write('debug', $currDebug); + $plugins = $app->getPlugins(); + + $this->assertTrue($plugins->has('DebugKit'), 'plugins has DebugKit?'); + } + + /** + * testMiddleware + * + * @return void + */ + public function testMiddleware() + { + $app = new Application(dirname(__DIR__, 2) . '/config'); + $middleware = new MiddlewareQueue(); + + $middleware = $app->middleware($middleware); + + $this->assertInstanceOf(ErrorHandlerMiddleware::class, $middleware->current()); + $middleware->seek(1); + $this->assertInstanceOf(RoutingMiddleware::class, $middleware->current()); + $middleware->seek(2); + $this->assertInstanceOf(BodyParserMiddleware::class, $middleware->current()); + $middleware->seek(3); + $this->assertInstanceOf(AuthenticationMiddleware::class, $middleware->current()); + $middleware->seek(4); + $this->assertInstanceOf(ApplicationMiddleware::class, $middleware->current()); + $middleware->seek(5); + $this->assertInstanceOf(LoggedUserMiddleware::class, $middleware->current()); + $middleware->seek(6); + $this->assertInstanceOf(AuthorizationMiddleware::class, $middleware->current()); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index aa61206..2f38af9 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -15,8 +15,11 @@ * @license https://opensource.org/licenses/mit-license.php MIT License */ +use Cake\Chronos\Chronos; use Cake\Core\Configure; use Cake\Datasource\ConnectionManager; +use Cake\TestSuite\ConnectionHelper; +use Migrations\TestSuite\Migrator; /** * Test runner bootstrap. @@ -26,17 +29,7 @@ */ require dirname(__DIR__) . '/vendor/autoload.php'; -define('ROOT', dirname(__DIR__)); -define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'vendor' . DS . 'cakephp' . DS . 'cakephp'); -define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); -define('CAKE', CORE_PATH . 'src' . DS); -define('TMP', sys_get_temp_dir() . DS); -define('LOGS', ROOT . DS . 'logs' . DS); -define('CONFIG', ROOT . DS . 'config' . DS); -define('CACHE', TMP . 'cache' . DS); - -require CORE_PATH . 'config' . DS . 'bootstrap.php'; -require CAKE . 'functions.php'; +require dirname(__DIR__) . '/config/bootstrap.php'; if (empty($_SERVER['HTTP_HOST']) && !Configure::read('App.fullBaseUrl')) { Configure::write('App.fullBaseUrl', 'http://localhost'); @@ -54,10 +47,29 @@ 'quoteIdentifiers' => false, ]); -//ConnectionManager::alias('test', 'default'); ConnectionManager::alias('test_debug_kit', 'debug_kit'); -// (new Migrator())->runMany([ -// ['plugin' => 'BEdita/Core', 'connection' => 'test'], -// ['connection' => 'test'], // default migrations of this application -// ]); +// Fixate now to avoid one-second-leap-issues +Chronos::setTestNow(Chronos::now()); + +// Fixate sessionid early on, as php7.2+ +// does not allow the sessionid to be set after stdout +// has been written to. +session_id('cli'); + +// Connection aliasing needs to happen before migrations are run. +// Otherwise, table objects inside migrations would use the default datasource +ConnectionHelper::addTestAliases(); + +// Use migrations to build test database schema. +// +// Will rebuild the database if the migration state differs +// from the migration history in files. +// +// If you are not using CakePHP's migrations you can +// hook into your migration tool of choice here or +// load schema from a SQL dump file with +// use Cake\TestSuite\Fixture\SchemaLoader; +// (new SchemaLoader())->loadSqlFiles('./tests/schema.sql', 'test'); + +(new Migrator())->run(); From 4c06373db6e3b56b3ec57065093e1a24e17fc9b9 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 23 Oct 2025 10:36:39 +0200 Subject: [PATCH 04/11] chore fix: bootstrap --- src/Application.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Application.php b/src/Application.php index e80dc88..50ee92a 100644 --- a/src/Application.php +++ b/src/Application.php @@ -16,8 +16,6 @@ use BEdita\API\App\BaseApplication; use Cake\Core\Configure; -use Cake\Datasource\FactoryLocator; -use Cake\ORM\Locator\TableLocator; /** * Application setup class. @@ -42,10 +40,10 @@ public function bootstrap(): void // Load other plugins via `Plugin` configuration key $this->addConfigPlugins(); - if (PHP_SAPI !== 'cli') { - // The bake plugin requires fallback table classes to work properly - FactoryLocator::add('Table', (new TableLocator())->allowFallbackClass(false)); - } + // if (PHP_SAPI !== 'cli') { + // // The bake plugin requires fallback table classes to work properly + // FactoryLocator::add('Table', (new TableLocator())->allowFallbackClass(false)); + // } } /** From 3094bc7dfeec1e9b6e44e1b2df50934beebc8795 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 23 Oct 2025 10:38:10 +0200 Subject: [PATCH 05/11] feat: load IdeHelper --- src/Application.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Application.php b/src/Application.php index 50ee92a..a90e3ef 100644 --- a/src/Application.php +++ b/src/Application.php @@ -56,5 +56,6 @@ protected function bootstrapCli(): void $this->addOptionalPlugin('Cake/Repl'); $this->addOptionalPlugin('DebugKit'); } + $this->addOptionalPlugin('IdeHelper'); } } From e7cd840c0ea41de54175bec15107b4e83065a623 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Fri, 24 Oct 2025 13:39:09 +0200 Subject: [PATCH 06/11] fix: add baseUrl key to Filesystem conf --- .github/workflows/php.yml | 8 ++++++++ config/app.php | 2 ++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 32df57d..06aa901 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -6,11 +6,19 @@ on: - '**/*.php' - '.github/workflows/php.yml' - '**/composer.json' + - 'phpcs.xml' + - 'phpstan.neon.dist' + - 'phpunit.xml.dist' + - 'psalm.xml' push: paths: - '**/*.php' - '.github/workflows/php.yml' - '**/composer.json' + - 'phpcs.xml' + - 'phpstan.neon.dist' + - 'phpunit.xml.dist' + - 'psalm.xml' jobs: cs: diff --git a/config/app.php b/config/app.php index 7c7b231..b04a7c5 100644 --- a/config/app.php +++ b/config/app.php @@ -505,11 +505,13 @@ 'default' => [ 'className' => 'BEdita/Core.Local', 'path' => WWW_ROOT . '_files', + 'baseUrl' => env('FILESYSTEM_BASE_DEFAULT_URL', null), 'url' => env('FILESYSTEM_DEFAULT_URL', null), ], 'thumbnails' => [ 'className' => 'BEdita/Core.Local', 'path' => WWW_ROOT . '_files' . DS . 'thumbs', + 'baseUrl' => env('FILESYSTEM_BASE_THUMBNAILS_URL', null), 'url' => env('FILESYSTEM_THUMBNAILS_URL', null), ], ], From dd901453b3d2bf29f3c772d67fe756ed04d7fe78 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Tue, 28 Oct 2025 10:37:36 +0100 Subject: [PATCH 07/11] feat: use bedita dev-tools 3.2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 743d290..8ba273d 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ }, "minimum-stability": "dev", "require-dev": { - "bedita/dev-tools": "4.x-dev", + "bedita/dev-tools": "^3.2", "cakephp/bake": "^3.5.0", "cakephp/cakephp-codesniffer": "^5.0", "cakephp/debug_kit": "^5.3.0", From 5b13417de04f3dc1afc47835cd1d2e32c3d20b24 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Tue, 4 Nov 2025 16:15:39 +0100 Subject: [PATCH 08/11] fix: non static function in routes.php --- config/routes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.php b/config/routes.php index 9726906..27962f3 100644 --- a/config/routes.php +++ b/config/routes.php @@ -24,7 +24,7 @@ use Cake\Routing\Route\DashedRoute; use Cake\Routing\RouteBuilder; -return static function (RouteBuilder $routes): void { +return function (RouteBuilder $routes): void { /* * The default class to use for all routes * From 821b484cca6c8b852aa3271aacd66bf32584a80c Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Tue, 4 Nov 2025 16:17:02 +0100 Subject: [PATCH 09/11] chore fix: no migrator in tests bootstrap --- tests/bootstrap.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 2f38af9..b2fbaa4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -19,7 +19,6 @@ use Cake\Core\Configure; use Cake\Datasource\ConnectionManager; use Cake\TestSuite\ConnectionHelper; -use Migrations\TestSuite\Migrator; /** * Test runner bootstrap. @@ -72,4 +71,4 @@ // use Cake\TestSuite\Fixture\SchemaLoader; // (new SchemaLoader())->loadSqlFiles('./tests/schema.sql', 'test'); -(new Migrator())->run(); +// (new Migrator())->run(); From 031efea2fc3fa7e667eef3ff3c79d923d2fc4c14 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Mon, 24 Nov 2025 21:06:26 +0100 Subject: [PATCH 10/11] feat: be api 6, aws 5 --- composer.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 8ba273d..9bd1870 100644 --- a/composer.json +++ b/composer.json @@ -6,13 +6,12 @@ "license": "MIT", "require": { "php": ">=8.3", - "bedita/api": "6.x-dev", - "bedita/aws": "5.x-dev", - "bedita/core": "6.x-dev", + "bedita/api": "^6.0", + "bedita/aws": "^5.0", + "bedita/core": "^6.0", "cakephp/cakephp": "~5.2.9", "cakephp/plugin-installer": "^2.0" }, - "minimum-stability": "dev", "require-dev": { "bedita/dev-tools": "^3.2", "cakephp/bake": "^3.5.0", From b16eef23f6b382f38d55fc49f029c08e42d51625 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Mon, 24 Nov 2025 21:08:35 +0100 Subject: [PATCH 11/11] fix: minimum stability dev --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 9bd1870..c7f5540 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ "phpstan/phpstan-deprecation-rules": "^1.0", "phpunit/phpunit": "^11.5 || ^12.1" }, + "minimum-stability": "dev", "suggest": { "markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification." },