Commit c9097ed0 by Qiang Xue

working on controllers and actions.

parent e38b8660
......@@ -18,7 +18,7 @@ namespace yii\base;
* Derived classes must implement a method named `run()`. This method
* will be invoked by the controller when the action is requested.
* 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>
* @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 @@
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.
* It can modify the context that the action is to run or decorate the result that the
* action generates.
* 1. authorize
* 2. beforeAction
* 3. beforeRender
* 4. afterRender
* 5. afterAction
*
* Override {@link preFilter()} to specify the filtering logic that should be applied
* before the action, and {@link postFilter()} for filtering logic after the action.
* Derived classes may respond to these events by overriding the corresponding methods in this class.
* For example, to create an access control filter, one may override the [[authorize()]] method.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ActionFilter extends CComponent implements IFilter
class ActionFilter extends Behavior
{
/**
* Performs the filtering.
* The default implementation is to invoke {@link preFilter}
* and {@link postFilter} which are meant to be overridden
* child classes. If a child class needs to override this method,
* make sure it calls <code>$filterChain->run()</code>
* if the action should be executed.
* @param ActionFilterChain $filterChain the filter chain that the filter is on.
* @var Controller the owner of this behavior. For action filters, this should be a controller object.
*/
public $owner;
/**
* @var array IDs (case-insensitive) of actions that this filter applies to.
* If this property is empty or not set, it means this filter applies to all actions.
* 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)
{
}
/**
* 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 beforeRender(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)
public function afterRender(ActionEvent $event)
{
return true;
}
/**
* Performs the post-action filtering.
* @param ActionFilterChain $filterChain the filter chain that the filter is on.
*/
protected function postFilter($filterChain)
public function afterAction(ActionEvent $event)
{
}
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;
* In particular, it can "inject" its own methods and properties into 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>
* @since 2.0
*/
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.
......@@ -70,7 +68,7 @@ class Behavior extends \yii\base\Object
*/
public function attach($owner)
{
$this->_owner = $owner;
$this->owner = $owner;
foreach ($this->events() as $event => $handler) {
$owner->on($event, is_string($handler) ? array($this, $handler) : $handler);
}
......@@ -88,15 +86,6 @@ class Behavior extends \yii\base\Object
foreach ($this->events() as $event => $handler) {
$owner->off($event, is_string($handler) ? array($this, $handler) : $handler);
}
$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;
$this->owner = null;
}
}
......@@ -450,6 +450,9 @@ class Component extends \yii\base\Object
if (!($behavior instanceof Behavior)) {
$behavior = \Yii::createObject($behavior);
}
if (is_int($name)) {
$name = '_b ' . $name; // anonymous behavior
}
if (isset($this->_b[$name])) {
$this->_b[$name]->detach($this);
}
......
......@@ -71,7 +71,10 @@ abstract class Controller extends Component implements Initable
public $defaultAction = 'index';
private $_id;
private $_action;
/**
* @var Action the action that is currently being executed
*/
public $action;
private $_module;
......@@ -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.
* Array keys are action IDs, and array values are the corresponding
* action class in dot syntax (e.g. 'edit'=>'application.controllers.article.EditArticle')
......@@ -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.
* Filters specified via {@link filters()} will be applied.
* @param string $actionID action ID
......@@ -234,10 +195,10 @@ abstract class Controller extends Component implements Initable
}
else
{
$priorAction = $this->_action;
$this->_action = $action;
$priorAction = $this->action;
$this->action = $action;
CFilterChain::create($this, $action, $filters)->run();
$this->_action = $priorAction;
$this->action = $priorAction;
}
}
......@@ -249,8 +210,8 @@ abstract class Controller extends Component implements Initable
*/
public function runAction($action)
{
$priorAction = $this->_action;
$this->_action = $action;
$priorAction = $this->action;
$this->action = $action;
if ($this->beforeAction($action)) {
if ($action->runWithParams($this->getActionParams())) {
$this->afterAction($action);
......@@ -258,7 +219,7 @@ abstract class Controller extends Component implements Initable
$this->invalidActionParams($action);
}
}
$this->_action = $priorAction;
$this->action = $priorAction;
}
/**
......@@ -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
*/
public function getId()
......@@ -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.)
* You may override this method to do last-minute preparation for the action.
* @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
* You may override this method to do some postprocessing for the action.
* @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
* the value of [[Application::sourceLanguage]].
*/
public $sourceLanguage;
/**
* @var mixed custom parameters that are available in the view template
*/
public $params;
/**
* Renders a view.
......
......@@ -354,7 +354,7 @@ class Command extends \yii\base\Component
}
\Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__);
//echo $sql . "\n\n";
if ($db->queryCachingCount > 0 && $db->queryCachingDuration >= 0 && $method !== '') {
$cache = \Yii::$application->getComponent($db->queryCacheID);
}
......
......@@ -208,4 +208,31 @@ class ArrayHelper extends \yii\base\Component
}
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