Skip to content

Discover providers from the project itself. - #84

Merged
GautierDele merged 2 commits into
xefi:mainfrom
sukei:feature/provider-discovery
Jul 31, 2026
Merged

Discover providers from the project itself.#84
GautierDele merged 2 commits into
xefi:mainfrom
sukei:feature/provider-discovery

Conversation

@sukei

@sukei sukei commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

The auto-discovery feature of installed packages is nice, however it fails to discover project-local providers and extensions. This PR address this issue by reading the project composer.json file too.

Summary by CodeRabbit

  • New Features

    • Manifest generation now includes project-level extra.faker configuration from the root Composer file.
    • Project configuration is supported under a default package entry when no package name is available.
    • Project-level settings take precedence over matching installed package configuration.
  • Bug Fixes

    • Manifests now rebuild when the root Composer file changes.
    • Improved freshness checks help keep generated manifests synchronized.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Manifest recompilation now checks the project root composer.json. PackageManifest also reads root-level extra.faker configuration. Tests add temporary project support and cover provider discovery, precedence, missing files, and timestamp-based recompilation.

Changes

Manifest Root composer.json Handling

Layer / File(s) Summary
PackageManifest root composer.json integration
src/Manifests/PackageManifest.php, tests/Unit/PackageManifestTest.php
build() merges root extra.faker settings into the package map. shouldRecompile() checks the root composer.json timestamp. Tests cover discovery, merging, fallback naming, precedence, missing configuration, missing files, and recompilation.
ContainerMixinManifest recompilation and Method tag fix
src/Manifests/ContainerMixinManifest.php, tests/Unit/ContainerMixinManifestTest.php
shouldRecompile() checks the root composer.json timestamp. Method tag construction places parameters before returnType. Tests cover project file timestamp changes.
Temporary project test support
tests/Support/Concerns/CreatesTemporaryProjects.php, tests/Support/composer.json
Adds helpers that create and remove temporary Composer projects. Adds a support Composer fixture with package name xefi/faker-php-tests-support.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: discovering providers from the project itself.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/Manifests/ContainerMixinManifest.php (1)

145-147: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Same filemtime guard issue as PackageManifest::shouldRecompile().

filemtime($this->basePath.'/composer.json') will emit a PHP warning if the file doesn't exist. Apply the same is_file() guard suggested for PackageManifest::shouldRecompile().

🛡️ Proposed fix
 public function shouldRecompile(): bool
 {
     return !is_file($this->containerMixinPath) ||
         // We check here if the manifest has been generated before changing the installed.json composer file or the project composer.json
-        filemtime($this->containerMixinPath) <= filemtime($this->vendorPath.'/composer/installed.json') ||
-        filemtime($this->containerMixinPath) <= filemtime($this->basePath.'/composer.json');
+        (is_file($this->vendorPath.'/composer/installed.json') && filemtime($this->containerMixinPath) <= filemtime($this->vendorPath.'/composer/installed.json')) ||
+        (is_file($this->basePath.'/composer.json') && filemtime($this->containerMixinPath) <= filemtime($this->basePath.'/composer.json'));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Manifests/ContainerMixinManifest.php` around lines 145 - 147, The
`ContainerMixinManifest` freshness check has the same unsafe `filemtime` usage
as `PackageManifest::shouldRecompile()`, and
`filemtime($this->basePath.'/composer.json')` can warn when the file is missing.
Update the logic around the manifest rebuild guard to use an `is_file()` check
before calling `filemtime()` for the project composer file, keeping the existing
comparison behavior in `ContainerMixinManifest` while avoiding warnings.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Manifests/PackageManifest.php`:
- Around line 144-147: The shouldRecompile() logic in PackageManifest currently
calls filemtime() on composer.json without verifying the file exists, which can
trigger warnings on missing layouts. Update shouldRecompile() to mirror the
build() guard by checking is_file() before any filemtime() call on the basePath
composer.json (and any other potentially absent paths), and only compare mtimes
when the files are present.

---

Duplicate comments:
In `@src/Manifests/ContainerMixinManifest.php`:
- Around line 145-147: The `ContainerMixinManifest` freshness check has the same
unsafe `filemtime` usage as `PackageManifest::shouldRecompile()`, and
`filemtime($this->basePath.'/composer.json')` can warn when the file is missing.
Update the logic around the manifest rebuild guard to use an `is_file()` check
before calling `filemtime()` for the project composer file, keeping the existing
comparison behavior in `ContainerMixinManifest` while avoiding warnings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0bb7e42d-a324-4d6a-bce2-f9e069c8f188

📥 Commits

Reviewing files that changed from the base of the PR and between 772724b and 5611b17.

📒 Files selected for processing (3)
  • src/Manifests/ContainerMixinManifest.php
  • src/Manifests/PackageManifest.php
  • tests/Support/composer.json

Comment thread src/Manifests/PackageManifest.php
Comment thread src/Manifests/ContainerMixinManifest.php
Comment thread tests/Support/composer.json
@martinsoenen

Copy link
Copy Markdown
Contributor

Interesting changes, thank you. I added some little feedbacks but the main thing is cool !

Cover the root composer.json branch added to PackageManifest::build():
providers declared by the project itself, merge with the installed
packages ones, the "root" fallback key when the project has no name,
and the ignored cases (no extra.faker, no composer.json at all).

Also cover the new project composer.json freshness check in both
PackageManifest::shouldRecompile() and
ContainerMixinManifest::shouldRecompile().
@GautierDele

Copy link
Copy Markdown
Member

Reviewed, and I pushed the missing tests onto the branch (8841a31) so we can close @martinsoenen's point.

Documentation

Companion doc PR: xefi/faker-doc#43 — a Project discovery section next to the existing Package discovery one, plus a pointer from the Custom Extension page, which until now documented faker()->resolveExtensions([...]) as the only way to load an application-local extension. Both should be merged together.

Tests added

PackageManifestTest — covers the new root composer.json branch of build():

  • providers declared by the project itself are discovered;
  • they are merged with the ones coming from the installed packages;
  • the root fallback key is used when the project composer.json has no name;
  • a project without an extra.faker section is ignored;
  • a project without a composer.json at all is ignored (the is_file() guard in build());
  • the project takes precedence over an installed package declaring the same name.

PackageManifestTest + ContainerMixinManifestTest — cover the new freshness check, i.e. that touching the project composer.json makes shouldRecompile() return true, mirroring the existing installed.json tests.

Each one is built on a throwaway project directory (tests/Support/Concerns/CreatesTemporaryProjects) rather than on the committed tests/Support fixture, so the mtime tests don't have to mutate tracked files the way the existing ones do.

I checked they actually pin the behaviour: reverting src/Manifests/* to the base commit fails 6 of them, and the two "ignored" cases stay green in both states as intended.

Two notes, neither blocking

  • The branch is 3 commits behind main and ArraysExtensionTest::testRandomElement fails on it — that one was fixed on main by :rotating_lights: Fix unit tests does are NOK anymore #90, so it's purely a stale base. On the merge result the suite is green on 8.3 / 8.4 / 8.5 (660 tests). Worth rebasing before merge anyway.
  • On the withdrawn CodeRabbit is_file() thread: @sukei's reasoning holds for the production path, but note it isn't strictly the same assumption — installed.json only exists after a composer install, whereas shouldRecompile() can now be reached with a basePath that has no composer.json, which is exactly why tests/Support/composer.json had to be added in this PR. It only costs a warning, so fine as is, but that fixture is load-bearing now and worth a comment if anyone is tempted to remove it.

Nice feature — this closes a real gap for apps that have extensions but no package to publish them in.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/Unit/PackageManifestTest.php`:
- Around line 195-219: The PackageManifest test must cover projects without a
root composer.json during recompilation checks. In
PackageManifest::shouldRecompile(), guard the composer.json filemtime lookup
with is_file() so missing files do not emit warnings, then update
testProjectWithoutComposerFileIsIgnored() to assert the expected
shouldRecompile() result after build().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c33d5371-87cb-4bad-8494-7fd6063e9d5a

📥 Commits

Reviewing files that changed from the base of the PR and between 5611b17 and 8841a31.

📒 Files selected for processing (3)
  • tests/Support/Concerns/CreatesTemporaryProjects.php
  • tests/Unit/ContainerMixinManifestTest.php
  • tests/Unit/PackageManifestTest.php

Comment on lines +195 to +219
public function testProjectWithoutComposerFileIsIgnored()
{
$projectPath = $this->createTemporaryProject(null, [
[
'name' => 'xefi/faker-number',
'extra' => [
'faker' => [
'providers' => [TestServiceProvider::class],
],
],
],
]);

$manifest = new PackageManifest($projectPath, $projectPath.'/packages.php');
$manifest->build();

$this->assertEquals(
[
'xefi/faker-number' => [
'providers' => [TestServiceProvider::class],
],
],
require $projectPath.'/packages.php'
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle a missing root composer.json in shouldRecompile().

This test declares that a project without composer.json is supported, but it only calls build(). PackageManifest::shouldRecompile() unconditionally calls filemtime($this->basePath.'/composer.json'), which emits a warning when this file is absent.

Guard that timestamp check with is_file(). Add a shouldRecompile() assertion here after build().

🧰 Tools
🪛 OpenGrep (1.26.0)

[ERROR] 217-217: Dynamic file path passed to include/require. This can lead to local or remote file inclusion. Use a fixed allowlist of paths.

(coderabbit.file-inclusion.php-dynamic-include)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Unit/PackageManifestTest.php` around lines 195 - 219, The
PackageManifest test must cover projects without a root composer.json during
recompilation checks. In PackageManifest::shouldRecompile(), guard the
composer.json filemtime lookup with is_file() so missing files do not emit
warnings, then update testProjectWithoutComposerFileIsIgnored() to assert the
expected shouldRecompile() result after build().

@GautierDele GautierDele left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @sukei, merging

@GautierDele
GautierDele merged commit 69bc47c into xefi:main Jul 31, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants