From bcce2625a8cb0b630d945c6849014049869e10ce Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 27 Nov 2018 12:01:36 +0100 Subject: Implemented AuthController for login * Moved /login functionality to AuthController * Refactored password handling logic to use the Authenticator --- src/Middleware/LegacyMiddleware.php | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/Middleware') diff --git a/src/Middleware/LegacyMiddleware.php b/src/Middleware/LegacyMiddleware.php index af2c6a70..7adcc88d 100644 --- a/src/Middleware/LegacyMiddleware.php +++ b/src/Middleware/LegacyMiddleware.php @@ -19,7 +19,6 @@ class LegacyMiddleware implements MiddlewareInterface 'angeltypes', 'atom', 'ical', - 'login', 'public_dashboard', 'rooms', 'shift_entries', @@ -175,10 +174,6 @@ class LegacyMiddleware implements MiddlewareInterface $title = settings_title(); $content = user_settings(); return [$title, $content]; - case 'login': - $title = login_title(); - $content = guest_login(); - return [$title, $content]; case 'register': $title = register_title(); $content = guest_register(); -- cgit v1.2.3-54-g00ecf From f90ab26feedb61615bde2f94bbf5acc7e4f28342 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Mon, 8 Jul 2019 01:31:59 +0200 Subject: Moved translation helpers to sub namespace --- config/app.php | 2 +- includes/helper/email_helper.php | 3 +- .../Translation/TranslationServiceProvider.php | 63 +++++++++ src/Helpers/Translation/Translator.php | 147 +++++++++++++++++++++ src/Helpers/TranslationServiceProvider.php | 63 --------- src/Helpers/Translator.php | 147 --------------------- src/Middleware/LegacyMiddleware.php | 2 +- src/Middleware/SetLocale.php | 2 +- src/Renderer/Twig/Extensions/Translation.php | 2 +- src/helpers.php | 2 +- .../Translation/TranslationServiceProviderTest.php | 84 ++++++++++++ tests/Unit/Helpers/Translation/TranslatorTest.php | 90 +++++++++++++ .../Helpers/TranslationServiceProviderTest.php | 84 ------------ tests/Unit/Helpers/TranslatorTest.php | 90 ------------- tests/Unit/HelpersTest.php | 2 +- tests/Unit/Middleware/LegacyMiddlewareTest.php | 2 +- tests/Unit/Middleware/SetLocaleTest.php | 2 +- .../Renderer/Twig/Extensions/TranslationTest.php | 2 +- 18 files changed, 395 insertions(+), 394 deletions(-) create mode 100644 src/Helpers/Translation/TranslationServiceProvider.php create mode 100644 src/Helpers/Translation/Translator.php delete mode 100644 src/Helpers/TranslationServiceProvider.php delete mode 100644 src/Helpers/Translator.php create mode 100644 tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php create mode 100644 tests/Unit/Helpers/Translation/TranslatorTest.php delete mode 100644 tests/Unit/Helpers/TranslationServiceProviderTest.php delete mode 100644 tests/Unit/Helpers/TranslatorTest.php (limited to 'src/Middleware') diff --git a/config/app.php b/config/app.php index 17fdee11..5fda67dd 100644 --- a/config/app.php +++ b/config/app.php @@ -17,7 +17,7 @@ return [ \Engelsystem\Database\DatabaseServiceProvider::class, \Engelsystem\Http\RequestServiceProvider::class, \Engelsystem\Http\SessionServiceProvider::class, - \Engelsystem\Helpers\TranslationServiceProvider::class, + \Engelsystem\Helpers\Translation\TranslationServiceProvider::class, \Engelsystem\Http\ResponseServiceProvider::class, \Engelsystem\Http\Psr7ServiceProvider::class, \Engelsystem\Helpers\AuthenticatorServiceProvider::class, diff --git a/includes/helper/email_helper.php b/includes/helper/email_helper.php index bad0d539..3012d5ce 100644 --- a/includes/helper/email_helper.php +++ b/includes/helper/email_helper.php @@ -1,5 +1,6 @@ get('translator'); $locale = $translator->getLocale(); diff --git a/src/Helpers/Translation/TranslationServiceProvider.php b/src/Helpers/Translation/TranslationServiceProvider.php new file mode 100644 index 00000000..d0cda6a8 --- /dev/null +++ b/src/Helpers/Translation/TranslationServiceProvider.php @@ -0,0 +1,63 @@ +app->get('config'); + /** @var Session $session */ + $session = $this->app->get('session'); + + $locales = $config->get('locales'); + $locale = $config->get('default_locale'); + + $sessionLocale = $session->get('locale', $locale); + if (isset($locales[$sessionLocale])) { + $locale = $sessionLocale; + } + + $this->initGettext(); + $session->set('locale', $locale); + + $translator = $this->app->make( + Translator::class, + ['locale' => $locale, 'locales' => $locales, 'localeChangeCallback' => [$this, 'setLocale']] + ); + $this->app->instance(Translator::class, $translator); + $this->app->instance('translator', $translator); + } + + /** + * @param string $textDomain + * @param string $encoding + * @codeCoverageIgnore + */ + protected function initGettext($textDomain = 'default', $encoding = 'UTF-8') + { + bindtextdomain($textDomain, $this->app->get('path.lang')); + bind_textdomain_codeset($textDomain, $encoding); + textdomain($textDomain); + } + + /** + * @param string $locale + * @codeCoverageIgnore + */ + public function setLocale($locale) + { + // Set the users locale + putenv('LC_ALL=' . $locale); + setlocale(LC_ALL, $locale); + + // Reset numeric formatting to allow output of floats + putenv('LC_NUMERIC=C'); + setlocale(LC_NUMERIC, 'C'); + } +} diff --git a/src/Helpers/Translation/Translator.php b/src/Helpers/Translation/Translator.php new file mode 100644 index 00000000..545963eb --- /dev/null +++ b/src/Helpers/Translation/Translator.php @@ -0,0 +1,147 @@ +localeChangeCallback = $localeChangeCallback; + + $this->setLocale($locale); + $this->setLocales($locales); + } + + /** + * Get the translation for a given key + * + * @param string $key + * @param array $replace + * @return string + */ + public function translate(string $key, array $replace = []): string + { + $translated = $this->translateGettext($key); + + return $this->replaceText($translated, $replace); + } + + /** + * Get the translation for a given key + * + * @param string $key + * @param string $pluralKey + * @param int $number + * @param array $replace + * @return string + */ + public function translatePlural(string $key, string $pluralKey, int $number, array $replace = []): string + { + $translated = $this->translateGettextPlural($key, $pluralKey, $number); + + return $this->replaceText($translated, $replace); + } + + /** + * Replace placeholders + * + * @param string $key + * @param array $replace + * @return mixed|string + */ + protected function replaceText(string $key, array $replace = []) + { + if (empty($replace)) { + return $key; + } + + return call_user_func_array('sprintf', array_merge([$key], $replace)); + } + + /** + * Translate the key via gettext + * + * @param string $key + * @return string + * @codeCoverageIgnore + */ + protected function translateGettext(string $key): string + { + return gettext($key); + } + + /** + * Translate the key via gettext + * + * @param string $key + * @param string $keyPlural + * @param int $number + * @return string + * @codeCoverageIgnore + */ + protected function translateGettextPlural(string $key, string $keyPlural, int $number): string + { + return ngettext($key, $keyPlural, $number); + } + + /** + * @return string + */ + public function getLocale(): string + { + return $this->locale; + } + + /** + * @param string $locale + */ + public function setLocale(string $locale) + { + $this->locale = $locale; + + if (is_callable($this->localeChangeCallback)) { + call_user_func_array($this->localeChangeCallback, [$locale]); + } + } + + /** + * @return string[] + */ + public function getLocales(): array + { + return $this->locales; + } + + /** + * @param string $locale + * @return bool + */ + public function hasLocale(string $locale): bool + { + return isset($this->locales[$locale]); + } + + /** + * @param string[] $locales + */ + public function setLocales(array $locales) + { + $this->locales = $locales; + } +} diff --git a/src/Helpers/TranslationServiceProvider.php b/src/Helpers/TranslationServiceProvider.php deleted file mode 100644 index 4565dfcd..00000000 --- a/src/Helpers/TranslationServiceProvider.php +++ /dev/null @@ -1,63 +0,0 @@ -app->get('config'); - /** @var Session $session */ - $session = $this->app->get('session'); - - $locales = $config->get('locales'); - $locale = $config->get('default_locale'); - - $sessionLocale = $session->get('locale', $locale); - if (isset($locales[$sessionLocale])) { - $locale = $sessionLocale; - } - - $this->initGettext(); - $session->set('locale', $locale); - - $translator = $this->app->make( - Translator::class, - ['locale' => $locale, 'locales' => $locales, 'localeChangeCallback' => [$this, 'setLocale']] - ); - $this->app->instance(Translator::class, $translator); - $this->app->instance('translator', $translator); - } - - /** - * @param string $textDomain - * @param string $encoding - * @codeCoverageIgnore - */ - protected function initGettext($textDomain = 'default', $encoding = 'UTF-8') - { - bindtextdomain($textDomain, $this->app->get('path.lang')); - bind_textdomain_codeset($textDomain, $encoding); - textdomain($textDomain); - } - - /** - * @param string $locale - * @codeCoverageIgnore - */ - public function setLocale($locale) - { - // Set the users locale - putenv('LC_ALL=' . $locale); - setlocale(LC_ALL, $locale); - - // Reset numeric formatting to allow output of floats - putenv('LC_NUMERIC=C'); - setlocale(LC_NUMERIC, 'C'); - } -} diff --git a/src/Helpers/Translator.php b/src/Helpers/Translator.php deleted file mode 100644 index 94fbd795..00000000 --- a/src/Helpers/Translator.php +++ /dev/null @@ -1,147 +0,0 @@ -localeChangeCallback = $localeChangeCallback; - - $this->setLocale($locale); - $this->setLocales($locales); - } - - /** - * Get the translation for a given key - * - * @param string $key - * @param array $replace - * @return string - */ - public function translate(string $key, array $replace = []): string - { - $translated = $this->translateGettext($key); - - return $this->replaceText($translated, $replace); - } - - /** - * Get the translation for a given key - * - * @param string $key - * @param string $pluralKey - * @param int $number - * @param array $replace - * @return string - */ - public function translatePlural(string $key, string $pluralKey, int $number, array $replace = []): string - { - $translated = $this->translateGettextPlural($key, $pluralKey, $number); - - return $this->replaceText($translated, $replace); - } - - /** - * Replace placeholders - * - * @param string $key - * @param array $replace - * @return mixed|string - */ - protected function replaceText(string $key, array $replace = []) - { - if (empty($replace)) { - return $key; - } - - return call_user_func_array('sprintf', array_merge([$key], $replace)); - } - - /** - * Translate the key via gettext - * - * @param string $key - * @return string - * @codeCoverageIgnore - */ - protected function translateGettext(string $key): string - { - return gettext($key); - } - - /** - * Translate the key via gettext - * - * @param string $key - * @param string $keyPlural - * @param int $number - * @return string - * @codeCoverageIgnore - */ - protected function translateGettextPlural(string $key, string $keyPlural, int $number): string - { - return ngettext($key, $keyPlural, $number); - } - - /** - * @return string - */ - public function getLocale(): string - { - return $this->locale; - } - - /** - * @param string $locale - */ - public function setLocale(string $locale) - { - $this->locale = $locale; - - if (is_callable($this->localeChangeCallback)) { - call_user_func_array($this->localeChangeCallback, [$locale]); - } - } - - /** - * @return string[] - */ - public function getLocales(): array - { - return $this->locales; - } - - /** - * @param string $locale - * @return bool - */ - public function hasLocale(string $locale): bool - { - return isset($this->locales[$locale]); - } - - /** - * @param string[] $locales - */ - public function setLocales(array $locales) - { - $this->locales = $locales; - } -} diff --git a/src/Middleware/LegacyMiddleware.php b/src/Middleware/LegacyMiddleware.php index 7adcc88d..27a15faa 100644 --- a/src/Middleware/LegacyMiddleware.php +++ b/src/Middleware/LegacyMiddleware.php @@ -3,7 +3,7 @@ namespace Engelsystem\Middleware; use Engelsystem\Helpers\Authenticator; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Psr\Container\ContainerInterface; diff --git a/src/Middleware/SetLocale.php b/src/Middleware/SetLocale.php index 86fa0b7f..568adbe6 100644 --- a/src/Middleware/SetLocale.php +++ b/src/Middleware/SetLocale.php @@ -2,7 +2,7 @@ namespace Engelsystem\Middleware; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; diff --git a/src/Renderer/Twig/Extensions/Translation.php b/src/Renderer/Twig/Extensions/Translation.php index 41619c19..3e6f30b4 100644 --- a/src/Renderer/Twig/Extensions/Translation.php +++ b/src/Renderer/Twig/Extensions/Translation.php @@ -2,7 +2,7 @@ namespace Engelsystem\Renderer\Twig\Extensions; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Twig_Extension as TwigExtension; use Twig_Extensions_TokenParser_Trans as TranslationTokenParser; use Twig_Filter as TwigFilter; diff --git a/src/helpers.php b/src/helpers.php index 111141e4..051b78a3 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -4,7 +4,7 @@ use Engelsystem\Application; use Engelsystem\Config\Config; use Engelsystem\Helpers\Authenticator; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Engelsystem\Http\UrlGeneratorInterface; diff --git a/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php b/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php new file mode 100644 index 00000000..171b5967 --- /dev/null +++ b/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php @@ -0,0 +1,84 @@ +getApp(['make', 'instance', 'get']); + /** @var Config|MockObject $config */ + $config = $this->createMock(Config::class); + /** @var Session|MockObject $session */ + $session = $this->createMock(Session::class); + /** @var Translator|MockObject $translator */ + $translator = $this->createMock(Translator::class); + + /** @var TranslationServiceProvider|MockObject $serviceProvider */ + $serviceProvider = $this->getMockBuilder(TranslationServiceProvider::class) + ->setConstructorArgs([$app]) + ->setMethods(['initGettext', 'setLocale']) + ->getMock(); + + $serviceProvider->expects($this->once()) + ->method('initGettext'); + + $app->expects($this->exactly(2)) + ->method('get') + ->withConsecutive(['config'], ['session']) + ->willReturnOnConsecutiveCalls($config, $session); + + $defaultLocale = 'fo_OO'; + $locale = 'te_ST.WTF-9'; + $locales = ['fo_OO' => 'Foo', 'fo_OO.BAR' => 'Foo (Bar)', 'te_ST.WTF-9' => 'WTF\'s Testing?']; + $config->expects($this->exactly(2)) + ->method('get') + ->withConsecutive( + ['locales'], + ['default_locale'] + ) + ->willReturnOnConsecutiveCalls( + $locales, + $defaultLocale + ); + + $session->expects($this->once()) + ->method('get') + ->with('locale', $defaultLocale) + ->willReturn($locale); + $session->expects($this->once()) + ->method('set') + ->with('locale', $locale); + + $app->expects($this->once()) + ->method('make') + ->with( + Translator::class, + [ + 'locale' => $locale, + 'locales' => $locales, + 'localeChangeCallback' => [$serviceProvider, 'setLocale'], + ] + ) + ->willReturn($translator); + + $app->expects($this->exactly(2)) + ->method('instance') + ->withConsecutive( + [Translator::class, $translator], + ['translator', $translator] + ); + + $serviceProvider->register(); + } +} diff --git a/tests/Unit/Helpers/Translation/TranslatorTest.php b/tests/Unit/Helpers/Translation/TranslatorTest.php new file mode 100644 index 00000000..7e9c534c --- /dev/null +++ b/tests/Unit/Helpers/Translation/TranslatorTest.php @@ -0,0 +1,90 @@ + 'Tests', 'fo_OO' => 'SomeFOO']; + $locale = 'te_ST.ER-01'; + + /** @var callable|MockObject $callable */ + $callable = $this->getMockBuilder(stdClass::class) + ->setMethods(['__invoke']) + ->getMock(); + $callable->expects($this->exactly(2)) + ->method('__invoke') + ->withConsecutive(['te_ST.ER-01'], ['fo_OO']); + + $translator = new Translator($locale, $locales, $callable); + + $this->assertEquals($locales, $translator->getLocales()); + $this->assertEquals($locale, $translator->getLocale()); + + $translator->setLocale('fo_OO'); + $this->assertEquals('fo_OO', $translator->getLocale()); + + $newLocales = ['lo_RM' => 'Lorem', 'ip_SU-M' => 'Ipsum']; + $translator->setLocales($newLocales); + $this->assertEquals($newLocales, $translator->getLocales()); + + $this->assertTrue($translator->hasLocale('ip_SU-M')); + $this->assertFalse($translator->hasLocale('te_ST.ER-01')); + } + + /** + * @covers \Engelsystem\Helpers\Translation\Translator::replaceText + * @covers \Engelsystem\Helpers\Translation\Translator::translate + */ + public function testTranslate() + { + /** @var Translator|MockObject $translator */ + $translator = $this->getMockBuilder(Translator::class) + ->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']]) + ->setMethods(['translateGettext']) + ->getMock(); + $translator->expects($this->exactly(2)) + ->method('translateGettext') + ->withConsecutive(['Hello!'], ['My favourite number is %u!']) + ->willReturnOnConsecutiveCalls('Hallo!', 'Meine Lieblingszahl ist die %u!'); + + $return = $translator->translate('Hello!'); + $this->assertEquals('Hallo!', $return); + + $return = $translator->translate('My favourite number is %u!', [3]); + $this->assertEquals('Meine Lieblingszahl ist die 3!', $return); + } + + /** + * @covers \Engelsystem\Helpers\Translation\Translator::translatePlural + */ + public function testTranslatePlural() + { + /** @var Translator|MockObject $translator */ + $translator = $this->getMockBuilder(Translator::class) + ->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']]) + ->setMethods(['translateGettextPlural']) + ->getMock(); + $translator->expects($this->once()) + ->method('translateGettextPlural') + ->with('%s apple', '%s apples', 2) + ->willReturn('2 Äpfel'); + + $return = $translator->translatePlural('%s apple', '%s apples', 2, [2]); + $this->assertEquals('2 Äpfel', $return); + } +} diff --git a/tests/Unit/Helpers/TranslationServiceProviderTest.php b/tests/Unit/Helpers/TranslationServiceProviderTest.php deleted file mode 100644 index 41c08aa5..00000000 --- a/tests/Unit/Helpers/TranslationServiceProviderTest.php +++ /dev/null @@ -1,84 +0,0 @@ -getApp(['make', 'instance', 'get']); - /** @var Config|MockObject $config */ - $config = $this->createMock(Config::class); - /** @var Session|MockObject $session */ - $session = $this->createMock(Session::class); - /** @var Translator|MockObject $translator */ - $translator = $this->createMock(Translator::class); - - /** @var TranslationServiceProvider|MockObject $serviceProvider */ - $serviceProvider = $this->getMockBuilder(TranslationServiceProvider::class) - ->setConstructorArgs([$app]) - ->setMethods(['initGettext', 'setLocale']) - ->getMock(); - - $serviceProvider->expects($this->once()) - ->method('initGettext'); - - $app->expects($this->exactly(2)) - ->method('get') - ->withConsecutive(['config'], ['session']) - ->willReturnOnConsecutiveCalls($config, $session); - - $defaultLocale = 'fo_OO'; - $locale = 'te_ST.WTF-9'; - $locales = ['fo_OO' => 'Foo', 'fo_OO.BAR' => 'Foo (Bar)', 'te_ST.WTF-9' => 'WTF\'s Testing?']; - $config->expects($this->exactly(2)) - ->method('get') - ->withConsecutive( - ['locales'], - ['default_locale'] - ) - ->willReturnOnConsecutiveCalls( - $locales, - $defaultLocale - ); - - $session->expects($this->once()) - ->method('get') - ->with('locale', $defaultLocale) - ->willReturn($locale); - $session->expects($this->once()) - ->method('set') - ->with('locale', $locale); - - $app->expects($this->once()) - ->method('make') - ->with( - Translator::class, - [ - 'locale' => $locale, - 'locales' => $locales, - 'localeChangeCallback' => [$serviceProvider, 'setLocale'], - ] - ) - ->willReturn($translator); - - $app->expects($this->exactly(2)) - ->method('instance') - ->withConsecutive( - [Translator::class, $translator], - ['translator', $translator] - ); - - $serviceProvider->register(); - } -} diff --git a/tests/Unit/Helpers/TranslatorTest.php b/tests/Unit/Helpers/TranslatorTest.php deleted file mode 100644 index 45ca769b..00000000 --- a/tests/Unit/Helpers/TranslatorTest.php +++ /dev/null @@ -1,90 +0,0 @@ - 'Tests', 'fo_OO' => 'SomeFOO']; - $locale = 'te_ST.ER-01'; - - /** @var callable|MockObject $callable */ - $callable = $this->getMockBuilder(stdClass::class) - ->setMethods(['__invoke']) - ->getMock(); - $callable->expects($this->exactly(2)) - ->method('__invoke') - ->withConsecutive(['te_ST.ER-01'], ['fo_OO']); - - $translator = new Translator($locale, $locales, $callable); - - $this->assertEquals($locales, $translator->getLocales()); - $this->assertEquals($locale, $translator->getLocale()); - - $translator->setLocale('fo_OO'); - $this->assertEquals('fo_OO', $translator->getLocale()); - - $newLocales = ['lo_RM' => 'Lorem', 'ip_SU-M' => 'Ipsum']; - $translator->setLocales($newLocales); - $this->assertEquals($newLocales, $translator->getLocales()); - - $this->assertTrue($translator->hasLocale('ip_SU-M')); - $this->assertFalse($translator->hasLocale('te_ST.ER-01')); - } - - /** - * @covers \Engelsystem\Helpers\Translator::replaceText - * @covers \Engelsystem\Helpers\Translator::translate - */ - public function testTranslate() - { - /** @var Translator|MockObject $translator */ - $translator = $this->getMockBuilder(Translator::class) - ->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']]) - ->setMethods(['translateGettext']) - ->getMock(); - $translator->expects($this->exactly(2)) - ->method('translateGettext') - ->withConsecutive(['Hello!'], ['My favourite number is %u!']) - ->willReturnOnConsecutiveCalls('Hallo!', 'Meine Lieblingszahl ist die %u!'); - - $return = $translator->translate('Hello!'); - $this->assertEquals('Hallo!', $return); - - $return = $translator->translate('My favourite number is %u!', [3]); - $this->assertEquals('Meine Lieblingszahl ist die 3!', $return); - } - - /** - * @covers \Engelsystem\Helpers\Translator::translatePlural - */ - public function testTranslatePlural() - { - /** @var Translator|MockObject $translator */ - $translator = $this->getMockBuilder(Translator::class) - ->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']]) - ->setMethods(['translateGettextPlural']) - ->getMock(); - $translator->expects($this->once()) - ->method('translateGettextPlural') - ->with('%s apple', '%s apples', 2) - ->willReturn('2 Äpfel'); - - $return = $translator->translatePlural('%s apple', '%s apples', 2, [2]); - $this->assertEquals('2 Äpfel', $return); - } -} diff --git a/tests/Unit/HelpersTest.php b/tests/Unit/HelpersTest.php index ad677cb3..09362a90 100644 --- a/tests/Unit/HelpersTest.php +++ b/tests/Unit/HelpersTest.php @@ -6,7 +6,7 @@ use Engelsystem\Application; use Engelsystem\Config\Config; use Engelsystem\Container\Container; use Engelsystem\Helpers\Authenticator; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Engelsystem\Http\UrlGeneratorInterface; diff --git a/tests/Unit/Middleware/LegacyMiddlewareTest.php b/tests/Unit/Middleware/LegacyMiddlewareTest.php index f14a38ed..cce7371a 100644 --- a/tests/Unit/Middleware/LegacyMiddlewareTest.php +++ b/tests/Unit/Middleware/LegacyMiddlewareTest.php @@ -3,7 +3,7 @@ namespace Engelsystem\Test\Unit\Middleware; use Engelsystem\Helpers\Authenticator; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Http\Request; use Engelsystem\Middleware\LegacyMiddleware; use PHPUnit\Framework\MockObject\MockObject; diff --git a/tests/Unit/Middleware/SetLocaleTest.php b/tests/Unit/Middleware/SetLocaleTest.php index dc68d83a..a586f6b7 100644 --- a/tests/Unit/Middleware/SetLocaleTest.php +++ b/tests/Unit/Middleware/SetLocaleTest.php @@ -2,7 +2,7 @@ namespace Engelsystem\Test\Unit\Middleware; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Middleware\SetLocale; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; diff --git a/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php b/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php index 18705683..0b055c44 100644 --- a/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php +++ b/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php @@ -2,7 +2,7 @@ namespace Engelsystem\Test\Unit\Renderer\Twig\Extensions; -use Engelsystem\Helpers\Translator; +use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Renderer\Twig\Extensions\Translation; use PHPUnit\Framework\MockObject\MockObject; use Twig_Extensions_TokenParser_Trans as TranslationTokenParser; -- cgit v1.2.3-54-g00ecf From 7414f9b23dbcc66e5f0efda3d0cbfd79372ec780 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 9 Jul 2019 21:43:18 +0200 Subject: Implemented Validation for controllers --- config/app.php | 1 + src/Controllers/BaseController.php | 4 + src/Http/Exceptions/ValidationException.php | 37 +++ src/Http/Validation/Validates.php | 154 +++++++++++ src/Http/Validation/ValidatesRequest.php | 37 +++ src/Http/Validation/ValidationServiceProvider.php | 28 ++ src/Http/Validation/Validator.php | 76 +++++ src/Middleware/ErrorHandler.php | 30 ++ tests/Unit/Controllers/BaseControllerTest.php | 2 + .../Http/Exceptions/ValidationExceptionTest.php | 25 ++ .../Stub/ValidatesRequestImplementation.php | 27 ++ .../Unit/Http/Validation/ValidatesRequestTest.php | 46 +++ tests/Unit/Http/Validation/ValidatesTest.php | 308 +++++++++++++++++++++ .../Validation/ValidationServiceProviderTest.php | 34 +++ tests/Unit/Http/Validation/ValidatorTest.php | 50 ++++ tests/Unit/Middleware/ErrorHandlerTest.php | 70 ++++- 16 files changed, 927 insertions(+), 2 deletions(-) create mode 100644 src/Http/Exceptions/ValidationException.php create mode 100644 src/Http/Validation/Validates.php create mode 100644 src/Http/Validation/ValidatesRequest.php create mode 100644 src/Http/Validation/ValidationServiceProvider.php create mode 100644 src/Http/Validation/Validator.php create mode 100644 tests/Unit/Http/Exceptions/ValidationExceptionTest.php create mode 100644 tests/Unit/Http/Validation/Stub/ValidatesRequestImplementation.php create mode 100644 tests/Unit/Http/Validation/ValidatesRequestTest.php create mode 100644 tests/Unit/Http/Validation/ValidatesTest.php create mode 100644 tests/Unit/Http/Validation/ValidationServiceProviderTest.php create mode 100644 tests/Unit/Http/Validation/ValidatorTest.php (limited to 'src/Middleware') diff --git a/config/app.php b/config/app.php index 5fda67dd..c4503086 100644 --- a/config/app.php +++ b/config/app.php @@ -25,6 +25,7 @@ return [ \Engelsystem\Middleware\RouteDispatcherServiceProvider::class, \Engelsystem\Middleware\RequestHandlerServiceProvider::class, \Engelsystem\Middleware\SessionHandlerServiceProvider::class, + \Engelsystem\Http\Validation\ValidationServiceProvider::class, // Additional services \Engelsystem\Mail\MailerServiceProvider::class, diff --git a/src/Controllers/BaseController.php b/src/Controllers/BaseController.php index cbc00931..655ed759 100644 --- a/src/Controllers/BaseController.php +++ b/src/Controllers/BaseController.php @@ -2,8 +2,12 @@ namespace Engelsystem\Controllers; +use Engelsystem\Http\Validation\ValidatesRequest; + abstract class BaseController { + use ValidatesRequest; + /** @var string[]|string[][] A list of Permissions required to access the controller or certain pages */ protected $permissions = []; diff --git a/src/Http/Exceptions/ValidationException.php b/src/Http/Exceptions/ValidationException.php new file mode 100644 index 00000000..e48fb0c3 --- /dev/null +++ b/src/Http/Exceptions/ValidationException.php @@ -0,0 +1,37 @@ +validator = $validator; + parent::__construct($message, $code, $previous); + } + + /** + * @return Validator + */ + public function getValidator(): Validator + { + return $this->validator; + } +} diff --git a/src/Http/Validation/Validates.php b/src/Http/Validation/Validates.php new file mode 100644 index 00000000..2e3a1a73 --- /dev/null +++ b/src/Http/Validation/Validates.php @@ -0,0 +1,154 @@ +validateParameterCount(2, $parameters, __FUNCTION__); + $size = $this->getSize($value); + + return $size >= $parameters[0] && $size <= $parameters[1]; + } + + /** + * @param mixed $value + * @return bool + */ + public function bool($value): bool + { + return in_array($value, ['1', 1, true, '0', 0, false], true); + } + + /** + * @param mixed $value + * @param array $parameters ['1,2,3,56,7'] + * @return bool + */ + public function in($value, $parameters): bool + { + $this->validateParameterCount(1, $parameters, __FUNCTION__); + + return in_array($value, explode(',', $parameters[0])); + } + + /** + * @param mixed $value + * @return bool + */ + public function int($value): bool + { + return filter_var($value, FILTER_VALIDATE_INT) !== false; + } + + /** + * @param string $value + * @param array $parameters ['max'] + * @return bool + */ + public function max($value, $parameters): bool + { + $this->validateParameterCount(1, $parameters, __FUNCTION__); + $size = $this->getSize($value); + + return $size <= $parameters[0]; + } + + /** + * @param string $value + * @param array $parameters ['min'] + * @return bool + */ + public function min($value, $parameters) + { + $this->validateParameterCount(1, $parameters, __FUNCTION__); + $size = $this->getSize($value); + + return $size >= $parameters[0]; + } + + /** + * @param mixed $value + * @param array $parameters ['1,2,3,56,7'] + * @return bool + */ + public function notIn($value, $parameters): bool + { + $this->validateParameterCount(1, $parameters, __FUNCTION__); + + return !$this->in($value, $parameters); + } + + /** + * @param mixed $value + * @return bool + */ + public function numeric($value): bool + { + return is_numeric($value); + } + + /** + * @param mixed $value + * @return bool + */ + public function required($value): bool + { + if ( + is_null($value) + || (is_string($value) && trim($value) === '') + ) { + return false; + } + + return true; + } + + /** + * @param mixed $value + * @return int|float + */ + protected function getSize($value) + { + if (is_numeric($value)) { + return $value; + } + + return mb_strlen($value); + } + + /** + * @param int $count + * @param array $parameters + * @param string $rule + * + * @throws InvalidArgumentException + */ + protected function validateParameterCount(int $count, array $parameters, string $rule) + { + if (count($parameters) < $count) { + throw new InvalidArgumentException(sprintf( + 'The rule "%s" requires at least %d parameters', + $rule, + $count + )); + } + } +} diff --git a/src/Http/Validation/ValidatesRequest.php b/src/Http/Validation/ValidatesRequest.php new file mode 100644 index 00000000..33ff76af --- /dev/null +++ b/src/Http/Validation/ValidatesRequest.php @@ -0,0 +1,37 @@ +validator->validate( + (array)$request->getParsedBody(), + $rules + )) { + throw new ValidationException($this->validator); + } + + return $this->validator->getData(); + } + + /** + * @param Validator $validator + */ + public function setValidator(Validator $validator) + { + $this->validator = $validator; + } +} diff --git a/src/Http/Validation/ValidationServiceProvider.php b/src/Http/Validation/ValidationServiceProvider.php new file mode 100644 index 00000000..2f1c6359 --- /dev/null +++ b/src/Http/Validation/ValidationServiceProvider.php @@ -0,0 +1,28 @@ +app->make(Validates::class); + $this->app->instance(Validates::class, $validates); + + $validator = $this->app->make(Validator::class); + $this->app->instance(Validator::class, $validator); + $this->app->instance('validator', $validator); + + $this->app->afterResolving(function ($object, Application $app) { + if (!$object instanceof BaseController) { + return; + } + + $object->setValidator($app->get(Validator::class)); + }); + } +} diff --git a/src/Http/Validation/Validator.php b/src/Http/Validation/Validator.php new file mode 100644 index 00000000..a9235a5f --- /dev/null +++ b/src/Http/Validation/Validator.php @@ -0,0 +1,76 @@ +validate = $validate; + } + + /** + * @param array $data + * @param array $rules + * @return bool + */ + public function validate($data, $rules) + { + $this->errors = []; + $this->data = []; + + foreach ($rules as $key => $values) { + foreach (explode('|', $values) as $parameters) { + $parameters = explode(':', $parameters); + $rule = array_shift($parameters); + $rule = Str::camel($rule); + + if (!method_exists($this->validate, $rule)) { + throw new InvalidArgumentException('Unknown validation rule: ' . $rule); + } + + $value = isset($data[$key]) ? $data[$key] : null; + if (!$this->validate->{$rule}($value, $parameters, $data)) { + $this->errors[$key][] = implode('.', ['validation', $key, $rule]); + + continue; + } + + $this->data[$key] = $value; + } + } + + return empty($this->errors); + } + + /** + * @return array + */ + public function getData(): array + { + return $this->data; + } + + /** + * @return string[] + */ + public function getErrors(): array + { + return $this->errors; + } +} diff --git a/src/Middleware/ErrorHandler.php b/src/Middleware/ErrorHandler.php index 29b1fac1..c89edb1a 100644 --- a/src/Middleware/ErrorHandler.php +++ b/src/Middleware/ErrorHandler.php @@ -3,6 +3,8 @@ namespace Engelsystem\Middleware; use Engelsystem\Http\Exceptions\HttpException; +use Engelsystem\Http\Exceptions\ValidationException; +use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -43,6 +45,21 @@ class ErrorHandler implements MiddlewareInterface $response = $handler->handle($request); } catch (HttpException $e) { $response = $this->createResponse($e->getMessage(), $e->getStatusCode(), $e->getHeaders()); + } catch (ValidationException $e) { + $response = $this->createResponse('', 302, ['Location' => $this->getPreviousUrl($request)]); + + if ($request instanceof Request) { + $session = $request->getSession(); + $session->set( + 'errors', + array_merge_recursive( + $session->get('errors', []), + ['validation' => $e->getValidator()->getErrors()] + ) + ); + + $session->set('form-data', $request->request->all()); + } } $statusCode = $response->getStatusCode(); @@ -106,4 +123,17 @@ class ErrorHandler implements MiddlewareInterface { return response($content, $status, $headers); } + + /** + * @param ServerRequestInterface $request + * @return string + */ + protected function getPreviousUrl(ServerRequestInterface $request) + { + if ($header = $request->getHeader('referer')) { + return array_pop($header); + } + + return '/'; + } } diff --git a/tests/Unit/Controllers/BaseControllerTest.php b/tests/Unit/Controllers/BaseControllerTest.php index 738b538f..2adc9dc7 100644 --- a/tests/Unit/Controllers/BaseControllerTest.php +++ b/tests/Unit/Controllers/BaseControllerTest.php @@ -21,5 +21,7 @@ class BaseControllerTest extends TestCase 'dolor', ], ], $controller->getPermissions()); + + $this->assertTrue(method_exists($controller, 'setValidator')); } } diff --git a/tests/Unit/Http/Exceptions/ValidationExceptionTest.php b/tests/Unit/Http/Exceptions/ValidationExceptionTest.php new file mode 100644 index 00000000..c5a38b5a --- /dev/null +++ b/tests/Unit/Http/Exceptions/ValidationExceptionTest.php @@ -0,0 +1,25 @@ +createMock(Validator::class); + + $exception = new ValidationException($validator); + + $this->assertEquals($validator, $exception->getValidator()); + } +} diff --git a/tests/Unit/Http/Validation/Stub/ValidatesRequestImplementation.php b/tests/Unit/Http/Validation/Stub/ValidatesRequestImplementation.php new file mode 100644 index 00000000..772b1dc9 --- /dev/null +++ b/tests/Unit/Http/Validation/Stub/ValidatesRequestImplementation.php @@ -0,0 +1,27 @@ +validate($request, $rules); + } + + /** + * @return bool + */ + public function hasValidator() + { + return !is_null($this->validator); + } +} diff --git a/tests/Unit/Http/Validation/ValidatesRequestTest.php b/tests/Unit/Http/Validation/ValidatesRequestTest.php new file mode 100644 index 00000000..8011bd03 --- /dev/null +++ b/tests/Unit/Http/Validation/ValidatesRequestTest.php @@ -0,0 +1,46 @@ +createMock(Validator::class); + $validator->expects($this->exactly(2)) + ->method('validate') + ->withConsecutive( + [['foo' => 'bar'], ['foo' => 'required']], + [[], ['foo' => 'required']] + ) + ->willReturnOnConsecutiveCalls( + true, + false + ); + $validator->expects($this->once()) + ->method('getData') + ->willReturn(['foo' => 'bar']); + + $implementation = new ValidatesRequestImplementation(); + $implementation->setValidator($validator); + + $return = $implementation->validateData(new Request([], ['foo' => 'bar']), ['foo' => 'required']); + + $this->assertEquals(['foo' => 'bar'], $return); + + $this->expectException(ValidationException::class); + $implementation->validateData(new Request([], []), ['foo' => 'required']); + } +} diff --git a/tests/Unit/Http/Validation/ValidatesTest.php b/tests/Unit/Http/Validation/ValidatesTest.php new file mode 100644 index 00000000..5cf0447a --- /dev/null +++ b/tests/Unit/Http/Validation/ValidatesTest.php @@ -0,0 +1,308 @@ +assertTrue($val->accepted($value) === $result); + } + + /** + * @return array + */ + public function provideBetween() + { + return [ + ['42', [10, 100]], + [42.5, [42, 43]], + [42, [42, 1000]], + [1337, [0, 99], false], + [-17, [32, 45], false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::between + * @param mixed $value + * @param array $parameters + * @param bool $result + * @dataProvider provideBetween + */ + public function testBetween($value, array $parameters, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->between($value, $parameters) === $result); + } + + /** + * @return array + */ + public function provideBool() + { + return [ + ['1'], + [1], + [true], + ['0'], + [0], + [false], + ['true', false], + ['false', false], + ['yes', false], + ['no', false], + ['bool', false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::bool + * @param mixed $value + * @param bool $result + * @dataProvider provideBool + */ + public function testBool($value, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->bool($value) === $result); + } + + /** + * @return array + */ + public function provideIn() + { + return [ + ['lorem', ['lorem,ipsum,dolor']], + [99, ['66,77,88,99,111']], + [4, ['1,3,5,7'], false], + ['toggle', ['on,off'], false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::in + * @param mixed $value + * @param array $parameters + * @param bool $result + * @dataProvider provideIn + */ + public function testIn($value, array $parameters, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->in($value, $parameters) === $result); + } + + /** + * @return array + */ + public function provideInt() + { + return [ + ['1337'], + [42], + ['0'], + [false, false], + ['12asd1', false], + ['one', false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::int + * @param mixed $value + * @param bool $result + * @dataProvider provideInt + */ + public function testInt($value, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->int($value) === $result); + } + + /** + * @return array + */ + public function provideMax() + { + return [ + ['99', [100]], + [-42, [1024]], + [99, [99]], + [100, [10], false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::max + * @param mixed $value + * @param array $parameters + * @param bool $result + * @dataProvider provideMax + */ + public function testMax($value, array $parameters, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->max($value, $parameters) === $result); + } + + /** + * @return array + */ + public function provideMin() + { + return [ + [32, [0]], + [7, [7]], + ['99', [10]], + [3, [42], false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::min + * @param mixed $value + * @param array $parameters + * @param bool $result + * @dataProvider provideMin + */ + public function testMin($value, array $parameters, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->min($value, $parameters) === $result); + } + + /** + * @return array + */ + public function provideNotIn() + { + return [ + [77, ['50,60,70']], + ['test', ['coding,deployment']], + ['PHP', ['Java,PHP,bash'], false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::notIn + * @param mixed $value + * @param array $parameters + * @param bool $result + * @dataProvider provideNotIn + */ + public function testNotIn($value, array $parameters, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->notIn($value, $parameters) === $result); + } + + /** + * @return array + */ + public function provideNumeric() + { + return [ + [77], + ['42'], + ['1337e0'], + ['123f00', false], + [null, false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::numeric + * @param mixed $value + * @param bool $result + * @dataProvider provideNumeric + */ + public function testNumeric($value, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->numeric($value) === $result); + } + + /** + * @return array + */ + public function provideRequired() + { + return [ + ['Lorem ipsum'], + ['1234'], + [1234], + ['0'], + [0], + ['', false], + [' ', false], + [null, false], + ]; + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::required + * @param mixed $value + * @param bool $result + * @dataProvider provideRequired + */ + public function testRequired($value, bool $result = true) + { + $val = new Validates; + $this->assertTrue($val->required($value) === $result); + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::getSize + */ + public function testGetSize() + { + $val = new Validates; + $this->assertTrue($val->max(42, [999])); + $this->assertTrue($val->max('99', [100])); + $this->assertFalse($val->max('101', [100])); + $this->assertTrue($val->max('lorem', [5])); + $this->assertFalse($val->max('Lorem Ipsum', [5])); + } + + /** + * @covers \Engelsystem\Http\Validation\Validates::validateParameterCount + */ + public function testValidateParameterCount() + { + $val = new Validates; + $this->assertTrue($val->between(42, [1, 100])); + + $this->expectException(InvalidArgumentException::class); + $val->between(42, [1]); + } +} diff --git a/tests/Unit/Http/Validation/ValidationServiceProviderTest.php b/tests/Unit/Http/Validation/ValidationServiceProviderTest.php new file mode 100644 index 00000000..969f4351 --- /dev/null +++ b/tests/Unit/Http/Validation/ValidationServiceProviderTest.php @@ -0,0 +1,34 @@ +register(); + + $this->assertTrue($app->has(Validator::class)); + $this->assertTrue($app->has('validator')); + + /** @var ValidatesRequestImplementation $validatesRequest */ + $validatesRequest = $app->make(ValidatesRequestImplementation::class); + $this->assertTrue($validatesRequest->hasValidator()); + + // Test afterResolving early return + $app->make(stdClass::class); + } +} diff --git a/tests/Unit/Http/Validation/ValidatorTest.php b/tests/Unit/Http/Validation/ValidatorTest.php new file mode 100644 index 00000000..799265ec --- /dev/null +++ b/tests/Unit/Http/Validation/ValidatorTest.php @@ -0,0 +1,50 @@ +assertTrue($val->validate( + ['foo' => 'bar', 'lorem' => 'on'], + ['foo' => 'required|not_in:lorem,ipsum,dolor', 'lorem' => 'accepted'] + )); + $this->assertEquals(['foo' => 'bar', 'lorem' => 'on'], $val->getData()); + + $this->assertFalse($val->validate( + [], + ['lorem' => 'required|min:3'] + )); + $this->assertEquals( + ['lorem' => ['validation.lorem.required', 'validation.lorem.min']], + $val->getErrors() + ); + } + + /** + * @covers \Engelsystem\Http\Validation\Validator::validate + */ + public function testValidateNotImplemented() + { + $val = new Validator(new Validates); + $this->expectException(InvalidArgumentException::class); + + $val->validate( + ['lorem' => 'bar'], + ['foo' => 'never_implemented'] + ); + } +} diff --git a/tests/Unit/Middleware/ErrorHandlerTest.php b/tests/Unit/Middleware/ErrorHandlerTest.php index 6c37b651..ea9cb216 100644 --- a/tests/Unit/Middleware/ErrorHandlerTest.php +++ b/tests/Unit/Middleware/ErrorHandlerTest.php @@ -2,14 +2,23 @@ namespace Engelsystem\Test\Unit\Middleware; +use Engelsystem\Application; use Engelsystem\Http\Exceptions\HttpException; +use Engelsystem\Http\Exceptions\ValidationException; +use Engelsystem\Http\Psr7ServiceProvider; +use Engelsystem\Http\Request; use Engelsystem\Http\Response; +use Engelsystem\Http\ResponseServiceProvider; +use Engelsystem\Http\Validation\Validator; use Engelsystem\Middleware\ErrorHandler; use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddlewareHandler; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Twig_LoaderInterface as TwigLoader; class ErrorHandlerTest extends TestCase @@ -104,7 +113,7 @@ class ErrorHandlerTest extends TestCase /** * @covers \Engelsystem\Middleware\ErrorHandler::process */ - public function testProcessException() + public function testProcessHttpException() { /** @var ServerRequestInterface|MockObject $request */ $request = $this->createMock(ServerRequestInterface::class); @@ -144,6 +153,63 @@ class ErrorHandlerTest extends TestCase $this->assertEquals($psrResponse, $return); } + /** + * @covers \Engelsystem\Middleware\ErrorHandler::process + * @covers \Engelsystem\Middleware\ErrorHandler::getPreviousUrl + */ + public function testProcessValidationException() + { + /** @var TwigLoader|MockObject $twigLoader */ + $twigLoader = $this->createMock(TwigLoader::class); + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + $validator = $this->createMock(Validator::class); + + $handler->expects($this->exactly(2)) + ->method('handle') + ->willReturnCallback(function () use ($validator) { + throw new ValidationException($validator); + }); + + $validator->expects($this->exactly(2)) + ->method('getErrors') + ->willReturn(['foo' => ['validation.foo.numeric']]); + + $session = new Session(new MockArraySessionStorage()); + $session->set('errors', ['validation' => ['foo' => ['validation.foo.required']]]); + $request = Request::create('/foo/bar', 'POST', ['foo' => 'bar']); + $request->setSession($session); + + /** @var Application $app */ + $app = app(); + (new ResponseServiceProvider($app))->register(); + (new Psr7ServiceProvider($app))->register(); + + $errorHandler = new ErrorHandler($twigLoader); + + $return = $errorHandler->process($request, $handler); + + $this->assertEquals(302, $return->getStatusCode()); + $this->assertEquals('/', $return->getHeaderLine('location')); + $this->assertEquals([ + 'errors' => [ + 'validation' => [ + 'foo' => [ + 'validation.foo.required', + 'validation.foo.numeric', + ], + ], + ], + 'form-data' => [ + 'foo' => 'bar', + ], + ], $session->all()); + + $request = $request->withAddedHeader('referer', '/foo/batz'); + $return = $errorHandler->process($request, $handler); + + $this->assertEquals('/foo/batz', $return->getHeaderLine('location')); + } + /** * @covers \Engelsystem\Middleware\ErrorHandler::process */ @@ -153,7 +219,7 @@ class ErrorHandlerTest extends TestCase $request = $this->createMock(ServerRequestInterface::class); /** @var TwigLoader|MockObject $twigLoader */ $twigLoader = $this->createMock(TwigLoader::class); - $response = new Response('

Hi!

', 500); + $response = new Response('

Hi!

', 500); $returnResponseHandler = new ReturnResponseMiddlewareHandler($response); /** @var ErrorHandler|MockObject $errorHandler */ -- cgit v1.2.3-54-g00ecf From 51a3c6eb44a5dbdf9d7a3cfac678f0d29b0d3eef Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Sun, 21 Jul 2019 13:24:47 +0200 Subject: ErrorHandler: Remove some form fields before serialization --- src/Middleware/ErrorHandler.php | 13 ++++++++++++- tests/Unit/Middleware/ErrorHandlerTest.php | 6 +++++- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/Middleware') diff --git a/src/Middleware/ErrorHandler.php b/src/Middleware/ErrorHandler.php index c89edb1a..544f35d5 100644 --- a/src/Middleware/ErrorHandler.php +++ b/src/Middleware/ErrorHandler.php @@ -6,6 +6,7 @@ use Engelsystem\Http\Exceptions\HttpException; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Request; use Engelsystem\Http\Response; +use Illuminate\Support\Arr; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; @@ -20,6 +21,16 @@ class ErrorHandler implements MiddlewareInterface /** @var string */ protected $viewPrefix = 'errors/'; + /** + * A list of inputs that are not saved from form input + * + * @var array + */ + protected $formIgnore = [ + 'password', + 'password_confirmation', + ]; + /** * @param TwigLoader $loader */ @@ -58,7 +69,7 @@ class ErrorHandler implements MiddlewareInterface ) ); - $session->set('form-data', $request->request->all()); + $session->set('form-data', Arr::except($request->request->all(), $this->formIgnore)); } } diff --git a/tests/Unit/Middleware/ErrorHandlerTest.php b/tests/Unit/Middleware/ErrorHandlerTest.php index ea9cb216..a9fdd71a 100644 --- a/tests/Unit/Middleware/ErrorHandlerTest.php +++ b/tests/Unit/Middleware/ErrorHandlerTest.php @@ -176,7 +176,11 @@ class ErrorHandlerTest extends TestCase $session = new Session(new MockArraySessionStorage()); $session->set('errors', ['validation' => ['foo' => ['validation.foo.required']]]); - $request = Request::create('/foo/bar', 'POST', ['foo' => 'bar']); + $request = Request::create( + '/foo/bar', + 'POST', + ['foo' => 'bar', 'password' => 'Test123', 'password_confirmation' => 'Test1234'] + ); $request->setSession($session); /** @var Application $app */ -- cgit v1.2.3-54-g00ecf From 3d8476efd3709806d254b1c41e26e906080e0b39 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Sun, 21 Jul 2019 13:37:35 +0200 Subject: ErrorHandler: Remove more form fields before serialization --- src/Middleware/ErrorHandler.php | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/Middleware') diff --git a/src/Middleware/ErrorHandler.php b/src/Middleware/ErrorHandler.php index 544f35d5..65e2e609 100644 --- a/src/Middleware/ErrorHandler.php +++ b/src/Middleware/ErrorHandler.php @@ -29,6 +29,12 @@ class ErrorHandler implements MiddlewareInterface protected $formIgnore = [ 'password', 'password_confirmation', + 'password2', + 'new_password', + 'new_password2', + 'new_pw', + 'new_pw2', + '_token', ]; /** -- cgit v1.2.3-54-g00ecf