1<?php
2namespace LimeSurvey\PluginManager;
3use Yii;
4use Hash;
5Yii::import('application.helpers.Hash');
6
7class PluginEvent
8{
9    /**
10     * The name of this event
11     *
12     * @var string
13     */
14    protected $_event = '';
15
16    /**
17     * This array holds the content blocks that plugins generate, idexed by plugin name
18     *
19     * @var array of PluginEventContent
20     */
21    protected $_content = array();
22
23    /**
24     * The class who fired the event, or null when not set
25     *
26     * @var object
27     */
28    protected $_sender = null;
29
30    /**
31     * When true it prevents delegating the event to other plugins.
32     *
33     * @var boolean
34     */
35    protected $_stop = false;
36
37    /**
38     * Internal storage for event data. Can be used to communicate between sender
39     * and plugin or between different plugins handling the event.
40     *
41     * @var array
42     */
43    protected $_parameters = array();
44
45    /**
46     * Constructor for the PluginEvent
47     *
48     * @param string $event    Name of the event fired
49     * @param object $sender   The object sending the event
50     * @return \PluginEvent
51     */
52    public function __construct($event, $sender = null)
53    {
54        if (!is_null($sender) && is_object($sender)) {
55            $this->_sender = $sender;
56        }
57
58        $this->_event = $event;
59
60        return $this;
61    }
62
63    /**
64     * Get a value for the given key.
65     *
66     * When the value is not set, it will return the given default or null when
67     * no default was given.
68     *
69     * @param string $key
70     * @param mixed $default
71     * @return mixed
72     */
73    public function get($key = null, $default = null)
74    {
75        if (!Hash::check($this->_parameters, $key)) {
76            return $default;
77        } else {
78            return Hash::get($this->_parameters, $key);
79        }
80    }
81
82    /**
83     * Return an array of pluginname / PluginEventContent but only when it has content
84     *
85     * @return PluginEventContent[]
86     */
87    public function getAllContent()
88    {
89        $output = array();
90        foreach ($this->_content as $plugin => $content) {
91            /* @var $content PluginEventContent */
92            if ($content->hasContent()) {
93                $output[$plugin] = $content;
94            }
95        }
96
97        return $output;
98    }
99
100    /**
101     * Returns content for the given plugin(name)
102     *
103     * When there is no content yet, it will return an empty content object.
104     *
105     * @param PluginBase|string $plugin The plugin we want content for or a string name
106     * @return PluginEventContent
107     */
108    public function getContent($plugin)
109    {
110        $pluginName = '';
111        if (is_string($plugin)) {
112            $pluginName = $plugin;
113        } elseif ($plugin instanceof PluginBase) {
114            $pluginName = get_class($plugin);
115        }
116
117        if (array_key_exists($pluginName, $this->_content)) {
118            return $this->_content[$pluginName];
119        } else {
120            return $this->setContent($pluginName);
121        }
122    }
123
124    /**
125     * Return the name of the event
126     *
127     * @return string
128     */
129    public function getEventName()
130    {
131        return $this->_event;
132    }
133
134    /**
135     * Return the sender of the event
136     *
137     * Normally the class that fired the event, but can return false when not set.
138     *
139     * @return object The object sending the event, or false when unknown
140     */
141    public function getSender()
142    {
143        if (!is_null($this->_sender)) {
144            return $this->_sender;
145        } else {
146            return false;
147        }
148    }
149
150    /**
151     * Returns true when execution of this event was stopped using $this->stop()
152     *
153     * @return boolean
154     */
155    public function isStopped()
156    {
157        return $this->_stop;
158    }
159
160    /**
161     * Set a key/value pair to be used by plugins hanlding this event.
162     *
163     * @param string $key
164     * @param mixed $value
165     * @return \PluginEvent Fluent interface
166     */
167    public function set($key, $value)
168    {
169        $this->_parameters = Hash::insert($this->_parameters, $key, $value);
170        return $this;
171    }
172
173    /**
174     * Appends a new value into the old.
175     *
176     * $value has to be an array in this case, since it is
177     * assumed that old value was an array. The new and old
178     * array value will be merged.
179     *
180     * @param string $key
181     * @param array $value
182     * @return \PluginEvent Fluent interface
183     */
184    public function append($key, array $value)
185    {
186        if (!Hash::check($this->_parameters, $key)) {
187            $oldValue = array();
188        } else {
189            $oldValue = Hash::get($this->_parameters, $key);
190        }
191
192        $value = array_merge($value, $oldValue);
193
194        $this->_parameters = Hash::insert($this->_parameters, $key, $value);
195        return $this;
196    }
197
198    /**
199     * Set content for $plugin, replacing any preexisting content
200     *
201     * @param string $plugin The plugin setting the context or a string name
202     * @param string $content
203     * @param string $cssClass
204     * @param string $id
205     * @return PluginEventContent
206     */
207    public function setContent($plugin, $content = null, $cssClass = null, $id = null)
208    {
209        if (is_string($plugin)) {
210            $pluginName = $plugin;
211        } elseif ($plugin instanceof PluginBase) {
212            $pluginName = get_class($plugin);
213        }
214
215        $contentObject = new PluginEventContent($content, $cssClass, $id);
216        if (isset($pluginName)) {
217            $this->_content[$pluginName] = $contentObject;
218        } else {
219            $this->_content[] = $contentObject;
220        }
221
222        return $contentObject;
223    }
224
225    /**
226     * Halt execution of this event by other plugins
227     */
228    public function stop()
229    {
230        $this->_stop = true;
231    }
232}
233