anonymous//src/Subject.php$0   A
last analyzed

Complexity

Total Complexity 1

Size/Duplication

Total Lines 7
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
wmc 1
1
<?php
2
3
namespace BFW;
4
5
use \Exception;
6
use \SplSubject;
7
use \SplObserver;
8
9
/**
10
 * Class to manage subject in observers systems
11
 */
12
class Subject implements SplSubject
13
{
14
    /**
15
     * @const ERR_OBSERVER_NOT_FOUND Exception code if the observer to detach
16
     * has not been found.
17
     */
18
    const ERR_OBSERVER_NOT_FOUND = 1109001;
19
    
20
    /**
21
     * @var \SplObserver[] $observers List of all observers
22
     */
23
    protected $observers = [];
24
    
25
    /**
26
     * @var object[] $notifyHeap List of notify to send
27
     */
28
    protected $notifyHeap = [];
29
    
30
    /**
31
     * @var string $action The current action to send to observers
32
     */
33
    protected $action = '';
34
    
35
    /**
36
     * @var mixed $context The current context to send to observers
37
     */
38
    protected $context = null;
39
    
40
    /**
41
     * Return list of all observers
42
     * 
43
     * @return \SplObserver[]
44
     */
45
    public function getObservers(): array
46
    {
47
        return $this->observers;
48
    }
49
    
50
    /**
51
     * Return list of all notify to send
52
     * 
53
     * @return object[]
54
     */
55
    public function getNotifyHeap(): array
56
    {
57
        return $this->notifyHeap;
58
    }
59
    
60
    /**
61
     * Return the action
62
     * 
63
     * @return string
64
     */
65
    public function getAction(): string
66
    {
67
        return $this->action;
68
    }
69
    
70
    /**
71
     * Return the context
72
     * 
73
     * @return mixed
74
     */
75
    public function getContext()
76
    {
77
        return $this->context;
78
    }
79
80
    /**
81
     * Attach a new observer to the list
82
     * 
83
     * @param \SplObserver $observer The new observer
84
     * 
85
     * @return void
86
     */
87
    public function attach(SplObserver $observer)
88
    {
89
        $this->observers[] = $observer;
90
    }
91
92
    /**
93
     * Detach a observer to the list
94
     * 
95
     * @param \SplObserver $observer The observer instance to detach
96
     * 
97
     * @return void
98
     */
99
    public function detach(SplObserver $observer)
100
    {
101
        $key = array_search($observer, $this->observers, true);
102
        
103
        if ($key === false) {
104
            throw new Exception(
105
                'The observer has not been found.',
106
                self::ERR_OBSERVER_NOT_FOUND
107
            );
108
        }
109
        
110
        unset($this->observers[$key]);
111
    }
112
113
    /**
114
     * Send a notification to all observers
115
     * 
116
     * @return void
117
     */
118
    public function notify()
119
    {
120
        \BFW\Application::getInstance()
121
            ->getMonolog()
122
            ->getLogger()
123
            ->debug(
124
                'Subject notify event',
125
                ['action' => $this->action]
126
            );
127
        
128
        foreach ($this->observers as $observer) {
129
            $observer->update($this);
130
        }
131
    }
132
    
133
    /**
134
     * Read the notify heap list and send each notify into the list.
135
     * 
136
     * @return $this
137
     */
138
    public function readNotifyHeap(): self
139
    {
140
        foreach ($this->notifyHeap as $notifyIndex => $notifyDatas) {
141
            $this->action  = $notifyDatas->action;
142
            $this->context = $notifyDatas->context;
143
            
144
            $this->notify();
145
            
146
            //Remove the current notification from list
147
            unset($this->notifyHeap[$notifyIndex]);
148
        }
149
        
150
        //Some new notifications has been added during the loop
151
        if (count($this->notifyHeap) > 0) {
152
            $this->readNotifyHeap();
153
        }
154
155
        return $this;
156
    }
157
    
158
    /**
159
     * Add a new notification to the list of notification to send.
160
     * If there is only one notification into the list, it will be send now.
161
     * Else, a notification is currently sent, so we wait it finish and the
162
     * current notification will be sent.
163
     * 
164
     * @param string $action The action to send
165
     * @param mixed $context (default null) The context to send
166
     * 
167
     * @return \BFW\Subject The current instance of this class
168
     */
169
    public function addNotification(string $action, $context = null): self
170
    {
171
        $this->notifyHeap[] = new class($action, $context) {
172
            public $action;
173
            public $context;
174
            
175
            public function __construct($action, $context) {
176
                $this->action  = $action;
177
                $this->context = $context;
178
            }
179
        };
180
        
181
        if (count($this->notifyHeap) === 1) {
182
            $this->readNotifyHeap();
183
        }
184
        
185
        return $this;
186
    }
187
}
188