BUGFIX Better handling of multibyte strings in LimitCharacters(), removed code duplication by more flexible base implementation at StringField->LimitCharacters() (Merge pull request #121 from edlund/sapphire)

This commit is contained in:
Ingo Schommer 2011-12-17 00:27:14 +01:00
parent dd495fb8bf
commit 0c3af80514
6 changed files with 61 additions and 63 deletions

View File

@ -13,30 +13,6 @@
class HTMLText extends Text {
public static $escape_type = 'xml';
/**
* Limit this field's content by a number of characters.
* This makes use of strip_tags() to avoid malforming the
* HTML tags in the string of text.
*
* @param int $limit Number of characters to limit by
* @param string $add Ellipsis to add to the end of truncated string
* @return string
*/
function LimitCharacters($limit = 20, $add = "...") {
$value = trim(strip_tags($this->value));
// Content html text to plan text before sub string-ing
// to cutting off part of the html entity character
// For example, & because &am
$value = html_entity_decode($value, ENT_COMPAT, 'UTF-8');
$value = (strlen($value) > $limit) ? substr($value, 0, $limit) . $add : $value;
// Convert plan text back to html entities
$value = htmlentities($value, ENT_COMPAT, 'UTF-8');
return $value;
}
/**
* Create a summary of the content. This will be some section of the first paragraph, limited by
@ -147,4 +123,4 @@ class HTMLText extends Text {
}
?>
?>

View File

@ -25,7 +25,5 @@ class HTMLVarchar extends Varchar {
public function scaffoldSearchField($title = null) {
return new TextField($this->name, $title);
}
}
?>
}

View File

@ -73,20 +73,42 @@ abstract class StringField extends DBField {
return parent::prepValueForDB($value);
}
}
/**
* Limit this field's content by a number of characters.
* This makes use of strip_tags() to avoid malforming the
* HTML tags in the string of text.
*
* @param int $limit Number of characters to limit by
* @param string $add Ellipsis to add to the end of truncated string
* @return string
*/
function LimitCharacters($limit, $add = '...') {
$value = trim($this->value);
if($this->stat('escape_type') == 'xml') {
$value = strip_tags($value);
$value = html_entity_decode($value, ENT_COMPAT, 'UTF-8');
$value = (mb_strlen($value) > $limit) ? mb_substr($value, 0, $limit) . $add : $value;
// Avoid encoding all multibyte characters as HTML entities by using htmlspecialchars().
$value = htmlspecialchars($value, ENT_COMPAT, 'UTF-8');
} else {
$value = (mb_strlen($value) > $limit) ? mb_substr($value, 0, $limit) . $add : $value;
}
return $value;
}
/**
* Return another DBField object with this value in lowercase.
*/
function Lower() {
return DBField::create(get_class($this), strtolower($this->value), $this->name);
return DBField::create(get_class($this), mb_strtolower($this->value), $this->name);
}
/**
* Return another DBField object with this value in uppercase.
*/
function Upper() {
return DBField::create(get_class($this), strtoupper($this->value), $this->name);
return DBField::create(get_class($this), mb_strtoupper($this->value), $this->name);
}
}

View File

@ -77,20 +77,6 @@ class Text extends StringField {
return HTTP::absoluteURLs($this->value);
}
/**
* Limit this field's content by a number of characters.
* CAUTION: Does not take into account HTML tags, so it
* has the potential to return malformed HTML.
*
* @param int $limit Number of characters to limit by
* @param string $add Ellipsis to add to the end of truncated string
* @return string
*/
function LimitCharacters($limit = 20, $add = "...") {
$value = trim($this->value);
return (strlen($value) > $limit) ? substr($value, 0, $limit) . $add : $value;
}
/**
* Limit the number of words of the current field's
* content. This is XML safe, so characters like &
@ -159,9 +145,10 @@ class Text extends StringField {
return "";
// grab the first paragraph, or, failing that, the whole content
if( strpos( $data, "\n\n" ) )
$data = substr( $data, 0, strpos( $data, "\n\n" ) );
$pos = strpos( $data, "\n\n" );
if( $pos )
$data = substr( $data, 0, $pos );
$sentences = explode( '.', $data );
$count = count( explode( ' ', $sentences[0] ) );
@ -241,8 +228,9 @@ class Text extends StringField {
if( !$data ) return "";
// grab the first paragraph, or, failing that, the whole content
if( strpos( $data, "\n\n" ) )
$data = substr( $data, 0, strpos( $data, "\n\n" ) );
$pos = strpos( $data, "\n\n" );
if( $pos )
$data = substr( $data, 0, $pos );
return $data;

View File

@ -69,18 +69,7 @@ class Varchar extends StringField {
function RTF() {
return str_replace("\n", '\par ', $this->value);
}
/**
* Returns the value of the string, limited to the specified number of characters
* @param $limit int Character limit
* @param $add string Extra string to add to the end of the limited string
* @return string
*/
function LimitCharacters($limit = 20, $add = "...") {
$value = trim($this->value);
return (strlen($value) > $limit) ? substr($value, 0, $limit) . $add : $value;
}
/**
* (non-PHPdoc)
* @see DBField::scaffoldFormField()

View File

@ -192,6 +192,31 @@ class DBFieldTest extends SapphireTest {
$textField->setValue(null);
$this->assertFalse($textField->hasValue());
}
function testStringFieldsWithMultibyteData() {
$plainFields = array('Varchar', 'Text');
$htmlFields = array('HTMLVarchar', 'HTMLText');
$allFields = array_merge($plainFields, $htmlFields);
$value = 'üåäöÜÅÄÖ';
foreach ($allFields as $stringField) {
$stringField = DBField::create($stringField, $value);
for ($i = 1; $i < mb_strlen($value); $i++) {
$expected = mb_substr($value, 0, $i) . '...';
$this->assertEquals($expected, $stringField->LimitCharacters($i));
}
}
$value = '<p>üåäö&amp;ÜÅÄÖ</p>';
foreach ($htmlFields as $stringField) {
$stringField = DBField::create($stringField, $value);
$this->assertEquals('üåäö&amp;ÜÅÄ...', $stringField->LimitCharacters(8));
}
$this->assertEquals('ÅÄÖ', DBField::create('Text', 'åäö')->Upper()->getValue());
$this->assertEquals('åäö', DBField::create('Text', 'ÅÄÖ')->Lower()->getValue());
}
}
?>