/model/fieldtypes/Text.php
PHP | 353 lines | 178 code | 55 blank | 120 comment | 54 complexity | 1979f92f08a9e8e7019c64426e2838e6 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1
- <?php
- /**
- * Represents a variable-length string of up to 2 megabytes, designed to store raw text
- *
- * Example definition via {@link DataObject::$db}:
- * <code>
- * static $db = array(
- * "MyDescription" => "Text",
- * );
- * </code>
- *
- * @see HTMLText
- * @see HTMLVarchar
- * @see Varchar
- *
- * @package sapphire
- * @subpackage model
- */
- class Text extends StringField {
- static $casting = array(
- "AbsoluteLinks" => "Text",
- "BigSummary" => "Text",
- "ContextSummary" => "Text",
- "FirstParagraph" => "Text",
- "FirstSentence" => "Text",
- "LimitCharacters" => "Text",
- "LimitSentences" => "Text",
- "Summary" => "Text",
- 'EscapeXML' => 'Text',
- 'LimitWordCount' => 'Text',
- 'LimitWordCountXML' => 'HTMLText',
- 'NoHTML' => 'Text',
- );
-
- /**
- * (non-PHPdoc)
- * @see DBField::requireField()
- */
- function requireField() {
- $parts=Array('datatype'=>'mediumtext', 'character set'=>'utf8', 'collate'=>'utf8_general_ci', 'arrayValue'=>$this->arrayValue);
- $values=Array('type'=>'text', 'parts'=>$parts);
- DB::requireField($this->tableName, $this->name, $values, $this->default);
- }
-
- /**
- * Limit this field's content by a number of words.
- * CAUTION: This is not XML safe. Please use
- * {@link LimitWordCountXML()} instead.
- *
- * @param int $numWords Number of words to limit by
- * @param string $add Ellipsis to add to the end of truncated string
- * @return string
- */
- function LimitWordCount($numWords = 26, $add = '...') {
- $this->value = trim(Convert::xml2raw($this->value));
- $ret = explode(' ', $this->value, $numWords + 1);
-
- if(count($ret) <= $numWords - 1) {
- $ret = $this->value;
- } else {
- array_pop($ret);
- $ret = implode(' ', $ret) . $add;
- }
-
- return $ret;
- }
-
- /**
- * Return the value of the field stripped of html tags
- * @return string
- */
- function NoHTML() {
- return strip_tags($this->value);
- }
- /**
- * Return the value of the field with XML tags escaped.
- *
- * @deprecated 3.0 Use DBField->XML() instead.
- * @return string
- */
- function EscapeXML() {
- Deprecation::notice('3.0', 'Use DBField->XML() instead.');
- return str_replace(array('&','<','>','"'), array('&','<','>','"'), $this->value);
- }
-
- /**
- * Return the value of the field with relative links converted to absolute urls.
- * @return string
- */
- function AbsoluteLinks() {
- return HTTP::absoluteURLs($this->value);
- }
-
- /**
- * Limit the number of words of the current field's
- * content. This is XML safe, so characters like &
- * are converted to &
- *
- * @param int $numWords Number of words to limit by
- * @param string $add Ellipsis to add to the end of truncated string
- * @return string
- */
- function LimitWordCountXML($numWords = 26, $add = '...') {
- $ret = $this->LimitWordCount($numWords, $add);
- return Convert::raw2xml($ret);
- }
- /**
- * Limit sentences, can be controlled by passing an integer.
- * @param int $sentCount The amount of sentences you want.
- */
- function LimitSentences($sentCount = 2) {
- if(!is_numeric($sentCount)) user_error("Text::LimitSentence() expects one numeric argument", E_USER_NOTICE);
-
- $output = array();
- $data = trim(Convert::xml2raw($this->value));
- $sentences = explode('.', $data);
- if ($sentCount == 0) return '';
- for($i = 0; $i < $sentCount; $i++) {
- if(isset($sentences[$i])) {
- $sentence = trim($sentences[$i]);
- if(!empty($sentence)) $output[] .= $sentence;
- }
- }
- return count($output)==0 ? '' : implode($output, '. ') . '.';
- }
-
-
- /**
- * Caution: Not XML/HTML-safe - does not respect closing tags.
- */
- function FirstSentence() {
- $data = Convert::xml2raw( $this->value );
- if( !$data ) return "";
-
-
- $sentences = explode( '.', $data );
-
- if( count( $sentences ) )
- return $sentences[0] . '.';
- else
- return $this->Summary(20);
- }
- /**
- * Caution: Not XML/HTML-safe - does not respect closing tags.
- */
- function Summary($maxWords = 50) {
- // get first sentence?
- // this needs to be more robust
- $value = Convert::xml2raw( $this->value /*, true*/ );
- if(!$value) return '';
-
- // grab the first paragraph, or, failing that, the whole content
- if(strpos($value, "\n\n")) $value = substr($value, 0, strpos($value, "\n\n"));
- $sentences = explode('.', $value);
- $count = count(explode(' ', $sentences[0]));
-
- // if the first sentence is too long, show only the first $maxWords words
- if($count > $maxWords) {
- return implode( ' ', array_slice(explode( ' ', $sentences[0] ), 0, $maxWords)) . '...';
- }
- // add each sentence while there are enough words to do so
- $result = '';
- do {
- $result .= trim(array_shift( $sentences )).'.';
- if(count($sentences) > 0) {
- $count += count(explode(' ', $sentences[0]));
- }
-
- // Ensure that we don't trim half way through a tag or a link
- $brokenLink = (
- substr_count($result,'<') != substr_count($result,'>')) ||
- (substr_count($result,'<a') != substr_count($result,'</a')
- );
- } while(($count < $maxWords || $brokenLink) && $sentences && trim( $sentences[0]));
-
- if(preg_match('/<a[^>]*>/', $result) && !preg_match( '/<\/a>/', $result)) $result .= '</a>';
-
- return Convert::raw2xml($result);
- }
-
- /**
- * Performs the same function as the big summary, but doesnt trim new paragraphs off data.
- * Caution: Not XML/HTML-safe - does not respect closing tags.
- */
- function BigSummary($maxWords = 50, $plain = 1) {
- $result = "";
-
- // get first sentence?
- // this needs to be more robust
- if($plain) $data = Convert::xml2raw($this->value, true);
-
- if(!$data) return "";
-
- $sentences = explode('.', $data);
- $count = count(explode(' ', $sentences[0]));
-
- // if the first sentence is too long, show only the first $maxWords words
- if($count > $maxWords) {
- return implode(' ', array_slice(explode( ' ', $sentences[0] ), 0, $maxWords)) . '...';
- }
- // add each sentence while there are enough words to do so
- do {
- $result .= trim(array_shift($sentences));
- if($sentences) {
- $result .= '. ';
- $count += count(explode(' ', $sentences[0]));
- }
-
- // Ensure that we don't trim half way through a tag or a link
- $brokenLink = (
- substr_count($result,'<') != substr_count($result,'>')) ||
- (substr_count($result,'<a') != substr_count($result,'</a')
- );
- } while(($count < $maxWords || $brokenLink) && $sentences && trim($sentences[0]));
-
- if(preg_match( '/<a[^>]*>/', $result) && !preg_match( '/<\/a>/', $result)) {
- $result .= '</a>';
- }
-
- return $result;
- }
-
- /**
- * Caution: Not XML/HTML-safe - does not respect closing tags.
- */
- function FirstParagraph($plain = 1) {
- // get first sentence?
- // this needs to be more robust
- if($plain && $plain != 'html') {
- $data = Convert::xml2raw($this->value, true);
- if(!$data) return "";
-
- // grab the first paragraph, or, failing that, the whole content
- $pos = strpos($data, "\n\n");
- if($pos) $data = substr($data, 0, $pos);
- return $data;
- } else {
- if(strpos($this->value, "</p>") === false) return $this->value;
-
- $data = substr($this->value, 0, strpos($this->value, "</p>") + 4);
- if(strlen($data) < 20 && strpos($this->value, "</p>", strlen($data))) {
- $data = substr($this->value, 0, strpos( $this->value, "</p>", strlen($data)) + 4 );
- }
-
- return $data;
- }
- }
-
- /**
- * Perform context searching to give some context to searches, optionally
- * highlighting the search term.
- *
- * @param int $characters Number of characters in the summary
- * @param boolean $string Supplied string ("keywords")
- * @param boolean $striphtml Strip HTML?
- * @param boolean $highlight Add a highlight <span> element around search query?
- * @param String prefix text
- * @param String suffix
- *
- * @return string
- */
- function ContextSummary($characters = 500, $string = false, $striphtml = true, $highlight = true, $prefix = "... ", $suffix = "...") {
- if(!$string) $string = $_REQUEST['Search']; // Use the default "Search" request variable (from SearchForm)
- // Remove HTML tags so we don't have to deal with matching tags
- $text = $striphtml ? $this->NoHTML() : $this->value;
-
- // Find the search string
- $position = (int) stripos($text, $string);
-
- // We want to search string to be in the middle of our block to give it some context
- $position = max(0, $position - ($characters / 2));
- if($position > 0) {
- // We don't want to start mid-word
- $position = max((int) strrpos(substr($text, 0, $position), ' '), (int) strrpos(substr($text, 0, $position), "\n"));
- }
- $summary = substr($text, $position, $characters);
- $stringPieces = explode(' ', $string);
-
- if($highlight) {
- // Add a span around all key words from the search term as well
- if($stringPieces) {
-
- foreach($stringPieces as $stringPiece) {
- if(strlen($stringPiece) > 2) {
- $summary = str_ireplace($stringPiece, "<span class=\"highlight\">$stringPiece</span>", $summary);
- }
- }
- }
- }
- $summary = trim($summary);
-
- if($position > 0) $summary = $prefix . $summary;
- if(strlen($this->value) > ($characters + $position)) $summary = $summary . $suffix;
-
- return $summary;
- }
-
- /**
- * Allows a sub-class of TextParser to be rendered.
- *
- * @see TextParser for implementation details.
- * @return string
- */
- function Parse($parser = "TextParser") {
- if($parser == "TextParser" || is_subclass_of($parser, "TextParser")) {
- $obj = new $parser($this->value);
- return $obj->parse();
- } else {
- // Fallback to using raw2xml and show a warning
- // TODO Don't kill script execution, we can continue without losing complete control of the app
- user_error("Couldn't find an appropriate TextParser sub-class to create (Looked for '$parser'). Make sure it sub-classes TextParser and that you've done ?flush=1.", E_USER_WARNING);
- return Convert::raw2xml($this->value);
- }
- }
-
- /**
- * (non-PHPdoc)
- * @see DBField::scaffoldFormField()
- */
- public function scaffoldFormField($title = null, $params = null) {
- if(!$this->nullifyEmpty) {
- // Allow the user to select if it's null instead of automatically assuming empty string is
- return new NullableField(new TextareaField($this->name, $title));
- } else {
- // Automatically determine null (empty string)
- return new TextareaField($this->name, $title);
- }
- }
-
- /**
- * (non-PHPdoc)
- * @see DBField::scaffoldSearchField()
- */
- public function scaffoldSearchField($title = null, $params = null) {
- return new TextField($this->name, $title);
- }
- }
- ?>