Completed
Push — master ( 55b06d...9f2a87 )
by Alexander
35:57
created

framework/base/ActionFilter.php (2 issues)

1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\base;
9
10
use yii\helpers\StringHelper;
11
12
/**
13
 * ActionFilter is the base class for action filters.
14
 *
15
 * An action filter will participate in the action execution workflow by responding to
16
 * the `beforeAction` and `afterAction` events triggered by modules and controllers.
17
 *
18
 * Check implementation of [[\yii\filters\AccessControl]], [[\yii\filters\PageCache]] and [[\yii\filters\HttpCache]] as examples on how to use it.
19
 *
20
 * For more details and usage information on ActionFilter, see the [guide article on filters](guide:structure-filters).
21
 *
22
 * @author Qiang Xue <[email protected]>
23
 * @since 2.0
24
 */
25
class ActionFilter extends Behavior
26
{
27
    /**
28
     * @var array list of action IDs that this filter should apply to. If this property is not set,
29
     * then the filter applies to all actions, unless they are listed in [[except]].
30
     * If an action ID appears in both [[only]] and [[except]], this filter will NOT apply to it.
31
     *
32
     * Note that if the filter is attached to a module, the action IDs should also include child module IDs (if any)
33
     * and controller IDs.
34
     *
35
     * Since version 2.0.9 action IDs can be specified as wildcards, e.g. `site/*`.
36
     *
37
     * @see except
38
     */
39
    public $only;
40
    /**
41
     * @var array list of action IDs that this filter should not apply to.
42
     * @see only
43
     */
44
    public $except = [];
45
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 62
    public function attach($owner)
51
    {
52 62
        $this->owner = $owner;
53 62
        $owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
54 62
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    public function detach()
60
    {
61
        if ($this->owner) {
62
            $this->owner->off(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
63
            $this->owner->off(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter']);
64
            $this->owner = null;
65
        }
66
    }
67
68
    /**
69
     * @param ActionEvent $event
70
     */
71 62
    public function beforeFilter($event)
72
    {
73 62
        if (!$this->isActive($event->action)) {
74
            return;
75
        }
76
77 62
        $event->isValid = $this->beforeAction($event->action);
78 60
        if ($event->isValid) {
79
            // call afterFilter only if beforeFilter succeeds
80
            // beforeFilter and afterFilter should be properly nested
81 60
            $this->owner->on(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter'], null, false);
0 ignored issues
show
The method on() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

81
            $this->owner->/** @scrutinizer ignore-call */ 
82
                          on(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter'], null, false);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
82
        } else {
83 1
            $event->handled = true;
84
        }
85 60
    }
86
87
    /**
88
     * @param ActionEvent $event
89
     */
90 60
    public function afterFilter($event)
91
    {
92 60
        $event->result = $this->afterAction($event->action, $event->result);
93 60
        $this->owner->off(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter']);
94 60
    }
95
96
    /**
97
     * This method is invoked right before an action is to be executed (after all possible filters.)
98
     * You may override this method to do last-minute preparation for the action.
99
     * @param Action $action the action to be executed.
100
     * @return bool whether the action should continue to be executed.
101
     */
102
    public function beforeAction($action)
103
    {
104
        return true;
105
    }
106
107
    /**
108
     * This method is invoked right after an action is executed.
109
     * You may override this method to do some postprocessing for the action.
110
     * @param Action $action the action just executed.
111
     * @param mixed $result the action execution result
112
     * @return mixed the processed action result.
113
     */
114 59
    public function afterAction($action, $result)
0 ignored issues
show
The parameter $action is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

114
    public function afterAction(/** @scrutinizer ignore-unused */ $action, $result)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
115
    {
116 59
        return $result;
117
    }
118
119
    /**
120
     * Returns an action ID by converting [[Action::$uniqueId]] into an ID relative to the module.
121
     * @param Action $action
122
     * @return string
123
     * @since 2.0.7
124
     */
125 76
    protected function getActionId($action)
126
    {
127 76
        if ($this->owner instanceof Module) {
128
            $mid = $this->owner->getUniqueId();
129
            $id = $action->getUniqueId();
130
            if ($mid !== '' && strpos($id, $mid) === 0) {
131
                $id = substr($id, strlen($mid) + 1);
132
            }
133
        } else {
134 76
            $id = $action->id;
135
        }
136
137 76
        return $id;
138
    }
139
140
    /**
141
     * Returns a value indicating whether the filter is active for the given action.
142
     * @param Action $action the action being filtered
143
     * @return bool whether the filter is active for the given action.
144
     */
145 74
    protected function isActive($action)
146
    {
147 74
        $id = $this->getActionId($action);
148
149 74
        if (empty($this->only)) {
150 72
            $onlyMatch = true;
151
        } else {
152 69
            $onlyMatch = false;
153 69
            foreach ($this->only as $pattern) {
154 69
                if (StringHelper::matchWildcard($pattern, $id)) {
155 69
                    $onlyMatch = true;
156 69
                    break;
157
                }
158
            }
159
        }
160
161 74
        $exceptMatch = false;
162 74
        foreach ($this->except as $pattern) {
163 67
            if (StringHelper::matchWildcard($pattern, $id)) {
164 12
                $exceptMatch = true;
165 67
                break;
166
            }
167
        }
168
169 74
        return !$exceptMatch && $onlyMatch;
170
    }
171
}
172