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

wingify / vwo-php-sdk / 5186579049

pending completion
5186579049

push

github

softvar
feat(meg): added support for weights and priority in MEG

36 of 36 new or added lines in 1 file covered. (100.0%)

1514 of 1700 relevant lines covered (89.06%)

56.14 hits per line

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

93.88
/src/Core/VariationDecider.php
1
<?php
2

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

19
namespace vwo\Core;
20

21
use Exception as Exception;
22
use Monolog\Logger as Logger;
23
use vwo\Constants\CampaignTypes;
24
use vwo\Constants\Hooks;
25
use vwo\Utils\Common as CommonUtil;
26
use vwo\Utils\Campaign as CampaignUtil;
27
use vwo\Services\LoggerService;
28
use vwo\Services\HooksManager;
29
use vwo\Core\Bucketer as Bucketer;
30
use vwo\Utils\ImpressionBuilder;
31
use vwo\Utils\UuidUtil;
32
use vwo\Utils\Validations as ValidationsUtil;
33

34
class VariationDecider
35
{
36
    public $hasStoredVariation;
37
    private $accountId;
38
    private $hooksManager;
39
    private $settings;
40

41
    const CLASSNAME = 'vwo\Core\VariationDecider';
42
    const RandomAlgo = 1;
43

44
    function __construct($settings = null)
45
    {
46
        $this->settings = $settings;
248✔
47
    }
248✔
48

49
    public function getAccountId()
50
    {
51
        return $this->accountId;
×
52
    }
53

54
    public function setAccountId($accountId)
55
    {
56
        $this->accountId = $accountId;
232✔
57
    }
232✔
58

59
    public function setHooksManager($hooksManager)
60
    {
61
        $this->hooksManager = $hooksManager;
248✔
62
    }
248✔
63

64
    public function getHooksManager()
65
    {
66
        return $this->hooksManager;
×
67
    }
68

69
    /**
70
     * Returns variation for the user for given campaign
71
     * This method achieves the variation assignment in the following way:
72
     * If campaign is part of any group, the winner is found in the following way:
73
     * 1. Check whitelisting for called campaign, if passed return targeted variation.
74
     * 2. Check user storage for called campaign, if passed return stored variation.
75
     * 3. Check presegmentation and traffic allocation for called campaign, if passed then
76
     * check whitelisting and user storage for other campaigns of same group if any
77
     * campaign passes return None else find eligible campaigns
78
     * 4. Find winner campaign from eligible campaigns and if winner campaign is same as
79
     * called campaign return bucketed variation and store variation in user storage,
80
     * however if winner campaign is not called campaign return None
81
     *
82
     * However if campaign is not part of any group, then this method achieves the variation
83
     * assignment in the following way:
84
     * 1. First get variation from UserStorage, if variation is found in user_storage_data,
85
     * return from there
86
     * 2. Evaluates white listing users for each variation, and find a targeted variation.
87
     * 3. If no targeted variation is found, evaluate pre-segmentation result
88
     * 4. Evaluate percent traffic
89
     * 5. If user becomes part of campaign assign a variation.
90
     * 6. Store the variation found in the user_storage
91
     *
92
     * @param  $userStorageObj
93
     * @param  $campaign
94
     * @param  $userId
95
     * @param  array $options
96
     * @param  $apiName
97
     * @param  $goalIdentifier
98
     * @return array|mixed|null
99
     */
100
    public function fetchVariationData($userStorageObj, $campaign, $userId, $options = [], $apiName = '', $goalIdentifier = '')
101
    {
102
        LoggerService::setApiName($apiName);
180✔
103
        $bucketInfo = null;
180✔
104
        $this->hasStoredVariation = false;
180✔
105

106
        if ($campaign == null) {
180✔
107
            return $bucketInfo;
4✔
108
        }
109

110
        $isCampaignPartOfGroup = $this->settings && CampaignUtil::isPartOfGroup($this->settings, $campaign["id"]);
180✔
111
        $campaignKey = $campaign['key'];
180✔
112
        $decision['isUserWhitelisted'] = false;
180✔
113
        $decision['fromUserStorageService'] = false;
180✔
114

115
        // VWO generated UUID based on passed UserId and Account ID
116
        if (isset($this->accountId)) {
180✔
117
            $decision['vwoUserId'] = UuidUtil::get($userId, $this->accountId);
172✔
118
        }
119

120
        if ($isCampaignPartOfGroup) {
180✔
121
            $groupId = $this->settings["campaignGroups"][$campaign["id"]];
76✔
122
            $decision["groupId"] = $groupId;
76✔
123
            $groupName = $this->settings["groups"][$groupId]["name"];
76✔
124
            $decision["groupName"] = $groupName;
76✔
125
        }
126

127
        //check for whitelisting if applied and get Variation Info
128
        $bucketInfo = CampaignUtil::findVariationFromWhiteListing($campaign, $userId, $options);
180✔
129
        // do murmur operations and get Variation for the userId
130
        if ($bucketInfo == null) {
180✔
131
            if (isset($campaign['isAlwaysCheckSegment'])) {
164✔
132
                $isPreSegmentation = ValidationsUtil::checkPreSegmentation($campaign, $userId, $options);
4✔
133
                $bucketInfo = $this->getVariationIfPreSegmentationApplied($isPreSegmentation, $campaign, $userId, $userStorageObj, $goalIdentifier);
4✔
134
            } else {
135
                $bucketInfo = $this->userStorageGet($userStorageObj, $userId, $campaign);
160✔
136
                if ($bucketInfo == null) {
160✔
137
                    if (self::checkCampaignNotActivated($apiName, $userStorageObj, $userId, $campaignKey)) {
140✔
138
                        return $bucketInfo;
8✔
139
                    }
140

141
                    $isPresegmentation = ValidationsUtil::checkPreSegmentation($campaign, $userId, $options);
136✔
142
                    $isPresegmentationAndTrafficPassed = $isPresegmentation && self::isUserPartOfCampaign($userId, $campaign['percentTraffic']);
136✔
143
                    if ($isPresegmentationAndTrafficPassed && $isCampaignPartOfGroup) {
136✔
144
                        $groupCampaigns = CampaignUtil::getGroupCampaigns($this->settings, $groupId);
48✔
145

146
                        if ($groupCampaigns) {
48✔
147
                            $isAnyCampaignWhitelistedOrStored = $this->checkWhitelistingOrStorageForGroupedCampaigns($userStorageObj, $userId, $campaign, $groupCampaigns, $groupName, $options);
48✔
148

149
                            // Return None as other campaign(s) is/are whitelisted or stored
150
                            if ($isAnyCampaignWhitelistedOrStored) {
48✔
151
                                LoggerService::log(
8✔
152
                                    Logger::INFO,
8✔
153
                                    'MEG_CALLED_CAMPAIGN_NOT_WINNER',
8✔
154
                                    [
155
                                        '{userId}' => $userId,
8✔
156
                                        '{campaignKey}' => $campaign["key"],
8✔
157
                                        '{groupName}' => $groupName
8✔
158
                                    ],
159
                                    self::CLASSNAME
8✔
160
                                );
161
                                return null;
8✔
162
                            }
163

164
                            $eligibleCampaigns = self::getEligibleCampaigns($userId, $groupCampaigns, $campaign, $options);
40✔
165
                            $megAlgoNumber = isset($this->settings["groups"][$groupId]["et"]) ? $this->settings["groups"][$groupId]["et"] : self::RandomAlgo ;
40✔
166

167
                            $nonEligibleCampaignsKey = self::getNonEligibleCampaignsKey($eligibleCampaigns, $groupCampaigns);
40✔
168
                            LoggerService::log(
40✔
169
                                Logger::DEBUG,
40✔
170
                                'MEG_ELIGIBLE_CAMPAIGNS',
40✔
171
                                [
172
                                    '{userId}' => $userId,
40✔
173
                                    '{eligibleCampaignKeys}' => implode(",", self::getEligibleCampaignsKey($eligibleCampaigns)),
40✔
174
                                    '{inEligibleText}' => "campaigns:" . ($nonEligibleCampaignsKey ? implode(",", $nonEligibleCampaignsKey) : "no campaigns"),
40✔
175
                                    '{groupName}' => $groupName
40✔
176
                                ],
177
                                self::CLASSNAME
40✔
178
                            );
179

180
                            LoggerService::log(
40✔
181
                                Logger::INFO,
40✔
182
                                'MEG_ELIGIBLE_CAMPAIGNS',
40✔
183
                                [
184
                                    '{userId}' => $userId,
40✔
185
                                    '{noOfEligibleCampaigns}' => count($eligibleCampaigns),
40✔
186
                                    '{noOfGroupCampaigns}' => count($groupCampaigns),
40✔
187
                                    '{groupName}' => $groupName
40✔
188
                                ],
189
                                self::CLASSNAME
40✔
190
                            );
191
                            $winnerCampaign = $this->findWinnerCampaign($userId, $eligibleCampaigns, $megAlgoNumber, $groupId, $this->settings);
40✔
192

193
                            LoggerService::log(
40✔
194
                                Logger::INFO,
40✔
195
                                'MEG_GOT_WINNER_CAMPAIGN',
40✔
196
                                [
197
                                    '{userId}' => $userId,
40✔
198
                                    '{campaignKey}' => $winnerCampaign["key"],
40✔
199
                                    '{groupName}' => $groupName
40✔
200
                                ],
201
                                self::CLASSNAME
40✔
202
                            );
203
                            if ($winnerCampaign && $winnerCampaign["id"] == $campaign["id"]) {
40✔
204
                                $bucketInfo = Bucketer::getBucket($userId, $campaign);
28✔
205
                                if ($bucketInfo == null) {
28✔
206
                                    return $bucketInfo;
×
207
                                } else {
208
                                    $this->userStorageSet($userStorageObj, $userId, $campaign['key'], $bucketInfo, $goalIdentifier);
28✔
209
                                }
210
                            } else {
211
                                // No winner/variation
212
                                LoggerService::log(
24✔
213
                                    Logger::INFO,
24✔
214
                                    'MEG_CALLED_CAMPAIGN_NOT_WINNER',
24✔
215
                                    [
216
                                        '{userId}' => $userId,
24✔
217
                                        '{campaignKey}' => $campaign["key"],
24✔
218
                                        '{groupName}' => $groupName
24✔
219
                                    ],
220
                                    self::CLASSNAME
24✔
221
                                );
222
                                return $bucketInfo;
24✔
223
                            }
224
                        }
225
                    }
226

227
                    if ($bucketInfo == null) {
116✔
228
                        $bucketInfo = $this->getVariationIfPreSegmentationApplied($isPresegmentation, $campaign, $userId, $userStorageObj, $goalIdentifier);
116✔
229
                    }
230
                } else {
231
                    $this->hasStoredVariation = true;
28✔
232
                    $decision['fromUserStorageService'] = !!$bucketInfo['name'];
28✔
233
                    LoggerService::log(
28✔
234
                        Logger::INFO,
28✔
235
                        'GOT_STORED_VARIATION',
28✔
236
                        [
237
                            '{userId}' => $userId,
28✔
238
                            '{variationName}' => $bucketInfo['name'],
28✔
239
                            '{campaignKey}' => $campaign['key']
28✔
240
                        ],
241
                        self::CLASSNAME
144✔
242
                    );
243
                }
244
            }
245
        } else {
246
            $decision['isUserWhitelisted'] = true;
20✔
247
        }
248

249
        if ($bucketInfo != null) {
160✔
250
            $decision['campaignId'] = $campaign['id'];
144✔
251
            $decision['campaignKey'] = $campaignKey;
144✔
252
            $decision['campaignType'] = $campaign['type'];
144✔
253
            // campaign segmentation conditions
254
            $decision['customVariables'] = isset($options['customVariables']) ? $options['customVariables'] : [];
144✔
255
            // event name
256
            $decision['event'] = Hooks::DECISION_TYPES['CAMPAIGN_DECISION'];
144✔
257
            // goal tracked in case of track API
258
            $decision['goalIdentifier'] = $goalIdentifier;
144✔
259
            // campaign whitelisting flag
260
            $decision['isForcedVariationEnabled'] = isset($campaign['isForcedVariationEnabled']) ? $campaign['isForcedVariationEnabled'] : false;
144✔
261
            $decision['sdkVersion'] = ImpressionBuilder::SDK_VERSION;
144✔
262
            // API name which triggered the event
263
            $decision['source'] = $apiName;
144✔
264
            // Passed in API
265
            $decision['userId'] = $userId;
144✔
266
            // Campaign Whitelisting conditions
267
            $decision['variationTargetingVariables'] = isset($options['variationTargetingVariables']) ? $options['variationTargetingVariables'] : [];
144✔
268

269
            if (isset($campaign['name'])) {
144✔
270
                $decision["campaignName"] = $campaign["name"];
124✔
271
            }
272

273
            $variationName = $bucketInfo['name'];
144✔
274
            if ($campaign['type'] === CampaignTypes::FEATURE_ROLLOUT) {
144✔
275
                $decision['isFeatureEnabled'] = true;
24✔
276
            } else {
277
                if ($campaign['type'] === CampaignTypes::FEATURE_TEST) {
120✔
278
                    $decision['isFeatureEnabled'] = $bucketInfo['isFeatureEnabled'];
28✔
279
                }
280
                $decision['variationName'] = $variationName;
120✔
281
                $decision['variationId'] = $bucketInfo['id'];
120✔
282
            }
283
            $this->hooksManager->execute($decision);
144✔
284
        }
285

286
        return $bucketInfo;
160✔
287
    }
288

289
    /***
290
     * @param  $userStorageObj
291
     * @param  $userId
292
     * @param  $campaign
293
     * @param  bool $disableLogs    optional: disable logs if True
294
     * @return array|null
295
     */
296
    private function userStorageGet($userStorageObj, $userId, $campaign, $disableLogs = false)
297
    {
298

299
        if (!empty($userStorageObj)) {
164✔
300
            $campaignKey = $campaign['key'];
36✔
301
            try {
302
                $variationInfo = $userStorageObj->get($userId, $campaignKey);
36✔
303
            } catch (Exception $e) {
×
304
                $variationInfo = null;
×
305
                LoggerService::log(
×
306
                    Logger::ERROR,
×
307
                    'USER_STORAGE_SERVICE_GET_FAILED',
×
308
                    ['{userId}' => $userId, '{error}' => $e->getMessage()],
×
309
                    self::CLASSNAME
×
310
                );
311
            }
312

313
            if (
314
                isset($variationInfo['variationName']) && is_string(
36✔
315
                    $variationInfo['variationName']
36✔
316
                ) && !empty($variationInfo['variationName']) && array_key_exists('campaignKey', $variationInfo) && $variationInfo['campaignKey'] == $campaignKey
36✔
317
            ) {
318
                LoggerService::log(
36✔
319
                    Logger::INFO,
36✔
320
                    'GETTING_DATA_USER_STORAGE_SERVICE',
36✔
321
                    ['{userId}' => $userId, '{campaignKey}' => $campaignKey],
36✔
322
                    self::CLASSNAME,
36✔
323
                    $disableLogs
36✔
324
                );
325
                if ($campaign !== null) {
36✔
326
                    $bucketInfo = Bucketer::getBucketVariationId(
36✔
327
                        $campaign,
36✔
328
                        $variationInfo['variationName']
36✔
329
                    );
330
                    if (isset($variationInfo['goalIdentifier'])) {
36✔
331
                        $bucketInfo['goalIdentifier'] = $variationInfo['goalIdentifier'];
4✔
332
                    }
333
                    return $bucketInfo;
36✔
334
                }
335
            } else {
336
                LoggerService::log(
12✔
337
                    Logger::DEBUG,
12✔
338
                    'USER_STORAGE_SERVICE_NO_STORED_DATA',
12✔
339
                    ['{userId}' => $userId, '{campaignKey}' => $campaignKey],
12✔
340
                    self::CLASSNAME,
12✔
341
                    $disableLogs
12✔
342
                );
343
            }
344
        } else {
345
            LoggerService::log(
132✔
346
                Logger::DEBUG,
132✔
347
                'USER_STORAGE_SERVICE_NOT_CONFIGURED',
132✔
348
                [],
132✔
349
                self::CLASSNAME,
132✔
350
                $disableLogs
132✔
351
            );
352
        }
353

354
        return null;
140✔
355
    }
356

357
    /**
358
     * this function will save the data to user-storage
359
     *
360
     * @param string $userId
361
     * @param string $campaignKey
362
     * @param array  $variation
363
     * @param string $goalIdentifier
364
     */
365
    public function userStorageSet($userStorageObj, $userId, $campaignKey, $variation, $goalIdentifier = '')
366
    {
367
        if (!empty($userStorageObj)) {
112✔
368
            $campaignInfo = CommonUtil::getUserCampaignVariationMapping($campaignKey, $variation, $userId, $goalIdentifier);
12✔
369
            try {
370
                $userStorageObj->set($campaignInfo);
12✔
371
            } catch (Exception $e) {
×
372
                LoggerService::log(
×
373
                    Logger::ERROR,
×
374
                    'USER_STORAGE_SERVICE_GET_FAILED',
×
375
                    ['{userId}' => $userId, '{error}' => $e->getMessage()],
×
376
                    self::CLASSNAME
×
377
                );
378
            }
379
            LoggerService::log(
12✔
380
                Logger::INFO,
12✔
381
                'SETTING_DATA_USER_STORAGE_SERVICE',
12✔
382
                ['{userId}' => $userId, '{campaignKey}' => $campaignKey],
12✔
383
                self::CLASSNAME
12✔
384
            );
385
        } else {
386
            LoggerService::log(Logger::DEBUG, 'USER_STORAGE_SERVICE_NOT_CONFIGURED', [], self::CLASSNAME);
104✔
387
        }
388
    }
112✔
389

390
    /**
391
     * Finds and returns eligible campaigns from $groupCampaigns.
392
     *
393
     * @param  string $userId         the unique ID assigned to User
394
     * @param  array  $groupCampaigns campaigns part of group
395
     * @param  array  $calledCampaign campaign for which api is called
396
     * @param  array  $options        contains variables for segmentation
397
     * @return array  eligible campaigns from which winner campaign is to be selected
398
     */
399
    private static function getEligibleCampaigns($userId, $groupCampaigns, $calledCampaign, $options)
400
    {
401
        $eligibleCampaigns = [];
40✔
402
        foreach ($groupCampaigns as $campaign) {
40✔
403
            if ($calledCampaign["id"] == $campaign["id"] || ValidationsUtil::checkPreSegmentation($campaign, $userId, $options, true) && self::isUserPartOfCampaign($userId, $campaign['percentTraffic'])) {
40✔
404
                $eligibleCampaigns[] = $campaign;
40✔
405
            }
406
        }
407
        return $eligibleCampaigns;
40✔
408
    }
409

410
    /**
411
     * Evaluates whether the user should become part of campaign or not
412
     *
413
     * @param  string    $userId         the unique ID assigned to User
414
     * @param  int|float $percentTraffic traffic for a campaign in which user is participating
415
     * @return bool
416
     */
417
    private static function isUserPartOfCampaign($userId, $percentTraffic)
418
    {
419
        list($bucketVal, $hashValue) = Bucketer::getBucketVal($userId, [], true);
124✔
420
        return Bucketer::isUserPartofCampaign($bucketVal, $percentTraffic);
124✔
421
    }
422

423
    /**
424
     * Finds and returns the winner campaign from $eligibleCampaigns list.
425
     *
426
     * @param  string $userId            the unique ID assigned to User
427
     * @param  array  $eligibleCampaigns campaigns part of group which were eligible to be winner
428
     * @return array  winner campaign from eligible_campaigns
429
     */
430
    private static function findWinnerCampaign($userId, $eligibleCampaigns, $megAlgoNumber, $groupId, $settingsFile)
431
    {
432
        if (count($eligibleCampaigns) == 1) {
40✔
433
            return  $eligibleCampaigns[0];
×
434
        } else {
435
            if ($megAlgoNumber == self::RandomAlgo) {
40✔
436
            //Scale the traffic percent of each campaign
437
                $eligibleCampaigns = CampaignUtil::scaleCampaigns($eligibleCampaigns);
20✔
438
            //Allocate new range for campaigns
439
                $eligibleCampaigns = Bucketer::addRangesToCampaigns($eligibleCampaigns);
20✔
440
            //Now retrieve the campaign from the modified_campaign_for_whitelisting
441
                list($bucketVal, $hashValue) = Bucketer::getBucketVal($userId, [], true);
20✔
442
                return Bucketer::getCampaignUsingRange($bucketVal, $eligibleCampaigns);
20✔
443
            } else {
444
                $winnerCampaign = null;
20✔
445

446
                $found = false; // flag to check whether winnerCampaign has been found or not and helps to break from the outer loop
20✔
447
                $priorityOrder = isset($settingsFile['groups'][$groupId]['p']) ? $settingsFile['groups'][$groupId]['p'] : [];
20✔
448
                $wt = isset($settingsFile['groups'][$groupId]['wt']) ? $settingsFile['groups'][$groupId]['wt'] : [];
20✔
449

450
                for ($i = 0; $i < count($priorityOrder); $i++) {
20✔
451
                    for ($j = 0; $j < count($eligibleCampaigns); $j++) {
8✔
452
                        if ($eligibleCampaigns[$j]['id'] == $priorityOrder[$i]) {
8✔
453
                            $winnerCampaign = $eligibleCampaigns[$j];
8✔
454
                            $found = true;
8✔
455
                            break;
8✔
456
                        }
457
                    }
458
                    if ($found == true) {
8✔
459
                        break;
8✔
460
                    }
461
                }
462

463
                // If winnerCampaign not found through Priority, then go for weighted Random distribution and for that,
464
                // Store the list of campaigns (participatingCampaigns) out of eligibleCampaigns and their corresponding weights which are present in weightage distribution array (wt) in 2 different lists
465
                if ($winnerCampaign == null) {
20✔
466
                    $weights = array();
12✔
467
                    $partipatingCampaignList = array();
12✔
468

469
                    for ($i = 0; $i < count($eligibleCampaigns); $i++) {
12✔
470
                        $campaignId = $eligibleCampaigns[$i]['id'];
12✔
471
                        if (isset($wt[$campaignId])) {
12✔
472
                            $weights[] = $wt[$campaignId];
12✔
473
                            $partipatingCampaignList[] = $eligibleCampaigns[$i];
12✔
474
                        }
475
                    }
476

477
                    /*
478
                    * Finding winner campaign using weighted random distribution :
479
                    1. Calculate the sum of all weights
480
                    2. Generate a random number between 0 and the weight sum:
481
                    3. Iterate over the weights array and subtract each weight from the random number until the random number becomes negative. The corresponding ith value is the required value
482
                    4. Set the ith campaign as WinnerCampaign
483
                    */
484
                    $weightSum = array_sum($weights);
12✔
485
                    $randomNumber = rand(1, $weightSum);
12✔
486

487
                    $sum = 0;
12✔
488
                    for ($i = 0; $i < count($weights); $i++) {
12✔
489
                        $sum += $weights[$i];
12✔
490
                        if ($randomNumber < $sum) {
12✔
491
                            $winnerCampaign = $partipatingCampaignList[$i];
12✔
492
                            break;
12✔
493
                        }
494
                    }
495
                }
496

497
                return $winnerCampaign;
20✔
498
            }
499
        }
500
    }
501

502
    /**
503
     * Get campaign keys of all eligibleCampaigns.
504
     *
505
     * @param  array $eligibleCampaigns contains eligibleCampaigns
506
     * @return array campaign keys of all eligibleCampaigns
507
     */
508
    private static function getEligibleCampaignsKey($eligibleCampaigns)
509
    {
510
        $eligibleCampaignsName = [];
40✔
511
        foreach ($eligibleCampaigns as $campaign) {
40✔
512
            $eligibleCampaignsName[] = $campaign["key"];
40✔
513
        }
514
        return $eligibleCampaignsName;
40✔
515
    }
516

517
    /**
518
     * get campaign keys of all non eligibleCampaigns.
519
     *
520
     * @param  array $eligibleCampaigns contains eligibleCampaigns
521
     * @param  array $groupCampaigns    contains groupCampaigns
522
     * @return array campaign keys of all non eligibleCampaigns
523
     */
524
    private static function getNonEligibleCampaignsKey($eligibleCampaigns, $groupCampaigns)
525
    {
526
        $NonEligibleCampaignsName = [];
40✔
527
        foreach ($groupCampaigns as $groupCampaign) {
40✔
528
            if (!in_array($groupCampaign, $eligibleCampaigns)) {
40✔
529
                $NonEligibleCampaignsName[] = $groupCampaign["key"];
×
530
            }
531
        }
532
        return $NonEligibleCampaignsName;
40✔
533
    }
534

535
    /**
536
     * Checks if any other campaign in groupCampaigns satisfies whitelisting or is in user storage.
537
     *
538
     * @param  object $userStorageObj userStorage object
539
     * @param  string $userId         the unique ID assigned to User
540
     * @param  array  $calledCampaign
541
     * @param  array  $groupCampaigns campaigns part of group
542
     * @param  string $groupName      group name
543
     * @param  array  $options        contains variationTargetingVariables
544
     * @return bool
545
     */
546
    private function checkWhitelistingOrStorageForGroupedCampaigns($userStorageObj, $userId, $calledCampaign, $groupCampaigns, $groupName, $options)
547
    {
548
        foreach ($groupCampaigns as $campaign) {
48✔
549
            if ($calledCampaign["id"] != $campaign["id"]) {
48✔
550
                $targetedVariation = CampaignUtil::findVariationFromWhiteListing($campaign, $userId, $options, true);
48✔
551
                if ($targetedVariation) {
48✔
552
                    LoggerService::log(
4✔
553
                        Logger::INFO,
4✔
554
                        'OTHER_CAMPAIGN_SATISFIES_WHITELISTING_STORAGE',
4✔
555
                        [
556
                            '{userId}' => $userId,
4✔
557
                            '{campaignKey}' => $campaign["key"],
4✔
558
                            '{groupName}' => $groupName,
4✔
559
                            '{type}' => "whitelisting"
4✔
560
                        ],
561
                        self::CLASSNAME
4✔
562
                    );
563
                    return true;
4✔
564
                }
565
            }
566
        }
567

568
        foreach ($groupCampaigns as $campaign) {
44✔
569
            if ($calledCampaign["id"] != $campaign["id"]) {
44✔
570
                $userStorageData = $this->userStorageGet($userStorageObj, $userId, $campaign, true);
44✔
571
                if ($userStorageData) {
44✔
572
                    LoggerService::log(
4✔
573
                        Logger::INFO,
4✔
574
                        'OTHER_CAMPAIGN_SATISFIES_WHITELISTING_STORAGE',
4✔
575
                        [
576
                            '{userId}' => $userId,
4✔
577
                            '{campaignKey}' => $campaign["key"],
4✔
578
                            '{groupName}' => $groupName,
4✔
579
                            '{type}' => "user storage"
4✔
580
                        ],
581
                        self::CLASSNAME
4✔
582
                    );
583
                    return true;
4✔
584
                }
585
            }
586
        }
587
        return false;
40✔
588
    }
589

590
    /**
591
     * Checks if campaign is activated for track, getVariationName, getFeatureVariableValue API when userStorage is used
592
     *
593
     * @param  string $apiName        api name
594
     * @param  object $userStorageObj userStorage object
595
     * @param  string $userId         the unique ID assigned to User
596
     * @param  string $campaignKey    Campaign Key
597
     * @return bool
598
     */
599
    private static function checkCampaignNotActivated($apiName, $userStorageObj, $userId, $campaignKey)
600
    {
601
        if (
602
            in_array($apiName, ['track', 'getVariationName', 'getFeatureVariableValue'])
140✔
603
            && !empty($userStorageObj)
140✔
604
        ) {
605
            LoggerService::log(
8✔
606
                Logger::WARNING,
8✔
607
                'CAMPAIGN_NOT_ACTIVATED',
8✔
608
                ['{userId}' => $userId, '{campaignKey}' => $campaignKey, '{api}' => $apiName],
8✔
609
                self::CLASSNAME
8✔
610
            );
611
            LoggerService::log(
8✔
612
                Logger::INFO,
8✔
613
                'CAMPAIGN_NOT_ACTIVATED',
8✔
614
                [
615
                    '{userId}' => $userId,
8✔
616
                    '{campaignKey}' => $campaignKey,
8✔
617
                    '{reason}' => $apiName === 'track' ? 'track it' : 'get the decision/value'
8✔
618
                ],
619
                self::CLASSNAME
8✔
620
            );
621
            return true;
8✔
622
        }
623
        return false;
136✔
624
    }
625

626
    /**
627
     * Get variation by murmur logic if pre segmentation pass
628
     *
629
     * @param  bool   $isPreSegmentation pre-segmentation flag
630
     * @param  string $userId         the unique ID assigned to User
631
     * @param  object $userStorageObj userStorage object
632
     * @param  array  $campaign       campaign data
633
     * @param  string $goalIdentifier goal Identifier used in track API
634
     * @return array|null
635
     */
636
    private function getVariationIfPreSegmentationApplied($isPreSegmentation, $campaign, $userId, $userStorageObj = null, $goalIdentifier = '')
637
    {
638
        $bucketInfo = null;
92✔
639
        //check for pre-segmentation if applied
640
        if ($isPreSegmentation == false) {
92✔
641
            LoggerService::log(
12✔
642
                Logger::INFO,
12✔
643
                'DECISION_NO_VARIATION_ALLOTED',
12✔
644
                [
645
                    '{userId}' => $userId,
12✔
646
                    '{campaignKey}' => $campaign['key']
12✔
647
                ],
648
                self::CLASSNAME
12✔
649
            );
650

651
            return $bucketInfo;
12✔
652
        }
653

654
        $bucketInfo = Bucketer::getBucket($userId, $campaign);
80✔
655
        LoggerService::log(
80✔
656
            Logger::INFO,
80✔
657
            'USER_VARIATION_ALLOCATION_STATUS',
80✔
658
            [
659
                '{userId}' => $userId,
80✔
660
                '{status}' => $bucketInfo ? 'got variation:' . $bucketInfo['name'] : 'did not get any variation',
80✔
661
                '{campaignKey}' => $campaign['key']
80✔
662
            ],
663
            self::CLASSNAME
80✔
664
        );
665
        if ($bucketInfo == null) {
80✔
666
            return $bucketInfo;
48✔
667
        }
668

669
        $this->userStorageSet($userStorageObj, $userId, $campaign['key'], $bucketInfo, $goalIdentifier);
72✔
670
        return $bucketInfo;
72✔
671
    }
672
}
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