Skip to content

Commit ec3d237

Browse files
Kaustubh22327rohitesh-wingify
authored andcommitted
fix: debug events, multi instance, deprecation warnings
1 parent 8a5338b commit ec3d237

23 files changed

Lines changed: 174 additions & 73 deletions

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.11.0] - 2026-08-06
9+
10+
### Fixed
11+
12+
- Fixed several bugs: wrong user ID in debug events, broken tracking URLs with special characters, mixed-up credentials when running multiple SDK instances, failed Gateway requests for some accounts, and PHP 8.4/8.5 deprecation warnings.
13+
814
## [2.10.0] - 2026-07-04
915

1016
### Added

‎composer.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "wingify/wingify-fme-php-sdk",
3-
"version": "2.10.0",
3+
"version": "2.11.0",
44
"keywords": [
55
"wingify",
66
"fme",

‎src/Api/GetFlag.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,8 +623,8 @@ public function get(
623623
// Update debug event props with decision keys
624624
$this->updateDebugEventPropsWithDecisionKeys($debugEventProps, $decision);
625625

626-
// Send debug event
627-
DebuggerServiceUtil::sendDebugEvent($debugEventProps);
626+
// Send debug event scoped to this SDK instance (multi-instance safe).
627+
DebuggerServiceUtil::sendDebugEvent($debugEventProps, $serviceContainer);
628628
}
629629

630630
// Send data for Impact Campaign, if defined

‎src/Api/SetAttribute.php‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class SetAttribute implements ISetAttribute
4343
* @param array $attributes Key-value map of attributes.
4444
* @param ContextModel $context Context containing user information.
4545
*/
46-
public function setAttribute(SettingsModel $settings, array $attributes, ContextModel $context, bool $isDebuggerUsed = false, ServiceContainer $serviceContainer = null)
46+
public function setAttribute(SettingsModel $settings, array $attributes, ContextModel $context, bool $isDebuggerUsed = false, $serviceContainer = null)
4747
{
4848
if (!$isDebuggerUsed) {
4949
$this->createImpressionForAttributes($settings, $attributes, $context, $serviceContainer);
@@ -57,7 +57,8 @@ public function setAttribute(SettingsModel $settings, array $attributes, Context
5757
* @param ContextModel $context Context containing user information.
5858
* @param ServiceContainer $serviceContainer The service container (optional).
5959
*/
60-
private function createImpressionForAttributes(SettingsModel $settings, array $attributes, ContextModel $context, ServiceContainer $serviceContainer = null)
60+
/** @param ServiceContainer|null $serviceContainer */
61+
private function createImpressionForAttributes(SettingsModel $settings, array $attributes, ContextModel $context, $serviceContainer = null)
6162
{
6263
$networkUtil = new NetworkUtil($serviceContainer);
6364

‎src/Api/TrackEvent.php‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class TrackEvent implements ITrack
5454
* @param HooksService $hooksService Manager for handling hooks and callbacks.
5555
* @return array Returns an array indicating the success or failure of the event tracking.
5656
*/
57-
public function track(SettingsModel $settings, string $eventName, ContextModel $context, array $eventProperties, HooksService $hooksService, bool $isDebuggerUsed = false, ServiceContainer $serviceContainer = null): array
57+
public function track(SettingsModel $settings, string $eventName, ContextModel $context, array $eventProperties, HooksService $hooksService, bool $isDebuggerUsed = false, $serviceContainer = null): array
5858
{
5959
if (FunctionUtil::doesEventBelongToAnyFeature($eventName, $settings) || FunctionUtil::doesEventBelongToAnyHoldout($eventName, $settings)) {
6060
// Create an impression for the track event
@@ -90,7 +90,8 @@ public function track(SettingsModel $settings, string $eventName, ContextModel $
9090
* @param array $eventProperties Properties associated with the event.
9191
* @param ServiceContainer $serviceContainer The service container (optional).
9292
*/
93-
private function createImpressionForTrack(SettingsModel $settings, string $eventName, ContextModel $context, array $eventProperties, ServiceContainer $serviceContainer = null)
93+
/** @param ServiceContainer|null $serviceContainer */
94+
private function createImpressionForTrack(SettingsModel $settings, string $eventName, ContextModel $context, array $eventProperties, $serviceContainer = null)
9495
{
9596
$networkUtil = new NetworkUtil($serviceContainer);
9697

‎src/Constants/Constants.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class Constants {
4949
const DEFAULT_EVENTS_PER_REQUEST = 100;
5050
const SDK_NAME = 'wingify-fme-php-sdk';
5151

52-
const SDK_VERSION = '2.10.0';
52+
const SDK_VERSION = '2.11.0';
5353
const AP = 'server';
5454

5555
const SETTINGS = 'settings';

‎src/Decorators/StorageDecorator.php‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,16 @@
3030

3131
interface IStorageDecorator
3232
{
33-
public function getFeatureFromStorage($featureKey, $context, $storageService, ServiceContainer $serviceContainer = null);
34-
public function setDataInStorage($data, $storageService, ServiceContainer $serviceContainer = null);
33+
/** @param ServiceContainer|null $serviceContainer */
34+
public function getFeatureFromStorage($featureKey, $context, $storageService, $serviceContainer = null);
35+
/** @param ServiceContainer|null $serviceContainer */
36+
public function setDataInStorage($data, $storageService, $serviceContainer = null);
3537
}
3638

3739
class StorageDecorator implements IStorageDecorator
3840
{
39-
public function getFeatureFromStorage($featureKey, $context, $storageService, ServiceContainer $serviceContainer = null)
41+
/** @param ServiceContainer|null $serviceContainer */
42+
public function getFeatureFromStorage($featureKey, $context, $storageService, $serviceContainer = null)
4043
{
4144
$campaignMap = $storageService->getDataInStorage($featureKey, $context, $serviceContainer);
4245

@@ -58,7 +61,8 @@ public function getFeatureFromStorage($featureKey, $context, $storageService, Se
5861
}
5962
}
6063

61-
public function setDataInStorage($data, $storageService, ServiceContainer $serviceContainer = null)
64+
/** @param ServiceContainer|null $serviceContainer */
65+
public function setDataInStorage($data, $storageService, $serviceContainer = null)
6266
{
6367
$featureKey = $data['featureKey'] ?? null;
6468
$featureId = $data['featureId'] ?? null;

‎src/Packages/NetworkLayer/Client/NetworkClient.php‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,10 @@ private function makeCurlRequest($request, $url, $method, $headers, $body = null
116116
$response = curl_exec($ch);
117117
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
118118
$error = curl_error($ch);
119-
curl_close($ch);
119+
// For PHP < 8.0, $ch is a resource and requires curl_close. For PHP >= 8.0, it's a CurlHandle object and closes automatically.
120+
if (is_resource($ch)) {
121+
curl_close($ch);
122+
}
120123

121124
$responseModel = new ResponseModel($response, $httpCode, $error);
122125

‎src/Packages/NetworkLayer/Models/RequestModel.php‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,11 @@ public function setPath($path) {
146146
public function getOptions() {
147147
$queryParams = '';
148148
foreach ($this->query as $key => $value) {
149-
$queryParams .= "{$key}={$value}&";
149+
if ($value === null) {
150+
continue;
151+
}
152+
// Encode query values (e.g. visitor_ua) so special characters do not break trackEvent/setAttribute URLs.
153+
$queryParams .= rawurlencode((string) $key) . '=' . rawurlencode((string) $value) . '&';
150154
}
151155
$queryParams = rtrim($queryParams, '&');
152156

‎src/Packages/SegmentationEvaluator/Core/SegmentationManager.php‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@ public function setContextualData(ServiceContainer $serviceContainer, $feature,
5252
$settings = $serviceContainer->getSettings();
5353
$loggerService = $serviceContainer->getLoggerService();
5454

55-
$this->attachEvaluator(); // Ensure a fresh evaluator instance
55+
// Pass serviceContainer into SegmentEvaluator so SegmentOperandEvaluator is also wired.
56+
// Previously only $this->evaluator->serviceContainer was set, leaving
57+
// segmentOperandEvaluator->serviceContainer null and causing
58+
// "Call to a member function getLogManager() on null" during holdout/IP/UA segmentation.
59+
$this->attachEvaluator(new SegmentEvaluator($serviceContainer, $context, $feature));
5660
$this->evaluator->settings = $settings; // Set settings in evaluator
57-
$this->evaluator->serviceContainer = $serviceContainer; // Set serviceContainer in evaluator
58-
$this->evaluator->context = $context; // Set context in evaluator
59-
$this->evaluator->feature = $feature; // Set feature in evaluator
6061

6162
// if both user agent and ip is null then we should not get data from gateway service
6263
if ($context->getUserAgent() === null && $context->getIpAddress() === null) {

0 commit comments

Comments
 (0)