Commit 5cb24302 by Alexander Makarov

Merge branch 'master'

parents b1d94e5c 8077ea3f
......@@ -69,7 +69,7 @@ class User extends ActiveRecord implements IdentityInterface
/**
* @inheritdoc
*/
public static function findIdentityByAccessToken($token)
public static function findIdentityByAccessToken($token, $type = null)
{
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
}
......
......@@ -38,7 +38,7 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface
/**
* @inheritdoc
*/
public static function findIdentityByAccessToken($token)
public static function findIdentityByAccessToken($token, $type = null)
{
foreach (self::$users as $user) {
if ($user['accessToken'] === $token) {
......
......@@ -679,7 +679,7 @@ use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
public static function findIdentityByAccessToken($token)
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
......
......@@ -32,7 +32,7 @@ class User extends ActiveRecord implements IdentityInterface
* @param string $token the token to be looked for
* @return IdentityInterface|null the identity object that matches the given token.
*/
public static function findIdentityByAccessToken($token)
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
......
......@@ -460,7 +460,7 @@ of the rule class, you need to respect this hierarchy as well. That is why when
the `execute()` method will return true if the user group is either 1 or 2 (meaning the user is in either "admin"
group or "author" group).
Next, configure `authManager` by listing the two roles in [[yii\rbac\ManagerInterface::defaultRoles]]:
Next, configure `authManager` by listing the two roles in [[yii\rbac\BaseManager::$defaultRoles]]:
```php
return [
......
Basic application template
==========================
Installing Yii
==============
There are two ways to install Yii:
* Using [Composer](http://getcomposer.org/);
* Downloading an archive file from [yiiframework.com](http://www.yiiframework.com/download/).
The first approach is highly recommended, as it allows you to automatically install updates
Installing via Composer
-----------------------
The recommended way to install Yii is to use the [Composer](http://getcomposer.org/) package manager. If you do not already
have Composer installed, you may download it from [http://getcomposer.org/](http://getcomposer.org/), or run the following command to download and install it:
```
curl -s http://getcomposer.org/installer | php
```
(It is strongly recommended to perform a [global Composer installation](https://getcomposer.org/doc/00-intro.md#globally)).
For problems with, or more information on, installing Composer, see the official Composer guide:
* [Linux](http://getcomposer.org/doc/00-intro.md#installation-nix)
* [Windows](http://getcomposer.org/doc/00-intro.md#installation-windows)
With Composer installed, you can create a new Yii site using one of Yii's ready-to-use application templates. Based on your needs, choosing the right template can help bootstrap your project.
Currently, there are two Yii application templates available:
- [Basic Application Template](https://github.com/yiisoft/yii2-app-basic), a basic frontend application template
- [Advanced Application Template](https://github.com/yiisoft/yii2-app-advanced), consisting of a frontend, a backend, console resources, common (shared code), and support for environments
For template installation instructions, see the above linked pages.
To read more about the ideas behind these application templates and the proposed usage,
refer to the [basic application template](apps-basic.md) and [advanced application template](apps-advanced.md) documents.
If you do not want to use a template, rather starting from scratch, you'll find information in the [creating your own application structure](apps-own.md) document. This approach is only recommended for advanced users.
Installing from zip
-------------------
Installation from a zip file involves two steps:
1. Downloading an application template from [yiiframework.com](http://www.yiiframework.com/download/).
2. Unpacking the downloaded file.
If you only want the Yii Framework files you can download a zip file directly from [github](https://github.com/yiisoft/yii2-framework/releases).
To create your application you might want to follow the steps described in [creating your own application structure](apps-own.md).
This is only recommended for advanced users.
> Tip: The Yii framework itself does not need to be installed under a web-accessible directory (in fact, it should not be).
A Yii application has one entry script, which is usually the only file that absolutely must be
exposed to web users (i.e., placed within the web directory). Other PHP scripts, including those
in the Yii Framework, should be protected from web access to prevent possible exploitation by hackers.
Requirements
------------
Yii 2 requires PHP 5.4.0 or higher. Yii has been tested with the [Apache HTTP server](http://httpd.apache.org/) and
[Nginx HTTP server](http://nginx.org/) on both Windows and Linux.
Yii may also be usable on other web servers and platforms, provided that PHP 5.4 or higher is present.
After installing Yii, you may want to verify that your server satisfies
Yii's requirements. You can do so by running the requirement checker
script in a web browser or from the command line.
If you have installed a Yii application template via the downloaded zip file or Composer, you'll find a `requirements.php` file in the
base directory of your application.
In order to run this script on the command line use the following command (after navigating to the directory where `requirements.php` can be found):
```
php requirements.php
```
In order to run this script in your browser, you must make sure it's within a web directory, and then
access `http://hostname/path/to/yii-app/requirements.php` in your browser.
> Note: This section is under development.
......
......@@ -42,6 +42,26 @@ class BaseDoc extends Object
*/
public $tags = [];
public function hasTag($name)
{
foreach ($this->tags as $tag) {
if (strtolower($tag->getName()) == $name) {
return true;
}
}
return false;
}
public function removeTag($name)
{
foreach ($this->tags as $i => $tag) {
if (strtolower($tag->getName()) == $name) {
unset($this->tags[$i]);
}
}
}
/**
* @param \phpDocumentor\Reflection\BaseReflector $reflector
* @param Context $context
......@@ -70,7 +90,7 @@ class BaseDoc extends Object
'message' => "No short description for " . substr(StringHelper::basename(get_class($this)), 0, -3) . " '{$this->name}'",
];
}
$this->description = $docblock->getLongDescription();
$this->description = $docblock->getLongDescription()->getContents();
$this->phpDocContext = $docblock->getContext();
......
......@@ -164,11 +164,33 @@ class Context extends Component
{
// TODO also for properties?
foreach ($class->methods as $m) {
$inheritedMethod = $this->inheritMethodRecursive($m, $class);
foreach (['shortDescription', 'description', 'params', 'return', 'returnType', 'returnTypes', 'exceptions'] as $property) {
if (empty($m->$property)) {
$m->$property = $inheritedMethod->$property;
if ($m->hasTag('inheritdoc')) {
$inheritedMethod = $this->inheritMethodRecursive($m, $class);
foreach (['shortDescription', 'description', 'return', 'returnType', 'returnTypes', 'exceptions'] as $property) {
if (empty($m->$property) || is_string($m->$property) && trim($m->$property) === '') {
$m->$property = $inheritedMethod->$property;
}
}
foreach ($m->params as $i => $param) {
if (!isset($inheritedMethod->params[$i])) {
$this->errors[] = [
'line' => $m->startLine,
'file' => $class->sourceFile,
'message' => "Method param $i does not exist in parent method, @inheritdoc not possible in {$m->name} in {$class->name}.",
];
continue;
}
if (empty($param->description) || trim($param->description) === '') {
$param->description = $inheritedMethod->params[$i]->description;
}
if (empty($param->type) || trim($param->type) === '') {
$param->type = $inheritedMethod->params[$i]->type;
}
if (empty($param->types) || trim($param->types) === '') {
$param->types = $inheritedMethod->params[$i]->types;
}
}
$m->removeTag('inheritdoc');
}
}
}
......@@ -179,20 +201,50 @@ class Context extends Component
*/
private function inheritMethodRecursive($method, $class)
{
if (!isset($this->classes[$class->parentClass])) {
return $method;
}
$parent = $this->classes[$class->parentClass];
foreach ($method->tags as $tag) {
if (strtolower($tag->getName()) == 'inheritdoc') {
if (isset($parent->methods[$method->name])) {
$method = $parent->methods[$method->name];
$inheritanceCandidates = array_merge(
$this->getParents($class),
$this->getInterfaces($class)
);
$methods = [];
foreach($inheritanceCandidates as $candidate) {
if (isset($candidate->methods[$method->name])) {
$cmethod = $candidate->methods[$method->name];
if ($cmethod->hasTag('inheritdoc')) {
$this->inheritDocs($candidate);
}
$methods[] = $cmethod;
}
}
return $this->inheritMethodRecursive($method, $parent);
return reset($methods);
}
/**
* @param ClassDoc $class
* @return array
*/
private function getParents($class)
{
if ($class->parentClass === null || !isset($this->classes[$class->parentClass])) {
return [];
}
return array_merge([$this->classes[$class->parentClass]], $this->getParents($this->classes[$class->parentClass]));
}
/**
* @param ClassDoc $class
* @return array
*/
private function getInterfaces($class)
{
$interfaces = [];
foreach($class->interfaces as $interface) {
if (isset($this->interfaces[$interface])) {
$interfaces[] = $this->interfaces[$interface];
}
}
return $method;
return $interfaces;
}
/**
......
......@@ -7,6 +7,7 @@
namespace yii\elasticsearch;
use yii\base\NotSupportedException;
use yii\db\ActiveQueryInterface;
use yii\db\ActiveQueryTrait;
use yii\db\ActiveRelationTrait;
......@@ -143,47 +144,21 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/
public function all($db = null)
{
if ($this->asArray) {
// TODO implement with
return parent::all($db);
}
$result = $this->createCommand($db)->search();
if (empty($result['hits']['hits'])) {
return [];
}
if ($this->fields !== null) {
foreach ($result['hits']['hits'] as &$row) {
$row['_source'] = isset($row['fields']) ? $row['fields'] : [];
unset($row['fields']);
}
unset($row);
}
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
$pk = $modelClass::primaryKey()[0];
if ($this->asArray && $this->indexBy) {
foreach ($result['hits']['hits'] as &$row) {
if ($pk === '_id') {
$row['_source']['_id'] = $row['_id'];
}
$row['_source']['_score'] = $row['_score'];
$row = $row['_source'];
}
unset($row);
}
$models = $this->createModels($result['hits']['hits']);
if ($this->asArray && !$this->indexBy) {
foreach ($models as $key => $model) {
if ($pk === '_id') {
$model['_source']['_id'] = $model['_id'];
}
$model['_source']['_score'] = $model['_score'];
$models[$key] = $model['_source'];
}
}
if (!empty($this->with)) {
$this->findWith($this->with, $models);
}
if (!$this->asArray) {
foreach ($models as $model) {
$model->afterFind();
}
foreach ($models as $model) {
$model->afterFind();
}
return $models;
......@@ -203,30 +178,34 @@ class ActiveQuery extends Query implements ActiveQueryInterface
return null;
}
if ($this->asArray) {
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
$model = $result['_source'];
$pk = $modelClass::primaryKey()[0];
if ($pk === '_id') {
$model['_id'] = $result['_id'];
}
$model['_score'] = $result['_score'];
// TODO implement with
// /** @var ActiveRecord $modelClass */
// $modelClass = $this->modelClass;
// $model = $result['_source'];
// $pk = $modelClass::primaryKey()[0];
// if ($pk === '_id') {
// $model['_id'] = $result['_id'];
// }
// $model['_score'] = $result['_score'];
// if (!empty($this->with)) {
// $models = [$model];
// $this->findWith($this->with, $models);
// $model = $models[0];
// }
return $result;
} else {
/** @var ActiveRecord $class */
$class = $this->modelClass;
$model = $class::instantiate($result);
$class::populateRecord($model, $result);
}
if (!empty($this->with)) {
$models = [$model];
$this->findWith($this->with, $models);
$model = $models[0];
}
if (!$this->asArray) {
if (!empty($this->with)) {
$models = [$model];
$this->findWith($this->with, $models);
$model = $models[0];
}
$model->afterFind();
return $model;
}
return $model;
}
/**
......@@ -235,27 +214,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface
public function search($db = null, $options = [])
{
$result = $this->createCommand($db)->search($options);
if (!empty($result['hits']['hits'])) {
// TODO implement with for asArray
if (!empty($result['hits']['hits']) && !$this->asArray) {
$models = $this->createModels($result['hits']['hits']);
if ($this->asArray) {
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
$pk = $modelClass::primaryKey()[0];
foreach ($models as $key => $model) {
if ($pk === '_id') {
$model['_source']['_id'] = $model['_id'];
}
$model['_source']['_score'] = $model['_score'];
$models[$key] = $model['_source'];
}
}
if (!empty($this->with)) {
$this->findWith($this->with, $models);
}
if (!$this->asArray) {
foreach ($models as $model) {
$model->afterFind();
}
foreach ($models as $model) {
$model->afterFind();
}
$result['hits']['hits'] = $models;
}
......@@ -266,28 +232,12 @@ class ActiveQuery extends Query implements ActiveQueryInterface
/**
* @inheritdoc
*/
public function scalar($field, $db = null)
{
$record = parent::one($db);
if ($record !== false) {
if ($field == '_id') {
return $record['_id'];
} elseif (isset($record['_source'][$field])) {
return $record['_source'][$field];
}
}
return null;
}
/**
* @inheritdoc
*/
public function column($field, $db = null)
{
if ($field == '_id') {
$command = $this->createCommand($db);
$command->queryParts['fields'] = [];
$command->queryParts['_source'] = false;
$result = $command->search();
if (empty($result['hits']['hits'])) {
return [];
......
......@@ -114,7 +114,7 @@ class ActiveRecord extends BaseActiveRecord
}
$command = static::getDb()->createCommand();
$result = $command->get(static::index(), static::type(), $primaryKey, $options);
if ($result['exists']) {
if ($result['found']) {
$model = static::instantiate($result);
static::populateRecord($model, $result);
$model->afterFind();
......@@ -150,7 +150,7 @@ class ActiveRecord extends BaseActiveRecord
$result = $command->mget(static::index(), static::type(), $primaryKeys, $options);
$models = [];
foreach ($result['docs'] as $doc) {
if ($doc['exists']) {
if ($doc['found']) {
$model = static::instantiate($doc);
static::populateRecord($model, $doc);
$model->afterFind();
......@@ -282,8 +282,23 @@ class ActiveRecord extends BaseActiveRecord
*/
public static function populateRecord($record, $row)
{
parent::populateRecord($record, $row['_source']);
$pk = static::primaryKey()[0];
$attributes = [];
if (isset($row['_source'])) {
$attributes = $row['_source'];
}
if (isset($row['fields'])) {
// reset fields in case it is scalar value TODO use field metadata for this
foreach($row['fields'] as $key => $value) {
if (count($value) == 1) {
$row['fields'][$key] = reset($value);
}
}
$attributes = array_merge($attributes, $row['fields']);
}
parent::populateRecord($record, $attributes);
$pk = static::primaryKey()[0];//TODO should always set ID in case of fields are not returned
if ($pk === '_id') {
$record->_id = $row['_id'];
}
......@@ -379,9 +394,9 @@ class ActiveRecord extends BaseActiveRecord
$options
);
if (!isset($response['ok'])) {
return false;
}
// if (!isset($response['ok'])) {
// return false;
// }
$pk = static::primaryKey()[0];
$this->$pk = $response['_id'];
if ($pk != '_id') {
......@@ -444,13 +459,13 @@ class ActiveRecord extends BaseActiveRecord
$n = 0;
$errors = [];
foreach ($response['items'] as $item) {
if (isset($item['update']['error'])) {
$errors[] = $item['update'];
} elseif ($item['update']['ok']) {
if (isset($item['update']['status']) && $item['update']['status'] == 200) {
$n++;
} else {
$errors[] = $item['update'];
}
}
if (!empty($errors)) {
if (!empty($errors) || isset($response['errors']) && $response['errors']) {
throw new Exception(__METHOD__ . ' failed updating records.', $errors);
}
......@@ -508,13 +523,13 @@ class ActiveRecord extends BaseActiveRecord
$n = 0;
$errors = [];
foreach ($response['items'] as $item) {
if (isset($item['update']['error'])) {
$errors[] = $item['update'];
} elseif ($item['update']['ok']) {
if (isset($item['update']['status']) && $item['update']['status'] == 200) {
$n++;
} else {
$errors[] = $item['update'];
}
}
if (!empty($errors)) {
if (!empty($errors) || isset($response['errors']) && $response['errors']) {
throw new Exception(__METHOD__ . ' failed updating records counters.', $errors);
}
......@@ -563,13 +578,15 @@ class ActiveRecord extends BaseActiveRecord
$n = 0;
$errors = [];
foreach ($response['items'] as $item) {
if (isset($item['delete']['error'])) {
if (isset($item['delete']['status']) && $item['delete']['status'] == 200) {
if (isset($item['delete']['found']) && $item['delete']['found']) {
$n++;
}
} else {
$errors[] = $item['delete'];
} elseif ($item['delete']['found'] && $item['delete']['ok']) {
$n++;
}
}
if (!empty($errors)) {
if (!empty($errors) || isset($response['errors']) && $response['errors']) {
throw new Exception(__METHOD__ . ' failed deleting records.', $errors);
}
......
......@@ -4,7 +4,9 @@ Yii Framework 2 elasticsearch extension Change Log
2.0.0-rc under development
--------------------------
- no changes in this release.
- Chg: asArray in ActiveQuery is now equal to using the normal Query. This means, that the output structure has changed and `with` is supported anymore. (cebe)
- Chg: Deletion of a record is now also considered successfull if the record did not exist. (cebe)
- Chg: Requirement changes: Yii now requires elasticsearch version 1.0 or higher (cebe)
2.0.0-beta April 13, 2014
......
......@@ -315,7 +315,7 @@ class Command extends Component
{
$body = $mapping !== null ? (is_string($mapping) ? $mapping : Json::encode($mapping)) : null;
return $this->db->put([$index, $type, '_mapping'], $options, $body);
return $this->db->put([$index, '_mapping', $type], $options, $body);
}
/**
......@@ -326,7 +326,7 @@ class Command extends Component
*/
public function getMapping($index = '_all', $type = '_all')
{
return $this->db->get([$index, $type, '_mapping']);
return $this->db->get([$index, '_mapping', $type]);
}
/**
......@@ -337,7 +337,7 @@ class Command extends Component
*/
public function deleteMapping($index, $type)
{
return $this->db->delete([$index, $type]);
return $this->db->delete([$index, '_mapping', $type]);
}
/**
......@@ -346,10 +346,11 @@ class Command extends Component
* @return mixed
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html
*/
public function getFieldMapping($index, $type = '_all')
{
return $this->db->put([$index, $type, '_mapping']);
}
// public function getFieldMapping($index, $type = '_all')
// {
// // TODO implement
// return $this->db->put([$index, $type, '_mapping']);
// }
/**
* @param $options
......
......@@ -109,7 +109,7 @@ class Connection extends Component
if (strncmp($host, 'inet[/', 6) == 0) {
$host = substr($host, 6, -1);
}
$response = $this->httpRequest('GET', 'http://' . $host . '/_cluster/nodes');
$response = $this->httpRequest('GET', 'http://' . $host . '/_nodes');
$this->nodes = $response['nodes'];
if (empty($this->nodes)) {
throw new Exception('cluster autodetection did not find any active node.');
......
......@@ -58,13 +58,52 @@ class Query extends Component implements QueryInterface
/**
* @var array the fields being retrieved from the documents. For example, `['id', 'name']`.
* If not set, it means retrieving all fields. An empty array will result in no fields being
* retrieved. This means that only the primaryKey of a record will be available in the result.
* If not set, this option will not be applied to the query and no fields will be returned.
* In this case the `_source` field will be returned by default which can be configured using [[source]].
* Setting this to an empty array will result in no fields being retrieved, which means that only the primaryKey
* of a record will be available in the result.
*
* For each field you may also add an array representing a [script field]. Example:
*
* ```php
* $query->fields = [
* 'id',
* 'name',
* 'value_times_two' => [
* 'script' => "doc['my_field_name'].value * 2",
* ],
* 'value_times_factor' => [
* 'script' => "doc['my_field_name'].value * factor",
* 'params' => [
* 'factor' => 2.0
* ],
* ],
* ]
* ```
*
* > Note: Field values are [always returned as arrays] even if they only have one value.
*
* [always returned as arrays]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/_return_values.html#_return_values
* [script field]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-script-fields.html
*
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-fields.html#search-request-fields
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-script-fields.html
* @see fields()
* @see source
*/
public $fields;
/**
* @var array this option controls how the `_source` field is returned from the documents. For example, `['id', 'name']`
* means that only the `id` and `name` field should be returned from `_source`.
* If not set, it means retrieving the full `_source` field unless [[fields]] are specified.
* Setting this option to `false` will disable return of the `_source` field, this means that only the primaryKey
* of a record will be available in the result.
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-source-filtering.html
* @see source()
* @see fields
*/
public $source;
/**
* @var string|array The index to retrieve data from. This can be a string representing a single index
* or a an array of multiple indexes. If this is not set, indexes are being queried.
* @see from()
......@@ -137,25 +176,20 @@ class Query extends Component implements QueryInterface
return [];
}
$rows = $result['hits']['hits'];
if ($this->indexBy === null && $this->fields === null) {
if ($this->indexBy === null) {
return $rows;
}
$models = [];
foreach ($rows as $key => $row) {
if ($this->fields !== null) {
$row['_source'] = isset($row['fields']) ? $row['fields'] : [];
unset($row['fields']);
}
if ($this->indexBy !== null) {
if (is_string($this->indexBy)) {
$key = $row['_source'][$this->indexBy];
$key = isset($row['fields'][$this->indexBy]) ? reset($row['fields'][$this->indexBy]) : $row['_source'][$this->indexBy];
} else {
$key = call_user_func($this->indexBy, $row);
}
}
$models[$key] = $row;
}
return $models;
}
......@@ -173,10 +207,6 @@ class Query extends Component implements QueryInterface
return false;
}
$record = reset($result['hits']['hits']);
if ($this->fields !== null) {
$record['_source'] = isset($record['fields']) ? $record['fields'] : [];
unset($record['fields']);
}
return $record;
}
......@@ -195,25 +225,18 @@ class Query extends Component implements QueryInterface
public function search($db = null, $options = [])
{
$result = $this->createCommand($db)->search($options);
if (!empty($result['hits']['hits']) && ($this->indexBy === null || $this->fields === null)) {
if (!empty($result['hits']['hits']) && $this->indexBy !== null) {
$rows = [];
foreach ($result['hits']['hits'] as $key => $row) {
if ($this->fields !== null) {
$row['_source'] = isset($row['fields']) ? $row['fields'] : [];
unset($row['fields']);
}
if ($this->indexBy !== null) {
if (is_string($this->indexBy)) {
$key = $row['_source'][$this->indexBy];
} else {
$key = call_user_func($this->indexBy, $row);
}
if (is_string($this->indexBy)) {
$key = isset($row['fields'][$this->indexBy]) ? $row['fields'][$this->indexBy] : $row['_source'][$this->indexBy];
} else {
$key = call_user_func($this->indexBy, $row);
}
$rows[$key] = $row;
}
$result['hits']['hits'] = $rows;
}
return $result;
}
......@@ -247,12 +270,17 @@ class Query extends Component implements QueryInterface
*/
public function scalar($field, $db = null)
{
$record = self::one($db); // TODO limit fields to the one required
if ($record !== false && isset($record['_source'][$field])) {
return $record['_source'][$field];
} else {
return null;
$record = self::one($db);
if ($record !== false) {
if ($field === '_id') {
return $record['_id'];
} elseif (isset($record['_source'][$field])) {
return $record['_source'][$field];
} elseif (isset($record['fields'][$field])) {
return count($record['fields'][$field]) == 1 ? reset($record['fields'][$field]) : $record['fields'][$field];
}
}
return null;
}
/**
......@@ -265,14 +293,14 @@ class Query extends Component implements QueryInterface
public function column($field, $db = null)
{
$command = $this->createCommand($db);
$command->queryParts['fields'] = [$field];
$command->queryParts['_source'] = [$field];
$result = $command->search();
if (empty($result['hits']['hits'])) {
return [];
}
$column = [];
foreach ($result['hits']['hits'] as $row) {
$column[] = isset($row['fields'][$field]) ? $row['fields'][$field] : null;
$column[] = isset($row['_source'][$field]) ? $row['_source'][$field] : null;
}
return $column;
}
......@@ -498,6 +526,22 @@ class Query extends Component implements QueryInterface
}
/**
* Sets the source filtering, specifying how the `_source` field of the document should be returned.
* @param array $source the source patterns to be selected.
* @return static the query object itself
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-source-filtering.html
*/
public function source($source)
{
if (is_array($source) || $source === null) {
$this->source = $source;
} else {
$this->source = func_get_args();
}
return $this;
}
/**
* Sets the search timeout.
* @param integer $timeout A search timeout, bounding the search request to be executed within the specified time value
* and bail with the hits accumulated up to that point when expired. Defaults to no timeout.
......
......@@ -45,8 +45,27 @@ class QueryBuilder extends \yii\base\Object
{
$parts = [];
if ($query->fields !== null) {
$parts['fields'] = (array) $query->fields;
if ($query->fields === []) {
$parts['fields'] = [];
} elseif ($query->fields !== null) {
$fields = [];
$scriptFields = [];
foreach($query->fields as $key => $field) {
if (is_int($key)) {
$fields[] = $field;
} else {
$scriptFields[$key] = $field;
}
}
if (!empty($fields)) {
$parts['fields'] = $fields;
}
if (!empty($scriptFields)) {
$parts['script_fields'] = $scriptFields;
}
}
if ($query->source !== null) {
$parts['_source'] = $query->source;
}
if ($query->limit !== null && $query->limit >= 0) {
$parts['size'] = $query->limit;
......
......@@ -22,6 +22,10 @@ return [
];
```
Requirements
------------
elasticsearch version 1.0 or higher is required.
Installation
------------
......
......@@ -11,7 +11,7 @@ $this->title = 'Welcome to Gii';
?>
<div class="default-index">
<div class="page-header">
<h1>Welcome to Gii <small>a magic tool that can write code for you</small></h1>
<h1>Welcome to Gii <small>a magical tool that can write code for you</small></h1>
</div>
<p class="lead">Start the fun with the following code generators:</p>
......
......@@ -4,7 +4,7 @@ Yii Framework 2 mongodb extension Change Log
2.0.0-rc under development
--------------------------
- no changes in this release.
- Bug #3385: Fixed "The 'connected' property is deprecated" (samdark)
2.0.0-beta April 13, 2014
......
......@@ -219,7 +219,7 @@ class Connection extends Component
*/
public function getIsActive()
{
return is_object($this->mongoClient) && $this->mongoClient->connected;
return is_object($this->mongoClient) && $this->mongoClient->getConnections() != [];
}
/**
......
......@@ -25,6 +25,7 @@ Yii Framework 2 Change Log
- Bug #3311: Fixed the bug that `yii\di\Container::has()` did not return correct value (mgrechanik, qiangxue)
- Bug #3327: Fixed "Unable to find debug data" when logging objects with circular references (jarekkozak, samdark)
- Bug #3368: Fix for comparing numeric attributes in JavaScript (technixp)
- Bug: Fixed inconsistent return of `\yii\console\Application::runAction()` (samdark)
- Enh #2264: `CookieCollection::has()` will return false for expired or removed cookies (qiangxue)
- Enh #2435: `yii\db\IntegrityException` is now thrown on database integrity errors instead of general `yii\db\Exception` (samdark)
- Enh #2837: Error page now shows arguments in stack trace method calls (samdark)
......@@ -45,9 +46,12 @@ Yii Framework 2 Change Log
- Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue)
- Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue)
- Enh: Added support to insert an event handler at the beginning of class-level event handler queue (qiangxue)
- Enh: Added `yii\console\Controller::EXIT_CODE_NORMAL` and `yii\console\Controller::EXIT_CODE_ERROR` constants (samdark)
- Enh: `yii\console\MigrateController` now returns `yii\console\Controller::EXIT_CODE_ERROR` in case of failed migration (samdark)
- Chg #2913: RBAC `DbManager` is now initialized via migration (samdark)
- Chg #3036: Upgraded Twitter Bootstrap to 3.1.x (qiangxue)
- Chg #3175: InvalidCallException, InvalidParamException, UnknownMethodException are now extended from SPL BadMethodCallException (samdark)
- Chg #3383: Added `$type` parameter to `IdentityInterface::findIdentityByAccessToken()` (qiangxue)
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
- Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue)
- Chg: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe)
......
......@@ -21,3 +21,11 @@ Upgrade from Yii 2.0 Beta
* If you override `yii\grid\DataColumn::getDataCellValue()` with visibility `protected` you have
to change visibility to `public` as visibility of the base method has changed.
* If you have classes implementing `yii\web\IdentityInterface` (very common), you should modify
the signature of `findIdentityByAccessToken()` as
`public static function findIdentityByAccessToken($token, $type = null)`. The new `$type` parameter
will contain the type information about the access token. For example, if you use
`yii\filters\auth\HttpBearerAuth` authentication method, the value of this parameter will be
`yii\filters\auth\HttpBearerAuth`. This allows you to differentiate access tokens taken by
different authentication methods.
......@@ -77,6 +77,7 @@ use Yii;
class Object
{
/**
* Returns the fully qualified name of this class.
* @return string the fully qualified name of this class.
*/
public static function className()
......
......@@ -54,7 +54,7 @@ class Widget extends Component implements ViewContextInterface
$config['class'] = get_called_class();
/** @var Widget $widget */
$widget = Yii::createObject($config);
self::$stack[] = $widget;
static::$stack[] = $widget;
return $widget;
}
......@@ -67,8 +67,8 @@ class Widget extends Component implements ViewContextInterface
*/
public static function end()
{
if (!empty(self::$stack)) {
$widget = array_pop(self::$stack);
if (!empty(static::$stack)) {
$widget = array_pop(static::$stack);
if (get_class($widget) === get_called_class()) {
echo $widget->run();
return $widget;
......@@ -108,7 +108,7 @@ class Widget extends Component implements ViewContextInterface
public function getId($autoGenerate = true)
{
if ($autoGenerate && $this->_id === null) {
$this->_id = self::$autoIdPrefix . self::$counter++;
$this->_id = static::$autoIdPrefix . static::$counter++;
}
return $this->_id;
......
......@@ -138,7 +138,7 @@ class Application extends \yii\base\Application
return $result;
} else {
$response = $this->getResponse();
$response->exitStatus = (int) $result;
$response->exitStatus = $result;
return $response;
}
......@@ -157,7 +157,7 @@ class Application extends \yii\base\Application
public function runAction($route, $params = [])
{
try {
return parent::runAction($route, $params);
return (int)parent::runAction($route, $params);
} catch (InvalidRouteException $e) {
throw new Exception(Yii::t('yii', 'Unknown command "{command}".', ['command' => $route]), 0, $e);
}
......
......@@ -29,6 +29,9 @@ use yii\helpers\Console;
*/
class Controller extends \yii\base\Controller
{
const EXIT_CODE_NORMAL = 0;
const EXIT_CODE_ERROR = 1;
/**
* @var boolean whether to run the command interactively.
*/
......
......@@ -611,7 +611,7 @@ return [
EOD;
if (file_exists($configFile)) {
if (!$this->confirm("File '{$configFile}' already exists. Do you wish to overwrite it?")) {
return;
return self::EXIT_CODE_NORMAL;
}
}
if (!file_put_contents($configFile, $template)) {
......
......@@ -96,7 +96,7 @@ class FixtureController extends Controller
}
if (!$this->confirmLoad($foundFixtures, $except)) {
return;
return self::EXIT_CODE_NORMAL;
}
$filtered = array_diff($foundFixtures, $except);
......@@ -140,7 +140,7 @@ class FixtureController extends Controller
}
if (!$this->confirmUnload($foundFixtures, $except)) {
return;
return self::EXIT_CODE_NORMAL;
}
$filtered = array_diff($foundFixtures, $except);
......
......@@ -54,7 +54,7 @@ class MessageController extends Controller
$filePath = Yii::getAlias($filePath);
if (file_exists($filePath)) {
if (!$this->confirm("File '{$filePath}' already exists. Do you wish to overwrite it?")) {
return;
return self::EXIT_CODE_NORMAL;
}
}
copy(Yii::getAlias('@yii/views/messageConfig.php'), $filePath);
......@@ -298,7 +298,7 @@ class MessageController extends Controller
if (array_keys($translated) == $messages) {
echo "nothing new...skipped.\n";
return;
return self::EXIT_CODE_NORMAL;
}
$merged = [];
$untranslated = [];
......
......@@ -81,10 +81,6 @@ class MigrateController extends Controller
*/
public $templateFile = '@yii/views/migration.php';
/**
* @var boolean whether to execute the migration in an interactive mode.
*/
public $interactive = true;
/**
* @var Connection|string the DB connection object or the application
* component ID of the DB connection.
*/
......@@ -148,6 +144,8 @@ class MigrateController extends Controller
*
* @param integer $limit the number of new migrations to be applied. If 0, it means
* applying all available new migrations.
*
* @return integer the status of the action execution. 0 means normal, other values mean abnormal.
*/
public function actionUp($limit = 0)
{
......@@ -155,7 +153,7 @@ class MigrateController extends Controller
if (empty($migrations)) {
echo "No new migration found. Your system is up-to-date.\n";
return;
return self::EXIT_CODE_NORMAL;
}
$total = count($migrations);
......@@ -181,7 +179,7 @@ class MigrateController extends Controller
if (!$this->migrateUp($migration)) {
echo "\nMigration failed. The rest of the migrations are canceled.\n";
return;
return self::EXIT_CODE_ERROR;
}
}
echo "\nMigrated up successfully.\n";
......@@ -200,6 +198,8 @@ class MigrateController extends Controller
* @param integer $limit the number of migrations to be reverted. Defaults to 1,
* meaning the last applied migration will be reverted.
* @throws Exception if the number of the steps specified is less than 1.
*
* @return integer the status of the action execution. 0 means normal, other values mean abnormal.
*/
public function actionDown($limit = 1)
{
......@@ -212,7 +212,7 @@ class MigrateController extends Controller
if (empty($migrations)) {
echo "No migration has been done before.\n";
return;
return self::EXIT_CODE_NORMAL;
}
$migrations = array_keys($migrations);
......@@ -228,7 +228,7 @@ class MigrateController extends Controller
if (!$this->migrateDown($migration)) {
echo "\nMigration failed. The rest of the migrations are canceled.\n";
return;
return self::EXIT_CODE_ERROR;
}
}
echo "\nMigrated down successfully.\n";
......@@ -249,6 +249,8 @@ class MigrateController extends Controller
* @param integer $limit the number of migrations to be redone. Defaults to 1,
* meaning the last applied migration will be redone.
* @throws Exception if the number of the steps specified is less than 1.
*
* @return integer the status of the action execution. 0 means normal, other values mean abnormal.
*/
public function actionRedo($limit = 1)
{
......@@ -261,7 +263,7 @@ class MigrateController extends Controller
if (empty($migrations)) {
echo "No migration has been done before.\n";
return;
return self::EXIT_CODE_NORMAL;
}
$migrations = array_keys($migrations);
......@@ -277,14 +279,14 @@ class MigrateController extends Controller
if (!$this->migrateDown($migration)) {
echo "\nMigration failed. The rest of the migrations are canceled.\n";
return;
return self::EXIT_CODE_ERROR;
}
}
foreach (array_reverse($migrations) as $migration) {
if (!$this->migrateUp($migration)) {
echo "\nMigration failed. The rest of the migrations migrations are canceled.\n";
return;
return self::EXIT_CODE_ERROR;
}
}
echo "\nMigration redone successfully.\n";
......@@ -365,7 +367,7 @@ class MigrateController extends Controller
echo "The migration history is set at $originalVersion.\nNo actual migration was performed.\n";
}
return;
return self::EXIT_CODE_NORMAL;
}
}
......@@ -387,7 +389,7 @@ class MigrateController extends Controller
}
}
return;
return self::EXIT_CODE_NORMAL;
}
}
......@@ -602,7 +604,7 @@ class MigrateController extends Controller
if (strpos($migration, $version . '_') === 0) {
$this->actionUp($i + 1);
return;
return self::EXIT_CODE_NORMAL;
}
}
......@@ -616,7 +618,7 @@ class MigrateController extends Controller
$this->actionDown($i);
}
return;
return self::EXIT_CODE_NORMAL;
}
}
......
......@@ -77,7 +77,7 @@ class HttpBasicAuth extends AuthMethod
return $identity;
}
} elseif ($username !== null) {
$identity = $user->loginByAccessToken($username);
$identity = $user->loginByAccessToken($username, get_class($this));
if ($identity === null) {
$this->handleFailure($response);
}
......
......@@ -43,7 +43,7 @@ class HttpBearerAuth extends AuthMethod
{
$authHeader = $request->getHeaders()->get('Authorization');
if ($authHeader !== null && preg_match("/^Bearer\\s+(.*?)$/", $authHeader, $matches)) {
$identity = $user->loginByAccessToken($matches[1]);
$identity = $user->loginByAccessToken($matches[1], get_class($this));
if ($identity === null) {
$this->handleFailure($response);
}
......
......@@ -30,7 +30,7 @@ class QueryParamAuth extends AuthMethod
{
$accessToken = $request->get($this->tokenParam);
if (is_string($accessToken)) {
$identity = $user->loginByAccessToken($accessToken);
$identity = $user->loginByAccessToken($accessToken, get_class($this));
if ($identity !== null) {
return $identity;
}
......
......@@ -98,9 +98,9 @@ class GettextMessageSource extends MessageSource
{
$messageFile = Yii::getAlias($this->basePath) . '/' . $language . '/' . $this->catalog;
if ($this->useMoFile) {
$messageFile .= static::MO_FILE_EXT;
$messageFile .= self::MO_FILE_EXT;
} else {
$messageFile .= static::PO_FILE_EXT;
$messageFile .= self::PO_FILE_EXT;
}
return $messageFile;
......
......@@ -21,7 +21,7 @@ use yii\di\Instance;
* The database connection is specified by [[db]]. The database schema could be initialized by applying migration:
*
* ```
* yii migrate --migrationPath=/vendor/yiisoft/yii2/rbac/migrations/
* yii migrate --migrationPath=@yii/rbac/migrations/
* ```
*
* You may change the names of the three tables used to store the authorization data by setting [[itemTable]],
......
<?php
use yii\base\InvalidConfigException;
use yii\db\Schema;
use yii\rbac\DbManager;
class m140506_102106_rbac_init extends \yii\db\Migration
{
/**
* @throws yii\base\InvalidConfigException
* @return DbManager
*/
protected function getAuthManager()
{
$authManager = Yii::$app->getAuthManager();
if (!$authManager instanceof DbManager) {
throw new InvalidConfigException('You should configure "authManager" component to use database before executing this migration.');
}
return $authManager;
}
public function up()
{
$authManager = $this->getAuthManager();
$tableOptions = null;
if ($this->db->driverName === 'mysql') {
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB';
}
$this->createTable('{{%auth_rule}}', [
$this->createTable($authManager->ruleTable, [
'name' => Schema::TYPE_STRING . '(64) NOT NULL',
'data' => Schema::TYPE_TEXT,
'created_at' => Schema::TYPE_INTEGER,
'updated_at' => Schema::TYPE_INTEGER,
'PRIMARY KEY (name)',
], $tableOptions);
$this->addPrimaryKey('pk-auth_rule', '{{%auth_rule}}', 'name');
$this->createTable('{{%auth_item}}', [
$this->createTable($authManager->itemTable, [
'name' => Schema::TYPE_STRING . '(64) NOT NULL',
'type' => Schema::TYPE_INTEGER . ' NOT NULL',
'description' => Schema::TYPE_TEXT,
......@@ -27,33 +44,35 @@ class m140506_102106_rbac_init extends \yii\db\Migration
'data' => Schema::TYPE_TEXT,
'created_at' => Schema::TYPE_INTEGER,
'updated_at' => Schema::TYPE_INTEGER,
'PRIMARY KEY (name)',
'FOREIGN KEY (rule_name) REFERENCES ' . $authManager->ruleTable . ' (name) ON DELETE SET NULL ON UPDATE CASCADE',
], $tableOptions);
$this->addPrimaryKey('pk-auth_item', '{{%auth_item}}', 'name');
$this->addForeignKey('fk-auth_item-rule_name', '{{%auth_item}}', 'rule_name', '{{%auth_rule}}', 'name', 'SET NULL', 'CASCADE');
$this->createIndex('idx-auth_item-type', '{{%auth_item}}', 'type');
$this->createIndex('idx-auth_item-type', $authManager->itemTable, 'type');
$this->createTable('{{%auth_item_child}}', [
$this->createTable($authManager->itemChildTable, [
'parent' => Schema::TYPE_STRING . '(64) NOT NULL',
'child' => Schema::TYPE_STRING . '(64) NOT NULL',
'PRIMARY KEY (parent, child)',
'FOREIGN KEY (parent) REFERENCES ' . $authManager->itemTable . ' (name) ON DELETE CASCADE ON UPDATE CASCADE',
'FOREIGN KEY (child) REFERENCES ' . $authManager->itemTable . ' (name) ON DELETE CASCADE ON UPDATE CASCADE',
], $tableOptions);
$this->addPrimaryKey('pk-auth_item_child', '{{%auth_item_child}}', ['parent', 'child']);
$this->addForeignKey('fk-auth_item_child-parent', '{{%auth_item_child}}', 'parent', '{{%auth_item}}', 'name', 'CASCADE', 'CASCADE');
$this->addForeignKey('fk-auth_item_child-child', '{{%auth_item_child}}', 'child', '{{%auth_item}}', 'name', 'CASCADE', 'CASCADE');
$this->createTable('{{%auth_assignment}}', [
$this->createTable($authManager->assignmentTable, [
'item_name' => Schema::TYPE_STRING . '(64) NOT NULL',
'user_id' => Schema::TYPE_STRING . '(64) NOT NULL',
'created_at' => Schema::TYPE_INTEGER,
'PRIMARY KEY (item_name, user_id)',
'FOREIGN KEY (item_name) REFERENCES ' . $authManager->itemTable . ' (name) ON DELETE CASCADE ON UPDATE CASCADE',
], $tableOptions);
$this->addPrimaryKey('pk-auth_assignment', '{{%auth_assignment}}', ['item_name', 'user_id']);
$this->addForeignKey('fk-auth_assignment-item_name', '{{%auth_assignment}}', 'item_name', '{{%auth_item}}', 'name', 'CASCADE', 'CASCADE');
}
public function down()
{
$this->dropTable('{{%auth_assignment}}');
$this->dropTable('{{%auth_item_child}}');
$this->dropTable('{{%auth_item}}');
$this->dropTable('{{%auth_rule}}');
$authManager = $this->getAuthManager();
$this->dropTable($authManager->assignmentTable);
$this->dropTable($authManager->itemChildTable);
$this->dropTable($authManager->itemTable);
$this->dropTable($authManager->ruleTable);
}
}
......@@ -21,7 +21,7 @@ namespace yii\web;
* return static::findOne($id);
* }
*
* public static function findIdentityByAccessToken($token)
* public static function findIdentityByAccessToken($token, $type = null)
* {
* return static::findOne(['access_token' => $token]);
* }
......@@ -59,11 +59,13 @@ interface IdentityInterface
/**
* Finds an identity by the given secrete token.
* @param string $token the secrete token
* @param mixed $type the type of the token. The value of this parameter depends on the implementation.
* For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`.
* @return IdentityInterface the identity object that matches the given token.
* Null should be returned if such an identity cannot be found
* or the identity is not in an active state (disabled, deleted, etc.)
*/
public static function findIdentityByAccessToken($token);
public static function findIdentityByAccessToken($token, $type = null);
/**
* Returns an ID that can uniquely identify a user identity.
* @return string|integer an ID that uniquely identifies a user identity.
......
......@@ -216,14 +216,16 @@ class User extends Component
* Note that unlike [[login()]], this method will NOT start a session to remember the user authentication status.
* Also if the access token is invalid, the user will remain as a guest.
* @param string $token the access token
* @param mixed $type the type of the token. The value of this parameter depends on the implementation.
* For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`.
* @return IdentityInterface the identity associated with the given access token. Null is returned if
* the access token is invalid.
*/
public function loginByAccessToken($token)
public function loginByAccessToken($token, $type = null)
{
/** @var IdentityInterface $class */
$class = $this->identityClass;
$identity = $class::findIdentityByAccessToken($token);
$identity = $class::findIdentityByAccessToken($token, $type);
$this->setIdentity($identity);
return $identity;
......
......@@ -27,7 +27,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
* @param mixed $default default value to use when param is not set.
* @return mixed the value of the configuration param
*/
public function getParam($name, $default = null)
public static function getParam($name, $default = null)
{
if (static::$params === null) {
static::$params = require(__DIR__ . '/data/config.php');
......
......@@ -14,6 +14,8 @@ use yii\elasticsearch\Command;
*/
class OrderItem extends ActiveRecord
{
public $total;
public function attributes()
{
return ['order_id', 'item_id', 'quantity', 'subtotal'];
......
......@@ -20,7 +20,7 @@ class ElasticSearchConnectionTest extends ElasticSearchTestCase
$connection->open();
$this->assertNotNull($connection->activeNode);
$this->assertArrayHasKey('name', reset($connection->nodes));
$this->assertArrayHasKey('hostname', reset($connection->nodes));
// $this->assertArrayHasKey('hostname', reset($connection->nodes));
$this->assertArrayHasKey('version', reset($connection->nodes));
$this->assertArrayHasKey('http_address', reset($connection->nodes));
}
......
......@@ -17,7 +17,7 @@ class ElasticSearchTestCase extends TestCase
{
$this->mockApplication();
$databases = $this->getParam('databases');
$databases = self::getParam('databases');
$params = isset($databases['elasticsearch']) ? $databases['elasticsearch'] : null;
if ($params === null || !isset($params['dsn'])) {
$this->markTestSkipped('No elasticsearch server connection configured.');
......@@ -40,7 +40,7 @@ class ElasticSearchTestCase extends TestCase
*/
public function getConnection($reset = true)
{
$databases = $this->getParam('databases');
$databases = self::getParam('databases');
$params = isset($databases['elasticsearch']) ? $databases['elasticsearch'] : [];
$db = new Connection();
if ($reset) {
......
......@@ -49,7 +49,7 @@ class QueryBuilderTest extends ElasticSearchTestCase
public function testYiiCanBeFoundByQuery()
{
$this->prepareDbData();
$queryParts = ['field' => ['title' => 'yii']];
$queryParts = ['term' => ['title' => 'yii']];
$query = new Query();
$query->from('yiitest', 'article');
$query->query = $queryParts;
......
......@@ -40,16 +40,16 @@ class QueryTest extends ElasticSearchTestCase
$this->assertEquals(['name', 'status'], $query->fields);
$result = $query->one($this->getConnection());
$this->assertEquals(2, count($result['_source']));
$this->assertArrayHasKey('status', $result['_source']);
$this->assertArrayHasKey('name', $result['_source']);
$this->assertEquals(2, count($result['fields']));
$this->assertArrayHasKey('status', $result['fields']);
$this->assertArrayHasKey('name', $result['fields']);
$this->assertArrayHasKey('_id', $result);
$query->fields([]);
$this->assertEquals([], $query->fields);
$result = $query->one($this->getConnection());
$this->assertEquals([], $result['_source']);
$this->assertArrayNotHasKey('fields', $result);
$this->assertArrayHasKey('_id', $result);
$query->fields(null);
......
......@@ -34,7 +34,7 @@ class MongoDbTestCase extends TestCase
if (!extension_loaded('mongo')) {
$this->markTestSkipped('mongo extension required.');
}
$config = $this->getParam('mongodb');
$config = self::getParam('mongodb');
if (!empty($config)) {
$this->mongoDbConfig = $config;
}
......
......@@ -22,7 +22,7 @@ class RedisCacheTest extends CacheTestCase
*/
protected function getCacheInstance()
{
$databases = $this->getParam('databases');
$databases = self::getParam('databases');
$params = isset($databases['redis']) ? $databases['redis'] : null;
if ($params === null) {
$this->markTestSkipped('No redis server connection configured.');
......
......@@ -15,7 +15,7 @@ abstract class RedisTestCase extends TestCase
{
protected function setUp()
{
$databases = $this->getParam('databases');
$databases = self::getParam('databases');
$params = isset($databases['redis']) ? $databases['redis'] : null;
if ($params === null) {
$this->markTestSkipped('No redis server connection configured.');
......@@ -36,7 +36,7 @@ abstract class RedisTestCase extends TestCase
*/
public function getConnection($reset = true)
{
$databases = $this->getParam('databases');
$databases = self::getParam('databases');
$params = isset($databases['redis']) ? $databases['redis'] : [];
$db = new Connection($params);
if ($reset) {
......
......@@ -48,7 +48,7 @@ class SphinxTestCase extends TestCase
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) {
$this->markTestSkipped('pdo and pdo_mysql extension are required.');
}
$config = $this->getParam('sphinx');
$config = self::getParam('sphinx');
if (!empty($config)) {
$this->sphinxConfig = $config['sphinx'];
$this->dbConfig = $config['db'];
......
......@@ -70,25 +70,6 @@ trait ActiveRecordTestTrait
$this->assertTrue($customers[1] instanceof $customerClass);
$this->assertTrue($customers[2] instanceof $customerClass);
// find all asArray
$customers = $customerClass::find()->asArray()->all();
$this->assertEquals(3, count($customers));
$this->assertArrayHasKey('id', $customers[0]);
$this->assertArrayHasKey('name', $customers[0]);
$this->assertArrayHasKey('email', $customers[0]);
$this->assertArrayHasKey('address', $customers[0]);
$this->assertArrayHasKey('status', $customers[0]);
$this->assertArrayHasKey('id', $customers[1]);
$this->assertArrayHasKey('name', $customers[1]);
$this->assertArrayHasKey('email', $customers[1]);
$this->assertArrayHasKey('address', $customers[1]);
$this->assertArrayHasKey('status', $customers[1]);
$this->assertArrayHasKey('id', $customers[2]);
$this->assertArrayHasKey('name', $customers[2]);
$this->assertArrayHasKey('email', $customers[2]);
$this->assertArrayHasKey('address', $customers[2]);
$this->assertArrayHasKey('status', $customers[2]);
// find by a single primary key
$customer = $customerClass::findOne(2);
$this->assertTrue($customer instanceof $customerClass);
......@@ -136,6 +117,25 @@ trait ActiveRecordTestTrait
'status' => 1,
'profile_id' => null,
], $customer);
// find all asArray
$customers = $customerClass::find()->asArray()->all();
$this->assertEquals(3, count($customers));
$this->assertArrayHasKey('id', $customers[0]);
$this->assertArrayHasKey('name', $customers[0]);
$this->assertArrayHasKey('email', $customers[0]);
$this->assertArrayHasKey('address', $customers[0]);
$this->assertArrayHasKey('status', $customers[0]);
$this->assertArrayHasKey('id', $customers[1]);
$this->assertArrayHasKey('name', $customers[1]);
$this->assertArrayHasKey('email', $customers[1]);
$this->assertArrayHasKey('address', $customers[1]);
$this->assertArrayHasKey('status', $customers[1]);
$this->assertArrayHasKey('id', $customers[2]);
$this->assertArrayHasKey('name', $customers[2]);
$this->assertArrayHasKey('email', $customers[2]);
$this->assertArrayHasKey('address', $customers[2]);
$this->assertArrayHasKey('status', $customers[2]);
}
public function testFindScalar()
......
......@@ -40,7 +40,7 @@ class DbCacheTest extends CacheTestCase
public function getConnection($reset = true)
{
if ($this->_connection === null) {
$databases = $this->getParam('databases');
$databases = self::getParam('databases');
$params = $databases['mysql'];
$db = new \yii\db\Connection;
$db->dsn = $params['dsn'];
......
......@@ -16,7 +16,7 @@ abstract class DatabaseTestCase extends TestCase
protected function setUp()
{
parent::setUp();
$databases = $this->getParam('databases');
$databases = self::getParam('databases');
$this->database = $databases[$this->driverName];
$pdo_database = 'pdo_'.$this->driverName;
......
<?php
namespace yiiunit\framework\rbac;
use Yii;
use yii\console\Application;
use yii\console\Controller;
use yii\console\controllers\MigrateController;
use yii\db\Connection;
use yii\rbac\DbManager;
......@@ -9,70 +13,97 @@ use yii\rbac\DbManager;
*/
abstract class DbManagerTestCase extends ManagerTestCase
{
protected $database;
protected $driverName = 'mysql';
protected static $database;
protected static $driverName = 'mysql';
/**
* @var Connection
*/
protected $db;
protected static $db;
protected function setUp()
protected static function runConsoleAction($route, $params = [])
{
parent::setUp();
$databases = $this->getParam('databases');
$this->database = $databases[$this->driverName];
$pdo_database = 'pdo_'.$this->driverName;
if (Yii::$app === null) {
new Application([
'id' => 'Migrator',
'basePath' => '@yiiunit',
'components' => [
'db' => static::getConnection(),
'authManager' => '\yii\rbac\DbManager',
],
]);
}
ob_start();
$result = Yii::$app->runAction('migrate/up', ['migrationPath' => '@yii/rbac/migrations/', 'interactive' => false]);
echo "Result is ".$result;
if ($result !== Controller::EXIT_CODE_NORMAL) {
ob_end_flush();
} else {
ob_end_clean();
}
}
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
$databases = static::getParam('databases');
static::$database = $databases[static::$driverName];
$pdo_database = 'pdo_' . static::$driverName;
if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) {
$this->markTestSkipped('pdo and '.$pdo_database.' extension are required.');
static::markTestSkipped('pdo and ' . $pdo_database . ' extension are required.');
}
static::runConsoleAction('migrate/up', ['migrationPath' => '@yii/rbac/migrations/', 'interactive' => false]);
}
public static function tearDownAfterClass()
{
static::runConsoleAction('migrate/down', ['migrationPath' => '@yii/rbac/migrations/', 'interactive' => false]);
if (static::$db) {
static::$db->close();
}
Yii::$app = null;
parent::tearDownAfterClass();
}
protected function setUp()
{
parent::setUp();
$this->auth = new DbManager(['db' => $this->getConnection()]);
}
protected function tearDown()
{
parent::tearDown();
if ($this->db) {
$this->db->close();
}
$this->destroyApplication();
$this->auth->removeAll();
}
/**
* @param boolean $reset whether to clean up the test database
* @param boolean $open whether to open and populate test database
* @throws \yii\base\InvalidParamException
* @throws \yii\db\Exception
* @throws \yii\base\InvalidConfigException
* @return \yii\db\Connection
*/
public function getConnection($reset = true, $open = true)
public static function getConnection()
{
if (!$reset && $this->db) {
return $this->db;
}
$db = new Connection;
$db->dsn = $this->database['dsn'];
if (isset($this->database['username'])) {
$db->username = $this->database['username'];
$db->password = $this->database['password'];
}
if (isset($this->database['attributes'])) {
$db->attributes = $this->database['attributes'];
}
if ($open) {
$db->open();
$lines = explode(';', file_get_contents(\Yii::getAlias('@yii/rbac/schema-'.$this->driverName.'.sql')));
foreach ($lines as $line) {
if (trim($line) !== '') {
$db->pdo->exec($line);
}
if (static::$db == null) {
$db = new Connection;
$db->dsn = static::$database['dsn'];
if (isset(static::$database['username'])) {
$db->username = static::$database['username'];
$db->password = static::$database['password'];
}
if (isset(static::$database['attributes'])) {
$db->attributes = static::$database['attributes'];
}
if (!$db->isActive) {
$db->open();
}
static::$db = $db;
}
$this->db = $db;
return $db;
return static::$db;
}
}
......@@ -6,5 +6,5 @@ namespace yiiunit\framework\rbac;
*/
class PgSQLManagerTest extends DbManagerTestCase
{
protected $driverName = 'pgsql';
protected static $driverName = 'pgsql';
}
......@@ -6,5 +6,5 @@ namespace yiiunit\framework\rbac;
*/
class SqliteManagerTest extends DbManagerTestCase
{
protected $driverName = 'sqlite';
protected static $driverName = 'sqlite';
}
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