Klimov Paul
11 years ago
8 changed files with 1680 additions and 2 deletions
@ -0,0 +1,207 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\sphinx; |
||||
|
||||
/** |
||||
* Class ActiveQuery |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class ActiveQuery extends Query |
||||
{ |
||||
/** |
||||
* @var string the name of the ActiveRecord class. |
||||
*/ |
||||
public $modelClass; |
||||
/** |
||||
* @var array list of relations that this query should be performed with |
||||
*/ |
||||
public $with; |
||||
/** |
||||
* @var boolean whether to return each record as an array. If false (default), an object |
||||
* of [[modelClass]] will be created to represent each record. |
||||
*/ |
||||
public $asArray; |
||||
/** |
||||
* @var string the SQL statement to be executed for retrieving AR records. |
||||
* This is set by [[ActiveRecord::findBySql()]]. |
||||
*/ |
||||
public $sql; |
||||
|
||||
/** |
||||
* PHP magic method. |
||||
* This method allows calling static method defined in [[modelClass]] via this query object. |
||||
* It is mainly implemented for supporting the feature of scope. |
||||
* @param string $name the method name to be called |
||||
* @param array $params the parameters passed to the method |
||||
* @return mixed the method return result |
||||
*/ |
||||
public function __call($name, $params) |
||||
{ |
||||
if (method_exists($this->modelClass, $name)) { |
||||
array_unshift($params, $this); |
||||
call_user_func_array([$this->modelClass, $name], $params); |
||||
return $this; |
||||
} else { |
||||
return parent::__call($name, $params); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Executes query and returns all results as an array. |
||||
* @param Connection $db the DB connection used to create the DB command. |
||||
* If null, the DB connection returned by [[modelClass]] will be used. |
||||
* @return array the query results. If the query results in nothing, an empty array will be returned. |
||||
*/ |
||||
public function all($db = null) |
||||
{ |
||||
$command = $this->createCommand($db); |
||||
$rows = $command->queryAll(); |
||||
if (!empty($rows)) { |
||||
$models = $this->createModels($rows); |
||||
// TODO relations |
||||
/*if (!empty($this->with)) { |
||||
$this->populateRelations($models, $this->with); |
||||
}*/ |
||||
return $models; |
||||
} else { |
||||
return []; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Executes query and returns a single row of result. |
||||
* @param Connection $db the DB connection used to create the DB command. |
||||
* If null, the DB connection returned by [[modelClass]] will be used. |
||||
* @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]], |
||||
* the query result may be either an array or an ActiveRecord object. Null will be returned |
||||
* if the query results in nothing. |
||||
*/ |
||||
public function one($db = null) |
||||
{ |
||||
$command = $this->createCommand($db); |
||||
$row = $command->queryOne(); |
||||
if ($row !== false) { |
||||
if ($this->asArray) { |
||||
$model = $row; |
||||
} else { |
||||
/** @var $class ActiveRecord */ |
||||
$class = $this->modelClass; |
||||
$model = $class::create($row); |
||||
} |
||||
// TODO relations |
||||
/*if (!empty($this->with)) { |
||||
$models = [$model]; |
||||
$this->populateRelations($models, $this->with); |
||||
$model = $models[0]; |
||||
}*/ |
||||
return $model; |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a DB command that can be used to execute this query. |
||||
* @param Connection $db the DB connection used to create the DB command. |
||||
* If null, the DB connection returned by [[modelClass]] will be used. |
||||
* @return Command the created DB command instance. |
||||
*/ |
||||
public function createCommand($db = null) |
||||
{ |
||||
/** @var $modelClass ActiveRecord */ |
||||
$modelClass = $this->modelClass; |
||||
if ($db === null) { |
||||
$db = $modelClass::getDb(); |
||||
} |
||||
|
||||
$params = $this->params; |
||||
if ($this->sql === null) { |
||||
if ($this->from === null) { |
||||
$tableName = $modelClass::indexName(); |
||||
if ($this->select === null && !empty($this->join)) { |
||||
$this->select = ["$tableName.*"]; |
||||
} |
||||
$this->from = [$tableName]; |
||||
} |
||||
list ($this->sql, $params) = $db->getQueryBuilder()->build($this); |
||||
} |
||||
return $db->createCommand($this->sql, $params); |
||||
} |
||||
|
||||
/** |
||||
* Sets the [[asArray]] property. |
||||
* @param boolean $value whether to return the query results in terms of arrays instead of Active Records. |
||||
* @return static the query object itself |
||||
*/ |
||||
public function asArray($value = true) |
||||
{ |
||||
$this->asArray = $value; |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Sets the [[indexBy]] property. |
||||
* @param string|callable $column the name of the column by which the query results should be indexed by. |
||||
* This can also be a callable (e.g. anonymous function) that returns the index value based on the given |
||||
* row or model data. The signature of the callable should be: |
||||
* |
||||
* ~~~ |
||||
* // $model is an AR instance when `asArray` is false, |
||||
* // or an array of column values when `asArray` is true. |
||||
* function ($model) |
||||
* { |
||||
* // return the index value corresponding to $model |
||||
* } |
||||
* ~~~ |
||||
* |
||||
* @return static the query object itself |
||||
*/ |
||||
public function indexBy($column) |
||||
{ |
||||
return parent::indexBy($column); |
||||
} |
||||
|
||||
private function createModels($rows) |
||||
{ |
||||
$models = []; |
||||
if ($this->asArray) { |
||||
if ($this->indexBy === null) { |
||||
return $rows; |
||||
} |
||||
foreach ($rows as $row) { |
||||
if (is_string($this->indexBy)) { |
||||
$key = $row[$this->indexBy]; |
||||
} else { |
||||
$key = call_user_func($this->indexBy, $row); |
||||
} |
||||
$models[$key] = $row; |
||||
} |
||||
} else { |
||||
/** @var $class ActiveRecord */ |
||||
$class = $this->modelClass; |
||||
if ($this->indexBy === null) { |
||||
foreach ($rows as $row) { |
||||
$models[] = $class::create($row); |
||||
} |
||||
} else { |
||||
foreach ($rows as $row) { |
||||
$model = $class::create($row); |
||||
if (is_string($this->indexBy)) { |
||||
$key = $model->{$this->indexBy}; |
||||
} else { |
||||
$key = call_user_func($this->indexBy, $model); |
||||
} |
||||
$models[$key] = $model; |
||||
} |
||||
} |
||||
} |
||||
return $models; |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,16 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\data\sphinx\ar; |
||||
|
||||
/** |
||||
* Test Sphinx ActiveRecord class |
||||
*/ |
||||
class ActiveRecord extends \yii\sphinx\ActiveRecord |
||||
{ |
||||
public static $db; |
||||
|
||||
public static function getDb() |
||||
{ |
||||
return self::$db; |
||||
} |
||||
} |
@ -0,0 +1,18 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\data\sphinx\ar; |
||||
|
||||
class ArticleIndex extends ActiveRecord |
||||
{ |
||||
public $custom_column; |
||||
|
||||
public static function indexName() |
||||
{ |
||||
return 'yii2_test_article_index'; |
||||
} |
||||
|
||||
public static function favoriteAuthor($query) |
||||
{ |
||||
$query->andWhere('author_id=1'); |
||||
} |
||||
} |
@ -0,0 +1,11 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\data\sphinx\ar; |
||||
|
||||
class ItemIndex extends ActiveRecord |
||||
{ |
||||
public static function indexName() |
||||
{ |
||||
return 'yii2_test_item_index'; |
||||
} |
||||
} |
@ -0,0 +1,11 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\data\sphinx\ar; |
||||
|
||||
class RuntimeIndex extends ActiveRecord |
||||
{ |
||||
public static function indexName() |
||||
{ |
||||
return 'yii2_test_rt_index'; |
||||
} |
||||
} |
@ -0,0 +1,228 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\sphinx; |
||||
|
||||
use yii\sphinx\ActiveQuery; |
||||
use yiiunit\data\sphinx\ar\ActiveRecord; |
||||
use yiiunit\data\sphinx\ar\ArticleIndex; |
||||
use yiiunit\data\sphinx\ar\RuntimeIndex; |
||||
|
||||
/** |
||||
* @group sphinx |
||||
*/ |
||||
class ActiveRecordTest extends SphinxTestCase |
||||
{ |
||||
protected function setUp() |
||||
{ |
||||
parent::setUp(); |
||||
ActiveRecord::$db = $this->getConnection(); |
||||
} |
||||
|
||||
protected function tearDown() |
||||
{ |
||||
$this->truncateRuntimeIndex('yii2_test_rt_index'); |
||||
parent::tearDown(); |
||||
} |
||||
|
||||
// Tests : |
||||
|
||||
public function testFind() |
||||
{ |
||||
// find one |
||||
$result = ArticleIndex::find(); |
||||
$this->assertTrue($result instanceof ActiveQuery); |
||||
$article = $result->one(); |
||||
$this->assertTrue($article instanceof ArticleIndex); |
||||
|
||||
// find all |
||||
$articles = ArticleIndex::find()->all(); |
||||
$this->assertEquals(2, count($articles)); |
||||
$this->assertTrue($articles[0] instanceof ArticleIndex); |
||||
$this->assertTrue($articles[1] instanceof ArticleIndex); |
||||
|
||||
// find fulltext |
||||
$articles = ArticleIndex::find('cats'); |
||||
$this->assertEquals(1, count($articles)); |
||||
$this->assertTrue($articles[0] instanceof ArticleIndex); |
||||
$this->assertEquals(1, $articles[0]->id); |
||||
|
||||
// find by column values |
||||
$article = ArticleIndex::find(['id' => 2, 'author_id' => 2]); |
||||
$this->assertTrue($article instanceof ArticleIndex); |
||||
$this->assertEquals(2, $article->id); |
||||
$this->assertEquals(2, $article->author_id); |
||||
$article = ArticleIndex::find(['id' => 2, 'author_id' => 1]); |
||||
$this->assertNull($article); |
||||
|
||||
// find by attributes |
||||
$article = ArticleIndex::find()->where(['author_id' => 2])->one(); |
||||
$this->assertTrue($article instanceof ArticleIndex); |
||||
$this->assertEquals(2, $article->id); |
||||
|
||||
// find custom column |
||||
$article = ArticleIndex::find()->select(['*', '(5*2) AS custom_column']) |
||||
->where(['author_id' => 1])->one(); |
||||
$this->assertEquals(1, $article->id); |
||||
$this->assertEquals(10, $article->custom_column); |
||||
|
||||
// find count, sum, average, min, max, scalar |
||||
$this->assertEquals(2, ArticleIndex::find()->count()); |
||||
$this->assertEquals(1, ArticleIndex::find()->where('id=1')->count()); |
||||
$this->assertEquals(3, ArticleIndex::find()->sum('id')); |
||||
$this->assertEquals(1.5, ArticleIndex::find()->average('id')); |
||||
$this->assertEquals(1, ArticleIndex::find()->min('id')); |
||||
$this->assertEquals(2, ArticleIndex::find()->max('id')); |
||||
$this->assertEquals(2, ArticleIndex::find()->select('COUNT(*)')->scalar()); |
||||
|
||||
// scope |
||||
$this->assertEquals(1, ArticleIndex::find()->favoriteAuthor()->count()); |
||||
|
||||
// asArray |
||||
$article = ArticleIndex::find()->where('id=2')->asArray()->one(); |
||||
$this->assertEquals([ |
||||
'id' => '2', |
||||
'author_id' => '2', |
||||
'add_date' => '1384466400', |
||||
'tag' => '3,4', |
||||
], $article); |
||||
|
||||
// indexBy |
||||
$articles = ArticleIndex::find()->indexBy('author_id')->orderBy('id DESC')->all(); |
||||
$this->assertEquals(2, count($articles)); |
||||
$this->assertTrue($articles['1'] instanceof ArticleIndex); |
||||
$this->assertTrue($articles['2'] instanceof ArticleIndex); |
||||
|
||||
// indexBy callable |
||||
$articles = ArticleIndex::find()->indexBy(function ($article) { |
||||
return $article->id . '-' . $article->author_id; |
||||
})->orderBy('id DESC')->all(); |
||||
$this->assertEquals(2, count($articles)); |
||||
$this->assertTrue($articles['1-1'] instanceof ArticleIndex); |
||||
$this->assertTrue($articles['2-2'] instanceof ArticleIndex); |
||||
} |
||||
|
||||
public function testFindBySql() |
||||
{ |
||||
// find one |
||||
$article = ArticleIndex::findBySql('SELECT * FROM yii2_test_article_index ORDER BY id DESC')->one(); |
||||
$this->assertTrue($article instanceof ArticleIndex); |
||||
$this->assertEquals(2, $article->author_id); |
||||
|
||||
// find all |
||||
$articles = ArticleIndex::findBySql('SELECT * FROM yii2_test_article_index')->all(); |
||||
$this->assertEquals(2, count($articles)); |
||||
|
||||
// find with parameter binding |
||||
$article = ArticleIndex::findBySql('SELECT * FROM yii2_test_article_index WHERE id=:id', [':id' => 2])->one(); |
||||
$this->assertTrue($article instanceof ArticleIndex); |
||||
$this->assertEquals(2, $article->author_id); |
||||
} |
||||
|
||||
public function testInsert() |
||||
{ |
||||
$record = new RuntimeIndex; |
||||
$record->id = 15; |
||||
$record->title = 'test title'; |
||||
$record->content = 'test content'; |
||||
$record->type_id = 7; |
||||
$record->category = [1, 2]; |
||||
|
||||
$this->assertTrue($record->isNewRecord); |
||||
|
||||
$record->save(); |
||||
|
||||
$this->assertEquals(15, $record->id); |
||||
$this->assertFalse($record->isNewRecord); |
||||
} |
||||
|
||||
/** |
||||
* @depends testInsert |
||||
*/ |
||||
public function testUpdate() |
||||
{ |
||||
$record = new RuntimeIndex; |
||||
$record->id = 2; |
||||
$record->title = 'test title'; |
||||
$record->content = 'test content'; |
||||
$record->type_id = 7; |
||||
$record->category = [1, 2]; |
||||
$record->save(); |
||||
|
||||
// save |
||||
$record = RuntimeIndex::find(['id' => 2]); |
||||
$this->assertTrue($record instanceof RuntimeIndex); |
||||
$this->assertEquals(7, $record->type_id); |
||||
$this->assertFalse($record->isNewRecord); |
||||
|
||||
$record->type_id = 9; |
||||
$record->save(); |
||||
$this->assertEquals(9, $record->type_id); |
||||
$this->assertFalse($record->isNewRecord); |
||||
$record2 = RuntimeIndex::find(['id' => 2]); |
||||
$this->assertEquals(9, $record2->type_id); |
||||
|
||||
// updateCounters |
||||
/*$pk = ['id' => 1]; |
||||
$record = RuntimeIndex::find($pk); |
||||
$this->assertEquals(1, $record->quantity); |
||||
$ret = $record->updateCounters(['quantity' => -1]); |
||||
$this->assertTrue($ret); |
||||
$this->assertEquals(0, $record->quantity); |
||||
$record = RuntimeIndex::find($pk); |
||||
$this->assertEquals(0, $record->quantity);*/ |
||||
|
||||
// updateAll |
||||
$pk = ['id' => 2]; |
||||
$ret = RuntimeIndex::updateAll(['type_id' => 55], $pk); |
||||
$this->assertEquals(1, $ret); |
||||
$record = RuntimeIndex::find($pk); |
||||
$this->assertEquals(55, $record->type_id); |
||||
|
||||
// updateAllCounters |
||||
/*$pk = ['order_id' => 1, 'item_id' => 2]; |
||||
$record = RuntimeIndex::find($pk); |
||||
$this->assertEquals(2, $record->quantity); |
||||
$ret = RuntimeIndex::updateAllCounters([ |
||||
'quantity' => 3, |
||||
'subtotal' => -10, |
||||
], $pk); |
||||
$this->assertEquals(1, $ret); |
||||
$record = RuntimeIndex::find($pk); |
||||
$this->assertEquals(5, $record->quantity); |
||||
$this->assertEquals(30, $record->subtotal);*/ |
||||
} |
||||
|
||||
/** |
||||
* @depends testInsert |
||||
*/ |
||||
public function testDelete() |
||||
{ |
||||
// delete |
||||
$record = new RuntimeIndex; |
||||
$record->id = 2; |
||||
$record->title = 'test title'; |
||||
$record->content = 'test content'; |
||||
$record->type_id = 7; |
||||
$record->category = [1, 2]; |
||||
$record->save(); |
||||
|
||||
$record = RuntimeIndex::find(['id' => 2]); |
||||
$record->delete(); |
||||
$record = RuntimeIndex::find(['id' => 2]); |
||||
$this->assertNull($record); |
||||
|
||||
// deleteAll |
||||
$record = new RuntimeIndex; |
||||
$record->id = 2; |
||||
$record->title = 'test title'; |
||||
$record->content = 'test content'; |
||||
$record->type_id = 7; |
||||
$record->category = [1, 2]; |
||||
$record->save(); |
||||
|
||||
$ret = RuntimeIndex::deleteAll('id = 2'); |
||||
$this->assertEquals(1, $ret); |
||||
$records = RuntimeIndex::find()->all(); |
||||
$this->assertEquals(0, count($records)); |
||||
} |
||||
} |
Loading…
Reference in new issue