Compare commits
2
Commits
v1.5.6
...
76a314576e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76a314576e
|
||
|
|
2781243742 |
@@ -0,0 +1,47 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
composer install
|
||||
composer test # PHPUnit — run after every code change
|
||||
composer lint # PHPStan (level 10, `src/` only)
|
||||
composer cs # PHPCS (WordPress standard + exclusions in phpcs.xml.dist)
|
||||
composer cs:fix # auto-fix coding standards
|
||||
composer build # -> dist/unsupervised-schedular-<version>.zip
|
||||
|
||||
./vendor/bin/phpunit tests/Unit/Offering/OfferingRepositoryTest.php
|
||||
./vendor/bin/phpunit --filter testInsertReturnsId
|
||||
```
|
||||
|
||||
CI (`.gitea/workflows/ci.yml`): `phpcs`, `phpstan`, `test` (PHP 8.1/8.2/8.3/8.5), `no-debug`. Write only PHP 8.1-compatible syntax. No `var_dump|var_export|print_r|error_log|dd|dump(` in `src/` — CI greps and fails.
|
||||
|
||||
## Architecture
|
||||
|
||||
- WordPress plugin, no front-end build (vanilla JS/CSS in `assets/`). PSR-4 `Unsupervised\Schedular\` -> `src/`.
|
||||
- **Package-by-domain:** `src/<Domain>/` (Auth, Availability, Booking, GroupClass, Guardian, Offering, Payment, Policy, Registration) owns its repos, services, endpoints, pages. Cross-cutting wiring lives directly in `src/`: `Plugin`, `Installer`, `Schema`, `AdminMenu`, `RestRegistrar`, `ShortcodeRegistrar`, `BlockRegistrar`, `Val`.
|
||||
- Entry: `unsupervised-schedular.php` -> `Plugin::boot()` (wires all dependencies). **Slug is `schedular`, not `scheduler`** — filename, text domain (`unsupervised-schedular`), option `us_schedular_version`, table prefix `us_`. Never "fix" the spelling.
|
||||
- REST: `/wp-json/us-scheduler/v1/`, `permission_callback` uses capability checks, never role names.
|
||||
- DB: custom `us_*` tables via `dbDelta`; `Schema::tables()` is the source of truth. **All `$wpdb` access inside repository classes only.**
|
||||
- `src/Val.php` coerces untyped WP input (`Val::int()`, `Val::string()`, `...OrNull`, etc.). For PHPCS, `Val::int/float/bool/...` count as unslashing passthrough only — still wrap with a real sanitizer: `absint( Val::int( $_GET['id'] ?? 0 ) )`.
|
||||
|
||||
## Schema changes (gotcha)
|
||||
|
||||
- `Plugin::boot()` only re-runs `Installer`/migrations when stored `us_schedular_version !== USC_VERSION`. **Bump both the `Version:` header and `USC_VERSION` in `unsupervised-schedular.php` or the change never reaches existing sites.**
|
||||
- `dbDelta` does not reliably relax column NULL-ability. Follow the existing pattern in `Plugin::boot()`: repository repair method + own `us_*` option flag (e.g. `us_questions_offering_nullable`), not the version gate.
|
||||
|
||||
## Tests
|
||||
|
||||
- Brain Monkey + Mockery, no live WP. All test classes extend `tests/Unit/TestCase.php` (handles `Monkey\setUp/tearDown`, stubs translations/escaping/`checked`/`selected`).
|
||||
- Mirror layout: `tests/Unit/<Domain>/` mirrors `src/<Domain>/`.
|
||||
- `Functions\when('fn')->alias(fn() => ...)` (never `returnUsing()`); `->justReturn($v)` for constants.
|
||||
- Use `when()` not `expect()` for argument-dependent routing.
|
||||
- No `\Mockery::type()` inside plain arrays passed to `with()` — use `\Mockery::on()` or `\Mockery::any()`.
|
||||
- `$wpdb` mock needs `$mock->prefix = 'wp_'` as a property.
|
||||
|
||||
## Adding a feature
|
||||
|
||||
1. Spec first: `docs/features/<feature-name>.md` (data model, API, classes, test paths).
|
||||
2. Code in `src/<Domain>/`; templates in `templates/` if needed.
|
||||
3. Tests in `tests/Unit/<Domain>/`.
|
||||
4. `composer test` must pass (also `composer lint` + `composer cs` before finishing).
|
||||
@@ -1,31 +1,3 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Commands
|
||||
|
||||
**Run `composer test` after every code change before considering a task complete.**
|
||||
|
||||
## Architecture
|
||||
|
||||
### Code organisation
|
||||
**Code is organised package-by-domain.** Each domain package under `src/<Domain>/` contains everything related to that domain: value objects, repositories, controllers, REST endpoints, and shortcode pages. Cross-cutting wiring classes (Plugin, AdminMenu, RestRegistrar, ShortcodeRegistrar, Schema) live directly under `src/`.
|
||||
|
||||
### Data Storage
|
||||
Custom database tables are created via `dbDelta` on activation; `Schema.php` holds the SQL.
|
||||
|
||||
All database access goes through repository classes within their domain package. No direct `$wpdb` calls outside repositories.
|
||||
|
||||
### REST API Namespace
|
||||
All endpoints live under `/wp-json/us-scheduler/v1/`. Permissions are enforced via `permission_callback` using capability checks (`manage_availability`, `book_lesson`), never role name checks.
|
||||
|
||||
### Testing Approach
|
||||
Tests stub WordPress with Brain\Monkey rather than booting a real WP install. The setup and the Brain\Monkey/Mockery API gotchas are in `tests/CLAUDE.md`.
|
||||
|
||||
### Adding a Feature
|
||||
0. **If the feature touches `Schema.php`, bump both the `Version:` header and `USC_VERSION` in `unsupervised-schedular.php`.** `Plugin::boot()` only re-runs `Installer`/`dbDelta` when the stored `us_schedular_version` differs, so a schema change without a version bump never reaches existing sites and inserts into new columns fail silently.
|
||||
1. Write the feature doc in `docs/features/<feature-name>.md` (data model, API, classes, test paths).
|
||||
2. Create a domain package under `src/<Domain>/` containing all classes for that feature.
|
||||
3. Add template(s) under `templates/` if needed.
|
||||
4. Write unit tests under `tests/Unit/<Domain>/` mirroring the `src/<Domain>/` structure.
|
||||
5. Run `composer test` — all tests must pass before the feature is complete.
|
||||
See `AGENTS.md` — it is the single source of truth for working in this repo.
|
||||
|
||||
+1
-12
@@ -1,14 +1,3 @@
|
||||
# Writing tests
|
||||
|
||||
Tests use [Brain\Monkey](https://brain-wp.github.io/BrainMonkey/) to stub WordPress functions without a full WP installation, and Mockery to mock `$wpdb` and other dependencies.
|
||||
|
||||
All test classes extend `tests/Unit/TestCase.php`, which handles `Monkey\setUp()` / `Monkey\tearDown()` and stubs all WP translation/escape functions automatically.
|
||||
|
||||
**Brain\Monkey API notes:**
|
||||
|
||||
- `Functions\when('fn')->alias(fn() => ...)` — stub with a closure (NOT `returnUsing()`)
|
||||
- `Functions\when('fn')->justReturn($val)` — stub returning a fixed value
|
||||
- `Functions\expect('fn')->once()->with(...)` — assert call count and arguments
|
||||
- Use `Functions\when()` (not `Functions\expect()`) when you need argument-routing (e.g. `get_role` returning different values per argument) to avoid chaining ambiguity
|
||||
- Mockery matchers (e.g. `\Mockery::type()`) inside plain PHP arrays do not work with `with()` — use `\Mockery::on(fn($arr) => ...)` or `\Mockery::any()` instead
|
||||
- When mocking `$wpdb`, set `$mock->prefix = 'wp_'` explicitly — it is a public property, not a method
|
||||
See `../../AGENTS.md` (Tests section) — it is the single source of truth for working in this repo.
|
||||
|
||||
Reference in New Issue
Block a user