Commit 386b58b2 by Klimov Paul

Snippet call options added to Sphinx Query.

parent 7fb4bfdd
...@@ -108,20 +108,76 @@ class Query extends Component ...@@ -108,20 +108,76 @@ class Query extends Component
* row data. For more details, see [[indexBy()]]. This property is only used by [[all()]]. * row data. For more details, see [[indexBy()]]. This property is only used by [[all()]].
*/ */
public $indexBy; public $indexBy;
/**
* @var callback PHP callback, which should be used to fetch source data for the snippets.
* Such callback will receive array of query result rows as an argument and must return the
* array of snippet source strings in the order, which match one of incoming rows.
* For example:
* ```php
* $query = new Query;
* $query->from('idx_item')
* ->match('pencil')
* ->snippetCallback(function ($rows) {
* $result = [];
* foreach ($rows as $row) {
* $result[] = file_get_contents('/path/to/index/files/' . $row['id'] . '.txt');
* }
* return $result;
* })
* ->all();
* ```
*/
public $snippetCallback;
/**
* @var array query options for the call snippet.
*/
public $snippetOptions;
/**
* @var Connection the Sphinx connection used to generate the SQL statements.
*/
private $_connection;
/**
* @param Connection $connection Sphinx connection instance
* @return static the query object itself
*/
public function setConnection($connection)
{
$this->_connection = $connection;
return $this;
}
/**
* @return Connection Sphinx connection instance
*/
public function getConnection()
{
if ($this->_connection === null) {
$this->_connection = $this->defaultConnection();
}
return $this->_connection;
}
/**
* @return Connection default connection value.
*/
protected function defaultConnection()
{
return Yii::$app->getComponent('sphinx');
}
/** /**
* Creates a Sphinx command that can be used to execute this query. * Creates a Sphinx command that can be used to execute this query.
* @param Connection $sphinxConnection the Sphinx connection used to generate the SQL statement. * @param Connection $connection the Sphinx connection used to generate the SQL statement.
* If this parameter is not given, the `sphinx` application component will be used. * If this parameter is not given, the `sphinx` application component will be used.
* @return Command the created Sphinx command instance. * @return Command the created Sphinx command instance.
*/ */
public function createCommand($sphinxConnection = null) public function createCommand($connection = null)
{ {
if ($sphinxConnection === null) { $this->setConnection($connection);
$sphinxConnection = Yii::$app->getComponent('sphinx'); $connection = $this->getConnection();
} list ($sql, $params) = $connection->getQueryBuilder()->build($this);
list ($sql, $params) = $sphinxConnection->getQueryBuilder()->build($this); return $connection->createCommand($sql, $params);
return $sphinxConnection->createCommand($sql, $params);
} }
/** /**
...@@ -154,6 +210,7 @@ class Query extends Component ...@@ -154,6 +210,7 @@ class Query extends Component
public function all($db = null) public function all($db = null)
{ {
$rows = $this->createCommand($db)->queryAll(); $rows = $this->createCommand($db)->queryAll();
$rows = $this->fillUpSnippets($rows);
if ($this->indexBy === null) { if ($this->indexBy === null) {
return $rows; return $rows;
} }
...@@ -178,7 +235,11 @@ class Query extends Component ...@@ -178,7 +235,11 @@ class Query extends Component
*/ */
public function one($db = null) public function one($db = null)
{ {
return $this->createCommand($db)->queryOne(); $result = $this->createCommand($db)->queryOne();
if ($result) {
list ($result) = $this->fillUpSnippets([$result]);
}
return $result;
} }
/** /**
...@@ -686,4 +747,58 @@ class Query extends Component ...@@ -686,4 +747,58 @@ class Query extends Component
} }
return $this; return $this;
} }
/**
* @param callback $callback
* @return static the query object itself
*/
public function snippetCallback($callback)
{
$this->snippetCallback = $callback;
return $this;
}
/**
* @param array $options
* @return static the query object itself
*/
public function snippetOptions($options)
{
$this->snippetOptions = $options;
return $this;
}
/**
* Fills the query result rows with the snippets built from source determined by
* [[snippetCallback]] result.
* @param array $rows raw query result rows.
* @return array query result rows with filled up snippets.
*/
protected function fillUpSnippets($rows)
{
if ($this->snippetCallback === null) {
return $rows;
}
$snippetSources = call_user_func($this->snippetCallback, $rows);
$snippets = $this->callSnippets($snippetSources);
$snippetKey = 0;
foreach ($rows as $key => $row) {
$rows[$key]['snippet'] = $snippets[$snippetKey];
$snippetKey++;
}
return $rows;
}
/**
* Builds a snippets from provided source data.
* @param array $source the source data to extract a snippet from.
* @return array snippets list
*/
protected function callSnippets(array $source)
{
$connection = $this->getConnection();
return $connection->createCommand()
->callSnippets($this->from[0], $source, $this->match, $this->snippetOptions)
->queryColumn();
}
} }
\ No newline at end of file
...@@ -151,4 +151,37 @@ class QueryTest extends SphinxTestCase ...@@ -151,4 +151,37 @@ class QueryTest extends SphinxTestCase
->all($connection); ->all($connection);
$this->assertNotEmpty($rows); $this->assertNotEmpty($rows);
} }
/**
* @depends testRun
*/
public function testSnippet()
{
$connection = $this->getConnection();
$match = 'about';
$snippetPrefix = 'snippet#';
$snippetCallback = function() use ($match, $snippetPrefix) {
return [
$snippetPrefix . '1: ' . $match,
$snippetPrefix . '2: ' . $match,
];
};
$snippetOptions = [
'before_match' => '[',
'after_match' => ']',
];
$query = new Query;
$rows = $query->from('yii2_test_article_index')
->match($match)
->snippetCallback($snippetCallback)
->snippetOptions($snippetOptions)
->all($connection);
$this->assertNotEmpty($rows);
foreach ($rows as $row) {
$this->assertContains($snippetPrefix, $row['snippet'], 'Snippet source not present!');
$this->assertContains($snippetOptions['before_match'] . $match, $row['snippet'] . $snippetOptions['after_match'], 'Options not applied!');
}
}
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment