Completed
Push — master ( e5ab12...9197f0 )
by Konstantinos
09:09
created

Event   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 6

Test Coverage

Coverage 57.14%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 21
lcom 0
cbo 6
dl 0
loc 156
ccs 36
cts 63
cp 0.5714
rs 10
c 1
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
B serialize() 0 36 5
B unserialize() 0 37 5
A isModel() 0 18 4
A notify() 0 3 1
B doNotify() 0 30 6
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
                } 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
            }
58
59 1
            $data[$property->getName()] = $value;
60
        }
61
62 1
        return serialize($data);
63
    }
64
65
    /**
66
     * Call the event's constructor using serialized data
67
     */
68 1
    public function unserialize($data)
69
    {
70 1
        $data = unserialize($data);
71
72 1
        $class = new \ReflectionObject($this);
73 1
        $params = $class->getConstructor()->getParameters();
74
75 1
        $pass = array();
76
77
        // Iterate through all the parameters of the constructor and try to
78
        // locate the value for each one in the serialized data
79 1
        foreach ($params as $param) {
80 1
            if (isset($data[$param->getName()])) {
81 1
                $value = $data[$param->getName()];
82
83
                // If the serialized data contained a model's ID (and type),
84
                // pass a new instance of it
85 1
                if ($this->isModel($param)) {
86 1
                    if (!$param->getClass()->isAbstract()) {
87 1
                        $value = $param->getClass()
88 1
                                       ->getMethod('get')
89 1
                                       ->invoke(null, $value);
90
                    } else {
91
                        $id = $value['id'];
92
                        $type = $value['type'];
93 1
                        $value = call_user_func(array($type, 'get'), $id);
94
                    }
95
                }
96
            } else {
97
                $value = null;
98
            }
99
100 1
            $pass[$param->getName()] = $value;
101
        }
102
103 1
        $class->getConstructor()->invokeArgs($this, $pass);
104 1
    }
105
106
    /**
107
     * Find out if the specified parameter of the Event's constructor needs a Model
108
     *
109
     * @param  \ReflectionParameter $param The constructor's parameter
110
     * @return bool
111
     */
112 1
    private static function isModel($param)
113
    {
114 1
        $class = $param->getClass();
115
116 1
        if ($class === null) {
117 1
            return false;
118
        }
119
120 1
        if ($class->isSubclassOf('\Model')) {
121 1
            return true;
122
        }
123
124
        if ($class->getName() === 'Model') {
125
            return true;
126
        }
127
128
        return false;
129
    }
130
131
    /**
132
     * Send a notification to the players affected by this event
133
     *
134
     * @param string $type The type of the event
135
     */
136
    public function notify($type)
137
    {
138
    }
139
140
    /**
141
     * Sends a notification to some players
142
     *
143
     * @param mixed A single player/ID or a player/ID list
144
     * @param string  $type   The type of the event
145
     * @param null|Player|int A player who should not receive a notification
146
     * @param \Player $except
147
     */
148
    protected function doNotify($players, $type, $except = null)
149
    {
150
        Debug::log("Notifying about $type", array(
151
            'players' => $players,
152
            'except'  => $except
153
        ));
154
155
        if ($except instanceof \Player) {
156
            $except = $except->getId();
157
        }
158
159
        if (!is_array($players)) {
160
            $players = array($players);
161
        }
162
163
        foreach ($players as $player) {
164
            if ($player instanceof \Player) {
165
                $player = $player->getId();
166
            }
167
168
            if ($player != $except) {
169
                $notification = \Notification::newNotification($player, $type, $this);
170
171
                \Service::getContainer()->get('event_dispatcher')->dispatch(
172
                    Events::NOTIFICATION_NEW,
173
                    new NewNotificationEvent($notification)
174
                );
175
            }
176
        }
177
    }
178
}
179