Completed
Push — feature/sass-standard ( 554da1...a5bd48 )
by Vladimir
12:37 queued 09:02
created

Event   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 6

Test Coverage

Coverage 54.55%

Importance

Changes 0
Metric Value
wmc 21
lcom 0
cbo 6
dl 0
loc 159
ccs 42
cts 77
cp 0.5455
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A isModel() 0 18 4
A notify() 0 3 1
B serialize() 0 36 5
B doNotify() 0 30 6
B unserialize() 0 37 5
1
<?php
2
/**
3
 * This file contains an abstract bzion event class
4
 *
5
 * @license    https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3
6
 */
7
8
namespace BZIon\Event;
9
10
use BZIon\Debug\Debug;
11
use Symfony\Component\EventDispatcher\Event as SymfonyEvent;
12
13
/**
14
 * A general BZiON event
15
 *
16
 * Events can be serialized using PHP's `serialize()` and `unserialize()`
17
 * functions. Class properties present as parameters to the constructor are
18
 * serialized and unserialized - if you provide type hinting for a model, only
19
 * its ID (and type, if necessary) is stored. This means that you shouldn't
20
 * change the parameter names or non-abstract model type hints without writing
21
 * the appropriate database migrations first.
22
 */
23
abstract class Event extends SymfonyEvent implements \Serializable
24
{
25
    /**
26
     * Serialize an event so that it can be stored in the database
27
     */
28 1
    public function serialize()
29
    {
30 1
        $class = new \ReflectionObject($this);
31 1
        $params = $class->getConstructor()->getParameters();
32
33 1
        $data = array();
34
35
        // Iterate through all the parameters of the constructor
36 1
        foreach ($params as $param) {
37
            // Find the related class property
38 1
            $property = $class->getProperty($param->getName());
39 1
            $property->setAccessible(true);
40 1
            $value = $property->getValue($this);
41
42
            // We just need to store IDs and types for models
43 1
            if ($value !== null && $this->isModel($param)) {
44 1
                if (!$param->getClass()->isAbstract()) {
45
                    // The parameter is a non-abstract model, we can just
46
                    // store its ID since the type will be known when
47
                    // unserializing
48 1
                    $value = $value->getId();
49 1
                } else {
50
                    // The parameter is an abstract model class, we need to
51
                    // store the model's type as well
52
                    $value = array(
53
                        'id'   => $value->getId(),
54
                        'type' => get_class($value)
55
                    );
56
                }
57 1
            }
58
59 1
            $data[$property->getName()] = $value;
60 1
        }
61
62 1
        return serialize($data);
63
    }
64
65
    /**
66
     * Call the event's constructor using serialized data
67
     *
68
     * @param string $data
69
     */
70 1
    public function unserialize($data)
71
    {
72 1
        $data = unserialize($data);
73
74 1
        $class = new \ReflectionObject($this);
75 1
        $params = $class->getConstructor()->getParameters();
76
77 1
        $pass = array();
78
79
        // Iterate through all the parameters of the constructor and try to
80
        // locate the value for each one in the serialized data
81 1
        foreach ($params as $param) {
82 1
            if (isset($data[$param->getName()])) {
83 1
                $value = $data[$param->getName()];
84
85
                // If the serialized data contained a model's ID (and type),
86
                // pass a new instance of it
87 1
                if ($this->isModel($param)) {
88 1
                    if (!$param->getClass()->isAbstract()) {
89 1
                        $value = $param->getClass()
90 1
                            ->getMethod('get')
91 1
                            ->invoke(null, $value);
92 1
                    } else {
93
                        $id = $value['id'];
94
                        $type = $value['type'];
95
                        $value = call_user_func(array($type, 'get'), $id);
96
                    }
97 1
                }
98 1
            } else {
99
                $value = null;
100
            }
101
102 1
            $pass[$param->getName()] = $value;
103 1
        }
104
105 1
        $class->getConstructor()->invokeArgs($this, $pass);
106 1
    }
107
108
    /**
109
     * Find out if the specified parameter of the Event's constructor needs a
110
     * Model
111
     *
112
     * @param  \ReflectionParameter $param The constructor's parameter
113
     * @return bool
114
     */
115 1
    private static function isModel($param)
116
    {
117 1
        $class = $param->getClass();
118
119 1
        if ($class === null) {
120 1
            return false;
121
        }
122
123 1
        if ($class->isSubclassOf('\Model')) {
124 1
            return true;
125
        }
126
127
        if ($class->getName() === 'Model') {
128
            return true;
129
        }
130
131
        return false;
132
    }
133
134
    /**
135
     * Send a notification to the players affected by this event
136
     *
137
     * @param string $type The type of the event
138
     */
139
    public function notify($type)
140
    {
141
    }
142
143
    /**
144
     * Sends a notification to some players
145
     *
146
     * @param mixed    $players A single player/ID or a player/ID list
147
     * @param string   $type   The type of the event
148
     * @param null|\Player|int $except A player who should not receive a notification
149
     * @param \Player $except
150
     */
151
    protected function doNotify($players, $type, $except = null)
152
    {
153
        Debug::log("Notifying about $type", array(
154
            'players' => $players,
155
            'except'  => $except
156
        ));
157
158
        if ($except instanceof \Player) {
159
            $except = $except->getId();
160
        }
161
162
        if (!is_array($players)) {
163
            $players = array($players);
164
        }
165
166
        foreach ($players as $player) {
167
            if ($player instanceof \Player) {
168
                $player = $player->getId();
169
            }
170
171
            if ($player != $except) {
172
                $notification = \Notification::newNotification($player, $type, $this);
173
174
                \Service::getContainer()->get('event_dispatcher')->dispatch(
175
                    Events::NOTIFICATION_NEW,
176
                    new NewNotificationEvent($notification)
177
                );
178
            }
179
        }
180
    }
181
}
182