|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +**Nette Bootstrap** is a foundational library for the Nette Framework that handles application initialization and Dependency Injection (DI) container generation. It's a standalone package (`nette/bootstrap`) that: |
| 8 | + |
| 9 | +- Initializes application environment settings (debug mode, timezone, etc.) |
| 10 | +- Generates and manages the DI container |
| 11 | +- Loads and processes NEON configuration files |
| 12 | +- Integrates all Nette framework extensions |
| 13 | +- Provides fluent interface for application configuration |
| 14 | + |
| 15 | +**Requirements:** PHP 8.0-8.5 |
| 16 | + |
| 17 | +## Basic Usage |
| 18 | + |
| 19 | +Typical bootstrap sequence for standalone usage (outside of full Nette framework): |
| 20 | + |
| 21 | +```php |
| 22 | +// 1. Create configurator |
| 23 | +$configurator = new Nette\Bootstrap\Configurator; |
| 24 | + |
| 25 | +// 2. Set temp directory (required - for DI container cache) |
| 26 | +$configurator->setTempDirectory(__DIR__ . '/temp'); |
| 27 | + |
| 28 | +// 3. Load configuration files |
| 29 | +$configurator->addConfig(__DIR__ . '/database.neon'); |
| 30 | +// Multiple configs can be added - later files override earlier ones |
| 31 | +$configurator->addConfig(__DIR__ . '/services.neon'); |
| 32 | + |
| 33 | +// 4. Optional: Add dynamic parameters (not cached, evaluated per request) |
| 34 | +$configurator->addDynamicParameters([ |
| 35 | + 'remoteIp' => $_SERVER['REMOTE_ADDR'], |
| 36 | +]); |
| 37 | + |
| 38 | +// 5. Create DI container |
| 39 | +$container = $configurator->createContainer(); |
| 40 | + |
| 41 | +// 6. Get services from container |
| 42 | +$db = $container->getByType(Nette\Database\Connection::class); |
| 43 | +// or by name when multiple instances exist |
| 44 | +$db = $container->getByName('database.main.connection'); |
| 45 | +``` |
| 46 | + |
| 47 | +**Important:** On Linux/macOS, set write permissions for the `temp/` directory. |
| 48 | + |
| 49 | +### Development vs Production Mode |
| 50 | + |
| 51 | +The container behavior differs between modes: |
| 52 | + |
| 53 | +- **Development mode:** Container auto-updates when configuration files change (convenience) |
| 54 | +- **Production mode:** Container generated once, changes ignored (performance) |
| 55 | + |
| 56 | +**Autodetection:** |
| 57 | +- Development: Running on localhost (`127.0.0.1` or `::1`) without proxy |
| 58 | +- Production: All other cases |
| 59 | + |
| 60 | +**Manual control:** |
| 61 | + |
| 62 | +```php |
| 63 | +// Enable for specific IP addresses |
| 64 | +$configurator->setDebugMode('23.75.345.200'); |
| 65 | +// or array of IPs |
| 66 | +$configurator->setDebugMode(['23.75.345.200', '192.168.1.100']); |
| 67 | + |
| 68 | +// Combine IP with cookie secret (recommended for production debugging) |
| 69 | +// Requires 'nette-debug' cookie with value 'secret1234' |
| 70 | +$configurator->setDebugMode(' [email protected]'); |
| 71 | + |
| 72 | +// Force disable even for localhost |
| 73 | +$configurator->setDebugMode(false); |
| 74 | +``` |
| 75 | + |
| 76 | +### Retrieving Services from Container |
| 77 | + |
| 78 | +```php |
| 79 | +// By type (when only one instance exists) |
| 80 | +$db = $container->getByType(Nette\Database\Connection::class); |
| 81 | +$explorer = $container->getByType(Nette\Database\Explorer::class); |
| 82 | + |
| 83 | +// By name (when multiple instances exist) |
| 84 | +$mainDb = $container->getByName('database.main.connection'); |
| 85 | +$logDb = $container->getByName('database.log.connection'); |
| 86 | +``` |
| 87 | + |
| 88 | +## Essential Commands |
| 89 | + |
| 90 | +### Testing |
| 91 | + |
| 92 | +```bash |
| 93 | +# Run all tests |
| 94 | +vendor/bin/tester tests -s |
| 95 | + |
| 96 | +# Run all tests with coverage info |
| 97 | +vendor/bin/tester tests -s -C |
| 98 | + |
| 99 | +# Run specific test file |
| 100 | +vendor/bin/tester tests/Bootstrap/Configurator.basic.phpt |
| 101 | + |
| 102 | +# Run tests with lowest dependencies (CI check) |
| 103 | +composer update --prefer-lowest && vendor/bin/tester tests -s |
| 104 | +``` |
| 105 | + |
| 106 | +### Code Quality |
| 107 | + |
| 108 | +```bash |
| 109 | +# Run PHPStan static analysis |
| 110 | +composer phpstan |
| 111 | + |
| 112 | +# Run PHPStan without progress bar (CI mode) |
| 113 | +composer phpstan -- --no-progress |
| 114 | +``` |
| 115 | + |
| 116 | +### Development |
| 117 | + |
| 118 | +```bash |
| 119 | +# Install dependencies |
| 120 | +composer install |
| 121 | + |
| 122 | +# Update dependencies |
| 123 | +composer update |
| 124 | +``` |
| 125 | + |
| 126 | +## Architecture |
| 127 | + |
| 128 | +### Core Component: Configurator Class |
| 129 | + |
| 130 | +Location: `src/Bootstrap/Configurator.php` |
| 131 | + |
| 132 | +The `Configurator` class is the heart of this library. It follows a fluent interface pattern and handles: |
| 133 | + |
| 134 | +**1. Environment Setup:** |
| 135 | +- `setDebugMode()` - Toggle debug/production mode with IP-based detection |
| 136 | +- `setTempDirectory()` - Set cache directory for DI container |
| 137 | +- `setTimeZone()` - Configure PHP timezone |
| 138 | +- `enableTracy()` - Enable Tracy debugger (if installed) |
| 139 | + |
| 140 | +**2. Parameter Management:** |
| 141 | +- **Static parameters** (set at config time, cached): `addStaticParameters()` |
| 142 | +- **Dynamic parameters** (evaluated per request, not cached): `addDynamicParameters()` |
| 143 | + - Useful for runtime values like `$_SERVER['REMOTE_ADDR']`, current user, etc. |
| 144 | + - Referenced in config using `%parameterName%` notation |
| 145 | + |
| 146 | +**Default parameters available:** |
| 147 | +- `appDir` - Application directory |
| 148 | +- `wwwDir` - Web root directory |
| 149 | +- `tempDir` - Temporary/cache directory |
| 150 | +- `vendorDir` - Composer vendor directory |
| 151 | +- `rootDir` - Project root (auto-detected from Composer) |
| 152 | +- `baseUrl` - Base URL (dynamically resolved from HTTP request) |
| 153 | +- `debugMode` / `productionMode` - Environment flags |
| 154 | +- `consoleMode` - CLI detection |
| 155 | + |
| 156 | +**3. Configuration Loading:** |
| 157 | +- `addConfig(string|array)` - Load NEON files or inline arrays |
| 158 | +- Multiple configs are merged (later configs override earlier ones) |
| 159 | +- Parameter expansion with `%paramName%` syntax |
| 160 | +- Recursive parameter substitution with type coercion |
| 161 | + |
| 162 | +**4. Container Generation:** |
| 163 | +- `createContainer()` - Create and initialize DI container |
| 164 | +- `loadContainer()` - Load cached container or generate new one |
| 165 | +- Caching based on: configs, static params, dynamic param names, PHP version, Composer mtime |
| 166 | + |
| 167 | +### Default Extensions System |
| 168 | + |
| 169 | +Bootstrap pre-registers 17 framework extensions in `$defaultExtensions`: |
| 170 | + |
| 171 | +``` |
| 172 | +application, assets, cache, constants, database, decorator, di, |
| 173 | +extensions, forms, http, inject, latte, mail, php, routing, |
| 174 | +search, security, session, tracy |
| 175 | +``` |
| 176 | + |
| 177 | +Each extension processes its own configuration section (e.g., `database:`, `forms:`, `mail:`). |
| 178 | + |
| 179 | +### Custom Bootstrap Extensions |
| 180 | + |
| 181 | +Two extensions in `src/Bootstrap/Extensions/`: |
| 182 | + |
| 183 | +**ConstantsExtension** - Defines PHP constants from configuration: |
| 184 | +```neon |
| 185 | +constants: |
| 186 | + MY_CONST: value |
| 187 | + ANOTHER: %parameter% |
| 188 | +``` |
| 189 | + |
| 190 | +**PhpExtension** - Sets PHP ini directives: |
| 191 | +```neon |
| 192 | +php: |
| 193 | + date.timezone: Europe/Prague |
| 194 | + display_errors: "0" |
| 195 | +``` |
| 196 | + |
| 197 | +### Configuration Flow |
| 198 | + |
| 199 | +``` |
| 200 | +1. User creates Configurator and sets environment |
| 201 | +2. User adds config files via addConfig() |
| 202 | +3. Configurator loads all NEON configs |
| 203 | +4. Extensions are instantiated in order |
| 204 | +5. Each extension processes its config section |
| 205 | +6. DI Compiler generates PHP container class |
| 206 | +7. Container cached in tempDir/cache/nette.configurator/ |
| 207 | +8. Dynamic parameters injected at runtime |
| 208 | +``` |
| 209 | + |
| 210 | +### Debug Mode Detection |
| 211 | + |
| 212 | +`Configurator::detectDebugMode($list)` supports: |
| 213 | +- **IP whitelist matching** - Single IP or CIDR subnet (e.g., `'23.75.345.200'` or `['192.168.1.0/24']`) |
| 214 | +- **Cookie-based secret ** - Format: `'secret@ip'` (e.g., `'[email protected]'`) |
| 215 | + - Checks for `nette-debug` cookie with the secret value |
| 216 | + - Recommended for production debugging - safe even if IP changes |
| 217 | +- **X-Forwarded-For** proxy header detection |
| 218 | +- **Auto-enables** for localhost (`127.0.0.1`, `::1`) |
| 219 | +- **Fallback** to computer hostname when no REMOTE_ADDR (CLI mode) |
| 220 | + |
| 221 | +## Testing Infrastructure |
| 222 | + |
| 223 | +**Framework:** Nette Tester with PHPT format (18 test files) |
| 224 | + |
| 225 | +**Test Organization:** |
| 226 | +``` |
| 227 | +tests/ |
| 228 | +├── bootstrap.php # Test setup with getTempDir() helper |
| 229 | +├── Bootstrap/ |
| 230 | +│ ├── Configurator.*.phpt |
| 231 | +│ ├── ConstantsExtension.phpt |
| 232 | +│ ├── PhpExtension.phpt |
| 233 | +│ └── files/ # NEON test fixtures |
| 234 | +└── tmp/ # Temporary test output |
| 235 | +``` |
| 236 | + |
| 237 | +**Test Bootstrap Helpers:** |
| 238 | +- `getTempDir()` - Creates per-process temp directory with automatic garbage collection |
| 239 | +- `test($title, $function)` - Simple test wrapper |
| 240 | + |
| 241 | +**Test Pattern:** |
| 242 | +```php |
| 243 | +require __DIR__ . '/../bootstrap.php'; |
| 244 | + |
| 245 | +$configurator = new Configurator; |
| 246 | +$configurator->setTempDirectory(getTempDir()); |
| 247 | +$configurator->addConfig('files/config.neon'); |
| 248 | +$container = $configurator->createContainer(); |
| 249 | + |
| 250 | +Assert::same('expected', $container->parameters['foo']); |
| 251 | +``` |
| 252 | + |
| 253 | +## CI/CD |
| 254 | + |
| 255 | +**GitHub Actions workflows:** |
| 256 | + |
| 257 | +1. **Tests** (`.github/workflows/tests.yml`): |
| 258 | + - Matrix: PHP 8.0, 8.1, 8.2, 8.3, 8.4, 8.5 |
| 259 | + - Runs `vendor/bin/tester tests -s -C` |
| 260 | + - Lowest dependencies test with `composer update --prefer-lowest` |
| 261 | + - Code coverage with phpdbg and php-coveralls |
| 262 | + |
| 263 | +2. **Static Analysis** (`.github/workflows/static-analysis.yml`): |
| 264 | + - Runs on master branch (informative only) |
| 265 | + - Command: `composer phpstan -- --no-progress` |
| 266 | + - Continues on error |
| 267 | + |
| 268 | +## NEON Configuration Format |
| 269 | + |
| 270 | +Bootstrap uses NEON (Nette's configuration language). Key sections: |
| 271 | + |
| 272 | +**Parameters:** |
| 273 | +```neon |
| 274 | +parameters: |
| 275 | + appDir: /path/to/app |
| 276 | + debugMode: true |
| 277 | + custom: value |
| 278 | +``` |
| 279 | + |
| 280 | +**Extensions:** |
| 281 | +```neon |
| 282 | +extensions: |
| 283 | + myExt: App\MyExtension |
| 284 | +``` |
| 285 | + |
| 286 | +**Framework-specific sections:** |
| 287 | +```neon |
| 288 | +constants: |
| 289 | + MY_CONST: value |
| 290 | +
|
| 291 | +php: |
| 292 | + date.timezone: Europe/Prague |
| 293 | +
|
| 294 | +database: |
| 295 | + dsn: "mysql:host=127.0.0.1;dbname=test" |
| 296 | + user: root |
| 297 | + password: secret |
| 298 | +``` |
| 299 | + |
| 300 | +**Parameter expansion** - Use `%paramName%` to reference parameters in config files. |
| 301 | + |
| 302 | +## Key Design Patterns |
| 303 | + |
| 304 | +1. **Fluent Interface** - All configuration methods return `static` for method chaining |
| 305 | +2. **Extension Pattern** - Extensible via DI extensions with `onCompile` callback |
| 306 | +3. **Container Caching** - Lazy loading with intelligent cache invalidation |
| 307 | +4. **Parameter Substitution** - Both compile-time (static) and runtime (dynamic) parameters |
| 308 | +5. **Singleton DI Container** - Generated PHP class with lazy service initialization |
| 309 | + |
| 310 | +## Important Notes |
| 311 | + |
| 312 | +- Container cache key includes PHP version, so cache is invalidated on PHP upgrades |
| 313 | +- Dynamic parameters are NOT cached - they're evaluated per request |
| 314 | +- Configuration merging uses `DI\Config\Helpers::merge()` for deep array merging |
| 315 | +- Debug mode can be forced via cookie secret (useful for production debugging) |
| 316 | +- The library has no direct dependency on tracy/tracy (optional integration) |
0 commit comments