Issues (910)

framework/base/ActionFilter.php (1 issue)

1
<?php
2
/**
3
 * @link https://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license https://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 76
    public function attach($owner)
51
    {
52 76
        $this->owner = $owner;
53 76
        $owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
54
    }
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 76
    public function beforeFilter($event)
72
    {
73 76
        if (!$this->isActive($event->action)) {
74
            return;
75
        }
76
77 76
        $event->isValid = $this->beforeAction($event->action);
78 70
        if ($event->isValid) {
79
            // call afterFilter only if beforeFilter succeeds
80
            // beforeFilter and afterFilter should be properly nested
81 70
            $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
    }
86
87
    /**
88
     * @param ActionEvent $event
89
     */
90 70
    public function afterFilter($event)
91
    {
92 70
        $event->result = $this->afterAction($event->action, $event->result);
93 70
        $this->owner->off(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter']);
94
    }
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 69
    public function afterAction($action, $result)
115
    {
116 69
        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 90
    protected function getActionId($action)
126
    {
127 90
        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 90
            $id = $action->id;
135
        }
136
137 90
        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 88
    protected function isActive($action)
146
    {
147 88
        $id = $this->getActionId($action);
148
149 88
        if (empty($this->only)) {
150 86
            $onlyMatch = true;
151
        } else {
152 76
            $onlyMatch = false;
153 76
            foreach ($this->only as $pattern) {
154 76
                if (StringHelper::matchWildcard($pattern, $id)) {
155 75
                    $onlyMatch = true;
156 75
                    break;
157
                }
158
            }
159
        }
160
161 88
        $exceptMatch = false;
162 88
        foreach ($this->except as $pattern) {
163 74
            if (StringHelper::matchWildcard($pattern, $id)) {
164 13
                $exceptMatch = true;
165 13
                break;
166
            }
167
        }
168
169 88
        return !$exceptMatch && $onlyMatch;
170
    }
171
}
172