prisma-php 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/docs/components.md
CHANGED
|
@@ -69,13 +69,89 @@ This is the right mental model for:
|
|
|
69
69
|
- componentized partials that PulsePoint should hydrate later
|
|
70
70
|
- keeping PHP templating ergonomics while still producing component-aware markup
|
|
71
71
|
|
|
72
|
-
For `ImportComponent`, think in terms of a
|
|
72
|
+
For `ImportComponent`, think in terms of a single-root component boundary: one parent element defines the island boundary, Prisma PHP serializes props onto that root, and the framework injects a stable `pp-component` attribute there. Do not design imported partials as loose sibling markup.
|
|
73
73
|
|
|
74
74
|
AI must not collapse these two models into one.
|
|
75
75
|
|
|
76
76
|
- **PHPX** is for class-based component authoring.
|
|
77
77
|
- **`ImportComponent`** is for importing PHP partial files as single-root component islands.
|
|
78
78
|
|
|
79
|
+
## Important distinction: route files vs imported partials
|
|
80
|
+
|
|
81
|
+
This is the route/component distinction AI must keep straight.
|
|
82
|
+
|
|
83
|
+
### Normal route files
|
|
84
|
+
|
|
85
|
+
For a normal route file such as `src/app/index.php` or nested `layout.php`, use this structure:
|
|
86
|
+
|
|
87
|
+
1. PHP
|
|
88
|
+
2. one parent HTML element for the route content
|
|
89
|
+
3. one `<script>` block after that parent element
|
|
90
|
+
|
|
91
|
+
Example route-file pattern:
|
|
92
|
+
|
|
93
|
+
```php filename="src/app/dashboard/index.php"
|
|
94
|
+
<?php
|
|
95
|
+
|
|
96
|
+
$title = 'Dashboard';
|
|
97
|
+
?>
|
|
98
|
+
|
|
99
|
+
<section class="dashboard-page">
|
|
100
|
+
<h1><?= htmlspecialchars($title) ?></h1>
|
|
101
|
+
<p>Count: {count}</p>
|
|
102
|
+
</section>
|
|
103
|
+
|
|
104
|
+
<script>
|
|
105
|
+
const [count, setCount] = pp.state(0);
|
|
106
|
+
</script>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
That is the correct route-page pattern. It is documented in `layouts-and-pages.md`, not in `ImportComponent`.
|
|
110
|
+
|
|
111
|
+
### Imported partials rendered with `ImportComponent`
|
|
112
|
+
|
|
113
|
+
For an imported partial, the file itself must emit exactly **one root element**. If the partial needs client script, place that script **inside** the parent root element.
|
|
114
|
+
|
|
115
|
+
Correct imported-partial pattern:
|
|
116
|
+
|
|
117
|
+
```php filename="src/app/inc/SearchBox.php"
|
|
118
|
+
<?php
|
|
119
|
+
|
|
120
|
+
$title = 'Search';
|
|
121
|
+
?>
|
|
122
|
+
|
|
123
|
+
<div class="rounded-lg border bg-card p-4" pp-component="search-box">
|
|
124
|
+
<h2 class="font-medium"><?= htmlspecialchars($title) ?></h2>
|
|
125
|
+
<input value="{query}" oninput="{(e) => setQuery(e.target.value)}" />
|
|
126
|
+
<script>
|
|
127
|
+
console.log('Search component ready');
|
|
128
|
+
</script>
|
|
129
|
+
</div>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Incorrect imported-partial pattern:
|
|
133
|
+
|
|
134
|
+
```php filename="src/app/inc/SearchBox.php"
|
|
135
|
+
<?php
|
|
136
|
+
|
|
137
|
+
$title = 'Search';
|
|
138
|
+
?>
|
|
139
|
+
|
|
140
|
+
<section class="rounded-lg border bg-card p-4">
|
|
141
|
+
<h2 class="font-medium"><?= htmlspecialchars($title) ?></h2>
|
|
142
|
+
</section>
|
|
143
|
+
|
|
144
|
+
<script>
|
|
145
|
+
console.log('This script is a second root element');
|
|
146
|
+
</script>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Why this is invalid:
|
|
150
|
+
|
|
151
|
+
- the `<section>` is one root element
|
|
152
|
+
- the sibling `<script>` is a second root element
|
|
153
|
+
- `ImportComponent` requires the file to resolve to **exactly one root element**
|
|
154
|
+
|
|
79
155
|
## Important AI rules for Prisma PHP components
|
|
80
156
|
|
|
81
157
|
- treat the official Prisma PHP component docs as the source of truth
|
|
@@ -91,6 +167,8 @@ AI must not collapse these two models into one.
|
|
|
91
167
|
- when using `ImportComponent`, always ensure the imported file renders **exactly one root element**
|
|
92
168
|
- treat the `ImportComponent` root as the real component boundary because Prisma PHP serializes props onto it and injects `pp-component`
|
|
93
169
|
- do not manually add `pp-component` inside imported partial source; let Prisma PHP inject it
|
|
170
|
+
- do not apply the imported-partial rule to normal route files
|
|
171
|
+
- do not apply the normal route-file pattern to imported partials
|
|
94
172
|
|
|
95
173
|
## Component file placement and naming
|
|
96
174
|
|
package/dist/docs/index.md
CHANGED
|
@@ -8,7 +8,7 @@ related:
|
|
|
8
8
|
- /docs/get-started
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
{/_AI agent hint: Prisma PHP uses local installed docs as the source of truth for the active project version. Before generating framework-specific code, read `prisma-php.json` first, then read the relevant docs from `node_modules/prisma-php/dist/docs`. For authentication, read `authentication.md` first, then verify the official auth docs: `auth-get-started`, `credentials`, and `state-manager-auth`. For file uploads, `multipart/form-data`, `$_FILES`, `PP\FileManager\UploadFile`, rename/delete flows, or file manager screens, read `file-manager.md` first, then verify the official File Manager docs: `get-started-file`. For ORM work, read `prisma-php-orm.md` before choosing schema, migration, or generation commands. For PulsePoint runtime behavior specifically, read `pulsepoint.md` before generating reactive UI code. For normal interactive full-stack page work, default to PulsePoint plus `pp.fetchFunction(...)` unless the user explicitly asks for a PHP-only interaction style.
|
|
11
|
+
{/_AI agent hint: Prisma PHP uses local installed docs as the source of truth for the active project version. Before generating framework-specific code, read `prisma-php.json` first, then read the relevant docs from `node_modules/prisma-php/dist/docs`. For authentication, read `authentication.md` first, then verify the official auth docs: `auth-get-started`, `credentials`, and `state-manager-auth`. For file uploads, `multipart/form-data`, `$_FILES`, `PP\FileManager\UploadFile`, rename/delete flows, or file manager screens, read `file-manager.md` first, then verify the official File Manager docs: `get-started-file`. For ORM work, read `prisma-php-orm.md` before choosing schema, migration, or generation commands. For PulsePoint runtime behavior specifically, read `pulsepoint.md` before generating reactive UI code. For normal interactive full-stack page work, default to PulsePoint plus `pp.fetchFunction(...)` unless the user explicitly asks for a PHP-only interaction style. For normal PulsePoint-aware route files such as `index.php` and nested `layout.php`, keep PHP first, HTML second, and one `<script>` block last, with the rendered route content inside a single parent HTML element that acts as the route-view boundary. For imported partial components rendered with `ImportComponent::render(...)`, keep exactly one root element and place any component-local `<script>` inside that root because Prisma PHP uses that root as the component boundary where serialized props and `pp-component` attach. Do not confuse the route-file pattern with the imported-partial pattern. For backend validation, sanitization, `Validator`, `Rule`, `pp.fetchFunction(...)` validation flows, or request validation in `route.php`, read `validator.md` first, then use `fetching-data.md`, `error-handling.md`, and `route-handlers.md` for context-specific patterns, then consult the official Validator docs. `PP\Validator` is a Prisma PHP core class located in `vendor/tsnc/prisma-php/src/Validator.php`. Route creation is file-based from `src/app`; Prisma PHP auto-generates route listings such as `files-list.json`, so AI agents must not create, edit, or maintain that file manually._/}
|
|
12
12
|
|
|
13
13
|
Welcome to the Prisma PHP documentation!
|
|
14
14
|
|
|
@@ -45,6 +45,69 @@ For typical full-stack Prisma PHP work, AI should assume this default:
|
|
|
45
45
|
|
|
46
46
|
Do **not** default to PHP-only interaction flows for normal reactive UI work unless the user explicitly asks for that style.
|
|
47
47
|
|
|
48
|
+
### Important structure rule
|
|
49
|
+
|
|
50
|
+
There are **two different valid structures** that AI must not mix up.
|
|
51
|
+
|
|
52
|
+
#### 1. Normal route files
|
|
53
|
+
|
|
54
|
+
For a normal route file such as `src/app/index.php` or nested `layout.php`, use:
|
|
55
|
+
|
|
56
|
+
1. PHP
|
|
57
|
+
2. one parent HTML element
|
|
58
|
+
3. one `<script>` block after that parent element
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
|
|
62
|
+
```php filename="src/app/index.php"
|
|
63
|
+
<?php
|
|
64
|
+
|
|
65
|
+
use PP\MainLayout;
|
|
66
|
+
|
|
67
|
+
MainLayout::$title = 'Todos';
|
|
68
|
+
MainLayout::$description = 'Track tasks and view the current item count.';
|
|
69
|
+
?>
|
|
70
|
+
|
|
71
|
+
<section>
|
|
72
|
+
<h1>Todos</h1>
|
|
73
|
+
<p>Count: {count}</p>
|
|
74
|
+
</section>
|
|
75
|
+
|
|
76
|
+
<script>
|
|
77
|
+
const [count, setCount] = pp.state(0);
|
|
78
|
+
</script>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For SEO metadata, prefer `MainLayout::$title` and `MainLayout::$description` instead of relying on a local heading variable alone.
|
|
82
|
+
|
|
83
|
+
#### 2. Imported partials rendered with `ImportComponent`
|
|
84
|
+
|
|
85
|
+
For an imported partial component, use:
|
|
86
|
+
|
|
87
|
+
1. PHP
|
|
88
|
+
2. exactly one parent root element containing the component markup
|
|
89
|
+
3. any component-local `<script>` **inside** that root element
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
|
|
93
|
+
```php filename="src/app/inc/SearchBox.php"
|
|
94
|
+
<?php
|
|
95
|
+
|
|
96
|
+
// PHP Code
|
|
97
|
+
|
|
98
|
+
?>
|
|
99
|
+
|
|
100
|
+
<div class="rounded-lg border p-4" pp-component="search-box">
|
|
101
|
+
<h2>Search</h2>
|
|
102
|
+
<input value="{query}" />
|
|
103
|
+
<script>
|
|
104
|
+
console.log('Search component ready');
|
|
105
|
+
</script>
|
|
106
|
+
</div>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Do not confuse the route-file pattern with the `ImportComponent` partial pattern.
|
|
110
|
+
|
|
48
111
|
### Read this doc when you need
|
|
49
112
|
|
|
50
113
|
- **project setup or file placement** → `project-structure.md`
|
|
@@ -72,7 +135,8 @@ Do **not** default to PHP-only interaction flows for normal reactive UI work unl
|
|
|
72
135
|
- do not create, edit, or maintain `files-list.json`; Prisma PHP generates route listings automatically
|
|
73
136
|
- when building interactive frontend behavior, prefer the documented PulsePoint pattern with browser-side reactive state and `pp.fetchFunction(...)` for server calls; treat this as the default unless the user explicitly asks for a PHP-only interaction pattern
|
|
74
137
|
- when building PulsePoint inside `index.php` or `layout.php`, read `layouts-and-pages.md` together with `pulsepoint.md`, use PHP then HTML then one `<script>` block, keep route content inside a single parent HTML element, and treat that root as the route-view boundary
|
|
75
|
-
- when importing a PHP partial with `ImportComponent`, require exactly one root element because Prisma PHP attaches serialized props and a stable `pp-component` attribute to that root
|
|
138
|
+
- when importing a PHP partial with `ImportComponent`, require exactly one root element and keep any partial-local `<script>` inside that root because Prisma PHP attaches serialized props and a stable `pp-component` attribute to that root
|
|
139
|
+
- do not manually sprinkle `pp-component` across normal route markup
|
|
76
140
|
- when building backend validation logic, read `validator.md` first, then use the route-specific docs for the request entry point
|
|
77
141
|
- when using `pp.fetchFunction(...)`, expose the PHP function explicitly with `#[Exposed]`
|
|
78
142
|
- when changing feature flags, update `prisma-php.json` first, then follow the documented update workflow
|
|
@@ -15,7 +15,7 @@ related:
|
|
|
15
15
|
- /docs/route-php
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
Prisma PHP uses **file-system based routing**, meaning you can use folders and files to define routes. This page
|
|
18
|
+
Prisma PHP uses **file-system based routing**, meaning you can use folders and files to define routes. This page explains how to create pages and layouts, how to choose the correct route file, and how to keep PulsePoint-aware route files structurally consistent.
|
|
19
19
|
|
|
20
20
|
## Important route generation note
|
|
21
21
|
|
|
@@ -30,7 +30,7 @@ When adding a page or nested route, create the correct folder and add the proper
|
|
|
30
30
|
Prisma PHP has two important route entry files, and they serve different purposes.
|
|
31
31
|
|
|
32
32
|
- `index.php` is the **UI entry point** for a route. Use it when the route should render HTML or a normal full-stack page. In full-stack projects, this is also the default home for route-local PulsePoint-driven interactivity.
|
|
33
|
-
- `route.php` is the **direct handler entry point** for a route. Use it when the route should behave like an API endpoint, JSON endpoint, AJAX handler, form-processing endpoint, or other no-view server handler.
|
|
33
|
+
- `route.php` is the **direct handler entry point** for a route. Use it when the route should behave like an API endpoint, JSON endpoint, AJAX handler, form-processing endpoint, webhook, or other no-view server handler.
|
|
34
34
|
|
|
35
35
|
A helpful project-level rule comes from `prisma-php.json`:
|
|
36
36
|
|
|
@@ -70,24 +70,38 @@ In practice, that means:
|
|
|
70
70
|
- render the route markup after the PHP block
|
|
71
71
|
- place one PulsePoint `<script>` block at the bottom of the file
|
|
72
72
|
|
|
73
|
-
For the HTML portion, keep a **single parent HTML tag** around the route content
|
|
73
|
+
For the HTML portion, keep a **single parent HTML tag** around the route content. Treat that root as the page or layout boundary instead of as a throwaway wrapper.
|
|
74
74
|
|
|
75
|
-
- In `index.php`, wrap the page UI in one parent element such as `<main>`, `<section>`, or `<article>`, and treat that root as the route
|
|
75
|
+
- In `index.php`, wrap the page UI in one parent element such as `<main>`, `<section>`, or `<article>`, and treat that root as the route-view boundary.
|
|
76
76
|
- In nested `layout.php`, wrap the shared layout UI and `<?= MainLayout::$children; ?>` in one parent element so the layout still behaves like one boundary.
|
|
77
|
-
- If that markup is later extracted into an `ImportComponent` partial, preserve the same single-root structure so Prisma PHP can attach the stable `pp-component` attribute to that root element.
|
|
78
77
|
- The root `layout.php` is the document shell and is the only layout that should contain `<html>` and `<body>`. Inside `<body>`, keep one clear wrapper around `<?= MainLayout::$children; ?>` when PulsePoint behavior is present.
|
|
79
78
|
|
|
80
|
-
|
|
79
|
+
### Important distinction: route files vs imported partials
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
Do **not** confuse the structure of a normal route file with the structure of an imported partial component.
|
|
82
|
+
|
|
83
|
+
For **normal route files** such as `src/app/index.php` and nested `layout.php`, use this shape:
|
|
84
|
+
|
|
85
|
+
1. PHP
|
|
86
|
+
2. one parent HTML element for the rendered route UI
|
|
87
|
+
3. one `<script>` block after that parent element
|
|
88
|
+
|
|
89
|
+
Correct route-file pattern:
|
|
90
|
+
|
|
91
|
+
```php filename="src/app/index.php"
|
|
83
92
|
<?php
|
|
84
93
|
|
|
85
|
-
|
|
94
|
+
use PP\Attributes\Exposed;
|
|
95
|
+
use PP\MainLayout;
|
|
96
|
+
use PP\Validator;
|
|
97
|
+
|
|
98
|
+
MainLayout::$title = 'Todos';
|
|
99
|
+
MainLayout::$description = 'Track tasks and view the current item count.';
|
|
86
100
|
?>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
|
|
102
|
+
<section class="space-y-4">
|
|
103
|
+
<h1>Todos</h1>
|
|
104
|
+
<p>Count: {count}</p>
|
|
91
105
|
</section>
|
|
92
106
|
|
|
93
107
|
<script>
|
|
@@ -95,7 +109,10 @@ $title = 'Dashboard';
|
|
|
95
109
|
</script>
|
|
96
110
|
```
|
|
97
111
|
|
|
98
|
-
|
|
112
|
+
That is the default structure for a PulsePoint-aware route page.
|
|
113
|
+
Use `MainLayout::$title` and `MainLayout::$description` for page metadata, and keep a separate heading variable only when the visible heading text needs to differ.
|
|
114
|
+
|
|
115
|
+
By contrast, **imported partials rendered with `ImportComponent::render(...)` follow a different rule**: the imported file must emit exactly **one root element**, and if it contains a `<script>`, that script must live **inside** that root element. Read `components.md` for that pattern.
|
|
99
116
|
|
|
100
117
|
## Creating a page
|
|
101
118
|
|
|
@@ -106,7 +123,15 @@ For example, to create an index page (`/`):
|
|
|
106
123
|
```php filename="src/app/index.php"
|
|
107
124
|
<?php
|
|
108
125
|
|
|
109
|
-
|
|
126
|
+
use PP\MainLayout;
|
|
127
|
+
|
|
128
|
+
MainLayout::$title = 'Hello Prisma PHP!';
|
|
129
|
+
MainLayout::$description = 'Welcome to your Prisma PHP application.';
|
|
130
|
+
?>
|
|
131
|
+
|
|
132
|
+
<section pp-component="home-page">
|
|
133
|
+
<h1>Hello Prisma PHP!</h1>
|
|
134
|
+
</section>
|
|
110
135
|
```
|
|
111
136
|
|
|
112
137
|
A route is created from the folder structure, and `index.php` is the default file used for route UI.
|
|
@@ -120,15 +145,18 @@ You can define a layout by creating a `layout.php` file. The root layout is requ
|
|
|
120
145
|
For example, to create a root layout:
|
|
121
146
|
|
|
122
147
|
```php filename="src/app/layout.php"
|
|
148
|
+
<?php
|
|
123
149
|
|
|
124
|
-
|
|
150
|
+
use PP\MainLayout;
|
|
151
|
+
?>
|
|
125
152
|
|
|
126
153
|
<!DOCTYPE html>
|
|
127
154
|
<html lang="en">
|
|
128
155
|
<head>
|
|
129
156
|
<meta charset="UTF-8">
|
|
130
157
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
131
|
-
<title
|
|
158
|
+
<title><?= htmlspecialchars(MainLayout::$title ?: 'My Prisma PHP App') ?></title>
|
|
159
|
+
<meta name="description" content="<?= htmlspecialchars(MainLayout::$description ?: 'Default application description') ?>">
|
|
132
160
|
</head>
|
|
133
161
|
<body>
|
|
134
162
|
<main>
|
|
@@ -157,7 +185,15 @@ src/app/
|
|
|
157
185
|
```php filename="src/app/blog/index.php"
|
|
158
186
|
<?php
|
|
159
187
|
|
|
160
|
-
|
|
188
|
+
use PP\MainLayout;
|
|
189
|
+
|
|
190
|
+
MainLayout::$title = 'Blog';
|
|
191
|
+
MainLayout::$description = 'Read the latest articles and updates.';
|
|
192
|
+
?>
|
|
193
|
+
|
|
194
|
+
<section pp-component="blog-page">
|
|
195
|
+
<h1>Blog</h1>
|
|
196
|
+
</section>
|
|
161
197
|
```
|
|
162
198
|
|
|
163
199
|
You can continue nesting folders to create deeper routes. For example, to create a route for a specific blog post:
|
|
@@ -172,11 +208,18 @@ src/app/
|
|
|
172
208
|
```php filename="src/app/blog/[slug]/index.php"
|
|
173
209
|
<?php
|
|
174
210
|
|
|
211
|
+
use PP\MainLayout;
|
|
175
212
|
use PP\Request;
|
|
176
213
|
|
|
177
214
|
$slug = Request::$dynamicParams['slug'] ?? null;
|
|
178
215
|
|
|
179
|
-
|
|
216
|
+
MainLayout::$title = 'Blog post: ' . ucfirst(str_replace('-', ' ', (string) $slug));
|
|
217
|
+
MainLayout::$description = 'Read the full article for ' . ucfirst(str_replace('-', ' ', (string) $slug)) . '.';
|
|
218
|
+
?>
|
|
219
|
+
|
|
220
|
+
<section pp-component="blog-post-page">
|
|
221
|
+
<h1>Blog post: <?= htmlspecialchars((string) $slug) ?></h1>
|
|
222
|
+
</section>
|
|
180
223
|
```
|
|
181
224
|
|
|
182
225
|
Wrapping a folder name in square brackets creates a **dynamic route segment** that can be filled from the incoming URL.
|
|
@@ -198,10 +241,12 @@ src/app/
|
|
|
198
241
|
```
|
|
199
242
|
|
|
200
243
|
```php filename="src/app/blog/layout.php"
|
|
244
|
+
<?php
|
|
201
245
|
|
|
202
|
-
|
|
246
|
+
use PP\MainLayout;
|
|
247
|
+
?>
|
|
203
248
|
|
|
204
|
-
<section>
|
|
249
|
+
<section pp-component="blog-layout">
|
|
205
250
|
<header>
|
|
206
251
|
<h1>Blog Section</h1>
|
|
207
252
|
</header>
|
|
@@ -211,7 +256,8 @@ src/app/
|
|
|
211
256
|
```
|
|
212
257
|
|
|
213
258
|
If you combine both layouts, the root layout wraps the blog layout, and the blog layout wraps both `src/app/blog/index.php` and `src/app/blog/[slug]/index.php`.
|
|
214
|
-
Nested layouts should behave like single-root route views: one parent element should wrap the shared layout UI and `MainLayout::$children;`.
|
|
259
|
+
Nested layouts should behave like single-root route views: one parent element should wrap the shared layout UI and `MainLayout::$children;`.
|
|
260
|
+
Keep thinking in terms of one component-style boundary, not multiple sibling roots.
|
|
215
261
|
|
|
216
262
|
## Creating a dynamic segment
|
|
217
263
|
|
|
@@ -320,9 +366,12 @@ Example:
|
|
|
320
366
|
```php filename="src/app/users/route.php"
|
|
321
367
|
<?php
|
|
322
368
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
369
|
+
use Lib\Prisma\Classes\Prisma;
|
|
370
|
+
|
|
371
|
+
$prisma = Prisma::getInstance();
|
|
372
|
+
$users = $prisma->user->findMany();
|
|
373
|
+
|
|
374
|
+
echo json_encode($users);
|
|
326
375
|
```
|
|
327
376
|
|
|
328
377
|
## Good to know
|
|
@@ -342,3 +391,4 @@ echo json_encode([
|
|
|
342
391
|
- Dynamic route parameters are available through `Request::$dynamicParams`.
|
|
343
392
|
- Route groups let you organize routes and assign different layouts without affecting the URL.
|
|
344
393
|
- Private folders help you colocate implementation files without making them routable.
|
|
394
|
+
- Imported partials rendered through `ImportComponent` follow a different structural rule: one root element containing any component-local `<script>`.
|
|
@@ -13,6 +13,8 @@ related:
|
|
|
13
13
|
|
|
14
14
|
This page explains how to manage metadata in Prisma PHP and how icon file conventions such as `favicon`, `icon`, and `apple-icon` work.
|
|
15
15
|
|
|
16
|
+
For better SEO, treat `MainLayout::$title` and `MainLayout::$description` as the primary way to set page metadata. A local `$title` variable only affects rendered page content unless you also assign the document metadata through `MainLayout`.
|
|
17
|
+
|
|
16
18
|
Prisma PHP’s metadata system is centered on the `MainLayout` class rather than Next.js exports like `metadata`, `generateMetadata`, or generated `opengraph-image.tsx`. The provided Prisma PHP docs describe dynamic page metadata and icon file conventions, but they do **not** document a dedicated Next.js-style generated Open Graph image pipeline on these pages. citeturn0view0turn1view0
|
|
17
19
|
|
|
18
20
|
## Metadata in Prisma PHP
|
|
@@ -40,6 +42,28 @@ In this model:
|
|
|
40
42
|
- `MainLayout::$description` sets the page description
|
|
41
43
|
- `MainLayout::addCustomMetaData(...)` adds additional metadata such as `author` or other `<meta>` values citeturn0view0
|
|
42
44
|
|
|
45
|
+
## Heading text vs document metadata
|
|
46
|
+
|
|
47
|
+
If your page has a visible heading, keep it separate from the document metadata when needed.
|
|
48
|
+
|
|
49
|
+
This is a better pattern than relying on a local `$title` variable alone:
|
|
50
|
+
|
|
51
|
+
```php filename="src/app/dashboard/index.php"
|
|
52
|
+
<?php
|
|
53
|
+
|
|
54
|
+
use Lib\MainLayout;
|
|
55
|
+
|
|
56
|
+
MainLayout::$title = "Dashboard";
|
|
57
|
+
MainLayout::$description = "View account stats, recent activity, and important actions.";
|
|
58
|
+
?>
|
|
59
|
+
|
|
60
|
+
<section>
|
|
61
|
+
<h1>Dashboard</h1>
|
|
62
|
+
</section>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use this pattern when the browser title, search-engine title, and page heading should stay aligned. If the visible heading needs to differ from the SEO title, keep the heading in its own variable and continue setting metadata through `MainLayout`.
|
|
66
|
+
|
|
43
67
|
## Dynamic metadata
|
|
44
68
|
|
|
45
69
|
Prisma PHP also supports dynamic metadata based on request data or other runtime conditions.
|
|
@@ -83,6 +107,34 @@ MainLayout::$description = "Learn more about our company.";
|
|
|
83
107
|
</section>
|
|
84
108
|
```
|
|
85
109
|
|
|
110
|
+
## Rendering metadata in the root layout
|
|
111
|
+
|
|
112
|
+
Your root `layout.php` can read from `MainLayout` so page-level metadata set in `index.php` or nested `layout.php` is reflected in the document head.
|
|
113
|
+
|
|
114
|
+
```php filename="src/app/layout.php"
|
|
115
|
+
<?php
|
|
116
|
+
|
|
117
|
+
use Lib\MainLayout;
|
|
118
|
+
?>
|
|
119
|
+
|
|
120
|
+
<!DOCTYPE html>
|
|
121
|
+
<html lang="en">
|
|
122
|
+
<head>
|
|
123
|
+
<meta charset="UTF-8">
|
|
124
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
125
|
+
<title><?= htmlspecialchars(MainLayout::$title ?: "My Prisma PHP App") ?></title>
|
|
126
|
+
<meta name="description" content="<?= htmlspecialchars(MainLayout::$description ?: "Default application description") ?>">
|
|
127
|
+
</head>
|
|
128
|
+
<body>
|
|
129
|
+
<main>
|
|
130
|
+
<?= MainLayout::$children; ?>
|
|
131
|
+
</main>
|
|
132
|
+
</body>
|
|
133
|
+
</html>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
This lets route files control SEO metadata while the root layout stays responsible for the actual `<head>` output.
|
|
137
|
+
|
|
86
138
|
## Adding custom metadata
|
|
87
139
|
|
|
88
140
|
You can attach additional custom metadata through `MainLayout::addCustomMetaData(...)`.
|
|
@@ -219,7 +271,7 @@ Because those pages do not document a dedicated Prisma PHP Open Graph image gene
|
|
|
219
271
|
## Good to know
|
|
220
272
|
|
|
221
273
|
- Prisma PHP uses `MainLayout` for dynamic metadata management. citeturn0view0
|
|
222
|
-
- `MainLayout::$title` and `MainLayout::$description` are the main documented page metadata properties.
|
|
274
|
+
- `MainLayout::$title` and `MainLayout::$description` are the main documented page metadata properties.
|
|
223
275
|
- `MainLayout::addCustomMetaData(...)` adds custom metadata such as `author`. citeturn0view0
|
|
224
276
|
- Metadata should be set before any HTML output. citeturn0view0
|
|
225
277
|
- `MainLayout::addHeadScript(...)` and `MainLayout::addFooterScript(...)` can inject scripts into the page shell. citeturn0view0
|
|
@@ -75,15 +75,15 @@ For AI-assisted generation, the default full-stack route pattern should be:
|
|
|
75
75
|
|
|
76
76
|
Only prefer a more PHP-only interaction pattern when the user explicitly asks for it.
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
## Framework-managed generated files
|
|
79
79
|
|
|
80
80
|
Some files in a Prisma PHP project are framework-managed and should not be manually maintained as part of normal route work.
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
### `files-list.json`
|
|
83
83
|
|
|
84
84
|
Prisma PHP automatically generates the route list in `files-list.json`.
|
|
85
85
|
|
|
86
|
-
Do **not** create routes by editing this file. Do **not** manually add, remove, reorder, or
|
|
86
|
+
Do **not** create routes by editing this file. Do **not** manually add, remove, reorder, or sync entries in it.
|
|
87
87
|
|
|
88
88
|
Instead, create or update the correct folders and route files in `src/app`, then let Prisma PHP regenerate `files-list.json` automatically.
|
|
89
89
|
|
|
@@ -104,6 +104,67 @@ Routes are defined by the route tree under `src/app`. Prisma PHP then derives ro
|
|
|
104
104
|
| `not-found.php` | Not found UI |
|
|
105
105
|
| `error.php` | Error handling UI |
|
|
106
106
|
|
|
107
|
+
## Route file shape rules
|
|
108
|
+
|
|
109
|
+
The route tree tells Prisma PHP **where** a route lives. The file shape tells AI **how** the route file should be structured.
|
|
110
|
+
|
|
111
|
+
### `index.php` and nested `layout.php`
|
|
112
|
+
|
|
113
|
+
For normal PulsePoint-aware route files, use:
|
|
114
|
+
|
|
115
|
+
1. PHP
|
|
116
|
+
2. one parent HTML element
|
|
117
|
+
3. one `<script>` block after that parent element
|
|
118
|
+
|
|
119
|
+
Example:
|
|
120
|
+
|
|
121
|
+
```php filename="src/app/dashboard/index.php"
|
|
122
|
+
<?php
|
|
123
|
+
|
|
124
|
+
use PP\MainLayout;
|
|
125
|
+
|
|
126
|
+
MainLayout::$title = 'Dashboard';
|
|
127
|
+
MainLayout::$description = 'View dashboard metrics and current activity.';
|
|
128
|
+
?>
|
|
129
|
+
|
|
130
|
+
<section class="dashboard-page">
|
|
131
|
+
<h1>Dashboard</h1>
|
|
132
|
+
<p>Count: {count}</p>
|
|
133
|
+
</section>
|
|
134
|
+
|
|
135
|
+
<script>
|
|
136
|
+
const [count, setCount] = pp.state(0);
|
|
137
|
+
</script>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
That is the default route-file structure for a full-stack page.
|
|
141
|
+
For document metadata, set `MainLayout::$title` and `MainLayout::$description` instead of assuming a local `$title` variable will populate the `<head>`.
|
|
142
|
+
|
|
143
|
+
### `ImportComponent` partials are different
|
|
144
|
+
|
|
145
|
+
An imported partial rendered through `ImportComponent::render(...)` is **not** a normal route file.
|
|
146
|
+
|
|
147
|
+
For imported partials, the file must emit exactly **one root element**, and if the partial contains a `<script>`, that script must live **inside** that root element.
|
|
148
|
+
|
|
149
|
+
Example:
|
|
150
|
+
|
|
151
|
+
```php filename="src/app/inc/SearchBox.php"
|
|
152
|
+
<?php
|
|
153
|
+
|
|
154
|
+
$title = 'Search';
|
|
155
|
+
?>
|
|
156
|
+
|
|
157
|
+
<div class="rounded-lg border p-4" pp-component="search-box">
|
|
158
|
+
<h2><?= htmlspecialchars($title) ?></h2>
|
|
159
|
+
<input value="{query}" />
|
|
160
|
+
<script>
|
|
161
|
+
console.log('Search component ready');
|
|
162
|
+
</script>
|
|
163
|
+
</div>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Do not confuse the normal route-file pattern with the imported-partial pattern.
|
|
167
|
+
|
|
107
168
|
## Nested routes
|
|
108
169
|
|
|
109
170
|
Folders define URL segments. Nesting folders nests segments. A route becomes publicly accessible when an `index.php` file exists inside that route folder.
|
|
@@ -198,6 +259,8 @@ prisma-php-project/
|
|
|
198
259
|
│ │ │ │ └── route.php
|
|
199
260
|
│ │ │ └── _components/
|
|
200
261
|
│ │ │ └── StatsCard.php
|
|
262
|
+
│ │ ├── inc/
|
|
263
|
+
│ │ │ └── SearchBox.php
|
|
201
264
|
│ │ └── blog/
|
|
202
265
|
│ │ ├── index.php
|
|
203
266
|
│ │ └── [slug]/
|