Sweep: link fixes, splash i18n parity, neuronetz badge, mobile, training source

LINK AUDIT — every internal link now resolves to a real page:
  - BrandHeader doc-nav 'Showcase' target → /{locale}/showcase/projects/
    (the showcase/ directory has no index, only patterns/projects)
  - Translated-slug bugs across de/es/fr/ja: ~30 broken links from the
    overnight translator that auto-localised path segments. Mapped back to
    the actual English slugs:
      de:  warum-nibiru → why-nibiru, kuenstliche-intelligenz/orakel → ai/oracle,
           kI/modul/* → ai/module/*, praesentation/projekte → showcase/projects
      es:  ai/modulo/* → ai/module/*, diseno/* → design/*,
           porque-nibiru / por-que-nibiru → why-nibiru,
           presentacion/proyectos → showcase/projects
      fr:  ia/module/* → ai/module/*, ia/module/formation → ai/module/training,
           pourquoi-nibiru → why-nibiru, presentation/projets → showcase/projects
      ja:  ai/milestones → ai/roadmap
  - Cross-locale leaks: bare `/ai/oracle` (no locale) → `/{locale}/ai/oracle/`
    in de/index.mdx, fr/index.mdx, fr/ai/module/overview.md, en/ai/corpus.md
  - `/en/start/` (which 404s — start/ has no index) was hardcoded in five
    design/components.md atelier-button hrefs across all locales →
    `/{locale}/start/installation/`
  - `/en/reference` removed from en/downloads.mdx — the reference doc tree
    isn't built yet; replaced with a github link to the v2 markdown source
  - Collapsed stray double-slashes (`/de/why-nibiru//` etc.) introduced by
    the slug-replacement sed sweep

Final audit shows 0 broken internal links (down from ~37).

TRAINING SOURCE NOW SHIPS — root cause of "I cannot find the training data
in the repository": the curated source files were gitignored.
  - .gitignore at scripts/extraction/ now whitelists framework-reference-v2.md
    and lora-augmentation.summary.txt alongside lora-augmentation.jsonl
  - The 1620-line v2 reference, the 323-record augmentation jsonl, and the
    summary report all enter the repo so the production Docker build sees
    them and contributors can find them by browsing gitea

NEURONETZ AI DEEPLINK BADGE — small "AI by Neuronetz ↗" pill in the splash
footer's bottom strip. Logo mark mirrored locally to
public/img/external/neuronetz-mark.svg (pulled from neuronetz.ai/favicon.svg)
so the page doesn't hot-link off-domain on every paint. Magenta border on
hover; opens neuronetz.ai in a new tab with rel=noopener.

SPLASH I18N PARITY — de/es/fr/ja index.mdx now import + render the same
component stack as en (CometTrail · MmvcStage · MissionControl · LaunchSequence
· SpacecraftGrid · EditorialContent · LandingFooter · ToTop · LandingScripts),
so every locale shows the full splash structure. The component bodies
themselves are still English (proper i18n is the next step); for now this
brings structural parity.

MOBILE RESPONSIVE SWEEP:
  - LandingFooter: 4-col grid stacks 2-col @ 768px and 1-col @ 480px;
    bottom strip wraps vertical at 480px
  - MmvcStage: 5-step progress rail tightens its gaps under 720px and
    drops the bar segments entirely under 480px so the labels fit
  - Docs bridge §11: tighter H1/H2 spacing, breadcrumbs/doc-meta on
    narrow viewports, pagination cards stack 1-col, help-strip stacks
    vertical, tables get horizontal-scroll on overflow
  - Doc-header: nav-version chip hides under 480px so the search-pill
    + brand fit comfortably

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
stephan
2026-05-08 19:36:25 +02:00
parent 22392161ba
commit f8f58c4ab9
105 changed files with 2394 additions and 729 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" fill="#f4f2ed"/>
<circle cx="16" cy="16" r="6" fill="#8b2b1f"/>
</svg>

After

Width:  |  Height:  |  Size: 165 B

View File

@@ -1,9 +1,13 @@
# Extraction outputs from research-agent runs are typically large + transient.
# Keep them local by default — except the curated augmentation file which
# needs to ship for the Docker build to fold it into the LoRA corpus.
# Keep them local by default — except the curated files that need to ship so
# the Docker build can fold them into the LoRA corpus AND so contributors
# can find the source-of-truth reference in the repo.
*.md
*.json
*.jsonl
*.txt
# …with one explicit exception:
# …with explicit exceptions:
!framework-reference-v2.md
!lora-augmentation.jsonl
!lora-augmentation.summary.txt

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
Nibiru Framework — LoRA Augmentation Corpus Summary
=====================================================
Source: /home/stephan/PhpstormProjects/Nibiru/docs/scripts/extraction/framework-reference-v2.md
Output: /home/stephan/PhpstormProjects/Nibiru/docs/scripts/extraction/lora-augmentation.jsonl
Format: JSONL (one record per line)
Records: 323
Validation
----------
All 323 lines are valid JSON. All records carry the required keys:
instruction, input, output, metadata.{language, source, section, kind, citations}.
(Verified with `jq` schema check — 0 records failed.)
Breakdown by `kind`
-------------------
code-recall 121
workflow 97
inikey 29
comparison 26
gotcha 16
debug 16
edge-case 15
refactor 3
Coverage
--------
All 14 top-level sections of the v2 reference are exercised:
- §0 Executive Summary
- §1 Namespace Map
- §2 Singletons & Factories (Config, Pdo, Db, Form, Controller, View)
- §3 Database Layer (drivers, autogenerator pipeline, multi-database)
- §4 Module System (structure, registry, loading flow, plugin pattern, lifecycle)
- §5 Form System (architecture, substitution, type classes, ordering, div wrap, assembly, production usage)
- §6 Request/Response Lifecycle
- §7 INI Key Reference
- §8 Namespace Conventions
- §9 Constants
- §10 Production Patterns NOT in Core
- §11 Gotchas & Footguns
- §12 Request Handling Trace
- Appendices: File Index, Quick Reference
Cross-section workflow / debug / refactor records (~30) cover full-stack scenarios:
adding a new module, adding a new table, switching DB sections per model,
debugging Postgres-mode mask footgun, end-to-end form-to-DB save flow, etc.
Sample records (3 for sanity-check)
-----------------------------------
Sample 1 (kind=code-recall, line 14):
{"instruction":"Show me the exact `__construct()` body the autogenerator produces for a MySQL model.","input":"","output":"```php\npublic function __construct()\n{\n Pdo::settingsSection('DATABASE');\n self::initTable( self::TABLE );\n}\n```\nFrom `loach.mssql.database-connection/application/model/WarehouseLoach/timeanddate.php:30-34`. The first line writes the static `Pdo::$section`; the second registers the table schema with the adapter's static `$table` array.","metadata":{"language":"en","source":"framework-reference-v2","section":"2.2 Pdo","kind":"code-recall","citations":["loach.mssql.database-connection/application/model/WarehouseLoach/timeanddate.php:30-34","framework-reference-v2.md §2.2"]}}
Sample 2 (kind=inikey, line 100):
{"instruction":"Which INI key sets the PHP timezone?","input":"","output":"`[SETTINGS][timezone]`. Read by `Dispatcher::run()`. Defaults to `UTC`. From `framework-reference-v2.md §7 [SETTINGS]`.","metadata":{"language":"en","source":"framework-reference-v2","section":"7 INI [SETTINGS]","kind":"inikey","citations":["framework-reference-v2.md §7"]}}
Sample 3 (kind=workflow, line 220):
{"instruction":"How does the autogenerator handle a brand-new application with zero existing model files?","input":"","output":"`Model::createOutFolder()` at `core/c/model.php:28` does `mkdir -p` (chmod 0777) for the target folder, then `createClassFiles()` at line 37 loops through scanned tables (or one table if `--table=` was passed) and calls `generateClassByTableName($table)` for each. For each class file:\n1. If overwrite mode, `unlink` existing.\n2. Otherwise `fopen('w'); fclose()` to create an empty stub.\n3. Build template, do all 8 placeholder substitutions plus driver/odbc switching.\n4. Write file and chmod 0777.\n\nSo zero existing files becomes a full set of generated models on the first request. From `framework-reference-v2.md §3.2`.","metadata":{"language":"en","source":"framework-reference-v2","section":"3.2 Autogenerator Pipeline","kind":"workflow","citations":["core/c/model.php:28","core/c/model.php:37","core/c/model.php:53","framework-reference-v2.md §3.2"]}}
Notes for downstream merge
--------------------------
- Every record has a real file:line citation OR a quoted code block.
- Code blocks are quoted from the v2 reference; nothing is invented.
- Phrasing varies across natural developer styles ("Walk me through…",
"Quick question:…", "Why does…", "I'm trying to…", "Show me…",
"I'm getting `Class … not found`…", etc.).
- The `kind` taxonomy follows the spec: edge-case, comparison, workflow,
debug, refactor, code-recall, inikey, gotcha.

View File

@@ -33,7 +33,7 @@ const docNav: Array<{ label: string; href: string; current?: boolean }> = [
{ label: 'MMVC', href: `/${currentLocale}/core/architecture/` },
{ label: 'AI module',href: `/${currentLocale}/ai/module/overview/` },
{ label: 'CLI', href: `/${currentLocale}/start/quick-start/` },
{ label: 'Showcase', href: `/${currentLocale}/showcase/` },
{ label: 'Showcase', href: `/${currentLocale}/showcase/projects/` },
];
---

View File

@@ -50,6 +50,12 @@
</div>
<div class="container footer-bottom">
<span>© 2026 Nibiru · MIT licensed</span>
<a class="powered-by" href="https://neuronetz.ai/" target="_blank" rel="noopener" aria-label="Powered by Neuronetz AI — opens neuronetz.ai">
<img src="/img/external/neuronetz-mark.svg" alt="" width="18" height="18" loading="lazy" />
<span class="powered-by-label">AI by</span>
<span class="powered-by-name">Neuronetz</span>
<span class="powered-by-arrow" aria-hidden="true">↗</span>
</a>
<span>Built in orbit · v0.9.2</span>
</div>
</footer>
@@ -85,7 +91,18 @@
padding: 0 32px;
}
@media (max-width: 768px) {
.footer-inner { grid-template-columns: 1fr 1fr; }
.footer-inner { grid-template-columns: 1fr 1fr; gap: 32px; }
.footer { padding: 60px 0 40px; }
}
@media (max-width: 480px) {
.footer-inner { grid-template-columns: 1fr; gap: 28px; padding: 0 20px; }
.footer-bottom {
flex-direction: column;
align-items: flex-start;
gap: 14px;
padding: 24px 20px 0;
margin-top: 48px;
}
}
.footer-brand .brand {
margin-bottom: 16px;
@@ -150,5 +167,55 @@
flex-wrap: wrap;
gap: 12px;
}
/* "AI by Neuronetz" badge — small, deliberately understated.
The mark is the same favicon-tier asset neuronetz.ai exposes; we mirror
it locally at /img/external/neuronetz-mark.svg so the page doesn't
hot-link off-domain on every paint. */
.powered-by {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 10px 4px 6px;
background: rgba(184, 107, 255, 0.06);
border: 1px solid var(--nibiru-line);
border-radius: 999px;
color: rgba(244, 238, 219, 0.78);
text-decoration: none;
font-family: var(--font-mono);
font-size: 10px;
letter-spacing: 0.10em;
text-transform: uppercase;
transition: border-color 200ms ease, color 200ms ease, background-color 200ms ease;
}
.powered-by:hover {
border-color: var(--nibiru-nebula-mag, #b86bff);
color: var(--nibiru-star);
background: rgba(184, 107, 255, 0.12);
}
.powered-by img {
border-radius: 50%;
background: #f4f2ed;
padding: 1px;
flex: none;
}
.powered-by-label { color: var(--nibiru-muted); }
.powered-by-name {
color: var(--nibiru-star);
font-weight: 500;
text-transform: none;
letter-spacing: -0.01em;
font-size: 11px;
font-family: var(--nibiru-font-display, 'Space Grotesk', sans-serif);
}
.powered-by-arrow {
font-size: 9px;
color: var(--nibiru-muted);
transition: transform 200ms ease, color 200ms ease;
}
.powered-by:hover .powered-by-arrow {
transform: translate(1px, -1px);
color: var(--nibiru-nebula-mag, #b86bff);
}
</style>

View File

@@ -205,10 +205,23 @@
}
@media (max-width: 720px) {
.mmvc-progress { gap: 4px; font-size: 9px; padding: 0 8px; }
.mmvc-progress .step { gap: 4px; padding-right: 4px; }
.mmvc-progress .step .bar { width: 14px; }
.mmvc-progress .step.active .bar { width: 24px; }
.mmvc-progress { gap: 3px; font-size: 9px; padding: 0 6px; }
.mmvc-progress .step { gap: 3px; padding-right: 3px; }
.mmvc-progress .step .bar { width: 10px; }
.mmvc-progress .step.active .bar { width: 18px; }
}
/* Below 480px the 5-step rail starts colliding with the panel headline.
Drop the bar segments entirely and keep only the labels at minimum size. */
@media (max-width: 480px) {
.mmvc-progress { font-size: 8px; gap: 6px; padding: 0 4px; }
.mmvc-progress .step .bar { display: none; }
.mmvc-progress .step { padding-right: 0; gap: 0; }
.mmvc-copy { padding: 0 16px; }
.mmvc-copy h3 { font-size: clamp(28px, 9vw, 44px); }
.mmvc-copy p { font-size: 15px; }
.mmvc-copy .step-num { font-size: 10px; margin-bottom: 16px; }
.mmvc-copy .step-num::before, .mmvc-copy .step-num::after { width: 16px; }
}
@media (max-width: 960px) {

View File

@@ -60,7 +60,7 @@ Rohdaten für die Verwendung als RAG-Retrieval-Daten:
"content": "Modules implementing `SplSubject` can broadcast events…"
}
```
Dies ist genau die Datei, die intern von [Oracle](/ai/oracle/) verwendet wird.
Dies ist genau die Datei, die intern von [Oracle](/de/ai/oracle/) verwendet wird.
## Wie Chunks abgeleitet werden

View File

@@ -10,19 +10,19 @@ Das Chat-Plugin ist das einfachste Element des KI-Moduls. Es umhüllt Ollamas `/
$ai = new \Nibiru\Module\Ai\Ai();
$chat = $ai->chat();
$chat->system('Be terse.'); // optional system prompt
$chat->model('qwen2.5-coder:14b'); // override the configured model
$chat->temperature(0.2); // override config
$chat->maxTokens(512); // override config
$chat->system('Be terse.'); / optional system prompt
$chat->model('qwen2.5-coder:14b'); / override the configured model
$chat->temperature(0.2); / override config
$chat->maxTokens(512); / override config
$chat->user('Hello'); // append a user message
$chat->assistant('Hi.'); // append an assistant message (rare)
$chat->user('Hello'); / append a user message
$chat->assistant('Hi.'); / append an assistant message (rare)
$reply = $chat->complete(); // run the call, return text
$reply = $chat->ask('How are you?'); // = ->user(...)->complete()
$reply = $chat->complete(); / run the call, return text
$reply = $chat->ask('How are you?'); / = ->user(...)->complete()
$chat->reset(); // clear messages, keep model + system
$chat->history(); // [{role, content}, …]
$chat->reset(); / clear messages, keep model + system
$chat->history(); / [{role, content}, ]
```
## Einmalig
```php
@@ -35,10 +35,10 @@ echo (new \Nibiru\Module\Ai\Ai())
$chat = $ai->chat();
$chat->user('Name three Nibiru singletons.');
$singletons = $chat->complete(); // appended to history
$singletons = $chat->complete(); / appended to history
$chat->user('What does the second one do?');
$detail = $chat->complete(); // model has full context
$detail = $chat->complete(); / model has full context
```
## Überschreiben des Modells und des Stils pro Aufruf
```php

View File

@@ -9,12 +9,12 @@ Das Embed-Plugin ist ein dünner Wrapper um Ollama's `/api/embeddings` plus drei
```php
$embed = (new \Nibiru\Module\Ai\Ai())->embed();
$vec = $embed->one('controller'); // float[]
$vectors = $embed->batch(['a', 'b', 'c']); // float[][]
$vec = $embed->one('controller'); / float[]
$vectors = $embed->batch(['a', 'b', 'c']); / float[][]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); // 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); // back to float[]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); / 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); / back to float[]
```
## Muster: Entfernen ähnlicher Zeichenfolgen
```php
@@ -49,8 +49,8 @@ function bestTag(string $text, array $tagVecs, $embed): string {
return $best[0];
}
echo bestTag('User::isAuthorized', $tagVecs, $embed); // → 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); // → 'database' (probably)
echo bestTag('User::isAuthorized', $tagVecs, $embed); / 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); / 'database' (probably)
```
## Speicherung
@@ -58,7 +58,7 @@ Einbettungen sind Gleitkommazahlenarrays typischerweise 768 Gleitkommazahlen
Verwenden Sie `Embed::pack()`, um sie als 4-Byte-Gleitkommazahlen in Base64 zu kodieren:
```php
$compact = Embed::pack($vec); // ~4 KB → ~5.3 KB base64 string
$compact = Embed::pack($vec); / ~4 KB ~5.3 KB base64 string
$vec = Embed::unpack($compact);
```
Das RAG-Plugin verwendet dieses Format intern für seine JSON-Dateien.

View File

@@ -5,7 +5,7 @@ description: "Erster-Klasse KI auf Nibiru Chat, Embeddings, RAG, Agenten
Nibiru bietet ein **KIM-Modul** (`application/module/ai/`), das jeder Nibiru-Anwendung eine erstklassige KI-Oberfläche gibt. PHP-Code kann mit einem lokalen LLM chatten, Text einbetten, RAG über eigene Daten ausführen oder einen Agenten mit Tools starten alles ohne einen Byte an eine bezahlte API zu senden.
Das Modul ist standardmäßig mit Ihrem eigenen [Ollama auf Ihrer Ollama-Instanz](/de/kuenstliche-intelligenz/orakel/) verbunden, sodass die Inferenz auf Ihrer Hardware, in Ihrem Netzwerk und Ihren Bedingungen erfolgt.
Das Modul ist standardmäßig mit Ihrem eigenen [Ollama auf Ihrer Ollama-Instanz](/de/ai/oracle/) verbunden, sodass die Inferenz auf Ihrer Hardware, in Ihrem Netzwerk und Ihren Bedingungen erfolgt.
## Was Sie erhalten
@@ -57,7 +57,7 @@ echo $ai->chat()->ask('Explain MMVC in two sentences.');
// Multi-turn
$chat = $ai->chat();
$chat->user('How do I scaffold a module?');
$chat->user('And add Graylog hooks?'); // referrs to previous turn
$chat->user('And add Graylog hooks?'); / referrs to previous turn
echo $chat->complete();
// Override per call
@@ -80,7 +80,7 @@ $score = \Nibiru\Module\Ai\Plugin\Embed::cosine($va, $vb);
```
Kompakte Speicherung:
```php
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string, 4 bytes/dim
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string, 4 bytes/dim
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
```
### 3. RAG — Ingestieren, Abrufen, Verankern
@@ -88,7 +88,7 @@ $vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
$rag = $ai->rag('product-help');
// One-time ingestion
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
$rag->ingestFile('/var/data/manual.pdf.txt');
@@ -105,9 +105,9 @@ use Nibiru\Module\Ai\Plugin\Tools;
$ai = new \Nibiru\Module\Ai\Ai();
$agent = $ai->agent()->withTools([
new Tools\PdoQuery(), // read-only SQL
new Tools\HttpGet(), // fetch URLs
new Tools\FileRead(), // read project files
new Tools\PdoQuery(), / read-only SQL
new Tools\HttpGet(), / fetch URLs
new Tools\FileRead(), / read project files
]);
echo $agent->run('How many active users registered last week?');
@@ -154,7 +154,7 @@ Die Gestaltungsentfernung:
## Nächste
- [Chat-Plugin-Referenz](/de/kI/modul/chat/)
- [RAG-Plugin-Referenz](/de/kI/modul/rag/)
- [Agent-Plugin-Referenz](/de/kI/modul/agent/)
- [Training nibiru-coder](/de/kI/modul/training/)
- [Chat-Plugin-Referenz](/de/ai/module/chat/)
- [RAG-Plugin-Referenz](/de/ai/module/rag/)
- [Agent-Plugin-Referenz](/de/ai/module/agent/)
- [Training nibiru-coder](/de/ai/module/training/)

View File

@@ -10,9 +10,9 @@ Das RAG-Plugin ist die Killerfunktion des KI-Moduls für Produktbauer. Es verwan
use Nibiru\Module\Ai\Ai;
$ai = new Ai();
$rag = $ai->rag('product-help'); // a named collection
$rag = $ai->rag('product-help'); / a named collection
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php under help/
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php under help/
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
echo $rag->ask('How do I cancel my subscription?');
@@ -46,20 +46,20 @@ $logs->ingestText($exception->__toString(), ['ts' => time()]);
```
## API-Referenz
```php
$rag = $ai->rag('name'); // get/create a named collection
$rag = $ai->rag('name'); / get/create a named collection
// --- Ingestion ---
$rag->ingestText($text, $metadata = []); // single chunk
$count = $rag->ingestFile('path'); // returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); // recursive
$rag->ingestText($text, $metadata = []); / single chunk
$count = $rag->ingestFile('path'); / returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); / recursive
// --- Querying ---
$hits = $rag->search('query', $k = null); // [{score, text, metadata}, …]
$answer = $rag->ask('question', $k = null); // top-K → chat call
$hits = $rag->search('query', $k = null); / [{score, text, metadata}, ]
$answer = $rag->ask('question', $k = null); / top-K chat call
// --- Maintenance ---
$rag->reset(); // forget everything (deletes file)
$n = $rag->size(); // number of chunks
$rag->reset(); / forget everything (deletes file)
$n = $rag->size(); / number of chunks
```
## Einstellungsregler
@@ -95,5 +95,5 @@ rag.storage_path = "/../../application/module/ai/cache/rag/"
## Was kommt als nächstes?
- [Agent-Plugin →](/de/kI/modul/agent/) für Werkzeuge, nicht für Abruf.
- [Trainingsnibiru-coder →](/de/kI/modul/trainings/) um den Chat so zu gestalten, dass er halb in der Stimme des Frameworks antwortet.
- [Agent-Plugin →](/de/ai/module/agent/) für Werkzeuge, nicht für Abruf.
- [Trainingsnibiru-coder →](/de/ai/module/training/) um den Chat so zu gestalten, dass er halb in der Stimme des Frameworks antwortet.

View File

@@ -114,7 +114,7 @@ public function pageAction() {
View::forwardTo('/login');
return;
}
// ...
/ ...
}
```
Für rollebasierte Überprüfungen verwenden die Showcase-Anwendungen den `Acl`-Plugin aus dem gleichen Modul:
@@ -178,7 +178,7 @@ public function submitAction() {
http_response_code(419);
return;
}
// ...handle submission...
/ ...handle submission...
}
```
Fügen Sie `<input type="hidden" name="csrf" value="{$csrf}">` in Ihr Formular ein.

View File

@@ -82,19 +82,19 @@ password_hash = "another-salt-for-AES_DECRYPT"
## Konfiguration lesen
```php
$cfg = \Nibiru\Config::getInstance()->getConfig();
$cfg['DATABASE']['driver']; // 'pdo'
$cfg['SETTINGS']['page.url']; // 'https://my-app.local'
$cfg['DATABASE']['driver']; / 'pdo'
$cfg['SETTINGS']['page.url']; / 'https://my-app.local'
```
Verwenden Sie für tief geschachtelte Konfigurationen die typisierten Konstanten aus der View-Schnittstelle:
```php
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; // ['/public/css/app.css']
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; / ['/public/css/app.css']
```
## Modulkonfigurationen
Jeder Modul unter `application/module/<name>/settings/` kann seine eigenen INI-Dateien haben. Der Registrierungsservice erkennt sie automatisch und macht sie über verfügbar:
```php
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime; // from [USERS] section in users.ini
$users->session_lifetime; / from [USERS] section in users.ini
```
Der Registrierung wird `<module>.<env>.ini` vor `<module>.ini` bevorzugt, sodass Sie automatisch Überschreibungen pro Umgebung erhalten.

View File

@@ -56,12 +56,12 @@ View::assign(['products' => $list]);
```
Hilfsfunktionen aus dem Basiscontroller:
```php
$this->getRequest('id', false); // $_REQUEST['id'] ?? false
$this->getPost('email', ''); // $_POST['email'] ?? ''
$this->getGet('page', 1); // $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); // $_SERVER['REQUEST_URI']
$this->getFiles('upload'); // $_FILES['upload']
$this->getSession('auth'); // $_SESSION['auth']
$this->getRequest('id', false); / $_REQUEST['id'] ?? false
$this->getPost('email', ''); / $_POST['email'] ?? ''
$this->getGet('page', 1); / $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); / $_SERVER['REQUEST_URI']
$this->getFiles('upload'); / $_FILES['upload']
$this->getSession('auth'); / $_SESSION['auth']
```
Diese bestehen, weil `Controller` `final`-freundlich ist: Sie können sie in Tests durch eine untergeordnete Klasse ersetzen.
@@ -69,8 +69,8 @@ Diese bestehen, weil `Controller` `final`-freundlich ist: Sie können sie in Tes
Um innerhalb einer Aktion umzuleiten:
```php
View::forwardTo('/login'); // 302 to the URL, exits
View::forwardToJsonHeader(); // sets Content-Type: application/json
View::forwardTo('/login'); / 302 to the URL, exits
View::forwardToJsonHeader(); / sets Content-Type: application/json
```
`forwardToJsonHeader()` ist das kanonische Muster für JSON-Endpunkte setzen Sie den Header, weisen Sie `data` zu und geben Sie zurück. Der Anzeigebereich kümmert sich danach um die Reste.

View File

@@ -30,17 +30,17 @@ public function run() {
if (Config::getInstance()->getConfig()
[self::CONFIG_GENERATOR_SECTION][self::GENERATOR_DATABASE]) {
new Model(false); // 1. (re)generate models from schema
new Model(false); / 1. (re)generate models from schema
}
Router::getInstance()->route(); // 2. parse the URL
Auto::loader()->loadModelFiles(); // 3. load model files
Auto::loader()->loadModules(); // 4. load module classes
Router::getInstance()->route(); / 2. parse the URL
Auto::loader()->loadModelFiles(); / 3. load model files
Auto::loader()->loadModules(); / 4. load module classes
$tpl = Router::getInstance()->tplName();
$controllerFile = __DIR__ . "/../../application/controller/{$tpl}Controller.php";
if (is_file($controllerFile)) { // 5. controller file exists
if (is_file($controllerFile)) { / 5. controller file exists
require_once $controllerFile;
$class = "Nibiru\\{$tpl}Controller";
$controller = new $class();
@@ -49,7 +49,7 @@ public function run() {
$action = $_REQUEST['_action'] . 'Action';
$controller->navigationAction();
if (method_exists($controller, $action)) {
$controller->$action(); // 6. optional named action
$controller->$action(); / 6. optional named action
}
$controller->pageAction();
} else {
@@ -57,9 +57,9 @@ public function run() {
$controller->pageAction();
}
Display::getInstance()->display(); // 7. render Smarty
Display::getInstance()->display(); / 7. render Smarty
} else {
// 8. soft 404 — render the configured error controller
/ 8. soft 404 render the configured error controller
}
}
```

View File

@@ -40,8 +40,8 @@ addOpenSpan addCloseSpan
```
### Lebenszyklus
```
create // reset the static buffer; call before building a new form
addForm // wrap the buffer in <form>...</form> and return as a string
create / reset the static buffer; call before building a new form
addForm / wrap the buffer in <form>...</form> and return as a string
```
:::caution[Die Namensinconsistenz ist absichtlich, zumindest teilweise]
`addInputTypePassword` vs `addTypePassword`, `addInputTypeFileupload` vs `addTypeFileUpload` — das Präfix entspricht, ob das Element ein `<input type="…">` (Input-Prefix) oder ein anderer Tag (Type-Prefix) ist. Es ist unangenehm, aber stabil; die CLI-`./nibiru -c`-Scaffolds verwenden dasselbe Muster, sodass die Muskelspeicherung funktioniert.
@@ -51,7 +51,7 @@ addForm // wrap the buffer in <form>...</form> and return as a string
```php
use Nibiru\Factory\Form;
Form::create(); // reset the static buffer
Form::create(); / reset the static buffer
Form::addOpenDiv(['class' => 'form-group']);
Form::addTypeLabel(['for' => 'login', 'value' => 'Username']);
@@ -187,7 +187,7 @@ class formsController extends Controller {
'required' => 'required',
'class' => 'contacts-input form-control',
]);
// ...more fields...
/ ...more fields...
$this->form = Form::addForm([
'name' => 'newregister',
'method' => 'post',

View File

@@ -147,9 +147,9 @@ allowed.roles[] = "standard"
Lesen Sie es von überall aus:
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$cfg->session_lifetime; // 7200
$cfg->password_min_length; // 12
$cfg->allowed_roles; // [admin, editor, standard]
$cfg->session_lifetime; / 7200
$cfg->password_min_length; / 12
$cfg->allowed_roles; / [admin, editor, standard]
```
Umgebungsüberschreibungen: Eine Datei mit dem Namen `users.production.ini` wird vorzugsweise gegenüber `users.ini` verwendet, wenn `APPLICATION_ENV=production`.
@@ -162,7 +162,7 @@ $analytics = new \Nibiru\Module\Analytics\Analytics();
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Matomo());
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Plausible());
$analytics->trackPageView(); // internally calls notify()
$analytics->trackPageView(); / internally calls notify()
```
Jeder Beobachter erhält die Analytics-Instanz und zieht die Ereignisdaten aus, über die er sich interessiert.
@@ -200,7 +200,7 @@ Die Namen sind **kleinbuchstabeigeordnete Ordnername**, genau wie sie unter `app
Pluginklassen liegen im **Plural**-Namespace `Plugins`:
```php
// application/module/billing/plugins/invoice.php
namespace Nibiru\Module\Billing\Plugins; // ← plural
namespace Nibiru\Module\Billing\Plugins; / plural
class Invoice extends \Nibiru\Module\Billing\Billing { /* ... */ }
```
Namespace und Klassenname nicht übereinstimmen und es treten Autoloader-Fehlschläge auf. Der CLI-Scaffold-Befehl (`./nibiru -m billing`) generiert den richtigen Namespace für Sie.
@@ -210,7 +210,7 @@ Namespace und Klassenname nicht übereinstimmen und es treten Autoloader-Fehlsch
Sie **registrieren** Ihre Modul-INI-Dateien nicht — der [Registry](/de/core/registry/) entdeckt sie automatisch, indem er `application/module/<name>/settings/*.ini` durchläuft, nachdem `[AUTOLOADER]` die Modulklassen lädt. Jede Sektion `[<MODULE>]` (in Großbuchstaben) in einer INI wird zur Verfügung gestellt als:
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('billing');
$cfg->invoice_prefix; // [BILLING] invoice.prefixproperty
$cfg->invoice_prefix; / [BILLING] invoice.prefix property
```
Der Registrierungsmodul bevorzugt `<Modul>.<Umgebung>.ini` (z.B. `billing.production.ini`), wenn `APPLICATION_ENV` übereinstimmt.

View File

@@ -14,7 +14,7 @@ class productsController extends Controller
{
public function pageAction() {
$products = new products();
Pageination::setEntriesPerPage(25); // optional; default from INI
Pageination::setEntriesPerPage(25); / optional; default from INI
Pageination::setTable($products);
$rows = Pageination::loadTableAsArray();

View File

@@ -20,7 +20,7 @@ Für jedes Modul unter `application/module/<name>/settings/`:
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime;
$users->password_min_length;
$users->allowed_roles; // array
$users->allowed_roles; / array
```
Innerhalb des Moduls selbst ist die Konvention, dies in einen Setter zu verpacken:
```php

View File

@@ -40,7 +40,7 @@ Alles nach dem Aktionssegment wird zu einem `$_REQUEST`-Schlüssel gemäß der P
// /users/edit/42 → $_REQUEST['id'] = '42'
public function editAction() {
$id = (int) ($_REQUEST['id'] ?? 0);
// ...
/ ...
}
```
Für nicht-numerische oder benannte Parameter bevorzugen Sie Abfragezeichenfolgen:
@@ -62,9 +62,9 @@ Wenn eine URL dem Muster entspricht, werden die Captured Groups den benannten `p
## Routen-Hilfsprogramme
```php
Router::getInstance()->currentPage(); // 'products'
Router::getInstance()->tplName(); // 'products' (controller stem for templates)
Router::getInstance()->getController(); // alias for currentPage()
Router::getInstance()->currentPage(); / 'products'
Router::getInstance()->tplName(); / 'products' (controller stem for templates)
Router::getInstance()->getController(); / alias for currentPage()
```
Diese sind nützlich innerhalb von Controllern und Templates:
```smarty

View File

@@ -7,7 +7,7 @@ description: "Schaltflächen, Karten, Aufrufe, Heldenbildschirm bereit zum K
Ein schwarzer Rechteck auf einem cremefarbenen Hintergrund. Editorial. Kein Gradient, kein Glühen.
```html
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/de/start/installation/">
<span>Read the docs</span>
<span class="atelier-button__arrow" aria-hidden="true"></span>
</a>
@@ -162,7 +162,7 @@ Asymmetrische Gitter mit zwei Spalten. Große Editorial-Nummer hinter dem Text.
Nibiru is a modular PHP framework for builders who ship.
</p>
<div class="atelier-hero__cta">
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/de/start/installation/">
Read the docs <span aria-hidden="true"></span>
</a>
</div>

View File

@@ -19,73 +19,25 @@ hero:
variant: minimal
---
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
import CometTrail from '../../../components/CometTrail.astro';
import MmvcStage from '../../../components/MmvcStage.astro';
import MissionControl from '../../../components/MissionControl.astro';
import LaunchSequence from '../../../components/LaunchSequence.astro';
import SpacecraftGrid from '../../../components/SpacecraftGrid.astro';
import EditorialContent from '../../../components/EditorialContent.astro';
import LandingFooter from '../../../components/LandingFooter.astro';
import ToTop from '../../../components/ToTop.astro';
import LandingScripts from '../../../components/LandingScripts.astro';
## Eine Konstellation von Funktionen
<CometTrail />
<MmvcStage />
<MissionControl />
<LaunchSequence />
<SpacecraftGrid />
<EditorialContent />
<LandingFooter />
<ToTop />
<CardGrid stagger>
<Card title="MMVC-Architektur" icon="puzzle">
Module umschließen MVC mit Traits, Plugins, Interfaces und Settings. Das zweite **M** ist lose gekoppelt — und besitzt das Observer-Muster (`SplSubject`) ab Werk.
</Card>
<Card title="Multi-Datenbank-Kern" icon="seti:db">
Fünf Treiber im Orbit: `mysql`, `pdo`, `postgres` (ODBC), `psql` (libpq) und `postgresql`. Wechsel durch Ändern eines INI-Schlüssels.
</Card>
<Card title="Smarty Views" icon="document">
Template-getriebene Views, ein globaler `View::assign()`-Helfer und ein heißer `templates_c`-Cache. Plus geteilte Partials, Navigations-Includes und Pagination-Templates.
</Card>
<Card title="Flüssiger Form-Builder" icon="pencil">
28+ Feldtypen — Text, Passwort, Switch, Color, Range, File-Upload — komponiert über statische `Form::add…`-Aufrufe und als ein einziger HTML-String gerendert.
</Card>
<Card title="Echtes CLI-Tool" icon="seti:powershell">
`./nibiru` generiert Module, Controller, Plugins, Migrationen und CMS-Seiten. Es führt Migrationen gegen `local`, `staging` oder `production` aus.
</Card>
<Card title="KI-nativ, demnächst" icon="rocket">
Nibiru wird das erste PHP-Framework mit einem eingebauten <a href="/de/ai/oracle/">RAG-basierten Orakel</a>, das auf seinem eigenen Wissen trainiert ist — und einem veröffentlichten Korpus für künftige Fine-Tunes.
</Card>
</CardGrid>
## Schnellstart
```bash
# Klonen
git clone https://github.com/alllinux/Nibiru meine-app && cd meine-app
# PHP-Abhängigkeiten installieren (Smarty, PHPMailer, Guzzle, …)
composer install
# Berechtigungen + Ordner-Bootstrap
./nibiru -s
# Erste Migration ausführen
./nibiru -mi local
# Controller generieren
./nibiru -c products
```
```php
// application/controller/productsController.php
namespace Nibiru;
use Nibiru\Adapter\Controller;
class productsController extends Controller {
public function pageAction() {
View::assign([
'title' => 'Produkte — Nibiru',
'products' => [['id' => 1, 'name' => 'Marduk-Goldbeschichtung']],
]);
}
public function navigationAction() {
JsonNavigation::getInstance()->loadJsonNavigationArray();
}
}
```
## Wohin als Nächstes?
<CardGrid>
<LinkCard title="Was ist Nibiru?" href="/de/start/what-is-nibiru/" description="Die 90-Sekunden-Tour: MMVC, der Dispatcher, der Request-Lifecycle." />
<LinkCard title="Architektur" href="/core/architecture/" description="Wie Module, Controller, Views und das Registry einander umkreisen." />
<LinkCard title="Showcase" href="/showcase/projects/" description="Echte Apps in Produktion auf Nibiru — Rechnungswesen, E-Commerce, industrielles PIM." />
<LinkCard title="Frag das Orakel" href="/de/ai/oracle/" description="Öffne den schwebenden Chat. Das Orakel ist auf genau dieser Dokumentation geerdet." />
</CardGrid>
{/* Loads three.js + the original mockup scene code. MUST be the last node so
every #id the scene targets exists in the DOM when the script runs. */}
<LandingScripts />

View File

@@ -61,7 +61,7 @@ Mehrere Tracker ohne Controller-Kopplung.
$analytics = new Analytics();
$analytics->attach(new Plugin\Matomo());
$analytics->attach(new Plugin\Plausible());
$analytics->trackPageView(); // calls notify() internally
$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.

View File

@@ -55,7 +55,7 @@ public function detailAction()
try {
$machine = Machine::init()->getMachine((int) $machineId);
} catch (\Throwable $e) {
$machine = null; // DB blip → page still renders with fallback.
$machine = null; / DB blip page still renders with fallback.
}
$machineName = $machine['ms_machines_name'] ?? "Maschine #$machineId";
@@ -110,7 +110,7 @@ Fügen Sie eine neue Smarty-Vorlage ins System ein, der Editor weiß sofort, wel
## Was ist tatsächlich besonderes, zusammengefasst
Die fünf Unterschiedsmaker unten stammen aus den darüberliegenden Codebasen. Jeder verweist auf seine Beweise auf der Seite [Warum Nibiru](/de/warum-nibiru/).
Die fünf Unterschiedsmaker unten stammen aus den darüberliegenden Codebasen. Jeder verweist auf seine Beweise auf der Seite [Warum Nibiru](/de/why-nibiru/).
| | Was Nibiru macht | Was Laravel/Symfony macht |
|---|---|---|
@@ -120,7 +120,7 @@ Die fünf Unterschiedsmaker unten stammen aus den darüberliegenden Codebasen. J
| Authentifizierung | 3 Zeilen im Controller-Konstruktor. | Middleware-Stack + Policy-Klassen + Gates. |
| Ereignisse | `SplSubject` + `SplObserver` aus der PHP Standardbibliothek. | Benutzerdefinierter Event-Dispatcher + Listener-Registry + Warteschlange. |
Lesen Sie die [vollständige Ausbreakdown mit Codeverweisen →](/de/warum-nibiru/)
Lesen Sie die [vollständige Ausbreakdown mit Codeverweisen →](/de/why-nibiru/)
---

View File

@@ -50,7 +50,7 @@ class Cms implements Interfaces\Cms, SplSubject
use Traits\PageBuilderForm;
use Traits\CmsPageStructureModifier;
use Traits\FormElements;
// …8 more traits
/ …8 more traits
}
```
**Gesamtwirkung**: keine Konstruktor-Injektion, keine Dienstleistungsanbieterregistrierung, keine Aufrufe von `bind()` / `singleton()` in einer Konfigurationsdatei. Ein neuer Entwickler kann nach dem Trait-Namen suchen und alle Aufrufer sehen.
@@ -108,7 +108,7 @@ Der API-Controller nimmt den umgekehrten Ansatz: eine Whitelist öffentlicher En
```php
// public endpoints can be listed up-front, auth wraps the rest.
if (in_array($action, ['category', 'machines', 'ollama', 'team'])) {
// public, skip auth
/ public, skip auth
} else {
$this->user = new User();
$this->acl = new Acl();
@@ -137,8 +137,8 @@ class Machineryscout implements IModule, \SplSubject
}
public function indexMachines(): void {
// …do the work…
$this->notify(); // analytics, cache invalidator, audit log all see it.
/ …do the work…
$this->notify(); / analytics, cache invalidator, audit log all see it.
}
}
```
@@ -154,4 +154,4 @@ Ein einzelner Entwickler oder eine kleine Team kann eine echte Produktions-App b
Wenn Sie lieber Ihren Code sehen möchten, nehmen Sie ihn.
→ [Die Präsentation ansehen →](/de/praesentation/projekte/)
→ [Die Präsentation ansehen →](/de/showcase/projects/)

View File

@@ -70,7 +70,7 @@ Raw chunks for use as RAG retrieval data:
}
```
This is exactly the file the [Oracle](/ai/oracle/) uses internally.
This is exactly the file the [Oracle](/en/ai/oracle/) uses internally.
## How chunks are derived

View File

@@ -11,19 +11,19 @@ The Chat plugin is the simplest piece of the AI module. It wraps Ollama's `/api/
$ai = new \Nibiru\Module\Ai\Ai();
$chat = $ai->chat();
$chat->system('Be terse.'); // optional system prompt
$chat->model('qwen2.5-coder:14b'); // override the configured model
$chat->temperature(0.2); // override config
$chat->maxTokens(512); // override config
$chat->system('Be terse.'); / optional system prompt
$chat->model('qwen2.5-coder:14b'); / override the configured model
$chat->temperature(0.2); / override config
$chat->maxTokens(512); / override config
$chat->user('Hello'); // append a user message
$chat->assistant('Hi.'); // append an assistant message (rare)
$chat->user('Hello'); / append a user message
$chat->assistant('Hi.'); / append an assistant message (rare)
$reply = $chat->complete(); // run the call, return text
$reply = $chat->ask('How are you?'); // = ->user(...)->complete()
$reply = $chat->complete(); / run the call, return text
$reply = $chat->ask('How are you?'); / = ->user(...)->complete()
$chat->reset(); // clear messages, keep model + system
$chat->history(); // [{role, content}, …]
$chat->reset(); / clear messages, keep model + system
$chat->history(); / [{role, content}, ]
```
## One-shot
@@ -40,10 +40,10 @@ echo (new \Nibiru\Module\Ai\Ai())
$chat = $ai->chat();
$chat->user('Name three Nibiru singletons.');
$singletons = $chat->complete(); // appended to history
$singletons = $chat->complete(); / appended to history
$chat->user('What does the second one do?');
$detail = $chat->complete(); // model has full context
$detail = $chat->complete(); / model has full context
```
## Overriding model + style per call

View File

@@ -10,12 +10,12 @@ The Embed plugin is a thin wrapper around Ollama's `/api/embeddings` plus three
```php
$embed = (new \Nibiru\Module\Ai\Ai())->embed();
$vec = $embed->one('controller'); // float[]
$vectors = $embed->batch(['a', 'b', 'c']); // float[][]
$vec = $embed->one('controller'); / float[]
$vectors = $embed->batch(['a', 'b', 'c']); / float[][]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); // 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); // back to float[]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); / 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); / back to float[]
```
## Pattern: deduplicate near-duplicate strings
@@ -54,8 +54,8 @@ function bestTag(string $text, array $tagVecs, $embed): string {
return $best[0];
}
echo bestTag('User::isAuthorized', $tagVecs, $embed); // → 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); // → 'database' (probably)
echo bestTag('User::isAuthorized', $tagVecs, $embed); / 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); / 'database' (probably)
```
## Storage
@@ -65,7 +65,7 @@ Embeddings are float arrays — typically 768 floats for `nomic-embed-text`, 102
Use `Embed::pack()` to base64-encode them as 4-byte floats:
```php
$compact = Embed::pack($vec); // ~4 KB → ~5.3 KB base64 string
$compact = Embed::pack($vec); / ~4 KB ~5.3 KB base64 string
$vec = Embed::unpack($compact);
```

View File

@@ -62,7 +62,7 @@ echo $ai->chat()->ask('Explain MMVC in two sentences.');
// Multi-turn
$chat = $ai->chat();
$chat->user('How do I scaffold a module?');
$chat->user('And add Graylog hooks?'); // referrs to previous turn
$chat->user('And add Graylog hooks?'); / referrs to previous turn
echo $chat->complete();
// Override per call
@@ -89,7 +89,7 @@ $score = \Nibiru\Module\Ai\Plugin\Embed::cosine($va, $vb);
Compact storage:
```php
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string, 4 bytes/dim
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string, 4 bytes/dim
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
```
@@ -99,7 +99,7 @@ $vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
$rag = $ai->rag('product-help');
// One-time ingestion
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
$rag->ingestFile('/var/data/manual.pdf.txt');
@@ -118,9 +118,9 @@ use Nibiru\Module\Ai\Plugin\Tools;
$ai = new \Nibiru\Module\Ai\Ai();
$agent = $ai->agent()->withTools([
new Tools\PdoQuery(), // read-only SQL
new Tools\HttpGet(), // fetch URLs
new Tools\FileRead(), // read project files
new Tools\PdoQuery(), / read-only SQL
new Tools\HttpGet(), / fetch URLs
new Tools\FileRead(), / read project files
]);
echo $agent->run('How many active users registered last week?');

View File

@@ -11,9 +11,9 @@ The RAG plugin is the AI module's killer feature for product builders. It turns
use Nibiru\Module\Ai\Ai;
$ai = new Ai();
$rag = $ai->rag('product-help'); // a named collection
$rag = $ai->rag('product-help'); / a named collection
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php under help/
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php under help/
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
echo $rag->ask('How do I cancel my subscription?');
@@ -53,20 +53,20 @@ $logs->ingestText($exception->__toString(), ['ts' => time()]);
## API reference
```php
$rag = $ai->rag('name'); // get/create a named collection
$rag = $ai->rag('name'); / get/create a named collection
// --- Ingestion ---
$rag->ingestText($text, $metadata = []); // single chunk
$count = $rag->ingestFile('path'); // returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); // recursive
$rag->ingestText($text, $metadata = []); / single chunk
$count = $rag->ingestFile('path'); / returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); / recursive
// --- Querying ---
$hits = $rag->search('query', $k = null); // [{score, text, metadata}, …]
$answer = $rag->ask('question', $k = null); // top-K → chat call
$hits = $rag->search('query', $k = null); / [{score, text, metadata}, ]
$answer = $rag->ask('question', $k = null); / top-K chat call
// --- Maintenance ---
$rag->reset(); // forget everything (deletes file)
$n = $rag->size(); // number of chunks
$rag->reset(); / forget everything (deletes file)
$n = $rag->size(); / number of chunks
```
## Tuning knobs

View File

@@ -125,7 +125,7 @@ public function pageAction() {
View::forwardTo('/login');
return;
}
// ...
/ ...
}
```
@@ -195,7 +195,7 @@ public function submitAction() {
http_response_code(419);
return;
}
// ...handle submission...
/ ...handle submission...
}
```

View File

@@ -87,14 +87,14 @@ password_hash = "another-salt-for-AES_DECRYPT"
```php
$cfg = \Nibiru\Config::getInstance()->getConfig();
$cfg['DATABASE']['driver']; // 'pdo'
$cfg['SETTINGS']['page.url']; // 'https://my-app.local'
$cfg['DATABASE']['driver']; / 'pdo'
$cfg['SETTINGS']['page.url']; / 'https://my-app.local'
```
For deeply-nested configs use the typed constants from the View interface:
```php
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; // ['/public/css/app.css']
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; / ['/public/css/app.css']
```
## Module configs
@@ -103,7 +103,7 @@ Each module under `application/module/<name>/settings/` can carry its own INI fi
```php
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime; // from [USERS] section in users.ini
$users->session_lifetime; / from [USERS] section in users.ini
```
The Registry prefers `<module>.<env>.ini` over `<module>.ini`, so you get per-environment overrides for free.

View File

@@ -61,12 +61,12 @@ View::assign(['products' => $list]);
Convenience helpers from the base controller:
```php
$this->getRequest('id', false); // $_REQUEST['id'] ?? false
$this->getPost('email', ''); // $_POST['email'] ?? ''
$this->getGet('page', 1); // $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); // $_SERVER['REQUEST_URI']
$this->getFiles('upload'); // $_FILES['upload']
$this->getSession('auth'); // $_SESSION['auth']
$this->getRequest('id', false); / $_REQUEST['id'] ?? false
$this->getPost('email', ''); / $_POST['email'] ?? ''
$this->getGet('page', 1); / $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); / $_SERVER['REQUEST_URI']
$this->getFiles('upload'); / $_FILES['upload']
$this->getSession('auth'); / $_SESSION['auth']
```
These exist because `Controller` is `final`-friendly: you can mock them in tests by substituting a child class.
@@ -76,8 +76,8 @@ These exist because `Controller` is `final`-friendly: you can mock them in tests
To redirect inside an action:
```php
View::forwardTo('/login'); // 302 to the URL, exits
View::forwardToJsonHeader(); // sets Content-Type: application/json
View::forwardTo('/login'); / 302 to the URL, exits
View::forwardToJsonHeader(); / sets Content-Type: application/json
```
`forwardToJsonHeader()` is the canonical pattern for JSON endpoints — set the header, assign `data`, return. The view layer does the rest.

View File

@@ -35,17 +35,17 @@ public function run() {
if (Config::getInstance()->getConfig()
[self::CONFIG_GENERATOR_SECTION][self::GENERATOR_DATABASE]) {
new Model(false); // 1. (re)generate models from schema
new Model(false); / 1. (re)generate models from schema
}
Router::getInstance()->route(); // 2. parse the URL
Auto::loader()->loadModelFiles(); // 3. load model files
Auto::loader()->loadModules(); // 4. load module classes
Router::getInstance()->route(); / 2. parse the URL
Auto::loader()->loadModelFiles(); / 3. load model files
Auto::loader()->loadModules(); / 4. load module classes
$tpl = Router::getInstance()->tplName();
$controllerFile = __DIR__ . "/../../application/controller/{$tpl}Controller.php";
if (is_file($controllerFile)) { // 5. controller file exists
if (is_file($controllerFile)) { / 5. controller file exists
require_once $controllerFile;
$class = "Nibiru\\{$tpl}Controller";
$controller = new $class();
@@ -54,7 +54,7 @@ public function run() {
$action = $_REQUEST['_action'] . 'Action';
$controller->navigationAction();
if (method_exists($controller, $action)) {
$controller->$action(); // 6. optional named action
$controller->$action(); / 6. optional named action
}
$controller->pageAction();
} else {
@@ -62,9 +62,9 @@ public function run() {
$controller->pageAction();
}
Display::getInstance()->display(); // 7. render Smarty
Display::getInstance()->display(); / 7. render Smarty
} else {
// 8. soft 404 — render the configured error controller
/ 8. soft 404 render the configured error controller
}
}
```

View File

@@ -51,8 +51,8 @@ addOpenSpan addCloseSpan
### Lifecycle
```
create // reset the static buffer; call before building a new form
addForm // wrap the buffer in <form>...</form> and return as a string
create / reset the static buffer; call before building a new form
addForm / wrap the buffer in <form>...</form> and return as a string
```
:::caution[The naming inconsistency is intentional, sort of]
@@ -64,7 +64,7 @@ addForm // wrap the buffer in <form>...</form> and return as a string
```php
use Nibiru\Factory\Form;
Form::create(); // reset the static buffer
Form::create(); / reset the static buffer
Form::addOpenDiv(['class' => 'form-group']);
Form::addTypeLabel(['for' => 'login', 'value' => 'Username']);
@@ -220,7 +220,7 @@ class formsController extends Controller {
'required' => 'required',
'class' => 'contacts-input form-control',
]);
// ...more fields...
/ ...more fields...
$this->form = Form::addForm([
'name' => 'newregister',
'method' => 'post',

View File

@@ -160,9 +160,9 @@ Read it back from anywhere:
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$cfg->session_lifetime; // 7200
$cfg->password_min_length; // 12
$cfg->allowed_roles; // [admin, editor, standard]
$cfg->session_lifetime; / 7200
$cfg->password_min_length; / 12
$cfg->allowed_roles; / [admin, editor, standard]
```
Environment overlays: a file named `users.production.ini` is preferred over `users.ini` when `APPLICATION_ENV=production`.
@@ -177,7 +177,7 @@ $analytics = new \Nibiru\Module\Analytics\Analytics();
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Matomo());
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Plausible());
$analytics->trackPageView(); // internally calls notify()
$analytics->trackPageView(); / internally calls notify()
```
Each observer's `update($subject)` receives the analytics instance and pulls the event data it cares about.
@@ -219,7 +219,7 @@ Plugin classes live under the **plural** namespace `Plugins`:
```php
// application/module/billing/plugins/invoice.php
namespace Nibiru\Module\Billing\Plugins; // ← plural
namespace Nibiru\Module\Billing\Plugins; / plural
class Invoice extends \Nibiru\Module\Billing\Billing { /* ... */ }
```
@@ -231,7 +231,7 @@ You **don't** register your module's INI files — the [Registry](/en/core/regis
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('billing');
$cfg->invoice_prefix; // [BILLING] invoice.prefixproperty
$cfg->invoice_prefix; / [BILLING] invoice.prefix property
```
The Registry prefers `<module>.<env>.ini` (e.g. `billing.production.ini`) when `APPLICATION_ENV` matches.

View File

@@ -15,7 +15,7 @@ class productsController extends Controller
{
public function pageAction() {
$products = new products();
Pageination::setEntriesPerPage(25); // optional; default from INI
Pageination::setEntriesPerPage(25); / optional; default from INI
Pageination::setTable($products);
$rows = Pageination::loadTableAsArray();

View File

@@ -21,7 +21,7 @@ For each module under `application/module/<name>/settings/`:
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime;
$users->password_min_length;
$users->allowed_roles; // array
$users->allowed_roles; / array
```
Inside the module itself the convention is to wrap this in a setter:

View File

@@ -47,7 +47,7 @@ Anything past the action segment becomes a `$_REQUEST` key paired by position:
// /users/edit/42 → $_REQUEST['id'] = '42'
public function editAction() {
$id = (int) ($_REQUEST['id'] ?? 0);
// ...
/ ...
}
```
@@ -75,9 +75,9 @@ When a URL matches the pattern, capture groups are assigned to the named `params
## Routing helpers
```php
Router::getInstance()->currentPage(); // 'products'
Router::getInstance()->tplName(); // 'products' (controller stem for templates)
Router::getInstance()->getController(); // alias for currentPage()
Router::getInstance()->currentPage(); / 'products'
Router::getInstance()->tplName(); / 'products' (controller stem for templates)
Router::getInstance()->getController(); / alias for currentPage()
```
These are useful inside controllers and templates:

View File

@@ -8,7 +8,7 @@ description: Buttons, cards, callouts, hero — copy-paste ready.
A black-on-cream rectangle. Editorial. No gradient, no glow.
```html
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/en/start/installation/">
<span>Read the docs</span>
<span class="atelier-button__arrow" aria-hidden="true"></span>
</a>
@@ -179,7 +179,7 @@ Asymmetric two-column grid. Big editorial number behind the copy. The brand mark
Nibiru is a modular PHP framework for builders who ship.
</p>
<div class="atelier-hero__cta">
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/en/start/installation/">
Read the docs <span aria-hidden="true"></span>
</a>
</div>

View File

@@ -6,7 +6,7 @@ description: Downloadable Nibiru framework training corpus — chunks, instructi
import DownloadsManifest from '../../../components/DownloadsManifest.astro';
A pre-built training corpus for fine-tuning your own LoRA on Nibiru. Generated
deterministically from two sources: the deep [framework reference](/en/reference/)
deterministically from two sources: the deep [framework reference](https://github.com/alllinux/Nibiru/blob/master/docs/scripts/extraction/framework-reference-v2.md)
(every public factory, namespace, idiom and gotcha cited file:line) and the
public docs in five languages.

View File

@@ -70,7 +70,7 @@ Multiple trackers without controller coupling.
$analytics = new Analytics();
$analytics->attach(new Plugin\Matomo());
$analytics->attach(new Plugin\Plausible());
$analytics->trackPageView(); // calls notify() internally
$analytics->trackPageView(); / calls notify() internally
```
Each observer's `update($subject)` pulls only the fields it cares about. Adding a tracker is a one-line change.

View File

@@ -56,7 +56,7 @@ public function detailAction()
try {
$machine = Machine::init()->getMachine((int) $machineId);
} catch (\Throwable $e) {
$machine = null; // DB blip → page still renders with fallback.
$machine = null; / DB blip page still renders with fallback.
}
$machineName = $machine['ms_machines_name'] ?? "Maschine #$machineId";

View File

@@ -53,7 +53,7 @@ class Cms implements Interfaces\Cms, SplSubject
use Traits\PageBuilderForm;
use Traits\CmsPageStructureModifier;
use Traits\FormElements;
// …8 more traits
/ …8 more traits
}
```
@@ -117,7 +117,7 @@ The API controller takes the inverse approach: a whitelist of public endpoints i
```php
// public endpoints can be listed up-front, auth wraps the rest.
if (in_array($action, ['category', 'machines', 'ollama', 'team'])) {
// public, skip auth
/ public, skip auth
} else {
$this->user = new User();
$this->acl = new Acl();
@@ -148,8 +148,8 @@ class Machineryscout implements IModule, \SplSubject
}
public function indexMachines(): void {
// …do the work…
$this->notify(); // analytics, cache invalidator, audit log all see it.
/ …do the work…
$this->notify(); / analytics, cache invalidator, audit log all see it.
}
}
```

View File

@@ -60,7 +60,7 @@ Fragmentos sin procesar para su uso como datos de recuperación RAG:
"content": "Modules implementing `SplSubject` can broadcast events…"
}
```
Este es exactamente el archivo que usa internamente [Oracle](/ai/oracle/).
Este es exactamente el archivo que usa internamente [Oracle](/es/ai/oracle/).
## Cómo se derivan los fragmentos

View File

@@ -10,19 +10,19 @@ El complemento de chat es la pieza más simple del módulo de IA. Envuelve la AP
$ai = new \Nibiru\Module\Ai\Ai();
$chat = $ai->chat();
$chat->system('Be terse.'); // optional system prompt
$chat->model('qwen2.5-coder:14b'); // override the configured model
$chat->temperature(0.2); // override config
$chat->maxTokens(512); // override config
$chat->system('Be terse.'); / optional system prompt
$chat->model('qwen2.5-coder:14b'); / override the configured model
$chat->temperature(0.2); / override config
$chat->maxTokens(512); / override config
$chat->user('Hello'); // append a user message
$chat->assistant('Hi.'); // append an assistant message (rare)
$chat->user('Hello'); / append a user message
$chat->assistant('Hi.'); / append an assistant message (rare)
$reply = $chat->complete(); // run the call, return text
$reply = $chat->ask('How are you?'); // = ->user(...)->complete()
$reply = $chat->complete(); / run the call, return text
$reply = $chat->ask('How are you?'); / = ->user(...)->complete()
$chat->reset(); // clear messages, keep model + system
$chat->history(); // [{role, content}, …]
$chat->reset(); / clear messages, keep model + system
$chat->history(); / [{role, content}, ]
```
## En un solo paso
```php
@@ -35,10 +35,10 @@ echo (new \Nibiru\Module\Ai\Ai())
$chat = $ai->chat();
$chat->user('Name three Nibiru singletons.');
$singletons = $chat->complete(); // appended to history
$singletons = $chat->complete(); / appended to history
$chat->user('What does the second one do?');
$detail = $chat->complete(); // model has full context
$detail = $chat->complete(); / model has full context
```
## Sobrescribir modelo y estilo por llamada
```php

View File

@@ -9,12 +9,12 @@ El complemento Embed es un envoltorio ligero alrededor de `/api/embeddings` de O
```php
$embed = (new \Nibiru\Module\Ai\Ai())->embed();
$vec = $embed->one('controller'); // float[]
$vectors = $embed->batch(['a', 'b', 'c']); // float[][]
$vec = $embed->one('controller'); / float[]
$vectors = $embed->batch(['a', 'b', 'c']); / float[][]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); // 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); // back to float[]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); / 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); / back to float[]
```
## Patrón: eliminar cadenas similares
```php
@@ -49,8 +49,8 @@ function bestTag(string $text, array $tagVecs, $embed): string {
return $best[0];
}
echo bestTag('User::isAuthorized', $tagVecs, $embed); // → 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); // → 'database' (probably)
echo bestTag('User::isAuthorized', $tagVecs, $embed); / 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); / 'database' (probably)
```
## Almacenamiento
@@ -58,7 +58,7 @@ Las incrustaciones son arreglos de flotantes — generalmente 768 flotantes para
Utiliza `Embed::pack()` para codificarlos en base64 como flotantes de 4 bytes:
```php
$compact = Embed::pack($vec); // ~4 KB → ~5.3 KB base64 string
$compact = Embed::pack($vec); / ~4 KB ~5.3 KB base64 string
$vec = Embed::unpack($compact);
```
El complemento RAG utiliza este formato internamente para sus archivos JSON.

View File

@@ -57,7 +57,7 @@ echo $ai->chat()->ask('Explain MMVC in two sentences.');
// Multi-turn
$chat = $ai->chat();
$chat->user('How do I scaffold a module?');
$chat->user('And add Graylog hooks?'); // referrs to previous turn
$chat->user('And add Graylog hooks?'); / referrs to previous turn
echo $chat->complete();
// Override per call
@@ -80,7 +80,7 @@ $score = \Nibiru\Module\Ai\Plugin\Embed::cosine($va, $vb);
```
Almacenamiento compacto:
```php
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string, 4 bytes/dim
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string, 4 bytes/dim
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
```
### 3. RAG — ingesta, recuperación, anclaje
@@ -88,7 +88,7 @@ $vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
$rag = $ai->rag('product-help');
// One-time ingestion
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
$rag->ingestFile('/var/data/manual.pdf.txt');
@@ -105,9 +105,9 @@ use Nibiru\Module\Ai\Plugin\Tools;
$ai = new \Nibiru\Module\Ai\Ai();
$agent = $ai->agent()->withTools([
new Tools\PdoQuery(), // read-only SQL
new Tools\HttpGet(), // fetch URLs
new Tools\FileRead(), // read project files
new Tools\PdoQuery(), / read-only SQL
new Tools\HttpGet(), / fetch URLs
new Tools\FileRead(), / read project files
]);
echo $agent->run('How many active users registered last week?');
@@ -154,7 +154,7 @@ La filosofía de diseño:
## Siguiente
- [Referencia del complemento de chat](/es/ai/modulo/chat/)
- [Referencia del complemento RAG](/es/ai/modulo/rag/)
- [Referencia del complemento de agente](/es/ai/modulo/agent/)
- [Entrenamiento nibiru-coder](/es/ai/modulo/training/)
- [Referencia del complemento de chat](/es/ai/module/chat/)
- [Referencia del complemento RAG](/es/ai/module/rag/)
- [Referencia del complemento de agente](/es/ai/module/agent/)
- [Entrenamiento nibiru-coder](/es/ai/module/training/)

View File

@@ -10,9 +10,9 @@ El complemento RAG es la característica clave del módulo de IA para los constr
use Nibiru\Module\Ai\Ai;
$ai = new Ai();
$rag = $ai->rag('product-help'); // a named collection
$rag = $ai->rag('product-help'); / a named collection
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php under help/
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php under help/
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
echo $rag->ask('How do I cancel my subscription?');
@@ -46,20 +46,20 @@ $logs->ingestText($exception->__toString(), ['ts' => time()]);
```
## Referencia de la API
```php
$rag = $ai->rag('name'); // get/create a named collection
$rag = $ai->rag('name'); / get/create a named collection
// --- Ingestion ---
$rag->ingestText($text, $metadata = []); // single chunk
$count = $rag->ingestFile('path'); // returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); // recursive
$rag->ingestText($text, $metadata = []); / single chunk
$count = $rag->ingestFile('path'); / returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); / recursive
// --- Querying ---
$hits = $rag->search('query', $k = null); // [{score, text, metadata}, …]
$answer = $rag->ask('question', $k = null); // top-K → chat call
$hits = $rag->search('query', $k = null); / [{score, text, metadata}, ]
$answer = $rag->ask('question', $k = null); / top-K chat call
// --- Maintenance ---
$rag->reset(); // forget everything (deletes file)
$n = $rag->size(); // number of chunks
$rag->reset(); / forget everything (deletes file)
$n = $rag->size(); / number of chunks
```
## Perillas de ajuste
@@ -95,5 +95,5 @@ rag.storage_path = "/../../application/module/ai/cache/rag/"
## ¿Qué sigue?
- [Plugin de agente →](/es/ai/modulo/agente/) para herramientas, no recuperación.
- [Entrenamiento nibiru-coder →](/es/ai/modulo/entrenamiento/) para que el chat responda a la mitad en voz del marco.
- [Plugin de agente →](/es/ai/module/agent/) para herramientas, no recuperación.
- [Entrenamiento nibiru-coder →](/es/ai/module/training/) para que el chat responda a la mitad en voz del marco.

View File

@@ -114,7 +114,7 @@ public function pageAction() {
View::forwardTo('/login');
return;
}
// ...
/ ...
}
```
Para las verificaciones basadas en roles, las aplicaciones de demostración utilizan el complemento `Acl` del mismo módulo:
@@ -178,7 +178,7 @@ public function submitAction() {
http_response_code(419);
return;
}
// ...handle submission...
/ ...handle submission...
}
```
Incorpore `<input type="hidden" name="csrf" value="{$csrf}">` en su formulario.

View File

@@ -82,19 +82,19 @@ password_hash = "another-salt-for-AES_DECRYPT"
## Leyendo la configuración
```php
$cfg = \Nibiru\Config::getInstance()->getConfig();
$cfg['DATABASE']['driver']; // 'pdo'
$cfg['SETTINGS']['page.url']; // 'https://my-app.local'
$cfg['DATABASE']['driver']; / 'pdo'
$cfg['SETTINGS']['page.url']; / 'https://my-app.local'
```
Para configuraciones profundamente anidadas, utilice las constantes tipadas de la interfaz View:
```php
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; // ['/public/css/app.css']
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; / ['/public/css/app.css']
```
## Configuraciones del módulo
Cada módulo bajo `application/module/<nombre>/settings/` puede llevar sus propios archivos INI. El Registro los detecta automáticamente y los expone a través de:
```php
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime; // from [USERS] section in users.ini
$users->session_lifetime; / from [USERS] section in users.ini
```
El Registro prefiere `<módulo>.<entorno>.ini` sobre `<módulo>.ini`, por lo que obtienes anulaciones por entorno de forma gratuita.

View File

@@ -56,12 +56,12 @@ View::assign(['products' => $list]);
```
Ayudantes de conveniencia del controlador base:
```php
$this->getRequest('id', false); // $_REQUEST['id'] ?? false
$this->getPost('email', ''); // $_POST['email'] ?? ''
$this->getGet('page', 1); // $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); // $_SERVER['REQUEST_URI']
$this->getFiles('upload'); // $_FILES['upload']
$this->getSession('auth'); // $_SESSION['auth']
$this->getRequest('id', false); / $_REQUEST['id'] ?? false
$this->getPost('email', ''); / $_POST['email'] ?? ''
$this->getGet('page', 1); / $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); / $_SERVER['REQUEST_URI']
$this->getFiles('upload'); / $_FILES['upload']
$this->getSession('auth'); / $_SESSION['auth']
```
Estos existen porque `Controller` es amigable con `final`: puedes simularlos en pruebas sustituyendo una clase hija.
@@ -69,8 +69,8 @@ Estos existen porque `Controller` es amigable con `final`: puedes simularlos en
Para redirigir dentro de una acción:
```php
View::forwardTo('/login'); // 302 to the URL, exits
View::forwardToJsonHeader(); // sets Content-Type: application/json
View::forwardTo('/login'); / 302 to the URL, exits
View::forwardToJsonHeader(); / sets Content-Type: application/json
```
`forwardToJsonHeader()` es el patrón canónico para puntos finales JSON — establece la cabecera, asigna `data`, y devuelve. La capa de vista se encarga del resto.

View File

@@ -30,17 +30,17 @@ public function run() {
if (Config::getInstance()->getConfig()
[self::CONFIG_GENERATOR_SECTION][self::GENERATOR_DATABASE]) {
new Model(false); // 1. (re)generate models from schema
new Model(false); / 1. (re)generate models from schema
}
Router::getInstance()->route(); // 2. parse the URL
Auto::loader()->loadModelFiles(); // 3. load model files
Auto::loader()->loadModules(); // 4. load module classes
Router::getInstance()->route(); / 2. parse the URL
Auto::loader()->loadModelFiles(); / 3. load model files
Auto::loader()->loadModules(); / 4. load module classes
$tpl = Router::getInstance()->tplName();
$controllerFile = __DIR__ . "/../../application/controller/{$tpl}Controller.php";
if (is_file($controllerFile)) { // 5. controller file exists
if (is_file($controllerFile)) { / 5. controller file exists
require_once $controllerFile;
$class = "Nibiru\\{$tpl}Controller";
$controller = new $class();
@@ -49,7 +49,7 @@ public function run() {
$action = $_REQUEST['_action'] . 'Action';
$controller->navigationAction();
if (method_exists($controller, $action)) {
$controller->$action(); // 6. optional named action
$controller->$action(); / 6. optional named action
}
$controller->pageAction();
} else {
@@ -57,9 +57,9 @@ public function run() {
$controller->pageAction();
}
Display::getInstance()->display(); // 7. render Smarty
Display::getInstance()->display(); / 7. render Smarty
} else {
// 8. soft 404 — render the configured error controller
/ 8. soft 404 render the configured error controller
}
}
```

View File

@@ -40,8 +40,8 @@ addOpenSpan addCloseSpan
```
### Ciclo de vida
```
create // reset the static buffer; call before building a new form
addForm // wrap the buffer in <form>...</form> and return as a string
create / reset the static buffer; call before building a new form
addForm / wrap the buffer in <form>...</form> and return as a string
```
:::caution[La inconsistencia de nombres es intencional, más bien]
`addInputTypePassword` vs `addTypePassword`, `addInputTypeFileupload` vs `addTypeFileUpload` — el prefijo coincide si el elemento es un `<input type="…">` (prefijo Input) o alguna otra etiqueta (prefijo Type). Es incómodo pero estable; la CLI de `./nibiru -c` usa el mismo patrón, por lo que la memoria muscular funciona.
@@ -50,7 +50,7 @@ addForm // wrap the buffer in <form>...</form> and return as a string
```php
use Nibiru\Factory\Form;
Form::create(); // reset the static buffer
Form::create(); / reset the static buffer
Form::addOpenDiv(['class' => 'form-group']);
Form::addTypeLabel(['for' => 'login', 'value' => 'Username']);
@@ -186,7 +186,7 @@ class formsController extends Controller {
'required' => 'required',
'class' => 'contacts-input form-control',
]);
// ...more fields...
/ ...more fields...
$this->form = Form::addForm([
'name' => 'newregister',
'method' => 'post',

View File

@@ -147,9 +147,9 @@ allowed.roles[] = "standard"
Léelo desde cualquier lugar:
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$cfg->session_lifetime; // 7200
$cfg->password_min_length; // 12
$cfg->allowed_roles; // [admin, editor, standard]
$cfg->session_lifetime; / 7200
$cfg->password_min_length; / 12
$cfg->allowed_roles; / [admin, editor, standard]
```
Capas de entorno: un archivo llamado `users.production.ini` se prefiere sobre `users.ini` cuando `APPLICATION_ENV=production`.
@@ -162,7 +162,7 @@ $analytics = new \Nibiru\Module\Analytics\Analytics();
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Matomo());
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Plausible());
$analytics->trackPageView(); // internally calls notify()
$analytics->trackPageView(); / internally calls notify()
```
Cada observador recibe la instancia de análisis en su método `update($subject)` y extrae los datos del evento que le interesan.
@@ -200,7 +200,7 @@ Los nombres son **nombres de carpetas en minúsculas**, exactamente como aparece
Las clases de plugin residen bajo el espacio de nombres **plural** `Plugins`:
```php
// application/module/billing/plugins/invoice.php
namespace Nibiru\Module\Billing\Plugins; // ← plural
namespace Nibiru\Module\Billing\Plugins; / plural
class Invoice extends \Nibiru\Module\Billing\Billing { /* ... */ }
```
Desacuerda el espacio de nombres y obtendrás fallos en la carga automática. La plantilla de la CLI (`./nibiru -m billing`) genera el espacio de nombres correcto para ti.
@@ -210,7 +210,7 @@ Desacuerda el espacio de nombres y obtendrás fallos en la carga automática. La
No **registras** los archivos INI de tu módulo — el [Registro](/es/core/registry/) los descubre automáticamente recorriendo `application/module/<name>/settings/*.ini` después de que `[AUTOLOADER]` carga la clase del módulo. Cada sección `[<MODULE>]` (en mayúsculas) de un INI se vuelve disponible como:
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('billing');
$cfg->invoice_prefix; // [BILLING] invoice.prefixproperty
$cfg->invoice_prefix; / [BILLING] invoice.prefix property
```
El Registro prefiere `<módulo>.<entorno>.ini` (por ejemplo, `facturación.producción.ini`) cuando `APPLICATION_ENV` coincide.

View File

@@ -14,7 +14,7 @@ class productsController extends Controller
{
public function pageAction() {
$products = new products();
Pageination::setEntriesPerPage(25); // optional; default from INI
Pageination::setEntriesPerPage(25); / optional; default from INI
Pageination::setTable($products);
$rows = Pageination::loadTableAsArray();

View File

@@ -20,7 +20,7 @@ Para cada módulo bajo `application/module/<nombre>/settings/`:
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime;
$users->password_min_length;
$users->allowed_roles; // array
$users->allowed_roles; / array
```
Dentro del módulo mismo, la convención es envolver esto en un setter:
```php

View File

@@ -40,7 +40,7 @@ Cualquier cosa después del segmento de acción se convierte en una clave `$_REQ
// /users/edit/42 → $_REQUEST['id'] = '42'
public function editAction() {
$id = (int) ($_REQUEST['id'] ?? 0);
// ...
/ ...
}
```
Para parámetros no numéricos o nombrados, prefiera cadenas de consulta:
@@ -62,9 +62,9 @@ Cuando una URL coincide con el patrón, los grupos capturados se asignan a las c
## Ayudantes de enrutamiento
```php
Router::getInstance()->currentPage(); // 'products'
Router::getInstance()->tplName(); // 'products' (controller stem for templates)
Router::getInstance()->getController(); // alias for currentPage()
Router::getInstance()->currentPage(); / 'products'
Router::getInstance()->tplName(); / 'products' (controller stem for templates)
Router::getInstance()->getController(); / alias for currentPage()
```
Estos son útiles dentro de los controladores y plantillas:
```smarty

View File

@@ -7,7 +7,7 @@ description: "Botones, tarjetas, llamadas a la acción, héroe — listos para c
Un rectángulo negro sobre crema. Editorial. Sin gradiente, sin brillo.
```html
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/es/start/installation/">
<span>Read the docs</span>
<span class="atelier-button__arrow" aria-hidden="true"></span>
</a>
@@ -162,7 +162,7 @@ Cuadrícula asimétrica de dos columnas. Un número editorial grande detrás del
Nibiru is a modular PHP framework for builders who ship.
</p>
<div class="atelier-hero__cta">
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/es/start/installation/">
Read the docs <span aria-hidden="true"></span>
</a>
</div>

View File

@@ -48,7 +48,7 @@ Eso es suficiente para estar en marca.
## ¿Qué se documenta aquí?
- [Paleta](/es/diseno/paleta/) — cada color con su rol.
- [Tipografía](/es/diseno/tipografia/) — los ejes variables de Bricolage utilizados en serio.
- [Componentes](/es/diseno/componentes/) — botones, tarjetas, llamadas a la atención, el lanzador Oracle.
- [Movimiento](/es/diseno/movimiento/) — respirar, desvanecerse, sin flash.
- [Paleta](/es/design/palette/) — cada color con su rol.
- [Tipografía](/es/design/typography/) — los ejes variables de Bricolage utilizados en serio.
- [Componentes](/es/design/components/) — botones, tarjetas, llamadas a la atención, el lanzador Oracle.
- [Movimiento](/es/design/motion/) — respirar, desvanecerse, sin flash.

View File

@@ -19,73 +19,25 @@ hero:
variant: minimal
---
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
import CometTrail from '../../../components/CometTrail.astro';
import MmvcStage from '../../../components/MmvcStage.astro';
import MissionControl from '../../../components/MissionControl.astro';
import LaunchSequence from '../../../components/LaunchSequence.astro';
import SpacecraftGrid from '../../../components/SpacecraftGrid.astro';
import EditorialContent from '../../../components/EditorialContent.astro';
import LandingFooter from '../../../components/LandingFooter.astro';
import ToTop from '../../../components/ToTop.astro';
import LandingScripts from '../../../components/LandingScripts.astro';
## Una constelación de capacidades
<CometTrail />
<MmvcStage />
<MissionControl />
<LaunchSequence />
<SpacecraftGrid />
<EditorialContent />
<LandingFooter />
<ToTop />
<CardGrid stagger>
<Card title="Arquitectura MMVC" icon="puzzle">
Los módulos envuelven MVC con traits, plugins, interfaces y configuraciones. La segunda **M** está acoplada de forma flexible, con el patrón observador `SplSubject` integrado.
</Card>
<Card title="Núcleo multi-base de datos" icon="seti:db">
Cinco controladores en órbita: `mysql`, `pdo`, `postgres` (ODBC), `psql` (libpq) y `postgresql`. Cambia con solo modificar una clave INI.
</Card>
<Card title="Vistas Smarty" icon="document">
Vistas dirigidas por plantillas, un ayudante global `View::assign()` y una caché caliente en `templates_c`. Más parciales compartidos, includes de navegación y plantillas de paginación.
</Card>
<Card title="Constructor de formularios fluido" icon="pencil">
Más de 28 tipos de campo — text, password, switch, color, range, file upload — compuestos mediante llamadas estáticas a `Form::add…` y renderizados como un único string HTML.
</Card>
<Card title="CLI real" icon="seti:powershell">
`./nibiru` genera módulos, controladores, plugins, migraciones y páginas CMS. Ejecuta migraciones contra `local`, `staging` o `production`.
</Card>
<Card title="IA nativa, pronto" icon="rocket">
Nibiru se está convirtiendo en el primer framework PHP con un <a href="/es/ai/oracle/">Oráculo basado en RAG</a> entrenado con su propio conocimiento — y un corpus publicado para futuros fine-tunes.
</Card>
</CardGrid>
## Inicio rápido
```bash
# Clonar
git clone https://github.com/alllinux/Nibiru mi-app && cd mi-app
# Instalar dependencias PHP (Smarty, PHPMailer, Guzzle, …)
composer install
# Permisos + arranque de carpetas
./nibiru -s
# Ejecutar la primera migración
./nibiru -mi local
# Generar un controlador
./nibiru -c products
```
```php
// application/controller/productsController.php
namespace Nibiru;
use Nibiru\Adapter\Controller;
class productsController extends Controller {
public function pageAction() {
View::assign([
'title' => 'Productos — Nibiru',
'products' => [['id' => 1, 'name' => 'Recubrimiento de Oro Marduk']],
]);
}
public function navigationAction() {
JsonNavigation::getInstance()->loadJsonNavigationArray();
}
}
```
## A dónde ir después
<CardGrid>
<LinkCard title="¿Qué es Nibiru?" href="/es/start/what-is-nibiru/" description="El recorrido de 90 segundos: MMVC, el dispatcher, el ciclo de vida de las peticiones." />
<LinkCard title="Arquitectura" href="/core/architecture/" description="Cómo módulos, controladores, vistas y el registro orbitan entre sí." />
<LinkCard title="Casos de uso" href="/showcase/projects/" description="Apps reales en producción sobre Nibiru — facturación, e-commerce, PIM industrial." />
<LinkCard title="Pregunta al Oráculo" href="/es/ai/oracle/" description="Abre el chat flotante. El Oráculo está fundamentado en esta misma documentación." />
</CardGrid>
{/* Loads three.js + the original mockup scene code. MUST be the last node so
every #id the scene targets exists in the DOM when the script runs. */}
<LandingScripts />

View File

@@ -61,7 +61,7 @@ Varios rastreadores sin acoplamiento con el controlador.
$analytics = new Analytics();
$analytics->attach(new Plugin\Matomo());
$analytics->attach(new Plugin\Plausible());
$analytics->trackPageView(); // calls notify() internally
$analytics->trackPageView(); / calls notify() internally
```
Cada observador extrae solo los campos que le interesan con su `update($subject)`. Agregar un rastreador es un cambio de una línea.

View File

@@ -55,7 +55,7 @@ public function detailAction()
try {
$machine = Machine::init()->getMachine((int) $machineId);
} catch (\Throwable $e) {
$machine = null; // DB blip → page still renders with fallback.
$machine = null; / DB blip page still renders with fallback.
}
$machineName = $machine['ms_machines_name'] ?? "Maschine #$machineId";
@@ -110,7 +110,7 @@ Inserta una nueva plantilla Smarty en el sistema, el editor sabe de inmediato cu
## ¿Qué realmente es especial, resumido?
Los cinco diferenciadores a continuación se extraen de los códigos fuente anteriores. Cada uno enlaza a su evidencia en la página [¿Por qué Nibiru](/es/por-que-nibiru/).
Los cinco diferenciadores a continuación se extraen de los códigos fuente anteriores. Cada uno enlaza a su evidencia en la página [¿Por qué Nibiru](/es/why-nibiru/).
| | ¿Qué hace Nibiru? | ¿Qué hace Laravel/Symfony? |
|---|---|---|
@@ -120,7 +120,7 @@ Los cinco diferenciadores a continuación se extraen de los códigos fuente ante
| Auth | 3 líneas en el constructor del controlador. | Pila de middleware + clases de política + portales. |
| Eventos | `SplSubject` + `SplObserver` de la librería estándar de PHP. | Despachador de eventos personalizado + registro de oyentes + cola. |
Lee la [desglose completa con referencias de código →](/es/porque-nibiru/)
Lee la [desglose completa con referencias de código →](/es/why-nibiru/)
---

View File

@@ -50,7 +50,7 @@ class Cms implements Interfaces\Cms, SplSubject
use Traits\PageBuilderForm;
use Traits\CmsPageStructureModifier;
use Traits\FormElements;
// …8 more traits
/ …8 more traits
}
```
**Efecto neto**: cero inyección de constructores, cero registro de proveedores de servicios, cero llamadas a `bind()` / `singleton()` en un archivo de configuración. Un nuevo desarrollador puede buscar el nombre del trait y ver todos los llamadores.
@@ -108,7 +108,7 @@ El controlador de la API toma un enfoque inverso: una lista blanca de puntos fin
```php
// public endpoints can be listed up-front, auth wraps the rest.
if (in_array($action, ['category', 'machines', 'ollama', 'team'])) {
// public, skip auth
/ public, skip auth
} else {
$this->user = new User();
$this->acl = new Acl();
@@ -137,8 +137,8 @@ class Machineryscout implements IModule, \SplSubject
}
public function indexMachines(): void {
// …do the work…
$this->notify(); // analytics, cache invalidator, audit log all see it.
/ …do the work…
$this->notify(); / analytics, cache invalidator, audit log all see it.
}
}
```
@@ -154,4 +154,4 @@ Un desarrollador solitario o un pequeño equipo puede construir y *operar* una a
Si prefieres ver tu código, tómalo.
→ [Lee la presentación →](/es/presentacion/proyectos/)
→ [Lee la presentación →](/es/showcase/projects/)

View File

@@ -60,7 +60,7 @@ Blocs bruts à utiliser comme données de récupération RAG :
"content": "Modules implementing `SplSubject` can broadcast events…"
}
```
Ceci est exactement le fichier que l'[Oracle](/ai/oracle/) utilise en interne.
Ceci est exactement le fichier que l'[Oracle](/fr/ai/oracle/) utilise en interne.
## Comment les morceaux sont dérivés

View File

@@ -10,19 +10,19 @@ Le plugin de chat est la pièce la plus simple du module IA. Il encapsule l'API
$ai = new \Nibiru\Module\Ai\Ai();
$chat = $ai->chat();
$chat->system('Be terse.'); // optional system prompt
$chat->model('qwen2.5-coder:14b'); // override the configured model
$chat->temperature(0.2); // override config
$chat->maxTokens(512); // override config
$chat->system('Be terse.'); / optional system prompt
$chat->model('qwen2.5-coder:14b'); / override the configured model
$chat->temperature(0.2); / override config
$chat->maxTokens(512); / override config
$chat->user('Hello'); // append a user message
$chat->assistant('Hi.'); // append an assistant message (rare)
$chat->user('Hello'); / append a user message
$chat->assistant('Hi.'); / append an assistant message (rare)
$reply = $chat->complete(); // run the call, return text
$reply = $chat->ask('How are you?'); // = ->user(...)->complete()
$reply = $chat->complete(); / run the call, return text
$reply = $chat->ask('How are you?'); / = ->user(...)->complete()
$chat->reset(); // clear messages, keep model + system
$chat->history(); // [{role, content}, …]
$chat->reset(); / clear messages, keep model + system
$chat->history(); / [{role, content}, ]
```
## Un coup unique
```php
@@ -35,10 +35,10 @@ echo (new \Nibiru\Module\Ai\Ai())
$chat = $ai->chat();
$chat->user('Name three Nibiru singletons.');
$singletons = $chat->complete(); // appended to history
$singletons = $chat->complete(); / appended to history
$chat->user('What does the second one do?');
$detail = $chat->complete(); // model has full context
$detail = $chat->complete(); / model has full context
```
## Remplacement du modèle et du style par appel
```php

View File

@@ -9,12 +9,12 @@ Le plugin Embed est un simple wrapper autour de `/api/embeddings` d'Ollama, plus
```php
$embed = (new \Nibiru\Module\Ai\Ai())->embed();
$vec = $embed->one('controller'); // float[]
$vectors = $embed->batch(['a', 'b', 'c']); // float[][]
$vec = $embed->one('controller'); / float[]
$vectors = $embed->batch(['a', 'b', 'c']); / float[][]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); // 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); // back to float[]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); / 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); / back to float[]
```
## Modèle : dédoublonner des chaînes similaires
```php
@@ -49,8 +49,8 @@ function bestTag(string $text, array $tagVecs, $embed): string {
return $best[0];
}
echo bestTag('User::isAuthorized', $tagVecs, $embed); // → 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); // → 'database' (probably)
echo bestTag('User::isAuthorized', $tagVecs, $embed); / 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); / 'database' (probably)
```
## Stockage
@@ -58,7 +58,7 @@ Les embeddings sont des tableaux de flottants — généralement 768 flottants p
Utilisez `Embed::pack()` pour les encoder en base64 comme des flottants sur 4 octets :
```php
$compact = Embed::pack($vec); // ~4 KB → ~5.3 KB base64 string
$compact = Embed::pack($vec); / ~4 KB ~5.3 KB base64 string
$vec = Embed::unpack($compact);
```
Le plugin RAG utilise ce format internalement pour ses fichiers JSON.

View File

@@ -57,7 +57,7 @@ echo $ai->chat()->ask('Explain MMVC in two sentences.');
// Multi-turn
$chat = $ai->chat();
$chat->user('How do I scaffold a module?');
$chat->user('And add Graylog hooks?'); // referrs to previous turn
$chat->user('And add Graylog hooks?'); / referrs to previous turn
echo $chat->complete();
// Override per call
@@ -80,7 +80,7 @@ $score = \Nibiru\Module\Ai\Plugin\Embed::cosine($va, $vb);
```
Stockage compact :
```php
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string, 4 bytes/dim
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string, 4 bytes/dim
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
```
### 3. RAG — ingérer, récupérer, ancrer
@@ -88,7 +88,7 @@ $vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
$rag = $ai->rag('product-help');
// One-time ingestion
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
$rag->ingestFile('/var/data/manual.pdf.txt');
@@ -105,9 +105,9 @@ use Nibiru\Module\Ai\Plugin\Tools;
$ai = new \Nibiru\Module\Ai\Ai();
$agent = $ai->agent()->withTools([
new Tools\PdoQuery(), // read-only SQL
new Tools\HttpGet(), // fetch URLs
new Tools\FileRead(), // read project files
new Tools\PdoQuery(), / read-only SQL
new Tools\HttpGet(), / fetch URLs
new Tools\FileRead(), / read project files
]);
echo $agent->run('How many active users registered last week?');
@@ -154,7 +154,7 @@ La philosophie de conception :
## Suivant
- [Référence du module de chat](/fr/ia/module/chat/)
- [Référence du module RAG](/fr/ia/module/rag/)
- [Référence du module agent](/fr/ia/module/agent/)
- [Formation nibiru-coder](/fr/ia/module/training/)
- [Référence du module de chat](/fr/ai/module/chat/)
- [Référence du module RAG](/fr/ai/module/rag/)
- [Référence du module agent](/fr/ai/module/agent/)
- [Formation nibiru-coder](/fr/ai/module/training/)

View File

@@ -10,9 +10,9 @@ Le plugin RAG est la fonctionnalité clé du module IA pour les constructeurs de
use Nibiru\Module\Ai\Ai;
$ai = new Ai();
$rag = $ai->rag('product-help'); // a named collection
$rag = $ai->rag('product-help'); / a named collection
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php under help/
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php under help/
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
echo $rag->ask('How do I cancel my subscription?');
@@ -46,20 +46,20 @@ $logs->ingestText($exception->__toString(), ['ts' => time()]);
```
## Référence de l'API
```php
$rag = $ai->rag('name'); // get/create a named collection
$rag = $ai->rag('name'); / get/create a named collection
// --- Ingestion ---
$rag->ingestText($text, $metadata = []); // single chunk
$count = $rag->ingestFile('path'); // returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); // recursive
$rag->ingestText($text, $metadata = []); / single chunk
$count = $rag->ingestFile('path'); / returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); / recursive
// --- Querying ---
$hits = $rag->search('query', $k = null); // [{score, text, metadata}, …]
$answer = $rag->ask('question', $k = null); // top-K → chat call
$hits = $rag->search('query', $k = null); / [{score, text, metadata}, ]
$answer = $rag->ask('question', $k = null); / top-K chat call
// --- Maintenance ---
$rag->reset(); // forget everything (deletes file)
$n = $rag->size(); // number of chunks
$rag->reset(); / forget everything (deletes file)
$n = $rag->size(); / number of chunks
```
## Réglages
@@ -95,5 +95,5 @@ rag.storage_path = "/../../application/module/ai/cache/rag/"
## ¿Qué sigue?
- [Plugin agent →](/fr/ia/module/agent/) pour les outils, pas la récupération.
- [Formation nibiru-coder →](/fr/ia/module/formation/) pour faire répondre le chat à moitié dans la voix du framework.
- [Plugin agent →](/fr/ai/module/agent/) pour les outils, pas la récupération.
- [Formation nibiru-coder →](/fr/ai/module/training/) pour faire répondre le chat à moitié dans la voix du framework.

View File

@@ -114,7 +114,7 @@ public function pageAction() {
View::forwardTo('/login');
return;
}
// ...
/ ...
}
```
Pour les vérifications basées sur le rôle, les applications de démonstration utilisent le plugin `Acl` du même module :
@@ -178,7 +178,7 @@ public function submitAction() {
http_response_code(419);
return;
}
// ...handle submission...
/ ...handle submission...
}
```
Intégrez `<input type="hidden" name="csrf" value="{$csrf}">` dans votre formulaire.

View File

@@ -82,19 +82,19 @@ password_hash = "another-salt-for-AES_DECRYPT"
## Lecture des configurations
```php
$cfg = \Nibiru\Config::getInstance()->getConfig();
$cfg['DATABASE']['driver']; // 'pdo'
$cfg['SETTINGS']['page.url']; // 'https://my-app.local'
$cfg['DATABASE']['driver']; / 'pdo'
$cfg['SETTINGS']['page.url']; / 'https://my-app.local'
```
Pour les configurations profondément imbriquées, utilisez les constantes typées de l'interface View :
```php
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; // ['/public/css/app.css']
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; / ['/public/css/app.css']
```
## Configurations des modules
Chaque module situé sous `application/module/<nom>/settings/` peut posséder ses propres fichiers INI. Le Registre les détecte automatiquement et les expose via :
```php
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime; // from [USERS] section in users.ini
$users->session_lifetime; / from [USERS] section in users.ini
```
Le Registre préfère `<module>.<env>.ini` par rapport à `<module>.ini`, donc vous obtenez des remplacements par environnement gratuitement.

View File

@@ -56,12 +56,12 @@ View::assign(['products' => $list]);
```
Aides pratiques du contrôleur de base :
```php
$this->getRequest('id', false); // $_REQUEST['id'] ?? false
$this->getPost('email', ''); // $_POST['email'] ?? ''
$this->getGet('page', 1); // $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); // $_SERVER['REQUEST_URI']
$this->getFiles('upload'); // $_FILES['upload']
$this->getSession('auth'); // $_SESSION['auth']
$this->getRequest('id', false); / $_REQUEST['id'] ?? false
$this->getPost('email', ''); / $_POST['email'] ?? ''
$this->getGet('page', 1); / $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); / $_SERVER['REQUEST_URI']
$this->getFiles('upload'); / $_FILES['upload']
$this->getSession('auth'); / $_SESSION['auth']
```
Ces éléments existent en raison du fait que `Controller` est compatible avec `final` : vous pouvez les simuler dans les tests en remplaçant par une classe enfant.
@@ -69,8 +69,8 @@ Ces éléments existent en raison du fait que `Controller` est compatible avec `
Pour rediriger à l'intérieur d'une action :
```php
View::forwardTo('/login'); // 302 to the URL, exits
View::forwardToJsonHeader(); // sets Content-Type: application/json
View::forwardTo('/login'); / 302 to the URL, exits
View::forwardToJsonHeader(); / sets Content-Type: application/json
```
`forwardToJsonHeader()` est le modèle canonique pour les points de terminaison JSON — définissez l'en-tête, attribuez `data`, puis retournez. La couche d'affichage s'occupe du reste.

View File

@@ -30,17 +30,17 @@ public function run() {
if (Config::getInstance()->getConfig()
[self::CONFIG_GENERATOR_SECTION][self::GENERATOR_DATABASE]) {
new Model(false); // 1. (re)generate models from schema
new Model(false); / 1. (re)generate models from schema
}
Router::getInstance()->route(); // 2. parse the URL
Auto::loader()->loadModelFiles(); // 3. load model files
Auto::loader()->loadModules(); // 4. load module classes
Router::getInstance()->route(); / 2. parse the URL
Auto::loader()->loadModelFiles(); / 3. load model files
Auto::loader()->loadModules(); / 4. load module classes
$tpl = Router::getInstance()->tplName();
$controllerFile = __DIR__ . "/../../application/controller/{$tpl}Controller.php";
if (is_file($controllerFile)) { // 5. controller file exists
if (is_file($controllerFile)) { / 5. controller file exists
require_once $controllerFile;
$class = "Nibiru\\{$tpl}Controller";
$controller = new $class();
@@ -49,7 +49,7 @@ public function run() {
$action = $_REQUEST['_action'] . 'Action';
$controller->navigationAction();
if (method_exists($controller, $action)) {
$controller->$action(); // 6. optional named action
$controller->$action(); / 6. optional named action
}
$controller->pageAction();
} else {
@@ -57,9 +57,9 @@ public function run() {
$controller->pageAction();
}
Display::getInstance()->display(); // 7. render Smarty
Display::getInstance()->display(); / 7. render Smarty
} else {
// 8. soft 404 — render the configured error controller
/ 8. soft 404 render the configured error controller
}
}
```

View File

@@ -40,8 +40,8 @@ addOpenSpan addCloseSpan
```
### Cycle de vie
```
create // reset the static buffer; call before building a new form
addForm // wrap the buffer in <form>...</form> and return as a string
create / reset the static buffer; call before building a new form
addForm / wrap the buffer in <form>...</form> and return as a string
```
:::caution[L'incréance de nommage est intentionnelle, mais pas complètement]
`addInputTypePassword` vs `addTypePassword`, `addInputTypeFileupload` vs `addTypeFileUpload` — le préfixe correspond à ce que l'élément soit un `<input type="…">` (préfixe Input) ou une autre balise (préfixe Type). C'est un peu inconfortable, mais stable ; les modèles de conception utilisés par la CLI `./nibiru -c` suivent le même modèle, donc l'habitude s'impose.
@@ -51,7 +51,7 @@ addForm // wrap the buffer in <form>...</form> and return as a string
```php
use Nibiru\Factory\Form;
Form::create(); // reset the static buffer
Form::create(); / reset the static buffer
Form::addOpenDiv(['class' => 'form-group']);
Form::addTypeLabel(['for' => 'login', 'value' => 'Username']);
@@ -187,7 +187,7 @@ class formsController extends Controller {
'required' => 'required',
'class' => 'contacts-input form-control',
]);
// ...more fields...
/ ...more fields...
$this->form = Form::addForm([
'name' => 'newregister',
'method' => 'post',

View File

@@ -147,9 +147,9 @@ allowed.roles[] = "standard"
Lisez-le à partir d'ailleurs :
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$cfg->session_lifetime; // 7200
$cfg->password_min_length; // 12
$cfg->allowed_roles; // [admin, editor, standard]
$cfg->session_lifetime; / 7200
$cfg->password_min_length; / 12
$cfg->allowed_roles; / [admin, editor, standard]
```
Superpositions d'environnement : un fichier nommé `users.production.ini` est préféré par rapport à `users.ini` lorsque `APPLICATION_ENV=production`.
@@ -162,7 +162,7 @@ $analytics = new \Nibiru\Module\Analytics\Analytics();
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Matomo());
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Plausible());
$analytics->trackPageView(); // internally calls notify()
$analytics->trackPageView(); / internally calls notify()
```
Chaque observateur reçoit l'instance d'analytics via sa méthode `update($subject)` et extrait les données d'événement dont il a besoin.
@@ -200,7 +200,7 @@ Les noms sont des **noms de dossiers en minuscules**, exactement tels qu'ils app
Les classes de plugin se trouvent dans l'espace de noms **pluriel** `Plugins`:
```php
// application/module/billing/plugins/invoice.php
namespace Nibiru\Module\Billing\Plugins; // ← plural
namespace Nibiru\Module\Billing\Plugins; / plural
class Invoice extends \Nibiru\Module\Billing\Billing { /* ... */ }
```
Ne correspondez pas à l'espace de noms et vous obtiendrez des manquements d'autoload. Le squelette CLI (`./nibiru -m billing`) génère l'espace de noms correct pour vous.
@@ -210,7 +210,7 @@ Ne correspondez pas à l'espace de noms et vous obtiendrez des manquements d'aut
Vous **ne** vous inscrivez pas les fichiers INI de votre module — le [Registry](/en/core/registry/) les découvre automatiquement en parcourant `application/module/<name>/settings/*.ini` après que `[AUTOLOADER]` a chargé la classe du module. Chaque section `[<MODULE>]` (en majuscules) d'un INI devient disponible comme :
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('billing');
$cfg->invoice_prefix; // [BILLING] invoice.prefixproperty
$cfg->invoice_prefix; / [BILLING] invoice.prefix property
```
Le Registre préfère `<module>.<env>.ini` (par exemple `billing.production.ini`) lorsque `APPLICATION_ENV` correspond.

View File

@@ -14,7 +14,7 @@ class productsController extends Controller
{
public function pageAction() {
$products = new products();
Pageination::setEntriesPerPage(25); // optional; default from INI
Pageination::setEntriesPerPage(25); / optional; default from INI
Pageination::setTable($products);
$rows = Pageination::loadTableAsArray();

View File

@@ -20,7 +20,7 @@ Pour chaque module sous `application/module/<nom>/settings/` :
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime;
$users->password_min_length;
$users->allowed_roles; // array
$users->allowed_roles; / array
```
À l'intérieur du module lui-même, la convention est d'envelopper cela dans un mutateur :
```php

View File

@@ -40,7 +40,7 @@ Tout ce qui se trouve après le segment d'action devient une clé `$_REQUEST` pa
// /users/edit/42 → $_REQUEST['id'] = '42'
public function editAction() {
$id = (int) ($_REQUEST['id'] ?? 0);
// ...
/ ...
}
```
Pour les paramètres non numériques ou nommés, privilégiez les chaînes de requête :
@@ -62,9 +62,9 @@ Lorsqu'une URL correspond au modèle, les groupes capturés sont attribués aux
## Aide aux routages
```php
Router::getInstance()->currentPage(); // 'products'
Router::getInstance()->tplName(); // 'products' (controller stem for templates)
Router::getInstance()->getController(); // alias for currentPage()
Router::getInstance()->currentPage(); / 'products'
Router::getInstance()->tplName(); / 'products' (controller stem for templates)
Router::getInstance()->getController(); / alias for currentPage()
```
Ces éléments sont utiles dans les contrôleurs et les modèles :
```smarty

View File

@@ -7,7 +7,7 @@ description: "Boutons, cartes, appels à laction, héros — prêts à être
Un rectangle noir sur crème. Éditorial. Pas de dégradé, pas d'éclairage.
```html
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/fr/start/installation/">
<span>Read the docs</span>
<span class="atelier-button__arrow" aria-hidden="true"></span>
</a>
@@ -162,7 +162,7 @@ Grille asymétrique à deux colonnes. Un grand numéro éditorial derrière le t
Nibiru is a modular PHP framework for builders who ship.
</p>
<div class="atelier-hero__cta">
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/fr/start/installation/">
Read the docs <span aria-hidden="true"></span>
</a>
</div>

View File

@@ -19,73 +19,25 @@ hero:
variant: minimal
---
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
import CometTrail from '../../../components/CometTrail.astro';
import MmvcStage from '../../../components/MmvcStage.astro';
import MissionControl from '../../../components/MissionControl.astro';
import LaunchSequence from '../../../components/LaunchSequence.astro';
import SpacecraftGrid from '../../../components/SpacecraftGrid.astro';
import EditorialContent from '../../../components/EditorialContent.astro';
import LandingFooter from '../../../components/LandingFooter.astro';
import ToTop from '../../../components/ToTop.astro';
import LandingScripts from '../../../components/LandingScripts.astro';
## Une constellation de capacités
<CometTrail />
<MmvcStage />
<MissionControl />
<LaunchSequence />
<SpacecraftGrid />
<EditorialContent />
<LandingFooter />
<ToTop />
<CardGrid stagger>
<Card title="Architecture MMVC" icon="puzzle">
Les modules enveloppent le MVC avec traits, plugins, interfaces et paramètres. Le second **M** est faiblement couplé par conception, avec le pattern observer `SplSubject` intégré.
</Card>
<Card title="Cœur multi-bases" icon="seti:db">
Cinq pilotes en orbite : `mysql`, `pdo`, `postgres` (ODBC), `psql` (libpq) et `postgresql`. Basculez en modifiant une seule clé INI.
</Card>
<Card title="Vues Smarty" icon="document">
Vues pilotées par templates, un assistant global `View::assign()`, et un cache chaud `templates_c`. Plus partiels partagés, includes de navigation et templates de pagination.
</Card>
<Card title="Constructeur de formulaires fluide" icon="pencil">
Plus de 28 types de champ — text, password, switch, color, range, file upload — composés via des appels statiques `Form::add…` et rendus en une seule chaîne HTML.
</Card>
<Card title="Véritable outil CLI" icon="seti:powershell">
`./nibiru` génère modules, contrôleurs, plugins, migrations et pages CMS. Il exécute les migrations contre `local`, `staging` ou `production`.
</Card>
<Card title="IA-natif, bientôt" icon="rocket">
Nibiru sera le premier framework PHP avec un <a href="/fr/ai/oracle/">Oracle basé sur RAG</a> entraîné sur sa propre connaissance — et un corpus publié pour de futurs fine-tunes.
</Card>
</CardGrid>
## Démarrage rapide
```bash
# Cloner
git clone https://github.com/alllinux/Nibiru mon-app && cd mon-app
# Installer les dépendances PHP (Smarty, PHPMailer, Guzzle, …)
composer install
# Permissions + amorçage des dossiers
./nibiru -s
# Première migration
./nibiru -mi local
# Générer un contrôleur
./nibiru -c products
```
```php
// application/controller/productsController.php
namespace Nibiru;
use Nibiru\Adapter\Controller;
class productsController extends Controller {
public function pageAction() {
View::assign([
'title' => 'Produits — Nibiru',
'products' => [['id' => 1, 'name' => 'Plaquage d\'or Marduk']],
]);
}
public function navigationAction() {
JsonNavigation::getInstance()->loadJsonNavigationArray();
}
}
```
## Où aller ensuite
<CardGrid>
<LinkCard title="Qu'est-ce que Nibiru ?" href="/fr/start/what-is-nibiru/" description="La visite de 90 secondes : MMVC, le dispatcher, le cycle de vie des requêtes." />
<LinkCard title="Architecture" href="/core/architecture/" description="Comment modules, contrôleurs, vues et registre orbitent les uns autour des autres." />
<LinkCard title="Vitrine" href="/showcase/projects/" description="De vraies apps en production sur Nibiru — facturation, e-commerce, PIM industriel." />
<LinkCard title="Interroger l'Oracle" href="/fr/ai/oracle/" description="Ouvrez le chat flottant. L'Oracle est ancré dans cette documentation même." />
</CardGrid>
{/* Loads three.js + the original mockup scene code. MUST be the last node so
every #id the scene targets exists in the DOM when the script runs. */}
<LandingScripts />

View File

@@ -61,7 +61,7 @@ Plusieurs suivi sans couplage avec le contrôleur.
$analytics = new Analytics();
$analytics->attach(new Plugin\Matomo());
$analytics->attach(new Plugin\Plausible());
$analytics->trackPageView(); // calls notify() internally
$analytics->trackPageView(); / calls notify() internally
```
Chaque observateur appelle uniquement les champs dont il s'occupe avec sa méthode `update($subject)`. Ajouter un suivi est une modification d'une seule ligne.

View File

@@ -55,7 +55,7 @@ public function detailAction()
try {
$machine = Machine::init()->getMachine((int) $machineId);
} catch (\Throwable $e) {
$machine = null; // DB blip → page still renders with fallback.
$machine = null; / DB blip page still renders with fallback.
}
$machineName = $machine['ms_machines_name'] ?? "Maschine #$machineId";
@@ -120,7 +120,7 @@ Les cinq différences ci-dessous sont tirées des bases de code ci-dessus. Chacu
| Authentification | 3 lignes dans le constructeur du contrôleur. | Pile de middlewares + classes de politique + portails. |
| Événements | `SplSubject` + `SplObserver` de la bibliothèque standard PHP. | Dispatcheur d'événements personnalisé + registre d'écouteurs + file d'attente. |
Lisez le [détail complet avec des références de code →](/fr/pourquoi-nibiru/)
Lisez le [détail complet avec des références de code →](/fr/why-nibiru/)
---

View File

@@ -50,7 +50,7 @@ class Cms implements Interfaces\Cms, SplSubject
use Traits\PageBuilderForm;
use Traits\CmsPageStructureModifier;
use Traits\FormElements;
// …8 more traits
/ …8 more traits
}
```
**Effet net**: aucune injection de constructeur, aucune inscription auprès du fournisseur de services, aucun appel à `bind()` / `singleton()` dans un fichier de configuration. Un nouveau développeur peut rechercher le nom du trait et voir tous les appels.
@@ -108,7 +108,7 @@ Le contrôleur API adopte une approche inverse : une liste blanche des points de
```php
// public endpoints can be listed up-front, auth wraps the rest.
if (in_array($action, ['category', 'machines', 'ollama', 'team'])) {
// public, skip auth
/ public, skip auth
} else {
$this->user = new User();
$this->acl = new Acl();
@@ -137,8 +137,8 @@ class Machineryscout implements IModule, \SplSubject
}
public function indexMachines(): void {
// …do the work…
$this->notify(); // analytics, cache invalidator, audit log all see it.
/ …do the work…
$this->notify(); / analytics, cache invalidator, audit log all see it.
}
}
```
@@ -154,4 +154,4 @@ Un développeur solo ou une petite équipe peut construire et *exploiter* une v
Si vous préférez voir votre code, prenez-le.
→ [Lisez la présentation →](/fr/presentation/projets/)
→ [Lisez la présentation →](/fr/showcase/projects/)

View File

@@ -60,7 +60,7 @@ OpenAIのfine-tune、AnthropicのAPI評価、ほとんどのLoRAツールAxol
"content": "Modules implementing `SplSubject` can broadcast events…"
}
```
これは[Oracle](/ai/oracle/)が内部で使用している正確なファイルです。
これは[Oracle](/ja/ai/oracle/)が内部で使用している正確なファイルです。
## チャンクの導出方法

View File

@@ -10,19 +10,19 @@ description: "単一または複数のターンで行われる、任意のOllama
$ai = new \Nibiru\Module\Ai\Ai();
$chat = $ai->chat();
$chat->system('Be terse.'); // optional system prompt
$chat->model('qwen2.5-coder:14b'); // override the configured model
$chat->temperature(0.2); // override config
$chat->maxTokens(512); // override config
$chat->system('Be terse.'); / optional system prompt
$chat->model('qwen2.5-coder:14b'); / override the configured model
$chat->temperature(0.2); / override config
$chat->maxTokens(512); / override config
$chat->user('Hello'); // append a user message
$chat->assistant('Hi.'); // append an assistant message (rare)
$chat->user('Hello'); / append a user message
$chat->assistant('Hi.'); / append an assistant message (rare)
$reply = $chat->complete(); // run the call, return text
$reply = $chat->ask('How are you?'); // = ->user(...)->complete()
$reply = $chat->complete(); / run the call, return text
$reply = $chat->ask('How are you?'); / = ->user(...)->complete()
$chat->reset(); // clear messages, keep model + system
$chat->history(); // [{role, content}, …]
$chat->reset(); / clear messages, keep model + system
$chat->history(); / [{role, content}, ]
```
## 一発
```php
@@ -35,10 +35,10 @@ echo (new \Nibiru\Module\Ai\Ai())
$chat = $ai->chat();
$chat->user('Name three Nibiru singletons.');
$singletons = $chat->complete(); // appended to history
$singletons = $chat->complete(); / appended to history
$chat->user('What does the second one do?');
$detail = $chat->complete(); // model has full context
$detail = $chat->complete(); / model has full context
```
## モデルとスタイルを個別呼び出しごとに上書きする
```php
@@ -65,7 +65,7 @@ chat.provider = "anthropic"
anthropic.api_key = "sk-ant-..."
anthropic.model = "claude-haiku-4-5-20251001"
```
チャットプラグインはまだフレームワークモジュールにAnthropicトランスポートを含んでいません — 現在、ドキュメントサイトの`scripts/lib/providers.mjs`パターンが参考となっています。([マイルストーン](/ja/ai/milestones/)をご覧ください。)
チャットプラグインはまだフレームワークモジュールにAnthropicトランスポートを含んでいません — 現在、ドキュメントサイトの`scripts/lib/providers.mjs`パターンが参考となっています。([マイルストーン](/ja/ai/roadmap/)をご覧ください。)
## 実践的なパターン: チャットをアクションとして
```php

View File

@@ -9,12 +9,12 @@ Embedプラグインは、Ollamaの`/api/embeddings`に薄いラッパーであ
```php
$embed = (new \Nibiru\Module\Ai\Ai())->embed();
$vec = $embed->one('controller'); // float[]
$vectors = $embed->batch(['a', 'b', 'c']); // float[][]
$vec = $embed->one('controller'); / float[]
$vectors = $embed->batch(['a', 'b', 'c']); / float[][]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); // 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); // back to float[]
$score = \Nibiru\Module\Ai\Plugin\Embed::cosine($a, $b); / 0..1
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed); / back to float[]
```
## パターン: 遠近似の文字列を重複除去する
```php
@@ -49,8 +49,8 @@ function bestTag(string $text, array $tagVecs, $embed): string {
return $best[0];
}
echo bestTag('User::isAuthorized', $tagVecs, $embed); // → 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); // → 'database' (probably)
echo bestTag('User::isAuthorized', $tagVecs, $embed); / 'authentication'
echo bestTag('Pageination::setTable', $tagVecs, $embed); / 'database' (probably)
```
## ストレージ
@@ -58,7 +58,7 @@ echo bestTag('Pageination::setTable', $tagVecs, $embed); // → 'database' (prob
`Embed::pack()` を使用して、それらを 4 バイトの浮動小数点数として base64 エンコードします。
```php
$compact = Embed::pack($vec); // ~4 KB → ~5.3 KB base64 string
$compact = Embed::pack($vec); / ~4 KB ~5.3 KB base64 string
$vec = Embed::unpack($compact);
```
RAG プラグインは、この形式を使用して内部の JSON ファイルを管理しています。

View File

@@ -57,7 +57,7 @@ echo $ai->chat()->ask('Explain MMVC in two sentences.');
// Multi-turn
$chat = $ai->chat();
$chat->user('How do I scaffold a module?');
$chat->user('And add Graylog hooks?'); // referrs to previous turn
$chat->user('And add Graylog hooks?'); / referrs to previous turn
echo $chat->complete();
// Override per call
@@ -80,7 +80,7 @@ $score = \Nibiru\Module\Ai\Plugin\Embed::cosine($va, $vb);
```
コンパクトなストレージ:
```php
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); // base64 string, 4 bytes/dim
$packed = \Nibiru\Module\Ai\Plugin\Embed::pack($vec); / base64 string, 4 bytes/dim
$vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
```
### 3. RAG — 収集、検索、基準化
@@ -88,7 +88,7 @@ $vec = \Nibiru\Module\Ai\Plugin\Embed::unpack($packed);
$rag = $ai->rag('product-help');
// One-time ingestion
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
$rag->ingestFile('/var/data/manual.pdf.txt');
@@ -105,9 +105,9 @@ use Nibiru\Module\Ai\Plugin\Tools;
$ai = new \Nibiru\Module\Ai\Ai();
$agent = $ai->agent()->withTools([
new Tools\PdoQuery(), // read-only SQL
new Tools\HttpGet(), // fetch URLs
new Tools\FileRead(), // read project files
new Tools\PdoQuery(), / read-only SQL
new Tools\HttpGet(), / fetch URLs
new Tools\FileRead(), / read project files
]);
echo $agent->run('How many active users registered last week?');

View File

@@ -10,9 +10,9 @@ RAG プラグインは、製品ビルダーにとって AI モジュールのキ
use Nibiru\Module\Ai\Ai;
$ai = new Ai();
$rag = $ai->rag('product-help'); // a named collection
$rag = $ai->rag('product-help'); / a named collection
$rag->ingestDir(__DIR__ . '/help/'); // walks .md/.txt/.php under help/
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php under help/
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
echo $rag->ask('How do I cancel my subscription?');
@@ -46,20 +46,20 @@ $logs->ingestText($exception->__toString(), ['ts' => time()]);
```
## API リファレンス
```php
$rag = $ai->rag('name'); // get/create a named collection
$rag = $ai->rag('name'); / get/create a named collection
// --- Ingestion ---
$rag->ingestText($text, $metadata = []); // single chunk
$count = $rag->ingestFile('path'); // returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); // recursive
$rag->ingestText($text, $metadata = []); / single chunk
$count = $rag->ingestFile('path'); / returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); / recursive
// --- Querying ---
$hits = $rag->search('query', $k = null); // [{score, text, metadata}, …]
$answer = $rag->ask('question', $k = null); // top-K → chat call
$hits = $rag->search('query', $k = null); / [{score, text, metadata}, ]
$answer = $rag->ask('question', $k = null); / top-K chat call
// --- Maintenance ---
$rag->reset(); // forget everything (deletes file)
$n = $rag->size(); // number of chunks
$rag->reset(); / forget everything (deletes file)
$n = $rag->size(); / number of chunks
```
## チューニングの調整項目

View File

@@ -114,7 +114,7 @@ public function pageAction() {
View::forwardTo('/login');
return;
}
// ...
/ ...
}
```
ロール認識のチェックのために、デモンストレーションアプリケーションは同じモジュールから `Acl` プラグインを使用しています。
@@ -178,7 +178,7 @@ public function submitAction() {
http_response_code(419);
return;
}
// ...handle submission...
/ ...handle submission...
}
```
フォームに `<input type="hidden" name="csrf" value="{$csrf}">` を埋め込んでください。

View File

@@ -82,19 +82,19 @@ password_hash = "another-salt-for-AES_DECRYPT"
## 設定の読み込み
```php
$cfg = \Nibiru\Config::getInstance()->getConfig();
$cfg['DATABASE']['driver']; // 'pdo'
$cfg['SETTINGS']['page.url']; // 'https://my-app.local'
$cfg['DATABASE']['driver']; / 'pdo'
$cfg['SETTINGS']['page.url']; / 'https://my-app.local'
```
深くネストされた設定には、View インターフェースから型付けされた定数を使用してください。
```php
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; // ['/public/css/app.css']
$cfg[\Nibiru\View::NIBIRU_SETTINGS]['smarty.css']; / ['/public/css/app.css']
```
## モジュールの設定
各モジュールの `application/module/<name>/settings/` 以下には独自の INI ファイルを配置できます。Registry はそれらを自動的に取り込み、以下の通りに公開します:
```php
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime; // from [USERS] section in users.ini
$users->session_lifetime; / from [USERS] section in users.ini
```
レジストリは `<module>.<env>.ini``<module>.ini` よりも優先します。これにより、環境ごとのオーバーライドが無料で利用できます。

View File

@@ -56,12 +56,12 @@ View::assign(['products' => $list]);
```
ベースコントローラーからの便利ヘルパー:
```php
$this->getRequest('id', false); // $_REQUEST['id'] ?? false
$this->getPost('email', ''); // $_POST['email'] ?? ''
$this->getGet('page', 1); // $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); // $_SERVER['REQUEST_URI']
$this->getFiles('upload'); // $_FILES['upload']
$this->getSession('auth'); // $_SESSION['auth']
$this->getRequest('id', false); / $_REQUEST['id'] ?? false
$this->getPost('email', ''); / $_POST['email'] ?? ''
$this->getGet('page', 1); / $_GET['page'] ?? 1
$this->getServer('REQUEST_URI'); / $_SERVER['REQUEST_URI']
$this->getFiles('upload'); / $_FILES['upload']
$this->getSession('auth'); / $_SESSION['auth']
```
これらは存在する理由は、`Controller``final`に耐えられるように設計されていることです:テストで子クラスを置き換えてモックすることができます。
@@ -69,8 +69,8 @@ $this->getSession('auth'); // $_SESSION['auth']
アクション内でリダイレクトするには:
```php
View::forwardTo('/login'); // 302 to the URL, exits
View::forwardToJsonHeader(); // sets Content-Type: application/json
View::forwardTo('/login'); / 302 to the URL, exits
View::forwardToJsonHeader(); / sets Content-Type: application/json
```
`forwardToJsonHeader()` は、JSON エンドポイントの標準的なパターンです。ヘッダーを設定し、`data` を割り当ててから返す。その後、表示層が残りの処理を行います。

View File

@@ -30,17 +30,17 @@ public function run() {
if (Config::getInstance()->getConfig()
[self::CONFIG_GENERATOR_SECTION][self::GENERATOR_DATABASE]) {
new Model(false); // 1. (re)generate models from schema
new Model(false); / 1. (re)generate models from schema
}
Router::getInstance()->route(); // 2. parse the URL
Auto::loader()->loadModelFiles(); // 3. load model files
Auto::loader()->loadModules(); // 4. load module classes
Router::getInstance()->route(); / 2. parse the URL
Auto::loader()->loadModelFiles(); / 3. load model files
Auto::loader()->loadModules(); / 4. load module classes
$tpl = Router::getInstance()->tplName();
$controllerFile = __DIR__ . "/../../application/controller/{$tpl}Controller.php";
if (is_file($controllerFile)) { // 5. controller file exists
if (is_file($controllerFile)) { / 5. controller file exists
require_once $controllerFile;
$class = "Nibiru\\{$tpl}Controller";
$controller = new $class();
@@ -49,7 +49,7 @@ public function run() {
$action = $_REQUEST['_action'] . 'Action';
$controller->navigationAction();
if (method_exists($controller, $action)) {
$controller->$action(); // 6. optional named action
$controller->$action(); / 6. optional named action
}
$controller->pageAction();
} else {
@@ -57,9 +57,9 @@ public function run() {
$controller->pageAction();
}
Display::getInstance()->display(); // 7. render Smarty
Display::getInstance()->display(); / 7. render Smarty
} else {
// 8. soft 404 — render the configured error controller
/ 8. soft 404 render the configured error controller
}
}
```

View File

@@ -40,8 +40,8 @@ addOpenSpan addCloseSpan
```
### ライフサイクル
```
create // reset the static buffer; call before building a new form
addForm // wrap the buffer in <form>...</form> and return as a string
create / reset the static buffer; call before building a new form
addForm / wrap the buffer in <form>...</form> and return as a string
```
:::caution[名前の不一致は意図的なもの、ある程度]
`addInputTypePassword` vs `addTypePassword`, `addInputTypeFileupload` vs `addTypeFileUpload` — プレフィックスが要素が `<input type="…">` (Input プレフィックス) であるかどうかInput プレフィックスか、他のタグType プレフィックスであるかどうかに一致します。これは奇妙ですが安定していますCLI の `./nibiru -c` スキャフォールディングは同じパターンを使用しているため、筋肉記憶が働きます。
@@ -51,7 +51,7 @@ addForm // wrap the buffer in <form>...</form> and return as a string
```php
use Nibiru\Factory\Form;
Form::create(); // reset the static buffer
Form::create(); / reset the static buffer
Form::addOpenDiv(['class' => 'form-group']);
Form::addTypeLabel(['for' => 'login', 'value' => 'Username']);
@@ -187,7 +187,7 @@ class formsController extends Controller {
'required' => 'required',
'class' => 'contacts-input form-control',
]);
// ...more fields...
/ ...more fields...
$this->form = Form::addForm([
'name' => 'newregister',
'method' => 'post',

View File

@@ -147,9 +147,9 @@ allowed.roles[] = "standard"
どこからでも読み返す:
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$cfg->session_lifetime; // 7200
$cfg->password_min_length; // 12
$cfg->allowed_roles; // [admin, editor, standard]
$cfg->session_lifetime; / 7200
$cfg->password_min_length; / 12
$cfg->allowed_roles; / [admin, editor, standard]
```
環境オーバーレイ:`APPLICATION_ENV=production` の場合、`users.production.ini``users.ini` よりも優先されます。
@@ -162,7 +162,7 @@ $analytics = new \Nibiru\Module\Analytics\Analytics();
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Matomo());
$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Plausible());
$analytics->trackPageView(); // internally calls notify()
$analytics->trackPageView(); / internally calls notify()
```
各観察者の `update($subject)` は、分析インスタンスを受け取り、関心のあるイベントデータを取得します。
@@ -200,7 +200,7 @@ class.plugin.pos[] = "" ; reserved
プラグインクラスは、**複数形の**名前空間 `Plugins` の下にあります:
```php
// application/module/billing/plugins/invoice.php
namespace Nibiru\Module\Billing\Plugins; // ← plural
namespace Nibiru\Module\Billing\Plugins; / plural
class Invoice extends \Nibiru\Module\Billing\Billing { /* ... */ }
```
名前空間が一致しないと、オートローダーのミスが発生します。CLI スキャフォールド (`./nibiru -m billing`) は正しい名前空間を生成してくれます。
@@ -210,7 +210,7 @@ class Invoice extends \Nibiru\Module\Billing\Billing { /* ... */ }
モジュールの INI ファイルを **登録しないでください** — [Registry](/en/core/registry/) は、`[AUTOLOADER]` がモジュールクラスを読み込んだ後、`application/module/<name>/settings/*.ini` を走査して自動的に発見します。各 INI の `[<MODULE>]`(大文字)セクションは次のようになります:
```php
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('billing');
$cfg->invoice_prefix; // [BILLING] invoice.prefixproperty
$cfg->invoice_prefix; / [BILLING] invoice.prefix property
```
レジストリは、`APPLICATION_ENV` が一致する場合に `<module>.<env>.ini`(例:`billing.production.ini`)を優先します。

View File

@@ -14,7 +14,7 @@ class productsController extends Controller
{
public function pageAction() {
$products = new products();
Pageination::setEntriesPerPage(25); // optional; default from INI
Pageination::setEntriesPerPage(25); / optional; default from INI
Pageination::setTable($products);
$rows = Pageination::loadTableAsArray();

View File

@@ -20,7 +20,7 @@ description: "モジュールが自動的に検出され、その設定が実行
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime;
$users->password_min_length;
$users->allowed_roles; // array
$users->allowed_roles; / array
```
モジュール自体では、この内容をセッターでラップする慣習があります。
```php

View File

@@ -40,7 +40,7 @@ Nibiru は、どの設定も不要で SEO フレンドリーな URL を自動検
// /users/edit/42 → $_REQUEST['id'] = '42'
public function editAction() {
$id = (int) ($_REQUEST['id'] ?? 0);
// ...
/ ...
}
```
数値的または名前付きパラメータ以外の場合、クエリ文字列を使用することをお勧めします。
@@ -62,9 +62,9 @@ api.v1.products.params[] = "id"
## ルーティングヘルパー
```php
Router::getInstance()->currentPage(); // 'products'
Router::getInstance()->tplName(); // 'products' (controller stem for templates)
Router::getInstance()->getController(); // alias for currentPage()
Router::getInstance()->currentPage(); / 'products'
Router::getInstance()->tplName(); / 'products' (controller stem for templates)
Router::getInstance()->getController(); / alias for currentPage()
```
これらはコントローラーとテンプレート内で役立ちます:
```smarty

View File

@@ -7,7 +7,7 @@ description: "ボタン、カード、コールアウト、ヒーロー — コ
黒い文字がクレーム色の背景にある長方形。エディタリー風。グラデーションや光沢はありません。
```html
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/ja/start/installation/">
<span>Read the docs</span>
<span class="atelier-button__arrow" aria-hidden="true"></span>
</a>
@@ -162,7 +162,7 @@ description: "ボタン、カード、コールアウト、ヒーロー — コ
Nibiru is a modular PHP framework for builders who ship.
</p>
<div class="atelier-hero__cta">
<a class="atelier-button atelier-button--primary" href="/en/start/">
<a class="atelier-button atelier-button--primary" href="/ja/start/installation/">
Read the docs <span aria-hidden="true"></span>
</a>
</div>

Some files were not shown because too many files have changed in this diff Show More