php-cooper-config

Convert
in package

FinalYes

Turns what `Cooper` loaded into application configuration -- the counterpart of the Elixir `CooperConfig.Convert` and the Praxis `cooper.config/as-app-config`.

Typed literals arrive untagged

Application configuration is read by code that has never heard of Cooper -- a database client, an HTTP client, a framework option -- so Cooper's measurements lose their wrapper on the way in:

CASC Cooper application configuration
1GiB CooperBytes 1073741824 (bytes; CooperInteger beyond 64 bits)
14d CooperDuration 1209600000 (milliseconds; CooperInteger beyond 64 bits)
10.0.0.1 CooperIPv4 "10.0.0.1"
10.0.0.0/8 CooperIPv4 with a prefix "10.0.0.0/8"
(1, "a") CooperTuple [1, "a"]

IPv6 follows IPv4. An address becomes its text where the references give the BEAM's address tuple: text is what PHP's own socket, stream, and filter functions take. A tuple becomes a list array where the references keep a tuple: PHP has no tuple type, a CooperTuple is Cooper's, and a list is the nearest value PHP code already knows how to read. Its elements are converted too.

Durations become milliseconds, the unit most PHP timeouts and TTLs take beside seconds (and the unit the references chose). One that is not a whole number of milliseconds (1500us) is refused rather than rounded: a silently shortened timeout is harder to find than a failed boot.

Maps (associative arrays) and lists are walked at every depth; dates, times, atoms, big integers, and everything else pass through as Cooper returns them -- each is a value, not a tag on one.

Secrets: cooper-secrets

A top-level block is one application (or one part of one), and it says how its own secrets arrive under the key cooper-secrets:

  • absent, or reveal -- revealed: configuration has always held raw values, and what reads it expects one;
  • keep -- left as Cooper's CooperSecret, untouched, for code that reveals at the point of use;
  • a string -- a module name, written as !module("...") takes one (dot-separated PascalCase, mapped through the modules option or translated by convention, App.Secret -> App\Secret): each secret is revealed, converted, and handed to that class's static new(), else its constructor -- for a codebase that owns a secret type.

The key is removed: it is this library's, not the application's. It governs every depth of its block and nothing else, and is refused at the document root (where it would name an application), nested deeper, with an unknown value, or naming a class that cannot wrap. It is a key in the document rather than an option because the document is the one place every way of loading it shares.

Table of Contents

Constants

POLICY_KEY  : mixed = 'cooper-secrets'
The key an application states its secret handling under. Named for the library, so an application can still have a setting called `secrets` of its own.
MODULE_VARIABLE  : mixed = 'COOPER_CONFIG_SECRET_MODULE'
Where `resolveModule()` passes the name to Cooper, so no CASC source is ever built from it.

Methods

toAppConfig()  : array<string|int, mixed>
Converts a `Cooper::loadFile()`/`loadString()` result into application configuration (see the class documentation).
__construct()  : mixed
converted()  : mixed
One value, as application configuration holds it.
describe()  : string
A policy value as the document wrote it, for the refusal.
milliseconds()  : int|CooperInteger
policyOf()  : "reveal"|"keep"|array{0: class-string, 1: bool}
How the application whose block is `$settings` wants its secrets: `'reveal'`, `'keep'`, or the class to wrap with and whether through `new()`.
resolveModule()  : string
`$name` exactly as `!module("...")` would give it back: through the `modules` option, else Cooper's convention. Cooper itself is asked -- with the name passed in through the environment, never spliced into source -- so the two can never disagree about what a module name is.
secret()  : mixed
One secret, as the policy asks for it. A revealed value is converted before it is wrapped: what the application's class receives is a value, not a Cooper measurement.
takesOneArgument()  : bool
walk()  : array<string|int, mixed>
wrapperFor()  : array{0: class-string, 1: bool}
The class `$name` names, and whether it wraps through `new()` (preferred, as the references call it) or its constructor.

Constants

POLICY_KEY

The key an application states its secret handling under. Named for the library, so an application can still have a setting called `secrets` of its own.

public mixed POLICY_KEY = 'cooper-secrets'

MODULE_VARIABLE

Where `resolveModule()` passes the name to Cooper, so no CASC source is ever built from it.

private mixed MODULE_VARIABLE = 'COOPER_CONFIG_SECRET_MODULE'

Methods

toAppConfig()

Converts a `Cooper::loadFile()`/`loadString()` result into application configuration (see the class documentation).

public static toAppConfig(array<string|int, mixed> $config[, array<string, mixed> $modules = [] ]) : array<string|int, mixed>
Parameters
$config : array<string|int, mixed>

what Cooper loaded

$modules : array<string, mixed> = []

the modules option the document was loaded with, for cooper-secrets = "Name"

Tags
throws
ConversionError

on a duration that is not whole milliseconds, or a refused cooper-secrets

Return values
array<string|int, mixed> —

the application configuration

__construct()

private __construct() : mixed

converted()

One value, as application configuration holds it.

private static converted(mixed $value, "reveal"|"keep"|array{0: class-string, 1: bool} $mode, array<int, string|int> $path) : mixed
Parameters
$value : mixed
$mode : "reveal"|"keep"|array{0: class-string, 1: bool}
$path : array<int, string|int>

where $value is, for error messages

Tags
throws
ConversionError

describe()

A policy value as the document wrote it, for the refusal.

private static describe(mixed $value) : string
Parameters
$value : mixed
Return values
string

milliseconds()

private static milliseconds(CooperDuration $duration, array<int, string|int> $path) : int|CooperInteger
Parameters
$duration : CooperDuration
$path : array<int, string|int>
Tags
throws
ConversionError
Return values
int|CooperInteger

policyOf()

How the application whose block is `$settings` wants its secrets: `'reveal'`, `'keep'`, or the class to wrap with and whether through `new()`.

private static policyOf(mixed $settings, array<string, mixed> $modules) : "reveal"|"keep"|array{0: class-string, 1: bool}
Parameters
$settings : mixed
$modules : array<string, mixed>
Tags
throws
ConversionError
Return values
"reveal"|"keep"|array{0: class-string, 1: bool}

resolveModule()

`$name` exactly as `!module("...")` would give it back: through the `modules` option, else Cooper's convention. Cooper itself is asked -- with the name passed in through the environment, never spliced into source -- so the two can never disagree about what a module name is.

private static resolveModule(string $name, array<string, mixed> $modules) : string
Parameters
$name : string
$modules : array<string, mixed>
Tags
throws
ConversionError
Return values
string

secret()

One secret, as the policy asks for it. A revealed value is converted before it is wrapped: what the application's class receives is a value, not a Cooper measurement.

private static secret(CooperSecret $secret, "reveal"|"keep"|array{0: class-string, 1: bool} $mode, array<int, string|int> $path) : mixed
Parameters
$secret : CooperSecret
$mode : "reveal"|"keep"|array{0: class-string, 1: bool}
$path : array<int, string|int>
Tags
throws
ConversionError

takesOneArgument()

private static takesOneArgument(ReflectionFunctionAbstract $function) : bool
Parameters
$function : ReflectionFunctionAbstract
Return values
bool

walk()

private static walk(array<string|int, mixed> $items, "reveal"|"keep"|array{0: class-string, 1: bool} $mode, array<int, string|int> $path) : array<string|int, mixed>
Parameters
$items : array<string|int, mixed>
$mode : "reveal"|"keep"|array{0: class-string, 1: bool}
$path : array<int, string|int>
Tags
throws
ConversionError
Return values
array<string|int, mixed>

wrapperFor()

The class `$name` names, and whether it wraps through `new()` (preferred, as the references call it) or its constructor.

private static wrapperFor(string $name, array<string, mixed> $modules) : array{0: class-string, 1: bool}

Checked when the policy is read, not when the first secret meets it, so a typo is found the first time the document loads.

Parameters
$name : string
$modules : array<string, mixed>
Tags
throws
ConversionError
Return values
array{0: class-string, 1: bool}
On this page

Search results