Skip to content

Commit

Permalink
Add support for Remote Config Parameter Value Types
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromegamez committed Jun 16, 2023
1 parent 6855b07 commit 29fbc6e
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 45 deletions.
15 changes: 8 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

## [Unreleased]

### Changed
### Added
*
* Added support for [Parameter Value Types](https://firebase.google.com/docs/reference/remote-config/rest/v1/RemoteConfig#parametervaluetype)
when getting and setting a RemoteConfig template.
([Documentation](https://firebase-php.readthedocs.io/en/latest/remote-config.html#parameter-value-types))

#### RemoteConfig
### Deprecated

* Introduced `Kreait\Firebase\RemoteConfig\ParameterValue` to be used instead of the explicit classes
`Kreait\Firebase\RemoteConfig\ExplicitValue` and `Kreait\Firebase\RemoteConfig\DefaultValue`
* `Kreait\Firebase\RemoteConfig\DefaultValue` should be regarded as deprecated, it is kept to not
create a breaking change
* `Kreait\Firebase\RemoteConfig\ExplicitValue` is deprecated
* `Kreait\Firebase\RemoteConfig\ExplicitValue` is deprecated
* `Kreait\Firebase\RemoteConfig\DefaultValue` should be regarded as deprecated, it is kept to not create a breaking changes

## [7.3.1] - 2023-06-10

Expand Down
29 changes: 29 additions & 0 deletions docs/remote-config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,41 @@ Add a parameter
.. code-block:: php
use Kreait\Firebase\RemoteConfig;
use Kreait\Firebase\RemoteConfig\ParameterValueType;
$welcomeMessageParameter = RemoteConfig\Parameter::named('welcome_message')
->withDefaultValue('Welcome!')
->withDescription('This is a welcome message') // optional
->withValueType(ParameterValueType $valueType): self
;
Parameter Value Types
---------------------

.. note::
Support for Parameter Value Types has been added in version 7.4.0 of the SDK

.. code-block:: php
use Kreait\Firebase\RemoteConfig\Parameter;
use Kreait\Firebase\RemoteConfig\ParameterValueType;
Parameter::named('string_parameter')
->withDefaultValue('Welcome!')
->withValueType(ParameterValueType::STRING);
Parameter::named('boolean_parameter')
->withDefaultValue('true')
->withValueType(ParameterValueType::BOOL);
Parameter::named('numeric_parameter')
->withDefaultValue('5')
->withValueType(ParameterValueType::NUMBER);
Parameter::named('json_parameter')
->withDefaultValue('{"foo": "bar"}')
->withValueType(ParameterValueType::JSON);
******************
Conditional values
******************
Expand Down
1 change: 1 addition & 0 deletions src/Firebase/RemoteConfig/DefaultValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* @phpstan-import-type RemoteConfigParameterValueShape from ParameterValue
*
* @todo Deprecate/Remove in 8.0
* @see ParameterValue
*/
class DefaultValue implements JsonSerializable
{
Expand Down
108 changes: 80 additions & 28 deletions src/Firebase/RemoteConfig/Parameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,52 +13,66 @@
* @phpstan-import-type RemoteConfigParameterValueShape from ParameterValue
*
* @phpstan-type RemoteConfigParameterShape array{
* defaultValue?: RemoteConfigParameterValueShape,
* conditionalValues?: array<non-empty-string, RemoteConfigParameterValueShape>,
* description?: string
* description?: string|null,
* defaultValue?: RemoteConfigParameterValueShape|null,
* conditionalValues?: array<non-empty-string, RemoteConfigParameterValueShape>|null,
* valueType?: non-empty-string|null
* }
*/
class Parameter implements JsonSerializable
{
private ?string $description = '';

/**
* @var list<ConditionalValue>
*/
private array $conditionalValues = [];

/**
* @param non-empty-string $name
* @param list<ConditionalValue> $conditionalValues
*/
private function __construct(
private readonly string $name,
private ?ParameterValue $defaultValue = null,
private readonly string $description,
private readonly ?ParameterValue $defaultValue,
private readonly array $conditionalValues,
private readonly ParameterValueType $valueType,
) {
}

/**
* @param non-empty-string $name
* @param DefaultValue|RemoteConfigParameterValueShape|string|bool|null $defaultValue
*/
public static function named(string $name, $defaultValue = null): self
public static function named(string $name, $defaultValue = null, ?ParameterValueType $valueType = null): self
{
$defaultValue = self::mapDefaultValue($defaultValue);

return new self(
name: $name,
description: '',
defaultValue: $defaultValue,
conditionalValues: [],
valueType: $valueType ?? ParameterValueType::UNSPECIFIED,
);
}

/**
* @param DefaultValue|RemoteConfigParameterValueShape|string|bool|null $defaultValue
*/
private static function mapDefaultValue($defaultValue): ?ParameterValue
{
if ($defaultValue === null) {
return new self($name, null);
return null;
}

if ($defaultValue instanceof DefaultValue) {
return new self($name, ParameterValue::fromArray($defaultValue->toArray()));
return ParameterValue::fromArray($defaultValue->toArray());
}

if (is_string($defaultValue)) {
return new self($name, ParameterValue::withValue($defaultValue));
return ParameterValue::withValue($defaultValue);
}

if (is_bool($defaultValue)) {
return new self($name, ParameterValue::inAppDefault());
return ParameterValue::inAppDefault();
}

return new self($name, ParameterValue::fromArray($defaultValue));
return ParameterValue::fromArray($defaultValue);
}

/**
Expand All @@ -71,25 +85,39 @@ public function name(): string

public function description(): string
{
return $this->description ?: '';
return $this->description;
}

public function withDescription(string $description): self
{
$parameter = clone $this;
$parameter->description = $description;

return $parameter;
return new self(
name: $this->name,
description: $description,
defaultValue: $this->defaultValue,
conditionalValues: $this->conditionalValues,
valueType: $this->valueType,
);
}

/**
* @param DefaultValue|RemoteConfigParameterValueShape|string|bool|null $defaultValue
*/
public function withDefaultValue($defaultValue): self
{
return self::named($this->name, $defaultValue);
$defaultValue = self::mapDefaultValue($defaultValue);

return new self(
name: $this->name,
description: $this->description,
defaultValue: $defaultValue,
conditionalValues: $this->conditionalValues,
valueType: $this->valueType,
);
}

/**
* @todo 8.0 Replace with `ParameterValue`
*/
public function defaultValue(): ?DefaultValue
{
if ($this->defaultValue === null) {
Expand All @@ -101,10 +129,16 @@ public function defaultValue(): ?DefaultValue

public function withConditionalValue(ConditionalValue $conditionalValue): self
{
$parameter = clone $this;
$parameter->conditionalValues[] = $conditionalValue;

return $parameter;
$conditionalValues = $this->conditionalValues;
$conditionalValues[] = $conditionalValue;

return new self(
name: $this->name,
description: $this->description,
defaultValue: $this->defaultValue,
conditionalValues: $conditionalValues,
valueType: $this->valueType,
);
}

/**
Expand All @@ -115,6 +149,22 @@ public function conditionalValues(): array
return $this->conditionalValues;
}

public function withValueType(ParameterValueType $valueType): self
{
return new self(
name: $this->name,
description: $this->description,
defaultValue: $this->defaultValue,
conditionalValues: $this->conditionalValues,
valueType: $valueType,
);
}

public function valueType(): ParameterValueType
{
return $this->valueType;
}

/**
* @return RemoteConfigParameterShape
*/
Expand All @@ -136,10 +186,12 @@ public function toArray(): array
$array['conditionalValues'] = $conditionalValues;
}

if ($this->description !== null && $this->description !== '') {
if ($this->description !== '') {
$array['description'] = $this->description;
}

$array['valueType'] = $this->valueType->value;

return $array;
}

Expand Down
21 changes: 21 additions & 0 deletions src/Firebase/RemoteConfig/ParameterValueType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Kreait\Firebase\RemoteConfig;

/**
* @see https://firebase.google.com/docs/reference/remote-config/rest/v1/RemoteConfig#ParameterValueType
*/
enum ParameterValueType: string
{
case UNSPECIFIED = 'PARAMETER_VALUE_TYPE_UNSPECIFIED';

case STRING = 'STRING';

case BOOL = 'BOOLEAN';

case NUMBER = 'NUMBER';

case JSON = 'JSON';
}
3 changes: 3 additions & 0 deletions src/Firebase/RemoteConfig/Template.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,12 @@ private static function buildCondition(string $name, array $data): Condition
*/
private static function buildParameter(string $name, array $data): Parameter
{
$valueType = ParameterValueType::tryFrom($data['valueType'] ?? '') ?? ParameterValueType::UNSPECIFIED;

$parameter = Parameter::named($name)
->withDescription((string) ($data['description'] ?? ''))
->withDefaultValue($data['defaultValue'] ?? null)
->withValueType($valueType)
;

foreach ((array) ($data['conditionalValues'] ?? []) as $key => $conditionalValueData) {
Expand Down
46 changes: 38 additions & 8 deletions tests/Integration/RemoteConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Kreait\Firebase\Exception\RemoteConfig\VersionNotFound;
use Kreait\Firebase\RemoteConfig\FindVersions;
use Kreait\Firebase\RemoteConfig\Parameter;
use Kreait\Firebase\RemoteConfig\ParameterValueType;
use Kreait\Firebase\RemoteConfig\Template;
use Kreait\Firebase\RemoteConfig\UpdateOrigin;
use Kreait\Firebase\RemoteConfig\UpdateType;
Expand Down Expand Up @@ -56,6 +57,29 @@ final class RemoteConfigTest extends IntegrationTestCase
}
},
"description": "This is a welcome message"
},
"no_value_type": {
"defaultValue": "1"
},
"unspecified_value_type": {
"defaultValue": "1",
"valueType": "STRING"
},
"string_value_type": {
"defaultValue": "1",
"valueType": "STRING"
},
"numeric_value_type": {
"defaultValue": "1",
"valueType": "NUMBER"
},
"boolean_value_type": {
"defaultValue": "true",
"valueType": "BOOLEAN"
},
"json_value_type": {
"defaultValue": "{\"key\": \"value\"}",
"valueType": "JSON"
}
},
"parameterGroups": {
Expand Down Expand Up @@ -111,16 +135,22 @@ public function forcePublishAndGet(): void

$check = $this->remoteConfig->get();

$this->assertEqualsCanonicalizing($this->template->jsonSerialize(), $check->jsonSerialize());
$parameters = $check->parameters();
$this->assertSameSize($this->template->parameters(), $parameters);
$this->assertSame(ParameterValueType::STRING, $parameters['no_value_type']->valueType());
$this->assertSame(ParameterValueType::STRING, $parameters['unspecified_value_type']->valueType());
$this->assertSame(ParameterValueType::STRING, $parameters['string_value_type']->valueType());
$this->assertSame(ParameterValueType::NUMBER, $parameters['numeric_value_type']->valueType());
$this->assertSame(ParameterValueType::BOOL, $parameters['boolean_value_type']->valueType());
$this->assertSame(ParameterValueType::JSON, $parameters['json_value_type']->valueType());

$version = $check->version();
$this->assertSameSize($this->template->conditions(), $check->conditions());
$this->assertSameSize($this->template->conditionNames(), $check->conditionNames());

if (!$version instanceof Version) {
$this->fail('The template has no version');
}
$version = $check->version();

$this->assertTrue($version->updateType()->equalsTo(UpdateType::FORCED_UPDATE));
$this->assertTrue($version->updateOrigin()->equalsTo(UpdateOrigin::REST_API));
$this->assertSame(UpdateType::FORCED_UPDATE, (string) $version?->updateType());
$this->assertSame(UpdateOrigin::REST_API, (string) $version?->updateOrigin());
}

#[Test]
Expand Down Expand Up @@ -264,7 +294,7 @@ public function findVersionsWithFilters(): void
$query = [
'startingAt' => $currentVersionUpdateDate->modify('-2 months'),
'endingAt' => $currentVersionUpdateDate,
'upToVersion' => $currentVersion->versionNumber(),
'lastVersionBeing' => $currentVersion->versionNumber(),
'pageSize' => 1,
'limit' => $limit = 2,
];
Expand Down
6 changes: 4 additions & 2 deletions tests/Unit/RemoteConfig/TemplateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ public function defaultVersionIsNull(): void
#[Test]
public function createWithInvalidConditionalValue(): void
{
$parameter = Parameter::named('foo')->withConditionalValue(new ConditionalValue('non_existing_condition', 'false'));
$parameter = Parameter::named('foo')
->withConditionalValue(ConditionalValue::basedOn('non_existing_condition'))
;

$this->expectException(InvalidArgumentException::class);
Template::new()->withParameter($parameter);
Expand Down Expand Up @@ -77,7 +79,7 @@ public function withFluidConfiguration(): void
;

$germanWelcomeMessage = ConditionalValue::basedOn($german)->withValue('Willkommen!');
$frenchWelcomeMessage = new ConditionalValue('lang_french', 'Bienvenu!');
$frenchWelcomeMessage = ConditionalValue::basedOn($french)->withValue('Bienvenu!');

$welcomeMessageParameter = Parameter::named('welcome_message')
->withDefaultValue('Welcome!')
Expand Down

0 comments on commit 29fbc6e

Please sign in to comment.