Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ concurrency:
permissions: {}

jobs:
lint:
php:
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -26,12 +26,17 @@ jobs:
- uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
tools: pint:1
coverage: none
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- run: composer lint
- run: composer install --no-interaction --prefer-dist

- name: Check formatting
run: composer run-script format

- name: Lint
run: composer run-script lint

test:
runs-on: ubuntu-latest
Expand Down
23 changes: 12 additions & 11 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"license": "MIT",
"authors": [
{
"name": "roots.dev",
"email": "team@roots.dev"
"name": "roots.io",
"email": "team@roots.io"
}
],
"autoload": {
Expand All @@ -16,16 +16,13 @@
},
"require": {
"php": ">=8.3",
"vlucas/phpdotenv": "^5.6"
},
"require-dev": {
"laravel/pint": "^1.29",
"pestphp/pest": "^3.8"
"vlucas/phpdotenv": "^5.0"
},
"scripts": {
"test": "pest",
"lint": "pint --test",
"lint:fix": "pint"
"format": "mago format --check",
"format:fix": "mago format",
"lint": "mago lint",
"test": "pest"
},
"config": {
"sort-packages": true,
Expand All @@ -34,5 +31,9 @@
}
},
"minimum-stability": "dev",
"prefer-stable": true
"prefer-stable": true,
"require-dev": {
"carthage-software/mago": "^1.0",
"pestphp/pest": "^4.0"
}
}
24 changes: 24 additions & 0 deletions mago.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
php-version = "8.3"

[source]
paths = ["src/", "tests/"]

[formatter]
print-width = 120
null-type-hint = "question"
space-before-arrow-function-parameter-list-parenthesis = true
space-after-logical-not-unary-prefix-operator = true
sort-uses = true

[linter.rules]
cyclomatic-complexity = { threshold = 25 }
function-name = { enabled = false } # test helpers use camelCase
kan-defect = { enabled = false }
literal-named-argument = { enabled = false } # too noisy with define(), etc.
no-isset = { enabled = false } # isset() is the correct way to check array key existence
no-redundant-file = { enabled = false }
no-shorthand-ternary = { enabled = false }
prefer-arrow-function = { enabled = false }
prefer-static-closure = { enabled = false }
strict-types = { enabled = false }
too-many-methods = { threshold = 20 }
3 changes: 0 additions & 3 deletions pint.json

This file was deleted.

22 changes: 9 additions & 13 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ public static function make(string $rootDir): static
*/
public function bootstrapEnv(): self
{
$envFiles = file_exists($this->rootDir . '/.env.local')
? ['.env', '.env.local']
: ['.env'];
$envFiles = file_exists($this->rootDir . '/.env.local') ? ['.env', '.env.local'] : ['.env'];

$repository = RepositoryBuilder::createWithNoAdapters()
->addAdapter(EnvConstAdapter::class)
Expand Down Expand Up @@ -89,7 +87,7 @@ public function set(string|array $key, mixed $value = null): self

if ($this->isConstantDefined($key)) {
throw new ConstantAlreadyDefinedException(
"Aborted trying to redefine constant '$key'. `define('$key', ...)` has already occurred elsewhere.",
"Aborted trying to redefine constant '{$key}'. `define('{$key}', ...)` has already occurred elsewhere.",
);
}

Expand Down Expand Up @@ -135,9 +133,7 @@ public function get(string $key, mixed $default = null): mixed
return $default;
}

throw new UndefinedConfigKeyException(
"'$key' has not been defined. Use `set('$key', ...)` first.",
);
throw new UndefinedConfigKeyException("'{$key}' has not been defined. Use `set('{$key}', ...)` first.");
}

return $this->configMap[$key];
Expand Down Expand Up @@ -184,7 +180,7 @@ public function doAction(string $tag, mixed ...$args): self
}

$hooks = $this->hooks[$tag];
usort($hooks, fn($a, $b) => $a['priority'] <=> $b['priority']);
usort($hooks, fn ($a, $b) => $a['priority'] <=> $b['priority']);

foreach ($hooks as $hook) {
$hook['callback']($this, ...$args);
Expand Down Expand Up @@ -213,16 +209,16 @@ public function apply(): void

foreach ($this->configMap as $key => $value) {
if ($this->isConstantDefined($key) && constant($key) !== $value) {
throw new ConstantAlreadyDefinedException(
"Cannot redefine constant '$key' with different value.",
);
throw new ConstantAlreadyDefinedException("Cannot redefine constant '{$key}' with different value.");
}
}

foreach ($this->configMap as $key => $value) {
if (! defined($key)) {
define($key, $value);
if (defined($key)) {
continue;
}

define($key, $value);
}
}

Expand Down
66 changes: 30 additions & 36 deletions tests/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,15 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
});

it('uses late static binding', function () {
$child = new class ($this->rootDir) extends Config {};
$child = new class($this->rootDir) extends Config {};

expect($child::make($this->rootDir))->toBeInstanceOf($child::class);
});
});

describe('set', function () {
it('supports fluent interface', function () {
$result = $this->config
->set('TEST_1', 'value1')
->set('TEST_2', 'value2');
$result = $this->config->set('TEST_1', 'value1')->set('TEST_2', 'value2');

expect($result)->toBeInstanceOf(Config::class);
expect($this->config->get('TEST_1'))->toBe('value1');
Expand Down Expand Up @@ -98,9 +96,9 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):

it('accepts an array of env variable names', function () {
withDotEnv($this->config, <<<ENV
TEST_ENV_VAR_1=value1
TEST_ENV_VAR_2=value2
ENV);
TEST_ENV_VAR_1=value1
TEST_ENV_VAR_2=value2
ENV);
$this->config->env(['TEST_ENV_VAR_1', 'TEST_ENV_VAR_2', 'BOGUS_ENV_VAR']);

expect($this->config->get('TEST_ENV_VAR_1'))->toBe('value1');
Expand Down Expand Up @@ -186,8 +184,8 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
$this->config->set('CHECK_KEY', 'yes');

$this->config->when(
fn($config) => $config->get('CHECK_KEY') === 'yes',
fn($config) => $config->set('DERIVED', true),
fn ($config) => $config->get('CHECK_KEY') === 'yes',
fn ($config) => $config->set('DERIVED', true),
);

expect($this->config->get('DERIVED'))->toBeTrue();
Expand Down Expand Up @@ -216,12 +214,10 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
});

it('defines constants from array config', function () {
$this->config
->set([
'CONFIG_ARR_1' => 'applied1',
'CONFIG_ARR_2' => 'applied2',
])
->apply();
$this->config->set([
'CONFIG_ARR_1' => 'applied1',
'CONFIG_ARR_2' => 'applied2',
])->apply();

expect(defined('CONFIG_ARR_1'))->toBeTrue();
expect(defined('CONFIG_ARR_2'))->toBeTrue();
Expand All @@ -232,9 +228,7 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
it('throws when constant already exists with different value', function () {
define('CONFLICT_TEST', 'original');

$this->config
->set('CONFLICT_TEST', 'new')
->apply();
$this->config->set('CONFLICT_TEST', 'new')->apply();
})->throws(ConstantAlreadyDefinedException::class);

it('detects conflicts at apply time for constants defined after set', function () {
Expand All @@ -255,9 +249,7 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
$hookExecuted = true;
});

$this->config
->set('HOOK_TEST', 'value')
->apply();
$this->config->set('HOOK_TEST', 'value')->apply();

expect($hookExecuted)->toBeTrue();
expect(defined('HOOK_TEST'))->toBeTrue();
Expand All @@ -266,17 +258,23 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
it('executes hooks in priority order', function () {
$executionOrder = [];

$this->config->addAction('before_apply', function ($config) use (&$executionOrder) {
$executionOrder[] = 'second';
}, 20);
$this->config->addAction(
'before_apply',
function ($config) use (&$executionOrder) {
$executionOrder[] = 'second';
},
20,
);

$this->config->addAction('before_apply', function ($config) use (&$executionOrder) {
$executionOrder[] = 'first';
}, 10);
$this->config->addAction(
'before_apply',
function ($config) use (&$executionOrder) {
$executionOrder[] = 'first';
},
10,
);

$this->config
->set('PRIORITY_TEST', 'value')
->apply();
$this->config->set('PRIORITY_TEST', 'value')->apply();

expect($executionOrder)->toBe(['first', 'second']);
expect(defined('PRIORITY_TEST'))->toBeTrue();
Expand All @@ -289,9 +287,7 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
$receivedConfig = $config;
});

$this->config
->set('INSTANCE_TEST', 'value')
->apply();
$this->config->set('INSTANCE_TEST', 'value')->apply();

expect($receivedConfig)->toBe($this->config);
});
Expand All @@ -301,9 +297,7 @@ function withDotEnv(Config $config, string $env = "TEST_ENV_VAR=test_value\n"):
$config->set('HOOK_ADDED', 'added_by_hook');
});

$this->config
->set('ORIGINAL_CONFIG', 'original')
->apply();
$this->config->set('ORIGINAL_CONFIG', 'original')->apply();

expect(defined('ORIGINAL_CONFIG'))->toBeTrue();
expect(defined('HOOK_ADDED'))->toBeTrue();
Expand Down