forked from fa/breadcrumb-the-shire
baseline
This commit is contained in:
717
docs/ARCHITECTURE.md
Normal file
717
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,717 @@
|
||||
# IMVS - Architektur und Grundprinzipien
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
1. [Projektübersicht](#1-projektübersicht)
|
||||
2. [Framework: MintyPHP](#2-framework-mintyphp)
|
||||
3. [Verzeichnisstruktur](#3-verzeichnisstruktur)
|
||||
4. [Datenbankarchitektur](#4-datenbankarchitektur)
|
||||
5. [PHP-Architektur](#5-php-architektur)
|
||||
6. [Frontend-Architektur](#6-frontend-architektur)
|
||||
7. [Template-System](#7-template-system)
|
||||
8. [Authentifizierung und Autorisierung](#8-authentifizierung-und-autorisierung)
|
||||
9. [Internationalisierung](#9-internationalisierung)
|
||||
10. [Best Practices](#10-best-practices)
|
||||
|
||||
---
|
||||
|
||||
## 1. Projektübersicht
|
||||
|
||||
**Projektname:** IMVS
|
||||
**Framework:** MintyPHP v3+
|
||||
**PHP-Version:** 8.5+
|
||||
**Datenbank:** MySQL 5.7+
|
||||
**Lizenz:** MIT
|
||||
|
||||
### Kernfeatures
|
||||
|
||||
- Multi-Tenant-Architektur
|
||||
- Rollen- und Berechtigungssystem
|
||||
- Mehrsprachigkeit (DE/EN)
|
||||
- Dark/Light Theme
|
||||
- E-Mail-Integration mit Templates
|
||||
|
||||
---
|
||||
|
||||
## 2. Framework: MintyPHP
|
||||
|
||||
### Philosophie
|
||||
|
||||
MintyPHP ist ein leichtgewichtiges PHP-Framework mit folgenden Prinzipien:
|
||||
|
||||
- **Easy to learn** - Einfach für PHP-Entwickler zu erlernen
|
||||
- **Secure by design** - Sicherheit als Grundprinzip
|
||||
- **Lightweight** - Minimaler Overhead
|
||||
- **Single variable scope** - Eine Variable-Scope für alle Layer
|
||||
- **SQL required** - Direktes SQL statt ORM
|
||||
- **PHP as templating** - PHP selbst als Template-Sprache
|
||||
|
||||
### Kern-Komponenten
|
||||
|
||||
| Komponente | Beschreibung |
|
||||
|------------|--------------|
|
||||
| `Router` | URL-Routing zu Pages |
|
||||
| `DB` | Datenbankzugriff mit Prepared Statements |
|
||||
| `Auth` | Basis-Authentifizierung |
|
||||
| `Session` | Session-Management |
|
||||
| `Buffer` | Output-Buffering für Templates |
|
||||
| `I18n` | Internationalisierung |
|
||||
| `Cache` | Memcached-Integration |
|
||||
| `Firewall` | DDoS-Schutz |
|
||||
|
||||
### Router-Konvention
|
||||
|
||||
```
|
||||
URL: /admin/users/edit/abc-123
|
||||
Datei: pages/admin/users/edit($id).php
|
||||
Variable: $id = 'abc-123'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Verzeichnisstruktur
|
||||
|
||||
```
|
||||
ImmobilienMaklerVerkaufssoftware/
|
||||
├── config/ # Konfigurationsdateien
|
||||
│ ├── config.php # Hauptkonfiguration
|
||||
│ ├── router.php # Route-Definitionen
|
||||
│ └── settings.php # App-Einstellungen (generiert)
|
||||
├── db/ # Datenbank
|
||||
│ └── init/init.sql # Schema und Seeds
|
||||
├── docker/ # Docker-Konfiguration
|
||||
├── docs/ # Dokumentation
|
||||
├── i18n/ # Sprachdateien
|
||||
│ ├── default_de.json
|
||||
│ └── default_en.json
|
||||
├── lib/ # Geschäftslogik
|
||||
│ ├── Http/ # HTTP-Utilities
|
||||
│ ├── Repository/ # Datenbankschicht
|
||||
│ ├── Service/ # Business-Logic
|
||||
│ └── Support/ # Helper und Guards
|
||||
├── pages/ # Seiten (Controller)
|
||||
│ ├── admin/ # Geschützte Admin-Seiten
|
||||
│ ├── auth/ # Authentifizierung
|
||||
│ ├── error/ # Fehlerseiten
|
||||
│ └── page/ # CMS-Seiten
|
||||
├── storage/ # Dateiablage
|
||||
│ ├── branding/ # Logos, Favicons
|
||||
│ ├── tenants/ # Tenant-Dateien
|
||||
│ └── users/ # User-Avatare
|
||||
├── templates/ # View-Templates
|
||||
│ ├── partials/ # Wiederverwendbare Teile
|
||||
│ └── emails/ # E-Mail-Templates
|
||||
├── tests/ # PHPUnit Tests
|
||||
├── vendor/ # Composer Dependencies
|
||||
└── web/ # Public Root
|
||||
├── css/ # Stylesheets
|
||||
├── js/ # JavaScript-Module
|
||||
├── vendor/ # Frontend-Libraries
|
||||
└── index.php # Entry Point
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Datenbankarchitektur
|
||||
|
||||
### Entity-Relationship-Diagramm
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────────┐ ┌─────────────┐
|
||||
│ USERS │────<│ USER_TENANTS │>────│ TENANTS │
|
||||
└─────────────┘ └─────────────────┘ └─────────────┘
|
||||
│ │
|
||||
│ ┌─────────────────┐ │
|
||||
└────────────<│ USER_ROLES │ │
|
||||
│ └─────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ ROLES │ │
|
||||
│ └─────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────────┐ │
|
||||
│ │ROLE_PERMISSIONS │ │
|
||||
│ └─────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ PERMISSIONS │ │
|
||||
│ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌──────┴──────┐
|
||||
└────────────<│USER_DEPARTMENTS │>────│ DEPARTMENTS │
|
||||
└─────────────────┘ └─────────────┘
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│TENANT_DEPTS │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
### Haupttabellen
|
||||
|
||||
#### users
|
||||
```sql
|
||||
id INT PRIMARY KEY AUTO_INCREMENT
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
first_name VARCHAR(100)
|
||||
last_name VARCHAR(100)
|
||||
email VARCHAR(255) UNIQUE
|
||||
password VARCHAR(255) -- bcrypt hash
|
||||
locale VARCHAR(10) -- 'de', 'en'
|
||||
theme VARCHAR(20) -- 'light', 'dark'
|
||||
active TINYINT DEFAULT 1
|
||||
primary_tenant_id INT FK -> tenants.id
|
||||
current_tenant_id INT FK -> tenants.id
|
||||
created_by INT FK -> users.id
|
||||
modified_by INT FK -> users.id
|
||||
created DATETIME
|
||||
modified DATETIME
|
||||
```
|
||||
|
||||
#### tenants
|
||||
```sql
|
||||
id INT PRIMARY KEY AUTO_INCREMENT
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
description VARCHAR(255) -- Name/Firma
|
||||
address VARCHAR(255)
|
||||
postal_code VARCHAR(20)
|
||||
city VARCHAR(100)
|
||||
country VARCHAR(100)
|
||||
vat_id VARCHAR(50) -- MwSt-ID
|
||||
tax_number VARCHAR(50)
|
||||
phone VARCHAR(50)
|
||||
email VARCHAR(255)
|
||||
website VARCHAR(255)
|
||||
created_by INT FK -> users.id
|
||||
modified_by INT FK -> users.id
|
||||
created DATETIME
|
||||
modified DATETIME
|
||||
```
|
||||
|
||||
#### roles
|
||||
```sql
|
||||
id INT PRIMARY KEY AUTO_INCREMENT
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
description VARCHAR(255) -- Rollenname
|
||||
created_by INT FK -> users.id
|
||||
modified_by INT FK -> users.id
|
||||
created DATETIME
|
||||
modified DATETIME
|
||||
```
|
||||
|
||||
#### permissions
|
||||
```sql
|
||||
id INT PRIMARY KEY AUTO_INCREMENT
|
||||
key VARCHAR(100) UNIQUE -- z.B. 'users.view'
|
||||
description VARCHAR(255)
|
||||
created DATETIME
|
||||
```
|
||||
|
||||
#### departments
|
||||
```sql
|
||||
id INT PRIMARY KEY AUTO_INCREMENT
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
description VARCHAR(255) -- Abteilungsname
|
||||
created_by INT FK -> users.id
|
||||
modified_by INT FK -> users.id
|
||||
created DATETIME
|
||||
modified DATETIME
|
||||
```
|
||||
|
||||
### Verknüpfungstabellen
|
||||
|
||||
| Tabelle | Beschreibung |
|
||||
|---------|--------------|
|
||||
| `user_tenants` | User ↔ Tenant (M:N) |
|
||||
| `user_roles` | User ↔ Role (M:N) |
|
||||
| `user_departments` | User ↔ Department (M:N) |
|
||||
| `role_permissions` | Role ↔ Permission (M:N) |
|
||||
| `tenant_departments` | Tenant ↔ Department (M:N) |
|
||||
|
||||
### Vordefinierte Permissions
|
||||
|
||||
```
|
||||
users.view, users.create, users.update, users.delete
|
||||
users.self_update, users.update_assignments
|
||||
tenants.view, tenants.create, tenants.update, tenants.delete
|
||||
departments.view, departments.create, departments.update, departments.delete
|
||||
roles.view, roles.create, roles.update, roles.delete
|
||||
permissions.view, permissions.create, permissions.update, permissions.delete
|
||||
settings.view, settings.update
|
||||
mail_log.view
|
||||
stats.view
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. PHP-Architektur
|
||||
|
||||
### Schichten-Architektur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Pages │
|
||||
│ (Controller/Actions) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Services │
|
||||
│ (Business Logic, Validation) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Repositories │
|
||||
│ (Data Access, SQL) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ DB │
|
||||
│ (MintyPHP Database) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Service-Layer (`lib/Service/`)
|
||||
|
||||
Services implementieren die Geschäftslogik:
|
||||
|
||||
```php
|
||||
namespace MintyPHP\Service;
|
||||
|
||||
class UserService
|
||||
{
|
||||
// Listen
|
||||
public static function list(): array
|
||||
public static function listPaged(array $options): array
|
||||
|
||||
// Finder
|
||||
public static function findByUuid(string $uuid): ?array
|
||||
public static function findById(int $id): ?array
|
||||
public static function findByEmail(string $email): ?array
|
||||
|
||||
// CRUD
|
||||
public static function createFromAdmin(array $input, int $currentUserId): array
|
||||
public static function updateFromAdmin(int $userId, array $input, int $currentUserId): array
|
||||
public static function deleteByUuid(string $uuid, int $currentUserId): array
|
||||
|
||||
// Bulk-Operationen
|
||||
public static function deleteByUuids(array $uuids, int $currentUserId): array
|
||||
public static function setActiveByUuids(array $uuids, bool $active, int $currentUserId): array
|
||||
}
|
||||
```
|
||||
|
||||
**Wichtige Services:**
|
||||
|
||||
| Service | Verantwortung |
|
||||
|---------|---------------|
|
||||
| `AuthService` | Login, Logout, Session-Management |
|
||||
| `UserService` | Benutzerverwaltung |
|
||||
| `TenantService` | Mandantenverwaltung |
|
||||
| `RoleService` | Rollenverwaltung |
|
||||
| `PermissionService` | Berechtigungsprüfung und -verwaltung |
|
||||
| `DepartmentService` | Abteilungsverwaltung |
|
||||
| `MailService` | E-Mail-Versand |
|
||||
| `SettingService` | App-Einstellungen |
|
||||
|
||||
### Repository-Layer (`lib/Repository/`)
|
||||
|
||||
Repositories kapseln Datenbankzugriffe:
|
||||
|
||||
```php
|
||||
namespace MintyPHP\Repository;
|
||||
|
||||
class UserRepository
|
||||
{
|
||||
public static function list(): array
|
||||
{
|
||||
return DB::select('SELECT * FROM users ORDER BY last_name, first_name');
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
{
|
||||
return DB::selectOne('SELECT * FROM users WHERE id = ?', [$id]);
|
||||
}
|
||||
|
||||
public static function create(array $data): int
|
||||
{
|
||||
return DB::insert('users', $data);
|
||||
}
|
||||
|
||||
public static function update(int $id, array $data): bool
|
||||
{
|
||||
return DB::update('users', $data, ['id' => $id]) > 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Support-Layer (`lib/Support/`)
|
||||
|
||||
#### Guard - Zugriffskontrolle
|
||||
|
||||
```php
|
||||
namespace MintyPHP\Support;
|
||||
|
||||
class Guard
|
||||
{
|
||||
// Nur für angemeldete Benutzer
|
||||
public static function requireLogin(string $redirect = 'login'): void
|
||||
|
||||
// Spezifische Berechtigung erforderlich
|
||||
public static function requirePermission(string $permissionKey, string $redirect = 'admin'): void
|
||||
|
||||
// Berechtigung oder 403 (für AJAX)
|
||||
public static function requirePermissionOrForbidden(string $permissionKey): void
|
||||
}
|
||||
```
|
||||
|
||||
#### Flash - Session-Nachrichten
|
||||
|
||||
```php
|
||||
namespace MintyPHP\Support;
|
||||
|
||||
class Flash
|
||||
{
|
||||
public static function success(string $message, ?string $scope = null, ?string $key = null): string
|
||||
public static function error(string $message, ?string $scope = null, ?string $key = null): string
|
||||
public static function info(string $message, ?string $scope = null, ?string $key = null): string
|
||||
public static function peek(?string $scope = null): array
|
||||
public static function has(): bool
|
||||
}
|
||||
```
|
||||
|
||||
### Helper-Funktionen (`lib/Support/helpers/`)
|
||||
|
||||
```php
|
||||
// HTML-Escape
|
||||
e($string);
|
||||
|
||||
// Asset-URL
|
||||
asset('css/style.css');
|
||||
|
||||
// Lokalisierte URL
|
||||
lurl('admin/users');
|
||||
|
||||
// Übersetzung
|
||||
t('Hello');
|
||||
t('Welcome %s', $name);
|
||||
|
||||
// App-Einstellung
|
||||
appSetting('app_title');
|
||||
|
||||
// Berechtigung prüfen
|
||||
can('users.view');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Frontend-Architektur
|
||||
|
||||
### CSS-Struktur (`web/css/`)
|
||||
|
||||
```
|
||||
web/css/
|
||||
├── base/
|
||||
│ └── variables.css # CSS-Variablen
|
||||
├── layout/
|
||||
│ ├── app-shell.css # Haupt-Layout
|
||||
│ ├── app-topbar.css # Header
|
||||
│ ├── app-sidebar.css # Navigation
|
||||
│ └── app-aside-icon-bar.css
|
||||
├── components/
|
||||
│ ├── app-buttons.css
|
||||
│ ├── app-forms.css
|
||||
│ ├── app-list-table.css
|
||||
│ ├── app-badges.css
|
||||
│ ├── app-tabs.css
|
||||
│ ├── app-flash.css
|
||||
│ └── vendor-*.css # Third-Party
|
||||
└── pages/
|
||||
└── app-login.css
|
||||
```
|
||||
|
||||
### JavaScript-Module (`web/js/`)
|
||||
|
||||
ES-Module-Architektur:
|
||||
|
||||
```
|
||||
web/js/
|
||||
├── app-init.js # Haupt-Initialisierung
|
||||
├── core/
|
||||
│ └── app-grid-factory.js # Grid/Tabellen-Generator
|
||||
├── components/
|
||||
│ ├── app-tenant-switcher.js
|
||||
│ ├── app-theme-toggle.js
|
||||
│ ├── app-bulk-selection.js
|
||||
│ ├── app-flash-auto-dismiss.js
|
||||
│ └── ...
|
||||
└── pages/
|
||||
├── app-users-list.js
|
||||
└── app-list-utils.js
|
||||
```
|
||||
|
||||
### Modul-Pattern
|
||||
|
||||
```javascript
|
||||
// web/js/components/app-tenant-switcher.js
|
||||
const switchTenant = async (link) => {
|
||||
const tenantId = link.dataset.switchTenant;
|
||||
// ...
|
||||
};
|
||||
|
||||
const initTenantSwitcher = () => {
|
||||
const tenantLinks = document.querySelectorAll('[data-switch-tenant]');
|
||||
tenantLinks.forEach(link => {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
switchTenant(link);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Auto-Init bei DOM Ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initTenantSwitcher);
|
||||
} else {
|
||||
initTenantSwitcher();
|
||||
}
|
||||
```
|
||||
|
||||
### Import in app-init.js
|
||||
|
||||
```javascript
|
||||
// web/js/app-init.js
|
||||
import './components/app-tenant-switcher.js';
|
||||
import './components/app-theme-toggle.js';
|
||||
import './components/app-flash-auto-dismiss.js';
|
||||
// ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Template-System
|
||||
|
||||
### Struktur
|
||||
|
||||
```
|
||||
templates/
|
||||
├── default.phtml # Haupt-Layout
|
||||
├── login.phtml # Login-Layout
|
||||
├── error.phtml # Fehler-Layout
|
||||
├── partials/
|
||||
│ ├── app-topbar.phtml
|
||||
│ ├── app-sidebar.phtml
|
||||
│ ├── app-aside.phtml
|
||||
│ ├── app-flash.phtml
|
||||
│ └── app-footer.phtml
|
||||
└── emails/
|
||||
├── de/
|
||||
│ ├── access_info.html
|
||||
│ └── reset_code.html
|
||||
└── en/
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Template-Rendering
|
||||
|
||||
```php
|
||||
<!-- templates/default.phtml -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php e(I18n::$locale); ?>">
|
||||
<head>
|
||||
<title><?php e(Buffer::get('title') ?? appTitle()); ?></title>
|
||||
<link rel="stylesheet" href="<?php e(asset('css/app.css')); ?>">
|
||||
</head>
|
||||
<body>
|
||||
<?php require 'partials/app-topbar.phtml'; ?>
|
||||
|
||||
<main>
|
||||
<?php require 'partials/app-flash.phtml'; ?>
|
||||
<?php echo Buffer::get('html'); ?>
|
||||
</main>
|
||||
|
||||
<script type="module" src="<?php e(asset('js/app-init.js')); ?>"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Page mit View
|
||||
|
||||
```php
|
||||
// pages/admin/users/index().php
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requirePermissionOrForbidden('users.view');
|
||||
|
||||
$users = UserService::list();
|
||||
|
||||
Buffer::set('title', t('Users'));
|
||||
|
||||
// View wird automatisch geladen: pages/admin/users/index(default).phtml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Authentifizierung und Autorisierung
|
||||
|
||||
### Login-Ablauf
|
||||
|
||||
```
|
||||
1. POST /login
|
||||
│
|
||||
├─> AuthService::login(email, password)
|
||||
│ ├─> Auth::login() - Passwort-Verifikation
|
||||
│ ├─> $_SESSION['user'] setzen
|
||||
│ ├─> PermissionService::getUserPermissions()
|
||||
│ │ └─> $_SESSION['permissions'] setzen
|
||||
│ └─> AuthService::loadTenantDataIntoSession()
|
||||
│ ├─> $_SESSION['available_tenants']
|
||||
│ └─> $_SESSION['current_tenant']
|
||||
│
|
||||
└─> Router::redirect('admin')
|
||||
```
|
||||
|
||||
### Berechtigungsprüfung
|
||||
|
||||
```php
|
||||
// In Page
|
||||
Guard::requirePermissionOrForbidden(PermissionService::USERS_VIEW);
|
||||
|
||||
// Im Template
|
||||
<?php if (can('users.create')): ?>
|
||||
<a href="admin/users/create">Neuer Benutzer</a>
|
||||
<?php endif; ?>
|
||||
```
|
||||
|
||||
### Session-Struktur
|
||||
|
||||
```php
|
||||
$_SESSION = [
|
||||
'user' => [
|
||||
'id' => 1,
|
||||
'uuid' => 'abc-123',
|
||||
'email' => 'user@example.com',
|
||||
'first_name' => 'Max',
|
||||
'last_name' => 'Mustermann',
|
||||
'locale' => 'de',
|
||||
'theme' => 'dark',
|
||||
],
|
||||
'permissions' => [
|
||||
'user_id' => 1,
|
||||
'keys' => ['users.view', 'users.create', ...],
|
||||
],
|
||||
'available_tenants' => [
|
||||
['id' => 1, 'uuid' => '...', 'description' => 'Tenant A'],
|
||||
['id' => 2, 'uuid' => '...', 'description' => 'Tenant B'],
|
||||
],
|
||||
'current_tenant' => [
|
||||
'id' => 1,
|
||||
'uuid' => '...',
|
||||
'description' => 'Tenant A',
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Internationalisierung
|
||||
|
||||
### Sprachdateien
|
||||
|
||||
```json
|
||||
// i18n/default_de.json
|
||||
{
|
||||
"Login": "Anmelden",
|
||||
"Users": "Benutzer",
|
||||
"At least %d characters": "Mindestens %d Zeichen"
|
||||
}
|
||||
|
||||
// i18n/default_en.json
|
||||
{
|
||||
"Login": "Login",
|
||||
"Users": "Users",
|
||||
"At least %d characters": "At least %d characters"
|
||||
}
|
||||
```
|
||||
|
||||
### Verwendung
|
||||
|
||||
```php
|
||||
// Einfache Übersetzung
|
||||
t('Login')
|
||||
|
||||
// Mit Parametern
|
||||
t('At least %d characters', 12)
|
||||
|
||||
// Im Template
|
||||
<?php e(t('Users')); ?>
|
||||
```
|
||||
|
||||
### Sprachauflösung
|
||||
|
||||
Priorität:
|
||||
1. URL-Präfix (`/de/admin`, `/en/admin`)
|
||||
2. Session (`$_SESSION['user']['locale']`)
|
||||
3. Cookie (`locale=de`)
|
||||
4. Default (`APP_LOCALE`)
|
||||
|
||||
---
|
||||
|
||||
## 10. Best Practices
|
||||
|
||||
### Service-Rückgabewerte
|
||||
|
||||
```php
|
||||
// Erfolg
|
||||
return [
|
||||
'ok' => true,
|
||||
'uuid' => $uuid,
|
||||
'id' => $id,
|
||||
];
|
||||
|
||||
// Fehler
|
||||
return [
|
||||
'ok' => false,
|
||||
'error' => 'validation_error',
|
||||
'errors' => ['email' => 'Email ist erforderlich'],
|
||||
'form' => $sanitizedInput,
|
||||
];
|
||||
```
|
||||
|
||||
### Datenbankzugriff
|
||||
|
||||
```php
|
||||
// RICHTIG - Prepared Statements
|
||||
$user = DB::selectOne('SELECT * FROM users WHERE email = ?', [$email]);
|
||||
|
||||
// FALSCH - SQL-Injection
|
||||
$user = DB::selectOne("SELECT * FROM users WHERE email = '$email'");
|
||||
```
|
||||
|
||||
### Template-Ausgabe
|
||||
|
||||
```php
|
||||
// RICHTIG - Escape
|
||||
<?php e($user['email']); ?>
|
||||
|
||||
// FALSCH - XSS-Risiko
|
||||
<?php echo $user['email']; ?>
|
||||
```
|
||||
|
||||
### Passwort-Anforderungen
|
||||
|
||||
- Mindestens 12 Zeichen
|
||||
- Mindestens 1 Großbuchstabe
|
||||
- Mindestens 1 Kleinbuchstabe
|
||||
- Mindestens 1 Ziffer
|
||||
- Mindestens 1 Sonderzeichen
|
||||
|
||||
### Code-Organisation
|
||||
|
||||
1. **Services** - Geschäftslogik und Validierung
|
||||
2. **Repositories** - Nur Datenbankzugriff, keine Logik
|
||||
3. **Guards** - Zugriffskontrolle
|
||||
4. **Helpers** - Wiederverwendbare Funktionen
|
||||
5. **Pages** - Koordination, keine Logik
|
||||
|
||||
---
|
||||
|
||||
## Weiterführende Dokumentation
|
||||
|
||||
- [MintyPHP Framework](https://github.com/mevdschee/php-crud-api)
|
||||
- [Docker Setup](../docker-compose.yml)
|
||||
- [Database Schema](../db/init/init.sql)
|
||||
Reference in New Issue
Block a user