Initial commit
This commit is contained in:
@@ -0,0 +1,348 @@
|
||||
# AI Agent Development Guide
|
||||
|
||||
**Project:** rte_ckeditor_image - TYPO3 CKEditor 5 Image Extension
|
||||
**Type:** TYPO3 CMS Extension (PHP 8.2+ + JavaScript/ES6)
|
||||
**License:** GPL-2.0-or-later
|
||||
|
||||
## 📋 Documentation Structure
|
||||
|
||||
This project uses a three-tier documentation system:
|
||||
|
||||
- **[claudedocs/](claudedocs/)** - AI session context (Markdown, gitignored, temporary)
|
||||
- **[Documentation/](Documentation/)** - Official TYPO3 docs (RST, published, permanent)
|
||||
- **Root** - Project essentials (README, CONTRIBUTING, SECURITY, LICENSE)
|
||||
|
||||
See **[claudedocs/INDEX.md](claudedocs/INDEX.md)** for AI context navigation and **[Documentation/AGENTS.md](Documentation/AGENTS.md)** for TYPO3 documentation system guide.
|
||||
|
||||
## 🎯 Quick Start
|
||||
|
||||
```bash
|
||||
# First time setup
|
||||
composer install
|
||||
make help # See all available targets
|
||||
|
||||
# Development workflow
|
||||
make lint # Run all linters
|
||||
make format # Fix code style
|
||||
make test # Run tests
|
||||
make ci # Full CI check (pre-commit)
|
||||
|
||||
# Composer shortcuts (if make unavailable)
|
||||
composer ci:test:php:lint # PHP syntax check
|
||||
composer ci:test:php:phpstan # Static analysis
|
||||
composer ci:test:php:cgl # Code style check
|
||||
composer ci:cgl # Fix code style
|
||||
```
|
||||
|
||||
## 🏗️ Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **PHP:** 8.2-8.9 with extensions: dom, libxml
|
||||
- **Composer:** Latest stable
|
||||
- **TYPO3:** 13.4+ (cms-core, cms-backend, cms-frontend, cms-rte-ckeditor)
|
||||
- **direnv:** Optional but recommended
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Clone and install
|
||||
git clone https://github.com/netresearch/t3x-rte_ckeditor_image.git
|
||||
cd t3x-rte_ckeditor_image
|
||||
composer install
|
||||
|
||||
# Enable direnv (optional)
|
||||
direnv allow
|
||||
```
|
||||
|
||||
## 🔧 Build & Test Commands
|
||||
|
||||
### Fast Quality Checks (Pre-commit)
|
||||
|
||||
```bash
|
||||
make lint # PHP lint + PHPStan + style check
|
||||
make format # Auto-fix code style
|
||||
make typecheck # PHPStan static analysis
|
||||
```
|
||||
|
||||
### Full CI Suite
|
||||
|
||||
```bash
|
||||
make ci # Complete CI pipeline
|
||||
make test # All tests (when available)
|
||||
```
|
||||
|
||||
### Individual Commands
|
||||
|
||||
```bash
|
||||
# PHP Linting
|
||||
composer ci:test:php:lint
|
||||
|
||||
# Static Analysis
|
||||
composer ci:test:php:phpstan
|
||||
|
||||
# Code Style Check
|
||||
composer ci:test:php:cgl
|
||||
|
||||
# Code Style Fix
|
||||
composer ci:cgl
|
||||
|
||||
# Rector (PHP Modernization)
|
||||
composer ci:test:php:rector
|
||||
composer ci:rector # Apply changes
|
||||
```
|
||||
|
||||
## 📝 Code Style
|
||||
|
||||
### PHP Standards
|
||||
|
||||
- **Base:** PSR-12 + PER-CS 2.0
|
||||
- **Strict types:** Required in all files (`declare(strict_types=1);`)
|
||||
- **Header comments:** Auto-managed by PHP-CS-Fixer
|
||||
- **Config:** `Build/.php-cs-fixer.dist.php`
|
||||
|
||||
### Key Rules
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of the package netresearch/rte-ckeditor-image.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Netresearch\RteCKEditorImage\Controller;
|
||||
|
||||
// Imports: Classes, constants, functions
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
// Alignment on = and =>
|
||||
$config = [
|
||||
'short' => 'value',
|
||||
'longer' => 'another',
|
||||
];
|
||||
```
|
||||
|
||||
### JavaScript Standards
|
||||
|
||||
- **ES6 modules:** CKEditor 5 plugin format
|
||||
- **No npm tooling:** TYPO3-managed assets
|
||||
- **Style:** Follow CKEditor 5 conventions
|
||||
- **Location:** `Resources/Public/JavaScript/`
|
||||
|
||||
## 🔒 Security
|
||||
|
||||
- **No secrets in VCS:** Use TYPO3's environment configuration
|
||||
- **Dependency scanning:** Renovate enabled (see `renovate.json`)
|
||||
- **Static analysis:** PHPStan with strict rules
|
||||
- **TYPO3 security:** Follow TYPO3 Security Guidelines
|
||||
- **File uploads:** Use FAL (File Abstraction Layer)
|
||||
- **XSS prevention:** All output escaped via Fluid templates
|
||||
|
||||
## ✅ PR/Commit Checklist
|
||||
|
||||
Before committing:
|
||||
|
||||
1. ✅ **Lint passed:** `make lint` or `composer ci:test:php:lint`
|
||||
2. ✅ **Style fixed:** `make format` or `composer ci:cgl`
|
||||
3. ✅ **Static analysis:** `composer ci:test:php:phpstan` (no new errors)
|
||||
4. ✅ **Rector check:** `composer ci:test:php:rector` (no suggestions)
|
||||
5. ✅ **Docs updated:** Update relevant docs/ files if API changed
|
||||
6. ✅ **CHANGELOG:** Add entry if user-facing change
|
||||
7. ✅ **Conventional Commits:** Use format: `type(scope): message`
|
||||
8. ✅ **Small PRs:** Keep ≤300 net LOC changed
|
||||
|
||||
### Commit Format
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer]
|
||||
```
|
||||
|
||||
**Types:** `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
|
||||
**Scopes:** `backend`, `frontend`, `config`, `docs`, `build`
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
feat(backend): add image processing hook for WebP
|
||||
fix(frontend): resolve style drop-down disabled for typo3image
|
||||
docs(api): update DataHandling API reference
|
||||
```
|
||||
|
||||
## 🎓 Good vs Bad Examples
|
||||
|
||||
### ✅ Good: TYPO3 Pattern
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Netresearch\RteCKEditorImage\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
|
||||
final class SelectImageController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ResourceFactory $resourceFactory
|
||||
) {
|
||||
}
|
||||
|
||||
public function infoAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$fileUid = (int)($request->getQueryParams()['fileId'] ?? 0);
|
||||
// Implementation...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ Bad: Missing strict types, no DI
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace Netresearch\RteCKEditorImage\Controller;
|
||||
|
||||
class SelectImageController
|
||||
{
|
||||
public function infoAction($request)
|
||||
{
|
||||
$fileUid = $_GET['fileId']; // Direct superglobal access
|
||||
$factory = new ResourceFactory(); // No DI
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Good: CKEditor 5 Plugin
|
||||
|
||||
```javascript
|
||||
export default class Typo3Image extends Core.Plugin {
|
||||
static get requires() {
|
||||
return ['StyleUtils', 'GeneralHtmlSupport'];
|
||||
}
|
||||
|
||||
init() {
|
||||
const editor = this.editor;
|
||||
this.listenTo(styleUtils, 'isStyleEnabledForBlock', (event, [style]) => {
|
||||
// Event handling...
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ Bad: Missing dependencies
|
||||
|
||||
```javascript
|
||||
class Typo3Image extends Core.Plugin {
|
||||
// Missing requires() - breaks style integration
|
||||
init() {
|
||||
// Implementation...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🆘 When Stuck
|
||||
|
||||
1. **AI Context:** Start with [claudedocs/INDEX.md](claudedocs/INDEX.md) for project navigation
|
||||
2. **Architecture:** Review [claudedocs/ARCHITECTURE.md](claudedocs/ARCHITECTURE.md)
|
||||
3. **Security:** Check [claudedocs/SECURITY.md](claudedocs/SECURITY.md)
|
||||
4. **API Reference:** See [claudedocs/API_REFERENCE.md](claudedocs/API_REFERENCE.md)
|
||||
5. **Development Guide:** Follow [claudedocs/DEVELOPMENT_GUIDE.md](claudedocs/DEVELOPMENT_GUIDE.md)
|
||||
6. **TYPO3 Docs Guide:** Read [Documentation/AGENTS.md](Documentation/AGENTS.md)
|
||||
7. **Published Manual:** https://docs.typo3.org/p/netresearch/rte-ckeditor-image/main/en-us/
|
||||
8. **TYPO3 Core Docs:** https://docs.typo3.org/
|
||||
9. **Issues:** https://github.com/netresearch/t3x-rte_ckeditor_image/issues
|
||||
|
||||
### Common Issues
|
||||
|
||||
- **Style drop-down disabled:** Missing `GeneralHtmlSupport` dependency (v13.0.0+)
|
||||
- **Images not in frontend:** Missing static template include
|
||||
- **PHPStan errors:** Run `composer ci:test:php:phpstan:baseline` to update baseline
|
||||
- **Code style fails:** Run `composer ci:cgl` to auto-fix
|
||||
|
||||
## 📐 House Rules
|
||||
|
||||
### Commits & PRs
|
||||
|
||||
- **Atomic commits:** One logical change per commit
|
||||
- **Conventional Commits:** Required format (see checklist)
|
||||
- **Small PRs:** Target ≤300 net LOC changed
|
||||
- **Branch naming:** `feature/short-description`, `fix/issue-123`
|
||||
|
||||
### Design Principles
|
||||
|
||||
- **SOLID:** Single responsibility, Open/closed, Liskov, Interface segregation, Dependency inversion
|
||||
- **KISS:** Keep it simple, stupid
|
||||
- **DRY:** Don't repeat yourself
|
||||
- **YAGNI:** You aren't gonna need it
|
||||
- **Composition > Inheritance:** Prefer composition
|
||||
- **Law of Demeter:** Minimize coupling
|
||||
|
||||
### Dependencies
|
||||
|
||||
- **Latest stable:** Use current TYPO3 13.4+ versions
|
||||
- **Renovate:** Auto-updates enabled
|
||||
- **Major updates:** Require changelog review + migration notes
|
||||
- **Composer:** Lock file committed
|
||||
|
||||
### API & Versioning
|
||||
|
||||
- **SemVer:** Semantic versioning (MAJOR.MINOR.PATCH)
|
||||
- **TYPO3 compatibility:** Follow TYPO3 versioning
|
||||
- **Breaking changes:** Increment major version
|
||||
- **Deprecations:** Add `@deprecated` tag + removal plan
|
||||
|
||||
### Testing
|
||||
|
||||
- **TYPO3 Testing Framework:** Use `typo3/testing-framework`
|
||||
- **Functional tests:** For database/integration scenarios
|
||||
- **Unit tests:** For isolated logic
|
||||
- **Test location:** `Tests/Functional/`, `Tests/Unit/`
|
||||
|
||||
### Licensing
|
||||
|
||||
- **License:** AGPL-3.0-or-later
|
||||
- **SPDX:** Use SPDX identifiers
|
||||
- **Headers:** Auto-managed by PHP-CS-Fixer
|
||||
- **Third-party:** Document in CHANGELOG
|
||||
|
||||
## 🔗 Related Files
|
||||
|
||||
**Root Documentation:**
|
||||
- **[README.md](README.md)** - Project overview and quick links
|
||||
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - Contribution guidelines
|
||||
- **[SECURITY.md](SECURITY.md)** - Security policy
|
||||
- **[LICENSE](LICENSE)** - GPL-2.0-or-later license
|
||||
|
||||
**AI Session Context (gitignored):**
|
||||
- **[claudedocs/INDEX.md](claudedocs/INDEX.md)** - Navigation hub
|
||||
- **[claudedocs/PROJECT_OVERVIEW.md](claudedocs/PROJECT_OVERVIEW.md)** - Project summary
|
||||
- **[claudedocs/ARCHITECTURE.md](claudedocs/ARCHITECTURE.md)** - System design
|
||||
- **[claudedocs/DEVELOPMENT_GUIDE.md](claudedocs/DEVELOPMENT_GUIDE.md)** - Development workflow
|
||||
- **[claudedocs/API_REFERENCE.md](claudedocs/API_REFERENCE.md)** - PHP API docs
|
||||
- **[claudedocs/SECURITY.md](claudedocs/SECURITY.md)** - Security analysis
|
||||
|
||||
**Official TYPO3 Documentation:**
|
||||
- **[Documentation/](Documentation/)** - RST documentation (published)
|
||||
- **[Documentation/AGENTS.md](Documentation/AGENTS.md)** - TYPO3 docs system guide
|
||||
|
||||
**Configuration:**
|
||||
- **[composer.json](composer.json)** - Dependencies & scripts
|
||||
- **[Build/](Build/)** - Development tools configuration
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- **Repository:** https://github.com/netresearch/t3x-rte_ckeditor_image
|
||||
- **Packagist:** https://packagist.org/packages/netresearch/rte-ckeditor-image
|
||||
- **TYPO3 Ext:** https://extensions.typo3.org/extension/rte_ckeditor_image
|
||||
- **TYPO3 Docs:** https://docs.typo3.org/
|
||||
- **CKEditor 5:** https://ckeditor.com/docs/ckeditor5/
|
||||
@@ -0,0 +1,392 @@
|
||||
# Classes/AGENTS.md
|
||||
|
||||
<!-- Managed by agent: keep sections & order; edit content, not structure. Last updated: 2025-10-15 -->
|
||||
|
||||
**Scope:** PHP backend components (Controllers, EventListeners, DataHandling, Utils)
|
||||
**Parent:** [../AGENTS.md](../AGENTS.md)
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
PHP backend implementation for TYPO3 CKEditor Image extension. Components:
|
||||
|
||||
### Controllers
|
||||
- **SelectImageController** - Image browser wizard, file selection, image info API
|
||||
- **ImageRenderingController** - Image rendering and processing for frontend
|
||||
- **ImageLinkRenderingController** - Link-wrapped image rendering
|
||||
|
||||
### EventListeners
|
||||
- **RteConfigurationListener** - PSR-14 event for RTE configuration injection
|
||||
|
||||
### DataHandling
|
||||
- **RteImagesDbHook** - Database hooks for image magic reference handling
|
||||
- **RteImageSoftReferenceParser** - Soft reference parsing for RTE images
|
||||
|
||||
### Backend Components
|
||||
- **RteImagePreviewRenderer** - Backend preview rendering
|
||||
|
||||
### Utilities
|
||||
- **ProcessedFilesHandler** - File processing and manipulation utilities
|
||||
|
||||
## 🏗️ Architecture Patterns
|
||||
|
||||
### TYPO3 Patterns
|
||||
- **FAL (File Abstraction Layer):** All file operations via ResourceFactory
|
||||
- **PSR-7 Request/Response:** HTTP message interfaces for controllers
|
||||
- **PSR-14 Events:** Event-driven configuration and hooks
|
||||
- **Dependency Injection:** Constructor-based DI (TYPO3 v13+)
|
||||
- **Service Configuration:** `Configuration/Services.yaml` for DI registration
|
||||
|
||||
### File Structure
|
||||
```
|
||||
Classes/
|
||||
├── Backend/
|
||||
│ └── Preview/
|
||||
│ └── RteImagePreviewRenderer.php
|
||||
├── Controller/
|
||||
│ ├── ImageLinkRenderingController.php
|
||||
│ ├── ImageRenderingController.php
|
||||
│ └── SelectImageController.php
|
||||
├── DataHandling/
|
||||
│ └── SoftReference/
|
||||
│ └── RteImageSoftReferenceParser.php
|
||||
├── Database/
|
||||
│ └── RteImagesDbHook.php
|
||||
├── EventListener/
|
||||
│ └── RteConfigurationListener.php
|
||||
└── Utils/
|
||||
└── ProcessedFilesHandler.php
|
||||
```
|
||||
|
||||
## 🔧 Build & Tests
|
||||
|
||||
```bash
|
||||
# PHP-specific quality checks
|
||||
make lint # All linters (syntax + PHPStan + Rector + style)
|
||||
composer ci:test:php:lint # PHP syntax check
|
||||
composer ci:test:php:phpstan # Static analysis
|
||||
composer ci:test:php:rector # Rector modernization check
|
||||
composer ci:test:php:cgl # Code style check
|
||||
|
||||
# Fixes
|
||||
make format # Auto-fix code style
|
||||
composer ci:cgl # Alternative: fix style
|
||||
composer ci:rector # Apply Rector changes
|
||||
|
||||
# Full CI
|
||||
make ci # Complete pipeline
|
||||
```
|
||||
|
||||
## 📝 Code Style
|
||||
|
||||
### Required Patterns
|
||||
|
||||
**1. Strict Types (Always First)**
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
```
|
||||
|
||||
**2. File Header (Auto-managed by PHP-CS-Fixer)**
|
||||
```php
|
||||
/**
|
||||
* This file is part of the package netresearch/rte-ckeditor-image.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
```
|
||||
|
||||
**3. Import Order**
|
||||
- Classes first
|
||||
- Functions second
|
||||
- Constants third
|
||||
- One blank line before namespace
|
||||
|
||||
**4. Type Hints**
|
||||
- All parameters must have type hints
|
||||
- All return types must be declared
|
||||
- Use nullable types `?Type` when appropriate
|
||||
- Use union types `Type1|Type2` for PHP 8+
|
||||
|
||||
**5. Property Types**
|
||||
```php
|
||||
private ResourceFactory $resourceFactory; // Required type declaration
|
||||
private readonly ResourceFactory $factory; // Readonly for immutability
|
||||
```
|
||||
|
||||
**6. Alignment**
|
||||
```php
|
||||
$config = [
|
||||
'short' => 'value', // Align on =>
|
||||
'longer' => 'another',
|
||||
];
|
||||
```
|
||||
|
||||
## 🔒 Security
|
||||
|
||||
### FAL (File Abstraction Layer)
|
||||
- **Always use FAL:** Never direct file system access
|
||||
- **ResourceFactory:** For retrieving files by UID
|
||||
- **File validation:** Check isDeleted(), isMissing()
|
||||
- **ProcessedFile:** Use process() for image manipulation
|
||||
|
||||
```php
|
||||
// ✅ Good: FAL usage
|
||||
$file = $this->resourceFactory->getFileObject($id);
|
||||
if ($file->isDeleted() || $file->isMissing()) {
|
||||
throw new \Exception('File not found');
|
||||
}
|
||||
|
||||
// ❌ Bad: Direct file access
|
||||
$file = file_get_contents('/var/www/uploads/' . $filename);
|
||||
```
|
||||
|
||||
### Input Validation
|
||||
- **Type cast superglobals:** `(int)($request->getQueryParams()['id'] ?? 0)`
|
||||
- **Validate before use:** Check ranges, formats, existence
|
||||
- **Exit on error:** Use HTTP status codes with `HttpUtility::HTTP_STATUS_*`
|
||||
|
||||
### XSS Prevention
|
||||
- **Fluid templates:** Auto-escaping enabled by default
|
||||
- **JSON responses:** Use `JsonResponse` class
|
||||
- **Localization:** Via `LocalizationUtility::translate()`
|
||||
|
||||
## ✅ PR/Commit Checklist
|
||||
|
||||
### PHP-Specific Checks
|
||||
1. ✅ **Strict types:** `declare(strict_types=1);` in all files
|
||||
2. ✅ **Type hints:** All parameters and return types declared
|
||||
3. ✅ **PHPStan:** Zero errors (`composer ci:test:php:phpstan`)
|
||||
4. ✅ **Code style:** PSR-12/PER-CS2.0 compliant (`make format`)
|
||||
5. ✅ **Rector:** No modernization suggestions (`composer ci:test:php:rector`)
|
||||
6. ✅ **FAL usage:** No direct file system access
|
||||
7. ✅ **DI pattern:** Constructor injection, no `new ClassName()`
|
||||
8. ✅ **PSR-7:** Request/Response for controllers
|
||||
9. ✅ **Documentation:** PHPDoc for public methods
|
||||
|
||||
## 🎓 Good vs Bad Examples
|
||||
|
||||
### ✅ Good: Controller Pattern
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Netresearch\RteCKEditorImage\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Http\JsonResponse;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
|
||||
final class SelectImageController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ResourceFactory $resourceFactory
|
||||
) {
|
||||
}
|
||||
|
||||
public function infoAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$fileUid = (int)($request->getQueryParams()['fileId'] ?? 0);
|
||||
|
||||
if ($fileUid <= 0) {
|
||||
return new JsonResponse(['error' => 'Invalid file ID'], 400);
|
||||
}
|
||||
|
||||
$file = $this->resourceFactory->getFileObject($fileUid);
|
||||
|
||||
return new JsonResponse([
|
||||
'uid' => $file->getUid(),
|
||||
'width' => $file->getProperty('width'),
|
||||
'height' => $file->getProperty('height'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ Bad: Anti-patterns
|
||||
|
||||
```php
|
||||
<?php
|
||||
// ❌ Missing strict types
|
||||
namespace Netresearch\RteCKEditorImage\Controller;
|
||||
|
||||
// ❌ Missing PSR-7 types
|
||||
class SelectImageController
|
||||
{
|
||||
// ❌ No constructor DI
|
||||
public function infoAction($request)
|
||||
{
|
||||
// ❌ Direct superglobal access
|
||||
$fileUid = $_GET['fileId'];
|
||||
|
||||
// ❌ No DI - manual instantiation
|
||||
$factory = new ResourceFactory();
|
||||
|
||||
// ❌ No type safety, no validation
|
||||
$file = $factory->getFileObject($fileUid);
|
||||
|
||||
// ❌ Manual JSON encoding
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['uid' => $file->getUid()]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Good: EventListener Pattern
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Netresearch\RteCKEditorImage\EventListener;
|
||||
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\RteCKEditor\Form\Element\Event\AfterPrepareConfigurationForEditorEvent;
|
||||
|
||||
final class RteConfigurationListener
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UriBuilder $uriBuilder
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(AfterPrepareConfigurationForEditorEvent $event): void
|
||||
{
|
||||
$configuration = $event->getConfiguration();
|
||||
$configuration['style']['typo3image'] = [
|
||||
'routeUrl' => (string)$this->uriBuilder->buildUriFromRoute('rteckeditorimage_wizard_select_image'),
|
||||
];
|
||||
$event->setConfiguration($configuration);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ Bad: EventListener Anti-pattern
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace Netresearch\RteCKEditorImage\EventListener;
|
||||
|
||||
class RteConfigurationListener
|
||||
{
|
||||
// ❌ Wrong signature - not invokable
|
||||
public function handle($event)
|
||||
{
|
||||
// ❌ Manual instantiation instead of DI
|
||||
$uriBuilder = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(UriBuilder::class);
|
||||
|
||||
// ❌ Array access without type safety
|
||||
$config = $event->getConfiguration();
|
||||
$config['style']['typo3image']['routeUrl'] = $uriBuilder->buildUriFromRoute('rteckeditorimage_wizard_select_image');
|
||||
$event->setConfiguration($config);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Good: FAL Usage
|
||||
|
||||
```php
|
||||
protected function getImage(int $id): File
|
||||
{
|
||||
try {
|
||||
$file = $this->resourceFactory->getFileObject($id);
|
||||
|
||||
if ($file->isDeleted() || $file->isMissing()) {
|
||||
throw new FileNotFoundException('File not found or deleted', 1234567890);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new FileNotFoundException('Could not load file', 1234567891, $e);
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ Bad: Direct File Access
|
||||
|
||||
```php
|
||||
// ❌ Multiple issues
|
||||
protected function getImage($id) // Missing return type, no type hint
|
||||
{
|
||||
// ❌ Direct file system access, bypassing FAL
|
||||
$path = '/var/www/html/fileadmin/' . $id;
|
||||
|
||||
// ❌ No validation, no error handling
|
||||
if (file_exists($path)) {
|
||||
return file_get_contents($path);
|
||||
}
|
||||
|
||||
return null; // ❌ Should throw exception or return typed null
|
||||
}
|
||||
```
|
||||
|
||||
## 🆘 When Stuck
|
||||
|
||||
### Documentation
|
||||
- **API Reference:** [docs/API/Controllers.md](../docs/API/Controllers.md) - Controller APIs
|
||||
- **Event Listeners:** [docs/API/EventListeners.md](../docs/API/EventListeners.md) - PSR-14 events
|
||||
- **Data Handling:** [docs/API/DataHandling.md](../docs/API/DataHandling.md) - Database hooks
|
||||
- **Architecture:** [docs/Architecture/Overview.md](../docs/Architecture/Overview.md) - System design
|
||||
|
||||
### TYPO3 Resources
|
||||
- **FAL Documentation:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Fal/Index.html
|
||||
- **PSR-14 Events:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Events/Index.html
|
||||
- **Dependency Injection:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/DependencyInjection/Index.html
|
||||
- **Controllers:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Backend/Controllers/Index.html
|
||||
|
||||
### Common Issues
|
||||
- **ResourceFactory errors:** Check file exists, not deleted, proper UID
|
||||
- **DI not working:** Verify `Configuration/Services.yaml` registration
|
||||
- **PHPStan errors:** Update baseline: `composer ci:test:php:phpstan:baseline`
|
||||
- **Type errors:** Enable strict_types, add all type hints
|
||||
|
||||
## 📐 House Rules
|
||||
|
||||
### Controllers
|
||||
- **Extend framework controllers:** ElementBrowserController for browsers
|
||||
- **Final by default:** Use `final class` unless inheritance required
|
||||
- **PSR-7 types:** ServerRequestInterface → ResponseInterface
|
||||
- **JSON responses:** Use `JsonResponse` class
|
||||
- **Validation first:** Validate all input parameters at method start
|
||||
|
||||
### EventListeners
|
||||
- **Invokable:** Use `__invoke()` method signature
|
||||
- **Event type hints:** Type-hint specific event classes
|
||||
- **Immutability aware:** Get, modify, set configuration/state
|
||||
- **Final classes:** Event listeners should be final
|
||||
|
||||
### DataHandling
|
||||
- **Soft references:** Implement soft reference parsing for data integrity
|
||||
- **Database hooks:** Use for maintaining referential integrity
|
||||
- **Transaction safety:** Consider rollback scenarios
|
||||
|
||||
### Dependencies
|
||||
- **Constructor injection:** All dependencies via constructor
|
||||
- **Readonly properties:** Use `readonly` for immutable dependencies
|
||||
- **Interface over implementation:** Depend on interfaces when available
|
||||
- **GeneralUtility::makeInstance:** Only for factories or when DI unavailable
|
||||
|
||||
### Error Handling
|
||||
- **Type-specific exceptions:** Use TYPO3 exception hierarchy
|
||||
- **HTTP status codes:** Via HttpUtility constants
|
||||
- **Meaningful messages:** Include context in exception messages
|
||||
- **Log important errors:** Use TYPO3 logging framework
|
||||
|
||||
### Testing
|
||||
- **Functional tests:** For controllers, database operations
|
||||
- **Unit tests:** For utilities, isolated logic
|
||||
- **Mock FAL:** Use TYPO3 testing framework FAL mocks
|
||||
- **Test location:** `Tests/Functional/` and `Tests/Unit/`
|
||||
|
||||
## 🔗 Related
|
||||
|
||||
- **[Resources/AGENTS.md](../Resources/AGENTS.md)** - JavaScript/CKEditor integration
|
||||
- **[Tests/AGENTS.md](../Tests/AGENTS.md)** - Testing patterns
|
||||
- **[Configuration/Services.yaml](../Configuration/Services.yaml)** - DI container configuration
|
||||
- **[docs/API/](../docs/API/)** - Complete API documentation
|
||||
Reference in New Issue
Block a user