diff --git a/apps/advanced/README.md b/apps/advanced/README.md
index 520c83a..a512e17 100644
--- a/apps/advanced/README.md
+++ b/apps/advanced/README.md
@@ -70,7 +70,7 @@ at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix).
You can then install the application using the following command:
~~~
-php composer.phar create-project --stability=alpha yiisoft/yii2-app-advanced advanced
+php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced advanced
~~~
diff --git a/apps/basic/README.md b/apps/basic/README.md
index ee6e8ae..d1a17e2 100644
--- a/apps/basic/README.md
+++ b/apps/basic/README.md
@@ -52,7 +52,7 @@ at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix).
You can then install this application template using the following command:
~~~
-php composer.phar create-project --stability=alpha yiisoft/yii2-app-basic basic
+php composer.phar create-project --stability=dev yiisoft/yii2-app-basic basic
~~~
Now you should be able to access the application through the following URL, assuming `basic` is the directory
diff --git a/apps/basic/requirements.php b/apps/basic/requirements.php
index 47bdf37..84ae427 100644
--- a/apps/basic/requirements.php
+++ b/apps/basic/requirements.php
@@ -48,6 +48,13 @@ $requirements = [
'by' => 'All DB-related classes',
'memo' => 'Required for MySQL database.',
],
+ [
+ 'name' => 'PDO PostgreSQL extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('pdo_pgsql'),
+ 'by' => 'All DB-related classes',
+ 'memo' => 'Required for PostgreSQL database.',
+ ],
// Cache :
[
'name' => 'Memcache extension',
diff --git a/docs/guide/controller.md b/docs/guide/controller.md
index 97ffe49..584c738 100644
--- a/docs/guide/controller.md
+++ b/docs/guide/controller.md
@@ -125,7 +125,7 @@ class BlogController extends Controller
throw new NotFoundHttpException;
}
- if (\Yii::$app->request->isPost)) {
+ if (\Yii::$app->request->isPost) {
$post->load($_POST);
if ($post->save()) {
$this->redirect(['view', 'id' => $post->id]);
diff --git a/docs/guide/url.md b/docs/guide/url.md
index e54be4b..c11e8cd 100644
--- a/docs/guide/url.md
+++ b/docs/guide/url.md
@@ -2,8 +2,8 @@ URL Management
==============
The concept of URL management in Yii fairly simple. URL management is based on the premise that the application uses internal routes and parameters
-everywhere. The framework itself will then translates routes into URLs, and translate URLs into routs, according to the URL manager's configuration.
-This approach allows you to change site-wide URLs merely by edited a single config file, without ever touching the application code.
+everywhere. The framework itself will then translates routes into URLs, and translate URLs into routes, according to the URL manager's configuration.
+This approach allows you to change site-wide URLs merely by editing a single config file, without ever touching the application code.
Internal route
--------------
diff --git a/extensions/debug/Module.php b/extensions/debug/Module.php
index 8a20021..6c1e6e0 100644
--- a/extensions/debug/Module.php
+++ b/extensions/debug/Module.php
@@ -61,7 +61,8 @@ class Module extends \yii\base\Module
Yii::$app->getView()->on(View::EVENT_END_BODY, [$this, 'renderToolbar']);
});
- foreach (array_merge($this->corePanels(), $this->panels) as $id => $config) {
+ $this->panels = array_merge($this->corePanels(), $this->panels);
+ foreach ($this->panels as $id => $config) {
$config['module'] = $this;
$config['id'] = $id;
$this->panels[$id] = Yii::createObject($config);
diff --git a/extensions/debug/Panel.php b/extensions/debug/Panel.php
index 055dbba..ebfa8b3 100644
--- a/extensions/debug/Panel.php
+++ b/extensions/debug/Panel.php
@@ -31,6 +31,12 @@ class Panel extends Component
*/
public $module;
public $data;
+ /**
+ * @var array array of actions to add to the debug modules default controller.
+ * This array will be merged with all other panels actions property.
+ * See [[yii\base\Controller::actions()]] for the format.
+ */
+ public $actions = [];
/**
* @return string name of the panel
diff --git a/extensions/debug/controllers/DefaultController.php b/extensions/debug/controllers/DefaultController.php
index 6694d26..0c8d6e9 100644
--- a/extensions/debug/controllers/DefaultController.php
+++ b/extensions/debug/controllers/DefaultController.php
@@ -27,6 +27,15 @@ class DefaultController extends Controller
*/
public $summary;
+ public function actions()
+ {
+ $actions = [];
+ foreach($this->module->panels as $panel) {
+ $actions = array_merge($actions, $panel->actions);
+ }
+ return $actions;
+ }
+
public function actionIndex()
{
return $this->render('index', ['manifest' => $this->getManifest()]);
@@ -82,7 +91,7 @@ class DefaultController extends Controller
return $this->_manifest;
}
- protected function loadData($tag)
+ public function loadData($tag)
{
$manifest = $this->getManifest();
if (isset($manifest[$tag])) {
diff --git a/extensions/elasticsearch/Command.php b/extensions/elasticsearch/Command.php
index 916d597..4b7b0a7 100644
--- a/extensions/elasticsearch/Command.php
+++ b/extensions/elasticsearch/Command.php
@@ -94,7 +94,7 @@ class Command extends Component
*/
public function get($index, $type, $id, $options = [])
{
- return $this->db->get([$index, $type, $id], $options, null, [200, 404]);
+ return $this->db->get([$index, $type, $id], $options, null);
}
/**
diff --git a/extensions/elasticsearch/Connection.php b/extensions/elasticsearch/Connection.php
index 098d6ee..75de7a3 100644
--- a/extensions/elasticsearch/Connection.php
+++ b/extensions/elasticsearch/Connection.php
@@ -177,10 +177,10 @@ class Connection extends Component
return new QueryBuilder($this);
}
- public function get($url, $options = [], $body = null)
+ public function get($url, $options = [], $body = null, $raw = false)
{
$this->open();
- return $this->httpRequest('GET', $this->createUrl($url, $options), $body);
+ return $this->httpRequest('GET', $this->createUrl($url, $options), $body, $raw);
}
public function head($url, $options = [], $body = null)
@@ -189,37 +189,43 @@ class Connection extends Component
return $this->httpRequest('HEAD', $this->createUrl($url, $options), $body);
}
- public function post($url, $options = [], $body = null)
+ public function post($url, $options = [], $body = null, $raw = false)
{
$this->open();
- return $this->httpRequest('POST', $this->createUrl($url, $options), $body);
+ return $this->httpRequest('POST', $this->createUrl($url, $options), $body, $raw);
}
- public function put($url, $options = [], $body = null)
+ public function put($url, $options = [], $body = null, $raw = false)
{
$this->open();
- return $this->httpRequest('PUT', $this->createUrl($url, $options), $body);
+ return $this->httpRequest('PUT', $this->createUrl($url, $options), $body, $raw);
}
- public function delete($url, $options = [], $body = null)
+ public function delete($url, $options = [], $body = null, $raw = false)
{
$this->open();
- return $this->httpRequest('DELETE', $this->createUrl($url, $options), $body);
+ return $this->httpRequest('DELETE', $this->createUrl($url, $options), $body, $raw);
}
private function createUrl($path, $options = [])
{
- $url = implode('/', array_map(function($a) {
- return urlencode(is_array($a) ? implode(',', $a) : $a);
- }, $path));
-
- if (!empty($options)) {
- $url .= '?' . http_build_query($options);
+ if (!is_string($path)) {
+ $url = implode('/', array_map(function($a) {
+ return urlencode(is_array($a) ? implode(',', $a) : $a);
+ }, $path));
+ if (!empty($options)) {
+ $url .= '?' . http_build_query($options);
+ }
+ } else {
+ $url = $path;
+ if (!empty($options)) {
+ $url .= (strpos($url, '?') === false ? '?' : '&') . http_build_query($options);
+ }
}
return [$this->nodes[$this->activeNode]['http_address'], $url];
}
- protected function httpRequest($method, $url, $requestBody = null)
+ protected function httpRequest($method, $url, $requestBody = null, $raw = false)
{
$method = strtoupper($method);
@@ -228,7 +234,7 @@ class Connection extends Component
$body = '';
$options = [
- CURLOPT_USERAGENT => 'Yii2 Framework ' . __CLASS__,
+ CURLOPT_USERAGENT => 'Yii Framework 2 ' . __CLASS__,
CURLOPT_RETURNTRANSFER => false,
CURLOPT_HEADER => false,
// http://www.php.net/manual/en/function.curl-setopt.php#82418
@@ -264,8 +270,11 @@ class Connection extends Component
if (is_array($url)) {
list($host, $q) = $url;
- if (strncmp($host, 'inet[/', 6) == 0) {
- $host = substr($host, 6, -1);
+ if (strncmp($host, 'inet[', 5) == 0) {
+ $host = substr($host, 5, -1);
+ if (($pos = strpos($host, '/')) !== false) {
+ $host = substr($host, $pos + 1);
+ }
}
$profile = $method . ' ' . $q . '#' . $requestBody;
$url = 'http://' . $host . '/' . $q;
@@ -312,7 +321,7 @@ class Connection extends Component
]);
}
if (isset($headers['content-type']) && !strncmp($headers['content-type'], 'application/json', 16)) {
- return Json::decode($body);
+ return $raw ? $body : Json::decode($body);
}
throw new Exception('Unsupported data received from elasticsearch: ' . $headers['content-type'], [
'requestMethod' => $method,
diff --git a/extensions/elasticsearch/DebugAction.php b/extensions/elasticsearch/DebugAction.php
new file mode 100644
index 0000000..d4ddd41
--- /dev/null
+++ b/extensions/elasticsearch/DebugAction.php
@@ -0,0 +1,76 @@
+
+ */
+
+namespace yii\elasticsearch;
+
+
+use yii\base\Action;
+use yii\base\NotSupportedException;
+use yii\debug\Panel;
+use yii\helpers\ArrayHelper;
+use yii\web\HttpException;
+use Yii;
+use yii\web\Response;
+
+class DebugAction extends Action
+{
+ /**
+ * @var string the connection id to use
+ */
+ public $db;
+ /**
+ * @var Panel
+ */
+ public $panel;
+
+ public function run($logId, $tag)
+ {
+ $this->controller->loadData($tag);
+
+ $timings = $this->panel->calculateTimings();
+ ArrayHelper::multisort($timings, 3, SORT_DESC);
+ if (!isset($timings[$logId])) {
+ throw new HttpException(404, 'Log message not found.');
+ }
+ $message = $timings[$logId][1];
+ if (($pos = mb_strpos($message, "#")) !== false) {
+ $url = mb_substr($message, 0, $pos);
+ $body = mb_substr($message, $pos + 1);
+ } else {
+ $url = $message;
+ $body = null;
+ }
+ $method = mb_substr($url, 0, $pos = mb_strpos($url, ' '));
+ $url = mb_substr($url, $pos + 1);
+
+ $options = ['pretty' => true];
+
+ /** @var Connection $db */
+ $db = \Yii::$app->getComponent($this->db);
+ $time = microtime(true);
+ switch($method) {
+ case 'GET': $result = $db->get($url, $options, $body, true); break;
+ case 'POST': $result = $db->post($url, $options, $body, true); break;
+ case 'PUT': $result = $db->put($url, $options, $body, true); break;
+ case 'DELETE': $result = $db->delete($url, $options, $body, true); break;
+ case 'HEAD': $result = $db->head($url, $options, $body); break;
+ default:
+ throw new NotSupportedException("Request method '$method' is not supported by elasticsearch.");
+ }
+ $time = microtime(true) - $time;
+
+ if ($result === true) {
+ $result = 'success';
+ } elseif ($result === false) {
+ $result = 'no success';
+ }
+
+ Yii::$app->response->format = Response::FORMAT_JSON;
+ return [
+ 'time' => sprintf('%.1f ms', $time * 1000),
+ 'result' => $result,
+ ];
+ }
+}
\ No newline at end of file
diff --git a/extensions/elasticsearch/DebugPanel.php b/extensions/elasticsearch/DebugPanel.php
index da5a824..1782b8d 100644
--- a/extensions/elasticsearch/DebugPanel.php
+++ b/extensions/elasticsearch/DebugPanel.php
@@ -8,6 +8,7 @@
namespace yii\elasticsearch;
use yii\debug\Panel;
+use yii\helpers\ArrayHelper;
use yii\log\Logger;
use yii\helpers\Html;
use yii\web\View;
@@ -20,6 +21,17 @@ use yii\web\View;
*/
class DebugPanel extends Panel
{
+ public $db = 'elasticsearch';
+
+ public function init()
+ {
+ $this->actions['elasticsearch-query'] = [
+ 'class' => 'yii\\elasticsearch\\DebugAction',
+ 'panel' => $this,
+ 'db' => $this->db,
+ ];
+ }
+
public function getName()
{
return 'Elasticsearch';
@@ -47,13 +59,14 @@ EOD;
public function getDetail()
{
+ $timings = $this->calculateTimings();
+ ArrayHelper::multisort($timings, 3, SORT_DESC);
$rows = [];
$i = 0;
- foreach ($this->data['messages'] as $log) {
- list ($message, $level, $category, $time, $traces) = $log;
- if ($level == Logger::LEVEL_PROFILE_BEGIN) {
- continue;
- }
+ foreach ($timings as $logId => $timing) {
+ $duration = sprintf('%.1f ms', $timing[3] * 1000);
+ $message = $timing[1];
+ $traces = $timing[4];
if (($pos = mb_strpos($message, "#")) !== false) {
$url = mb_substr($message, 0, $pos);
$body = mb_substr($message, $pos + 1);
@@ -66,48 +79,43 @@ EOD;
$traceString .= Html::ul($traces, [
'class' => 'trace',
'item' => function ($trace) {
- return "
{$trace['file']}({$trace['line']})";
- },
+ return "{$trace['file']}({$trace['line']})";
+ },
]);
}
- $runLinks = '';
- $c = 0;
- \Yii::$app->elasticsearch->open();
- foreach(\Yii::$app->elasticsearch->nodes as $node) {
- $pos = mb_strpos($url, ' ');
- $type = mb_substr($url, 0, $pos);
- if ($type == 'GET' && !empty($body)) {
- $type = 'POST';
- }
- $host = $node['http_address'];
- if (strncmp($host, 'inet[/', 6) == 0) {
- $host = substr($host, 6, -1);
- }
- $nodeUrl = 'http://' . $host . '/' . mb_substr($url, $pos + 1);
- $nodeUrl .= (strpos($nodeUrl, '?') === false) ? '?pretty=true' : '&pretty=true';
- $nodeBody = json_encode($body);
- \Yii::$app->view->registerJs(<< $logId, 'tag' => $this->tag]);
+ \Yii::$app->view->registerJs(<<Error: ' + errorThrown + ' - ' + textStatus + '
' + jqXHR.responseText);
+ },
+ dataType: "json"
});
return false;
});
JS
, View::POS_READY);
- $runLinks .= Html::a(isset($node['name']) ? $node['name'] : $node['http_address'], '#', ['id' => "elastic-link-$i-$c"]) . '
';
- $c++;
- }
- $rows[] = " | $runLinks |
|
";
+ $runLink = Html::a('run query', '#', ['id' => "elastic-link-$i"]) . '
';
+ $rows[] = <<
+ $duration |
+ |
+ $runLink |
+
+ | |
+HTML;
$i++;
}
$rows = implode("\n", $rows);
@@ -117,8 +125,9 @@ JS
- Url / Query |
- Run Query on node |
+ Time |
+ Url / Query |
+ Run Query on node |
@@ -130,7 +139,7 @@ HTML;
private $_timings;
- protected function calculateTimings()
+ public function calculateTimings()
{
if ($this->_timings !== null) {
return $this->_timings;
diff --git a/extensions/elasticsearch/README-debug.png b/extensions/elasticsearch/README-debug.png
new file mode 100644
index 0000000..8877a60
Binary files /dev/null and b/extensions/elasticsearch/README-debug.png differ
diff --git a/extensions/elasticsearch/README.md b/extensions/elasticsearch/README.md
index 2a07155..ecbf633 100644
--- a/extensions/elasticsearch/README.md
+++ b/extensions/elasticsearch/README.md
@@ -172,3 +172,5 @@ Add the following to you application config to enable it:
],
// ...
```
+
+![elasticsearch DebugPanel](README-debug.png)
\ No newline at end of file
diff --git a/extensions/gii/generators/crud/Generator.php b/extensions/gii/generators/crud/Generator.php
index 4b31d70..b126c7b 100644
--- a/extensions/gii/generators/crud/Generator.php
+++ b/extensions/gii/generators/crud/Generator.php
@@ -348,7 +348,6 @@ class Generator extends \yii\gii\Generator
case Schema::TYPE_TIME:
case Schema::TYPE_DATETIME:
case Schema::TYPE_TIMESTAMP:
- case
$conditions[] = "\$this->addCondition(\$query, '{$column}');";
break;
default:
diff --git a/extensions/gii/generators/model/Generator.php b/extensions/gii/generators/model/Generator.php
index cd2fcbf..591cb3b 100644
--- a/extensions/gii/generators/model/Generator.php
+++ b/extensions/gii/generators/model/Generator.php
@@ -397,10 +397,10 @@ class Generator extends \yii\gii\Generator
}
$name = $rawName = Inflector::id2camel($key, '_');
$i = 0;
- while (isset($table->columns[$name])) {
+ while (isset($table->columns[lcfirst($name)])) {
$name = $rawName . ($i++);
}
- while (isset($relations[$className][$name])) {
+ while (isset($relations[$className][lcfirst($name)])) {
$name = $rawName . ($i++);
}
diff --git a/extensions/sphinx/ActiveRecord.php b/extensions/sphinx/ActiveRecord.php
index 206c340..7128b79 100644
--- a/extensions/sphinx/ActiveRecord.php
+++ b/extensions/sphinx/ActiveRecord.php
@@ -8,11 +8,8 @@
namespace yii\sphinx;
use yii\base\InvalidConfigException;
-use yii\base\InvalidParamException;
-use yii\base\Model;
-use yii\base\ModelEvent;
+use yii\db\BaseActiveRecord;
use yii\base\NotSupportedException;
-use yii\base\UnknownMethodException;
use yii\db\ActiveRelationInterface;
use yii\db\StaleObjectException;
use yii\helpers\Inflector;
@@ -22,6 +19,9 @@ use Yii;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
*
+ * Warning: optimistic lock will NOT work in case of updating fields (not attributes) for the
+ * runtime indexes!
+ *
* @property array $dirtyAttributes The changed attribute values (name-value pairs). This property is
* read-only.
* @property boolean $isNewRecord Whether the record is new and should be inserted when calling [[save()]].
@@ -40,45 +40,9 @@ use Yii;
* @author Paul Klimov
* @since 2.0
*/
-abstract class ActiveRecord extends Model
+abstract class ActiveRecord extends BaseActiveRecord
{
/**
- * @event Event an event that is triggered when the record is initialized via [[init()]].
- */
- const EVENT_INIT = 'init';
- /**
- * @event Event an event that is triggered after the record is created and populated with query result.
- */
- const EVENT_AFTER_FIND = 'afterFind';
- /**
- * @event ModelEvent an event that is triggered before inserting a record.
- * You may set [[ModelEvent::isValid]] to be false to stop the insertion.
- */
- const EVENT_BEFORE_INSERT = 'beforeInsert';
- /**
- * @event Event an event that is triggered after a record is inserted.
- */
- const EVENT_AFTER_INSERT = 'afterInsert';
- /**
- * @event ModelEvent an event that is triggered before updating a record.
- * You may set [[ModelEvent::isValid]] to be false to stop the update.
- */
- const EVENT_BEFORE_UPDATE = 'beforeUpdate';
- /**
- * @event Event an event that is triggered after a record is updated.
- */
- const EVENT_AFTER_UPDATE = 'afterUpdate';
- /**
- * @event ModelEvent an event that is triggered before deleting a record.
- * You may set [[ModelEvent::isValid]] to be false to stop the deletion.
- */
- const EVENT_BEFORE_DELETE = 'beforeDelete';
- /**
- * @event Event an event that is triggered after a record is deleted.
- */
- const EVENT_AFTER_DELETE = 'afterDelete';
-
- /**
* The insert operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional.
*/
const OP_INSERT = 0x01;
@@ -97,18 +61,6 @@ abstract class ActiveRecord extends Model
const OP_ALL = 0x07;
/**
- * @var array attribute values indexed by attribute names
- */
- private $_attributes = [];
- /**
- * @var array old attribute values indexed by attribute names.
- */
- private $_oldAttributes;
- /**
- * @var array related models indexed by the relation names
- */
- private $_related = [];
- /**
* @var string current snippet value for this Active Record instance.
* It will be filled up automatically when instance found using [[Query::snippetCallback]]
* or [[ActiveQuery::snippetByModel()]].
@@ -127,33 +79,6 @@ abstract class ActiveRecord extends Model
}
/**
- * Creates an [[ActiveQuery]] instance for query purpose.
- *
- * @param mixed $q the query parameter. This can be one of the followings:
- *
- * - a string: fulltext query by a query string and return the list
- * of matching records.
- * - an array of name-value pairs: query by a set of column values and return a single record matching all of them.
- * - null: return a new [[ActiveQuery]] object for further query purpose.
- *
- * @return ActiveQuery|ActiveRecord[]|ActiveRecord|null When `$q` is null, a new [[ActiveQuery]] instance
- * is returned; when `$q` is a string, an array of ActiveRecord objects matching it will be returned;
- * when `$q` is an array, an ActiveRecord object matching it will be returned (null
- * will be returned if there is no matching).
- * @see createQuery()
- */
- public static function find($q = null)
- {
- $query = static::createQuery();
- if (is_array($q)) {
- return $query->where($q)->one();
- } elseif ($q !== null) {
- return $query->match($q)->all();
- }
- return $query;
- }
-
- /**
* Creates an [[ActiveQuery]] instance with a given SQL statement.
*
* Note that because the SQL statement is already specified, calling additional
@@ -359,37 +284,6 @@ abstract class ActiveRecord extends Model
}
/**
- * Returns the name of the column that stores the lock version for implementing optimistic locking.
- *
- * Optimistic locking allows multiple users to access the same record for edits and avoids
- * potential conflicts. In case when a user attempts to save the record upon some staled data
- * (because another user has modified the data), a [[StaleObjectException]] exception will be thrown,
- * and the update or deletion is skipped.
- *
- * Optimistic locking is only supported by [[update()]] and [[delete()]].
- *
- * To use optimistic locking:
- *
- * 1. Create a column to store the version number of each row. The column type should be `BIGINT DEFAULT 0`.
- * Override this method to return the name of this column.
- * 2. In the Web form that collects the user input, add a hidden field that stores
- * the lock version of the recording being updated.
- * 3. In the controller action that does the data updating, try to catch the [[StaleObjectException]]
- * and implement necessary business logic (e.g. merging the changes, prompting stated data)
- * to resolve the conflict.
- *
- * Warning: optimistic lock will NOT work in case of updating fields (not attributes) for the
- * runtime indexes!
- *
- * @return string the column name that stores the lock version of a table row.
- * If null is returned (default implemented), optimistic locking will not be supported.
- */
- public function optimisticLock()
- {
- return null;
- }
-
- /**
* Declares which operations should be performed within a transaction in different scenarios.
* The supported DB operations are: [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]],
* which correspond to the [[insert()]], [[update()]] and [[delete()]] methods, respectively.
@@ -422,161 +316,6 @@ abstract class ActiveRecord extends Model
}
/**
- * PHP getter magic method.
- * This method is overridden so that attributes and related objects can be accessed like properties.
- * @param string $name property name
- * @return mixed property value
- * @see getAttribute()
- */
- public function __get($name)
- {
- if (isset($this->_attributes[$name]) || array_key_exists($name, $this->_attributes)) {
- return $this->_attributes[$name];
- } elseif ($this->hasAttribute($name)) {
- return null;
- } else {
- if (isset($this->_related[$name]) || array_key_exists($name, $this->_related)) {
- return $this->_related[$name];
- }
- $value = parent::__get($name);
- if ($value instanceof ActiveRelationInterface) {
- return $this->_related[$name] = $value->multiple ? $value->all() : $value->one();
- } else {
- return $value;
- }
- }
- }
-
- /**
- * PHP setter magic method.
- * This method is overridden so that AR attributes can be accessed like properties.
- * @param string $name property name
- * @param mixed $value property value
- */
- public function __set($name, $value)
- {
- if ($this->hasAttribute($name)) {
- $this->_attributes[$name] = $value;
- } else {
- parent::__set($name, $value);
- }
- }
-
- /**
- * Checks if a property value is null.
- * This method overrides the parent implementation by checking if the named attribute is null or not.
- * @param string $name the property name or the event name
- * @return boolean whether the property value is null
- */
- public function __isset($name)
- {
- try {
- return $this->__get($name) !== null;
- } catch (\Exception $e) {
- return false;
- }
- }
-
- /**
- * Sets a component property to be null.
- * This method overrides the parent implementation by clearing
- * the specified attribute value.
- * @param string $name the property name or the event name
- */
- public function __unset($name)
- {
- if ($this->hasAttribute($name)) {
- unset($this->_attributes[$name]);
- } else {
- if (isset($this->_related[$name])) {
- unset($this->_related[$name]);
- } else {
- parent::__unset($name);
- }
- }
- }
-
- /**
- * Declares a `has-one` relation.
- * The declaration is returned in terms of an [[ActiveRelation]] instance
- * through which the related record can be queried and retrieved back.
- *
- * A `has-one` relation means that there is at most one related record matching
- * the criteria set by this relation, e.g., a particular index has one source.
- *
- * For example, to declare the `source` relation for `ArticleIndex` class, we can write
- * the following code in the `ArticleIndex` class:
- *
- * ~~~
- * public function getSource()
- * {
- * return $this->hasOne('db', ArticleContent::className(), ['article_id' => 'id']);
- * }
- * ~~~
- *
- * Note that in the above, the 'article_id' key in the `$link` parameter refers to an attribute name
- * in the related class `ArticleContent`, while the 'id' value refers to an attribute name
- * in the current AR class.
- *
- * Call methods declared in [[ActiveRelation]] to further customize the relation.
- *
- * @param string $class the class name of the related record
- * @param array $link the primary-foreign key constraint. The keys of the array refer to
- * the attributes in the `$class` model, while the values of the array refer to the corresponding
- * attributes in the index associated with this AR class.
- * @return ActiveRelationInterface the relation object.
- */
- public function hasOne($class, $link)
- {
- /** @var ActiveRecord $class */
- return $class::createActiveRelation([
- 'modelClass' => $class,
- 'primaryModel' => $this,
- 'link' => $link,
- 'multiple' => false,
- ]);
- }
-
- /**
- * Declares a `has-many` relation.
- * The declaration is returned in terms of an [[ActiveRelationInterface]] instance
- * through which the related record can be queried and retrieved back.
- *
- * A `has-many` relation means that there are multiple related records matching
- * the criteria set by this relation, e.g., an article has many tags.
- *
- * For example, to declare the `tags` relation for `ArticleIndex` class, we can write
- * the following code in the `ArticleIndex` class:
- *
- * ~~~
- * public function getOrders()
- * {
- * return $this->hasMany('db', Tag::className(), ['id' => 'tag_id']);
- * }
- * ~~~
- *
- * Note that in the above, the 'id' key in the `$link` parameter refers to
- * an attribute name in the related class `Tag`, while the 'tag_id' value refers to
- * a multi value attribute name in the current AR class.
- *
- * @param string $class the class name of the related record
- * @param array $link the primary-foreign key constraint. The keys of the array refer to
- * the columns in the table associated with the `$class` model, while the values of the
- * array refer to the corresponding columns in the table associated with this AR class.
- * @return ActiveRelationInterface the relation object.
- */
- public function hasMany($class, $link)
- {
- /** @var ActiveRecord $class */
- return $class::createActiveRelation([
- 'modelClass' => $class,
- 'primaryModel' => $this,
- 'link' => $link,
- 'multiple' => true,
- ]);
- }
-
- /**
* Creates an [[ActiveRelationInterface]] instance.
* This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance.
* You may override this method to return a customized relation.
@@ -589,36 +328,6 @@ abstract class ActiveRecord extends Model
}
/**
- * Populates the named relation with the related records.
- * Note that this method does not check if the relation exists or not.
- * @param string $name the relation name (case-sensitive)
- * @param ActiveRecord|array|null the related records to be populated into the relation.
- */
- public function populateRelation($name, $records)
- {
- $this->_related[$name] = $records;
- }
-
- /**
- * Check whether the named relation has been populated with records.
- * @param string $name the relation name (case-sensitive)
- * @return bool whether relation has been populated with records.
- */
- public function isRelationPopulated($name)
- {
- return array_key_exists($name, $this->_related);
- }
-
- /**
- * Returns all populated relations.
- * @return array an array of relation data indexed by relation names.
- */
- public function getPopulatedRelations()
- {
- return $this->_related;
- }
-
- /**
* Returns the list of all attribute names of the model.
* The default implementation will return all column names of the table associated with this AR class.
* @return array list of attribute names.
@@ -629,169 +338,6 @@ abstract class ActiveRecord extends Model
}
/**
- * Returns a value indicating whether the model has an attribute with the specified name.
- * @param string $name the name of the attribute
- * @return boolean whether the model has an attribute with the specified name.
- */
- public function hasAttribute($name)
- {
- return isset($this->_attributes[$name]) || in_array($name, $this->attributes());
- }
-
- /**
- * Returns the named attribute value.
- * If this record is the result of a query and the attribute is not loaded,
- * null will be returned.
- * @param string $name the attribute name
- * @return mixed the attribute value. Null if the attribute is not set or does not exist.
- * @see hasAttribute()
- */
- public function getAttribute($name)
- {
- return isset($this->_attributes[$name]) ? $this->_attributes[$name] : null;
- }
-
- /**
- * Sets the named attribute value.
- * @param string $name the attribute name
- * @param mixed $value the attribute value.
- * @throws InvalidParamException if the named attribute does not exist.
- * @see hasAttribute()
- */
- public function setAttribute($name, $value)
- {
- if ($this->hasAttribute($name)) {
- $this->_attributes[$name] = $value;
- } else {
- throw new InvalidParamException(get_class($this) . ' has no attribute named "' . $name . '".');
- }
- }
-
- /**
- * Returns the old attribute values.
- * @return array the old attribute values (name-value pairs)
- */
- public function getOldAttributes()
- {
- return $this->_oldAttributes === null ? [] : $this->_oldAttributes;
- }
-
- /**
- * Sets the old attribute values.
- * All existing old attribute values will be discarded.
- * @param array $values old attribute values to be set.
- */
- public function setOldAttributes($values)
- {
- $this->_oldAttributes = $values;
- }
-
- /**
- * Returns the old value of the named attribute.
- * If this record is the result of a query and the attribute is not loaded,
- * null will be returned.
- * @param string $name the attribute name
- * @return mixed the old attribute value. Null if the attribute is not loaded before
- * or does not exist.
- * @see hasAttribute()
- */
- public function getOldAttribute($name)
- {
- return isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
- }
-
- /**
- * Sets the old value of the named attribute.
- * @param string $name the attribute name
- * @param mixed $value the old attribute value.
- * @throws InvalidParamException if the named attribute does not exist.
- * @see hasAttribute()
- */
- public function setOldAttribute($name, $value)
- {
- if (isset($this->_oldAttributes[$name]) || $this->hasAttribute($name)) {
- $this->_oldAttributes[$name] = $value;
- } else {
- throw new InvalidParamException(get_class($this) . ' has no attribute named "' . $name . '".');
- }
- }
-
- /**
- * Returns a value indicating whether the named attribute has been changed.
- * @param string $name the name of the attribute
- * @return boolean whether the attribute has been changed
- */
- public function isAttributeChanged($name)
- {
- if (isset($this->_attributes[$name], $this->_oldAttributes[$name])) {
- return $this->_attributes[$name] !== $this->_oldAttributes[$name];
- } else {
- return isset($this->_attributes[$name]) || isset($this->_oldAttributes[$name]);
- }
- }
-
- /**
- * Returns the attribute values that have been modified since they are loaded or saved most recently.
- * @param string[]|null $names the names of the attributes whose values may be returned if they are
- * changed recently. If null, [[attributes()]] will be used.
- * @return array the changed attribute values (name-value pairs)
- */
- public function getDirtyAttributes($names = null)
- {
- if ($names === null) {
- $names = $this->attributes();
- }
- $names = array_flip($names);
- $attributes = [];
- if ($this->_oldAttributes === null) {
- foreach ($this->_attributes as $name => $value) {
- if (isset($names[$name])) {
- $attributes[$name] = $value;
- }
- }
- } else {
- foreach ($this->_attributes as $name => $value) {
- if (isset($names[$name]) && (!array_key_exists($name, $this->_oldAttributes) || $value !== $this->_oldAttributes[$name])) {
- $attributes[$name] = $value;
- }
- }
- }
- return $attributes;
- }
-
- /**
- * Saves the current record.
- *
- * This method will call [[insert()]] when [[isNewRecord]] is true, or [[update()]]
- * when [[isNewRecord]] is false.
- *
- * For example, to save an article record:
- *
- * ~~~
- * $customer = new Article; // or $customer = Article::find(['id' => $id]);
- * $customer->id = $id;
- * $customer->genre_id = $genreId;
- * $customer->content = $email;
- * $customer->save();
- * ~~~
- *
- *
- * @param boolean $runValidation whether to perform validation before saving the record.
- * If the validation fails, the record will not be saved.
- * @param array $attributes list of attributes that need to be saved. Defaults to null,
- * meaning all attributes that are loaded from index will be saved.
- * @return boolean whether the saving succeeds
- */
- public function save($runValidation = true, $attributes = null)
- {
- if ($this->getIsNewRecord()) {
- return $this->insert($runValidation, $attributes);
- } else {
- return $this->update($runValidation, $attributes) !== false;
- }
- }
-
- /**
* Inserts a row into the associated Sphinx index using the attribute values of this record.
*
* This method performs the following steps in order:
@@ -862,8 +408,8 @@ abstract class ActiveRecord extends Model
}
$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
- foreach ($this->primaryKey() as $key) {
- $values[$key] = isset($this->_attributes[$key]) ? $this->_attributes[$key] : null;
+ foreach ($this->getPrimaryKey(true) as $key => $value) {
+ $values[$key] = $value;
}
}
$db = static::getDb();
@@ -872,7 +418,7 @@ abstract class ActiveRecord extends Model
return false;
}
foreach ($values as $name => $value) {
- $this->_oldAttributes[$name] = $value;
+ $this->setOldAttribute($name, $value);
}
$this->afterSave(true);
return true;
@@ -957,7 +503,7 @@ abstract class ActiveRecord extends Model
* @see CActiveRecord::update()
* @throws StaleObjectException
*/
- private function updateInternal($attributes = null)
+ protected function updateInternal($attributes = null)
{
if (!$this->beforeSave(false)) {
return false;
@@ -1007,7 +553,7 @@ abstract class ActiveRecord extends Model
}
foreach ($values as $name => $value) {
- $this->_oldAttributes[$name] = $this->_attributes[$name];
+ $this->setOldAttribute($name, $this->getAttribute($name));
}
$this->afterSave(false);
return $rows;
@@ -1050,7 +596,7 @@ abstract class ActiveRecord extends Model
if ($lock !== null && !$result) {
throw new StaleObjectException('The object being deleted is outdated.');
}
- $this->_oldAttributes = null;
+ $this->setOldAttributes(null);
$this->afterDelete();
}
if ($transaction !== null) {
@@ -1070,149 +616,6 @@ abstract class ActiveRecord extends Model
}
/**
- * Returns a value indicating whether the current record is new.
- * @return boolean whether the record is new and should be inserted when calling [[save()]].
- */
- public function getIsNewRecord()
- {
- return $this->_oldAttributes === null;
- }
-
- /**
- * Sets the value indicating whether the record is new.
- * @param boolean $value whether the record is new and should be inserted when calling [[save()]].
- * @see getIsNewRecord()
- */
- public function setIsNewRecord($value)
- {
- $this->_oldAttributes = $value ? null : $this->_attributes;
- }
-
- /**
- * Initializes the object.
- * This method is called at the end of the constructor.
- * The default implementation will trigger an [[EVENT_INIT]] event.
- * If you override this method, make sure you call the parent implementation at the end
- * to ensure triggering of the event.
- */
- public function init()
- {
- parent::init();
- $this->trigger(self::EVENT_INIT);
- }
-
- /**
- * This method is called when the AR object is created and populated with the query result.
- * The default implementation will trigger an [[EVENT_AFTER_FIND]] event.
- * When overriding this method, make sure you call the parent implementation to ensure the
- * event is triggered.
- */
- public function afterFind()
- {
- $this->trigger(self::EVENT_AFTER_FIND);
- }
-
- /**
- * This method is called at the beginning of inserting or updating a record.
- * The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is true,
- * or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is false.
- * When overriding this method, make sure you call the parent implementation like the following:
- *
- * ~~~
- * public function beforeSave($insert)
- * {
- * if (parent::beforeSave($insert)) {
- * // ...custom code here...
- * return true;
- * } else {
- * return false;
- * }
- * }
- * ~~~
- *
- * @param boolean $insert whether this method called while inserting a record.
- * If false, it means the method is called while updating a record.
- * @return boolean whether the insertion or updating should continue.
- * If false, the insertion or updating will be cancelled.
- */
- public function beforeSave($insert)
- {
- $event = new ModelEvent;
- $this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event);
- return $event->isValid;
- }
-
- /**
- * This method is called at the end of inserting or updating a record.
- * The default implementation will trigger an [[EVENT_AFTER_INSERT]] event when `$insert` is true,
- * or an [[EVENT_AFTER_UPDATE]] event if `$insert` is false.
- * When overriding this method, make sure you call the parent implementation so that
- * the event is triggered.
- * @param boolean $insert whether this method called while inserting a record.
- * If false, it means the method is called while updating a record.
- */
- public function afterSave($insert)
- {
- $this->trigger($insert ? self::EVENT_AFTER_INSERT : self::EVENT_AFTER_UPDATE);
- }
-
- /**
- * This method is invoked before deleting a record.
- * The default implementation raises the [[EVENT_BEFORE_DELETE]] event.
- * When overriding this method, make sure you call the parent implementation like the following:
- *
- * ~~~
- * public function beforeDelete()
- * {
- * if (parent::beforeDelete()) {
- * // ...custom code here...
- * return true;
- * } else {
- * return false;
- * }
- * }
- * ~~~
- *
- * @return boolean whether the record should be deleted. Defaults to true.
- */
- public function beforeDelete()
- {
- $event = new ModelEvent;
- $this->trigger(self::EVENT_BEFORE_DELETE, $event);
- return $event->isValid;
- }
-
- /**
- * This method is invoked after deleting a record.
- * The default implementation raises the [[EVENT_AFTER_DELETE]] event.
- * You may override this method to do postprocessing after the record is deleted.
- * Make sure you call the parent implementation so that the event is raised properly.
- */
- public function afterDelete()
- {
- $this->trigger(self::EVENT_AFTER_DELETE);
- }
-
- /**
- * Repopulates this active record with the latest data.
- * @return boolean whether the row still exists in the database. If true, the latest data
- * will be populated to this active record. Otherwise, this record will remain unchanged.
- */
- public function refresh()
- {
- $record = $this->find($this->getPrimaryKey(true));
- if ($record === null) {
- return false;
- }
- foreach ($this->attributes() as $name) {
- $this->_attributes[$name] = isset($record->_attributes[$name]) ? $record->_attributes[$name] : null;
- }
- $this->_oldAttributes = $this->_attributes;
- $this->_related = [];
- return true;
- }
-
- /**
* Returns a value indicating whether the given active record is the same as the current one.
* The comparison is made by comparing the index names and the primary key values of the two active records.
* If one of the records [[isNewRecord|is new]] they are also considered not equal.
@@ -1228,61 +631,6 @@ abstract class ActiveRecord extends Model
}
/**
- * Returns the primary key value(s).
- * @param boolean $asArray whether to return the primary key value as an array. If true,
- * the return value will be an array with column names as keys and column values as values.
- * Note that for composite primary keys, an array will always be returned regardless of this parameter value.
- * @property mixed The primary key value. An array (column name => column value) is returned if
- * the primary key is composite. A string is returned otherwise (null will be returned if
- * the key value is null).
- * @return mixed the primary key value. An array (column name => column value) is returned if the primary key
- * is composite or `$asArray` is true. A string is returned otherwise (null will be returned if
- * the key value is null).
- */
- public function getPrimaryKey($asArray = false)
- {
- $keys = $this->primaryKey();
- if (count($keys) === 1 && !$asArray) {
- return isset($this->_attributes[$keys[0]]) ? $this->_attributes[$keys[0]] : null;
- } else {
- $values = [];
- foreach ($keys as $name) {
- $values[$name] = isset($this->_attributes[$name]) ? $this->_attributes[$name] : null;
- }
- return $values;
- }
- }
-
- /**
- * Returns the old primary key value(s).
- * This refers to the primary key value that is populated into the record
- * after executing a find method (e.g. find(), findAll()).
- * The value remains unchanged even if the primary key attribute is manually assigned with a different value.
- * @param boolean $asArray whether to return the primary key value as an array. If true,
- * the return value will be an array with column name as key and column value as value.
- * If this is false (default), a scalar value will be returned for non-composite primary key.
- * @property mixed The old primary key value. An array (column name => column value) is
- * returned if the primary key is composite. A string is returned otherwise (null will be
- * returned if the key value is null).
- * @return mixed the old primary key value. An array (column name => column value) is returned if the primary key
- * is composite or `$asArray` is true. A string is returned otherwise (null will be returned if
- * the key value is null).
- */
- public function getOldPrimaryKey($asArray = false)
- {
- $keys = $this->primaryKey();
- if (count($keys) === 1 && !$asArray) {
- return isset($this->_oldAttributes[$keys[0]]) ? $this->_oldAttributes[$keys[0]] : null;
- } else {
- $values = [];
- foreach ($keys as $name) {
- $values[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
- }
- return $values;
- }
- }
-
- /**
* Creates an active record object using a row of data.
* This method is called by [[ActiveQuery]] to populate the query results
* into Active Records. It is not meant to be used to create new records.
@@ -1299,64 +647,17 @@ abstract class ActiveRecord extends Model
if ($column->isMva) {
$value = explode(',', $value);
}
- $record->_attributes[$name] = $value;
+ $record->setAttribute($name, $value);
} else {
$record->$name = $value;
}
}
- $record->_oldAttributes = $record->_attributes;
+ $record->setOldAttributes($record->getAttributes());
$record->afterFind();
return $record;
}
/**
- * Creates an active record instance.
- * This method is called by [[create()]].
- * You may override this method if the instance being created
- * depends on the row data to be populated into the record.
- * @param array $row row data to be populated into the record.
- * @return ActiveRecord the newly created active record
- */
- public static function instantiate($row)
- {
- return new static;
- }
-
- /**
- * Returns whether there is an element at the specified offset.
- * This method is required by the interface ArrayAccess.
- * @param mixed $offset the offset to check on
- * @return boolean whether there is an element at the specified offset.
- */
- public function offsetExists($offset)
- {
- return $this->__isset($offset);
- }
-
- /**
- * Returns the relation object with the specified name.
- * A relation is defined by a getter method which returns an [[ActiveRelationInterface]] object.
- * It can be declared in either the Active Record class itself or one of its behaviors.
- * @param string $name the relation name
- * @return ActiveRelationInterface the relation object
- * @throws InvalidParamException if the named relation does not exist.
- */
- public function getRelation($name)
- {
- $getter = 'get' . $name;
- try {
- $relation = $this->$getter();
- if ($relation instanceof ActiveRelationInterface) {
- return $relation;
- } else {
- throw new InvalidParamException(get_class($this) . ' has no relation named "' . $name . '".');
- }
- } catch (UnknownMethodException $e) {
- throw new InvalidParamException(get_class($this) . ' has no relation named "' . $name . '".', 0, $e);
- }
- }
-
- /**
* Returns a value indicating whether the specified operation is transactional in the current [[scenario]].
* @param integer $operation the operation to check. Possible values are [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]].
* @return boolean whether the specified operation is transactional in the current [[scenario]].
@@ -1367,29 +668,4 @@ abstract class ActiveRecord extends Model
$transactions = $this->transactions();
return isset($transactions[$scenario]) && ($transactions[$scenario] & $operation);
}
-
- /**
- * Sets the element at the specified offset.
- * This method is required by the SPL interface `ArrayAccess`.
- * It is implicitly called when you use something like `$model[$offset] = $item;`.
- * @param integer $offset the offset to set element
- * @param mixed $item the element value
- * @throws \Exception on failure
- */
- public function offsetSet($offset, $item)
- {
- // Bypass relation owner restriction to 'yii\db\ActiveRecord' at [[yii\db\ActiveRelationTrait::findWith()]]:
- try {
- $relation = $this->getRelation($offset);
- if (is_object($relation)) {
- $this->populateRelation($offset, $item);
- return;
- }
- } catch (InvalidParamException $e) {
- // shut down exception : has getter, but not relation
- } catch (UnknownMethodException $e) {
- throw $e->getPrevious();
- }
- parent::offsetSet($offset, $item);
- }
}
\ No newline at end of file
diff --git a/framework/yii/assets/yii.activeForm.js b/framework/yii/assets/yii.activeForm.js
index 2cb3b90..c1d5bf5 100644
--- a/framework/yii/assets/yii.activeForm.js
+++ b/framework/yii/assets/yii.activeForm.js
@@ -128,7 +128,6 @@
data = $form.data('yiiActiveForm');
if (data.validated) {
// continue submitting the form since validation passes
- data.validated = false;
return true;
}
diff --git a/framework/yii/db/Query.php b/framework/yii/db/Query.php
index 870c66d..301b2e1 100644
--- a/framework/yii/db/Query.php
+++ b/framework/yii/db/Query.php
@@ -23,10 +23,13 @@ use yii\base\Component;
*
* ~~~
* $query = new Query;
+ * // compose the query
* $query->select('id, name')
* ->from('tbl_user')
* ->limit(10);
* // build and execute the query
+ * $rows = $query->all();
+ * // alternatively, you can create DB command and execute it
* $command = $query->createCommand();
* // $command->sql returns the actual SQL
* $rows = $command->queryAll();
diff --git a/framework/yii/helpers/BaseArrayHelper.php b/framework/yii/helpers/BaseArrayHelper.php
index da63238..ad8cb21 100644
--- a/framework/yii/helpers/BaseArrayHelper.php
+++ b/framework/yii/helpers/BaseArrayHelper.php
@@ -327,6 +327,29 @@ class BaseArrayHelper
}
/**
+ * Checks if the given array contains the specified key.
+ * This method enhances the `array_key_exists()` function by supporting case-insensitive
+ * key comparison.
+ * @param string $key the key to check
+ * @param array $array the array with keys to check
+ * @param boolean $caseSensitive whether the key comparison should be case-sensitive
+ * @return boolean whether the array contains the specified key
+ */
+ public static function keyExists($key, $array, $caseSensitive = true)
+ {
+ if ($caseSensitive) {
+ return array_key_exists($key, $array);
+ } else {
+ foreach (array_keys($array) as $k) {
+ if (strcasecmp($key, $k) === 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
* Sorts an array of objects or arrays (with the same structure) by one or several keys.
* @param array $array the array to be sorted. The array will be modified after calling this method.
* @param string|\Closure|array $key the key(s) to be sorted by. This refers to a key name of the sub-array
diff --git a/framework/yii/helpers/BaseHtml.php b/framework/yii/helpers/BaseHtml.php
index d435d71..93c988a 100644
--- a/framework/yii/helpers/BaseHtml.php
+++ b/framework/yii/helpers/BaseHtml.php
@@ -551,8 +551,11 @@ class BaseHtml
* in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks.
* When this option is specified, the radio button will be enclosed by a label tag.
* - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified.
+ * - container: array|boolean, the HTML attributes for the container tag. This is only used when the "label" option is specified.
+ * If it is false, no container will be rendered. If it is an array or not, a "div" container will be rendered
+ * around the the radio button.
*
- * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * The rest of the options will be rendered as the attributes of the resulting radio button tag. The values will
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
*
* @return string the generated radio button tag
@@ -571,9 +574,14 @@ class BaseHtml
if (isset($options['label'])) {
$label = $options['label'];
$labelOptions = isset($options['labelOptions']) ? $options['labelOptions'] : [];
- unset($options['label'], $options['labelOptions']);
+ $container = isset($options['container']) ? $options['container'] : ['class' => 'radio'];
+ unset($options['label'], $options['labelOptions'], $options['container']);
$content = static::label(static::input('radio', $name, $value, $options) . ' ' . $label, null, $labelOptions);
- return $hidden . static::tag('div', $content, ['class' => 'radio']);
+ if (is_array($container)) {
+ return $hidden . static::tag('div', $content, $container);
+ } else {
+ return $hidden . $content;
+ }
} else {
return $hidden . static::input('radio', $name, $value, $options);
}
@@ -592,8 +600,11 @@ class BaseHtml
* in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks.
* When this option is specified, the checkbox will be enclosed by a label tag.
* - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified.
+ * - container: array|boolean, the HTML attributes for the container tag. This is only used when the "label" option is specified.
+ * If it is false, no container will be rendered. If it is an array or not, a "div" container will be rendered
+ * around the the radio button.
*
- * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * The rest of the options will be rendered as the attributes of the resulting checkbox tag. The values will
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
*
* @return string the generated checkbox tag
@@ -612,9 +623,14 @@ class BaseHtml
if (isset($options['label'])) {
$label = $options['label'];
$labelOptions = isset($options['labelOptions']) ? $options['labelOptions'] : [];
- unset($options['label'], $options['labelOptions']);
+ $container = isset($options['container']) ? $options['container'] : ['class' => 'checkbox'];
+ unset($options['label'], $options['labelOptions'], $options['container']);
$content = static::label(static::input('checkbox', $name, $value, $options) . ' ' . $label, null, $labelOptions);
- return $hidden . static::tag('div', $content, ['class' => 'checkbox']);
+ if (is_array($container)) {
+ return $hidden . static::tag('div', $content, $container);
+ } else {
+ return $hidden . $content;
+ }
} else {
return $hidden . static::input('checkbox', $name, $value, $options);
}
diff --git a/tests/unit/data/sphinx/ar/ActiveRecord.php b/tests/unit/data/ar/sphinx/ActiveRecord.php
similarity index 83%
rename from tests/unit/data/sphinx/ar/ActiveRecord.php
rename to tests/unit/data/ar/sphinx/ActiveRecord.php
index 12150b2..2e5183e 100644
--- a/tests/unit/data/sphinx/ar/ActiveRecord.php
+++ b/tests/unit/data/ar/sphinx/ActiveRecord.php
@@ -1,6 +1,6 @@
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);
+ $article = ArticleIndex::find(2);
+ $this->assertTrue($article instanceof ArticleIndex);
+ $this->assertEquals(2, $article->id);
// find by column values
$article = ArticleIndex::find(['id' => 2, 'author_id' => 2]);
@@ -168,7 +167,7 @@ class ActiveRecordTest extends SphinxTestCase
$record = RuntimeIndex::find(['id' => 2]);
$record->content = 'Test content with ' . $query;
$record->save();
- $rows = RuntimeIndex::find($query);
+ $rows = RuntimeIndex::find()->match($query);
$this->assertNotEmpty($rows);
// updateAll
diff --git a/tests/unit/extensions/sphinx/ActiveRelationTest.php b/tests/unit/extensions/sphinx/ActiveRelationTest.php
index 05c48c9..f66845f 100644
--- a/tests/unit/extensions/sphinx/ActiveRelationTest.php
+++ b/tests/unit/extensions/sphinx/ActiveRelationTest.php
@@ -2,10 +2,10 @@
namespace yiiunit\extensions\sphinx;
-use yiiunit\data\sphinx\ar\ActiveRecord;
+use yiiunit\data\ar\sphinx\ActiveRecord;
use yiiunit\data\ar\ActiveRecord as ActiveRecordDb;
-use yiiunit\data\sphinx\ar\ArticleIndex;
-use yiiunit\data\sphinx\ar\ArticleDb;
+use yiiunit\data\ar\sphinx\ArticleIndex;
+use yiiunit\data\ar\sphinx\ArticleDb;
/**
* @group sphinx
diff --git a/tests/unit/extensions/sphinx/ExternalActiveRelationTest.php b/tests/unit/extensions/sphinx/ExternalActiveRelationTest.php
index 0893944..e30a0cf 100644
--- a/tests/unit/extensions/sphinx/ExternalActiveRelationTest.php
+++ b/tests/unit/extensions/sphinx/ExternalActiveRelationTest.php
@@ -2,11 +2,11 @@
namespace yiiunit\extensions\sphinx;
-use yiiunit\data\sphinx\ar\ActiveRecord;
+use yiiunit\data\ar\sphinx\ActiveRecord;
use yiiunit\data\ar\ActiveRecord as ActiveRecordDb;
-use yiiunit\data\sphinx\ar\ArticleIndex;
-use yiiunit\data\sphinx\ar\ArticleDb;
-use yiiunit\data\sphinx\ar\TagDb;
+use yiiunit\data\ar\sphinx\ArticleIndex;
+use yiiunit\data\ar\sphinx\ArticleDb;
+use yiiunit\data\ar\sphinx\TagDb;
/**
* @group sphinx
diff --git a/tests/unit/framework/helpers/ArrayHelperTest.php b/tests/unit/framework/helpers/ArrayHelperTest.php
index a2b5bee..f7410d5 100644
--- a/tests/unit/framework/helpers/ArrayHelperTest.php
+++ b/tests/unit/framework/helpers/ArrayHelperTest.php
@@ -303,4 +303,21 @@ class ArrayHelperTest extends TestCase
],
], $result);
}
+
+ public function testKeyExists()
+ {
+ $array = [
+ 'a' => 1,
+ 'B' => 2,
+ ];
+ $this->assertTrue(ArrayHelper::keyExists('a', $array));
+ $this->assertFalse(ArrayHelper::keyExists('b', $array));
+ $this->assertTrue(ArrayHelper::keyExists('B', $array));
+ $this->assertFalse(ArrayHelper::keyExists('c', $array));
+
+ $this->assertTrue(ArrayHelper::keyExists('a', $array, false));
+ $this->assertTrue(ArrayHelper::keyExists('b', $array, false));
+ $this->assertTrue(ArrayHelper::keyExists('B', $array, false));
+ $this->assertFalse(ArrayHelper::keyExists('c', $array, false));
+ }
}