create-prisma-php-app 1.26.503 → 1.26.505
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/bootstrap.php +85 -24
- package/dist/index.js +1 -1
- package/dist/settings/auto-swagger-docs.ts +409 -214
- package/dist/settings/bs-config.ts +2 -2
- package/dist/settings/prisma-schema-config.json +13 -4
- package/dist/settings/project-name.ts +10 -7
- package/dist/settings/swagger-config.ts +5 -4
- package/dist/src/Lib/AI/ChatGPTClient.php +2 -0
- package/dist/src/Lib/Auth/Auth.php +5 -3
- package/dist/src/Lib/Auth/AuthConfig.php +2 -0
- package/dist/src/Lib/FileManager/UploadFile.php +2 -0
- package/dist/src/Lib/Headers/Boom.php +2 -0
- package/dist/src/Lib/MainLayout.php +2 -0
- package/dist/src/Lib/Middleware/AuthMiddleware.php +2 -0
- package/dist/src/Lib/PHPMailer/Mailer.php +2 -0
- package/dist/src/Lib/PrismaPHPSettings.php +71 -15
- package/dist/src/Lib/Request.php +79 -33
- package/dist/src/Lib/StateManager.php +2 -0
- package/dist/src/Lib/Validator.php +2 -0
- package/dist/src/Lib/Websocket/ConnectionManager.php +2 -0
- package/dist/src/Lib/Websocket/server.php +2 -0
- package/dist/src/app/js/index.js +1 -1
- package/package.json +1 -1
|
@@ -7,12 +7,145 @@ import { swaggerConfig } from "./swagger-config.js";
|
|
|
7
7
|
import { getFileMeta } from "./utils.js";
|
|
8
8
|
import prismaSchemaConfigJson from "./prisma-schema-config.json";
|
|
9
9
|
import prompts from "prompts";
|
|
10
|
+
import { exit } from "process";
|
|
10
11
|
|
|
11
12
|
const { __dirname } = getFileMeta();
|
|
12
13
|
const prismaSchemaJsonPath = resolve(__dirname, "./prisma-schema.json");
|
|
13
14
|
|
|
15
|
+
type PrismaSchemaConfig = {
|
|
16
|
+
swaggerDocsDir: string;
|
|
17
|
+
skipDefaultName: string[];
|
|
18
|
+
skipByPropertyValue: Record<string, boolean>;
|
|
19
|
+
skipFields: string[];
|
|
20
|
+
generateEndpoints: boolean;
|
|
21
|
+
generatePhpClasses: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type Field = {
|
|
25
|
+
name: string;
|
|
26
|
+
kind: string;
|
|
27
|
+
isList: boolean;
|
|
28
|
+
isRequired: boolean;
|
|
29
|
+
isUnique: boolean;
|
|
30
|
+
isId: boolean;
|
|
31
|
+
isReadOnly: boolean;
|
|
32
|
+
hasDefaultValue: boolean;
|
|
33
|
+
type: string;
|
|
34
|
+
isGenerated: boolean;
|
|
35
|
+
isUpdatedAt: boolean;
|
|
36
|
+
default?: {
|
|
37
|
+
name: string;
|
|
38
|
+
args: any[];
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function shouldSkipField(field: Field): boolean {
|
|
43
|
+
const config: PrismaSchemaConfig = prismaSchemaConfigJson;
|
|
44
|
+
|
|
45
|
+
if (field.kind === "object") {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Skip fields that are explicitly marked to be skipped by name
|
|
50
|
+
if (config.skipFields && config.skipFields.includes(field.name)) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Skip fields based on specific property values defined in skipByPropertyValue
|
|
55
|
+
for (const [property, value] of Object.entries(config.skipByPropertyValue)) {
|
|
56
|
+
if ((field as any)[property] === value) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Skip ID fields with auto-creation during creation
|
|
62
|
+
if (config.skipDefaultName.includes(field.default?.name || "")) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Function to determine an appropriate example based on the field type for Prisma ORM
|
|
70
|
+
function getExampleValue(field: Field): any {
|
|
71
|
+
const fieldType = field.type.toLowerCase();
|
|
72
|
+
|
|
73
|
+
if (field.isId) {
|
|
74
|
+
// Provide examples based on common ID types
|
|
75
|
+
if (field.hasDefaultValue) {
|
|
76
|
+
switch (field.default?.name.toLowerCase()) {
|
|
77
|
+
case "uuid(4)":
|
|
78
|
+
return `"123e4567-e89b-12d3-a456-426614174000"`; // Example for UUID IDs
|
|
79
|
+
case "cuid":
|
|
80
|
+
return `"cjrscj5d40002s6s0b6nq9jfg"`; // Example for CUID IDs
|
|
81
|
+
case "autoincrement":
|
|
82
|
+
return 1; // Example for auto-increment IDs
|
|
83
|
+
default:
|
|
84
|
+
return `"${field.name}"`; // Default example for unknown ID types
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
switch (fieldType) {
|
|
88
|
+
case "int":
|
|
89
|
+
case "bigint":
|
|
90
|
+
return 123; // Example for integer and BigInt IDs
|
|
91
|
+
default:
|
|
92
|
+
return `"${field.name}"`; // Default example for unknown ID types
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Example values for other field types
|
|
98
|
+
switch (fieldType) {
|
|
99
|
+
case "int":
|
|
100
|
+
case "bigint":
|
|
101
|
+
return 123; // Example for integer and BigInt types
|
|
102
|
+
case "float":
|
|
103
|
+
case "decimal":
|
|
104
|
+
return 123.45; // Example for floating-point types
|
|
105
|
+
case "boolean":
|
|
106
|
+
return true; // Example for boolean types
|
|
107
|
+
case "string":
|
|
108
|
+
return `"${field.name}"`; // Example for string types
|
|
109
|
+
case "datetime":
|
|
110
|
+
return `"2024-01-01T00:00:00Z"`; // Example for date/time types
|
|
111
|
+
case "json":
|
|
112
|
+
return `{"key": "value"}`; // Example for JSON type
|
|
113
|
+
case "uuid":
|
|
114
|
+
return `"123e4567-e89b-12d3-a456-426614174000"`; // Example for UUID type
|
|
115
|
+
case "cuid":
|
|
116
|
+
return `"cjrscj5d40002s6s0b6nq9jfg"`; // Example for CUID type
|
|
117
|
+
default:
|
|
118
|
+
return `"${field.name}"`; // Default example for unrecognized types
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Convert a Prisma field type to a Swagger-supported type.
|
|
124
|
+
* @param prismaType The type of the field as defined in the Prisma schema
|
|
125
|
+
* @returns A Swagger-compatible type
|
|
126
|
+
*/
|
|
127
|
+
function convertPrismaTypeToSwaggerType(prismaType: string): string {
|
|
128
|
+
// Map Prisma types to Swagger-compatible types
|
|
129
|
+
const typeMapping: Record<string, string> = {
|
|
130
|
+
String: "string",
|
|
131
|
+
Int: "integer",
|
|
132
|
+
BigInt: "integer",
|
|
133
|
+
Float: "number",
|
|
134
|
+
Decimal: "number",
|
|
135
|
+
Boolean: "boolean",
|
|
136
|
+
DateTime: "string", // For Swagger, we use "string" with format date-time
|
|
137
|
+
Json: "object",
|
|
138
|
+
UUID: "string",
|
|
139
|
+
CUID: "string",
|
|
140
|
+
Bytes: "string", // Can be represented as base64 strings in Swagger
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Default to "string" if the type is not found in the mapping
|
|
144
|
+
return typeMapping[prismaType] || "string";
|
|
145
|
+
}
|
|
146
|
+
|
|
14
147
|
// Function to generate properties for Swagger annotations
|
|
15
|
-
function generateProperties(fields:
|
|
148
|
+
function generateProperties(fields: Field[]): {
|
|
16
149
|
properties: string;
|
|
17
150
|
allProperties: string;
|
|
18
151
|
} {
|
|
@@ -24,24 +157,21 @@ function generateProperties(fields: any[]): {
|
|
|
24
157
|
return;
|
|
25
158
|
}
|
|
26
159
|
|
|
27
|
-
const example =
|
|
160
|
+
const example = getExampleValue(field);
|
|
161
|
+
const fieldType = convertPrismaTypeToSwaggerType(field.type); // Convert Prisma type to Swagger type
|
|
28
162
|
allProperties += `
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
163
|
+
* ${field.name}:
|
|
164
|
+
* type: ${fieldType}
|
|
165
|
+
* example: ${example}`;
|
|
32
166
|
|
|
33
|
-
if (
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (prismaSchemaConfigJson.skipDefaultName.includes(field.default?.name)) {
|
|
167
|
+
if (shouldSkipField(field)) {
|
|
38
168
|
return;
|
|
39
169
|
}
|
|
40
170
|
|
|
41
171
|
properties += `
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
172
|
+
* ${field.name}:
|
|
173
|
+
* type: ${fieldType}
|
|
174
|
+
* example: ${example}`;
|
|
45
175
|
});
|
|
46
176
|
|
|
47
177
|
return { properties, allProperties };
|
|
@@ -54,170 +184,143 @@ function toKebabCase(str: string): string {
|
|
|
54
184
|
.toLowerCase();
|
|
55
185
|
}
|
|
56
186
|
|
|
187
|
+
// Function to find the ID field from the model
|
|
188
|
+
function getIdField(fields: Field[]): Field | undefined {
|
|
189
|
+
return fields.find((field) => field.isId);
|
|
190
|
+
}
|
|
191
|
+
|
|
57
192
|
// Function to generate Swagger annotation for a CRUD operation
|
|
58
|
-
function generateSwaggerAnnotation(modelName: string, fields:
|
|
193
|
+
function generateSwaggerAnnotation(modelName: string, fields: Field[]): string {
|
|
194
|
+
// Extract the ID field dynamically
|
|
195
|
+
const idField = getIdField(fields);
|
|
196
|
+
if (!idField) {
|
|
197
|
+
throw new Error(`No ID field found for model: ${modelName}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const idFieldName = idField.name;
|
|
201
|
+
const idFieldType = convertPrismaTypeToSwaggerType(idField.type); // Convert Prisma type to Swagger type
|
|
59
202
|
const { properties, allProperties } = generateProperties(fields);
|
|
60
203
|
const kebabCaseModelName = toKebabCase(modelName);
|
|
61
204
|
|
|
62
205
|
return `/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Function to generate dynamic validation rules and request payloads
|
|
185
|
-
function generateValidationAndPayload(fields: any[]) {
|
|
186
|
-
let validations = "";
|
|
187
|
-
let payload = "";
|
|
188
|
-
let variableAssignments = "";
|
|
189
|
-
|
|
190
|
-
fields.forEach((field) => {
|
|
191
|
-
if (field.kind === "object") return; // Skip relations for now
|
|
192
|
-
|
|
193
|
-
// Skip fields that are explicitly marked to be skipped
|
|
194
|
-
if (prismaSchemaConfigJson.skipFields.includes(field.name)) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Skip ID fields with auto-creation during creation
|
|
199
|
-
if (prismaSchemaConfigJson.skipDefaultName.includes(field.default?.name)) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Define variable assignments
|
|
204
|
-
const variableName = field.name;
|
|
205
|
-
variableAssignments += `$${variableName} = Request::$params->${variableName} ?? null;\n`;
|
|
206
|
-
|
|
207
|
-
// Dynamic validation for required fields (excluding skipped fields)
|
|
208
|
-
if (field.isRequired) {
|
|
209
|
-
const fieldType = field.type.toLowerCase();
|
|
210
|
-
validations += `
|
|
211
|
-
if (!Validator::${fieldType}($${variableName})) {
|
|
212
|
-
Boom::badRequest("Invalid ${variableName}")->toResponse();
|
|
213
|
-
}`;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Prepare payload dynamically
|
|
217
|
-
payload += `'${variableName}' => $${variableName},\n `;
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
return { validations, payload, variableAssignments };
|
|
206
|
+
* @swagger
|
|
207
|
+
* tags:
|
|
208
|
+
* name: ${modelName}
|
|
209
|
+
* description: ${modelName} management API
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @swagger
|
|
214
|
+
* /${kebabCaseModelName}:
|
|
215
|
+
* get:
|
|
216
|
+
* summary: Retrieve a list of ${modelName}
|
|
217
|
+
* tags:
|
|
218
|
+
* - ${modelName}
|
|
219
|
+
* responses:
|
|
220
|
+
* 200:
|
|
221
|
+
* description: A list of ${modelName}
|
|
222
|
+
* content:
|
|
223
|
+
* application/json:
|
|
224
|
+
* schema:
|
|
225
|
+
* type: array
|
|
226
|
+
* items:
|
|
227
|
+
* type: object
|
|
228
|
+
* properties:${allProperties}
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @swagger
|
|
233
|
+
* /${kebabCaseModelName}/{${idFieldName}}:
|
|
234
|
+
* get:
|
|
235
|
+
* summary: Retrieve a single ${modelName} by ${idFieldName}
|
|
236
|
+
* tags:
|
|
237
|
+
* - ${modelName}
|
|
238
|
+
* parameters:
|
|
239
|
+
* - in: path
|
|
240
|
+
* name: ${idFieldName}
|
|
241
|
+
* required: true
|
|
242
|
+
* description: The ${modelName} ${idFieldName}
|
|
243
|
+
* schema:
|
|
244
|
+
* type: ${idFieldType}
|
|
245
|
+
* responses:
|
|
246
|
+
* 200:
|
|
247
|
+
* description: A single ${modelName} object
|
|
248
|
+
* content:
|
|
249
|
+
* application/json:
|
|
250
|
+
* schema:
|
|
251
|
+
* type: object
|
|
252
|
+
* properties:${allProperties}
|
|
253
|
+
* 404:
|
|
254
|
+
* description: ${modelName} not found
|
|
255
|
+
*/
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* @swagger
|
|
259
|
+
* /${kebabCaseModelName}/create:
|
|
260
|
+
* post:
|
|
261
|
+
* summary: Create a new ${modelName}
|
|
262
|
+
* tags:
|
|
263
|
+
* - ${modelName}
|
|
264
|
+
* requestBody:
|
|
265
|
+
* required: true
|
|
266
|
+
* content:
|
|
267
|
+
* application/json:
|
|
268
|
+
* schema:
|
|
269
|
+
* type: object
|
|
270
|
+
* properties:${properties}
|
|
271
|
+
* responses:
|
|
272
|
+
* 201:
|
|
273
|
+
* description: ${modelName} created successfully.
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @swagger
|
|
278
|
+
* /${kebabCaseModelName}/update/{${idFieldName}}:
|
|
279
|
+
* put:
|
|
280
|
+
* summary: Update a ${modelName} by ${idFieldName}
|
|
281
|
+
* tags:
|
|
282
|
+
* - ${modelName}
|
|
283
|
+
* parameters:
|
|
284
|
+
* - in: path
|
|
285
|
+
* name: ${idFieldName}
|
|
286
|
+
* required: true
|
|
287
|
+
* description: The ${modelName} ${idFieldName}
|
|
288
|
+
* schema:
|
|
289
|
+
* type: ${idFieldType}
|
|
290
|
+
* requestBody:
|
|
291
|
+
* required: true
|
|
292
|
+
* content:
|
|
293
|
+
* application/json:
|
|
294
|
+
* schema:
|
|
295
|
+
* type: object
|
|
296
|
+
* properties:${properties}
|
|
297
|
+
* responses:
|
|
298
|
+
* 200:
|
|
299
|
+
* description: ${modelName} updated successfully.
|
|
300
|
+
* 404:
|
|
301
|
+
* description: ${modelName} not found
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @swagger
|
|
306
|
+
* /${kebabCaseModelName}/delete/{${idFieldName}}:
|
|
307
|
+
* delete:
|
|
308
|
+
* summary: Delete a ${modelName} by ${idFieldName}
|
|
309
|
+
* tags:
|
|
310
|
+
* - ${modelName}
|
|
311
|
+
* parameters:
|
|
312
|
+
* - in: path
|
|
313
|
+
* name: ${idFieldName}
|
|
314
|
+
* required: true
|
|
315
|
+
* description: The ${modelName} ${idFieldName}
|
|
316
|
+
* schema:
|
|
317
|
+
* type: ${idFieldType}
|
|
318
|
+
* responses:
|
|
319
|
+
* 204:
|
|
320
|
+
* description: ${modelName} successfully deleted
|
|
321
|
+
* 404:
|
|
322
|
+
* description: ${modelName} not found
|
|
323
|
+
*/`;
|
|
221
324
|
}
|
|
222
325
|
|
|
223
326
|
// Function to generate dynamic ID validation logic for update and find-by-ID routes
|
|
@@ -241,6 +344,10 @@ function generateEndpoints(modelName: string, fields: any[]): void {
|
|
|
241
344
|
modelName.charAt(0).toLowerCase() + modelName.slice(1);
|
|
242
345
|
const baseDir = `src/app/${kebabCasedModelName}`;
|
|
243
346
|
const idField = fields.find((field) => field.isId);
|
|
347
|
+
const fieldsToCreateAndUpdate = fields.filter(
|
|
348
|
+
(field) => shouldSkipField(field) === false
|
|
349
|
+
);
|
|
350
|
+
const idFieldName = idField.name;
|
|
244
351
|
const baseDirPath = resolve(__dirname, `../${baseDir}`);
|
|
245
352
|
|
|
246
353
|
mkdirSync(baseDirPath, { recursive: true });
|
|
@@ -279,7 +386,7 @@ ${idValidationLogic}
|
|
|
279
386
|
|
|
280
387
|
$${camelCaseModelName} = $prisma->${camelCaseModelName}->findUnique([
|
|
281
388
|
'where' => [
|
|
282
|
-
'
|
|
389
|
+
'${idFieldName}' => $id
|
|
283
390
|
]
|
|
284
391
|
]);
|
|
285
392
|
|
|
@@ -295,15 +402,10 @@ echo json_encode($${camelCaseModelName});`;
|
|
|
295
402
|
);
|
|
296
403
|
|
|
297
404
|
// Endpoint: POST /{kebabCasedModelName}/create
|
|
298
|
-
const {
|
|
299
|
-
validations: createValidations,
|
|
300
|
-
payload: createPayload,
|
|
301
|
-
variableAssignments,
|
|
302
|
-
} = generateValidationAndPayload(fields);
|
|
303
|
-
|
|
304
405
|
const createDir = `${baseDir}/create`;
|
|
305
406
|
mkdirSync(resolve(__dirname, `../${createDir}`), { recursive: true });
|
|
306
407
|
const createRoutePath = `${createDir}/route.php`;
|
|
408
|
+
|
|
307
409
|
const createRouteContent = `<?php
|
|
308
410
|
|
|
309
411
|
use Lib\\Prisma\\Classes\\Prisma;
|
|
@@ -312,26 +414,57 @@ use Lib\\Headers\\Boom;
|
|
|
312
414
|
use Lib\\Request;
|
|
313
415
|
|
|
314
416
|
$prisma = Prisma::getInstance();
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
417
|
+
|
|
418
|
+
// Define fields with their types, required status, and validation functions
|
|
419
|
+
$fieldsWithTypesAndStatus = [
|
|
420
|
+
${fieldsToCreateAndUpdate
|
|
421
|
+
.map(
|
|
422
|
+
(field) =>
|
|
423
|
+
` '${field.name}' => [
|
|
424
|
+
'type' => '${field.type.toLowerCase()}',
|
|
425
|
+
'required' => ${field.isRequired ? "true" : "false"},
|
|
426
|
+
'validate' => fn($value) => is_null($value) || $value === '' || Validator::${field.type.toLowerCase()}($value)
|
|
427
|
+
]`
|
|
428
|
+
)
|
|
429
|
+
.join(",\n")}
|
|
430
|
+
];
|
|
431
|
+
|
|
432
|
+
$data = [];
|
|
433
|
+
foreach ($fieldsWithTypesAndStatus as $field => $details) {
|
|
434
|
+
$isRequired = $details['required'];
|
|
435
|
+
$type = $details['type'];
|
|
436
|
+
$validationFn = $details['validate'];
|
|
437
|
+
|
|
438
|
+
// Check if the field is required and missing in the request
|
|
439
|
+
if ($isRequired && !isset(Request::$params->$field)) {
|
|
440
|
+
Boom::badRequest("Missing {$field}")->toResponse();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Check if the field is present in the request
|
|
444
|
+
if (isset(Request::$params->$field)) {
|
|
445
|
+
$value = Request::$params->$field;
|
|
446
|
+
|
|
447
|
+
// Validate the field using the validation function
|
|
448
|
+
if (!$validationFn($value)) {
|
|
449
|
+
Boom::badRequest("Invalid {$field}", ["Expected type '{$type}'"])->toResponse();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Assign the validated value to the data array
|
|
453
|
+
$data[$field] = $value;
|
|
454
|
+
}
|
|
324
455
|
}
|
|
325
456
|
|
|
457
|
+
// Create the new record using the Prisma instance
|
|
326
458
|
$new${modelName} = $prisma->${camelCaseModelName}->create([
|
|
327
|
-
'data' =>
|
|
328
|
-
${createPayload}
|
|
329
|
-
]
|
|
459
|
+
'data' => $data
|
|
330
460
|
]);
|
|
331
461
|
|
|
462
|
+
// Handle potential internal server error
|
|
332
463
|
if (!$new${modelName}) {
|
|
333
464
|
Boom::internal()->toResponse();
|
|
334
465
|
}
|
|
466
|
+
|
|
467
|
+
// Return the newly created record in JSON format
|
|
335
468
|
echo json_encode($new${modelName});`;
|
|
336
469
|
|
|
337
470
|
writeFileSync(
|
|
@@ -341,12 +474,10 @@ echo json_encode($new${modelName});`;
|
|
|
341
474
|
);
|
|
342
475
|
|
|
343
476
|
// Endpoint: PUT /{kebabCasedModelName}/update/{id}
|
|
344
|
-
const { validations: updateValidations, payload: updatePayload } =
|
|
345
|
-
generateValidationAndPayload(fields);
|
|
346
|
-
|
|
347
477
|
const updateDir = `${baseDir}/update/[id]`;
|
|
348
478
|
mkdirSync(resolve(__dirname, `../${updateDir}`), { recursive: true });
|
|
349
479
|
const updateRoutePath = `${updateDir}/route.php`;
|
|
480
|
+
|
|
350
481
|
const updateRouteContent = `<?php
|
|
351
482
|
|
|
352
483
|
use Lib\\Prisma\\Classes\\Prisma;
|
|
@@ -356,29 +487,65 @@ use Lib\\Request;
|
|
|
356
487
|
|
|
357
488
|
$prisma = Prisma::getInstance();
|
|
358
489
|
$id = Request::$dynamicParams->id ?? null;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
490
|
+
|
|
491
|
+
// Perform validation for the ID
|
|
492
|
+
if (!Validator::int($id)) {
|
|
493
|
+
Boom::badRequest("Invalid id")->toResponse();
|
|
363
494
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
495
|
+
|
|
496
|
+
// Define fields with their types, required status, and validation functions
|
|
497
|
+
$fieldsWithTypesAndStatus = [
|
|
498
|
+
${fieldsToCreateAndUpdate
|
|
499
|
+
.map(
|
|
500
|
+
(field) =>
|
|
501
|
+
` '${field.name}' => [
|
|
502
|
+
'type' => '${field.type.toLowerCase()}',
|
|
503
|
+
'required' => ${field.isRequired ? "true" : "false"},
|
|
504
|
+
'validate' => fn($value) => is_null($value) || $value === '' || Validator::${field.type.toLowerCase()}($value)
|
|
505
|
+
]`
|
|
506
|
+
)
|
|
507
|
+
.join(",\n")}
|
|
508
|
+
];
|
|
509
|
+
|
|
510
|
+
$data = [];
|
|
511
|
+
foreach ($fieldsWithTypesAndStatus as $field => $details) {
|
|
512
|
+
$isRequired = $details['required'];
|
|
513
|
+
$type = $details['type'];
|
|
514
|
+
$validationFn = $details['validate'];
|
|
515
|
+
|
|
516
|
+
// Check if the field is required and missing in the request
|
|
517
|
+
if ($isRequired && !isset(Request::$params->$field)) {
|
|
518
|
+
Boom::badRequest("Missing {$field}")->toResponse();
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Check if the field is present in the request
|
|
522
|
+
if (isset(Request::$params->$field)) {
|
|
523
|
+
$value = Request::$params->$field;
|
|
524
|
+
|
|
525
|
+
// Validate the field using the validation function
|
|
526
|
+
if (!$validationFn($value)) {
|
|
527
|
+
Boom::badRequest("Invalid {$field}", ["Expected type '{$type}'"])->toResponse();
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Assign the validated value to the data array
|
|
531
|
+
$data[$field] = $value;
|
|
532
|
+
}
|
|
369
533
|
}
|
|
370
534
|
|
|
535
|
+
// Update the record
|
|
371
536
|
$updated${modelName} = $prisma->${camelCaseModelName}->update([
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
${updatePayload}
|
|
375
|
-
]
|
|
537
|
+
'where' => ['${idFieldName}' => $id],
|
|
538
|
+
'data' => $data,
|
|
376
539
|
]);
|
|
377
540
|
|
|
541
|
+
// Handle potential internal server error
|
|
378
542
|
if (!$updated${modelName}) {
|
|
379
|
-
|
|
543
|
+
Boom::notFound()->toResponse();
|
|
380
544
|
}
|
|
381
|
-
|
|
545
|
+
|
|
546
|
+
// Return the updated record in JSON format
|
|
547
|
+
echo json_encode($updated${modelName});
|
|
548
|
+
`;
|
|
382
549
|
|
|
383
550
|
writeFileSync(
|
|
384
551
|
resolve(__dirname, `../${updateRoutePath}`),
|
|
@@ -403,7 +570,7 @@ ${idValidationLogic}
|
|
|
403
570
|
|
|
404
571
|
$deleted${modelName} = $prisma->${camelCaseModelName}->delete([
|
|
405
572
|
'where' => [
|
|
406
|
-
'
|
|
573
|
+
'${idFieldName}' => $id
|
|
407
574
|
]
|
|
408
575
|
]);
|
|
409
576
|
|
|
@@ -421,6 +588,33 @@ echo json_encode($deleted${modelName});`;
|
|
|
421
588
|
|
|
422
589
|
async function promptUserForGenerationOptions() {
|
|
423
590
|
const response = await prompts([
|
|
591
|
+
{
|
|
592
|
+
type: "confirm",
|
|
593
|
+
name: "generateApisOnly",
|
|
594
|
+
message: "Do you want to generate swagger docs only?",
|
|
595
|
+
initial: false,
|
|
596
|
+
},
|
|
597
|
+
]);
|
|
598
|
+
|
|
599
|
+
// If the user wants to generate only Swagger docs
|
|
600
|
+
if (response.generateApisOnly) {
|
|
601
|
+
// Update the configuration
|
|
602
|
+
prismaSchemaConfigJson.generateSwaggerDocsOnly = true;
|
|
603
|
+
|
|
604
|
+
// Save the updated settings back to the JSON file if needed
|
|
605
|
+
writeFileSync(
|
|
606
|
+
resolve(__dirname, "./prisma-schema-config.json"),
|
|
607
|
+
JSON.stringify(prismaSchemaConfigJson, null, 2),
|
|
608
|
+
"utf-8"
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
// Generate Swagger docs and exit
|
|
612
|
+
await swaggerConfig();
|
|
613
|
+
exit(0); // Exit the process here
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// If the user did not select generateApisOnly, ask for other options
|
|
617
|
+
const otherResponses = await prompts([
|
|
424
618
|
{
|
|
425
619
|
type: "confirm",
|
|
426
620
|
name: "generateEndpoints",
|
|
@@ -435,11 +629,12 @@ async function promptUserForGenerationOptions() {
|
|
|
435
629
|
},
|
|
436
630
|
]);
|
|
437
631
|
|
|
438
|
-
// Update the configuration based on
|
|
439
|
-
prismaSchemaConfigJson.
|
|
440
|
-
prismaSchemaConfigJson.
|
|
632
|
+
// Update the configuration based on other responses
|
|
633
|
+
prismaSchemaConfigJson.generateSwaggerDocsOnly = false;
|
|
634
|
+
prismaSchemaConfigJson.generateEndpoints = otherResponses.generateEndpoints;
|
|
635
|
+
prismaSchemaConfigJson.generatePhpClasses = otherResponses.generatePhpClasses;
|
|
441
636
|
|
|
442
|
-
//
|
|
637
|
+
// Save the updated settings back to the JSON file
|
|
443
638
|
writeFileSync(
|
|
444
639
|
resolve(__dirname, "./prisma-schema-config.json"),
|
|
445
640
|
JSON.stringify(prismaSchemaConfigJson, null, 2),
|