Commit e35f1354 by Qiang Xue

Merge branch 'master' of https://github.com/yiisoft/yii2

parents f1316131 6431019a
...@@ -27,7 +27,7 @@ $this->registerAssetBundle('app'); ...@@ -27,7 +27,7 @@ $this->registerAssetBundle('app');
<div class="navbar"> <div class="navbar">
<div class="navbar-inner"> <div class="navbar-inner">
<div class="container"> <div class="container">
<?php echo Menu::widget($this, array( <?php echo Menu::widget(array(
'options' => array('class' => 'nav'), 'options' => array('class' => 'nav'),
'items' => array( 'items' => array(
array('label' => 'Home', 'url' => array('/site/index')), array('label' => 'Home', 'url' => array('/site/index')),
...@@ -44,7 +44,7 @@ $this->registerAssetBundle('app'); ...@@ -44,7 +44,7 @@ $this->registerAssetBundle('app');
<!-- /.navbar --> <!-- /.navbar -->
</div> </div>
<?php echo Breadcrumbs::widget($this, array( <?php echo Breadcrumbs::widget(array(
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(), 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(),
)); ?> )); ?>
<?php echo $content; ?> <?php echo $content; ?>
...@@ -60,7 +60,7 @@ $this->registerAssetBundle('app'); ...@@ -60,7 +60,7 @@ $this->registerAssetBundle('app');
</div> </div>
<?php $this->endBody(); ?> <?php $this->endBody(); ?>
</div> </div>
<?php echo Toolbar::widget($this); ?> <?php echo Toolbar::widget(); ?>
</body> </body>
</html> </html>
<?php $this->endPage(); ?> <?php $this->endPage(); ?>
...@@ -23,7 +23,7 @@ $this->params['breadcrumbs'][] = $this->title; ...@@ -23,7 +23,7 @@ $this->params['breadcrumbs'][] = $this->title;
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. If you have business inquiries or other questions, please fill out the following form to contact us. Thank you.
</p> </p>
<?php $form = ActiveForm::begin($this, array( <?php $form = ActiveForm::begin(array(
'options' => array('class' => 'form-horizontal'), 'options' => array('class' => 'form-horizontal'),
'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')), 'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')),
)); ?> )); ?>
...@@ -35,7 +35,7 @@ $this->params['breadcrumbs'][] = $this->title; ...@@ -35,7 +35,7 @@ $this->params['breadcrumbs'][] = $this->title;
$field = $form->field($model, 'verifyCode'); $field = $form->field($model, 'verifyCode');
echo $field->begin() echo $field->begin()
. $field->label() . $field->label()
. Captcha::widget($this) . Captcha::widget()
. Html::activeTextInput($model, 'verifyCode', array('class' => 'input-medium')) . Html::activeTextInput($model, 'verifyCode', array('class' => 'input-medium'))
. $field->error() . $field->error()
. $field->end(); . $field->end();
......
...@@ -14,7 +14,7 @@ $this->params['breadcrumbs'][] = $this->title; ...@@ -14,7 +14,7 @@ $this->params['breadcrumbs'][] = $this->title;
<p>Please fill out the following fields to login:</p> <p>Please fill out the following fields to login:</p>
<?php $form = ActiveForm::begin($this, array('options' => array('class' => 'form-horizontal'))); ?> <?php $form = ActiveForm::begin(array('options' => array('class' => 'form-horizontal'))); ?>
<?php echo $form->field($model, 'username')->textInput(); ?> <?php echo $form->field($model, 'username')->textInput(); ?>
<?php echo $form->field($model, 'password')->passwordInput(); ?> <?php echo $form->field($model, 'password')->passwordInput(); ?>
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?> <?php echo $form->field($model, 'rememberMe')->checkbox(); ?>
......
...@@ -446,3 +446,7 @@ $customers = Customer::find()->olderThan(50)->all(); ...@@ -446,3 +446,7 @@ $customers = Customer::find()->olderThan(50)->all();
The parameters should follow after the `$query` parameter when defining the scope method, and they The parameters should follow after the `$query` parameter when defining the scope method, and they
can take default values like shown above. can take default values like shown above.
### Atomic operations and scenarios
TBD
...@@ -218,7 +218,7 @@ methods of the `Widget` class. For example, ...@@ -218,7 +218,7 @@ methods of the `Widget` class. For example,
```php ```php
// $this refers to the View object // $this refers to the View object
// Note that you have to "echo" the result to display it // Note that you have to "echo" the result to display it
echo \yii\widgets\Menu::widget($this, array('items' => $items)); echo \yii\widgets\Menu::widget(array('items' => $items));
// $this refers to the View object // $this refers to the View object
$form = \yii\widgets\ActiveForm::begin($this); $form = \yii\widgets\ActiveForm::begin($this);
......
ActiveRecord ActiveRecord
============ ============
Scenarios
---------
Possible scenario formats supported by ActiveRecord:
```php
public function scenarios()
{
return array(
// attributes array, all operations won't be wrapped with transaction
'scenario1' => array('attribute1', 'attribute2'),
// insert and update operations will be wrapped with transaction, delete won't be wrapped
'scenario2' => array(
'attributes' => array('attribute1', 'attribute2'),
'atomic' => array(self::OP_INSERT, self::OP_UPDATE),
),
);
}
```
Query Query
----- -----
### Basic Queries ### Basic Queries
### Relational Queries ### Relational Queries
### Scopes ### Scopes
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
// whether to perform validation when a change is detected on the input // whether to perform validation when a change is detected on the input
validateOnChange: false, validateOnChange: false,
// whether to perform validation when the user is typing. // whether to perform validation when the user is typing.
validateOnType: false, validateOnType: false,
// number of milliseconds that the validation should be delayed when a user is typing in the input field. // number of milliseconds that the validation should be delayed when a user is typing in the input field.
validationDelay: 200, validationDelay: 200,
// whether to enable AJAX-based validation. // whether to enable AJAX-based validation.
......
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
dataType: 'json', dataType: 'json',
cache: false, cache: false,
success: function(data) { success: function(data) {
$e.attr('src', data['url']); $e.attr('src', data.url);
$('body').data(settings.hashKey, [data['hash1'], data['hash2']]); $('body').data(settings.hashKey, [data.hash1, data.hash2]);
} }
}); });
}, },
......
...@@ -410,6 +410,7 @@ class Controller extends Component ...@@ -410,6 +410,7 @@ class Controller extends Component
* Returns the view object that can be used to render views or view files. * Returns the view object that can be used to render views or view files.
* The [[render()]], [[renderPartial()]] and [[renderFile()]] methods will use * The [[render()]], [[renderPartial()]] and [[renderFile()]] methods will use
* this view object to implement the actual view rendering. * this view object to implement the actual view rendering.
* If not set, it will default to the "view" application component.
* @return View the view object that can be used to render views or view files. * @return View the view object that can be used to render views or view files.
*/ */
public function getView() public function getView()
......
...@@ -590,18 +590,22 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess ...@@ -590,18 +590,22 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
/** /**
* Returns the attribute names that are safe to be massively assigned in the current scenario. * Returns the attribute names that are safe to be massively assigned in the current scenario.
* @return array safe attribute names * @return string[] safe attribute names
*/ */
public function safeAttributes() public function safeAttributes()
{ {
$scenario = $this->getScenario(); $scenario = $this->getScenario();
$scenarios = $this->scenarios(); $scenarios = $this->scenarios();
if (!isset($scenarios[$scenario])) {
return array();
}
$attributes = array(); $attributes = array();
if (isset($scenarios[$scenario])) { if (isset($scenarios[$scenario]['attributes']) && is_array($scenarios[$scenario]['attributes'])) {
foreach ($scenarios[$scenario] as $attribute) { $scenarios[$scenario] = $scenarios[$scenario]['attributes'];
if ($attribute[0] !== '!') { }
$attributes[] = $attribute; foreach ($scenarios[$scenario] as $attribute) {
} if ($attribute[0] !== '!') {
$attributes[] = $attribute;
} }
} }
return $attributes; return $attributes;
...@@ -609,23 +613,26 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess ...@@ -609,23 +613,26 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
/** /**
* Returns the attribute names that are subject to validation in the current scenario. * Returns the attribute names that are subject to validation in the current scenario.
* @return array safe attribute names * @return string[] safe attribute names
*/ */
public function activeAttributes() public function activeAttributes()
{ {
$scenario = $this->getScenario(); $scenario = $this->getScenario();
$scenarios = $this->scenarios(); $scenarios = $this->scenarios();
if (isset($scenarios[$scenario])) { if (!isset($scenarios[$scenario])) {
$attributes = $scenarios[$this->getScenario()];
foreach ($attributes as $i => $attribute) {
if ($attribute[0] === '!') {
$attributes[$i] = substr($attribute, 1);
}
}
return $attributes;
} else {
return array(); return array();
} }
if (isset($scenarios[$scenario]['attributes']) && is_array($scenarios[$scenario]['attributes'])) {
$attributes = $scenarios[$scenario]['attributes'];
} else {
$attributes = $scenarios[$scenario];
}
foreach ($attributes as $i => $attribute) {
if ($attribute[0] === '!') {
$attributes[$i] = substr($attribute, 1);
}
}
return $attributes;
} }
/** /**
......
...@@ -449,7 +449,7 @@ abstract class Module extends Component ...@@ -449,7 +449,7 @@ abstract class Module extends Component
public function getComponent($id, $load = true) public function getComponent($id, $load = true)
{ {
if (isset($this->_components[$id])) { if (isset($this->_components[$id])) {
if ($this->_components[$id] instanceof Component) { if ($this->_components[$id] instanceof Object) {
return $this->_components[$id]; return $this->_components[$id];
} elseif ($load) { } elseif ($load) {
Yii::trace("Loading component: $id", __METHOD__); Yii::trace("Loading component: $id", __METHOD__);
......
...@@ -373,9 +373,10 @@ class View extends Component ...@@ -373,9 +373,10 @@ class View extends Component
*/ */
public function beginBlock($id, $renderInPlace = false) public function beginBlock($id, $renderInPlace = false)
{ {
return Block::begin($this, array( return Block::begin(array(
'id' => $id, 'id' => $id,
'renderInPlace' => $renderInPlace, 'renderInPlace' => $renderInPlace,
'view' => $this,
)); ));
} }
...@@ -406,9 +407,10 @@ class View extends Component ...@@ -406,9 +407,10 @@ class View extends Component
*/ */
public function beginContent($viewFile, $params = array()) public function beginContent($viewFile, $params = array())
{ {
return ContentDecorator::begin($this, array( return ContentDecorator::begin(array(
'viewFile' => $viewFile, 'viewFile' => $viewFile,
'params' => $params, 'params' => $params,
'view' => $this,
)); ));
} }
...@@ -442,8 +444,9 @@ class View extends Component ...@@ -442,8 +444,9 @@ class View extends Component
public function beginCache($id, $properties = array()) public function beginCache($id, $properties = array())
{ {
$properties['id'] = $id; $properties['id'] = $id;
$properties['view'] = $this;
/** @var $cache FragmentCache */ /** @var $cache FragmentCache */
$cache = FragmentCache::begin($this, $properties); $cache = FragmentCache::begin($properties);
if ($cache->getCachedContent() !== false) { if ($cache->getCachedContent() !== false) {
$this->endCache(); $this->endCache();
return false; return false;
......
...@@ -18,16 +18,6 @@ use Yii; ...@@ -18,16 +18,6 @@ use Yii;
class Widget extends Component class Widget extends Component
{ {
/** /**
* @var View the view object that this widget is associated with.
* The widget will use this view object to register any needed assets.
* This property is also required by [[render()]] and [[renderFile()]].
*/
public $view;
/**
* @var string id of the widget.
*/
private $_id;
/**
* @var integer a counter used to generate [[id]] for widgets. * @var integer a counter used to generate [[id]] for widgets.
* @internal * @internal
*/ */
...@@ -39,32 +29,19 @@ class Widget extends Component ...@@ -39,32 +29,19 @@ class Widget extends Component
*/ */
public static $_stack = array(); public static $_stack = array();
/**
* Constructor.
* @param View $view the view object that this widget is associated with.
* The widget will use this view object to register any needed assets.
* It is also required by [[render()]] and [[renderFile()]].
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($view, $config = array())
{
$this->view = $view;
parent::__construct($config);
}
/** /**
* Begins a widget. * Begins a widget.
* This method creates an instance of the calling class. It will apply the configuration * This method creates an instance of the calling class. It will apply the configuration
* to the created instance. A matching [[end()]] call should be called later. * to the created instance. A matching [[end()]] call should be called later.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties * @param array $config name-value pairs that will be used to initialize the object properties
* @return Widget the newly created widget instance * @return Widget the newly created widget instance
*/ */
public static function begin($view, $config = array()) public static function begin($config = array())
{ {
$config['class'] = get_called_class(); $config['class'] = get_called_class();
/** @var Widget $widget */ /** @var Widget $widget */
$widget = Yii::createObject($config, $view); $widget = Yii::createObject($config);
self::$_stack[] = $widget; self::$_stack[] = $widget;
return $widget; return $widget;
} }
...@@ -93,21 +70,22 @@ class Widget extends Component ...@@ -93,21 +70,22 @@ class Widget extends Component
/** /**
* Creates a widget instance and runs it. * Creates a widget instance and runs it.
* The widget rendering result is returned by this method. * The widget rendering result is returned by this method.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties * @param array $config name-value pairs that will be used to initialize the object properties
* @return string the rendering result of the widget. * @return string the rendering result of the widget.
*/ */
public static function widget($view, $config = array()) public static function widget($config = array())
{ {
ob_start(); ob_start();
ob_implicit_flush(false); ob_implicit_flush(false);
/** @var Widget $widget */ /** @var Widget $widget */
$config['class'] = get_called_class(); $config['class'] = get_called_class();
$widget = Yii::createObject($config, $view); $widget = Yii::createObject($config);
$widget->run(); $widget->run();
return ob_get_clean(); return ob_get_clean();
} }
private $_id;
/** /**
* Returns the ID of the widget. * Returns the ID of the widget.
* @param boolean $autoGenerate whether to generate an ID if it is not set previously * @param boolean $autoGenerate whether to generate an ID if it is not set previously
...@@ -130,6 +108,32 @@ class Widget extends Component ...@@ -130,6 +108,32 @@ class Widget extends Component
$this->_id = $value; $this->_id = $value;
} }
private $_view;
/**
* Returns the view object that can be used to render views or view files.
* The [[render()]] and [[renderFile()]] methods will use
* this view object to implement the actual view rendering.
* If not set, it will default to the "view" application component.
* @return View the view object that can be used to render views or view files.
*/
public function getView()
{
if ($this->_view === null) {
$this->_view = Yii::$app->getView();
}
return $this->_view;
}
/**
* Sets the view object to be used by this widget.
* @param View $view the view object that can be used to render views or view files.
*/
public function setView($view)
{
$this->_view = $view;
}
/** /**
* Executes the widget. * Executes the widget.
*/ */
...@@ -159,7 +163,7 @@ class Widget extends Component ...@@ -159,7 +163,7 @@ class Widget extends Component
public function render($view, $params = array()) public function render($view, $params = array())
{ {
$viewFile = $this->findViewFile($view); $viewFile = $this->findViewFile($view);
return $this->view->renderFile($viewFile, $params, $this); return $this->getView()->renderFile($viewFile, $params, $this);
} }
/** /**
...@@ -171,7 +175,7 @@ class Widget extends Component ...@@ -171,7 +175,7 @@ class Widget extends Component
*/ */
public function renderFile($file, $params = array()) public function renderFile($file, $params = array())
{ {
return $this->view->renderFile($file, $params, $this); return $this->getView()->renderFile($file, $params, $this);
} }
/** /**
......
...@@ -74,6 +74,22 @@ class ActiveRecord extends Model ...@@ -74,6 +74,22 @@ class ActiveRecord extends Model
const EVENT_AFTER_DELETE = 'afterDelete'; const EVENT_AFTER_DELETE = 'afterDelete';
/** /**
* Represents insert ActiveRecord operation. This constant is used for specifying set of atomic operations
* for particular scenario in the [[scenarios()]] method.
*/
const OP_INSERT = 'insert';
/**
* Represents update ActiveRecord operation. This constant is used for specifying set of atomic operations
* for particular scenario in the [[scenarios()]] method.
*/
const OP_UPDATE = 'update';
/**
* Represents delete ActiveRecord operation. This constant is used for specifying set of atomic operations
* for particular scenario in the [[scenarios()]] method.
*/
const OP_DELETE = 'delete';
/**
* @var array attribute values indexed by attribute names * @var array attribute values indexed by attribute names
*/ */
private $_attributes = array(); private $_attributes = array();
...@@ -664,10 +680,39 @@ class ActiveRecord extends Model ...@@ -664,10 +680,39 @@ class ActiveRecord extends Model
* @param array $attributes list of attributes that need to be saved. Defaults to null, * @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved. * meaning all attributes that are loaded from DB will be saved.
* @return boolean whether the attributes are valid and the record is inserted successfully. * @return boolean whether the attributes are valid and the record is inserted successfully.
* @throws \Exception in case insert failed.
*/ */
public function insert($runValidation = true, $attributes = null) public function insert($runValidation = true, $attributes = null)
{ {
if ($runValidation && !$this->validate($attributes) || !$this->beforeSave(true)) { if ($runValidation && !$this->validate($attributes)) {
return false;
}
$db = static::getDb();
$transaction = $this->isOperationAtomic(self::OP_INSERT) && $db->getTransaction() === null ? $db->beginTransaction() : null;
try {
$result = $this->insertInternal($attributes);
if ($transaction !== null) {
if ($result === false) {
$transaction->rollback();
} else {
$transaction->commit();
}
}
} catch (\Exception $e) {
if ($transaction !== null) {
$transaction->rollback();
}
throw $e;
}
return $result;
}
/**
* @see ActiveRecord::insert()
*/
private function insertInternal($attributes = null)
{
if (!$this->beforeSave(true)) {
return false; return false;
} }
$values = $this->getDirtyAttributes($attributes); $values = $this->getDirtyAttributes($attributes);
...@@ -678,22 +723,23 @@ class ActiveRecord extends Model ...@@ -678,22 +723,23 @@ class ActiveRecord extends Model
} }
$db = static::getDb(); $db = static::getDb();
$command = $db->createCommand()->insert($this->tableName(), $values); $command = $db->createCommand()->insert($this->tableName(), $values);
if ($command->execute()) { if (!$command->execute()) {
$table = $this->getTableSchema(); return false;
if ($table->sequenceName !== null) { }
foreach ($table->primaryKey as $name) { $table = $this->getTableSchema();
if (!isset($this->_attributes[$name])) { if ($table->sequenceName !== null) {
$this->_oldAttributes[$name] = $this->_attributes[$name] = $db->getLastInsertID($table->sequenceName); foreach ($table->primaryKey as $name) {
break; if (!isset($this->_attributes[$name])) {
} $this->_oldAttributes[$name] = $this->_attributes[$name] = $db->getLastInsertID($table->sequenceName);
break;
} }
} }
foreach ($values as $name => $value) {
$this->_oldAttributes[$name] = $value;
}
$this->afterSave(true);
return true;
} }
foreach ($values as $name => $value) {
$this->_oldAttributes[$name] = $value;
}
$this->afterSave(true);
return true;
} }
/** /**
...@@ -744,39 +790,67 @@ class ActiveRecord extends Model ...@@ -744,39 +790,67 @@ class ActiveRecord extends Model
* or [[beforeSave()]] stops the updating process. * or [[beforeSave()]] stops the updating process.
* @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data
* being updated is outdated. * being updated is outdated.
* @throws \Exception in case update failed.
*/ */
public function update($runValidation = true, $attributes = null) public function update($runValidation = true, $attributes = null)
{ {
if ($runValidation && !$this->validate($attributes) || !$this->beforeSave(false)) { if ($runValidation && !$this->validate($attributes)) {
return false; return false;
} }
$values = $this->getDirtyAttributes($attributes); $db = static::getDb();
if (!empty($values)) { $transaction = $this->isOperationAtomic(self::OP_UPDATE) && $db->getTransaction() === null ? $db->beginTransaction() : null;
$condition = $this->getOldPrimaryKey(true); try {
$lock = $this->optimisticLock(); $result = $this->updateInternal($attributes);
if ($lock !== null) { if ($transaction !== null) {
if (!isset($values[$lock])) { if ($result === false) {
$values[$lock] = $this->$lock + 1; $transaction->rollback();
} else {
$transaction->commit();
} }
$condition[$lock] = $this->$lock;
} }
// We do not check the return value of updateAll() because it's possible } catch (\Exception $e) {
// that the UPDATE statement doesn't change anything and thus returns 0. if ($transaction !== null) {
$rows = $this->updateAll($values, $condition); $transaction->rollback();
if ($lock !== null && !$rows) {
throw new StaleObjectException('The object being updated is outdated.');
} }
throw $e;
}
return $result;
}
foreach ($values as $name => $value) { /**
$this->_oldAttributes[$name] = $this->_attributes[$name]; * @see CActiveRecord::update()
* @throws StaleObjectException
*/
private function updateInternal($attributes = null)
{
if (!$this->beforeSave(false)) {
return false;
}
$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
return 0;
}
$condition = $this->getOldPrimaryKey(true);
$lock = $this->optimisticLock();
if ($lock !== null) {
if (!isset($values[$lock])) {
$values[$lock] = $this->$lock + 1;
} }
$condition[$lock] = $this->$lock;
}
// We do not check the return value of updateAll() because it's possible
// that the UPDATE statement doesn't change anything and thus returns 0.
$rows = $this->updateAll($values, $condition);
$this->afterSave(false); if ($lock !== null && !$rows) {
return $rows; throw new StaleObjectException('The object being updated is outdated.');
} else { }
return 0;
foreach ($values as $name => $value) {
$this->_oldAttributes[$name] = $this->_attributes[$name];
} }
$this->afterSave(false);
return $rows;
} }
/** /**
...@@ -826,27 +900,43 @@ class ActiveRecord extends Model ...@@ -826,27 +900,43 @@ class ActiveRecord extends Model
* Note that it is possible the number of rows deleted is 0, even though the deletion execution is successful. * Note that it is possible the number of rows deleted is 0, even though the deletion execution is successful.
* @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data
* being deleted is outdated. * being deleted is outdated.
* @throws \Exception in case delete failed.
*/ */
public function delete() public function delete()
{ {
if ($this->beforeDelete()) { $db = static::getDb();
// we do not check the return value of deleteAll() because it's possible $transaction = $this->isOperationAtomic(self::OP_DELETE) && $db->getTransaction() === null ? $db->beginTransaction() : null;
// the record is already deleted in the database and thus the method will return 0 try {
$condition = $this->getOldPrimaryKey(true); $result = false;
$lock = $this->optimisticLock(); if ($this->beforeDelete()) {
if ($lock !== null) { // we do not check the return value of deleteAll() because it's possible
$condition[$lock] = $this->$lock; // the record is already deleted in the database and thus the method will return 0
$condition = $this->getOldPrimaryKey(true);
$lock = $this->optimisticLock();
if ($lock !== null) {
$condition[$lock] = $this->$lock;
}
$result = $this->deleteAll($condition);
if ($lock !== null && !$result) {
throw new StaleObjectException('The object being deleted is outdated.');
}
$this->_oldAttributes = null;
$this->afterDelete();
} }
$rows = $this->deleteAll($condition); if ($transaction !== null) {
if ($lock !== null && !$rows) { if ($result === false) {
throw new StaleObjectException('The object being deleted is outdated.'); $transaction->rollback();
} else {
$transaction->commit();
}
} }
$this->_oldAttributes = null; } catch (\Exception $e) {
$this->afterDelete(); if ($transaction !== null) {
return $rows; $transaction->rollback();
} else { }
return false; throw $e;
} }
return $result;
} }
/** /**
...@@ -1336,4 +1426,19 @@ class ActiveRecord extends Model ...@@ -1336,4 +1426,19 @@ class ActiveRecord extends Model
} }
return true; return true;
} }
/**
* @param string $operation possible values are ActiveRecord::INSERT, ActiveRecord::UPDATE and ActiveRecord::DELETE.
* @return boolean whether given operation is atomic. Currently active scenario is taken into account.
*/
private function isOperationAtomic($operation)
{
$scenario = $this->getScenario();
$scenarios = $this->scenarios();
if (isset($scenarios[$scenario], $scenario[$scenario]['atomic']) && is_array($scenarios[$scenario]['atomic'])) {
return in_array($operation, $scenarios[$scenario]['atomic']);
} else {
return false;
}
}
} }
...@@ -260,10 +260,6 @@ class CaptchaAction extends Action ...@@ -260,10 +260,6 @@ class CaptchaAction extends Action
(int)($this->foreColor % 0x10000 / 0x100), (int)($this->foreColor % 0x10000 / 0x100),
$this->foreColor % 0x100); $this->foreColor % 0x100);
if ($this->fontFile === null) {
$this->fontFile = dirname(__FILE__) . '/SpicyRice.ttf';
}
$length = strlen($code); $length = strlen($code);
$box = imagettfbbox(30, 0, $this->fontFile, $code); $box = imagettfbbox(30, 0, $this->fontFile, $code);
$w = $box[4] - $box[0] + $this->offset * ($length - 1); $w = $box[4] - $box[0] + $this->offset * ($length - 1);
...@@ -302,10 +298,6 @@ class CaptchaAction extends Action ...@@ -302,10 +298,6 @@ class CaptchaAction extends Action
$image = new \Imagick(); $image = new \Imagick();
$image->newImage($this->width, $this->height, $backColor); $image->newImage($this->width, $this->height, $backColor);
if ($this->fontFile === null) {
$this->fontFile = dirname(__FILE__) . '/SpicyRice.ttf';
}
$draw = new \ImagickDraw(); $draw = new \ImagickDraw();
$draw->setFont($this->fontFile); $draw->setFont($this->fontFile);
$draw->setFontSize(30); $draw->setFontSize(30);
......
...@@ -47,7 +47,7 @@ use Yii; ...@@ -47,7 +47,7 @@ use Yii;
* } * }
* *
* // display pagination * // display pagination
* LinkPager::widget($this, array( * LinkPager::widget(array(
* 'pages' => $pages, * 'pages' => $pages,
* )); * ));
* ~~~ * ~~~
......
...@@ -23,7 +23,7 @@ use yii\helpers\Html; ...@@ -23,7 +23,7 @@ use yii\helpers\Html;
* *
* ~~~ * ~~~
* // $this is the view object currently being used * // $this is the view object currently being used
* echo Breadcrumbs::widget($this, array( * echo Breadcrumbs::widget(array(
* 'links' => array( * 'links' => array(
* array('label' => 'Sample Post', 'url' => array('post/edit', 'id' => 1)), * array('label' => 'Sample Post', 'url' => array('post/edit', 'id' => 1)),
* 'Edit', * 'Edit',
...@@ -37,7 +37,7 @@ use yii\helpers\Html; ...@@ -37,7 +37,7 @@ use yii\helpers\Html;
* *
* ~~~ * ~~~
* // $this is the view object currently being used * // $this is the view object currently being used
* echo Breadcrumbs::widget($this, array( * echo Breadcrumbs::widget(array(
* 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(), * 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(),
* )); * ));
* ~~~ * ~~~
......
...@@ -27,7 +27,7 @@ use yii\helpers\Html; ...@@ -27,7 +27,7 @@ use yii\helpers\Html;
* *
* ~~~ * ~~~
* // $this is the view object currently being used * // $this is the view object currently being used
* echo Menu::widget($this, array( * echo Menu::widget(array(
* 'items' => array( * 'items' => array(
* // Important: you need to specify url as 'controller/action', * // Important: you need to specify url as 'controller/action',
* // not just as 'controller' even if default action is used. * // not just as 'controller' even if default action is used.
......
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