create-prisma-php-app 1.21.500 → 1.22.500

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.
@@ -25,8 +25,17 @@ function determineContentToInclude()
25
25
  $baseDir = APP_PATH;
26
26
  $includePath = '';
27
27
  $layoutsToInclude = [];
28
- writeRoutes();
28
+
29
+ /**
30
+ * ============ Middleware Management ============
31
+ * AuthMiddleware is invoked to handle authentication logic for the current route ($uri).
32
+ * ================================================
33
+ */
29
34
  AuthMiddleware::handle($uri);
35
+ /**
36
+ * ============ End of Middleware Management ======
37
+ * ================================================
38
+ */
30
39
 
31
40
  $isDirectAccessToPrivateRoute = preg_match('/\/_/', $uri);
32
41
  if ($isDirectAccessToPrivateRoute) {
@@ -107,31 +116,23 @@ function getFilePrecedence()
107
116
  global $_filesListRoutes;
108
117
 
109
118
  // Normalize the file paths for consistent comparison
110
- $_filesListRoutes = array_map(function ($route) {
111
- return str_replace('\\', '/', $route);
112
- }, $_filesListRoutes);
113
-
114
- // Look for route.php in the /src/app/ directory
115
- $routeFile = array_filter($_filesListRoutes, function ($route) {
116
- return preg_match('/^\.\/src\/app\/route\.php$/', $route);
117
- });
118
-
119
- // If route.php is found, return just the file name
120
- if (!empty($routeFile)) {
121
- return '/route.php';
119
+ foreach ($_filesListRoutes as $route) {
120
+ $normalizedRoute = str_replace('\\', '/', $route);
121
+ // First, check for route.php
122
+ if (preg_match('/^\.\/src\/app\/route\.php$/', $normalizedRoute)) {
123
+ return '/route.php';
124
+ }
122
125
  }
123
126
 
124
- // If route.php is not found, look for index.php in the /src/app/ directory
125
- $indexFile = array_filter($_filesListRoutes, function ($route) {
126
- return preg_match('/^\.\/src\/app\/index\.php$/', $route);
127
- });
128
-
129
- // If index.php is found, return just the file name
130
- if (!empty($indexFile)) {
131
- return '/index.php';
127
+ // If no route.php is found, check for index.php
128
+ foreach ($_filesListRoutes as $route) {
129
+ $normalizedRoute = str_replace('\\', '/', $route);
130
+ if (preg_match('/^\.\/src\/app\/index\.php$/', $normalizedRoute)) {
131
+ return '/index.php';
132
+ }
132
133
  }
133
134
 
134
- // If neither file is found, return null or handle the case as needed
135
+ // If neither file is found, return null
135
136
  return null;
136
137
  }
137
138
 
@@ -145,42 +146,19 @@ function uriExtractor(string $scriptUrl): string
145
146
  }
146
147
 
147
148
  $escapedIdentifier = preg_quote($projectName, '/');
148
- $pattern = "/(?:.*$escapedIdentifier)(\/.*)$/";
149
- if (preg_match($pattern, $scriptUrl, $matches)) {
150
- if (!empty($matches[1])) {
151
- $leftTrim = ltrim($matches[1], '/');
152
- $rightTrim = rtrim($leftTrim, '/');
153
- return "$rightTrim";
154
- }
149
+ if (preg_match("/(?:.*$escapedIdentifier)(\/.*)$/", $scriptUrl, $matches) && !empty($matches[1])) {
150
+ return rtrim(ltrim($matches[1], '/'), '/');
155
151
  }
156
152
 
157
153
  return "/";
158
154
  }
159
155
 
160
- function writeRoutes()
156
+ function getFilesListRoutes()
161
157
  {
162
- global $_filesListRoutes;
163
- $directory = './src/app';
164
-
165
- if (is_dir($directory)) {
166
- $filesList = [];
167
-
168
- $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
169
-
170
- foreach ($iterator as $file) {
171
- if ($file->isFile()) {
172
- $filesList[] = $file->getPathname();
173
- }
174
- }
175
-
176
- $jsonData = json_encode($filesList, JSON_PRETTY_PRINT);
177
- $jsonFileName = SETTINGS_PATH . '/files-list.json';
178
- file_put_contents($jsonFileName, $jsonData);
158
+ $jsonFileName = SETTINGS_PATH . '/files-list.json';
159
+ $routeFiles = file_exists($jsonFileName) ? json_decode(file_get_contents($jsonFileName), true) : [];
179
160
 
180
- if (file_exists($jsonFileName)) {
181
- $_filesListRoutes = json_decode(file_get_contents($jsonFileName), true);
182
- }
183
- }
161
+ return $routeFiles;
184
162
  }
185
163
 
186
164
  function findGroupFolder($uri): string
@@ -213,14 +191,21 @@ function dynamicRoute($uri)
213
191
  foreach ($_filesListRoutes as $route) {
214
192
  $normalizedRoute = trim(str_replace('\\', '/', $route), '.');
215
193
  $routeSegments = explode('/', ltrim($normalizedRoute, '/'));
194
+
195
+ $filteredRouteSegments = array_values(array_filter($routeSegments, function ($segment) {
196
+ return !preg_match('/\(.+\)/', $segment); // Skip segments with parentheses (groups)
197
+ }));
198
+
216
199
  $singleDynamic = preg_match_all('/\[[^\]]+\]/', $normalizedRoute, $matches) === 1 && !strpos($normalizedRoute, '[...');
217
200
  if ($singleDynamic) {
218
- $segmentMatch = singleDynamicRoute($uriSegments, $routeSegments);
219
- if (!empty($segmentMatch)) {
201
+ $segmentMatch = singleDynamicRoute($uriSegments, $filteredRouteSegments);
202
+ $index = array_search($segmentMatch, $filteredRouteSegments);
203
+ if ($index !== false && isset($uriSegments[$index])) {
220
204
  $trimSegmentMatch = trim($segmentMatch, '[]');
221
- $dynamicRouteParams = new \ArrayObject([$trimSegmentMatch => $uriSegments[array_search($segmentMatch, $routeSegments)]], \ArrayObject::ARRAY_AS_PROPS);
222
-
223
- $dynamicRouteUri = str_replace($segmentMatch, $uriSegments[array_search($segmentMatch, $routeSegments)], $normalizedRoute);
205
+ $dynamicRouteParams = new \ArrayObject([$trimSegmentMatch => $uriSegments[$index]], \ArrayObject::ARRAY_AS_PROPS);
206
+ $dynamicRouteUri = str_replace($segmentMatch, $uriSegments[$index], $normalizedRoute);
207
+ $dynamicRouteUri = preg_replace('/\(.+\)/', '', $dynamicRouteUri);
208
+ $dynamicRouteUri = preg_replace('/\/+/', '/', $dynamicRouteUri);
224
209
  $dynamicRouteUriDirname = dirname($dynamicRouteUri);
225
210
  $dynamicRouteUriDirname = rtrim($dynamicRouteUriDirname, '/');
226
211
 
@@ -235,30 +220,41 @@ function dynamicRoute($uri)
235
220
  }
236
221
  }
237
222
  } elseif (strpos($normalizedRoute, '[...') !== false) {
238
- $cleanedRoute = preg_replace('/\[\.\.\..*?\].*/', '', $normalizedRoute);
239
- if (strpos('/src/app/' . $normalizedUri, $cleanedRoute) === 0) {
240
-
241
- $normalizedUriEdited = "/src/app/$normalizedUri";
242
- $trimNormalizedUriEdited = str_replace($cleanedRoute, '', $normalizedUriEdited);
243
- $explodedNormalizedUri = explode('/', $trimNormalizedUriEdited);
244
- $pattern = '/\[\.\.\.(.*?)\]/';
245
- if (preg_match($pattern, $normalizedRoute, $matches)) {
246
- $contentWithinBrackets = $matches[1];
247
- $dynamicRouteParams = new \ArrayObject([$contentWithinBrackets => $explodedNormalizedUri], \ArrayObject::ARRAY_AS_PROPS);
223
+ // Clean and normalize the route
224
+ $cleanedNormalizedRoute = preg_replace('/\(.+\)/', '', $normalizedRoute); // Remove any public/private segment
225
+ $cleanedNormalizedRoute = preg_replace('/\/+/', '/', $cleanedNormalizedRoute); // Replace multiple slashes
226
+ $dynamicSegmentRoute = preg_replace('/\[\.\.\..*?\].*/', '', $cleanedNormalizedRoute); // Remove the dynamic segment
227
+
228
+ // Check if the normalized URI starts with the cleaned route
229
+ if (strpos("/src/app/$normalizedUri", $dynamicSegmentRoute) === 0) {
230
+ $trimmedUri = str_replace($dynamicSegmentRoute, '', "/src/app/$normalizedUri");
231
+ $uriParts = explode('/', trim($trimmedUri, '/'));
232
+
233
+ // Extract the dynamic segment content
234
+ if (preg_match('/\[\.\.\.(.*?)\]/', $normalizedRoute, $matches)) {
235
+ $dynamicParam = $matches[1];
236
+ $dynamicRouteParams = new \ArrayObject([$dynamicParam => $uriParts], \ArrayObject::ARRAY_AS_PROPS);
248
237
  }
238
+
239
+ // Check for 'route.php'
249
240
  if (strpos($normalizedRoute, 'route.php') !== false) {
250
241
  $uriMatch = $normalizedRoute;
251
242
  break;
252
- } else {
253
- if (strpos($normalizedRoute, 'index.php') !== false) {
254
- $segmentMatch = "[...$contentWithinBrackets]";
255
- $dynamicRouteUri = str_replace($segmentMatch, $uriSegments[array_search($segmentMatch, $routeSegments)], $normalizedRoute);
256
- $dynamicRouteUriDirname = dirname($dynamicRouteUri);
257
- $dynamicRouteUriDirname = rtrim($dynamicRouteUriDirname, '/');
243
+ }
244
+
245
+ // Handle matching routes ending with 'index.php'
246
+ if (strpos($normalizedRoute, 'index.php') !== false) {
247
+ $segmentMatch = "[...$dynamicParam]";
248
+ $index = array_search($segmentMatch, $filteredRouteSegments);
249
+
250
+ if ($index !== false && isset($uriSegments[$index])) {
251
+ // Generate the dynamic URI
252
+ $dynamicRouteUri = str_replace($segmentMatch, implode('/', $uriParts), $cleanedNormalizedRoute);
253
+ $dynamicRouteUriDirname = rtrim(dirname($dynamicRouteUri), '/');
258
254
 
259
- $expectedUri = '/src/app/' . $normalizedUri;
260
- $expectedUri = rtrim($expectedUri, '/');
255
+ $expectedUri = rtrim("/src/app/$normalizedUri", '/');
261
256
 
257
+ // Compare the expected and dynamic URIs
262
258
  if ($expectedUri === $dynamicRouteUriDirname) {
263
259
  $uriMatch = $normalizedRoute;
264
260
  break;
@@ -280,6 +276,7 @@ function isGroupIdentifier($segment): bool
280
276
  function matchGroupFolder($constructedPath): ?string
281
277
  {
282
278
  global $_filesListRoutes;
279
+
283
280
  $bestMatch = null;
284
281
  $normalizedConstructedPath = ltrim(str_replace('\\', '/', $constructedPath), './');
285
282
 
@@ -330,6 +327,10 @@ function singleDynamicRoute($uriSegments, $routeSegments)
330
327
 
331
328
  function checkForDuplicateRoutes()
332
329
  {
330
+ if ($_ENV['APP_ENV'] !== 'development') {
331
+ return;
332
+ }
333
+
333
334
  global $_filesListRoutes;
334
335
  $normalizedRoutesMap = [];
335
336
  foreach ($_filesListRoutes as $route) {
@@ -363,72 +364,27 @@ function checkForDuplicateRoutes()
363
364
  }
364
365
  }
365
366
 
366
- function setupErrorHandling(&$content)
367
- {
368
- set_error_handler(function ($severity, $message, $file, $line) use (&$content) {
369
- $content .= "<div class='error'>Error: {$severity} - {$message} in {$file} on line {$line}</div>";
370
- });
371
-
372
- set_exception_handler(function ($exception) use (&$content) {
373
- $content .= "<div class='error'>Exception: " . htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8') . "</div>";
374
- });
375
-
376
- register_shutdown_function(function () use (&$content) {
377
- $error = error_get_last();
378
- if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR])) {
379
- $formattedError = "<div class='error'>Fatal Error: " . htmlspecialchars($error['message'], ENT_QUOTES, 'UTF-8') .
380
- " in " . htmlspecialchars($error['file'], ENT_QUOTES, 'UTF-8') .
381
- " on line " . $error['line'] . "</div>";
382
- $content .= $formattedError;
383
- modifyOutputLayoutForError($content);
384
- }
385
- });
386
- }
387
-
388
367
 
389
368
  function containsChildContent($filePath)
390
369
  {
391
370
  $fileContent = file_get_contents($filePath);
392
- if (
393
- (strpos($fileContent, 'echo $childContent') === false &&
394
- strpos($fileContent, 'echo $childContent;') === false) &&
395
- (strpos($fileContent, '<?= $childContent ?>') === false) &&
396
- (strpos($fileContent, '<?= $childContent; ?>') === false)
397
- ) {
398
- return true;
399
- } else {
400
- return false;
401
- }
371
+
372
+ // Regular expression to match different ways of echoing $childContent
373
+ $pattern = '/\<\?=\s*\$childContent\s*;?\s*\?>|echo\s*\$childContent\s*;?/';
374
+
375
+ // Return true if $childContent variables are found, false otherwise
376
+ return preg_match($pattern, $fileContent) === 1;
402
377
  }
403
378
 
404
379
  function containsContent($filePath)
405
380
  {
406
381
  $fileContent = file_get_contents($filePath);
407
- if (
408
- (strpos($fileContent, 'echo $content') === false &&
409
- strpos($fileContent, 'echo $content;') === false) &&
410
- (strpos($fileContent, '<?= $content ?>') === false) &&
411
- (strpos($fileContent, '<?= $content; ?>') === false)
412
- ) {
413
- return true;
414
- } else {
415
- return false;
416
- }
417
- }
418
-
419
- function modifyOutputLayoutForError($contentToAdd)
420
- {
421
- if ($_ENV['SHOW_ERRORS'] === "false") exit;
422
-
423
- $layoutContent = file_get_contents(APP_PATH . '/layout.php');
424
- if ($layoutContent !== false) {
425
- $newBodyContent = "<body class=\"fatal-error\">$contentToAdd</body>";
426
382
 
427
- $modifiedNotFoundContent = preg_replace('~<body.*?>.*?</body>~s', $newBodyContent, $layoutContent);
383
+ // Improved regular expression to match different ways of echoing $content
384
+ $pattern = '/\<\?=\s*\$content\s*;?\s*\?>|echo\s*\$content\s*;?/';
428
385
 
429
- echo $modifiedNotFoundContent;
430
- exit;
431
- }
386
+ // Return true if content variables are found, false otherwise
387
+ return preg_match($pattern, $fileContent) === 1;
432
388
  }
433
389
 
434
390
  function convertToArrayObject($data)
@@ -579,17 +535,7 @@ function getLoadingsFiles()
579
535
  return '';
580
536
  }
581
537
 
582
- function authenticateUserToken()
583
- {
584
- $token = getBearerToken();
585
- if ($token) {
586
- $auth = Auth::getInstance();
587
- $verifyToken = $auth->verifyToken($token);
588
- if ($verifyToken) {
589
- $auth->authenticate($verifyToken);
590
- }
591
- }
592
- }
538
+
593
539
 
594
540
  function getPrismaSettings(): \ArrayObject
595
541
  {
@@ -607,15 +553,101 @@ function getPrismaSettings(): \ArrayObject
607
553
  }
608
554
  }
609
555
 
610
- ob_start();
556
+ function modifyOutputLayoutForError($contentToAdd)
557
+ {
558
+ global
559
+ $baseUrl,
560
+ $metadata,
561
+ $content,
562
+ $childContent,
563
+ $uri,
564
+ $pathname,
565
+ $dynamicRouteParams,
566
+ $params,
567
+ $referer,
568
+ $mainLayoutHead,
569
+ $mainLayoutFooter;
570
+
571
+ $errorFile = APP_PATH . '/error.php';
572
+ $errorFileExists = file_exists($errorFile);
573
+
574
+ if ($_ENV['SHOW_ERRORS'] === "false") {
575
+ if ($errorFileExists) {
576
+ $contentToAdd = "<div class='error'>An error occurred</div>";
577
+ } else {
578
+ exit; // Exit if SHOW_ERRORS is false and no error file exists
579
+ }
580
+ }
581
+
582
+ if ($errorFileExists) {
583
+
584
+ $errorContent = $contentToAdd;
585
+
586
+ $layoutFile = APP_PATH . '/layout.php';
587
+ if (file_exists($layoutFile)) {
588
+
589
+ ob_start();
590
+ include_once $errorFile;
591
+ $content = ob_get_clean();
592
+ include $layoutFile;
593
+ } else {
594
+ echo $errorContent;
595
+ }
596
+ }
597
+ exit;
598
+ }
599
+
600
+ set_error_handler(function ($severity, $message, $file, $line) {
601
+ if (!(error_reporting() & $severity)) {
602
+ // This error code is not included in error_reporting
603
+ return;
604
+ }
605
+
606
+ // Capture the specific severity types, including warnings (E_WARNING)
607
+ $errorContent = "<div class='error'>Error: {$severity} - {$message} in {$file} on line {$line}</div>";
608
+
609
+ // If needed, log it or output immediately based on severity
610
+ if ($severity === E_WARNING || $severity === E_NOTICE) {
611
+ modifyOutputLayoutForError($errorContent);
612
+ }
613
+ });
614
+
615
+ set_exception_handler(function ($exception) {
616
+ $errorContent = "<div class='error'>Exception: " . htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8') . "</div>";
617
+ modifyOutputLayoutForError($errorContent);
618
+ });
619
+
620
+ register_shutdown_function(function () {
621
+ $error = error_get_last();
622
+ if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR])) {
623
+ $formattedError = "<div class='error'>Fatal Error: " . htmlspecialchars($error['message'], ENT_QUOTES, 'UTF-8') .
624
+ " in " . htmlspecialchars($error['file'], ENT_QUOTES, 'UTF-8') .
625
+ " on line " . $error['line'] . "</div>";
626
+ $errorContent = $formattedError;
627
+ modifyOutputLayoutForError($errorContent);
628
+ }
629
+ });
630
+
611
631
  require_once SETTINGS_PATH . '/public-functions.php';
612
632
  require_once SETTINGS_PATH . '/request-methods.php';
613
633
  $_metadataFile = APP_PATH . '/metadata.php';
614
634
  $_metadataArray = file_exists($_metadataFile) ? require_once $_metadataFile : [];
615
- $_filesListRoutes = [];
635
+ $_filesListRoutes = getFilesListRoutes();
616
636
  $_prismaPHPSettings = getPrismaSettings();
617
637
  $_fileToInclude = '';
618
638
 
639
+ function authenticateUserToken()
640
+ {
641
+ $token = getBearerToken();
642
+ if ($token) {
643
+ $auth = Auth::getInstance();
644
+ $verifyToken = $auth->verifyToken($token);
645
+ if ($verifyToken) {
646
+ $auth->authenticate($verifyToken);
647
+ }
648
+ }
649
+ }
650
+
619
651
  /**
620
652
  * @var array $metadata Metadata information
621
653
  */
@@ -656,7 +688,10 @@ try {
656
688
  $_layoutsToInclude = $_determineContentToInclude['layouts'] ?? [];
657
689
  $uri = $_determineContentToInclude['uri'] ?? '';
658
690
  $pathname = $uri ? "/" . $uri : "/";
659
- $_fileToInclude = basename($_contentToInclude);
691
+ $_fileToInclude = null;
692
+ if (is_file($_contentToInclude)) {
693
+ $_fileToInclude = basename($_contentToInclude); // returns the file name
694
+ }
660
695
  authenticateUserToken();
661
696
 
662
697
  if (empty($_contentToInclude)) {
@@ -710,11 +745,11 @@ try {
710
745
 
711
746
  $_isContentIncluded = false;
712
747
  $_isChildContentIncluded = false;
713
- if (containsContent($_parentLayoutPath)) {
748
+ $_isContentVariableIncluded = containsContent($_parentLayoutPath);
749
+ if (!$_isContentVariableIncluded) {
714
750
  $_isContentIncluded = true;
715
751
  }
716
752
 
717
- ob_start();
718
753
  if (!empty($_contentToInclude)) {
719
754
  if (!$_isParentLayout) {
720
755
  ob_start();
@@ -726,7 +761,8 @@ try {
726
761
  continue;
727
762
  }
728
763
 
729
- if (containsChildContent($layoutPath)) {
764
+ $_isChildContentVariableIncluded = containsChildContent($layoutPath);
765
+ if (!$_isChildContentVariableIncluded) {
730
766
  $_isChildContentIncluded = true;
731
767
  }
732
768
 
@@ -759,18 +795,15 @@ try {
759
795
  }
760
796
  } else {
761
797
  if ($_isContentIncluded) {
762
- $content .= "<div class='error'>The parent layout file does not contain &lt;?php echo \$content; ?&gt; Or &lt;?= \$content ?&gt;<br>" . "<strong>$_parentLayoutPath</strong></div>";
763
- modifyOutputLayoutForError($content);
798
+ echo "<div class='error'>The parent layout file does not contain &lt;?php echo \$content; ?&gt; Or &lt;?= \$content ?&gt;<br>" . "<strong>$_parentLayoutPath</strong></div>";
764
799
  } else {
765
- $content .= "<div class='error'>The layout file does not contain &lt;?php echo \$childContent; ?&gt; or &lt;?= \$childContent ?&gt;<br><strong>$layoutPath</strong></div>";
766
- modifyOutputLayoutForError($content);
800
+ echo "<div class='error'>The layout file does not contain &lt;?php echo \$childContent; ?&gt; or &lt;?= \$childContent ?&gt;<br><strong>$layoutPath</strong></div>";
767
801
  }
768
802
  }
769
803
  } catch (Throwable $e) {
770
- $content = ob_get_clean();
771
804
  $errorDetails = "Unhandled Exception: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
772
805
  $errorDetails .= "<br>File: " . htmlspecialchars($e->getFile(), ENT_QUOTES, 'UTF-8');
773
806
  $errorDetails .= "<br>Line: " . htmlspecialchars($e->getLine(), ENT_QUOTES, 'UTF-8');
774
- $content .= "<div class='error'>" . $errorDetails . "</div>";
775
- modifyOutputLayoutForError($content);
807
+ $errorDetails = "<div class='error'>$errorDetails</div>";
808
+ modifyOutputLayoutForError($errorDetails);
776
809
  }
package/dist/index.js CHANGED
@@ -67,10 +67,31 @@ function configureBrowserSyncCommand(baseDir) {
67
67
  // TypeScript content to write
68
68
  const bsConfigTsContent = `const { createProxyMiddleware } = require("http-proxy-middleware");
69
69
  const fs = require("fs");
70
+ const chokidar = require("chokidar");
71
+ const { execSync } = require("child_process");
70
72
 
71
73
  const jsonData = fs.readFileSync("prisma-php.json", "utf8");
72
74
  const config = JSON.parse(jsonData);
73
75
 
76
+ // Watch for file changes (create, delete, save)
77
+ const watcher = chokidar.watch("src/**/*", {
78
+ ignored: /(^|[\/\\])\../, // Ignore dotfiles
79
+ persistent: true,
80
+ usePolling: true,
81
+ interval: 1000,
82
+ });
83
+
84
+ watcher
85
+ .on("add", async (path) => {
86
+ execSync("node settings/files-list-config.js");
87
+ })
88
+ .on("change", async (path) => {
89
+ execSync("node settings/files-list-config.js");
90
+ })
91
+ .on("unlink", async (path) => {
92
+ execSync("node settings/files-list-config.js");
93
+ });
94
+
74
95
  module.exports = {
75
96
  proxy: "http://localhost:3000",
76
97
  middleware: [
@@ -91,6 +112,10 @@ module.exports = {
91
112
  open: false,
92
113
  ghostMode: false,
93
114
  codeSync: true, // Disable synchronization of code changes across clients
115
+ watchOptions: {
116
+ usePolling: true,
117
+ interval: 1000,
118
+ },
94
119
  };`;
95
120
  // Determine the path and write the bs-config.js
96
121
  const bsConfigPath = path.join(baseDir, "settings", "bs-config.cjs");
@@ -149,12 +174,11 @@ async function updatePackageJson(baseDir, answer) {
149
174
  let updatedScripts = Object.assign({}, packageJson.scripts);
150
175
  // Conditionally add "browser-sync" command
151
176
  updatedScripts.browserSync = browserSyncCommand;
152
- updatedScripts._dev =
177
+ updatedScripts.npmRunAll =
153
178
  answersToInclude.length > 0
154
179
  ? `npm-run-all -p ${answersToInclude.join(" ")}`
155
180
  : 'echo "No additional scripts to run"';
156
- updatedScripts.startDev = `node settings/start-dev.js`;
157
- updatedScripts.dev = `npm run startDev`;
181
+ updatedScripts.dev = `node settings/start-dev.js`;
158
182
  // Finally, assign the updated scripts back to packageJson
159
183
  packageJson.scripts = updatedScripts;
160
184
  packageJson.type = "module";
@@ -285,11 +309,7 @@ function copyRecursiveSync(src, dest, answer) {
285
309
  return;
286
310
  }
287
311
  if (!answer.backendOnly && dest.includes("route.php")) return;
288
- if (
289
- answer.backendOnly &&
290
- !answer.swaggerDocs &&
291
- (dest.includes("start-dev.js") || dest.includes("swagger-setup.js"))
292
- ) {
312
+ if (!answer.swaggerDocs && dest.includes("swagger-setup.js")) {
293
313
  return;
294
314
  }
295
315
  fs.copyFileSync(src, dest, 0);
@@ -308,7 +328,7 @@ function createOrUpdateTailwindConfig(baseDir) {
308
328
  const filePath = path.join(baseDir, "tailwind.config.js");
309
329
  if (checkExcludeFiles(filePath)) return;
310
330
  const newContent = [
311
- "./src/app/**/*.{html,js,php}",
331
+ "./src/**/*.{html,js,php}",
312
332
  // Add more paths as needed
313
333
  ];
314
334
  let configData = fs.readFileSync(filePath, "utf8");
@@ -488,7 +508,10 @@ SHOW_ERRORS=true
488
508
  # CHATGPT_API_KEY=sk-your-api-key
489
509
 
490
510
  # APP TIMEZONE - Set your application timezone - Default is "UTC"
491
- APP_TIMEZONE="UTC"`;
511
+ APP_TIMEZONE="UTC"
512
+
513
+ # APP ENV - Set your application environment - Default is "development" - Change this in production to "production"
514
+ APP_ENV=development`;
492
515
  if (answer.prisma) {
493
516
  const prismaEnvContent = `# Environment variables declared in this file are automatically made available to Prisma.
494
517
  # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
@@ -1019,6 +1042,16 @@ async function main() {
1019
1042
  fs.rmSync(swaggerDocsFolder, { recursive: true, force: true }); // Use fs.rmSync instead of fs.rmdirSync
1020
1043
  console.log(`swagger-docs was deleted successfully.`);
1021
1044
  }
1045
+ const swaggerFiles = ["swagger-setup.js"];
1046
+ swaggerFiles.forEach((file) => {
1047
+ const filePath = path.join(projectPath, "settings", file);
1048
+ if (fs.existsSync(filePath)) {
1049
+ fs.unlinkSync(filePath); // Delete each file if it exists
1050
+ console.log(`${file} was deleted successfully.`);
1051
+ } else {
1052
+ console.log(`${file} does not exist.`);
1053
+ }
1054
+ });
1022
1055
  updateUninstallDependencies.push("swagger-jsdoc");
1023
1056
  }
1024
1057
  if (!updateAnswer.tailwindcss) {
@@ -5,4 +5,5 @@ module.exports = {
5
5
  notify: false,
6
6
  open: false,
7
7
  ghostMode: false,
8
+ codeSync: true, // Disable synchronization of code changes across clients
8
9
  };
@@ -148,10 +148,10 @@ async function startDev() {
148
148
  console.error(`Failed to start browserSync process: ${err.message}`);
149
149
  });
150
150
 
151
- // Function to start _dev process
151
+ // Function to start npmRunAll process
152
152
  function startDevProcess() {
153
- console.log("Starting _dev...");
154
- devProcess = spawn("npm", ["run", "_dev"], { shell: true });
153
+ console.log("Starting npmRunAll...");
154
+ devProcess = spawn("npm", ["run", "npmRunAll"], { shell: true });
155
155
 
156
156
  devProcess.stdout.on("data", (data) => {
157
157
  process.stdout.write(data);
@@ -72,6 +72,19 @@ class Boom
72
72
  return new self(401, $message, $details);
73
73
  }
74
74
 
75
+ /**
76
+ * Factory method for 402 Payment Required.
77
+ *
78
+ * @param string $message Error message.
79
+ * @param array $details Additional error details.
80
+ *
81
+ * @return self
82
+ */
83
+ public static function paymentRequired(string $message = 'Payment Required', array $details = []): self
84
+ {
85
+ return new self(402, $message, $details);
86
+ }
87
+
75
88
  /**
76
89
  * Factory method for 403 Forbidden.
77
90
  *
@@ -98,6 +111,32 @@ class Boom
98
111
  return new self(404, $message, $details);
99
112
  }
100
113
 
114
+ /**
115
+ * Factory method for 405 Method Not Allowed.
116
+ *
117
+ * @param string $message Error message.
118
+ * @param array $details Additional error details.
119
+ *
120
+ * @return self
121
+ */
122
+ public static function methodNotAllowed(string $message = 'Method Not Allowed', array $details = []): self
123
+ {
124
+ return new self(405, $message, $details);
125
+ }
126
+
127
+ /**
128
+ * Factory method for 406 Not Acceptable.
129
+ *
130
+ * @param string $message Error message.
131
+ * @param array $details Additional error details.
132
+ *
133
+ * @return self
134
+ */
135
+ public static function notAcceptable(string $message = 'Not Acceptable', array $details = []): self
136
+ {
137
+ return new self(406, $message, $details);
138
+ }
139
+
101
140
  /**
102
141
  * Factory method for 500 Internal Server Error.
103
142
  *
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <meta name="pp-description" content="<?= htmlspecialchars($metadata['description']); ?>">
8
8
  <title><?= htmlspecialchars($metadata['title']); ?></title>
9
- <link rel="icon" href="<?= $baseUrl; ?>\favicon.ico" type="image/x-icon">
9
+ <link rel="icon" href="<?= $baseUrl; ?>/favicon.ico" type="image/x-icon">
10
10
  </head>
11
11
 
12
12
  <body>
@@ -1,11 +1,8 @@
1
1
  /** @type {import('tailwindcss').Config} */
2
- export default {
3
- content: [
4
- "./src/app/**/*.{html,js,php}"
5
- ],
2
+ module.exports = {
3
+ content: ["./src/**/*.{html,js,php}"],
6
4
  theme: {
7
5
  extend: {},
8
6
  },
9
7
  plugins: [],
10
- }
11
-
8
+ };
@@ -11,7 +11,7 @@
11
11
  // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12
12
 
13
13
  /* Language and Environment */
14
- "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
14
+ "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
15
15
  // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16
16
  // "jsx": "preserve", /* Specify what JSX code is generated. */
17
17
  // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
@@ -25,7 +25,7 @@
25
25
  // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26
26
 
27
27
  /* Modules */
28
- "module": "commonjs", /* Specify what module code is generated. */
28
+ "module": "NodeNext" /* Specify what module code is generated. */,
29
29
  // "rootDir": "./", /* Specify the root folder within your source files. */
30
30
  // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
31
31
  // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
@@ -39,7 +39,7 @@
39
39
  // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
40
40
  // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
41
41
  // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
42
- // "resolveJsonModule": true, /* Enable importing .json files. */
42
+ "resolveJsonModule": true /* Enable importing .json files. */,
43
43
  // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
44
44
  // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
45
45
 
@@ -77,12 +77,12 @@
77
77
  // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
78
78
  // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
79
79
  // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
80
- "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
80
+ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
81
81
  // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
82
- "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
82
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
83
83
 
84
84
  /* Type Checking */
85
- "strict": true, /* Enable all strict type-checking options. */
85
+ "strict": true /* Enable all strict type-checking options. */,
86
86
  // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
87
87
  // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
88
88
  // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
@@ -104,8 +104,8 @@
104
104
 
105
105
  /* Completeness */
106
106
  // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
107
- "skipLibCheck": true /* Skip type checking all .d.ts files. */
107
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
108
108
  },
109
- "include": ["src/**/*.ts"],
110
- "exclude": ["node_modules"]
109
+ "include": ["src/**/*.ts", "settings/**/*.ts"],
110
+ "exclude": ["node_modules", "vendor"]
111
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-prisma-php-app",
3
- "version": "1.21.500",
3
+ "version": "1.22.500",
4
4
  "description": "Prisma-PHP: A Revolutionary Library Bridging PHP with Prisma ORM",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",