Muster aus der Produktion
Konkrete Muster, die in den Produktionsanwendungen von Nibiru verwendet werden – kopierbar und bereit zum Einfügen.
Sieben Muster, die sich wiederholt finden in den Produktionsanwendungen von Nibiru. Jedes ist klein, bereit zum Kopieren und Einfügen und basiert auf einer echten Codebasis.
1. Dünnere Controller → Delegierung an Modul-Plugins
Abschnitt betitelt „1. Dünnere Controller → Delegierung an Modul-Plugins“Behalten Sie die Controller klein. Verschieben Sie die Logik in Modul-Plugins.
// thinclass erpController extends Controller { public function syncAction(): void { View::forwardToJsonHeader(); $result = \Nibiru\Module\Erp\Plugin\Sync::run(); View::assign(['data' => $result]); }}``````php// fatclass Sync extends Erp { public static function run(): array { $svc = AlphaplanSyncService::getInstance(); try { return ['success' => true, 'changes' => $svc->syncAbDocuments()]; } catch (\Throwable $e) { return ['success' => false, 'error' => $e->getMessage()]; } }}Der Controller kann in 5 Sekunden überprüft werden; das Plugin ist testbar.
2. CMS als Inhaltsquelle
Abschnitt betitelt „2. CMS als Inhaltsquelle“Trennen Sie Text und Layout voneinander. Redakteure aktualisieren den Kopf über die Benutzeroberfläche des CMS-Moduls; Vorlagen bleiben Eigentum der Entwickler.
public function pageAction() { $path = $this->getController() . '/' . $this->getRequest('_action', 'page'); foreach (Cms::init($this->getController()) ->loadCmsTemplateTextsByControllerPath($path, $this->language) as $t) { View::assign([ $t['cms_template_texts_text_identifier'] => $t['cms_template_texts_text_content'] ]); }}Vorlagen verweisen auf die Bezeichner, als wären sie normale Variablen:
<h1>{$hero_title}</h1><p>{$hero_intro}</p>3. Beobachtergesteuerte Analyse
Abschnitt betitelt „3. Beobachtergesteuerte Analyse“Mehrere Tracker ohne Controller-Kopplung.
$analytics = new Analytics();$analytics->attach(new Plugin\Matomo());$analytics->attach(new Plugin\Plausible());$analytics->trackPageView(); / calls notify() internallyJeder Beobachter ruft nur die Felder ab, die er interessiert sind. Hinzufügen eines Trackers ist eine Änderung in einer Zeile.
4. Mehrfach-Navigationskomposition
Abschnitt betitelt „4. Mehrfach-Navigationskomposition“Seiten mit mehreren benannten Navigationsarrays anstelle einer einheitlichen Struktur erstellen.
public function navigationAction() { foreach (['head', 'main', 'social', 'footer'] as $name) { JsonNavigation::getInstance()->loadJsonNavigationArray($name); }}``````smarty<header>{include file="navigation.tpl" array=$head}</header><aside>{include file="navigation.tpl" array=$main}</aside><footer>{include file="navigation.tpl" array=$footer}</footer>Jede JSON-Datei ist klein, eingeschränkt, leicht bearbeitbar und ohne Konflikte in Pull Requests.
5. JSON-Endpunkte mit forwardToJsonHeader
Abschnitt betitelt „5. JSON-Endpunkte mit forwardToJsonHeader“Standardvertrag für AJAX:
public function searchAction() { View::forwardToJsonHeader(); $q = trim($_REQUEST['q'] ?? ''); if (strlen($q) < 2) { View::assign(['data' => ['results' => []]]); return; } View::assign(['data' => [ 'results' => MachineryScout::index()->search($q), ]]);}Kopfzeilen werden automatisch gesetzt; keine manuelle header('Content-Type: application/json').
6. Vielschrittiger Workflow über Aktionen
Abschnitt betitelt „6. Vielschrittiger Workflow über Aktionen“Zustandsmaschinen abgebildet auf Controlleraktionen:
class quotesController extends Controller { public function pageAction() { /* list view */ } public function detailAction() { /* one quote */ } public function acceptAction() { /* state transition: open → accepted */ } public function rejectAction() { /* state transition: open → rejected */ } public function archiveAction() { /* state transition: any → archived */ }}/quotes/accept/42 führt acceptAction() mit $_REQUEST['id'] = 42 aus. Jede Übergang ist eine kleine Aktion; Persistenz und Benachrichtigungen erfolgen durch ein QuotesService-Plugin.
7. Schema-first Modelle mit einer benutzerdefinierten Methode pro Absicht
Abschnitt betitelt „7. Schema-first Modelle mit einer benutzerdefinierten Methode pro Absicht“Generieren Sie das Modell aus dem Schema und fügen Sie dann mit Absicht benannte Methoden hinzu, die Ihre Abfragen umschließen:
class users extends Db{ const TABLE = ['table' => 'users', 'field' => [/* … */]]; public function __construct() { self::initTable(self::TABLE); }
public function findByLogin(string $login): ?array { return Pdo::fetchRow('SELECT * FROM users WHERE user_login = :l', [':l' => $login]) ?: null; }
public function activeStandardUsers(): array { return Pdo::fetchAll( 'SELECT * FROM users WHERE user_account_active = 1 AND user_role = :r', [':r' => 'standard'] ); }}Zukünftiges Sie, das den Aufrufort geht, sieht findByLogin($login) – die Absicht – nicht rohe SQL.
Muster zu vermeiden
Abschnitt betitelt „Muster zu vermeiden“- Statische-Puffer-Leckage in Formularen. Verwenden Sie immer
Form::create()vor dem Aufbau. - Logik in
navigationAction(). Sie wird bei jeder Anfrage ausgeführt, einschließlich JSON-Endpunkten. - Massenverwendung von
View::assign()ohne strukturiertes Array. Verwenden SieView::assign(['…'])einmal. - Benutzerdefinierte Routen für was die SEO-URL bereits tut.
/products/<slug>/<id>ist kostenlos. - Bearbeiten generierter Modelle. Sie werden überschrieben. Benutzerdefinierte Methoden → Kindklasse oder
database.overwrite = false.