Zum Inhalt springen
Nibiru docsv0.9.2

Muster aus der Produktion

Konkrete Muster, die in den Produktionsanwendungen von Nibiru verwendet werden – kopierbar und bereit zum Einfügen.

Stable Reading time ~ 3 min Edit on GitHub

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.

// thin
class erpController extends Controller {
public function syncAction(): void {
View::forwardToJsonHeader();
$result = \Nibiru\Module\Erp\Plugin\Sync::run();
View::assign(['data' => $result]);
}
}
``````php
// fat
class 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.

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>

Mehrere Tracker ohne Controller-Kopplung.

$analytics = new Analytics();
$analytics->attach(new Plugin\Matomo());
$analytics->attach(new Plugin\Plausible());
$analytics->trackPageView(); / calls notify() internally

Jeder Beobachter ruft nur die Felder ab, die er interessiert sind. Hinzufügen eines Trackers ist eine Änderung in einer Zeile.

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.

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').

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.

  • 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 Sie View::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.