diff --git a/.github/workflows/manifest.yml b/.github/workflows/manifest.yml
index e03b53d42c..522a735073 100644
--- a/.github/workflows/manifest.yml
+++ b/.github/workflows/manifest.yml
@@ -15,9 +15,7 @@ jobs:
name: Update manifest
runs-on: ubuntu-latest
env:
- phpVersion: "8.4"
- extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
- key: winter-cms-cache-develop
+ GITHUB_TOKEN: ${{ secrets.COMPOSER_GITHUB_TOKEN }}
steps:
- name: Checkout changes
uses: actions/checkout@v4
@@ -25,8 +23,8 @@ jobs:
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
- php-version: ${{ env.phpVersion }}
- extensions: ${{ env.extensions }}
+ php-version: 8.4
+ extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
- name: Install Composer dependencies
run: composer install --no-interaction --no-progress --no-scripts
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 398fe5a813..921665ef45 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -21,59 +21,30 @@ jobs:
runs-on: ${{ matrix.operatingSystem }}
name: ${{ matrix.operatingSystem }} / JavaScript
env:
- nodeVersion: 16
- phpVersion: '8.2'
- extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
- key: winter-cms-cache-develop
+ GITHUB_TOKEN: ${{ secrets.COMPOSER_GITHUB_TOKEN }}
steps:
- name: Checkout changes
- uses: actions/checkout@v3
-
- - name: Setup extension cache
- id: extcache
- uses: shivammathur/cache-extensions@v1
- with:
- php-version: ${{ env.phpVersion }}
- extensions: ${{ env.extensions }}
- key: ${{ env.key }}
-
- - name: Cache extensions
- uses: actions/cache@v3
- with:
- path: ${{ steps.extcache.outputs.dir }}
- key: ${{ steps.extcache.outputs.key }}
- restore-keys: ${{ steps.extcache.outputs.key }}
+ uses: actions/checkout@v4
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
- php-version: ${{ env.phpVersion }}
- extensions: ${{ env.extensions }}
+ php-version: 8.2
+ extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
- name: Install Node
uses: actions/setup-node@v3
with:
- node-version: ${{ env.nodeVersion }}
+ node-version: 16
- name: Switch library dependency (develop)
if: github.ref == 'refs/heads/develop' || github.base_ref == 'develop'
- run: php ./.github/workflows/utilities/library-switcher "dev-develop as 1.2"
+ run: php ./.github/workflows/utilities/library-switcher "dev-wip/1.3 as 1.3"
- name: Switch library dependency (1.2)
if: github.head_ref == '1.2' || github.ref == 'refs/heads/1.2' || github.base_ref == '1.2'
run: php ./.github/workflows/utilities/library-switcher "1.2.x-dev as 1.2"
- - name: Setup dependency cache
- id: composercache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
- - name: Cache dependencies
- uses: actions/cache@v3
- with:
- path: ${{ steps.composercache.outputs.dir }}
- key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
- restore-keys: ${{ runner.os }}-composer-
-
- name: Install Composer dependencies
run: composer install --no-interaction --no-progress --no-scripts
@@ -95,41 +66,25 @@ jobs:
max-parallel: 8
matrix:
operatingSystem: [ubuntu-latest, windows-latest]
- phpVersion: ['8.1', '8.2', '8.3', '8.4', '8.5']
+ phpVersion: ['8.2', '8.3', '8.4', '8.5']
fail-fast: false
runs-on: ${{ matrix.operatingSystem }}
name: ${{ matrix.operatingSystem }} / PHP ${{ matrix.phpVersion }}
env:
- extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
- key: winter-cms-cache-develop
+ GITHUB_TOKEN: ${{ secrets.COMPOSER_GITHUB_TOKEN }}
steps:
- name: Checkout changes
- uses: actions/checkout@v3
-
- - name: Setup extension cache
- id: extcache
- uses: shivammathur/cache-extensions@v1
- with:
- php-version: ${{ matrix.phpVersion }}
- extensions: ${{ env.extensions }}
- key: ${{ env.key }}
-
- - name: Cache extensions
- uses: actions/cache@v3
- with:
- path: ${{ steps.extcache.outputs.dir }}
- key: ${{ steps.extcache.outputs.key }}
- restore-keys: ${{ steps.extcache.outputs.key }}
+ uses: actions/checkout@v4
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.phpVersion }}
- extensions: ${{ env.extensions }}
+ extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
- name: Switch library dependency (develop)
if: github.ref == 'refs/heads/develop' || github.base_ref == 'develop'
- run: php ./.github/workflows/utilities/library-switcher "dev-develop as 1.2"
+ run: php ./.github/workflows/utilities/library-switcher "dev-wip/1.3 as 1.3"
- name: Switch library dependency (1.0)
if: github.head_ref == '1.0' || github.ref == 'refs/heads/1.0' || github.base_ref == '1.0'
@@ -143,17 +98,6 @@ jobs:
if: github.head_ref == '1.2' || github.ref == 'refs/heads/1.2' || github.base_ref == '1.2'
run: php ./.github/workflows/utilities/library-switcher "1.2.x-dev as 1.2"
- - name: Setup dependency cache
- id: composercache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
- - name: Cache dependencies
- uses: actions/cache@v3
- with:
- path: ${{ steps.composercache.outputs.dir }}
- key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
- restore-keys: ${{ runner.os }}-composer-
-
- name: Install Composer dependencies
run: composer install --no-interaction --no-progress --no-scripts
@@ -165,10 +109,6 @@ jobs:
- name: Run post-update Composer scripts
run: php artisan package:discover
- - name: Setup problem matchers for PHPUnit
- if: matrix.phpVersion == '8.1'
- run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
-
- name: Run Linting and Tests
run: |
composer lint
diff --git a/.gitignore b/.gitignore
index bb60dbc6e3..a20f241e2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ composer.lock
selenium.php
/bootstrap/compiled.php
.phpunit.result.cache
+.phpunit.cache
# Hosting ignores
php_errors.log
@@ -26,6 +27,7 @@ nbproject
.vscode
!.devcontainer/.vscode
_ide_helper.php
+*.code-workspace
.zed
# Other ignores
diff --git a/composer.json b/composer.json
index 7948a44910..49915a8696 100644
--- a/composer.json
+++ b/composer.json
@@ -29,22 +29,28 @@
"source": "https://github.com/wintercms/winter"
},
"require": {
- "php": ">=8.1",
- "winter/storm": "dev-develop as 1.2",
- "winter/wn-system-module": "dev-develop",
- "winter/wn-backend-module": "dev-develop",
- "winter/wn-cms-module": "dev-develop",
- "laravel/framework": "^9.1",
+ "php": "^8.2",
+ "winter/storm": "dev-wip/1.3 as 1.3",
+ "winter/wn-system-module": "dev-wip/1.3",
+ "winter/wn-backend-module": "dev-wip/1.3",
+ "winter/wn-cms-module": "dev-wip/1.3",
+ "laravel/framework": "^12.0",
"wikimedia/composer-merge-plugin": "~2.1.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.5.8",
+ "phpunit/phpunit": "^11.0",
"mockery/mockery": "^1.4.4",
"fakerphp/faker": "^1.9.2",
"squizlabs/php_codesniffer": "^3.2",
"php-parallel-lint/php-parallel-lint": "^1.0",
- "dms/phpunit-arraysubset-asserts": "^0.1.0|^0.2.1"
+ "dms/phpunit-arraysubset-asserts": "dev-add-phpunit-11-support"
},
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/pieterocp/phpunit-arraysubset-asserts"
+ }
+ ],
"scripts": {
"post-create-project-cmd": [
"@php artisan winter:install",
@@ -65,7 +71,6 @@
"phpcs --colors -nq --report=\"full\" --extensions=\"php\""
]
},
- "minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"merge-plugin": {
diff --git a/config/app.php b/config/app.php
index e4a78cb57e..e1ec05c6eb 100644
--- a/config/app.php
+++ b/config/app.php
@@ -2,6 +2,32 @@
return [
+ /*
+ |--------------------------------------------------------------------------
+ | Application Name
+ |--------------------------------------------------------------------------
+ |
+ | This value is the name of your application. This value is used when the
+ | framework needs to place the application's name in a notification or
+ | any other location as required by the application or its packages.
+ |
+ */
+
+ 'name' => env('APP_NAME', 'Winter CMS'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Environment
+ |--------------------------------------------------------------------------
+ |
+ | This value determines the "environment" your application is currently
+ | running in. This may determine how you prefer to configure various
+ | services the application utilizes. Set this in your ".env" file.
+ |
+ */
+
+ 'env' => env('APP_ENV', 'production'),
+
/*
|--------------------------------------------------------------------------
| Application Debug Mode
@@ -20,20 +46,7 @@
|
*/
- 'debug' => env('APP_DEBUG', true),
-
- /*
- |--------------------------------------------------------------------------
- | Application Name
- |--------------------------------------------------------------------------
- |
- | This value is the name of your application. This value is used when the
- | framework needs to place the application's name in a notification or
- | any other location as required by the application or its packages.
- |
- */
-
- 'name' => env('APP_NAME', 'Winter CMS'),
+ 'debug' => (bool) env('APP_DEBUG', true),
/*
|--------------------------------------------------------------------------
@@ -42,7 +55,7 @@
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
- | your application so that it is used when running Artisan tasks.
+ | the application so that it's available within Artisan commands.
|
*/
@@ -183,7 +196,6 @@
| will be used by the PHP date and date-time functions. We have gone
| ahead and set this to a sensible default for you out of the box.
|
- |
| -------- STOP! --------
| Before you change this value, consider carefully if that is actually
| what you want to do. It is HIGHLY recommended that this is always set
@@ -225,7 +237,7 @@
|
*/
- 'locale' => 'en',
+ 'locale' => env('APP_LOCALE', 'en'),
/*
|--------------------------------------------------------------------------
@@ -238,7 +250,7 @@
|
*/
- 'fallback_locale' => 'en',
+ 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
/*
|--------------------------------------------------------------------------
@@ -251,7 +263,7 @@
|
*/
- 'faker_locale' => 'en_US',
+ 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
/*
|--------------------------------------------------------------------------
@@ -264,9 +276,16 @@
|
*/
- 'key' => env('APP_KEY'),
'cipher' => 'AES-256-CBC',
+ 'key' => env('APP_KEY'),
+
+ 'previous_keys' => [
+ ...array_filter(
+ explode(',', (string) env('APP_PREVIOUS_KEYS', ''))
+ ),
+ ],
+
/*
|--------------------------------------------------------------------------
| Autoloaded Service Providers
diff --git a/config/hashing.php b/config/hashing.php
index ad56664fb1..7bf45fba5c 100644
--- a/config/hashing.php
+++ b/config/hashing.php
@@ -48,4 +48,17 @@
'threads' => 1,
'time' => 4,
],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Password Rehashing
+ |--------------------------------------------------------------------------
+ |
+ | Laravel 11 will automatically rehash your user's passwords during
+ | authentication if your hashing algorithm's "work factor" has been updated
+ | since the password was last hashed.
+ |
+ */
+
+ 'rehash_on_login' => false,
];
diff --git a/modules/backend/composer.json b/modules/backend/composer.json
index bb1830994c..bb0d6050f7 100644
--- a/modules/backend/composer.json
+++ b/modules/backend/composer.json
@@ -23,9 +23,9 @@
}
],
"require": {
- "php": ">=8.1",
+ "php": "^8.2",
"composer/installers": "~1.11.0",
- "laravel/framework": "^9.1"
+ "laravel/framework": "^12.0"
},
"replace": {
"october/backend": "1.1.*"
diff --git a/modules/backend/controllers/Index.php b/modules/backend/controllers/Index.php
index 6856a9b729..008da92dfa 100644
--- a/modules/backend/controllers/Index.php
+++ b/modules/backend/controllers/Index.php
@@ -6,6 +6,8 @@
use Backend\Classes\Controller;
use Backend\Widgets\ReportContainer;
+use Winter\Storm\Support\Arr;
+
/**
* Dashboard controller
*
@@ -72,7 +74,7 @@ protected function initReportContainer()
protected function checkPermissionRedirect()
{
if (!$this->user->hasAccess('backend.access_dashboard')) {
- if ($first = array_first(BackendMenu::listMainMenuItems())) {
+ if ($first = Arr::first(BackendMenu::listMainMenuItems())) {
return Redirect::intended($first->url);
}
return Backend::redirect('backend/myaccount');
diff --git a/modules/backend/lang/fr/lang.php b/modules/backend/lang/fr/lang.php
index ef499132bf..69a3196ef7 100644
--- a/modules/backend/lang/fr/lang.php
+++ b/modules/backend/lang/fr/lang.php
@@ -10,7 +10,8 @@
'options_method_invalid_model' => "L\'attribut ':field' ne correspond à aucun modèle valide. Essayez de spécifier explicitement la méthode d\'options pour la classe du modèle ':model'.",
'options_method_not_exists' => 'La classe du modèle :model doit définir une méthode :method() renvoyant des options pour le champ ":field" du formulaire.',
'options_static_method_invalid_value' => "La méthode statique ':method()' de :class ne renvoie pas un tableau d'options valide.",
- 'colors_method_not_exists' => "La classe du modèle :model doit définir une méthode :method() renvoyant le code html en hexadécimal de la couleur du champ ':field' du formulaire."
+ 'colors_method_not_exists' => "La classe du modèle :model doit définir une méthode :method() renvoyant le code html en hexadécimal de la couleur du champ ':field' du formulaire.",
+ 'colors_invalid_input' => 'La valeur de couleur fournie est invalide, veuillez réessayer.',
],
'widget' => [
'not_registered' => 'Aucun widget au nom de classe ":name" n\'a été enregistré',
@@ -153,17 +154,31 @@
'superuser_comment' => 'Donner à ce compte un niveau d\'accès illimité à toutes les sections du système. Les super-utilisateurs peuvent ajouter et gérer les autres utilisateurs. ',
'send_invite' => 'Envoyer une invitation par e-mail',
'send_invite_comment' => 'Envoyer une invitation aux utilisateurs par e-mail contenant l\'identifiant et le mot de passe.',
+ 'auto_generate_password' => 'Générer automatiquement le mot de passe',
+ 'auto_generate_password_comment' => 'Créer automatiquement un mot de passe sécurisé aléatoire. Décochez pour définir un mot de passe manuellement.',
'delete_confirm' => 'Supprimer cet administrateur ?',
'return' => 'Retour à la liste des administrateurs',
'allow' => 'Autoriser',
'inherit' => 'Hériter',
'deny' => 'Interdire',
+ 'permissions_toggle_section_allow' => 'Autoriser toutes les permissions dans cette section',
+ 'permissions_toggle_section_inherit' => 'Hériter de toutes les permissions dans cette section',
+ 'permissions_toggle_section_deny' => 'Interdire toutes les permissions dans cette section',
'activated' => 'Activé',
'last_login' => 'Dernière connexion',
'created_at' => 'Créé le',
'updated_at' => 'Mis à jour le',
'deleted_at' => 'Supprimé le',
'show_deleted' => 'Afficher les supprimés',
+ 'self_escalation_denied' => 'Vous ne pouvez pas modifier votre propre rôle, vos permissions ou votre statut de super-utilisateur.',
+ 'cannot_manage_user' => 'Vous n\'avez pas la permission de gérer cet administrateur.',
+ 'throttle_tab' => 'Échecs de connexion',
+ 'throttle_tab_label' => 'Historique des échecs de connexion',
+ 'throttle_comment' => 'Voir les tentatives de connexion échouées pour cet utilisateur. Ces enregistrements sont générés automatiquement lorsque les tentatives de connexion échouent. Les utilisateurs sont suspendus après avoir dépassé la limite de tentatives.',
+ 'throttle_ip_address' => 'Adresse IP',
+ 'throttle_attempts' => 'Tentatives',
+ 'throttle_last_attempt' => 'Dernière tentative',
+ 'throttle_suspended_at' => 'Suspendu le',
'group' => [
'name' => 'Groupe',
'name_comment' => 'Le nom est affiché dans la liste des groupes dans le formulaire de création/modification des administrateurs.',
@@ -221,6 +236,7 @@
'loading' => 'Chargement…',
'setup_title' => 'Configuration de la liste',
'setup_help' => 'Cocher les colonnes qui doivent être affichées dans la liste. Il est possible de modifier l\'ordre des colonnes en les glissant vers le haut ou le bas.',
+ 'sort_drag_title' => 'Glisser pour réorganiser',
'records_per_page' => 'Nombre d\'enregistrements par page',
'records_per_page_help' => 'Choisir le nombre d\'enregistrements à afficher. Note : un nombre d\'enregistrements trop élevé sur une seule page peut réduire les performances.',
'check' => 'Sélectionner',
@@ -251,6 +267,7 @@
'form' => [
'create_title' => 'Créer un(e) :name',
'update_title' => 'Mise à jour d\'un(e) :name',
+ 'preview' => 'Aperçu',
'preview_title' => 'Aperçu d\'un(e) :name',
'create_success' => ':name créé(e) avec succès',
'update_success' => ':name modifié(e) avec succès',
@@ -308,7 +325,10 @@
'delete_row' => 'Supprimer une ligne',
'concurrency_file_changed_title' => 'Le fichier a été modifié',
'concurrency_file_changed_description' => 'Un autre utilisateur a modifié ce fichier sur le disque. Vous pouvez ou recharger le fichier depuis le disque, mais vous perdrez vos modifications, ou écraser le fichier sur le disque.',
- 'return_to_list' => 'Retourner à la liste'
+ 'return_to_list' => 'Retourner à la liste',
+ 'record_navigation' => 'Navigation dans les enregistrements',
+ 'previous_record' => 'Enregistrement précédent',
+ 'next_record' => 'Enregistrement suivant',
],
'recordfinder' => [
'default_prompt' => 'Cliquer sur %s pour chercher un enregistrement',
@@ -321,6 +341,7 @@
'select_page' => 'Sélectionnez une page...'
],
'relation' => [
+ 'missing_behavior' => 'Le champ ":field" nécessite que le contrôleur ":controller" implémente le comportement "RelationController".',
'missing_config' => 'La behavior relation n\'a pas de configuration pour ":config".',
'missing_definition' => 'La behavior relation n\'a pas de définition pour le champ ":field".',
'missing_model' => 'La behavior relation utilisée dans la classe :class n\'a pas de modèle défini.',
@@ -329,6 +350,7 @@
'relationwidget_unsupported_type' => 'Le type de relation ":type" n\'est pas supporté par le widget Relation.',
'help' => 'Cliquer sur un élément pour l\'ajouter',
'related_data' => 'Donnée :name liée',
+ 'refresh' => 'Actualiser',
'add' => 'Ajouter',
'add_selected' => 'Ajouter la sélection',
'add_a_new' => 'Ajouter un(e) :name',
@@ -356,6 +378,7 @@
],
'reorder' => [
'default_title' => 'Réorganiser les enregistrements',
+ 'reorder_title' => 'Réorganiser :name',
'no_records' => 'Il n\'y a aucun enregistrement à trier.',
],
'model' => [
@@ -370,12 +393,16 @@
'warnings' => [
'tips' => 'Astuces de configuration du système',
'tips_description' => 'Il y a des éléments à prendre en compte pour configurer le système correctement.',
+ 'how_to_fix' => 'Comment corriger',
'permissions' => 'PHP ne peut pas écrire dans le répertoire :name et ses sous-dossiers. Veuillez modifier les permissions en écriture du serveur web pour ce répertoire.',
'extension' => 'L\'extension PHP :name n\'est pas installée. Veuillez installer la librairie et activer l\'extension.',
'plugin_missing' => 'Le plugin :name est une dépendance mais n\'est pas installé. Veuillez installer le plugin.',
'debug' => "Le mode debug est activé. Cela n'est pas recommandé pour les installations en production.",
'decompileBackendAssets' => "Les assets dans le Backend sont actuellement décompilés. Cela n'est pas recommandé pour les installations en production.",
'default_backend_user' => "Un utilisateur avec les détails de connexion par défaut (admin / admin@domain.tld) a été trouvé. Changez son nom d'utilisateur et / ou son adresse e-mail pour aider à protéger le système.",
+ 'auth_throttle_disabled' => 'Le throttling de l\'authentification du backend est désactivé. Cela n\'est pas recommandé pour les installations en production car cela peut permettre à des utilisateurs malveillants de forcer les mots de passe des utilisateurs.',
+ 'csrf' => 'La protection CSRF est désactivée. Cela n\'est pas recommandé pour les installations en production car cela compromet la sécurité des installations et peut permettre des attaques de type cross-site scripting.',
+ 'restrict_base_dir' => 'La restriction du répertoire de base est désactivée. Cela n\'est pas recommandé pour les installations en production car cela peut permettre aux thèmes et aux fichiers de configuration d\'accéder à des fichiers en dehors de votre installation Winter CMS.',
],
'editor' => [
'menu_label' => 'Préférences de l\'éditeur de code',
@@ -384,15 +411,16 @@
'font_size' => 'Taille de la police',
'tab_size' => 'Taille de la tabulation',
'use_hard_tabs' => 'Indentation par tabulation',
- 'code_folding' => 'Replier le code',
- 'code_folding_begin' => 'Marquer le début',
- 'code_folding_begin_end' => 'Marquer le début et la fin',
+ 'enable_folding' => 'Activer le repli du code',
+ 'bracket_colors' => 'Activer la coloration des couples de parenthèses',
+ 'show_colors' => 'Activer le sélecteur de couleurs en ligne',
'autocompletion' => 'Auto-complétion',
'word_wrap' => 'Retour à la ligne',
'highlight_active_line' => 'Sélectionner la ligne active',
'auto_closing' => 'Fermer automatiquement les tags',
'show_invisibles' => 'Afficher les caractères invisibles',
'show_gutter' => 'Afficher les numéros de ligne',
+ 'show_minimap' => 'Afficher la minimap',
'basic_autocompletion'=> 'Auto-complétion basique (Ctrl + Espace)',
'live_autocompletion'=> 'Auto-complétion en temps réel',
'enable_snippets'=> 'Activer les extraits de code (Tab)',
@@ -438,7 +466,8 @@
'full' => 'Complète',
],
'paragraph_formats' => 'Styles des paragraphes',
- 'paragraph_formats_comment' => 'Les options qui apparaîtrons dans la liste déroulante des styles de paragraphe.',
+ 'paragraph_formats_comment' => 'Les options qui apparaîtront dans la liste déroulante des styles de paragraphe.',
+ 'toggle_fullscreen' => 'Basculer en plein écran',
],
'tooltips' => [
'preview_website' => 'Aperçu du site'
@@ -512,6 +541,8 @@
'number_all' => 'tous les nombres',
],
'import_export' => [
+ 'export' => 'Exporter',
+ 'import' => 'Importer',
'upload_csv_file' => '1. Envoyer un fichier CSV',
'import_file' => 'Importer un fichier',
'row' => 'Ligne :row',
@@ -588,6 +619,7 @@
'permissions' => [
'manage_media' => 'Déposer et gérer les contenus media - images, vidéos, sons, documents',
'allow_unsafe_markdown' => 'Utilisation de Markdown non sécurisé (peut inclure du Javascript)',
+ 'allow_unsafe_markdown_comment' => 'Autoriser le Markdown non sécurisé permettra d\'utiliser des balises HTML, y compris JavaScript, dans le contenu Markdown. Cela peut représenter un risque de sécurité si accordé à un utilisateur non fiable.',
],
'mediafinder' => [
'label' => 'Galerie média',
diff --git a/modules/backend/phpunit.xml b/modules/backend/phpunit.xml
index 7c0631aa89..2023f43f78 100644
--- a/modules/backend/phpunit.xml
+++ b/modules/backend/phpunit.xml
@@ -1,17 +1,16 @@
-
-
-
- ./tests
-
-
+
+
+ ./tests
+
+
diff --git a/modules/backend/tests/classes/AuthManagerTest.php b/modules/backend/tests/classes/AuthManagerTest.php
index 7b4ed3fb76..2cb7f578d9 100644
--- a/modules/backend/tests/classes/AuthManagerTest.php
+++ b/modules/backend/tests/classes/AuthManagerTest.php
@@ -2,9 +2,9 @@
namespace Backend\Tests\Classes;
+use Backend\Classes\AuthManager;
use System\Tests\Bootstrap\TestCase;
use Winter\Storm\Exception\SystemException;
-use Backend\Classes\AuthManager;
class AuthManagerTest extends TestCase
{
@@ -44,6 +44,7 @@ protected function listNewPermissions()
public function tearDown(): void
{
AuthManager::forgetInstance();
+ parent::tearDown();
}
public function testListPermissions()
diff --git a/modules/backend/tests/classes/ControllerPostbackTest.php b/modules/backend/tests/classes/ControllerPostbackTest.php
index 6124f27d03..af2ac8f858 100644
--- a/modules/backend/tests/classes/ControllerPostbackTest.php
+++ b/modules/backend/tests/classes/ControllerPostbackTest.php
@@ -19,7 +19,7 @@ protected function configAjaxRequestMock(string $handler)
$requestMock = $this
->getMockBuilder('Illuminate\Http\Request')
->disableOriginalConstructor()
- ->setMethods(['ajax', 'method', 'header', 'secure', 'path', 'getScheme', 'getHost', 'getPort', 'getBaseUrl'])
+ ->onlyMethods(['ajax', 'method', 'header', 'secure', 'path', 'getScheme', 'getHost', 'getPort', 'getBaseUrl'])
->getMock();
$map = [
@@ -50,7 +50,7 @@ protected function configPostbackRequestMock(string $handler)
$requestMock = $this
->getMockBuilder('Illuminate\Http\Request')
->disableOriginalConstructor()
- ->setMethods(['ajax', 'method', 'header', 'post', 'input', 'secure', 'path', 'getScheme', 'getHost', 'getPort', 'getBaseUrl'])
+ ->onlyMethods(['ajax', 'method', 'header', 'post', 'input', 'secure', 'path', 'getScheme', 'getHost', 'getPort', 'getBaseUrl'])
->getMock();
$requestMock->expects($this->any())->method('ajax')->willReturn(false);
diff --git a/modules/backend/tests/traits/WidgetMakerTest.php b/modules/backend/tests/traits/WidgetMakerTest.php
index 4d1caf2df9..be125946c3 100644
--- a/modules/backend/tests/traits/WidgetMakerTest.php
+++ b/modules/backend/tests/traits/WidgetMakerTest.php
@@ -9,6 +9,8 @@ class ExampleTraitClass
{
use \Backend\Traits\WidgetMaker;
+ protected Controller $controller;
+
public function __construct()
{
$this->controller = new Controller;
@@ -35,8 +37,9 @@ public function setUp(): void
{
parent::setUp();
- $traitName = 'Backend\Traits\WidgetMaker';
- $this->traitObject = $this->getObjectForTrait($traitName);
+ $this->traitObject = new class {
+ use \Backend\Traits\WidgetMaker;
+ };
}
public function testTraitObject()
diff --git a/modules/cms/classes/ComponentManager.php b/modules/cms/classes/ComponentManager.php
index 5388c53ac4..01858ce7c1 100644
--- a/modules/cms/classes/ComponentManager.php
+++ b/modules/cms/classes/ComponentManager.php
@@ -1,9 +1,11 @@
-=8.1",
+ "php": "^8.2",
"composer/installers": "~1.11.0",
- "laravel/framework": "^9.1"
+ "laravel/framework": "^12.0"
},
"replace": {
"october/cms": "1.1.*"
diff --git a/modules/cms/phpunit.xml b/modules/cms/phpunit.xml
index 4cb34b9f38..bb4330c7dc 100644
--- a/modules/cms/phpunit.xml
+++ b/modules/cms/phpunit.xml
@@ -1,17 +1,16 @@
-
-
-
- ./tests
-
-
+
+
+ ./tests
+
+
diff --git a/modules/cms/tests/classes/CmsObjectTest.php b/modules/cms/tests/classes/CmsObjectTest.php
index 61bacb711a..02b83c1170 100644
--- a/modules/cms/tests/classes/CmsObjectTest.php
+++ b/modules/cms/tests/classes/CmsObjectTest.php
@@ -5,6 +5,7 @@
use System\Tests\Bootstrap\TestCase;
use Cms\Classes\CmsObject;
use Cms\Classes\Theme;
+use PHPUnit\Framework\Attributes\Depends;
class TestCmsObject extends CmsObject
{
@@ -236,9 +237,7 @@ public function testSave()
$this->assertEquals($testContents, file_get_contents($destFilePath));
}
- /**
- * @depends testSave
- */
+ #[Depends('testSave')]
public function testRename()
{
$theme = Theme::load('apitest');
@@ -265,9 +264,7 @@ public function testRename()
$this->assertEquals($testContents, file_get_contents($destFilePath));
}
- /**
- * @depends testRename
- */
+ #[Depends('testRename')]
public function testSaveSameName()
{
$theme = Theme::load('apitest');
@@ -288,9 +285,7 @@ public function testSaveSameName()
$this->assertEquals($testContents, file_get_contents($filePath));
}
- /**
- * @depends testRename
- */
+ #[Depends('testRename')]
public function testRenameToExistingFile()
{
$this->expectException(\Winter\Storm\Exception\ApplicationException::class);
diff --git a/modules/cms/tests/classes/ControllerPostbackTest.php b/modules/cms/tests/classes/ControllerPostbackTest.php
index 8f18741908..4dab2e53e1 100644
--- a/modules/cms/tests/classes/ControllerPostbackTest.php
+++ b/modules/cms/tests/classes/ControllerPostbackTest.php
@@ -29,7 +29,7 @@ protected function configAjaxRequestMock(string $handler, $partials = false)
$requestMock = $this
->getMockBuilder('Illuminate\Http\Request')
->disableOriginalConstructor()
- ->setMethods(['ajax', 'method', 'header'])
+ ->onlyMethods(['ajax', 'method', 'header'])
->getMock();
$map = [
@@ -60,7 +60,7 @@ protected function configPostbackRequestMock(string $handler)
$requestMock = $this
->getMockBuilder('Illuminate\Http\Request')
->disableOriginalConstructor()
- ->setMethods(['ajax', 'method', 'header', 'post', 'input'])
+ ->onlyMethods(['ajax', 'method', 'header', 'post', 'input'])
->getMock();
$requestMock->expects($this->any())
diff --git a/modules/cms/tests/classes/ControllerTest.php b/modules/cms/tests/classes/ControllerTest.php
index 16d72cb9ce..6a098d6f52 100644
--- a/modules/cms/tests/classes/ControllerTest.php
+++ b/modules/cms/tests/classes/ControllerTest.php
@@ -2,12 +2,13 @@
namespace Cms\Tests\Classes;
-use Cms;
-use Request;
-use System\Tests\Bootstrap\TestCase;
-use Cms\Classes\Theme;
use Cms\Classes\Controller;
+use Cms\Classes\Theme;
+use Cms\Facades\Cms;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Request;
use System\Helpers\View;
+use System\Tests\Bootstrap\TestCase;
use Winter\Storm\Halcyon\Model;
use Winter\Storm\Support\Facades\Config;
@@ -79,7 +80,7 @@ public function testThemeCombineAssets(): void
$cacheKey = 'combiner.' . str_before(basename($url), '-');
// Load the cached config
- $combinerConfig = \Cache::get($cacheKey);
+ $combinerConfig = Cache::get($cacheKey);
$this->assertIsString($combinerConfig);
// Decode the config
@@ -299,30 +300,32 @@ public function testChildThemePageLifeCycle()
protected function configAjaxRequestMock($handler, $partials = false)
{
- $requestMock = $this
- ->getMockBuilder('Illuminate\Http\Request')
- ->disableOriginalConstructor()
- ->setMethods(['ajax', 'method', 'header'])
- ->getMock();
-
- $map = [
- ['X_WINTER_REQUEST_HANDLER', null, $handler],
- ['X_WINTER_REQUEST_PARTIALS', null, $partials],
- ];
-
- $requestMock->expects($this->any())
- ->method('ajax')
- ->will($this->returnValue(true));
-
- $requestMock->expects($this->any())
- ->method('method')
- ->will($this->returnValue('POST'));
-
- $requestMock->expects($this->any())
- ->method('header')
- ->will($this->returnValueMap($map));
-
- return $requestMock;
+ return new class($handler, $partials) extends \Illuminate\Http\Request {
+ protected $handler;
+ protected $partials;
+ public function __construct($handler, $partials)
+ {
+ $this->handler = $handler;
+ $this->partials = $partials;
+ parent::__construct();
+ }
+ public function ajax()
+ {
+ return true;
+ }
+ public function method()
+ {
+ return 'POST';
+ }
+ public function header($key = null, $default = null)
+ {
+ return match ($key) {
+ 'X_WINTER_REQUEST_HANDLER' => $this->handler,
+ 'X_WINTER_REQUEST_PARTIALS' => $this->partials,
+ default => $default,
+ };
+ }
+ };
}
public function testAjaxHandlerNotFound()
diff --git a/modules/cms/tests/classes/ThemeTest.php b/modules/cms/tests/classes/ThemeTest.php
index 3e904e8811..9c07ebcd25 100644
--- a/modules/cms/tests/classes/ThemeTest.php
+++ b/modules/cms/tests/classes/ThemeTest.php
@@ -125,7 +125,7 @@ public function testChildThemeAssetUrl()
);
}
- public function dirNameValidityProvider(): array
+ public static function dirNameValidityProvider(): array
{
return [
// Valid names
diff --git a/modules/system/classes/UpdateManager.php b/modules/system/classes/UpdateManager.php
index e56643d98c..b02f2a9699 100644
--- a/modules/system/classes/UpdateManager.php
+++ b/modules/system/classes/UpdateManager.php
@@ -135,6 +135,13 @@ public function bindContainerObjects()
public function update()
{
try {
+ $connection = Schema::getConnection();
+ if ($connection->getDriverName() === 'sqlite') {
+ if (version_compare($connection->getServerVersion(), '3.35', '<')) {
+ throw new Exception("SQLite version minimum requirement not met (>= 3.35)");
+ }
+ };
+
$firstUp = !Schema::hasTable($this->getMigrationTableName());
if ($firstUp) {
$this->repository->createRepository();
diff --git a/modules/system/composer.json b/modules/system/composer.json
index 6b5c4929d9..3d58afe4e6 100644
--- a/modules/system/composer.json
+++ b/modules/system/composer.json
@@ -23,9 +23,9 @@
}
],
"require": {
- "php": ">=8.1",
+ "php": "^8.2",
"composer/installers": "~1.11.0",
- "laravel/framework": "^9.1",
+ "laravel/framework": "^12.0",
"composer/semver": "^3.2"
},
"replace": {
diff --git a/modules/system/console/WinterTest.php b/modules/system/console/WinterTest.php
index 7d24d105c7..5a96ead94c 100644
--- a/modules/system/console/WinterTest.php
+++ b/modules/system/console/WinterTest.php
@@ -1,6 +1,7 @@
-option($type)) {
foreach ($this->option($type) as $target) {
+ if (empty($target)) {
+ continue;
+ }
$target = strtolower($target);
if (!isset($configs[$type . 's'][$target])) {
throw new ApplicationException(sprintf(
@@ -123,8 +128,15 @@ public function handle()
return $exitCode;
}
- // default to running all defined configs found
- foreach (['modules', 'plugins'] as $type) {
+ // default to running all defined configs found, run all tests if no options provided
+ $types = [
+ 'modules' => count($this->option('module')) + !$this->option('plugin'),
+ 'plugins' => count($this->option('plugin')) + !$this->option('module'),
+ ];
+ foreach ($types as $type => $count) {
+ if (!$count) {
+ continue;
+ }
foreach ($configs[$type] as $name => $config) {
$this->info(
$type === 'plugins'
diff --git a/modules/system/console/asset/mix/MixCompile.php b/modules/system/console/asset/mix/MixCompile.php
index 14559cb39d..c86d0faf73 100644
--- a/modules/system/console/asset/mix/MixCompile.php
+++ b/modules/system/console/asset/mix/MixCompile.php
@@ -19,7 +19,6 @@ class MixCompile extends AssetCompile
protected $signature = 'mix:compile
{webpackArgs?* : Arguments to pass through to the Webpack CLI}
{--f|production : Runs compilation in "production" mode}
- {--s|silent : Enables silent mode, no output will be shown.}
{--d|disable-tty : Disable tty mode}
{--e|stop-on-error : Exit once an error is encountered}
{--m|manifest= : Defines package.json to use for compile}
diff --git a/modules/system/console/asset/mix/MixCreate.php b/modules/system/console/asset/mix/MixCreate.php
index 85e1259aee..437b98562f 100644
--- a/modules/system/console/asset/mix/MixCreate.php
+++ b/modules/system/console/asset/mix/MixCreate.php
@@ -15,7 +15,6 @@ class MixCreate extends AssetCreate
protected $signature = 'mix:create
{packageName : The package name to add configuration for}
{--no-stubs : Disable stub file generation}
- {--s|silent : Enables silent mode, no output will be shown.}
{--f|force : Force file overwrites}';
/**
diff --git a/modules/system/console/asset/mix/MixInstall.php b/modules/system/console/asset/mix/MixInstall.php
index b08d8c4b96..272ad6852a 100644
--- a/modules/system/console/asset/mix/MixInstall.php
+++ b/modules/system/console/asset/mix/MixInstall.php
@@ -17,7 +17,6 @@ class MixInstall extends AssetInstall
{--no-install : Tells Winter not to run npm install after config update.}
{--npm= : Defines a custom path to the "npm" binary.}
{--d|disable-tty : Disable tty mode.}
- {--s|silent : Enables silent mode, no output will be shown.}
{--p|package-json= : Defines a custom path to "package.json" file. Must be above the workspace path.}';
/**
diff --git a/modules/system/console/asset/mix/MixWatch.php b/modules/system/console/asset/mix/MixWatch.php
index 53aee49133..b30b84e7b5 100644
--- a/modules/system/console/asset/mix/MixWatch.php
+++ b/modules/system/console/asset/mix/MixWatch.php
@@ -17,7 +17,6 @@ class MixWatch extends MixCompile
{webpackArgs?* : Arguments to pass through to the Webpack CLI}
{--f|production : Runs compilation in "production" mode}
{--m|manifest= : Defines package.json to use for compile}
- {--s|silent : Enables silent mode, no output will be shown.}
{--d|disable-tty : Disable tty mode}
{--no-progress : Do not show mix progress}';
diff --git a/modules/system/console/asset/npm/NpmInstall.php b/modules/system/console/asset/npm/NpmInstall.php
index da697e42ae..c2e89d917a 100644
--- a/modules/system/console/asset/npm/NpmInstall.php
+++ b/modules/system/console/asset/npm/NpmInstall.php
@@ -25,7 +25,6 @@ class NpmInstall extends NpmCommand
{npmArgs?* : Arguments to pass through to the "npm" binary}
{--npm= : Defines a custom path to the "npm" binary}
{--d|dev : Install packages in devDependencies}
- {--s|silent : Silent mode.}
{--disable-tty : Disable tty mode}';
/**
diff --git a/modules/system/console/asset/npm/NpmRun.php b/modules/system/console/asset/npm/NpmRun.php
index cd45313acd..5bfea734d8 100644
--- a/modules/system/console/asset/npm/NpmRun.php
+++ b/modules/system/console/asset/npm/NpmRun.php
@@ -19,7 +19,6 @@ class NpmRun extends NpmCommand
{script : The name of the script to run, as defined in the package.json "scripts" config.}
{additionalArgs?* : Arguments to pass through to the script being run.}
{--f|production : Runs the script in "production" mode.}
- {--s|silent : Silent mode.}
{--disable-tty : Disable tty mode}';
/**
diff --git a/modules/system/console/asset/npm/NpmUpdate.php b/modules/system/console/asset/npm/NpmUpdate.php
index f578c5c4c1..2668391f2b 100644
--- a/modules/system/console/asset/npm/NpmUpdate.php
+++ b/modules/system/console/asset/npm/NpmUpdate.php
@@ -25,7 +25,6 @@ class NpmUpdate extends NpmCommand
{npmArgs?* : Arguments to pass through to the "npm" binary.}
{--npm= : Defines a custom path to the "npm" binary.}
{--a|save : Tell npm to update package.json.}
- {--s|silent : Silent mode.}
{--disable-tty : Disable tty mode}';
/**
diff --git a/modules/system/console/asset/npm/NpmVersion.php b/modules/system/console/asset/npm/NpmVersion.php
index 78e4a4a0b7..0fda33770c 100644
--- a/modules/system/console/asset/npm/NpmVersion.php
+++ b/modules/system/console/asset/npm/NpmVersion.php
@@ -19,7 +19,6 @@ class NpmVersion extends NpmCommand
*/
protected $signature = 'npm:version
{--c|compatible : Report compatible version via exit code.}
- {--s|silent : Silent mode.}
{--disable-tty : Disable tty mode}';
/**
diff --git a/modules/system/console/asset/vite/ViteCompile.php b/modules/system/console/asset/vite/ViteCompile.php
index eb10fea008..5a40904182 100644
--- a/modules/system/console/asset/vite/ViteCompile.php
+++ b/modules/system/console/asset/vite/ViteCompile.php
@@ -18,7 +18,6 @@ class ViteCompile extends AssetCompile
protected $signature = 'vite:compile
{viteArgs?* : Arguments to pass through to the Vite CLI}
{--f|production : Runs compilation in "production" mode}
- {--s|silent : Enables silent mode, no output will be shown.}
{--d|disable-tty : Disable tty mode}
{--e|stop-on-error : Exit once an error is encountered}
{--m|manifest= : Defines package.json to use for compile}
diff --git a/modules/system/console/asset/vite/ViteCreate.php b/modules/system/console/asset/vite/ViteCreate.php
index 9067fb82ea..a26829a4a6 100644
--- a/modules/system/console/asset/vite/ViteCreate.php
+++ b/modules/system/console/asset/vite/ViteCreate.php
@@ -17,7 +17,6 @@ class ViteCreate extends AssetCreate
protected $signature = 'vite:create
{packageName : The package name to add configuration for}
{--no-stubs : Disable stub file generation}
- {--s|silent : Enables silent mode, no output will be shown.}
{--f|force : Force file overwrites}';
/**
diff --git a/modules/system/console/asset/vite/ViteInstall.php b/modules/system/console/asset/vite/ViteInstall.php
index 035e7328c8..f21c236715 100644
--- a/modules/system/console/asset/vite/ViteInstall.php
+++ b/modules/system/console/asset/vite/ViteInstall.php
@@ -19,7 +19,6 @@ class ViteInstall extends AssetInstall
{--no-install : Tells Winter not to run npm install after config update.}
{--npm= : Defines a custom path to the "npm" binary.}
{--d|disable-tty : Disable tty mode.}
- {--s|silent : Enables silent mode, no output will be shown.}
{--p|package-json= : Defines a custom path to "package.json" file. Must be above the workspace path.}';
/**
diff --git a/modules/system/console/asset/vite/ViteWatch.php b/modules/system/console/asset/vite/ViteWatch.php
index 2825724793..2175f8a94a 100644
--- a/modules/system/console/asset/vite/ViteWatch.php
+++ b/modules/system/console/asset/vite/ViteWatch.php
@@ -19,7 +19,6 @@ class ViteWatch extends ViteCompile
{viteArgs?* : Arguments to pass through to the Webpack CLI}
{--f|production : Runs compilation in "production" mode}
{--m|manifest= : Defines package.json to use for compile}
- {--s|silent : Enables silent mode, no output will be shown.}
{--d|disable-tty : Disable tty mode}
{--no-progress : Do not show mix progress}';
diff --git a/modules/system/console/scaffold/test/phpunit.stub b/modules/system/console/scaffold/test/phpunit.stub
index e7877ce389..e1ab1fedca 100644
--- a/modules/system/console/scaffold/test/phpunit.stub
+++ b/modules/system/console/scaffold/test/phpunit.stub
@@ -1,13 +1,7 @@
-
diff --git a/modules/system/phpunit.xml b/modules/system/phpunit.xml
index af5eee72a0..66ab407567 100644
--- a/modules/system/phpunit.xml
+++ b/modules/system/phpunit.xml
@@ -1,17 +1,16 @@
-
-
-
- ./tests
-
-
+
+
+ ./tests
+
+
diff --git a/modules/system/tests/ServiceProviderTest.php b/modules/system/tests/ServiceProviderTest.php
index f583e962c9..4ce143ef31 100644
--- a/modules/system/tests/ServiceProviderTest.php
+++ b/modules/system/tests/ServiceProviderTest.php
@@ -2,9 +2,9 @@
namespace System\Tests;
-use Db;
-use Log;
+use Illuminate\Support\Facades\Log;
use System\Tests\Bootstrap\PluginTestCase;
+use Winter\Storm\Support\Facades\DB;
class ServiceProviderTest extends PluginTestCase
{
@@ -21,7 +21,7 @@ public function testRegisterLogging()
'key' => 'Dummy value',
];
Log::info($message, $details);
- $latestLog = Db::table('system_event_logs')->latest()->first();
+ $latestLog = DB::table('system_event_logs')->latest()->first();
$this->assertEquals($message, $latestLog->message);
$this->assertEquals($details, json_decode($latestLog->details, true));
}
diff --git a/modules/system/tests/bootstrap/PluginTestCase.php b/modules/system/tests/bootstrap/PluginTestCase.php
index 5acaa26d5e..b78877be37 100644
--- a/modules/system/tests/bootstrap/PluginTestCase.php
+++ b/modules/system/tests/bootstrap/PluginTestCase.php
@@ -39,11 +39,7 @@ abstract class PluginTestCase extends TestCase
*/
public function createApplication()
{
- $app = require __DIR__ . '/../../../../bootstrap/app.php';
- $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
-
- $app['cache']->setDefaultDriver('array');
- $app->setLocale('en');
+ $app = parent::createApplication();
$app->singleton('backend.auth', function ($app) {
$app['auth.loaded'] = true;
@@ -60,9 +56,6 @@ public function createApplication()
$app['config']->set('database.default', 'testing');
}
- // Set random encryption key
- $app['config']->set('app.key', bin2hex(random_bytes(16)));
-
// Modify the plugin path away from the test context
$app->setPluginsPath(realpath(base_path() . Config::get('cms.pluginsPath')));
diff --git a/modules/system/tests/bootstrap/TestCase.php b/modules/system/tests/bootstrap/TestCase.php
index 3bdb052718..dd324fe061 100644
--- a/modules/system/tests/bootstrap/TestCase.php
+++ b/modules/system/tests/bootstrap/TestCase.php
@@ -2,8 +2,11 @@
namespace System\Tests\Bootstrap;
-use ReflectionClass;
+use Illuminate\Contracts\Console\Kernel;
+use Illuminate\Contracts\Events\Dispatcher;
+use Illuminate\Contracts\Foundation\Application;
use PHPUnit\Framework\Assert;
+use ReflectionClass;
class TestCase extends \Illuminate\Foundation\Testing\TestCase
{
@@ -24,6 +27,29 @@ public function createApplication()
// Set random encryption key
$app['config']->set('app.key', bin2hex(random_bytes(16)));
+ // Override the Kernel call method to prevent symfony shell verbosity breaking scripts.
+ // @see: https://github.com/symfony/symfony/pull/53632
+ // @see: https://github.com/symfony/symfony/pull/24425
+ $app->bind(Kernel::class, function (Application $app) {
+ return new class($app, $app->make(Dispatcher::class)) extends \Winter\Storm\Foundation\Console\Kernel
+ {
+ public function call($command, array $parameters = [], $outputBuffer = null)
+ {
+ $result = parent::call($command, $parameters, $outputBuffer);
+
+ $shellVerbosity = 0;
+
+ if (\function_exists('putenv')) {
+ @putenv('SHELL_VERBOSITY=' . $shellVerbosity);
+ }
+
+ $_ENV['SHELL_VERBOSITY'] = $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
+
+ return $result;
+ }
+ };
+ });
+
return $app;
}
@@ -59,36 +85,26 @@ public static function setProtectedProperty($object, $name, $value)
}
/**
- * Stub for `assertFileNotExists` to allow compatibility with both PHPUnit 8 and 9.
- *
- * @param string $filename
- * @param string $message
- * @return void
+ * Stub for `assertFileNotExists`
*/
public static function assertFileNotExists(string $filename, string $message = ''): void
{
- if (method_exists(Assert::class, 'assertFileDoesNotExist')) {
- Assert::assertFileDoesNotExist($filename, $message);
- return;
- }
-
- Assert::assertFileNotExists($filename, $message);
+ Assert::assertFileDoesNotExist($filename, $message);
}
/**
- * Stub for `assertRegExp` to allow compatibility with both PHPUnit 8 and 9.
- *
- * @param string $filename
- * @param string $message
- * @return void
+ * Stub for `assertRegExp`
*/
public static function assertRegExp(string $pattern, string $string, string $message = ''): void
{
- if (method_exists(Assert::class, 'assertMatchesRegularExpression')) {
- Assert::assertMatchesRegularExpression($pattern, $string, $message);
- return;
- }
+ Assert::assertMatchesRegularExpression($pattern, $string, $message);
+ }
- Assert::assertRegExp($pattern, $string, $message);
+ /**
+ * Stub for `assertObjectHasAttribute`
+ */
+ public static function assertObjectHasAttribute(string $propertyName, $object, string $message = ''): void
+ {
+ Assert::assertObjectHasProperty($propertyName, $object, $message);
}
}
diff --git a/modules/system/tests/classes/MediaLibraryTest.php b/modules/system/tests/classes/MediaLibraryTest.php
index ac9e67f6ae..751f989f46 100644
--- a/modules/system/tests/classes/MediaLibraryTest.php
+++ b/modules/system/tests/classes/MediaLibraryTest.php
@@ -4,6 +4,7 @@
use System\Tests\Bootstrap\TestCase;
use Illuminate\Filesystem\FilesystemAdapter;
+use PHPUnit\Framework\Attributes\DataProvider;
use System\Classes\MediaLibrary;
class MediaLibraryTest extends TestCase
@@ -20,7 +21,7 @@ public function tearDown(): void
parent::tearDown();
}
- public function invalidPathsProvider()
+ public static function invalidPathsProvider()
{
return [
['./file'],
@@ -36,7 +37,7 @@ public function invalidPathsProvider()
];
}
- public function validPathsProvider()
+ public static function validPathsProvider()
{
return [
['file'],
@@ -61,18 +62,14 @@ public function validPathsProvider()
];
}
- /**
- * @dataProvider invalidPathsProvider
- */
+ #[DataProvider('invalidPathsProvider')]
public function testInvalidPathsOnValidatePath($path)
{
$this->expectException('ApplicationException');
MediaLibrary::validatePath($path);
}
- /**
- * @dataProvider validPathsProvider
- */
+ #[DataProvider('validPathsProvider')]
public function testValidPathsOnValidatePath($path)
{
$result = MediaLibrary::validatePath($path);
diff --git a/modules/system/tests/classes/SourceManifestTest.php b/modules/system/tests/classes/SourceManifestTest.php
index 3b3ed20ea3..b5a692bdec 100644
--- a/modules/system/tests/classes/SourceManifestTest.php
+++ b/modules/system/tests/classes/SourceManifestTest.php
@@ -2,10 +2,10 @@
namespace System\Tests\Classes;
+use System\Classes\FileManifest;
+use System\Classes\SourceManifest;
use System\Tests\Bootstrap\TestCase;
use Winter\Storm\Argon\Argon;
-use System\Classes\SourceManifest;
-use System\Classes\FileManifest;
class SourceManifestTest extends TestCase
{
@@ -53,6 +53,7 @@ public function tearDown(): void
{
Argon::setTestNow();
$this->deleteManifest();
+ parent::tearDown();
}
public function testCreateManifest()
diff --git a/modules/system/tests/classes/VersionManagerTest.php b/modules/system/tests/classes/VersionManagerTest.php
index b4d0463a4c..b760e3d617 100644
--- a/modules/system/tests/classes/VersionManagerTest.php
+++ b/modules/system/tests/classes/VersionManagerTest.php
@@ -2,6 +2,7 @@
namespace System\Tests\Classes;
+use PHPUnit\Framework\Attributes\DataProvider;
use System\Tests\Bootstrap\TestCase;
use System\Classes\VersionManager;
@@ -138,13 +139,7 @@ public function testGetNewFileVersions()
$this->assertArrayHasKey('1.5.1', $result);
}
- /**
- * @dataProvider versionInfoProvider
- *
- * @param $versionInfo
- * @param $expectedComments
- * @param $expectedScripts
- */
+ #[DataProvider('versionInfoProvider')]
public function testExtractScriptsAndComments($versionInfo, $expectedComments, $expectedScripts)
{
$manager = VersionManager::instance();
@@ -157,7 +152,7 @@ public function testExtractScriptsAndComments($versionInfo, $expectedComments, $
$this->assertEquals($expectedScripts, $scripts);
}
- public function versionInfoProvider()
+ public static function versionInfoProvider()
{
return [
[
diff --git a/modules/system/tests/console/CreateCommandTest.php b/modules/system/tests/console/CreateCommandTest.php
index 4bb186ba4a..b65947f17d 100644
--- a/modules/system/tests/console/CreateCommandTest.php
+++ b/modules/system/tests/console/CreateCommandTest.php
@@ -2,9 +2,8 @@
namespace System\Tests\Console;
-use File;
-use InvalidArgumentException;
use System\Tests\Bootstrap\TestCase;
+use Winter\Storm\Support\Facades\File;
class CreateCommandTest extends TestCase
{
diff --git a/modules/system/tests/console/CreateMigrationTest.php b/modules/system/tests/console/CreateMigrationTest.php
index 77e30eea71..bac810e607 100644
--- a/modules/system/tests/console/CreateMigrationTest.php
+++ b/modules/system/tests/console/CreateMigrationTest.php
@@ -2,13 +2,16 @@
namespace System\Tests\Console;
-use File;
-use Illuminate\Database\Schema\Blueprint;
-use Schema;
use System\Tests\Bootstrap\PluginTestCase;
+use Winter\Storm\Support\Facades\File;
+use Winter\Storm\Support\Facades\Schema;
class CreateMigrationTest extends PluginTestCase
{
+ protected ?string $versionFile = null;
+ protected ?string $versionFolder = null;
+ protected ?string $table = null;
+
public function setUp(): void
{
parent::setUp();
@@ -34,46 +37,50 @@ public function testCreateMigration()
$columns = [
'id' => ['type'=>'integer', 'index'=>'primary', 'required'=>true],
- 'cb' => ['type'=>'boolean'],
- 'switch' => ['type'=>'boolean'],
+ 'cb' => ['type'=>'tinyint'],
+ 'switch' => ['type'=>'tinyint'],
'int' => ['type'=>'integer'],
'uint' => ['type'=>'integer', 'required'=>true],
- 'double' => ['type'=>'float'],
+ 'double' => ['type'=>'double'],
'range' => ['type'=>'integer', 'required'=>true],
'datetime' => ['type'=>'datetime'],
'date' => ['type'=>'date', 'required'=>true],
'time' => ['type'=>'time'],
'md' => ['type'=>'text'],
'textarea' => ['type'=>'text'],
- 'text' => ['type'=>'string', 'required'=>true],
+ 'text' => ['type'=>'varchar', 'required'=>true],
'phone_id' => ['type'=>'integer', 'index'=>true, 'required'=>true],
'user_id' => ['type'=>'integer', 'index'=>true, 'required'=>true],
'data' => ['type'=>'text'],
'sort_order' => ['type'=>'integer', 'index'=>true],
'taggable_id' => ['type'=>'integer', 'index'=>'morphable_index'],
- 'taggable_type' => ['type'=>'string', 'index'=>'morphable_index'],
+ 'taggable_type' => ['type'=>'varchar', 'index'=>'morphable_index'],
'created_at' => ['type'=>'datetime'],
'updated_at' => ['type'=>'datetime'],
];
- $table = Schema::getConnection()->getDoctrineSchemaManager()->listTableDetails($this->table);
+ $schemaBuilder = Schema::getConnection()->getSchemaBuilder();
+
+ $tableColumns = collect($schemaBuilder->getColumns($this->table));
+ $tableIndexes = collect($schemaBuilder->getIndexes($this->table))->pluck('columns', 'name');
foreach ($columns as $name => $definition) {
- $this->assertEquals(array_get($definition, 'type'), Schema::getColumnType($this->table, $name));
+ $column = $tableColumns->where('name', $name)->first();
+
+ $this->assertEquals(array_get($definition, 'type'), $column['type_name']);
+ $this->assertEquals(array_get($definition, 'required', false), !$column['nullable']);
// assert an index has been created for the primary, morph and foreign keys
if ($indexName = array_get($definition, 'index')) {
if ($indexName === true) {
$indexName = sprintf("%s_%s_index", $this->table, $name);
}
- $this->assertTrue($table->hasIndex($indexName));
+ $this->assertTrue($schemaBuilder->hasIndex($this->table, $indexName));
- if ($indexName === 'morphable_index') {
- $index = $table->getIndex($indexName);
- $this->assertTrue(in_array($name, $index->getColumns()));
+ if ($indexColumns = array_get($indexName, $tableIndexes)) {
+ $this->assertTrue(in_array($name, $indexColumns));
}
}
- $this->assertEquals(array_get($definition, 'required', false), $table->getColumn($name)->getNotnull());
}
$migration->down();
diff --git a/modules/system/tests/console/WinterUtilTest.php b/modules/system/tests/console/WinterUtilTest.php
index f604ba9439..f0ecb84d8b 100644
--- a/modules/system/tests/console/WinterUtilTest.php
+++ b/modules/system/tests/console/WinterUtilTest.php
@@ -94,5 +94,7 @@ protected function tearDown(): void
}
$this->artisan('winter:util compile lang')->execute();
+
+ parent::tearDown();
}
}
diff --git a/modules/system/tests/console/asset/mix/MixCreateTest.php b/modules/system/tests/console/asset/mix/MixCreateTest.php
index f9fcb1f747..5247147269 100644
--- a/modules/system/tests/console/asset/mix/MixCreateTest.php
+++ b/modules/system/tests/console/asset/mix/MixCreateTest.php
@@ -230,5 +230,7 @@ public function tearDown(): void
File::delete($file);
}
}
+
+ parent::tearDown();
}
}
diff --git a/modules/system/tests/console/asset/mix/MixInstallTest.php b/modules/system/tests/console/asset/mix/MixInstallTest.php
index 1494610628..9127977153 100644
--- a/modules/system/tests/console/asset/mix/MixInstallTest.php
+++ b/modules/system/tests/console/asset/mix/MixInstallTest.php
@@ -18,16 +18,16 @@ public function setUp(): void
{
parent::setUp();
- if (!File::exists(base_path('node_modules'))) {
- $this->markTestSkipped('This test requires node_modules to be installed');
- }
-
// Define some helpful paths
$this->fixturePath = base_path('modules/system/tests');
$this->jsonPath = $this->fixturePath . '/package.json';
$this->lockPath = $this->fixturePath . '/package-lock.json';
$this->backupPath = $this->fixturePath . '/package-testing.json';
+ if (!File::exists(base_path('node_modules'))) {
+ $this->markTestSkipped('This test requires node_modules to be installed');
+ }
+
// Add our testing theme because it won't be auto discovered
PackageManager::instance()->registerPackage(
'theme-assettest',
diff --git a/modules/system/tests/console/asset/npm/NpmInstallTest.php b/modules/system/tests/console/asset/npm/NpmInstallTest.php
index 611ab20df7..8b28c57894 100644
--- a/modules/system/tests/console/asset/npm/NpmInstallTest.php
+++ b/modules/system/tests/console/asset/npm/NpmInstallTest.php
@@ -20,16 +20,16 @@ public function setUp(): void
{
parent::setUp();
- if (!File::exists(base_path('node_modules'))) {
- $this->markTestSkipped('This test requires node_modules to be installed');
- }
-
// Define some helpful paths
$this->themePath = base_path('modules/system/tests/fixtures/themes/npmtest');
$this->jsonPath = $this->themePath . '/package.json';
$this->lockPath = $this->themePath . '/package-lock.json';
$this->backupPath = $this->themePath . '/package.backup.json';
+ if (!File::exists(base_path('node_modules'))) {
+ $this->markTestSkipped('This test requires node_modules to be installed');
+ }
+
// Add our testing theme because it won't be auto discovered
PackageManager::instance()->registerPackage(
'theme-npmtest',
diff --git a/modules/system/tests/console/asset/npm/NpmUpdateTest.php b/modules/system/tests/console/asset/npm/NpmUpdateTest.php
index 38b63d9827..7a509c2847 100644
--- a/modules/system/tests/console/asset/npm/NpmUpdateTest.php
+++ b/modules/system/tests/console/asset/npm/NpmUpdateTest.php
@@ -20,16 +20,16 @@ public function setUp(): void
{
parent::setUp();
- if (!File::exists(base_path('node_modules'))) {
- $this->markTestSkipped('This test requires node_modules to be installed');
- }
-
// Define some helpful paths
$this->themePath = base_path('modules/system/tests/fixtures/themes/npmtest');
$this->jsonPath = $this->themePath . '/package.json';
$this->lockPath = $this->themePath . '/package-lock.json';
$this->backupPath = $this->themePath . '/package.backup.json';
+ if (!File::exists(base_path('node_modules'))) {
+ $this->markTestSkipped('This test requires node_modules to be installed');
+ }
+
// Add our testing theme because it won't be auto discovered
PackageManager::instance()->registerPackage(
'theme-npmtest',
diff --git a/modules/system/tests/console/asset/vite/ViteCreateTest.php b/modules/system/tests/console/asset/vite/ViteCreateTest.php
index cdcfc855ae..db09c2f5b8 100644
--- a/modules/system/tests/console/asset/vite/ViteCreateTest.php
+++ b/modules/system/tests/console/asset/vite/ViteCreateTest.php
@@ -230,5 +230,7 @@ public function tearDown(): void
File::delete($file);
}
}
+
+ parent::tearDown();
}
}
diff --git a/modules/system/tests/console/asset/vite/ViteInstallTest.php b/modules/system/tests/console/asset/vite/ViteInstallTest.php
index 7d97ccf107..e2138116bc 100644
--- a/modules/system/tests/console/asset/vite/ViteInstallTest.php
+++ b/modules/system/tests/console/asset/vite/ViteInstallTest.php
@@ -12,21 +12,22 @@ class ViteInstallTest extends TestCase
protected string $jsonPath;
protected string $lockPath;
protected string $backupPath;
+ protected string $fixturePath;
public function setUp(): void
{
parent::setUp();
- if (!File::exists(base_path('node_modules'))) {
- $this->markTestSkipped('This test requires node_modules to be installed');
- }
-
// Define some helpful paths
$this->fixturePath = base_path('modules/system/tests');
$this->jsonPath = $this->fixturePath . '/package.json';
$this->lockPath = $this->fixturePath . '/package-lock.json';
$this->backupPath = $this->fixturePath . '/package-testing.json';
+ if (!File::exists(base_path('node_modules'))) {
+ $this->markTestSkipped('This test requires node_modules to be installed');
+ }
+
// Add our testing theme because it won't be auto discovered
PackageManager::instance()->registerPackage(
'theme-assettest',
diff --git a/modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php b/modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php
index f5e38b5c5a..f0b0e29d31 100644
--- a/modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php
+++ b/modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php
@@ -8,7 +8,7 @@ class Comments extends ComponentBase
{
private $users;
- public function __construct(?CodeBase $cmsObject = null, $properties = [], ?Users $users = null)
+ public function __construct(Users $users, ?CodeBase $cmsObject = null, $properties = [])
{
parent::__construct($cmsObject, $properties);
$this->users = $users;
diff --git a/phpunit.xml b/phpunit.xml
index 72f7f52986..a53e3ba0c2 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,39 +1,34 @@
-
-
- ./modules/
-
-
- ./modules/backend/routes.php
- ./modules/cms/routes.php
- ./modules/system/routes.php
- ./modules/backend/database
- ./modules/cms/database
- ./modules/system/database
-
-
-
-
- ./modules/system
- ./modules/cms
- ./modules/backend
-
-
-
-
-
-
-
+
+
+ ./modules/system
+ ./modules/cms
+ ./modules/backend
+
+
+
+
+
+
+
+
+
+
+ ./modules/
+
+
+ ./modules/backend/routes.php
+ ./modules/cms/routes.php
+ ./modules/system/routes.php
+ ./modules/backend/database
+ ./modules/cms/database
+ ./modules/system/database
+
+