• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

optimizely / php-sdk / 4536635044

pending completion
4536635044

Pull #265

github

GitHub
Merge 019774507 into 34bebf03a
Pull Request #265: [FSSDK-8940] Correct return type hints

2871 of 2957 relevant lines covered (97.09%)

63.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.24
/src/Optimizely/Notification/NotificationCenter.php
1
<?php
2
/**
3
 * Copyright 2017-2019, Optimizely Inc and Contributors
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
namespace Optimizely\Notification;
18

19
use ArgumentCountError;
20
use Exception;
21
use Throwable;
22

23
use Monolog\Logger;
24

25
use Optimizely\ErrorHandler\ErrorHandlerInterface;
26
use Optimizely\Exceptions\InvalidCallbackArgumentCountException;
27
use Optimizely\Exceptions\InvalidNotificationTypeException;
28
use Optimizely\Logger\LoggerInterface;
29
use Optimizely\Logger\NoOpLogger;
30

31
class NotificationCenter
32
{
33
    private $_notificationId;
34

35
    private $_notifications;
36

37
    private $_logger;
38

39
    private $_errorHandler;
40

41
    public function __construct(LoggerInterface $logger, ErrorHandlerInterface $errorHandler)
42
    {
43
        $this->_notificationId = 1;
288✔
44
        $this->_notifications = [];
288✔
45
        foreach (array_values(NotificationType::getAll()) as $type) {
288✔
46
            $this->_notifications[$type] = [];
288✔
47
        }
288✔
48

49
        $this->_logger = $logger;
288✔
50
        $this->_errorHandler = $errorHandler;
288✔
51
    }
288✔
52

53
    public function getNotifications()
54
    {
55
        return $this->_notifications;
6✔
56
    }
57

58
    /**
59
     * Adds a notification callback for a notification type to the notification center
60
     *
61
     * @param string   $notification_type     One of the constants defined in NotificationType
62
     * @param callable $notification_callback A valid PHP callback
63
     *
64
     * @return null  Given invalid notification type/callback
65
     *         -1    Given callback has been already added
66
     *         int   Notification ID for the added callback
67
     */
68
    public function addNotificationListener($notification_type, $notification_callback)
69
    {
70
        if (!NotificationType::isNotificationTypeValid($notification_type)) {
11✔
71
            $this->_logger->log(Logger::ERROR, "Invalid notification type.");
1✔
72
            $this->_errorHandler->handleError(new InvalidNotificationTypeException('Invalid notification type.'));
1✔
73
            return null;
1✔
74
        }
75

76
        if (!is_callable($notification_callback)) {
11✔
77
            $this->_logger->log(Logger::ERROR, "Invalid notification callback.");
1✔
78
            return null;
1✔
79
        }
80

81
        foreach (array_values($this->_notifications[$notification_type]) as $callback) {
10✔
82
            if ($notification_callback == $callback) {
8✔
83
                // Note: anonymous methods sent with the same body will be re-added.
84
                // Only variable and object methods can be checked for duplication
85
                $this->_logger->log(Logger::DEBUG, "Callback already added for notification type '{$notification_type}'.");
1✔
86
                return -1;
1✔
87
            }
88
        }
10✔
89

90
        $this->_notifications[$notification_type][$this->_notificationId] = $notification_callback;
10✔
91
        $this->_logger->log(Logger::INFO, "Callback added for notification type '{$notification_type}'.");
10✔
92
        $returnVal = $this->_notificationId++;
10✔
93
        return $returnVal;
10✔
94
    }
95

96
    /**
97
     * Removes notification callback from the notification center
98
     *
99
     * @param int $notification_id notification ID
100
     *
101
     * @return true   When callback removed
102
     *         false  When no callback found for the given notification ID
103
     */
104
    public function removeNotificationListener($notification_id)
105
    {
106
        foreach ($this->_notifications as $notification_type => $notifications) {
1✔
107
            foreach (array_keys($notifications) as $id) {
1✔
108
                if ($notification_id == $id) {
1✔
109
                    unset($this->_notifications[$notification_type][$id]);
1✔
110
                    $this->_logger->log(Logger::INFO, "Callback with notification ID '{$notification_id}' has been removed.");
1✔
111
                    return true;
1✔
112
                }
113
            }
1✔
114
        }
1✔
115

116
        $this->_logger->log(Logger::DEBUG, "No Callback found with notification ID '{$notification_id}'.");
1✔
117
        return false;
1✔
118
    }
119

120
    /**
121
     * Logs deprecation message
122
     *
123
     * @deprecated Use 'clearNotificationListeners' instead.
124
     */
125
    public function clearNotifications($notification_type)
126
    {
127
        $this->_logger->log(
128
            Logger::WARNING,
129
            "'clearNotifications' is deprecated. Call 'clearNotificationListeners' instead."
130
        );
131
        $this->clearNotificationListeners($notification_type);
132
    }
133

134
    /**
135
     * Removes all notification callbacks for the given notification type
136
     *
137
     * @param string $notification_type One of the constants defined in NotificationType
138
     */
139
    public function clearNotificationListeners($notification_type)
140
    {
141
        if (!NotificationType::isNotificationTypeValid($notification_type)) {
1✔
142
            $this->_logger->log(Logger::ERROR, "Invalid notification type.");
1✔
143
            $this->_errorHandler->handleError(new InvalidNotificationTypeException('Invalid notification type.'));
1✔
144
            return;
1✔
145
        }
146

147
        $this->_notifications[$notification_type] = [];
1✔
148
        $this->_logger->log(Logger::INFO, "All callbacks for notification type '{$notification_type}' have been removed.");
1✔
149
    }
1✔
150

151
    /**
152
     * Logs deprecation message
153
     *
154
     * @deprecated Use 'clearAllNotificationListeners' instead.
155
     */
156
    public function cleanAllNotifications()
157
    {
158
        $this->_logger->log(
159
            Logger::WARNING,
160
            "'cleanAllNotifications' is deprecated. Call 'clearAllNotificationListeners' instead."
161
        );
162
        $this->clearAllNotificationListeners();
163
    }
164

165
    /**
166
     * Removes all notifications for all notification types
167
     * from the notification center
168
     */
169
    public function clearAllNotificationListeners()
170
    {
171
        foreach (array_values(NotificationType::getAll()) as $type) {
10✔
172
            $this->_notifications[$type] = [];
10✔
173
        }
10✔
174
    }
10✔
175

176
    /**
177
     * Executes all registered callbacks for the given notification type
178
     *
179
     * @param string $notification_type One of the constants defined in NotificationType
180
     * @param array  $args              Array of items to pass as arguments to the callback
181
     */
182
    public function sendNotifications($notification_type, array $args = [])
183
    {
184
        if (!isset($this->_notifications[$notification_type])) {
77✔
185
            // No exception thrown and error logged since this method will be called from
186
            // within the SDK
187
            return;
1✔
188
        }
189

190
        /**
191
         * Note: Before PHP 7, if the callback in call_user_func is called with less number of arguments than expected,
192
         * a warning is issued but the method is still executed with assigning null to the remaining
193
         * arguments. From PHP 7, ArgumentCountError is thrown in such case and the method isn't executed.
194
         * Therefore, we set error handler for warnings so that we raise an exception and notify the
195
         * user that the registered callback has more number of arguments than
196
         * expected. This should be done to keep a consistent behavior across all PHP versions.
197
         */
198

199
        set_error_handler(array($this, 'reportArgumentCountError'), E_WARNING);
77✔
200

201
        foreach (array_values($this->_notifications[$notification_type]) as $callback) {
77✔
202
            try {
203
                call_user_func_array($callback, $args);
3✔
204
            } catch (ArgumentCountError $e) {
3✔
205
                $this->reportArgumentCountError();
×
206
            } catch (Exception $e) {
×
207
                $this->_logger->log(Logger::ERROR, "Problem calling notify callback.");
×
208
            }
209
        }
77✔
210

211
        restore_error_handler();
77✔
212
    }
77✔
213

214
    /**
215
     * Logs and raises an exception when registered callback expects more number of arguments when executed
216
     */
217
    public function reportArgumentCountError()
218
    {
219
        $this->_logger->log(Logger::ERROR, "Problem calling notify callback.");
1✔
220
        $this->_errorHandler->handleError(
1✔
221
            new InvalidCallbackArgumentCountException('Registered callback expects more number of arguments than the actual number')
1✔
222
        );
1✔
223
    }
1✔
224
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc