Commit c9097ed0 by Qiang Xue

working on controllers and actions.

parent e38b8660
...@@ -18,7 +18,7 @@ namespace yii\base; ...@@ -18,7 +18,7 @@ namespace yii\base;
* Derived classes must implement a method named `run()`. This method * Derived classes must implement a method named `run()`. This method
* will be invoked by the controller when the action is requested. * will be invoked by the controller when the action is requested.
* The `run()` method can have parameters which will be filled up * The `run()` method can have parameters which will be filled up
* automatically according to their names. * with user input values automatically according to their names.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
......
<?php
/**
* ActionEvent class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* ActionEvent represents the event parameter used for an action event.
*
* By setting the [[isValid]] property, one may control whether to continue the life cycle of
* the action currently being executed.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ActionEvent extends Event
{
/**
* @var Action the action currently being executed
*/
public $action;
/**
* @var boolean whether the action is in valid state and its life cycle should proceed.
*/
public $isValid = true;
/**
* Constructor.
* @param Action $action the action associated with this action event.
*/
public function __construct(Action $action)
{
$this->action = $action;
}
}
...@@ -9,66 +9,84 @@ ...@@ -9,66 +9,84 @@
namespace yii\base; namespace yii\base;
use yii\util\ArrayHelper;
/** /**
* ActionFilter is the base class for all filters. * ActionFilter is the base class for all action filters.
*
* A filter can be applied to a controller action at different stages of its life cycle. In particular,
* it responds to the following events that are raised when an action is being executed:
* *
* A filter can be applied before and after an action is executed. * 1. authorize
* It can modify the context that the action is to run or decorate the result that the * 2. beforeAction
* action generates. * 3. beforeRender
* 4. afterRender
* 5. afterAction
* *
* Override {@link preFilter()} to specify the filtering logic that should be applied * Derived classes may respond to these events by overriding the corresponding methods in this class.
* before the action, and {@link postFilter()} for filtering logic after the action. * For example, to create an access control filter, one may override the [[authorize()]] method.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class ActionFilter extends CComponent implements IFilter class ActionFilter extends Behavior
{ {
/** /**
* Performs the filtering. * @var Controller the owner of this behavior. For action filters, this should be a controller object.
* The default implementation is to invoke {@link preFilter} */
* and {@link postFilter} which are meant to be overridden public $owner;
* child classes. If a child class needs to override this method, /**
* make sure it calls <code>$filterChain->run()</code> * @var array IDs (case-insensitive) of actions that this filter applies to.
* if the action should be executed. * If this property is empty or not set, it means this filter applies to all actions.
* @param ActionFilterChain $filterChain the filter chain that the filter is on. * Note that if an action appears in [[except]], the filter will not apply to this action, even
* if the action also appears in [[only]].
* @see exception
*/ */
public function filter($filterChain) public $only;
/**
* @var array IDs (case-insensitive) of actions that this filter does NOT apply to.
*/
public $except;
public function init()
{ {
if($this->preFilter($filterChain)) $this->owner->on('authorize', array($this, 'handleEvent'));
$this->owner->on('beforeAction', array($this, 'handleEvent'));
$this->owner->on('beforeRender', array($this, 'handleEvent'));
$this->owner->getEventHandlers('afterRender')->insertAt(0, array($this, 'handleEvent'));
$this->owner->getEventHandlers('afterAction')->insertAt(0, array($this, 'handleEvent'));
}
public function authorize(ActionEvent $event)
{ {
$filterChain->run();
$this->postFilter($filterChain);
} }
public function beforeAction(ActionEvent $event)
{
} }
/** public function beforeRender(ActionEvent $event)
* Initializes the filter.
* This method is invoked after the filter properties are initialized
* and before {@link preFilter} is called.
* You may override this method to include some initialization logic.
* @since 1.1.4
*/
public function init()
{ {
} }
/** public function afterRender(ActionEvent $event)
* Performs the pre-action filtering.
* @param ActionFilterChain $filterChain the filter chain that the filter is on.
* @return boolean whether the filtering process should continue and the action
* should be executed.
*/
protected function preFilter($filterChain)
{ {
return true;
} }
/** public function afterAction(ActionEvent $event)
* Performs the post-action filtering. {
* @param ActionFilterChain $filterChain the filter chain that the filter is on. }
*/
protected function postFilter($filterChain) public function handleEvent(ActionEvent $event)
{
if ($this->applyTo($event->action)) {
$this->{$event->name}($event);
}
}
public function applyTo(Action $action)
{ {
return (empty($this->only) || ArrayHelper::search($action->id, $this->only, false) !== false)
&& (empty($this->except) || ArrayHelper::search($action->id, $this->except, false) === false);
} }
} }
\ No newline at end of file
...@@ -16,17 +16,15 @@ namespace yii\base; ...@@ -16,17 +16,15 @@ namespace yii\base;
* In particular, it can "inject" its own methods and properties into the component * In particular, it can "inject" its own methods and properties into the component
* and make them directly accessible via the component. * and make them directly accessible via the component.
* *
* @property Component $owner The owner component that this behavior is attached to.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class Behavior extends \yii\base\Object class Behavior extends \yii\base\Object
{ {
/** /**
* @var Component the owner component * @var Component the owner of this behavior
*/ */
private $_owner; public $owner;
/** /**
* Declares event handlers for the [[owner]]'s events. * Declares event handlers for the [[owner]]'s events.
...@@ -70,7 +68,7 @@ class Behavior extends \yii\base\Object ...@@ -70,7 +68,7 @@ class Behavior extends \yii\base\Object
*/ */
public function attach($owner) public function attach($owner)
{ {
$this->_owner = $owner; $this->owner = $owner;
foreach ($this->events() as $event => $handler) { foreach ($this->events() as $event => $handler) {
$owner->on($event, is_string($handler) ? array($this, $handler) : $handler); $owner->on($event, is_string($handler) ? array($this, $handler) : $handler);
} }
...@@ -88,15 +86,6 @@ class Behavior extends \yii\base\Object ...@@ -88,15 +86,6 @@ class Behavior extends \yii\base\Object
foreach ($this->events() as $event => $handler) { foreach ($this->events() as $event => $handler) {
$owner->off($event, is_string($handler) ? array($this, $handler) : $handler); $owner->off($event, is_string($handler) ? array($this, $handler) : $handler);
} }
$this->_owner = null; $this->owner = null;
}
/**
* Returns the owner component that this behavior is attached to.
* @return Component the owner component that this behavior is attached to.
*/
public function getOwner()
{
return $this->_owner;
} }
} }
...@@ -450,6 +450,9 @@ class Component extends \yii\base\Object ...@@ -450,6 +450,9 @@ class Component extends \yii\base\Object
if (!($behavior instanceof Behavior)) { if (!($behavior instanceof Behavior)) {
$behavior = \Yii::createObject($behavior); $behavior = \Yii::createObject($behavior);
} }
if (is_int($name)) {
$name = '_b ' . $name; // anonymous behavior
}
if (isset($this->_b[$name])) { if (isset($this->_b[$name])) {
$this->_b[$name]->detach($this); $this->_b[$name]->detach($this);
} }
......
...@@ -71,7 +71,10 @@ abstract class Controller extends Component implements Initable ...@@ -71,7 +71,10 @@ abstract class Controller extends Component implements Initable
public $defaultAction = 'index'; public $defaultAction = 'index';
private $_id; private $_id;
private $_action; /**
* @var Action the action that is currently being executed
*/
public $action;
private $_module; private $_module;
...@@ -95,38 +98,6 @@ abstract class Controller extends Component implements Initable ...@@ -95,38 +98,6 @@ abstract class Controller extends Component implements Initable
} }
/** /**
* Returns the filter configurations.
*
* By overriding this method, child classes can specify filters to be applied to actions.
*
* This method returns an array of filter specifications. Each array element specify a single filter.
*
* For a method-based filter (called inline filter), it is specified as 'FilterName[ +|- Action1, Action2, ...]',
* where the '+' ('-') operators describe which actions should be (should not be) applied with the filter.
*
* For a class-based filter, it is specified as an array like the following:
* <pre>
* array(
* 'FilterClass[ +|- Action1, Action2, ...]',
* 'name1'=>'value1',
* 'name2'=>'value2',
* ...
* )
* </pre>
* where the name-value pairs will be used to initialize the properties of the filter.
*
* Note, in order to inherit filters defined in the parent class, a child class needs to
* merge the parent filters with child filters using functions like array_merge().
*
* @return array a list of filter configurations.
* @see CFilter
*/
public function filters()
{
return array();
}
/**
* Returns a list of external action classes. * Returns a list of external action classes.
* Array keys are action IDs, and array values are the corresponding * Array keys are action IDs, and array values are the corresponding
* action class in dot syntax (e.g. 'edit'=>'application.controllers.article.EditArticle') * action class in dot syntax (e.g. 'edit'=>'application.controllers.article.EditArticle')
...@@ -182,16 +153,6 @@ abstract class Controller extends Component implements Initable ...@@ -182,16 +153,6 @@ abstract class Controller extends Component implements Initable
} }
/** /**
* Returns the access rules for this controller.
* Override this method if you use the {@link filterAccessControl accessControl} filter.
* @return array list of access rules. See {@link CAccessControlFilter} for details about rule specification.
*/
public function accessRules()
{
return array();
}
/**
* Runs the named action. * Runs the named action.
* Filters specified via {@link filters()} will be applied. * Filters specified via {@link filters()} will be applied.
* @param string $actionID action ID * @param string $actionID action ID
...@@ -234,10 +195,10 @@ abstract class Controller extends Component implements Initable ...@@ -234,10 +195,10 @@ abstract class Controller extends Component implements Initable
} }
else else
{ {
$priorAction = $this->_action; $priorAction = $this->action;
$this->_action = $action; $this->action = $action;
CFilterChain::create($this, $action, $filters)->run(); CFilterChain::create($this, $action, $filters)->run();
$this->_action = $priorAction; $this->action = $priorAction;
} }
} }
...@@ -249,8 +210,8 @@ abstract class Controller extends Component implements Initable ...@@ -249,8 +210,8 @@ abstract class Controller extends Component implements Initable
*/ */
public function runAction($action) public function runAction($action)
{ {
$priorAction = $this->_action; $priorAction = $this->action;
$this->_action = $action; $this->action = $action;
if ($this->beforeAction($action)) { if ($this->beforeAction($action)) {
if ($action->runWithParams($this->getActionParams())) { if ($action->runWithParams($this->getActionParams())) {
$this->afterAction($action); $this->afterAction($action);
...@@ -258,7 +219,7 @@ abstract class Controller extends Component implements Initable ...@@ -258,7 +219,7 @@ abstract class Controller extends Component implements Initable
$this->invalidActionParams($action); $this->invalidActionParams($action);
} }
} }
$this->_action = $priorAction; $this->action = $priorAction;
} }
/** /**
...@@ -384,22 +345,6 @@ abstract class Controller extends Component implements Initable ...@@ -384,22 +345,6 @@ abstract class Controller extends Component implements Initable
} }
/** /**
* @return Action the action currently being executed, null if no active action.
*/
public function getAction()
{
return $this->_action;
}
/**
* @param Action $value the action currently being executed.
*/
public function setAction($value)
{
$this->_action = $value;
}
/**
* @return string ID of the controller * @return string ID of the controller
*/ */
public function getId() public function getId()
...@@ -467,14 +412,28 @@ abstract class Controller extends Component implements Initable ...@@ -467,14 +412,28 @@ abstract class Controller extends Component implements Initable
} }
/** /**
* This method is invoked when checking the access for the action to be executed.
* @param Action $action the action to be executed.
* @return boolean whether the action is allowed to be executed.
*/
public function authorize(Action $action)
{
$event = new ActionEvent($action);
$this->trigger(__METHOD__, $event);
return $event->isValid;
}
/**
* This method is invoked right before an action is to be executed (after all possible filters.) * This method is invoked right before an action is to be executed (after all possible filters.)
* You may override this method to do last-minute preparation for the action. * You may override this method to do last-minute preparation for the action.
* @param Action $action the action to be executed. * @param Action $action the action to be executed.
* @return boolean whether the action should be executed. * @return boolean whether the action should continue to be executed.
*/ */
protected function beforeAction($action) public function beforeAction(Action $action)
{ {
return true; $event = new ActionEvent($action);
$this->trigger(__METHOD__, $event);
return $event->isValid;
} }
/** /**
...@@ -482,7 +441,31 @@ abstract class Controller extends Component implements Initable ...@@ -482,7 +441,31 @@ abstract class Controller extends Component implements Initable
* You may override this method to do some postprocessing for the action. * You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed. * @param Action $action the action just executed.
*/ */
protected function afterAction($action) public function afterAction(Action $action)
{
$event = new ActionEvent($action);
$this->trigger(__METHOD__, $event);
}
/**
* This method is invoked right before an action renders its result using [[render()]].
* @param Action $action the action to be executed.
* @return boolean whether the action should continue to render.
*/
public function beforeRender(Action $action)
{
$event = new ActionEvent($action);
$this->trigger(__METHOD__, $event);
return $event->isValid;
}
/**
* This method is invoked right after an action renders its result using [[render()]].
* @param Action $action the action just executed.
*/
public function afterRender(Action $action)
{ {
$event = new ActionEvent($action);
$this->trigger(__METHOD__, $event);
} }
} }
...@@ -39,6 +39,10 @@ class View extends Component ...@@ -39,6 +39,10 @@ class View extends Component
* the value of [[Application::sourceLanguage]]. * the value of [[Application::sourceLanguage]].
*/ */
public $sourceLanguage; public $sourceLanguage;
/**
* @var mixed custom parameters that are available in the view template
*/
public $params;
/** /**
* Renders a view. * Renders a view.
......
...@@ -354,7 +354,7 @@ class Command extends \yii\base\Component ...@@ -354,7 +354,7 @@ class Command extends \yii\base\Component
} }
\Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__); \Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__);
//echo $sql . "\n\n";
if ($db->queryCachingCount > 0 && $db->queryCachingDuration >= 0 && $method !== '') { if ($db->queryCachingCount > 0 && $db->queryCachingDuration >= 0 && $method !== '') {
$cache = \Yii::$application->getComponent($db->queryCacheID); $cache = \Yii::$application->getComponent($db->queryCacheID);
} }
......
...@@ -208,4 +208,31 @@ class ArrayHelper extends \yii\base\Component ...@@ -208,4 +208,31 @@ class ArrayHelper extends \yii\base\Component
} }
return $result; return $result;
} }
/**
* Searches the array for a given value and returns the corresponding key if found.
* This method is similar to array_search() with the enhancement that it can also
* search for strings in a case-insensitive manner.
* @param mixed $needle the value being searched for
* @param array $haystack the array to be searched through
* @param boolean $caseSensitive whether to perform a case-sensitive search
* @param boolean $strict whether to perform a type-strict search
* @return boolean|mixed the key of the value if it matches $needle. False if the value is not found.
*/
public static function search($needle, array $haystack, $caseSensitive = true, $strict = true)
{
if ($caseSensitive || !is_string($needle)) {
return array_search($needle, $haystack, $strict);
}
foreach ($haystack as $key => $value) {
if (is_string($value)) {
if (strcasecmp($value, $needle) === 0) {
return true;
}
} elseif ($strict && $key === $value || !$strict && $key == $value) {
return true;
}
}
return false;
}
} }
\ No newline at end of file
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