# AI Contribution Guidelines

Welcome, AI assistant. Please follow these guidelines when contributing to this repository.

## Project Overview

EasyAdminBundle is a third-party Symfony bundle for creating admin backends. It provides CRUD controllers, dashboard management, and extensive field/filter configuration.

**Requirements:** PHP 8.2+, Symfony 6.4/7.x/8.x, Doctrine ORM 2.20+ or 3.6+

## General Rules

- Language: American English for code, comments, commits, branches
- Code quotes: wrap strings with single quotes in PHP, CSS, JavaScript
- Text quotes: straight quotes only (`'` and `"`, no typographic)
- Security: prevent XSS, CSRF, injections, auth bypass, open redirects

### Do Not Edit
- `vendor/` - managed by Composer
- `node_modules/` - managed by Yarn
- `var/` - Symfony cache/logs
- `public/bundles/` - generated assets
- `composer.lock`, `yarn.lock` - update only via package manager commands

## Architecture

### Key Patterns
- **Factory**: ActionFactory, EntityFactory, FieldFactory, FilterFactory, FormFactory
- **Configurator Chain**: FieldConfiguratorInterface, FilterConfiguratorInterface
- **Context Facade**: AdminContext wraps Request/Crud/Dashboard/I18n contexts
- **DTO Layer**: Type-safe data transfer (ActionDto, EntityDto, FieldDto, etc.)
- **Event Subscriber**: AdminRouterSubscriber, CrudAutocompleteSubscriber
- **Registry**: AdminControllerRegistry, TemplateRegistry
- **Provider**: AdminContextProvider, FieldProvider
- **Typed Collections**: FieldCollection, ActionCollection, FilterCollection
- **Argument Resolver**: AdminContextResolver, BatchActionDtoResolver

Don't modify the public API in `Contracts/` lightly — it's a stable, versioned interface that third-party code depends on.

### Design Principles
- Never surface internal complexity to end users. Keep the public API small, simple, and consistent; push complexity down into internal classes (factories, configurators, DTOs), not onto the people configuring a backend.
- Public APIs are stable contracts: prefer additive, backward-compatible changes and don't leak internal types or implementation details through them.

### Backward Compatibility
Follow [Symfony's BC policy](https://symfony.com/bc): never break public API — deprecate first, keep the old path working, remove only in the next major. Emit deprecations with `@trigger_deprecation('easycorp/easyadmin-bundle', '<version>', '<message>')`, naming the replacement and removal version.

### Configuration Model
User-facing config uses fluent **builders** (`Config/`, `Field/`): static `new()` + chainable setters returning `self`. Each builder converts via `getAsDto()` into an immutable **DTO** (`Dto/`) for internal use. New configurable concepts follow this split — fluent builder for users, DTO internally; never expose a DTO as the config surface.

### Main Namespace
`EasyCorp\Bundle\EasyAdminBundle\`

## Commands

The `Makefile` is the source of truth for build/lint/test commands; its targets match what CI runs. Prefer them over hand-typed invocations. Run `make help` to list every target.

### Setup
```bash
make build          # composer update + yarn install (first-time setup)
composer install    # PHP dependencies only
yarn install        # JS dependencies only
```

### Before Creating a PR
Run the full check suite (linters + tests, identical to CI):
```bash
make checks-before-pr
```

### Pre-Commit Checklist
Run the relevant target(s) for what you changed:

| Changed          | Run                                                               |
|------------------|-------------------------------------------------------------------|
| PHP code         | `make linter-phpstan`, `make linter-cs-fixer`, `make tests`       |
| JS / CSS         | `yarn ci`, then `make build-assets`                               |
| Twig templates   | `make linter-twig`                                                |
| Documentation    | `make linter-docs`                                                |
| Translations     | keep all locales consistent; use English as placeholder if unsure |

Run targeted tests with `make tests ARGS=...` (keeps the deprecation baseline and cache reset; full guide in `tests/AGENTS.md`):
```bash
make tests                            # whole suite
make tests ARGS="tests/Unit/Field/"   # one directory
make tests ARGS="--filter=testFoo"    # one test
```
A bare `./vendor/bin/simple-phpunit` run skips the deprecation baseline (`tests/baseline-ignore.txt`) and the cache reset.

## Git and Pull Requests

### Commit Messages
- Use imperative mood: "Add feature" not "Added feature"
- First line: concise summary (50 chars max)
- Reference issues when applicable: "Fix #123"
- No period at end of subject line

### Branch Naming
- Feature: `<short description>` (e.g., `add_new_field_type`)
- Bug fix: `fix_<issue number>` (e.g., `fix_123`)
- Use lowercase with underscores

## PHP Code Standards

php-cs-fixer (`@Symfony` + `@Symfony:risky`) auto-formats most style — trailing commas, braces, strict comparisons, Yoda conditions, blank lines, quotes, etc. Run `make linter-cs-fixer` and let it handle formatting. The rules below are the conventions it does **not** enforce.

### Conventions
- PHP 8.2+ syntax with constructor property promotion
- Don't add `declare(strict_types=1);` to PHP files
- No service autowiring — configure explicitly in `config/services.php`
- Use enums (`UpperCamelCase` case names) instead of constants for fixed sets of values
- Prefer project constants (`Action::EDIT`, `EA::QUERY`) over hardcoded strings
- Avoid `else`/`elseif` after `return`/`throw` — return/throw early instead
- `return null;` for nullable, `return;` for void
- Use `sprintf()` for exception messages with `get_debug_type()` for class names
- Exception/error messages: start capital, end with a period, no backticks; concise but actionable (include class names, file paths)
- Handle exceptions explicitly (no silent catches)
- Comments: only for complex/unintuitive code, lowercase start, no period end; never as section separators (e.g. `// === Methods for dashboards ===`)
- Config files in PHP format (`config/services.php`, `translations/*.php`)

### Naming
- Variables/methods: `camelCase`
- Config/routes/Twig: `snake_case`
- Constants: `SCREAMING_SNAKE_CASE`
- Classes: `UpperCamelCase`
- Abstract classes: `Abstract*` (except test cases)
- Interfaces: `*Interface`, Traits: `*Trait`, Exceptions: `*Exception`
- Most classes add a suffix showing their type:
  `*Controller`, `*Configurator`, `*Context`, `*Dto`, `*Event`,
  `*Field`, `*Filter`, `*Subscriber`, `*Type`, `*Test`
- Templates/assets: `snake_case` (e.g., `detail_page.html.twig`)

### Class Organization
1. Properties before methods
2. Constructor first, then public, protected, private methods in that order

### PHPDoc
- No single-line docblocks
- No `@return` for void methods
- Group annotations by type

## Templates (Twig)

twig-cs-fixer handles formatting (`make linter-twig`). Conventions it doesn't enforce:

- Modern HTML5 and Twig syntax
- Icons: FontAwesome 6.x names
- All user-facing text via `|trans` filter (no hardcoded strings)
- Keep translation logic in templates, not PHP (use `TranslatableInterface`)
- Reuse components from `templates/components/` when available — see `src/Twig/Component/AGENTS.md` before adding or changing a component
- Accessibility: `aria-*` attributes, semantic tags, labels

## JavaScript

biome handles formatting (`yarn ci`). Conventions it doesn't enforce:

- ES6+ syntax
- `camelCase` for variables and functions

## CSS

- Standard CSS only (no SCSS/LESS)
- Don't use nested rules — keep selectors flat
- `kebab-case` for class names
- Bootstrap 5.3 classes and utilities
- Logical properties: `margin-block-end` instead of `margin-bottom`
- Responsive design required; use only these Bootstrap breakpoints:
  - Medium (md): ≥768px
  - Large (lg): ≥992px
  - Extra large (xl): ≥1200px

## Documentation (doc/)

- Format: reStructuredText (.rst)
- Heading symbols: `=`, `-`, `~`, `.`, `"` for levels 1-5
- Line length: 72-78 characters
- Code blocks: prefer `::` over `.. code-block:: php`
- Separate link text from URLs (no inline hyperlinks)
- Show config in order: YAML, XML, PHP (or Attributes)
- Code line limit: 85 chars (use `...` for folded code)
- Include `use` statements for referenced classes
- Bash lines prefixed with `$`
- Root directory: `your-project/`
- Vendor name: `Acme`
- URLs: `example.com`, `example.org`, `example.net`
- Trailing slashes for directories, leading dots for extensions

### Writing Style
- American English, second person (you)
- Gender-neutral (they/them)
- Use contractions (it's, don't, you're)
- Avoid: "just", "obviously", "easy", "simply"
- Realistic examples (no foo/bar placeholders)
- Write for non-native English speakers: use simple vocabulary, avoid idioms, and complex sentence structures
