Merge pull request #16745 from mauriciofauth/flash-messages

Add a flash messages service provider
This commit is contained in:
Maurício Meneghini Fauth 2021-03-20 21:13:51 -03:00 committed by GitHub
commit 5af5fb3fae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 197 additions and 22 deletions

View File

@ -10,6 +10,7 @@ use PhpMyAdmin\Config\PageSettings;
use PhpMyAdmin\Core;
use PhpMyAdmin\Database\CentralColumns;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\FlashMessages;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Message;
use PhpMyAdmin\Operations;
@ -91,6 +92,9 @@ class StructureController extends AbstractController
/** @var DatabaseInterface */
private $dbi;
/** @var FlashMessages */
private $flash;
/**
* @param Response $response
* @param string $db Database name
@ -106,7 +110,8 @@ class StructureController extends AbstractController
$replication,
RelationCleanup $relationCleanup,
Operations $operations,
$dbi
$dbi,
FlashMessages $flash
) {
parent::__construct($response, $template, $db);
$this->relation = $relation;
@ -114,6 +119,7 @@ class StructureController extends AbstractController
$this->relationCleanup = $relationCleanup;
$this->operations = $operations;
$this->dbi = $dbi;
$this->flash = $flash;
$this->replicationInfo = new ReplicationInfo($this->dbi);
}
@ -1552,15 +1558,9 @@ class StructureController extends AbstractController
$selected = $_POST['selected'] ?? [];
if ($mult_btn !== __('Yes')) {
$message = Message::success(__('No change'));
$this->flash->addMessage('success', __('No change'));
if (empty($_POST['message'])) {
$_POST['message'] = Message::success();
}
unset($_POST['mult_btn']);
$this->index();
Core::sendHeaderLocation('./index.php?route=/database/structure' . Url::getCommonRaw(['db' => $db], '&'));
return;
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin;
use RuntimeException;
final class FlashMessages
{
private const STORAGE_KEY = 'flashMessages';
/** @var array */
private $storage;
/** @var array<string, string[]> */
private $previousMessages = [];
public function __construct()
{
if (! isset($_SESSION)) {
throw new RuntimeException(__('Session not found.'));
}
$this->storage = &$_SESSION;
if (isset($this->storage[self::STORAGE_KEY])) {
$this->previousMessages = $this->storage[self::STORAGE_KEY];
}
$this->storage[self::STORAGE_KEY] = [];
}
public function addMessage(string $key, string $message): void
{
if (! isset($this->storage[self::STORAGE_KEY][$key])) {
$this->storage[self::STORAGE_KEY][$key] = [];
}
$this->storage[self::STORAGE_KEY][$key][] = $message;
}
/** @return string[]|null */
public function getMessage(string $key): ?array
{
return $this->previousMessages[$key] ?? null;
}
/** @return array<string, string[]> */
public function getMessages(): array
{
return $this->previousMessages;
}
}

View File

@ -7,6 +7,7 @@ namespace PhpMyAdmin;
use PhpMyAdmin\Twig\AssetExtension;
use PhpMyAdmin\Twig\CoreExtension;
use PhpMyAdmin\Twig\Extensions\Node\TransNode;
use PhpMyAdmin\Twig\FlashMessagesExtension;
use PhpMyAdmin\Twig\I18nExtension;
use PhpMyAdmin\Twig\MessageExtension;
use PhpMyAdmin\Twig\PluginsExtension;
@ -25,6 +26,7 @@ use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Extension\DebugExtension;
use Twig\Loader\FilesystemLoader;
use Twig\RuntimeLoader\ContainerRuntimeLoader;
use Twig\TemplateWrapper;
use function sprintf;
@ -61,7 +63,7 @@ class Template
public static function getTwigEnvironment(?string $cacheDir): Environment
{
global $cfg;
global $cfg, $containerBuilder;
/* Twig expects false when cache is not configured */
if ($cacheDir === null) {
@ -74,6 +76,8 @@ class Template
'cache' => $cacheDir,
]);
$twig->addRuntimeLoader(new ContainerRuntimeLoader($containerBuilder));
if ($cfg['environment'] === 'development') {
$twig->enableDebug();
$twig->addExtension(new DebugExtension());
@ -89,6 +93,7 @@ class Template
$twig->addExtension(new AssetExtension());
$twig->addExtension(new CoreExtension());
$twig->addExtension(new FlashMessagesExtension());
$twig->addExtension(new I18nExtension());
$twig->addExtension(new MessageExtension());
$twig->addExtension(new PluginsExtension());

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Twig;
use PhpMyAdmin\FlashMessages;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
final class FlashMessagesExtension extends AbstractExtension
{
/** @return TwigFunction[] */
public function getFunctions(): array
{
return [new TwigFunction('flash', [FlashMessages::class, 'getMessages'])];
}
}

View File

@ -84,6 +84,9 @@ return [
'expression_language' => [
'class' => Symfony\Component\ExpressionLanguage\ExpressionLanguage::class,
],
'flash' => [
'class' => PhpMyAdmin\FlashMessages::class,
],
'http_request' => [
'class' => PhpMyAdmin\Utils\HttpRequest::class,
],
@ -214,7 +217,8 @@ return [
'user_preferences' => [
'class' => PhpMyAdmin\UserPreferences::class,
],
PhpMyAdmin\Response::class => 'response',
PhpMyAdmin\DatabaseInterface::class => 'dbi',
PhpMyAdmin\FlashMessages::class => 'flash',
PhpMyAdmin\Response::class => 'response',
],
];

View File

@ -201,6 +201,7 @@ return [
'$relationCleanup' => '@relation_cleanup',
'$operations' => '@operations',
'$dbi' => '@dbi',
'$flash' => '@flash',
],
],
PhpMyAdmin\Controllers\Database\TrackingController::class => [

View File

@ -4,6 +4,7 @@
use PhpMyAdmin\Command\CacheWarmupCommand;
use PhpMyAdmin\Command\SetVersionCommand;
use PhpMyAdmin\Config;
use PhpMyAdmin\Core;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Template;
use PhpMyAdmin\Tests\Stubs\DbiDummy;
@ -24,6 +25,7 @@ if (! class_exists(Application::class)) {
exit(1);
}
$containerBuilder = Core::getContainerBuilder();
$cfg['environment'] = 'production';
$config = new Config(CONFIG_FILE);
$config->set('environment', $cfg['environment']);

View File

@ -1,4 +1,4 @@
<form action="{{ url('/database/structure/empty-table') }}" method="post">
<form action="{{ url('/database/structure/empty-table') }}" class="disableAjax" method="post">
{{ get_hidden_inputs(url_params) }}
<fieldset class="pma-fieldset confirmation">

View File

@ -1,3 +1,11 @@
{% for flash_key, flash_messages in flash() %}
{% for flash_message in flash_messages %}
<div class="alert alert-{{ flash_key }}" role="alert">
{{ flash_message }}
</div>
{% endfor %}
{% endfor %}
{% if has_tables %}
<div id="tableslistcontainer">
{{ list_navigator_html|raw }}

View File

@ -6,6 +6,7 @@
declare(strict_types=1);
use PhpMyAdmin\Config;
use PhpMyAdmin\Core;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\MoTranslator\Loader;
use PhpMyAdmin\Tests\Stubs\DbiDummy;
@ -47,6 +48,8 @@ require_once ROOT_PATH . 'libraries/vendor_config.php';
require_once AUTOLOAD_FILE;
Loader::loadFunctions();
$GLOBALS['containerBuilder'] = Core::getContainerBuilder();
$GLOBALS['config'] = new Config();
$GLOBALS['config']->set('environment', 'development');
$GLOBALS['cfg']['environment'] = 'development';

View File

@ -11,6 +11,7 @@ namespace PhpMyAdmin\Tests\Controllers\Database;
use PhpMyAdmin\Controllers\Database\StructureController;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\FlashMessages;
use PhpMyAdmin\Operations;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Relation;
@ -53,6 +54,9 @@ class StructureControllerTest extends AbstractTestCase
/** @var Operations */
private $operations;
/** @var FlashMessages */
private $flash;
/**
* Prepares environment for the test.
*/
@ -95,6 +99,7 @@ class StructureControllerTest extends AbstractTestCase
$this->replication = new Replication();
$this->relationCleanup = new RelationCleanup($dbi, $this->relation);
$this->operations = new Operations($dbi, $this->relation);
$this->flash = new FlashMessages();
}
/**
@ -113,7 +118,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
// Showing statistics
$property = $class->getProperty('isShowStats');
@ -173,7 +179,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
$currentTable['ENGINE'] = 'InnoDB';
@ -216,7 +223,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
// Showing statistics
$property = $class->getProperty('isShowStats');
@ -280,7 +288,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
[$currentTable, , , , , , $sumSize] = $method->invokeArgs(
$controller,
@ -304,7 +313,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
[$currentTable] = $method->invokeArgs(
$controller,
@ -338,7 +348,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
// When parameter $db is empty
@ -376,7 +387,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] = [
@ -414,7 +426,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
// The user hash for test
@ -474,7 +487,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
// Showing statistics
$class = new ReflectionClass(StructureController::class);
@ -524,7 +538,8 @@ class StructureControllerTest extends AbstractTestCase
$this->replication,
$this->relationCleanup,
$this->operations,
$GLOBALS['dbi']
$GLOBALS['dbi'],
$this->flash
);
// Showing statistics
$class = new ReflectionClass(StructureController::class);

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Tests;
use PhpMyAdmin\FlashMessages;
use RuntimeException;
class FlashMessagesTest extends AbstractTestCase
{
private const STORAGE_KEY = 'flashMessages';
public function testConstructor(): void
{
$this->assertArrayNotHasKey(self::STORAGE_KEY, $_SESSION);
$flash = new FlashMessages();
$this->assertIsArray($_SESSION[self::STORAGE_KEY]);
$_SESSION = null;
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Session not found.');
$flash = new FlashMessages();
}
public function testAddMessage(): void
{
$flash = new FlashMessages();
$this->assertArrayNotHasKey('error', $_SESSION[self::STORAGE_KEY]);
$flash->addMessage('error', 'Error');
$this->assertArrayHasKey('error', $_SESSION[self::STORAGE_KEY]);
$this->assertIsArray($_SESSION[self::STORAGE_KEY]['error']);
$this->assertEquals(['Error'], $_SESSION[self::STORAGE_KEY]['error']);
}
public function testGetMessage(): void
{
$_SESSION[self::STORAGE_KEY] = ['warning' => ['Warning']];
$flash = new FlashMessages();
$message = $flash->getMessage('error');
$this->assertNull($message);
$message = $flash->getMessage('warning');
$this->assertEquals(['Warning'], $message);
}
public function testGetMessages(): void
{
$_SESSION[self::STORAGE_KEY] = [
'error' => ['Error1', 'Error2'],
'warning' => ['Warning'],
];
$flash = new FlashMessages();
$flash->addMessage('notice', 'Notice');
$messages = $flash->getMessages();
$this->assertEquals(
[
'error' => ['Error1', 'Error2'],
'warning' => ['Warning'],
],
$messages
);
}
}

View File

@ -30,6 +30,8 @@ class TemplateTest extends AbstractTestCase
{
global $cfg;
$this->loadContainerBuilder();
$cfg['environment'] = 'production';
$twig = Template::getTwigEnvironment(null);
$this->assertFalse($twig->isDebug());