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

optimizely / php-sdk / 5092738569

pending completion
5092738569

push

github

web-flow
[FSSDK-9073] Update to support PHP 8.x (#268)

* [FSSDK-9022] Ignore .phpunit.result.cache

* [FSSDK-9022] Increment version of php to 8.0+

* [FSSDK-9022] Update murmurhash version & use

* [FSSDK-9022] Fixed tests' setUp() signatures

* [FSSDK-9022]

* [FSSDK-9022] Convert PHPUnit_Framework_TestCase to TestCase

* [FSSDK-9022] Adjust deps

* [FSSDK-9022] Adjust PHPUnit bootstrapping

* [FSSDK-9022] Rollback to older murmurhash lib

* [FSSDK-9022] Fix exception type check condition for PHP8

* [FSSDK-9022] Expand the memory limit for running PHPUnit tests

* [FSSDK-9022] Update GitHub Actions workflow

* [FSSDK-9022] Remove @expectedException

* [FSSDK-9022] Try fix for no coverage file produced

* [FSSDK-9022] Try fixing clover.xml path

* [FSSDK-9022] Add step to fail if clover.xml not created

* [FSSDK-9022] Try using php-actions/phpunit@v3

* [FSSDK-9022] Adjust phpunit action

* [FSSDK-9022] Set bootstrap: phpunit_bootstrap.php

* [FSSDK-9022] Rollback to script based run PHPUnit

* [FSSDK-9022] Upgrade to minimum PHPUnit that outputs coverage for PHP8

* Add composer.lock to repo

* Move Source Clear scan inside CI

* Remove support for 8.0...

which is no longer actively supported and security support ends 26 Nov 2023

* Fix php workflow to use master

* Add missing property dec + refactors

* Add end of file line

* Add missing Copyright years

4 of 4 new or added lines in 2 files covered. (100.0%)

2701 of 2775 relevant lines covered (97.33%)

109.44 hits per line

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

96.77
/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;
576✔
44
        $this->_notifications = [];
576✔
45
        foreach (array_values(NotificationType::getAll()) as $type) {
576✔
46
            $this->_notifications[$type] = [];
576✔
47
        }
48

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

53
    public function getNotifications()
54
    {
55
        return $this->_notifications;
12✔
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)) {
22✔
71
            $this->_logger->log(Logger::ERROR, "Invalid notification type.");
2✔
72
            $this->_errorHandler->handleError(new InvalidNotificationTypeException('Invalid notification type.'));
2✔
73
            return null;
2✔
74
        }
75

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

81
        foreach (array_values($this->_notifications[$notification_type]) as $callback) {
20✔
82
            if ($notification_callback == $callback) {
16✔
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}'.");
2✔
86
                return -1;
2✔
87
            }
88
        }
89

90
        $this->_notifications[$notification_type][$this->_notificationId] = $notification_callback;
20✔
91
        $this->_logger->log(Logger::INFO, "Callback added for notification type '{$notification_type}'.");
20✔
92
        $returnVal = $this->_notificationId++;
20✔
93
        return $returnVal;
20✔
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) {
2✔
107
            foreach (array_keys($notifications) as $id) {
2✔
108
                if ($notification_id == $id) {
2✔
109
                    unset($this->_notifications[$notification_type][$id]);
2✔
110
                    $this->_logger->log(Logger::INFO, "Callback with notification ID '{$notification_id}' has been removed.");
2✔
111
                    return true;
2✔
112
                }
113
            }
114
        }
115

116
        $this->_logger->log(Logger::DEBUG, "No Callback found with notification ID '{$notification_id}'.");
2✔
117
        return false;
2✔
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(
2✔
128
            Logger::WARNING,
2✔
129
            "'clearNotifications' is deprecated. Call 'clearNotificationListeners' instead."
2✔
130
        );
2✔
131
        $this->clearNotificationListeners($notification_type);
2✔
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)) {
2✔
142
            $this->_logger->log(Logger::ERROR, "Invalid notification type.");
2✔
143
            $this->_errorHandler->handleError(new InvalidNotificationTypeException('Invalid notification type.'));
2✔
144
            return;
2✔
145
        }
146

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

151
    /**
152
     * Logs deprecation message
153
     *
154
     * @deprecated Use 'clearAllNotificationListeners' instead.
155
     */
156
    public function cleanAllNotifications()
157
    {
158
        $this->_logger->log(
2✔
159
            Logger::WARNING,
2✔
160
            "'cleanAllNotifications' is deprecated. Call 'clearAllNotificationListeners' instead."
2✔
161
        );
2✔
162
        $this->clearAllNotificationListeners();
2✔
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) {
20✔
172
            $this->_notifications[$type] = [];
20✔
173
        }
174
    }
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])) {
154✔
185
            // No exception thrown and error logged since this method will be called from
186
            // within the SDK
187
            return;
2✔
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);
154✔
200

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

211
        restore_error_handler();
154✔
212
    }
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.");
2✔
220
        $this->_errorHandler->handleError(
2✔
221
            new InvalidCallbackArgumentCountException('Registered callback expects more number of arguments than the actual number')
2✔
222
        );
2✔
223
    }
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