Commit 70cebf25 by Tobias Munk

Merge commit 'beafb99e' into feature/toolbar-ui-2

Conflicts: extensions/debug/Module.php
parents e4f0e800 beafb99e
......@@ -16,7 +16,7 @@ namespace frontend\widgets;
* - \Yii::$app->getSession()->setFlash('info', 'This is the message');
*
* @author Kartik Visweswaran <kartikv2@gmail.com>
* @author Alexander Makarov <sam@rmcerative.ru>
* @author Alexander Makarov <sam@rmcreative.ru>
*/
class Alert extends \yii\bootstrap\Widget
{
......
......@@ -15,6 +15,8 @@ modules:
- PhpBrowser
# you can use WebDriver instead of PhpBrowser to test javascript and ajax.
# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium
# "restart" option is used by the WebDriver to start each time per test-file new session and cookies,
# it is useful if you want to login in your app in each test.
# - WebDriver
config:
PhpBrowser:
......@@ -22,3 +24,4 @@ modules:
# WebDriver:
# url: 'http://localhost'
# browser: firefox
# restart: true
......@@ -33,7 +33,7 @@ the installed application. You only need to do these once for all.
```
php /path/to/yii-application/init
```
2. Create a new database and adjust the `components.db` configuration in `common/config/params-local.php` accordingly.
2. Create a new database and adjust the `components.db` configuration in `common/config/main-local.php` accordingly.
3. Apply migrations with console command `yii migrate`.
4. Set document roots of your Web server:
......
......@@ -38,14 +38,12 @@ class Module extends \yii\base\Module
*/
public $logTarget;
/**
* @var array|Panel[]
* @var array list of debug panels. The array keys are the panel IDs, and values are the corresponding
* panel class names or configuration arrays. This will be merged with [[corePanels()]].
* You may set a panel to be false to disable a core panel.
*/
public $panels = [];
/**
* @var string postion of the custom configured panels 'begin' or 'end'
*/
public $panelsPosition = 'end';
/**
* @var string the directory storing the debugger data files. This can be specified using a path alias.
*/
public $dataPath = '@runtime/debug';
......@@ -78,15 +76,7 @@ class Module extends \yii\base\Module
Yii::$app->getView()->on(View::EVENT_END_BODY, [$this, 'renderToolbar']);
});
switch ($this->panelsPosition) {
case 'begin':
$this->panels = ArrayHelper::merge($this->panels, $this->corePanels());
break;
case 'end':
default:
$this->panels = ArrayHelper::merge($this->corePanels(), $this->panels);
break;
}
$this->panels = array_filter(ArrayHelper::merge($this->corePanels(), $this->panels));
foreach ($this->panels as $id => $config) {
$config['module'] = $this;
$config['id'] = $id;
......
......@@ -5,6 +5,7 @@ Yii Framework 2 elasticsearch extension Change Log
----------------------------
- Bug #1993: afterFind event in AR is now called after relations have been populated (cebe, creocoder)
- Bug #2324: Fixed QueryBuilder bug when building a query with "query" option (mintao)
- Enh #1313: made index and type available in `ActiveRecord::instantiate()` to allow creating records based on elasticsearch type when doing cross index/type search (cebe)
- Enh #1382: Added a debug toolbar panel for elasticsearch (cebe)
- Enh #1765: Added support for primary key path mapping, pk can now be part of the attributes when mapping is defined (cebe)
......
......@@ -55,8 +55,10 @@ class QueryBuilder extends \yii\base\Object
$parts['from'] = (int) $query->offset;
}
if (empty($parts['query'])) {
if (empty($query->query)) {
$parts['query'] = ["match_all" => (object)[]];
} else {
$parts['query'] = $query->query;
}
$whereFilter = $this->buildCondition($query->where);
......
......@@ -5,6 +5,7 @@ Yii Framework 2 gii extension Change Log
----------------------------
- Bug #1405: fixed disambiguation of relation names generated by gii (qiangxue)
- Bug #1904: Fixed autocomplete to work with underscore inputs "_" (tonydspaniard)
- Bug #2298: Fixed the bug that Gii controller generator did not allow digit in the controller ID (qiangxue)
- Bug: fixed controller in crud template to avoid returning query in findModel() (cebe)
- Enh #1624: generate rules for unique indexes (lucianobaraglia)
......
......@@ -71,6 +71,15 @@ yii.gii = (function ($) {
};
return {
autocomplete: function (counter, data) {
var datum = new Bloodhound({
datumTokenizer: function(d){return Bloodhound.tokenizers.whitespace(d.word);},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data
});
datum.initialize();
jQuery('.typeahead-'+counter).typeahead(null,{displayKey: 'word', source: datum.ttAdapter()});
},
init: function () {
initHintBlocks();
initStickyInputs();
......
......@@ -63,7 +63,10 @@ class ActiveField extends \yii\widgets\ActiveField
{
static $counter = 0;
$this->inputOptions['class'] .= ' typeahead-' . (++$counter);
$this->form->getView()->registerJs("jQuery('.typeahead-{$counter}').typeahead({local: " . Json::encode($data) . "});");
foreach ($data as &$item) {
$item = array('word' => $item);
}
$this->form->getView()->registerJs("yii.gii.autocomplete($counter, " . Json::encode($data) . ");");
return $this;
}
}
......@@ -44,6 +44,7 @@ Yii Framework 2 Change Log
- Bug #2212: `yii\gridview\DataColumn` generates incorrect labels when used with nosql DB and there is no data (qiangxue)
- Bug #2298: Fixed the bug that Gii controller generator did not allow digit in the controller ID (qiangxue)
- Bug #2303: Fixed the bug that `yii\base\Theme::pathMap` did not support dynamic update with path aliases (qiangxue)
- Bug #2324: Fixed QueryBuilder bug when building a query with "query" option (mintao)
- Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark)
- Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark)
- Bug: Json::encode() did not handle objects that implement JsonSerializable interface correctly (cebe)
......@@ -162,6 +163,7 @@ Yii Framework 2 Change Log
- Chg: Renamed `yii\web\Request::acceptedLanguages` to `acceptableLanguages` (qiangxue)
- Chg: Removed implementation of `Arrayable` from `yii\Object` (qiangxue)
- Chg: Renamed `ActiveRecordInterface::createActiveRelation()` to `createRelation()` (qiangxue)
- Chg: The scripts in asset bundles are now registered in `View` at the end of `endBody()`. It was done in `endPage()` previously (qiangxue)
- New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul)
- New #706: Added `yii\widgets\Pjax` and enhanced `GridView` to work with `Pjax` to support AJAX-update (qiangxue)
- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo)
......
......@@ -61,17 +61,23 @@
applyFilter: function () {
var $grid = $(this);
var settings = $grid.data('yiiGridView').settings;
var data = $(settings.filterSelector).serialize();
var url = settings.filterUrl;
if (url.indexOf('?') >= 0) {
url += '&' + data;
} else {
url += '?' + data;
}
var data = {};
$.each($(settings.filterSelector).serializeArray(), function () {
data[this.name] = this.value;
});
$.each(yii.getQueryParams(settings.filterUrl), function (name, value) {
if (data[name] === undefined) {
data[name] = value;
}
});
var pos = settings.filterUrl.indexOf('?');
var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos);
$grid.find('form.gridview-filter-form').remove();
var $form = $('<form action="' + url + '" method="get" class="gridview-filter-form" style="display:none" data-pjax></form>').appendTo($grid);
$.each(yii.getQueryParams(url), function (name, value) {
$.each(data, function (name, value) {
$form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value));
});
$form.submit();
......
......@@ -222,7 +222,7 @@ class FixtureController extends Controller
*/
private function notifyUnloaded($fixtures)
{
$this->stdout("Fixtures were successfully loaded from namespace:\n", Console::FG_YELLOW);
$this->stdout("Fixtures were successfully unloaded from namespace:\n", Console::FG_YELLOW);
$this->stdout("\t\"" . Yii::getAlias($this->namespace) . "\"\n\n", Console::FG_GREEN);
$this->outputList($fixtures);
}
......
......@@ -95,7 +95,10 @@ class Query extends Component implements QueryInterface
public $having;
/**
* @var array this is used to construct the UNION clause(s) in a SQL statement.
* Each array element can be either a string or a [[Query]] object representing a sub-query.
* Each array element is an array of the following structure:
*
* - `query`: either a string or a [[Query]] object representing a query
* - `all`: boolean, whether it should be `UNION ALL` or `UNION`
*/
public $union;
/**
......
......@@ -767,8 +767,11 @@ class QueryBuilder extends \yii\base\Object
if ($query instanceof Query) {
// save the original parameters so that we can restore them later to prevent from modifying the query object
$originalParams = $query->params;
$query->addParams($params);
list ($unions[$i]['query'], $params) = $this->build($query);
$command = $query->createCommand($this->db);
$unions[$i]['query'] = $command->sql;
foreach ($command->params as $name => $value) {
$params[$name] = $value;
}
$query->params = $originalParams;
}
......@@ -1107,11 +1110,18 @@ class QueryBuilder extends \yii\base\Object
* @param array $operands contains only one element which is a [[Query]] object representing the sub-query.
* @param array $params the binding parameters to be populated
* @return string the generated SQL expression
* @throws InvalidParamException if the operand is not a [[Query]] object.
*/
public function buildExistsCondition($operator, $operands, &$params)
{
$subQuery = $operands[0];
list($subQuerySql, $subQueryParams) = $this->build($subQuery);
if (!$subQuery instanceof Query) {
throw new InvalidParamException('Subquery for EXISTS operator must be a Query object.');
}
$command = $subQuery->createCommand($this->db);
$subQuerySql = $command->sql;
$subQueryParams = $command->params;
if (!empty($subQueryParams)) {
foreach ($subQueryParams as $name => $value) {
$params[$name] = $value;
......
......@@ -127,6 +127,58 @@ class View extends \yii\base\View
private $_assetManager;
/**
* Marks the position of an HTML head section.
*/
public function head()
{
echo self::PH_HEAD;
}
/**
* Marks the beginning of an HTML body section.
*/
public function beginBody()
{
echo self::PH_BODY_BEGIN;
$this->trigger(self::EVENT_BEGIN_BODY);
}
/**
* Marks the ending of an HTML body section.
*/
public function endBody()
{
$this->trigger(self::EVENT_END_BODY);
echo self::PH_BODY_END;
foreach (array_keys($this->assetBundles) as $bundle) {
$this->registerAssetFiles($bundle);
}
}
/**
* Marks the ending of an HTML page.
* @param boolean $ajaxMode whether the view is rendering in AJAX mode.
* If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
* will be rendered at the end of the view like normal scripts.
*/
public function endPage($ajaxMode = false)
{
$this->trigger(self::EVENT_END_PAGE);
$content = ob_get_clean();
echo strtr($content, [
self::PH_HEAD => $this->renderHeadHtml(),
self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode),
]);
$this->clear();
}
/**
* Renders a view in response to an AJAX request.
*
......@@ -178,29 +230,6 @@ class View extends \yii\base\View
}
/**
* Marks the ending of an HTML page.
* @param boolean $ajaxMode whether the view is rendering in AJAX mode.
* If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
* will be rendered at the end of the view like normal scripts.
*/
public function endPage($ajaxMode = false)
{
$this->trigger(self::EVENT_END_PAGE);
$content = ob_get_clean();
foreach (array_keys($this->assetBundles) as $bundle) {
$this->registerAssetFiles($bundle);
}
echo strtr($content, [
self::PH_HEAD => $this->renderHeadHtml(),
self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode),
]);
$this->clear();
}
/**
* Clears up the registered meta tags, link tags, css/js scripts and files.
*/
public function clear()
......@@ -234,32 +263,6 @@ class View extends \yii\base\View
}
/**
* Marks the beginning of an HTML body section.
*/
public function beginBody()
{
echo self::PH_BODY_BEGIN;
$this->trigger(self::EVENT_BEGIN_BODY);
}
/**
* Marks the ending of an HTML body section.
*/
public function endBody()
{
$this->trigger(self::EVENT_END_BODY);
echo self::PH_BODY_END;
}
/**
* Marks the position of an HTML head section.
*/
public function head()
{
echo self::PH_HEAD;
}
/**
* Registers the named asset bundle.
* All dependent asset bundles will be registered.
* @param string $name the name of the asset bundle.
......
......@@ -66,7 +66,9 @@ class Pjax extends Widget
*/
public $enableReplaceState = false;
/**
* @var integer pjax timeout setting (in milliseconds)
* @var integer pjax timeout setting (in milliseconds). This timeout is used when making AJAX requests.
* Use a bigger number if your server is slow. If the server does not respond within the timeout,
* a full page load will be triggered.
*/
public $timeout = 1000;
/**
......@@ -89,15 +91,17 @@ class Pjax extends Widget
$this->options['id'] = $this->getId();
}
ob_start();
ob_implicit_flush(false);
if ($this->requiresPjax()) {
ob_start();
ob_implicit_flush(false);
$view = $this->getView();
$view->clear();
$view->beginPage();
$view->head();
$view->beginBody();
if ($view->title !== null) {
echo Html::tag('title', Html::encode($view->title));
}
}
echo Html::beginTag('div', $this->options);
}
......@@ -108,32 +112,37 @@ class Pjax extends Widget
public function run()
{
echo Html::endTag('div');
if ($requiresPjax = $this->requiresPjax()) {
$view = $this->getView();
$view->endBody();
$view->endPage(true);
if (!$this->requiresPjax()) {
$this->registerClientScript();
return;
}
$view = $this->getView();
$view->endBody();
// Do not re-send css files as it may override the css files that were loaded after them.
// This is a temporary fix for https://github.com/yiisoft/yii2/issues/2310
// It should be removed once pjax supports loading only missing css files
$view->cssFiles = null;
$view->endPage(true);
$content = ob_get_clean();
if ($requiresPjax) {
// only need the content enclosed within this widget
$response = Yii::$app->getResponse();
$level = ob_get_level();
$response->clearOutputBuffers();
$response->setStatusCode(200);
$response->format = Response::FORMAT_HTML;
$response->content = $content;
$response->send();
// only need the content enclosed within this widget
$response = Yii::$app->getResponse();
$level = ob_get_level();
$response->clearOutputBuffers();
$response->setStatusCode(200);
$response->format = Response::FORMAT_HTML;
$response->content = $content;
$response->send();
// re-enable output buffer to capture content after this widget
for (; $level > 0; --$level) {
ob_start();
ob_implicit_flush(false);
}
} else {
$this->registerClientScript();
echo $content;
// re-enable output buffer to capture content after this widget
for (; $level > 0; --$level) {
ob_start();
ob_implicit_flush(false);
}
}
......@@ -162,7 +171,7 @@ class Pjax extends Widget
$view = $this->getView();
PjaxAsset::register($view);
$js = "jQuery(document).pjax($linkSelector, \"#$id\", $options);";
$js .= "\njQuery(document).on('submit', $formSelector, function (event) {jQuery.pjax.submit(event, '#$id');});";
$js .= "\njQuery(document).on('submit', $formSelector, function (event) {jQuery.pjax.submit(event, '#$id', $options);});";
$view->registerJs($js);
}
}
<?php
namespace yiiunit\extensions\elasticsearch;
use yii\elasticsearch\Query;
use yii\elasticsearch\QueryBuilder;
/**
* @group elasticsearch
*/
class QueryBuilderTest extends ElasticSearchTestCase
{
public function setUp()
{
parent::setUp();
$command = $this->getConnection()->createCommand();
// delete index
if ($command->indexExists('yiitest')) {
$command->deleteIndex('yiitest');
}
}
private function prepareDbData()
{
$command = $this->getConnection()->createCommand();
$command->insert('yiitest', 'article', ['title' => 'I love yii!'], 1);
$command->insert('yiitest', 'article', ['title' => 'Symfony2 is another framework'], 2);
$command->insert('yiitest', 'article', ['title' => 'Yii2 out now!'], 3);
$command->insert('yiitest', 'article', ['title' => 'yii test'], 4);
$command->flushIndex('yiitest');
}
public function testQueryBuilderRespectsQuery()
{
$queryParts = ['field' => ['title' => 'yii']];
$queryBuilder = new QueryBuilder($this->getConnection());
$query = new Query();
$query->query = $queryParts;
$build = $queryBuilder->build($query);
$this->assertTrue(array_key_exists('queryParts', $build));
$this->assertTrue(array_key_exists('query', $build['queryParts']));
$this->assertFalse(array_key_exists('match_all', $build['queryParts']), 'Match all should not be set');
$this->assertSame($queryParts, $build['queryParts']['query']);
}
public function testYiiCanBeFoundByQuery()
{
$this->prepareDbData();
$queryParts = ['field' => ['title' => 'yii']];
$query = new Query();
$query->from('yiitest', 'article');
$query->query = $queryParts;
$result = $query->search($this->getConnection());
$this->assertEquals(2, $result['hits']['total']);
}
public function testFuzzySearch()
{
$this->prepareDbData();
$queryParts = [
"fuzzy_like_this" => [
"fields" => ["title"],
"like_text" => "Similar to YII",
"max_query_terms" => 4
]
];
$query = new Query();
$query->from('yiitest', 'article');
$query->query = $queryParts;
$result = $query->search($this->getConnection());
$this->assertEquals(3, $result['hits']['total']);
}
}
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