diff --git a/extensions/sphinx/ActiveRecord.php b/extensions/sphinx/ActiveRecord.php index 690a59d..58325c6 100644 --- a/extensions/sphinx/ActiveRecord.php +++ b/extensions/sphinx/ActiveRecord.php @@ -11,6 +11,7 @@ use yii\base\InvalidConfigException; use yii\base\InvalidParamException; use yii\base\Model; use yii\base\ModelEvent; +use yii\base\NotSupportedException; use yii\base\UnknownMethodException; use yii\db\ActiveRelationInterface; use yii\db\Expression; @@ -92,6 +93,10 @@ class ActiveRecord extends Model * @var array related models indexed by the relation names */ private $_related = []; + /** + * @var string snippet value for this Active Record instance. + */ + private $_snippet; /** * Returns the Sphinx connection used by this AR class. @@ -248,6 +253,90 @@ class ActiveRecord extends Model } /** + * Builds a snippet from provided data and query, using specified index settings. + * @param string|array $source is the source data to extract a snippet from. + * It could be either a single string or array of strings. + * @param string $query the full-text query to build snippets for. + * @param array $options list of options in format: optionName => optionValue + * @return string|array built snippet in case "source" is a string, list of built snippets + * in case "source" is an array. + */ + public static function callSnippets($source, $query, $options = []) + { + $command = static::getDb()->createCommand(); + $command->callSnippets(static::indexName(), $source, $query, $options); + if (is_array($source)) { + return $command->queryColumn(); + } else { + return $command->queryScalar(); + } + } + + /** + * Returns tokenized and normalized forms of the keywords, and, optionally, keyword statistics. + * @param string $text the text to break down to keywords. + * @param boolean $fetchStatistic whether to return document and hit occurrence statistics + * @return array keywords and statistics + */ + public static function callKeywords($text, $fetchStatistic = false) + { + $command = static::getDb()->createCommand(); + $command->callKeywords(static::indexName(), $text, $fetchStatistic); + return $command->queryAll(); + } + + /** + * @param string $snippet + */ + public function setSnippet($snippet) + { + $this->_snippet = $snippet; + } + + /** + * @param string $query snippet source query + * @param array $options list of options in format: optionName => optionValue + * @return string snippet value + */ + public function getSnippet($query = null, $options = []) + { + if ($query !== null) { + $this->_snippet = $this->fetchSnippet($query, $options); + } + return $this->_snippet; + } + + /** + * Builds up the snippet value from the given query. + * @param string $query the full-text query to build snippets for. + * @param array $options list of options in format: optionName => optionValue + * @return string snippet value. + */ + protected function fetchSnippet($query, $options = []) + { + return static::callSnippets($this->getSnippetSource(), $query, $options); + } + + /** + * Returns the string, which should be used as a source to create snippet for this + * Active Record instance. + * Child classes must implement this method to return the actual snippet source text. + * For example: + * ```php + * public function getSnippetSource() + * { + * return $this->snippetSourceRelation->content; + * } + * ``` + * @return string snippet source string. + * @throws \yii\base\NotSupportedException if this is not supported by the Active Record class + */ + public function getSnippetSource() + { + throw new NotSupportedException($this->className() . ' does not provide snippet source.'); + } + + /** * Returns the name of the column that stores the lock version for implementing optimistic locking. * * Optimistic locking allows multiple users to access the same record for edits and avoids @@ -1137,7 +1226,7 @@ class ActiveRecord extends Model */ public function offsetSet($offset, $item) { - // Bypass relation owner restriction to 'yii\db\ActiveRecord' at [[ActiveRelationTrait::findWith()]]: + // Bypass relation owner restriction to 'yii\db\ActiveRecord' at [[yii\db\ActiveRelationTrait::findWith()]]: try { $relation = $this->getRelation($offset); if (is_object($relation)) { diff --git a/tests/unit/extensions/sphinx/ActiveRecordTest.php b/tests/unit/extensions/sphinx/ActiveRecordTest.php index fe15697..815ebe8 100644 --- a/tests/unit/extensions/sphinx/ActiveRecordTest.php +++ b/tests/unit/extensions/sphinx/ActiveRecordTest.php @@ -202,4 +202,27 @@ class ActiveRecordTest extends SphinxTestCase $records = RuntimeIndex::find()->all(); $this->assertEquals(0, count($records)); } + + public function testCallSnippets() + { + $query = 'pencil'; + $source = 'Some data sentence about ' . $query; + + $snippet = ArticleIndex::callSnippets($source, $query); + $this->assertNotEmpty($snippet, 'Unable to call snippets!'); + $this->assertContains('' . $query . '', $snippet, 'Query not present in the snippet!'); + + $rows = ArticleIndex::callSnippets([$source], $query); + $this->assertNotEmpty($rows, 'Unable to call snippets!'); + $this->assertContains('' . $query . '', $rows[0], 'Query not present in the snippet!'); + } + + public function testCallKeywords() + { + $text = 'table pencil'; + $rows = ArticleIndex::callKeywords($text); + $this->assertNotEmpty($rows, 'Unable to call keywords!'); + $this->assertArrayHasKey('tokenized', $rows[0], 'No tokenized keyword!'); + $this->assertArrayHasKey('normalized', $rows[0], 'No normalized keyword!'); + } } \ No newline at end of file