Skip to content

feat(upgrade): give each model a factory, written from its migrations - #60

Merged
imorland merged 2 commits into
3.xfrom
im/upgrade-model-factories
Oct 11, 2026
Merged

imorland merged 2 commits into
3.xfrom
im/upgrade-model-factories

Conversation

@imorland

@imorland imorland commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

Fixes: no issue.

Changes proposed in this pull request:
Flarum 2.0 tests fill the columns a test leaves out from a model's factory, when prepareDatabase() is given the model class rather than its table. Until now the upgrade only linked to the docs. A new step, "Model factories for tests" (run before the PHPUnit step), writes a factory next to each of the extension's models and gives the model HasFactory. A factory the extension already has is kept.

Each factory is written from what the extension's migrations say about the model's table, replayed in the order Flarum runs them. It follows core's factories: created_at is Carbon::now(), a required foreign key is Model::factory(), nullable columns are null, and strings get a faker value. A column it can't fill gets a @TODO.

The PHPUnit step now names the extension's own tables, and api_keys, by their models in prepareDatabase(). fl make backend model generates the factory alongside the model.

It also fixes a regression from #58: converted tests got #[DataProvider] above #[Test] when @dataProvider was written first. #[Test] comes first again, as in the original rewriter and Flarum's own tests. I found it by running the original and current rewriters over 364 real test files (the 1.x tests of 36 FoF extensions and core); the other differences are intended: stray empty * doc lines go, and api_keys becomes ApiKey::class.

Reviewers should focus on:

  • change() is read as Laravel 11+ does: it replaces the column, so a column not restated as nullable gets a value. Flags' 1.x reason_detail is the real case; 2.x restated ->nullable() there.
  • I checked it on real code. From Flags' and Tags' 1.x migrations, the built CLI wrote factories with the same columns as the hand-written 2.x FlagFactory and TagFactory, plus Tags' three 1.x-only columns. On Tags' 1.x tests, every model table became Model::class; only pivot tables without a model stayed as table names. The reader ran without error over 68 extensions' migrations (bundled 1.x and installed third-party).
  • A model with no $table takes the table Eloquent names after it (pluralSnakeCaseModel). Subclasses of core models, such as post types, share core's table and factory, so they are skipped.

Screenshot
N/A

Necessity

  • Has the problem that is being solved here been clearly explained?
  • If applicable, have various options for solving this problem been considered?
  • For core PRs, does this need to be in core, or could it be in an extension? (N/A)
  • Are we willing to maintain this for years / potentially forever?

Confirmed

  • Frontend changes: tested on a local Flarum installation. (The built CLI ran the new step and the PHPUnit step on 1.x Flags and Tags, and fl make backend model on a fixture extension.)
  • Frontend changes: tests are green (run yarn test in js/). (yarn test: 267 tests, plus Prettier, ESLint and tsc.)
  • Frontend changes: tests have been added, or are not appropriate here. (23 new tests. All but three were seen failing first; those three pin edge cases in adding the trait, written after that code.)
  • Backend changes: tests are green (run composer test). (N/A)
  • Backend changes: tests have been added, or are not appropriate here. (N/A)
  • Where applicable, changes are suitable for all supported database drivers (MySQL, MariaDB, PostgreSQL, SQLite). (N/A)
  • Core developer confirmed locally this works as intended.
  • The description above is written by me and describes what this pull request actually does.

Required changes:

None.

Flarum 2.0 tests fill the columns a test leaves out from a model's
factory, when prepareDatabase() is given the model class rather than its
table.

- A new upgrade step writes a factory next to each of the extension's
  models, from what its migrations say about the model's table, and gives
  the model HasFactory. A factory the extension already has is kept.
- The PHPUnit step names the extension's own tables, and api_keys, by
  their models in prepareDatabase().
- fl make backend model generates the factory with the model.
The PHPUnit 12 rewrite in #58 wrote attributes in the order the
annotations were written, so a test with @dataProvider above @test got
#[DataProvider] above #[Test]. The original rewriter put #[Test] first,
as Flarum's own tests have it. Found by running both versions over the
1.x tests of 36 FoF extensions and core.
@imorland
imorland marked this pull request as ready for review October 11, 2026 12:06
@imorland
imorland merged commit ef58441 into 3.x Oct 11, 2026
3 checks passed
@imorland
imorland deleted the im/upgrade-model-factories branch October 11, 2026 12:12
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.

1 participant