-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] CaseViewHelper for StandaloneFluid (#841)
CaseViewHelper doesn't have any dependencies to TYPO3, it can be moved to Fluid Standalone.
- Loading branch information
Showing
2 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file belongs to the package "TYPO3 Fluid". | ||
* See LICENSE.txt that was shipped with this package. | ||
*/ | ||
|
||
namespace TYPO3Fluid\Fluid\ViewHelpers\Format; | ||
|
||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; | ||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; | ||
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception; | ||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; | ||
|
||
/** | ||
* Modifies the case of an input string to upper- or lowercase or capitalization. | ||
* The default transformation will be uppercase as in `mb_convert_case`_. | ||
* | ||
* Possible modes are: | ||
* | ||
* ``lower`` | ||
* Transforms the input string to its lowercase representation | ||
* | ||
* ``upper`` | ||
* Transforms the input string to its uppercase representation | ||
* | ||
* ``capital`` | ||
* Transforms the input string to its first letter upper-cased, i.e. capitalization | ||
* | ||
* ``uncapital`` | ||
* Transforms the input string to its first letter lower-cased, i.e. uncapitalization | ||
* | ||
* ``capitalWords`` | ||
* Not supported yet: Transforms the input string to each containing word being capitalized | ||
* | ||
* Note that the behavior will be the same as in the appropriate PHP function `mb_convert_case`_; | ||
* especially regarding locale and multibyte behavior. | ||
* | ||
* .. _mb_convert_case: https://www.php.net/manual/function.mb-convert-case.php | ||
* | ||
* Examples | ||
* ======== | ||
* | ||
* Default | ||
* ------- | ||
* | ||
* :: | ||
* | ||
* <f:format.case>Some Text with miXed case</f:format.case> | ||
* | ||
* Output:: | ||
* | ||
* SOME TEXT WITH MIXED CASE | ||
* | ||
* Example with given mode | ||
* ----------------------- | ||
* | ||
* :: | ||
* | ||
* <f:format.case mode="capital">someString</f:format.case> | ||
* | ||
* Output:: | ||
* | ||
* SomeString | ||
*/ | ||
final class CaseViewHelper extends AbstractViewHelper | ||
{ | ||
use CompileWithRenderStatic; | ||
|
||
/** | ||
* Directs the input string being converted to "lowercase" | ||
*/ | ||
private const CASE_LOWER = 'lower'; | ||
|
||
/** | ||
* Directs the input string being converted to "UPPERCASE" | ||
*/ | ||
private const CASE_UPPER = 'upper'; | ||
|
||
/** | ||
* Directs the input string being converted to "Capital case" | ||
*/ | ||
private const CASE_CAPITAL = 'capital'; | ||
|
||
/** | ||
* Directs the input string being converted to "unCapital case" | ||
*/ | ||
private const CASE_UNCAPITAL = 'uncapital'; | ||
|
||
/** | ||
* Directs the input string being converted to "Capital Case For Each Word" | ||
*/ | ||
private const CASE_CAPITAL_WORDS = 'capitalWords'; | ||
|
||
/** | ||
* Output is escaped already. We must not escape children, to avoid double encoding. | ||
* | ||
* @var bool | ||
*/ | ||
protected $escapeChildren = false; | ||
|
||
public function initializeArguments(): void | ||
{ | ||
$this->registerArgument('value', 'string', 'The input value. If not given, the evaluated child nodes will be used.', false); | ||
$this->registerArgument('mode', 'string', 'The case to apply, must be one of this\' CASE_* constants. Defaults to uppercase application.', false, self::CASE_UPPER); | ||
} | ||
|
||
/** | ||
* Changes the case of the input string | ||
* @throws Exception | ||
*/ | ||
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext): string | ||
{ | ||
$value = $arguments['value']; | ||
$mode = $arguments['mode']; | ||
|
||
if ($value === null) { | ||
$value = (string)$renderChildrenClosure(); | ||
} | ||
|
||
switch ($mode) { | ||
case self::CASE_LOWER: | ||
$output = mb_strtolower($value, 'utf-8'); | ||
break; | ||
case self::CASE_UPPER: | ||
$output = mb_strtoupper($value, 'utf-8'); | ||
break; | ||
case self::CASE_CAPITAL: | ||
$firstChar = mb_substr($value, 0, 1, 'utf-8'); | ||
$firstChar = mb_strtoupper($firstChar, 'utf-8'); | ||
$remainder = mb_substr($value, 1, null, 'utf-8'); | ||
$output = $firstChar . $remainder; | ||
break; | ||
case self::CASE_UNCAPITAL: | ||
$firstChar = mb_substr($value, 0, 1, 'utf-8'); | ||
$firstChar = mb_strtolower($firstChar, 'utf-8'); | ||
$remainder = mb_substr($value, 1, null, 'utf-8'); | ||
$output = $firstChar . $remainder; | ||
break; | ||
case self::CASE_CAPITAL_WORDS: | ||
$output = mb_convert_case($value, MB_CASE_TITLE, 'utf-8'); | ||
break; | ||
default: | ||
throw new Exception('The case mode "' . $mode . '" supplied to Fluid\'s format.case ViewHelper is not supported.', 1358349150); | ||
} | ||
|
||
return $output; | ||
} | ||
} |
96 changes: 96 additions & 0 deletions
96
tests/Functional/ViewHelpers/Format/CaseViewHelperTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file belongs to the package "TYPO3 Fluid". | ||
* See LICENSE.txt that was shipped with this package. | ||
*/ | ||
|
||
namespace TYPO3Fluid\Fluid\Tests\Functional\ViewHelpers\Format; | ||
|
||
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception; | ||
use TYPO3Fluid\Fluid\Tests\Functional\AbstractFunctionalTestCase; | ||
use TYPO3Fluid\Fluid\View\TemplateView; | ||
|
||
final class CaseViewHelperTest extends AbstractFunctionalTestCase | ||
{ | ||
public static function renderConvertsAValueDataProvider(): array | ||
{ | ||
return [ | ||
'empty value' => [ | ||
'<f:format.case value="" />', | ||
'', | ||
], | ||
'value from child, uppercase default' => [ | ||
'<f:format.case>foob4r</f:format.case>', | ||
'FOOB4R', | ||
], | ||
'simple value' => [ | ||
'<f:format.case value="foo" />', | ||
'FOO', | ||
], | ||
'mode lower' => [ | ||
'<f:format.case value="FooB4r" mode="lower" />', | ||
'foob4r', | ||
], | ||
'mode upper' => [ | ||
'<f:format.case value="FooB4r" mode="upper" />', | ||
'FOOB4R', | ||
], | ||
'mode capital' => [ | ||
'<f:format.case value="foo bar" mode="capital" />', | ||
'Foo bar', | ||
], | ||
'mode uncapital' => [ | ||
'<f:format.case value="FOO Bar" mode="uncapital" />', | ||
'fOO Bar', | ||
], | ||
'special chars 1' => [ | ||
'<f:format.case value="smørrebrød" mode="upper" />', | ||
'SMØRREBRØD', | ||
], | ||
'special chars 2' => [ | ||
'<f:format.case value="smørrebrød" mode="capital" />', | ||
'Smørrebrød', | ||
], | ||
'special chars 3' => [ | ||
'<f:format.case value="römtömtömtöm" mode="upper" />', | ||
'RÖMTÖMTÖMTÖM', | ||
], | ||
'special chars 4' => [ | ||
'<f:format.case value="Ἕλλάς α ω" mode="upper" />', | ||
'ἝΛΛΆΣ Α Ω', | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* @test | ||
* @dataProvider renderConvertsAValueDataProvider | ||
*/ | ||
public function renderConvertsAValue(string $template, string $expected): void | ||
{ | ||
$view = new TemplateView(); | ||
$view->getRenderingContext()->setCache(self::$cache); | ||
$view->getRenderingContext()->getTemplatePaths()->setTemplateSource($template); | ||
self::assertSame($expected, $view->render()); | ||
|
||
$view = new TemplateView(); | ||
$view->getRenderingContext()->setCache(self::$cache); | ||
$view->getRenderingContext()->getTemplatePaths()->setTemplateSource($template); | ||
self::assertSame($expected, $view->render()); | ||
} | ||
|
||
/** | ||
* @test | ||
*/ | ||
public function viewHelperThrowsExceptionIfIncorrectModeIsGiven(): void | ||
{ | ||
$this->expectException(Exception::class); | ||
$this->expectExceptionCode(1358349150); | ||
$view = new TemplateView(); | ||
$view->getRenderingContext()->getTemplatePaths()->setTemplateSource('<f:format.case value="foo" mode="invalid" />'); | ||
$view->render(); | ||
} | ||
} |