Skip to content

Commit b9d09ce

Browse files
committed
Merge branch '4.1' into 'main'
2 parents a96f5e0 + ccd424d commit b9d09ce

39 files changed

+7837
-1780
lines changed

.docker/apache/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#####################################
77
#=== Unique stage without payload ===
88
#####################################
9-
FROM php:8.4.5RC1-apache
9+
FROM php:8.4-apache
1010

1111
#=== Install gd PHP dependencie ===
1212
RUN set -x \
@@ -58,7 +58,7 @@ RUN set -ex \
5858
&& rm -rf /var/lib/apt/lists/*
5959

6060
#=== Install xdebug PHP dependencies ===
61-
RUN pecl install xdebug-3.4.2 \
61+
RUN pecl install xdebug-3.5.0 \
6262
&& docker-php-ext-enable xdebug
6363

6464
#=== php default ===

.docker/php-fpm/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#####################################
77
#=== Unique stage without payload ===
88
#####################################
9-
FROM php:8.4.5RC1-fpm
9+
FROM php:8.4-fpm
1010

1111
#=== Install gd PHP dependencies ===
1212
RUN set -x \
@@ -58,7 +58,7 @@ RUN set -ex \
5858
&& rm -rf /var/lib/apt/lists/*
5959

6060
#=== Install xdebug PHP dependencies ===
61-
RUN pecl install xdebug-3.4.2 \
61+
RUN pecl install xdebug-3.5.0 \
6262
&& docker-php-ext-enable xdebug
6363

6464
#=== php default ===

CHANGELOG.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ This is a log of major user-visible changes in each phpMyFAQ release.
1010

1111
- changed PHP requirement to PHP 8.4 or later (Thorsten)
1212

13-
### phpMyFAQ v4.1.0-RC - 2025-12-29
13+
### phpMyFAQ v4.1.0-RC.2 - unreleased
1414

15-
- fixed security vulnerabilities (Thorsten)
1615
- changed PHP requirement to PHP 8.3 or later (Thorsten)
1716
- added configuration to edit robots.txt (Thorsten)
1817
- added configuration to edit llms.txt (Thorsten)
@@ -55,13 +54,25 @@ This is a log of major user-visible changes in each phpMyFAQ release.
5554
- updated Basque translation
5655
- updated Bengali translation
5756
- updated Bosnian translation
57+
- updated Ukrainian translation
58+
- updated Czech translation
59+
- updated Welsh translation
60+
- updated Danish translation
61+
- updated Greek translation
62+
- updated Farsi translation
63+
- updated Canadian French translation
64+
- updated Hebrew translation
5865
- updated to PHPUnit v12 (Thorsten)
5966
- migrated codebase to use PHP 8.3 language features (Thorsten)
6067
- migrated from WYSIWYG editor from TinyMCE to Jodit Editor (Thorsten)
6168
- migrated from JavaScript to TypeScript (Thorsten)
6269
- migrated from Webpack to Vite v7 (Thorsten)
6370
- migrated from Jest to Vitest v4 (Thorsten)
6471

72+
### phpMyFAQ v4.0.17 - unreleased
73+
74+
- updated third party dependencies (Thorsten)
75+
6576
### phpMyFAQ v4.0.16 - 2025-12-29
6677

6778
- fixed security vulnerabilities (Thorsten)

phpmyfaq/assets/templates/admin/configuration/plugins.twig

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,38 @@
3636
</tbody>
3737
</table>
3838

39-
<p>
39+
{% if incompatiblePlugins is not empty %}
40+
<div class="alert alert-warning mt-4" role="alert">
41+
<h5 class="alert-heading">
42+
<i aria-hidden="true" class="bi bi-exclamation-triangle-fill"></i>
43+
{{ 'msgIncompatiblePlugins' | translate }}
44+
</h5>
45+
<p>{{ 'msgIncompatiblePluginsInfo' | translate }}</p>
46+
</div>
47+
48+
<table class="table table-striped">
49+
<thead>
50+
<tr>
51+
<th>{{ 'msgPluginName' | translate }}</th>
52+
<th>{{ 'msgPluginVersion' | translate }}</th>
53+
<th>{{ 'msgPluginAuthor' | translate }}</th>
54+
<th>{{ 'msgPluginReason' | translate }}</th>
55+
</tr>
56+
</thead>
57+
<tbody>
58+
{% for name, info in incompatiblePlugins %}
59+
<tr>
60+
<td>{{ info.plugin.name }}</td>
61+
<td>{{ info.plugin.version }}</td>
62+
<td>{{ info.plugin.author }}</td>
63+
<td><small class="text-danger">{{ info.reason }}</small></td>
64+
</tr>
65+
{% endfor %}
66+
</tbody>
67+
</table>
68+
{% endif %}
69+
70+
<p class="mt-3">
4071
<a target="_blank" href="https://phpmyfaq.readthedocs.io/en/main/plugins/">
4172
{{ 'msgDocumentation' | translate }}
4273
</a>

phpmyfaq/src/phpMyFAQ/Controller/Administration/GroupController.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@ public function create(Request $request): Response
9292

9393
$user = $this->container->get(id: 'phpmyfaq.user');
9494

95-
$groupName = Filter::filterVar($request->attributes->get('group_name'), FILTER_SANITIZE_SPECIAL_CHARS);
95+
$groupName = Filter::filterVar($request->request->get('group_name'), FILTER_SANITIZE_SPECIAL_CHARS);
9696
$groupDescription = Filter::filterVar(
97-
$request->attributes->get('group_description'),
97+
$request->request->get('group_description'),
9898
FILTER_SANITIZE_SPECIAL_CHARS,
9999
);
100-
$groupAutoJoin = Filter::filterVar($request->attributes->get('group_auto_join'), FILTER_SANITIZE_SPECIAL_CHARS);
100+
$groupAutoJoin = Filter::filterVar($request->request->get('group_auto_join'), FILTER_SANITIZE_SPECIAL_CHARS);
101101

102102
// check group name
103103
if ($groupName === '') {
@@ -137,7 +137,7 @@ public function confirm(Request $request): Response
137137

138138
$session = $this->container->get(id: 'session');
139139

140-
$groupId = (int) Filter::filterVar($request->attributes->get('group_list_select'), FILTER_VALIDATE_INT);
140+
$groupId = (int) Filter::filterVar($request->request->get('group_list_select'), FILTER_VALIDATE_INT);
141141
$groupData = $this->currentUser->perm->getGroupData($groupId);
142142

143143
$this->addExtension(new AttributeExtension(PermissionTranslationTwigExtension::class));
@@ -159,8 +159,8 @@ public function delete(Request $request): Response
159159
{
160160
$this->userHasPermission(PermissionType::GROUP_DELETE);
161161

162-
$groupId = (int) Filter::filterVar($request->attributes->get('group_id'), FILTER_VALIDATE_INT);
163-
$csrfToken = Filter::filterVar($request->attributes->get('pmf-csrf-token'), FILTER_SANITIZE_SPECIAL_CHARS);
162+
$groupId = (int) Filter::filterVar($request->request->get('group_id'), FILTER_VALIDATE_INT);
163+
$csrfToken = Filter::filterVar($request->request->get('pmf-csrf-token'), FILTER_SANITIZE_SPECIAL_CHARS);
164164

165165
if (!Token::getInstance($this->container->get(id: 'session'))->verifyToken('delete-group', $csrfToken)) {
166166
throw new UnauthorizedHttpException('Invalid CSRF token');
@@ -194,13 +194,13 @@ public function update(Request $request): Response
194194
{
195195
$this->userHasPermission(PermissionType::GROUP_EDIT);
196196

197-
$groupId = (int) Filter::filterVar($request->attributes->get('group_id'), FILTER_VALIDATE_INT);
197+
$groupId = (int) Filter::filterVar($request->request->get('group_id'), FILTER_VALIDATE_INT);
198198

199199
$groupData = [];
200200
$dataFields = ['name', 'description', 'auto_join'];
201201
foreach ($dataFields as $dataField) {
202202
$groupData[$dataField] = Filter::filterVar(
203-
$request->attributes->get($dataField),
203+
$request->request->get($dataField),
204204
FILTER_SANITIZE_SPECIAL_CHARS,
205205
'',
206206
);
@@ -242,7 +242,7 @@ public function updateMembers(Request $request): Response
242242
{
243243
$this->userHasPermission(PermissionType::GROUP_EDIT);
244244

245-
$groupId = (int) Filter::filterVar($request->attributes->get('group_id'), FILTER_VALIDATE_INT);
245+
$groupId = (int) Filter::filterVar($request->request->get('group_id'), FILTER_VALIDATE_INT);
246246
$groupMembers = $request->request->all()['group_members'];
247247

248248
$user = $this->container->get(id: 'phpmyfaq.user');
@@ -280,7 +280,7 @@ public function updatePermissions(Request $request): Response
280280
{
281281
$this->userHasPermission(PermissionType::GROUP_EDIT);
282282

283-
$groupId = (int) Filter::filterVar($request->attributes->get('group_id'), FILTER_VALIDATE_INT);
283+
$groupId = (int) Filter::filterVar($request->request->get('group_id'), FILTER_VALIDATE_INT);
284284
$groupPermissions = $request->request->all()['group_rights'];
285285

286286
$user = $this->container->get(id: 'phpmyfaq.user');

phpmyfaq/src/phpMyFAQ/Controller/Administration/PluginController.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
namespace phpMyFAQ\Controller\Administration;
2121

2222
use phpMyFAQ\Core\Exception;
23-
use phpMyFAQ\Plugin\PluginException;
2423
use Symfony\Component\HttpFoundation\Request;
2524
use Symfony\Component\HttpFoundation\Response;
2625
use Symfony\Component\Routing\Attribute\Route;
@@ -29,7 +28,6 @@
2928
final class PluginController extends AbstractAdministrationController
3029
{
3130
/**
32-
* @throws PluginException
3331
* @throws LoaderError
3432
* @throws Exception
3533
* @throws \Exception
@@ -44,6 +42,7 @@ public function index(Request $request): Response
4442
...$this->getHeader($request),
4543
...$this->getFooter(),
4644
'pluginList' => $pluginManager->getPlugins(),
45+
'incompatiblePlugins' => $pluginManager->getIncompatiblePlugins(),
4746
]);
4847
}
4948
}

phpmyfaq/src/phpMyFAQ/Plugin/PluginManager.php

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ class PluginManager
4141
/** @var string[] */
4242
private array $loadedPlugins = [];
4343

44-
/** @var array<string, string[]> Plugin stylesheets: [pluginName => [css paths]] */
44+
/** @var array<string, array{plugin: PluginInterface, reason: string}> */
45+
private array $incompatiblePlugins = [];
46+
47+
/** @var array<string, string[]> Plugin stylesheets: [pluginName => [CSS paths]] */
4548
private array $pluginStylesheets = [];
4649

4750
/** @var array<string, string[]> Plugin scripts: [pluginName => [js paths]] */
@@ -57,7 +60,6 @@ public function __construct()
5760

5861
/**
5962
* Registers a plugin
60-
* @throws PluginException
6163
*/
6264
public function registerPlugin(string $pluginClass): void
6365
{
@@ -66,13 +68,20 @@ public function registerPlugin(string $pluginClass): void
6668
$this->plugins[$plugin->getName()] = $plugin;
6769
$this->containerBuilder->register($plugin->getName(), $pluginClass);
6870
} else {
69-
throw new PluginException(sprintf('Plugin %s is not compatible.', $plugin->getName()));
71+
$this->incompatiblePlugins[$plugin->getName()] = [
72+
'plugin' => $plugin,
73+
'reason' => sprintf(
74+
'Plugin version %s is not compatible with system version %s',
75+
$plugin->getVersion(),
76+
System::getPluginVersion(),
77+
),
78+
];
7079
}
7180
}
7281

7382
/**
7483
* Loads and registers all plugins
75-
* @throws PluginException|Exception
84+
* @throws Exception
7685
*/
7786
public function loadPlugins(): void
7887
{
@@ -121,7 +130,13 @@ public function loadPlugins(): void
121130
$this->registerPluginScripts($plugin->getName(), $scripts);
122131
}
123132
} else {
124-
throw new PluginException(sprintf('Dependencies for plugin %s are not met.', $plugin->getName()));
133+
$missingDeps = $this->getMissingDependencies($plugin);
134+
$this->incompatiblePlugins[$plugin->getName()] = [
135+
'plugin' => $plugin,
136+
'reason' => sprintf('Missing dependencies: %s', implode(', ', $missingDeps)),
137+
];
138+
// Remove plugin from the plugins array since it's incompatible
139+
unset($this->plugins[$plugin->getName()]);
125140
}
126141
}
127142
}
@@ -319,4 +334,31 @@ public function getPluginScripts(string $pluginName): array
319334
{
320335
return $this->pluginScripts[$pluginName] ?? [];
321336
}
337+
338+
/**
339+
* Returns all incompatible plugins with their reasons
340+
*
341+
* @return array<string, array{plugin: PluginInterface, reason: string}>
342+
*/
343+
public function getIncompatiblePlugins(): array
344+
{
345+
return $this->incompatiblePlugins;
346+
}
347+
348+
/**
349+
* Gets the missing dependencies for a plugin
350+
*
351+
* @return string[]
352+
*/
353+
private function getMissingDependencies(PluginInterface $plugin): array
354+
{
355+
$missingDeps = [];
356+
foreach ($plugin->getDependencies() as $dependency) {
357+
if (!in_array($dependency, $this->loadedPlugins)) {
358+
$missingDeps[] = $dependency;
359+
}
360+
}
361+
362+
return $missingDeps;
363+
}
322364
}

phpmyfaq/translations/language_ar.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,9 @@
14711471
$PMF_LANG['msgPluginVersion'] = 'الإصدار';
14721472
$PMF_LANG['msgPluginAuthor'] = 'المؤلف';
14731473
$PMF_LANG['msgPluginDescription'] = 'الوصف';
1474+
$PMF_LANG['msgPluginReason'] = 'السبب';
1475+
$PMF_LANG['msgIncompatiblePlugins'] = 'إضافات غير متوافقة';
1476+
$PMF_LANG['msgIncompatiblePluginsInfo'] = 'تعذر تحميل الإضافات التالية بسبب مشكلات التوافق.';
14741477

14751478
// added v4.1.0-alpha.2 - 2025-02-23 by Thorsten
14761479
$PMF_LANG['msgReportABug'] = 'الإبلاغ عن خطأ';

phpmyfaq/translations/language_bn.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,9 @@
14751475
$PMF_LANG['msgPluginVersion'] = 'সংস্করণ';
14761476
$PMF_LANG['msgPluginAuthor'] = 'লেখক';
14771477
$PMF_LANG['msgPluginDescription'] = 'বিবরণ';
1478+
$PMF_LANG['msgPluginReason'] = 'কারণ';
1479+
$PMF_LANG['msgIncompatiblePlugins'] = 'অসামঞ্জস্যপূর্ণ প্লাগইন';
1480+
$PMF_LANG['msgIncompatiblePluginsInfo'] = 'সামঞ্জস্যের সমস্যার কারণে নিম্নলিখিত প্লাগইনগুলি লোড করা যায়নি।';
14781481

14791482
// added v4.1.0-alpha.2 - 2025-02-23 by Thorsten
14801483
$PMF_LANG['msgReportABug'] = 'একটি বাগ রিপোর্ট করুন';

phpmyfaq/translations/language_bs.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,9 @@
14721472
$PMF_LANG['msgPluginVersion'] = 'Verzija';
14731473
$PMF_LANG['msgPluginAuthor'] = 'Autor';
14741474
$PMF_LANG['msgPluginDescription'] = 'Opis';
1475+
$PMF_LANG['msgPluginReason'] = 'Razlog';
1476+
$PMF_LANG['msgIncompatiblePlugins'] = 'Nekompatibilni dodaci';
1477+
$PMF_LANG['msgIncompatiblePluginsInfo'] = 'Sljedeći dodaci nisu mogli biti učitani zbog problema s kompatibilnošću.';
14751478

14761479
// added v4.1.0-alpha.2 - 2025-02-23 by Thorsten
14771480
$PMF_LANG['msgReportABug'] = 'Prijavi grešku';

0 commit comments

Comments
 (0)