1515use LaunchDarkly \Impl \UnrecoverableHTTPStatusException ;
1616use LaunchDarkly \Impl \Util ;
1717use LaunchDarkly \Integrations \Guzzle ;
18+ use LaunchDarkly \Migrations \OpTracker ;
19+ use LaunchDarkly \Migrations \Stage ;
1820use LaunchDarkly \Subsystems \FeatureRequester ;
1921use LaunchDarkly \Types \ApplicationInfo ;
2022use Monolog \Handler \ErrorLogHandler ;
@@ -199,7 +201,7 @@ private function getFeatureRequester(string $sdkKey, array $options): FeatureReq
199201 */
200202 public function variation (string $ key , LDContext |LDUser $ context , mixed $ defaultValue = false ): mixed
201203 {
202- $ detail = $ this ->variationDetailInternal ($ key , $ context , $ defaultValue , $ this ->_eventFactoryDefault );
204+ $ detail = $ this ->variationDetailInternal ($ key , $ context , $ defaultValue , $ this ->_eventFactoryDefault )[ ' detail ' ] ;
203205 return $ detail ->getValue ();
204206 }
205207
@@ -219,7 +221,58 @@ public function variation(string $key, LDContext|LDUser $context, mixed $default
219221 */
220222 public function variationDetail (string $ key , LDContext |LDUser $ context , mixed $ defaultValue = false ): EvaluationDetail
221223 {
222- return $ this ->variationDetailInternal ($ key , $ context , $ defaultValue , $ this ->_eventFactoryWithReasons );
224+ return $ this ->variationDetailInternal ($ key , $ context , $ defaultValue , $ this ->_eventFactoryWithReasons )['detail ' ];
225+ }
226+
227+ /**
228+ * This method returns the migration stage of the migration feature flag
229+ * for the given evaluation context.
230+ *
231+ * This method returns the default stage if there is an error or the flag
232+ * does not exist. If the default stage is not a valid stage, then a
233+ * default stage of {@see Stage::OFF} will be used
234+ * instead.
235+ *
236+ * @psalm-return array{'stage': Stage, 'tracker': OpTracker}
237+ */
238+ public function migrationVariation (string $ key , LDContext |LDUser $ context , Stage $ defaultStage ): array
239+ {
240+ $ result = $ this ->variationDetailInternal ($ key , $ context , $ defaultStage ->value , $ this ->_eventFactoryDefault );
241+ /** @var EvaluationDetail $detail */
242+ $ detail = $ result ['detail ' ];
243+ /** @var ?FeatureFlag $flag */
244+ $ flag = $ result ['flag ' ];
245+
246+ $ valueAsString = Stage::tryFrom ($ detail ->getValue ());
247+
248+ if ($ valueAsString !== null ) {
249+ $ tracker = new OpTracker (
250+ $ this ->_logger ,
251+ $ key ,
252+ $ flag ,
253+ $ context ,
254+ $ detail ,
255+ $ defaultStage
256+ );
257+
258+ return ['stage ' => $ valueAsString , 'tracker ' => $ tracker ];
259+ }
260+
261+ $ detail = new EvaluationDetail (
262+ $ defaultStage ->value ,
263+ null ,
264+ EvaluationReason::error (EvaluationReason::WRONG_TYPE_ERROR )
265+ );
266+ $ tracker = new OpTracker (
267+ $ this ->_logger ,
268+ $ key ,
269+ $ flag ,
270+ $ context ,
271+ $ detail ,
272+ $ defaultStage
273+ );
274+
275+ return ['stage ' => $ defaultStage , 'tracker ' => $ tracker ];
223276 }
224277
225278 /**
@@ -228,9 +281,9 @@ public function variationDetail(string $key, LDContext|LDUser $context, mixed $d
228281 * @param mixed $default
229282 * @param EventFactory $eventFactory
230283 *
231- * @return EvaluationDetail
284+ * @psalm- return array{'detail': EvaluationDetail, 'flag': ?FeatureFlag}
232285 */
233- private function variationDetailInternal (string $ key , LDContext |LDUser $ contextOrUser , mixed $ default , EventFactory $ eventFactory ): EvaluationDetail
286+ private function variationDetailInternal (string $ key , LDContext |LDUser $ contextOrUser , mixed $ default , EventFactory $ eventFactory ): array
234287 {
235288 $ context = $ contextOrUser instanceof LDUser ? LDContext::fromUser ($ contextOrUser ) : $ contextOrUser ;
236289 $ default = $ this ->_get_default ($ key , $ default );
@@ -258,25 +311,26 @@ private function variationDetailInternal(string $key, LDContext|LDUser $contextO
258311 ]
259312 );
260313
261- return $ result ;
314+ return [ ' detail ' => $ result, ' flag ' => null ] ;
262315 }
263316
264317 if ($ this ->_offline ) {
265- return $ errorDetail (EvaluationReason::CLIENT_NOT_READY_ERROR );
318+ return [ ' detail ' => $ errorDetail (EvaluationReason::CLIENT_NOT_READY_ERROR ), ' flag ' => null ] ;
266319 }
267320
321+ $ flag = null ;
268322 try {
269323 try {
270324 $ flag = $ this ->_featureRequester ->getFeature ($ key );
271325 } catch (UnrecoverableHTTPStatusException $ e ) {
272326 $ this ->handleUnrecoverableError ();
273- return $ errorDetail (EvaluationReason::EXCEPTION_ERROR );
327+ return [ ' detail ' => $ errorDetail (EvaluationReason::EXCEPTION_ERROR ), ' flag ' => null ] ;
274328 }
275329
276330 if (is_null ($ flag )) {
277331 $ result = $ errorDetail (EvaluationReason::FLAG_NOT_FOUND_ERROR );
278332 $ sendEvent (new EvalResult ($ result , false ), null );
279- return $ result ;
333+ return [ ' detail ' => $ result, ' flag ' => null ] ;
280334 }
281335 $ evalResult = $ this ->_evaluator ->evaluate (
282336 $ flag ,
@@ -298,12 +352,12 @@ function (PrerequisiteEvaluationRecord $pe) use ($context, $eventFactory) {
298352 $ evalResult = new EvalResult ($ detail , $ evalResult ->isForceReasonTracking ());
299353 }
300354 $ sendEvent ($ evalResult , $ flag );
301- return $ detail ;
355+ return [ ' detail ' => $ detail, ' flag ' => $ flag ] ;
302356 } catch (\Exception $ e ) {
303357 Util::logExceptionAtErrorLevel ($ this ->_logger , $ e , "Unexpected error evaluating flag $ key " );
304358 $ result = $ errorDetail (EvaluationReason::EXCEPTION_ERROR );
305359 $ sendEvent (new EvalResult ($ result , false ), null );
306- return $ result ;
360+ return [ ' detail ' => $ result, ' flag ' => $ flag ] ;
307361 }
308362 }
309363
0 commit comments