|
| 1 | +# FlightPHP Skeleton Project Instructions |
| 2 | + |
| 3 | +This document provides guidelines and best practices for structuring and developing a project using the FlightPHP framework. |
| 4 | + |
| 5 | +## Instructions for AI Coding Assistants |
| 6 | + |
| 7 | +As you are developing this project, follow these guidelines as close as you can. If you are unsure about something, ask for clarification before proceeding. You should feel 95% confident in the coding decisions that you make, but allow yourself an offramp if you are not sure about something to ask questions. |
| 8 | + |
| 9 | +## Project Structure |
| 10 | + |
| 11 | +Organize your project as follows: |
| 12 | + |
| 13 | +project-root/ |
| 14 | +│ |
| 15 | +├── app/ # Application-specific code |
| 16 | +│ ├── commands/ # Custom CLI commands for Runway (built using adhocore/cli) |
| 17 | +│ ├── config/ # Configuration files (database, app settings, routes) |
| 18 | +│ # Key files in this folder: |
| 19 | +│ # - bootstrap.php: Bootstraps and connects the files in the config folder. |
| 20 | +│ # - routes.php: Route definitions. |
| 21 | +│ # - services.php: Service definitions (where config variables are used and injected). |
| 22 | +│ ├── controllers/ # Route controllers (e.g., HomeController.php) |
| 23 | +│ ├── logic/ # (For large projects) Business logic classes/services, called from controllers |
| 24 | +│ ├── middlewares/ # Custom middleware classes/functions |
| 25 | +│ ├── models/ # Data models (if needed, usually using flightphp/active-record) |
| 26 | +│ ├── utils/ # Utility/helper functions |
| 27 | +│ └── views/ # View templates (if using) |
| 28 | +│ |
| 29 | +├── public/ # Web root (index.php, assets, etc.) |
| 30 | +│ |
| 31 | +├── vendor/ # Composer dependencies |
| 32 | +│ |
| 33 | +├── tests/ # Unit and integration tests |
| 34 | +│ |
| 35 | +├── composer.json # Composer config |
| 36 | +│ |
| 37 | +└── README.md # Project overview |
| 38 | + |
| 39 | +## Development Guidelines |
| 40 | + |
| 41 | +- **Controllers:** Place all route-handling logic in `app/controllers/`. Each controller should handle a specific resource or feature. For large projects, move business logic out of controllers and into the `app/logic/` directory as dedicated classes/services, and call them from your controllers. Use appropriate namespaces for organization. By default, all controllers inject the `Engine $app` variable unless this project has its own dependency injection handler. Namespaces for Flight projects are defined in lowercase characters until the name of the class. For example, it is `app/controllers/HomeController.php` and not `App/Controllers/HomeController.php`. |
| 42 | +- **Middlewares:** Store reusable middleware in `app/middlewares/`. Register them in your bootstrap or route files. |
| 43 | +- **Utils:** Place helper functions and utilities in `app/utils/`. |
| 44 | +- **Models:** If your app uses data models, keep them in `app/models/`. |
| 45 | +- **Views:** Store templates in `app/views/` if using a templating engine. |
| 46 | +- **Config:** Use the `app/config/` directory for configuration files. The main config file is `config.php`, which should be created by copying `config_sample.php` and updating as needed. |
| 47 | +- **Public:** Only expose the `public/` directory to the web server. All requests should go through `public/index.php`. |
| 48 | +- **Environment:** Do not use .env files; all configuration should be managed in `app/config/config.php`. |
| 49 | + |
| 50 | +## Getting Started |
| 51 | + |
| 52 | +1. Clone the repository and run `composer install`. |
| 53 | +2. Copy `app/config/config_sample.php` to `app/config/config.php` and update configuration values as needed. |
| 54 | +3. Set your web server's document root to the `public/` directory. |
| 55 | +4. Add new controllers, middlewares, and utilities as needed, following the structure above. |
| 56 | +5. Register routes and middlewares in your bootstrap file (usually `public/index.php`). |
| 57 | + |
| 58 | +## CLI Commands |
| 59 | + |
| 60 | +Flight projects can include custom CLI commands to automate tasks such as migrations, seeding, or maintenance. The recommended CLI tool is [flightphp/runway](https://github.com/flightphp/runway), which builds on the [adhocore/cli](https://github.com/adhocore/cli) package (not Symfony Console). |
| 61 | + |
| 62 | +- Place your custom command classes in the `app/commands/` directory. |
| 63 | +- Runway will automatically discover and register commands from this directory. |
| 64 | +- All CLI commands should be built using the adhocore/cli package (do not use Symfony Console). |
| 65 | +- Use CLI commands to manage your application, generate code, or perform routine tasks. |
| 66 | + |
| 67 | +Refer to the Runway documentation for details on creating and using custom commands with adhocore/cli. |
| 68 | + |
| 69 | +## Additional Tips |
| 70 | + |
| 71 | +- Keep controllers focused and small; delegate global or common logic to `app/utils/` when possible. For large projects, move business logic to `app/logic/` and use appropriate namespaces. |
| 72 | +- Write tests for class files in the `tests/` directory. |
| 73 | +- Use Composer for dependency management. |
| 74 | +- Document your code and update the README as your project evolves. |
| 75 | +- **Favor simplicity and minimalism:** Keep your codebase simple and avoid unnecessary abstractions or complexity. Only add dependencies when absolutely necessary, as fewer dependencies mean fewer potential issues and security risks. |
| 76 | +- **Follow coding standards:** Use PSR1 coding standards and strict comparisons (`===`). Maintain a high level of code quality and consistency throughout your project. |
| 77 | +- **Test thoroughly:** Regularly run and maintain tests for your codebase. Ensure your application works as expected. |
| 78 | + |
| 79 | +For more details, see the README file or visit the FlightPHP documentation. |
| 80 | + |
| 81 | +## Suggested Packages |
| 82 | + |
| 83 | +Flight is highly extensible. Here are some recommended packages and plugins for common needs: |
| 84 | + |
| 85 | +- **ORM / Database:** |
| 86 | + - [flightphp/active-record](https://github.com/flightphp/active-record) (official ORM/Mapper) |
| 87 | + - [flightphp/core](https://github.com/flightphp/core) PdoWrapper (simple PDO wrapper) |
| 88 | + - [byjg/php-migration](https://github.com/byjg/php-migration) (database migrations) |
| 89 | +- **Session:** |
| 90 | + - [flightphp/session](https://github.com/flightphp/session) (official session library) |
| 91 | + - [Ghostff/Session](https://github.com/Ghostff/Session) (advanced session manager) |
| 92 | +- **Permissions:** |
| 93 | + - [flightphp/permissions](https://github.com/flightphp/permissions) (official permissions library) |
| 94 | +- **Caching:** |
| 95 | + - [flightphp/cache](https://github.com/flightphp/cache) (official in-file caching) |
| 96 | +- **CLI:** |
| 97 | + - [flightphp/runway](https://github.com/flightphp/runway) (official CLI tool, built on adhocore/cli) |
| 98 | +- **Cookies:** |
| 99 | + - [overclokk/cookie](https://github.com/overclokk/cookie) (cookie management) |
| 100 | +- **Debugging:** |
| 101 | + - [tracy/tracy](https://github.com/nette/tracy) (error handler and debugger) |
| 102 | + - [flightphp/tracy-extensions](https://github.com/flightphp/tracy-extensions) (Flight-specific Tracy panels) |
| 103 | +- **APM (Performance Monitoring):** |
| 104 | + - [flightphp/apm](https://github.com/flightphp/apm) (application performance monitoring) |
| 105 | +- **Encryption:** |
| 106 | + - [defuse/php-encryption](https://github.com/defuse/php-encryption) (encryption/decryption) |
| 107 | +- **Job Queue:** |
| 108 | + - [n0nag0n/simple-job-queue](https://github.com/n0nag0n/simple-job-queue) (asynchronous job processing) |
| 109 | +- **Templating:** |
| 110 | + - [latte/latte](https://github.com/nette/latte) (recommended templating engine) |
| 111 | + - (Deprecated) flightphp/core View (basic, not recommended for large projects) |
| 112 | +- **API Documentation:**betaflightphp |
| 113 | + - [SwaggerUI](https://github.com/zircote/swagger-php) (Swagger/OpenAPI documentation) |
| 114 | + - [FlightPHP OpenAPI Generator](https://daniel-schreiber.de/blog/flightphp-openapi-generator.html) (API-first approach) |
| 115 | + |
| 116 | +Choose the packages that best fit your project's needs. Official FlightPHP packages are recommended for core functionality. |
| 117 | + |
| 118 | +## Security Best Practices |
| 119 | + |
| 120 | +All code implemented in this project must follow secure coding best practices. Insecure code will not be accepted. Always assume user input is hostile and never trust data from users or external sources. The following guidelines and examples are required for all code contributions: |
| 121 | + |
| 122 | +### Cross Site Scripting (XSS) |
| 123 | +- Always escape output from users before rendering in views. |
| 124 | +- Use Flight's view class or a templating engine like Latte, which auto-escapes variables. |
| 125 | + |
| 126 | +```php |
| 127 | +// Example: Escaping user input in views |
| 128 | +$name = '<script>alert("XSS")</script>'; |
| 129 | +Flight::view()->set('name', $name); // Escapes output |
| 130 | +Flight::view()->render('template', ['name' => $name]); // Latte auto-escapes |
| 131 | +``` |
| 132 | + |
| 133 | +### SQL Injection |
| 134 | +- Never concatenate user input into SQL queries. |
| 135 | +- Always use prepared statements or parameterized queries. |
| 136 | + |
| 137 | +```php |
| 138 | +// Secure: Using prepared statements |
| 139 | +$statement = Flight::db()->prepare('SELECT * FROM users WHERE username = :username'); |
| 140 | +$statement->execute([':username' => $username]); |
| 141 | +$users = $statement->fetchAll(); |
| 142 | + |
| 143 | +// Or with PdoWrapper |
| 144 | +$users = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]); |
| 145 | +``` |
| 146 | + |
| 147 | +### CORS (Cross-Origin Resource Sharing) |
| 148 | +- Set CORS headers using a utility or middleware before Flight::start(). |
| 149 | +- Only allow trusted origins. |
| 150 | + |
| 151 | +```php |
| 152 | +// Example: app/utils/CorsUtil.php |
| 153 | +namespace app\utils; |
| 154 | +class CorsUtil { |
| 155 | + public function set(array $params): void { /* ...see docs for full example... */ } |
| 156 | + private function allowOrigins(): void { /* ... */ } |
| 157 | +} |
| 158 | +// In index.php |
| 159 | +$CorsUtil = new CorsUtil(); |
| 160 | +Flight::before('start', [ $CorsUtil, 'set' ]); |
| 161 | +``` |
| 162 | + |
| 163 | +### Error Handling |
| 164 | +- Never display sensitive error details in production. |
| 165 | +- Log errors instead and use Flight::halt() for controlled responses. |
| 166 | + |
| 167 | +```php |
| 168 | +$environment = ENVIRONMENT; |
| 169 | +if ($environment === 'production') { |
| 170 | + ini_set('display_errors', 0); |
| 171 | + ini_set('log_errors', 1); |
| 172 | + ini_set('error_log', '/path/to/error.log'); |
| 173 | +} |
| 174 | +// Controlled error response |
| 175 | +Flight::halt(403, 'Access denied'); |
| 176 | +``` |
| 177 | + |
| 178 | +### Input Sanitization |
| 179 | +- Always sanitize and validate user input before processing. |
| 180 | + |
| 181 | +```php |
| 182 | +$clean_input = filter_var(Flight::request()->data->input, FILTER_SANITIZE_STRING); |
| 183 | +$clean_email = filter_var(Flight::request()->data->email, FILTER_SANITIZE_EMAIL); |
| 184 | +``` |
| 185 | + |
| 186 | +### Password Hashing |
| 187 | +- Always hash passwords using PHP's built-in functions. Never store plain text passwords. |
| 188 | + |
| 189 | +```php |
| 190 | +$hashed_password = password_hash($password, PASSWORD_DEFAULT); |
| 191 | +if (password_verify($password, $stored_hash)) { /* Password matches */ } |
| 192 | +``` |
| 193 | + |
| 194 | +### Rate Limiting |
| 195 | +- Use caching or middleware to limit repeated requests and prevent brute force attacks. |
| 196 | + |
| 197 | +```php |
| 198 | +Flight::before('start', function() { |
| 199 | + $cache = Flight::cache(); |
| 200 | + $ip = Flight::request()->ip; |
| 201 | + $key = "rate_limit_{$ip}"; |
| 202 | + $attempts = (int) $cache->retrieve($key); |
| 203 | + if ($attempts >= 10) { |
| 204 | + Flight::halt(429, 'Too many requests'); |
| 205 | + } |
| 206 | + $cache->set($key, $attempts + 1, 60); |
| 207 | +}); |
| 208 | +``` |
0 commit comments