* static $db = array( * "MyDescription" => "Text", * ); * * * @see HTMLText * @see HTMLVarchar * @see Varchar * * @package framework * @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() */ public 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 */ public 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 */ public function NoHTML() { return strip_tags($this->value); } /** * Return the value of the field with relative links converted to absolute urls. * @return string */ public 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 */ public 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. */ public 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. */ public 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. */ public 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,']*>/', $result) && !preg_match( '/<\/a>/', $result)) $result .= ''; 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. */ public 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,']*>/', $result) && !preg_match( '/<\/a>/', $result)) { $result .= ''; } return $result; } /** * Caution: Not XML/HTML-safe - does not respect closing tags. */ public 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, "

") === false) return $this->value; $data = substr($this->value, 0, strpos($this->value, "

") + 4); if(strlen($data) < 20 && strpos($this->value, "

", strlen($data))) { $data = substr($this->value, 0, strpos( $this->value, "

", 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 element around search query? * @param String prefix text * @param String suffix * * @return string */ public 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, "$stringPiece", $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 */ public 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); } }