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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- docs: update command syntax in `development.md` and `testing.md` for clarity and consistency.
- fix: remove the unnecessary `src` argument from the Rector command in `composer.json`.
- feat: prepare Foxy `0.3` for PHP `8.3`, faster execution, safer fallbacks, updated tooling, and clearer docs.
- fix: preserve plugin self-updates and clarify framework-agnostic Composer application support.

## 0.2.0 January 24, 2026

Expand Down
39 changes: 8 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- markdownlint-disable MD041 -->
<p align="center">
<a href="https://github.com/php-forge/support" target="_blank">
<img src="https://avatars.githubusercontent.com/u/103309199?s=400&u=ca3561c692f53ed7eb290d3bb226a2828741606f&v=4" height="150px" alt="PHP Forge">
<a href="https://github.com/php-forge/foxy" target="_blank">
<img src="https://avatars.githubusercontent.com/u/103309199?s=400&u=ca3561c692f53ed7eb290d3bb226a2828741606f&v=4" width="30%" alt="PHP Forge">
</a>
<h1 align="center">Foxy</h1>
<br>
Expand All @@ -18,8 +18,8 @@
<a href="https://github.com/php-forge/foxy/actions/workflows/ecs.yml" target="_blank">
<img src="https://img.shields.io/github/actions/workflow/status/php-forge/foxy/ecs.yml?style=for-the-badge&label=ECS&logo=github" alt="Easy Coding Standard">
</a>
<a href="https://github.com/php-forge/foxy/actions/workflows/dependency-check.yml" target="_blank">
<img src="https://img.shields.io/github/actions/workflow/status/php-forge/foxy/dependency-check.yml?style=for-the-badge&label=Dependency%20Check&logo=github" alt="Dependency Check">
<a href="https://github.com/php-forge/foxy/actions/workflows/security.yml" target="_blank">
<img src="https://img.shields.io/github/actions/workflow/status/php-forge/foxy/security.yml?style=for-the-badge&label=Security&logo=github" alt="Security">
</a>
</p>

Expand Down Expand Up @@ -74,33 +74,11 @@ contains lockfiles from more than one manager.

## Quick start

### Yii2 application template 22
### Composer-based PHP application

The [Yii2 basic application template branch 22](https://github.com/yiisoft/yii2-app-basic/tree/22) requires PHP 8.3
and targets [Yii2 framework branch 22.0](https://github.com/yiisoft/yii2/tree/22.0). Create the tested development
version with:

```bash
composer create-project --prefer-dist yiisoft/yii2-app-basic basic 22.x-dev
```

The application keeps `package.json` at the project root and configures npm explicitly. Foxy merges frontend
dependencies from installed Composer packages and runs npm during Composer install and update operations.

For an existing Yii2 22 application, use the installation commands above and ensure its configuration contains:

```json
{
"config": {
"allow-plugins": {
"php-forge/foxy": true
},
"foxy": {
"manager": "npm"
}
}
}
```
Foxy is framework agnostic and works with any Composer-based PHP application that meets the requirements above. No
framework integration or application template is required. Composer packages that opt in contribute their frontend
dependencies, and Foxy merges them whenever Composer installs or updates the project.

### Project with package.json under web/

Expand Down Expand Up @@ -145,7 +123,6 @@ the Composer project directory.
[![PHPStan Level 5](https://img.shields.io/badge/PHPStan-Level%205-4F5D95.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/php-forge/foxy/actions/workflows/static.yml)
[![Quality](https://img.shields.io/github/actions/workflow/status/php-forge/foxy/quality.yml?style=for-the-badge&label=Quality&logo=github)](https://github.com/php-forge/foxy/actions/workflows/quality.yml)
[![Dependency Check](https://img.shields.io/github/actions/workflow/status/php-forge/foxy/dependency-check.yml?style=for-the-badge&label=Dependency%20Check&logo=github)](https://github.com/php-forge/foxy/actions/workflows/dependency-check.yml)
[![Security](https://img.shields.io/github/actions/workflow/status/php-forge/foxy/security.yml?style=for-the-badge&label=Security&logo=github)](https://github.com/php-forge/foxy/actions/workflows/security.yml)

## Community

Expand Down
9 changes: 6 additions & 3 deletions src/Foxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public function init(): void
$this->assetFallback->save();
$this->composerFallback->save();

if ($this->config->isEnabled('run-asset-manager')) {
if ($this->isEnabled('run-asset-manager')) {
$this->assetManager->validate();
}
}
Expand Down Expand Up @@ -208,8 +208,11 @@ private function getAssetManager(
/**
* Check whether plugin execution is enabled.
*/
private function isEnabled(): bool
private function isEnabled(string $key = 'enabled'): bool
{
return $this->config->isEnabled('enabled');
// Composer can load this entry point with the previous Config class during a plugin self-update.
$value = $this->config->get($key);

return true === $value || 1 === $value || '1' === $value;
}
}
26 changes: 26 additions & 0 deletions tests/FoxyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Composer\Repository\RepositoryManager;
use Composer\Script\{Event, ScriptEvents};
use Foxy\Asset\{AbstractAssetManager, AssetManagerInterface};
use Foxy\Config\Config as FoxyConfig;
use Foxy\Exception\RuntimeException;
use Foxy\Fallback\AssetFallback;
use Foxy\Foxy;
Expand Down Expand Up @@ -247,6 +248,31 @@ public function testActivateWithInvalidManager(): void
$foxy->activate($this->composer, $this->io);
}

public function testConfigurationFlagsRemainCompatibleDuringPluginSelfUpdate(): void
{
$config = $this
->getMockBuilder(FoxyConfig::class)
->disableOriginalConstructor()
->onlyMethods(['get', 'isEnabled'])
->getMock();

$config
->expects(self::exactly(2))
->method('get')
->willReturnCallback(
static fn(string $key): bool|int => 'enabled' === $key ? 1 : false,
);
$config->expects(self::never())->method('isEnabled');

$foxy = new Foxy();
$reflection = new ReflectionClass($foxy);
$reflection->getProperty('config')->setValue($foxy, $config);
$isEnabled = $reflection->getMethod('isEnabled');

self::assertTrue($isEnabled->invoke($foxy));
self::assertFalse($isEnabled->invoke($foxy, 'run-asset-manager'));
}

public function testDeactivate(): void
{
$foxy = new Foxy();
Expand Down
Loading