Skip to content

Contributing

Muhammet Şafak edited this page May 24, 2026 · 1 revision

Contributing

Thank you for considering a contribution. This page tells you how the package is built, what tooling runs in CI, and what a good PR looks like.

Ground rules

  • All contributions are released under the MIT license the package itself uses.
  • Be kind in code review and issue threads. We assume good faith.
  • Open an issue before big changes (refactors, new APIs, dependency bumps). For typo fixes / docs / small bugs, just send a PR.

Quick start

git clone https://github.com/InitORM/Database.git
cd Database
composer install
composer qa

composer qa runs the whole quality suite — code style, static analysis, and tests. The PR will run the same suite in CI.

Individual commands:

Command What it does
composer test PHPUnit
composer test:coverage PHPUnit + HTML coverage in build/coverage
composer cs PHP_CodeSniffer (PSR-12 + 120-char line cap)
composer cs-fix Auto-fix what PHPCBF can
composer stan PHPStan at level 6
composer qa cs-ci + stan + test

Quality bar

Every PR must pass:

  • PHPUnit: existing tests stay green; new behaviour ships with new tests.
  • PHPStan level 6: no new errors.
  • PHP_CodeSniffer (PSR-12): no new violations.
  • composer validate --strict: composer.json stays clean.

CI runs PHPUnit across PHP 8.1, 8.2, 8.3, and 8.4 — your code has to work on the full matrix.

Repository layout

src/
  Database.php                     ← main class, CRUD + transactions
  Facade/DB.php                    ← static facade
  Interfaces/DatabaseInterface.php
  Exceptions/                      ← DatabaseException, DatabaseInvalidArgumentException
tests/
  AbstractDatabaseTestCase.php     ← SQLite in-memory base
  Support/SqliteHelper.php         ← test fixtures
  BugRegressionTest.php            ← per-bug pinpoint tests
  CrudTest.php
  TransactionTest.php
  FacadeTest.php
  QueryLogTest.php
  DatabaseConstructionTest.php
docs/                              ← long-form reference docs
.github/workflows/                 ← phpunit, phpcs, phpstan, composer-validate

The package is small (~400 LoC of production code) on purpose — most of the surface is delegated via __call to initorm/query-builder and initorm/dbal.

Writing tests

The whole test suite uses SQLite in-memory — no external services, no fixtures, no docker-compose. New tests should keep that property: they must run on a vanilla composer install against just ext-pdo_sqlite.

Naming

Test method names are snake_case for readability:

public function test_bug3_transaction_failure_propagates_with_original_error(): void

This is explicitly allowed in phpcs.xml.dist:

<rule ref="PSR1.Methods.CamelCapsMethodName">
    <exclude-pattern>tests/*</exclude-pattern>
</rule>

Pattern

Extend AbstractDatabaseTestCase for "normal" tests:

final class MyFeatureTest extends AbstractDatabaseTestCase
{
    public function test_does_a_thing(): void
    {
        $this->db->create('users', [...]);
        // ...
    }
}

For tests that need fresh control over construction, use SqliteHelper directly:

$connection = SqliteHelper::makeConnection();
$db         = new Database($connection);

Regression tests

When you fix a bug, add a test that fails without your fix. Name it after the issue / bug number so future contributors can trace failures back:

/**
 * BUG-1: Database::read() snapshotted parameters BEFORE compiling the SELECT,
 * so any WHERE registered through generateSelectQuery()'s $conditions
 * shortcut was missing from the bound array → SQLSTATE[HY093].
 */
public function test_bug1_read_with_conditions_binds_parameters_correctly(): void
{
    // …
}

Code style

PSR-12 with two small relaxations:

  • 120-char line cap on src/, relaxed on src/Facade/DB.php (the facade carries 100+ long @method annotations mirrored from QueryBuilderInterface).
  • Tests can use snake_case method names (see above).

Both relaxations are encoded in phpcs.xml.dist. Run composer cs-fix to auto-fix everything PHPCBF can.

Documentation

The package has three documentation surfaces:

Surface Purpose When to update
README.md Repo landing, quick start New top-level features, install flow changes
docs/ Long-form reference embedded in the repo New methods, architectural changes
Wiki This — public-facing, navigation-friendly Same as docs/, in the matching page

Keep all three in sync. If you change behaviour, update README + the relevant docs/ page + the matching wiki page.

PR workflow

  1. Fork master, branch with a descriptive name (fix/transaction-rollback-guard, not patch-1).
  2. Make the change + add tests + update docs.
  3. Run composer qa locally until everything is green.
  4. Open the PR. A useful PR description includes:
    • The problem (link an issue if one exists)
    • The approach
    • The tradeoffs you considered
    • Anything you're unsure about
  5. CI will run the full matrix. Fix anything it flags.
  6. A maintainer reviews. Expect questions; this is normal.
  7. Squash-and-merge is the default. Your commit message becomes the merge commit subject — keep it clear and imperative.

What makes a great PR

  • One concern per PR. Don't bundle a bug fix with a refactor; submit them separately. Easier to review, easier to revert.
  • Tests for behaviour, not implementation. A test that asserts "the result is correct" survives refactors; a test that asserts "this private method was called" breaks the moment you rename it.
  • Document the why, not the what. Comments on the WHAT decay with the code; comments on the WHY (rationale, tradeoffs, references to incidents) age well.
  • Match the surrounding style. If the rest of the file uses early returns, use early returns. If methods are sorted by visibility, sort yours too.

Reporting bugs

Open an issue at https://github.com/InitORM/Database/issues. Useful reports include:

  • Composer composer show initorm/database output
  • PHP version + driver versions
  • Minimal reproducer (a single test method ideally)
  • Expected vs actual behaviour
  • Stack trace if any

Reproducer beats words: a PR with a failing test is the fastest path to a fix.

Suggesting features

Open an issue describing the use case first — features tend to balloon. A short issue thread can save you a lot of work. Once the direction is clear, send a PR.

See also

Clone this wiki locally