# php-orchard-features

Split.io-backed feature flag library for Orchard PHP applications.

## What this library provides

- A single service to evaluate one or many feature flags.
- Context objects for account/profile-based targeting.
- Normalized variants: `on` is returned as `enabled`, all other treatments as `disabled`.
- Split SDK initialization with Redis cache.
- Local development mode using a YAML split file.

## Requirements

- PHP `>=8.2 <9.0`
- Redis (for Split SDK cache)
- Split SDK key (or local mode for development)

Main dependencies are defined in `composer.json`:

- `splitsoftware/split-sdk-php`
- `predis/predis`
- `orchard/common`

## Installation

```bash
composer require theorchard/php-orchard-features
```

For local development in this repository:

```bash
make env
```

## Configuration

The library reads the environment in this order:

- `Environment`, then `ENVIRONMENT`, then `ENV` (default: `dev`)

### Required environment variables

- `SPLITIO_REDIS_HOST` (required outside local mode)

### Optional environment variables

- `SPLITIO_API_KEY`
  - If missing, library attempts to load `{environment}/split/API_KEY` from AWS Secrets Manager (`us-east-1`)
  - In `dev`/`test`, it falls back to `localhost` when secret resolution fails
- `SPLITIO_REDIS_PORT` (default: `6379`)
- `SPLITIO_REDIS_PREFIX` (default: empty)
- `SPLIT_FILE_PATH` (optional local split definition file)

### Local mode

Local mode is enabled when:

- `SPLITIO_API_KEY=localhost`
- and a valid split file exists (`SPLIT_FILE_PATH` or `examples/splits.yml`)

In local mode, Split evaluations are resolved from the YAML file.

## Quick start

```php
<?php

declare(strict_types=1);

use Orchard\FeatureFlags\Context\AccountContext;
use Orchard\FeatureFlags\FeatureService;

$featureService = new FeatureService();

$context = new AccountContext(
	orchardUserId: 'oa:3174',
	vendorId: '55555'
);

$isEnabled = $featureService->isVariant(
	'product_code_error_correction',
	'enabled',
	$context
);
```

## Context types

### Account context

Use `Orchard\FeatureFlags\Context\AccountContext` when evaluating by user/vendor/subaccount/identity.

Supported attributes produced by `toAttributes()`:

- `user_id`
- `vendor_id`
- `subaccount_id`
- `identity_id`
- `orchard_identity_uuid`
- `profile_type_and_id` (derived for `alw:*` and `oa:*` users)

Legacy helper:

```php
$context = AccountContext::fromLegacy(
	userId: '3174',
	userType: 'oa',
	vendorId: null,
	subaccountId: null
);
```

### Profile context

Use `Orchard\FeatureFlags\Context\ProfileContext` for profile-based targeting.

Supported attributes produced by `toAttributes()`:

- `profile_type_and_id` (e.g. `ArtistProfile:777`)
- `identity_id`
- `user_id` (derived for `OrchAdminProfile` as `oa:{profileId}`)
- `orchard_identity_uuid`

## Traffic key resolution order

The effective Split key is resolved with this precedence:

1. `orchard_identity_uuid`
2. `identity_id`
3. `profile_type_and_id`
4. `user_id`
5. `vendor_id` (prefixed as `vendor:{id}`)
6. `subaccount_id` (prefixed as `subaccount:{id}`)
7. fallback: `anonymous`

## API reference

`Orchard\FeatureFlags\FeatureService` exposes:

- `getSingleFeature(string $featureName, FeatureContextInterface $context): string`
- `isVariant(string $featureName, string $expectedVariant, FeatureContextInterface $context): bool`
- `getAllFeatures(FeatureContextInterface $context): array<string, string>`
- `getSingleFeatureByAttributes(string $featureName, array<string, string> $attributes): string`
- `getAllFeaturesByAttributes(array<string, string> $attributes): array<string, string>`

Returned variant values are normalized to:

- `enabled`
- `disabled`

## Examples

See runnable examples:

- `examples/modern_example.php`
- `examples/migration_example.php`
- `examples/local_test.php`
- `examples/splits.yml`

## Development commands

```bash
make env              # install dependencies
make lint             # phpcs + parallel lint
make phpstan          # static analysis
make unit_lint        # lint + phpstan script
make docker_unit_lint_82
make docker_unit_lint_84
```

Additional Composer scripts:

```bash
composer test
composer format
composer lint-and-test
```
