Skip to content

Commit c3136a0

Browse files
committed
[String] Add WORD_STRICT mode to truncate method
1 parent 68a5704 commit c3136a0

File tree

5 files changed

+79
-4
lines changed

5 files changed

+79
-4
lines changed

UPGRADE-7.2.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,11 @@ Yaml
1717
----
1818

1919
* Deprecate parsing duplicate mapping keys whose value is `null`
20+
21+
String
22+
------
23+
24+
* `truncate` method now also accept `TruncateMode` enum instead of a boolean:
25+
* `TruncateMode::Char` is equivalent to `true` value ;
26+
* `TruncateMode::WordAfter` is equivalent to `true` value ;
27+
* `TruncateMode::Word` is a new mode that will cut the sentence on the last word before the limit is reached.

src/Symfony/Component/String/AbstractString.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ public function trimSuffix($suffix): static
605605
return $str;
606606
}
607607

608-
public function truncate(int $length, string $ellipsis = '', bool $cut = true): static
608+
public function truncate(int $length, string $ellipsis = '', bool|TruncateMode $cut = TruncateMode::Char): static
609609
{
610610
$stringLength = $this->length();
611611

@@ -619,7 +619,8 @@ public function truncate(int $length, string $ellipsis = '', bool $cut = true):
619619
$ellipsisLength = 0;
620620
}
621621

622-
if (!$cut) {
622+
$desiredLength = $length;
623+
if (TruncateMode::WordAfter === $cut || TruncateMode::WordBefore === $cut || !$cut) {
623624
if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) {
624625
return clone $this;
625626
}
@@ -629,6 +630,14 @@ public function truncate(int $length, string $ellipsis = '', bool $cut = true):
629630

630631
$str = $this->slice(0, $length - $ellipsisLength);
631632

633+
if (TruncateMode::WordBefore === $cut) {
634+
if (0 === $ellipsisLength && $desiredLength === $this->indexOf([' ', "\r", "\n", "\t"], $length)) {
635+
return $str;
636+
}
637+
638+
$str = $str->beforeLast([' ', "\r", "\n", "\t"]);
639+
}
640+
632641
return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str;
633642
}
634643

src/Symfony/Component/String/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.2
5+
---
6+
7+
* Add `TruncateMode` enum to handle more truncate methods
8+
49
7.1
510
---
611

src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\String\ByteString;
1717
use Symfony\Component\String\CodePointString;
1818
use Symfony\Component\String\Exception\InvalidArgumentException;
19+
use Symfony\Component\String\TruncateMode;
1920
use Symfony\Component\String\UnicodeString;
2021

2122
abstract class AbstractAsciiTestCase extends TestCase
@@ -1500,22 +1501,24 @@ public static function providePadStart()
15001501
/**
15011502
* @dataProvider provideTruncate
15021503
*/
1503-
public function testTruncate(string $expected, string $origin, int $length, string $ellipsis, bool $cut = true)
1504+
public function testTruncate(string $expected, string $origin, int $length, string $ellipsis, bool|TruncateMode $cut = TruncateMode::Char)
15041505
{
15051506
$instance = static::createFromString($origin)->truncate($length, $ellipsis, $cut);
15061507

15071508
$this->assertEquals(static::createFromString($expected), $instance);
15081509
}
15091510

1510-
public static function provideTruncate()
1511+
public static function provideTruncate(): array
15111512
{
15121513
return [
15131514
['', '', 3, ''],
15141515
['', 'foo', 0, '...'],
15151516
['foo', 'foo', 0, '...', false],
1517+
['foo', 'foo', 0, '...', TruncateMode::WordAfter],
15161518
['fo', 'foobar', 2, ''],
15171519
['foobar', 'foobar', 10, ''],
15181520
['foobar', 'foobar', 10, '...', false],
1521+
['foobar', 'foobar', 10, '...', TruncateMode::WordAfter],
15191522
['foo', 'foo', 3, '...'],
15201523
['fo', 'foobar', 2, '...'],
15211524
['...', 'foobar', 3, '...'],
@@ -1524,6 +1527,14 @@ public static function provideTruncate()
15241527
['foobar...', 'foobar foo', 7, '...', false],
15251528
['foobar foo...', 'foobar foo a', 10, '...', false],
15261529
['foobar foo aar', 'foobar foo aar', 12, '...', false],
1530+
['foobar...', 'foobar foo', 6, '...', TruncateMode::WordAfter],
1531+
['foobar...', 'foobar foo', 7, '...', TruncateMode::WordAfter],
1532+
['foobar foo...', 'foobar foo a', 10, '...', TruncateMode::WordAfter],
1533+
['foobar foo aar', 'foobar foo aar', 12, '...', TruncateMode::WordAfter],
1534+
['foobar foo', 'foobar foo aar', 10, '', TruncateMode::WordBefore],
1535+
['foobar...', 'foobar foo aar', 10, '...', TruncateMode::WordBefore],
1536+
['Lorem ipsum', 'Lorem ipsum dolor sit amet', 14, '', TruncateMode::WordBefore],
1537+
['Lorem...', 'Lorem ipsum dolor sit amet', 10, '...', TruncateMode::WordBefore],
15271538
];
15281539
}
15291540

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\String;
13+
14+
enum TruncateMode
15+
{
16+
/**
17+
* Will cut exactly at given length.
18+
*
19+
* Length: 14
20+
* Source: Lorem ipsum dolor sit amet
21+
* Output: Lorem ipsum do
22+
*/
23+
case Char;
24+
25+
/**
26+
* Returns the string up to the last complete word containing the specified length.
27+
*
28+
* Length: 14
29+
* Source: Lorem ipsum dolor sit amet
30+
* Output: Lorem ipsum
31+
*/
32+
case WordBefore;
33+
34+
/**
35+
* Returns the string up to the complete word after or at the given length.
36+
*
37+
* Length: 14
38+
* Source: Lorem ipsum dolor sit amet
39+
* Output: Lorem ipsum dolor
40+
*/
41+
case WordAfter;
42+
}

0 commit comments

Comments
 (0)