prisma-php 0.0.1
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/01-getting-started/authentication.md +280 -0
- package/dist/docs/01-getting-started/caching.md +346 -0
- package/dist/docs/01-getting-started/components.md +589 -0
- package/dist/docs/01-getting-started/error-handling.md +359 -0
- package/dist/docs/01-getting-started/fetching-data.md +637 -0
- package/dist/docs/01-getting-started/file-manager.md +307 -0
- package/dist/docs/01-getting-started/index.md +142 -0
- package/dist/docs/01-getting-started/installation.md +18 -0
- package/dist/docs/01-getting-started/layouts-and-pages.md +289 -0
- package/dist/docs/01-getting-started/metadata-and-og-images.md +228 -0
- package/dist/docs/01-getting-started/prisma-php-orm.md +374 -0
- package/dist/docs/01-getting-started/project-structure.md +328 -0
- package/dist/docs/01-getting-started/pulsepoint.md +434 -0
- package/dist/docs/01-getting-started/route-handlers.md +344 -0
- package/dist/docs/01-getting-started/upgrading.md +172 -0
- package/dist/docs/index.md +243 -0
- package/package.json +16 -0
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Fetching Data
|
|
3
|
+
description: Learn how to fetch data in Prisma PHP using `pp.fetchFunction`, `#[Exposed]`, page handlers, and route handlers.
|
|
4
|
+
related:
|
|
5
|
+
title: API Reference
|
|
6
|
+
description: Learn more about the features mentioned in this page by reading the Prisma PHP docs.
|
|
7
|
+
links:
|
|
8
|
+
- /docs/fetch-function
|
|
9
|
+
- /docs/index-php
|
|
10
|
+
- /docs/route-php
|
|
11
|
+
- /docs/pages-and-layouts
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
This page will walk you through how you can fetch data in Prisma PHP, when to use `pp.fetchFunction(...)`, when to use `index.php`, when to use `route.php`, and how to validate incoming data correctly on the PHP side.
|
|
15
|
+
|
|
16
|
+
Prisma PHP has a different mental model from Next.js. Instead of focusing on React Server Components, Suspense streaming, and client data libraries, Prisma PHP gives you direct function invocation from the frontend to PHP, plus file-based routing for page UI and direct route handlers.
|
|
17
|
+
|
|
18
|
+
When using `pp.fetchFunction(...)`, the PHP function must be explicitly exposed with `#[Exposed]`. Functions are private by default, so a non-exposed function cannot be called from the client.
|
|
19
|
+
|
|
20
|
+
For validation, the default backend pattern should be **`PP\Validator`**. Use it to sanitize, cast, and validate values inside exposed functions and route handlers. This keeps the browser reactive while keeping the authoritative validation on the server.
|
|
21
|
+
|
|
22
|
+
## Validation is a server concern
|
|
23
|
+
|
|
24
|
+
In Prisma PHP, frontend interactivity and backend validation work together, but they are not the same thing.
|
|
25
|
+
|
|
26
|
+
Use this split:
|
|
27
|
+
|
|
28
|
+
- use **PulsePoint** for local input state, loading state, and reactive UI feedback
|
|
29
|
+
- use **`pp.fetchFunction(...)`** to send data to PHP during interactive flows
|
|
30
|
+
- use **`PP\Validator`** in PHP to sanitize, cast, and validate the incoming payload
|
|
31
|
+
- return a **structured response** such as `success`, `errors`, and normalized values
|
|
32
|
+
- do not trust browser-only validation as the final source of truth
|
|
33
|
+
|
|
34
|
+
This makes `Validator` a natural fit for:
|
|
35
|
+
|
|
36
|
+
- live field validation
|
|
37
|
+
- inline availability checks
|
|
38
|
+
- form submission validation
|
|
39
|
+
- normalization before database writes
|
|
40
|
+
- reusable backend validation for both page-local RPC and direct handlers
|
|
41
|
+
|
|
42
|
+
## Recommended Validator pattern for `pp.fetchFunction(...)`
|
|
43
|
+
|
|
44
|
+
For reactive UI work, the best Prisma PHP pattern is usually:
|
|
45
|
+
|
|
46
|
+
1. keep the current field state in PulsePoint
|
|
47
|
+
2. call an exposed PHP function with `pp.fetchFunction(...)`
|
|
48
|
+
3. validate on the server with `Validator`
|
|
49
|
+
4. return a structured object for the UI to render
|
|
50
|
+
|
|
51
|
+
The official Validator docs recommend the **`Rule` builder** for most rule-based validation because it is easier to discover, easier to refactor, and less error-prone than raw pipe strings.
|
|
52
|
+
|
|
53
|
+
## Recommended pattern for reactive Prisma PHP UIs
|
|
54
|
+
|
|
55
|
+
For normal interactive UI work in Prisma PHP, the default approach should be:
|
|
56
|
+
|
|
57
|
+
1. render the page with `index.php`
|
|
58
|
+
2. manage browser-side reactivity with PulsePoint
|
|
59
|
+
3. call PHP from the frontend with `pp.fetchFunction(...)`
|
|
60
|
+
4. expose callable functions with `#[Exposed]`
|
|
61
|
+
|
|
62
|
+
This is the preferred pattern for live search, inline validation, toggles, quick edits, filtering, lightweight mutations, and similar route-local interactions.
|
|
63
|
+
|
|
64
|
+
Do **not** default to building extra `route.php` endpoints for every interactive action when `pp.fetchFunction(...)` is the better fit. Reserve `route.php` for explicit API-style endpoints, webhooks, JSON handlers, or routes that must be called independently of the page.
|
|
65
|
+
|
|
66
|
+
## Fetching data in Prisma PHP
|
|
67
|
+
|
|
68
|
+
There are three common ways to fetch or load data in Prisma PHP:
|
|
69
|
+
|
|
70
|
+
1. **Load data directly in `index.php`** for full-stack page rendering
|
|
71
|
+
2. **Call PHP functions from JavaScript with `pp.fetchFunction(...)`**
|
|
72
|
+
3. **Use `route.php`** for API-style or direct JSON endpoints
|
|
73
|
+
|
|
74
|
+
### Choosing the right approach
|
|
75
|
+
|
|
76
|
+
Use this rule of thumb:
|
|
77
|
+
|
|
78
|
+
- use `index.php` when the route should render page UI
|
|
79
|
+
- use `pp.fetchFunction(...)` when frontend interactivity should call backend PHP directly without creating a dedicated route file
|
|
80
|
+
- use `route.php` when you need a direct API-style endpoint, JSON handler, webhook, or no-view request path
|
|
81
|
+
|
|
82
|
+
In a full-stack Prisma PHP project, normal page data is usually loaded in `index.php`, and interactive frontend updates are commonly handled with `pp.fetchFunction(...)`.
|
|
83
|
+
|
|
84
|
+
## Fetching data in `index.php`
|
|
85
|
+
|
|
86
|
+
For full-stack page routes, the most direct way to fetch data is inside `index.php`.
|
|
87
|
+
|
|
88
|
+
Because `index.php` is the UI entry point for a route, it is the right place to query the database, prepare data, and render HTML or PHPX-based output.
|
|
89
|
+
|
|
90
|
+
```php filename="src/app/blog/index.php"
|
|
91
|
+
<?php
|
|
92
|
+
|
|
93
|
+
use Lib\Prisma\Classes\Prisma;
|
|
94
|
+
|
|
95
|
+
$prisma = Prisma::getInstance();
|
|
96
|
+
|
|
97
|
+
$posts = $prisma->post->findMany([
|
|
98
|
+
'orderBy' => [
|
|
99
|
+
'createdAt' => 'desc',
|
|
100
|
+
],
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
?>
|
|
104
|
+
|
|
105
|
+
<ul>
|
|
106
|
+
<?php foreach ($posts as $post): ?>
|
|
107
|
+
<li><?= htmlspecialchars($post['title']) ?></li>
|
|
108
|
+
<?php endforeach; ?>
|
|
109
|
+
</ul>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This is the closest Prisma PHP equivalent to server-side page data loading.
|
|
113
|
+
|
|
114
|
+
## Fetching data with `pp.fetchFunction(...)`
|
|
115
|
+
|
|
116
|
+
One of Prisma PHP’s main frontend-to-backend patterns is **Direct Function Invocation** with `pp.fetchFunction(...)`.
|
|
117
|
+
|
|
118
|
+
This allows you to call PHP functions directly from frontend JavaScript without creating route files, controllers, or custom API endpoints.
|
|
119
|
+
|
|
120
|
+
### Basic example
|
|
121
|
+
|
|
122
|
+
Before a PHP function can be called with `pp.fetchFunction(...)`, it must be marked with `#[Exposed]`.
|
|
123
|
+
|
|
124
|
+
Functions and methods are private by default in this flow. `pp.fetchFunction(...)` will only work for functions that are intentionally exposed.
|
|
125
|
+
|
|
126
|
+
```php filename="src/app/users/index.php"
|
|
127
|
+
<?php
|
|
128
|
+
|
|
129
|
+
use PP\Attributes\Exposed;
|
|
130
|
+
use PP\Validator;
|
|
131
|
+
|
|
132
|
+
#[Exposed]
|
|
133
|
+
function validateUser($data)
|
|
134
|
+
{
|
|
135
|
+
$id = Validator::int($data->id);
|
|
136
|
+
|
|
137
|
+
if ($id <= 0) {
|
|
138
|
+
return [
|
|
139
|
+
'success' => false,
|
|
140
|
+
'msg' => 'Invalid ID',
|
|
141
|
+
];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return [
|
|
145
|
+
'success' => true,
|
|
146
|
+
'msg' => 'Valid ID',
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
?>
|
|
150
|
+
|
|
151
|
+
<script>
|
|
152
|
+
const [id, setId] = pp.state('');
|
|
153
|
+
const [msg, setMsg] = pp.state('');
|
|
154
|
+
|
|
155
|
+
async function checkId() {
|
|
156
|
+
const response = await pp.fetchFunction('validateUser', { id });
|
|
157
|
+
|
|
158
|
+
if (response.success) {
|
|
159
|
+
setMsg(response.msg);
|
|
160
|
+
} else {
|
|
161
|
+
setMsg(response.msg);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<input value="{id}" oninput="setId(val)" />
|
|
167
|
+
<button onclick="checkId()">Check</button>
|
|
168
|
+
<p>{msg}</p>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
If `validateUser()` is not decorated with `#[Exposed]`, the client cannot invoke it through `pp.fetchFunction(...)`.
|
|
172
|
+
Prisma PHP automatically serializes the request and parses the PHP return value back into JavaScript. If the response is JSON-compatible, the result is returned as a parsed object. If the backend returns non-JSON data, the result may be returned as a raw string.
|
|
173
|
+
|
|
174
|
+
## Why `pp.fetchFunction(...)` is important
|
|
175
|
+
|
|
176
|
+
`pp.fetchFunction(...)` is one of Prisma PHP’s biggest differences from other frameworks.
|
|
177
|
+
|
|
178
|
+
It removes the need for:
|
|
179
|
+
|
|
180
|
+
- controller boilerplate
|
|
181
|
+
- custom route definitions
|
|
182
|
+
- manual `fetch('/api/...')` setup for many interactions
|
|
183
|
+
- repetitive JSON parsing code on both sides
|
|
184
|
+
|
|
185
|
+
Instead, you define an exposed PHP function and call it directly.
|
|
186
|
+
|
|
187
|
+
This makes it especially useful for:
|
|
188
|
+
|
|
189
|
+
- form validation
|
|
190
|
+
- search-as-you-type
|
|
191
|
+
- quick data checks
|
|
192
|
+
- lightweight mutations
|
|
193
|
+
- UI-triggered backend actions
|
|
194
|
+
- interactive dashboard behavior
|
|
195
|
+
|
|
196
|
+
## Working with `Exposed`
|
|
197
|
+
|
|
198
|
+
`#[Exposed]` is not just an optional enhancement for `pp.fetchFunction(...)`—it is the requirement that makes a PHP function callable from the client.
|
|
199
|
+
|
|
200
|
+
Functions are private by default. To allow frontend access, you must explicitly opt in with the `Exposed` attribute. This keeps server logic locked down unless you intentionally expose it.
|
|
201
|
+
|
|
202
|
+
```php filename="src/app/users/index.php"
|
|
203
|
+
<?php
|
|
204
|
+
|
|
205
|
+
use PP\Attributes\Exposed;
|
|
206
|
+
use PP\Validator;
|
|
207
|
+
|
|
208
|
+
#[Exposed]
|
|
209
|
+
function validateUser($data)
|
|
210
|
+
{
|
|
211
|
+
$id = Validator::int($data->id);
|
|
212
|
+
|
|
213
|
+
return [
|
|
214
|
+
'success' => $id > 0,
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
#[Exposed(
|
|
219
|
+
requiresAuth: true,
|
|
220
|
+
allowedRoles: ['admin'],
|
|
221
|
+
limits: '20/min'
|
|
222
|
+
)]
|
|
223
|
+
function searchUsers($data)
|
|
224
|
+
{
|
|
225
|
+
$query = Validator::string($data->query ?? '');
|
|
226
|
+
|
|
227
|
+
return [
|
|
228
|
+
'success' => true,
|
|
229
|
+
'query' => $query,
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The `Exposed` attribute supports:
|
|
235
|
+
|
|
236
|
+
- `requiresAuth`
|
|
237
|
+
- `allowedRoles`
|
|
238
|
+
- `limits`
|
|
239
|
+
|
|
240
|
+
Based on the provided class definition, it can be applied to functions and methods and is designed for direct invocation with authentication, role checks, and rate limiting.
|
|
241
|
+
|
|
242
|
+
### What each option does
|
|
243
|
+
|
|
244
|
+
- `#[Exposed]` makes the function publicly callable from `pp.fetchFunction(...)`
|
|
245
|
+
- `requiresAuth: true` restricts access to authenticated users
|
|
246
|
+
- `allowedRoles: [...]` restricts access to specific roles
|
|
247
|
+
- `limits` applies one or more rate limits such as `"5/minute"` or `["5/m", "100/d"]`
|
|
248
|
+
|
|
249
|
+
### Private by default
|
|
250
|
+
|
|
251
|
+
This is the key rule to remember:
|
|
252
|
+
|
|
253
|
+
- `pp.fetchFunction('myFunction')` only works if `myFunction` is exposed
|
|
254
|
+
- a normal PHP function without `#[Exposed]` remains private to the server context
|
|
255
|
+
- use `#[Exposed]` whenever you want frontend JavaScript to call a PHP function directly
|
|
256
|
+
|
|
257
|
+
## Parameters and automatic parsing
|
|
258
|
+
|
|
259
|
+
`pp.fetchFunction(...)` accepts the function name, a payload object, and an optional third argument for request behavior.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
fetchFunction<T = any>(
|
|
263
|
+
functionName: string,
|
|
264
|
+
data: Record<string, any> = {},
|
|
265
|
+
options: boolean | RpcOptions = false
|
|
266
|
+
): Promise<T | void>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Parameters
|
|
270
|
+
|
|
271
|
+
- `functionName`: the exact PHP function name to call
|
|
272
|
+
- `data`: an object containing the arguments to send
|
|
273
|
+
- `options`: either `true`/`false` for simple abort behavior or an options object for advanced features
|
|
274
|
+
|
|
275
|
+
### Common options
|
|
276
|
+
|
|
277
|
+
- `abortPrevious`: cancel previous pending requests from the same caller
|
|
278
|
+
- `onStream`: handle streamed SSE chunks
|
|
279
|
+
- `onStreamError`: handle stream errors
|
|
280
|
+
- `onStreamComplete`: run logic when streaming finishes
|
|
281
|
+
- `onUploadProgress`: track real upload progress when sending `File` or `FileList`
|
|
282
|
+
- `onUploadComplete`: run logic when the upload finishes
|
|
283
|
+
|
|
284
|
+
This is useful for search inputs, streaming responses, uploads, and other rapid repeated interactions.
|
|
285
|
+
|
|
286
|
+
```html
|
|
287
|
+
<script>
|
|
288
|
+
async function onSearch(val) {
|
|
289
|
+
const response = await pp.fetchFunction(
|
|
290
|
+
"searchUsers",
|
|
291
|
+
{ query: val },
|
|
292
|
+
{ abortPrevious: true },
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
console.log(response);
|
|
296
|
+
}
|
|
297
|
+
</script>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
As with every `pp.fetchFunction(...)` call, `searchUsers` must be decorated with `#[Exposed]` on the PHP side.
|
|
301
|
+
|
|
302
|
+
## File upload support
|
|
303
|
+
|
|
304
|
+
Prisma PHP’s fetch function automatically switches to multipart handling when the payload contains a `File` or `FileList`.
|
|
305
|
+
|
|
306
|
+
The upload handler still needs to be exposed with `#[Exposed]` if it is being called from `pp.fetchFunction(...)`.
|
|
307
|
+
|
|
308
|
+
That means you do not need to manually build `FormData` for many common upload flows.
|
|
309
|
+
|
|
310
|
+
```html
|
|
311
|
+
<script>
|
|
312
|
+
async function uploadAvatar() {
|
|
313
|
+
const fileInput = document.getElementById("avatar");
|
|
314
|
+
|
|
315
|
+
const response = await pp.fetchFunction("uploadAvatar", {
|
|
316
|
+
image: fileInput.files[0],
|
|
317
|
+
userId: 12,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
console.log(response);
|
|
321
|
+
}
|
|
322
|
+
</script>
|
|
323
|
+
|
|
324
|
+
<input id="avatar" type="file" />
|
|
325
|
+
<button onclick="uploadAvatar()">Upload</button>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Request cancellation
|
|
329
|
+
|
|
330
|
+
For fast-changing inputs such as live search, Prisma PHP can automatically cancel stale requests by using `abortPrevious: true`.
|
|
331
|
+
|
|
332
|
+
```html
|
|
333
|
+
<script>
|
|
334
|
+
async function searchPosts(val) {
|
|
335
|
+
const response = await pp.fetchFunction(
|
|
336
|
+
"searchPosts",
|
|
337
|
+
{ query: val },
|
|
338
|
+
{ abortPrevious: true },
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
console.log(response);
|
|
342
|
+
}
|
|
343
|
+
</script>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
This helps prevent race conditions and outdated responses from overwriting newer UI state.
|
|
347
|
+
|
|
348
|
+
## Transparent redirects
|
|
349
|
+
|
|
350
|
+
If a PHP function returns a redirect instruction, or if authentication fails in a way that triggers redirect behavior, `pp.fetchFunction(...)` can automatically perform a client-side redirect through Prisma PHP’s navigation helpers.
|
|
351
|
+
|
|
352
|
+
This makes interactive authenticated flows smoother without requiring extra frontend redirect wiring.
|
|
353
|
+
|
|
354
|
+
## Using `Validator` inside exposed functions
|
|
355
|
+
|
|
356
|
+
An exposed function should do more than simply accept the raw payload. It should:
|
|
357
|
+
|
|
358
|
+
1. normalize incoming values
|
|
359
|
+
2. validate the shape and business rules
|
|
360
|
+
3. return predictable frontend-friendly output
|
|
361
|
+
|
|
362
|
+
A practical pattern is:
|
|
363
|
+
|
|
364
|
+
```php filename="src/app/settings/index.php"
|
|
365
|
+
<?php
|
|
366
|
+
|
|
367
|
+
use PP\Attributes\Exposed;
|
|
368
|
+
use PP\Rule;
|
|
369
|
+
use PP\Validator;
|
|
370
|
+
|
|
371
|
+
#[Exposed]
|
|
372
|
+
function saveProfile($data)
|
|
373
|
+
{
|
|
374
|
+
$name = Validator::string($data->name ?? '');
|
|
375
|
+
$email = Validator::email($data->email ?? '');
|
|
376
|
+
$newsletter = Validator::boolean($data->newsletter ?? false);
|
|
377
|
+
|
|
378
|
+
$nameResult = Validator::withRules($name, Rule::required()->min(3)->max(80));
|
|
379
|
+
|
|
380
|
+
if ($nameResult !== true) {
|
|
381
|
+
return [
|
|
382
|
+
'success' => false,
|
|
383
|
+
'errors' => [
|
|
384
|
+
'name' => $nameResult,
|
|
385
|
+
],
|
|
386
|
+
];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if ($email === null) {
|
|
390
|
+
return [
|
|
391
|
+
'success' => false,
|
|
392
|
+
'errors' => [
|
|
393
|
+
'email' => 'A valid email address is required.',
|
|
394
|
+
],
|
|
395
|
+
];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return [
|
|
399
|
+
'success' => true,
|
|
400
|
+
'errors' => [],
|
|
401
|
+
'data' => [
|
|
402
|
+
'name' => $name,
|
|
403
|
+
'email' => $email,
|
|
404
|
+
'newsletter' => $newsletter ?? false,
|
|
405
|
+
],
|
|
406
|
+
];
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
This pattern works well because the UI can render field errors immediately, while the backend still controls the final truth.
|
|
411
|
+
|
|
412
|
+
## `Validator` helpers you will commonly use
|
|
413
|
+
|
|
414
|
+
Some of the most useful helpers for reactive and backend validation include:
|
|
415
|
+
|
|
416
|
+
- `Validator::string(...)` for sanitized strings
|
|
417
|
+
- `Validator::email(...)` for email addresses
|
|
418
|
+
- `Validator::int(...)` and `Validator::float(...)` for numeric casting
|
|
419
|
+
- `Validator::boolean(...)` for smart boolean conversion
|
|
420
|
+
- `Validator::json(...)` for JSON-safe validation or encoding
|
|
421
|
+
- `Validator::date(...)` and `Validator::dateTime(...)` for normalized date values
|
|
422
|
+
- `Validator::enum(...)` and `Validator::enumClass(...)` for allowed options
|
|
423
|
+
- `Validator::withRules(...)` for rule-based validation
|
|
424
|
+
|
|
425
|
+
Use primitive helpers for normalization first, then apply `withRules(...)` when the value has business constraints such as required, minimum length, confirmed fields, allowed lists, or date rules.
|
|
426
|
+
|
|
427
|
+
## Using `route.php` for data fetching
|
|
428
|
+
|
|
429
|
+
When you need an explicit endpoint instead of direct function invocation, use `route.php`.
|
|
430
|
+
|
|
431
|
+
This is a better fit for:
|
|
432
|
+
|
|
433
|
+
- external integrations
|
|
434
|
+
- webhooks
|
|
435
|
+
- standalone JSON endpoints
|
|
436
|
+
- routes that should be called outside the current page context
|
|
437
|
+
- API-style request handlers
|
|
438
|
+
|
|
439
|
+
Example:
|
|
440
|
+
|
|
441
|
+
```php filename="src/app/users/route.php"
|
|
442
|
+
<?php
|
|
443
|
+
|
|
444
|
+
use Lib\Prisma\Classes\Prisma;
|
|
445
|
+
use PP\Request;
|
|
446
|
+
|
|
447
|
+
if (!Request::$isGet) {
|
|
448
|
+
exit;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
$prisma = Prisma::getInstance();
|
|
452
|
+
|
|
453
|
+
$users = $prisma->user->findMany();
|
|
454
|
+
|
|
455
|
+
echo json_encode($users);
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
In Prisma PHP, `route.php` is the direct handler entry point for a route segment and is commonly used for API-style behavior.
|
|
459
|
+
|
|
460
|
+
## `index.php` vs `route.php` for fetching data
|
|
461
|
+
|
|
462
|
+
Use `index.php` when:
|
|
463
|
+
|
|
464
|
+
- the route should render page UI
|
|
465
|
+
- data belongs to the page render itself
|
|
466
|
+
- the request is part of the normal full-stack page flow
|
|
467
|
+
|
|
468
|
+
Use `route.php` when:
|
|
469
|
+
|
|
470
|
+
- the route should act like an API endpoint
|
|
471
|
+
- the response should bypass standard page rendering
|
|
472
|
+
- the request needs a dedicated direct handler
|
|
473
|
+
|
|
474
|
+
Use `pp.fetchFunction(...)` when:
|
|
475
|
+
|
|
476
|
+
- you are inside an existing page
|
|
477
|
+
- the frontend needs to call PHP directly
|
|
478
|
+
- you want less boilerplate than a dedicated route file
|
|
479
|
+
|
|
480
|
+
## Common Prisma PHP data-fetching patterns
|
|
481
|
+
|
|
482
|
+
### Page loads in `index.php`
|
|
483
|
+
|
|
484
|
+
```php filename="src/app/dashboard/index.php"
|
|
485
|
+
<?php
|
|
486
|
+
|
|
487
|
+
use Lib\Prisma\Classes\Prisma;
|
|
488
|
+
|
|
489
|
+
$prisma = Prisma::getInstance();
|
|
490
|
+
|
|
491
|
+
$stats = $prisma->user->count();
|
|
492
|
+
|
|
493
|
+
echo "<h1>Total users: " . (int) $stats . "</h1>";
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Interactive validation with `pp.fetchFunction(...)`
|
|
497
|
+
|
|
498
|
+
```php filename="src/app/profile/index.php"
|
|
499
|
+
<?php
|
|
500
|
+
|
|
501
|
+
use PP\Attributes\Exposed;
|
|
502
|
+
use PP\Rule;
|
|
503
|
+
use PP\Validator;
|
|
504
|
+
|
|
505
|
+
#[Exposed]
|
|
506
|
+
function validateUsername($data)
|
|
507
|
+
{
|
|
508
|
+
$username = Validator::string($data->username ?? '');
|
|
509
|
+
|
|
510
|
+
$result = Validator::withRules(
|
|
511
|
+
$username,
|
|
512
|
+
Rule::required()->min(3)->max(30)
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
if ($result !== true) {
|
|
516
|
+
return [
|
|
517
|
+
'success' => false,
|
|
518
|
+
'errors' => [
|
|
519
|
+
'username' => $result,
|
|
520
|
+
],
|
|
521
|
+
];
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if ($username === 'admin') {
|
|
525
|
+
return [
|
|
526
|
+
'success' => false,
|
|
527
|
+
'errors' => [
|
|
528
|
+
'username' => 'This username is not available.',
|
|
529
|
+
],
|
|
530
|
+
];
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return [
|
|
534
|
+
'success' => true,
|
|
535
|
+
'errors' => [],
|
|
536
|
+
'normalized' => [
|
|
537
|
+
'username' => $username,
|
|
538
|
+
],
|
|
539
|
+
];
|
|
540
|
+
}
|
|
541
|
+
?>
|
|
542
|
+
|
|
543
|
+
<input
|
|
544
|
+
type="text"
|
|
545
|
+
value="{username}"
|
|
546
|
+
oninput="validateUsername(event.target.value)"
|
|
547
|
+
/>
|
|
548
|
+
<p hidden="{!usernameError}">{usernameError}</p>
|
|
549
|
+
|
|
550
|
+
<script>
|
|
551
|
+
const [username, setUsername] = pp.state('');
|
|
552
|
+
const [usernameError, setUsernameError] = pp.state('');
|
|
553
|
+
|
|
554
|
+
async function validateUsername(val) {
|
|
555
|
+
setUsername(val);
|
|
556
|
+
|
|
557
|
+
const response = await pp.fetchFunction(
|
|
558
|
+
'validateUsername',
|
|
559
|
+
{ username: val },
|
|
560
|
+
{ abortPrevious: true }
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
setUsernameError(response.errors?.username ?? '');
|
|
564
|
+
}
|
|
565
|
+
</script>
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Dedicated JSON endpoint with `route.php`
|
|
569
|
+
|
|
570
|
+
```php filename="src/app/reports/route.php"
|
|
571
|
+
<?php
|
|
572
|
+
|
|
573
|
+
echo json_encode([
|
|
574
|
+
'success' => true,
|
|
575
|
+
'generatedAt' => date('c'),
|
|
576
|
+
]);
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## Loading states
|
|
580
|
+
|
|
581
|
+
Unlike Next.js, Prisma PHP’s data-fetching story here is not centered on React Suspense or streaming server components.
|
|
582
|
+
|
|
583
|
+
Instead, loading behavior is typically handled in the UI with:
|
|
584
|
+
|
|
585
|
+
- local PulsePoint state
|
|
586
|
+
- `pp-loading-content`
|
|
587
|
+
- route-level `loading.php`
|
|
588
|
+
- custom interactive state patterns
|
|
589
|
+
|
|
590
|
+
For interactive fetches, you usually manage loading state yourself:
|
|
591
|
+
|
|
592
|
+
```html
|
|
593
|
+
<script>
|
|
594
|
+
const [loading, setLoading] = pp.state(false);
|
|
595
|
+
const [items, setItems] = pp.state([]);
|
|
596
|
+
|
|
597
|
+
async function loadItems() {
|
|
598
|
+
setLoading(true);
|
|
599
|
+
|
|
600
|
+
try {
|
|
601
|
+
const response = await pp.fetchFunction("getItems");
|
|
602
|
+
setItems(response.items ?? []);
|
|
603
|
+
} finally {
|
|
604
|
+
setLoading(false);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
</script>
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
## Security and backend rules
|
|
611
|
+
|
|
612
|
+
When fetching data from Prisma PHP:
|
|
613
|
+
|
|
614
|
+
- validate incoming values on the server
|
|
615
|
+
- use `Validator` as the default PHP validation layer for interactive requests
|
|
616
|
+
- prefer the `Rule` builder for rule-based validation
|
|
617
|
+
- every function called through `pp.fetchFunction(...)` must use `#[Exposed]`
|
|
618
|
+
- return structured validation results instead of relying on thrown exceptions for routine failures
|
|
619
|
+
- use `Exposed` options to enforce auth, roles, or rate limits
|
|
620
|
+
- prefer `route.php` for dedicated public or integration-facing endpoints
|
|
621
|
+
- keep sensitive database access on the server side
|
|
622
|
+
|
|
623
|
+
Because Prisma PHP runs the data logic in PHP, database credentials and internal query logic stay on the server.
|
|
624
|
+
|
|
625
|
+
## Good to know
|
|
626
|
+
|
|
627
|
+
- Prisma PHP’s primary interactive fetch model is `pp.fetchFunction(...)`.
|
|
628
|
+
- `index.php` is the UI entry point for page rendering.
|
|
629
|
+
- `route.php` is the direct handler entry point for API-style routes.
|
|
630
|
+
- `pp.fetchFunction(...)` only works for functions that are explicitly marked with `#[Exposed]`.
|
|
631
|
+
- `pp.fetchFunction(...)` automatically serializes and parses data.
|
|
632
|
+
- `Validator` is the default PHP validation layer for reactive requests and backend handlers.
|
|
633
|
+
- prefer `Validator::withRules(...)` with `Rule` for rule-based validation.
|
|
634
|
+
- `abortPrevious: true` helps cancel stale requests.
|
|
635
|
+
- file uploads can be handled automatically without manual `FormData` in many cases.
|
|
636
|
+
- `Exposed` can be used to declare authentication, allowed roles, and rate limits for callable functions.
|
|
637
|
+
- for full-stack routes, load page data in `index.php` and use direct function invocation for interactive updates.
|