create-prisma-php-app 1.8.21 → 1.9.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/.htaccess CHANGED
@@ -10,9 +10,20 @@ RewriteEngine On
10
10
  # Allow cross-origin requests (CORS) for all routes
11
11
  <IfModule mod_headers.c>
12
12
  Header set Access-Control-Allow-Origin "*"
13
- Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
13
+ Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS"
14
14
  Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"
15
15
  </IfModule>
16
16
 
17
+ # Exclude OPTIONS method from being redirected
18
+ RewriteCond %{REQUEST_METHOD} !OPTIONS
19
+
20
+ # Redirect all AJAX requests to bootstrap-ajax.php
21
+ RewriteCond %{HTTP:X-Requested-With} ^XMLHttpRequest$
22
+ RewriteRule ^(.*)$ bootstrap-ajax.php [L,QSA]
23
+
17
24
  # Redirect all non-file and non-directory requests not starting with src/app/ to src/app/layout.php
18
25
  RewriteRule !^src/app/ src/app/layout.php [QSA,L]
26
+
27
+ # Add this to ensure OPTIONS requests are handled correctly
28
+ RewriteCond %{REQUEST_METHOD} OPTIONS
29
+ RewriteRule ^(.*)$ $1 [R=200,L]
@@ -0,0 +1,141 @@
1
+ <?php
2
+
3
+ header('Content-Type: application/json');
4
+
5
+ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
6
+ header('HTTP/1.1 200 OK');
7
+ exit;
8
+ }
9
+
10
+ if (empty($_SERVER["HTTP_X_REQUESTED_WITH"]) || $_SERVER["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest") {
11
+ header("HTTP/1.0 400 Bad Request");
12
+ echo json_encode(["error" => "Invalid request method or type."]);
13
+ exit;
14
+ }
15
+
16
+ // Determine the request method
17
+ $requestMethod = $_SERVER['REQUEST_METHOD'];
18
+ $allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'];
19
+
20
+ if (!in_array($requestMethod, $allowedMethods)) {
21
+ echo "Method not allowed\n";
22
+ header("HTTP/1.1 405 Method Not Allowed");
23
+ exit;
24
+ }
25
+
26
+ $isGet = $requestMethod === 'GET';
27
+ $isPost = $requestMethod === 'POST';
28
+ $isPut = $requestMethod === 'PUT';
29
+ $isDelete = $requestMethod === 'DELETE';
30
+ $isHead = $requestMethod === 'HEAD';
31
+ $isOptions = $requestMethod === 'OPTIONS';
32
+ $contentType = $_SERVER['CONTENT_TYPE'] ?? '';
33
+ $params = [];
34
+
35
+ if (stripos($contentType, 'application/json') !== false) {
36
+ $jsonInput = file_get_contents('php://input');
37
+ if (!empty($jsonInput)) {
38
+ $data = json_decode($jsonInput, true);
39
+ if (json_last_error() === JSON_ERROR_NONE) {
40
+ $params = $data;
41
+ } else {
42
+ echo json_encode(['error' => 'Error: Invalid JSON body!']);
43
+ exit;
44
+ }
45
+ }
46
+ }
47
+
48
+ $scriptUrl = $_SERVER['REQUEST_URI'];
49
+ $scriptUrl = explode('?', $scriptUrl, 2)[0];
50
+ $uri = $_SERVER['SCRIPT_URL'] ?? uriExtractor($scriptUrl);
51
+
52
+ // Check for private directory access
53
+ if (strpos($uri, '/_') !== false || strpos($uri, '_') === 0) {
54
+ handleNotFound();
55
+ }
56
+
57
+ $baseDir = __DIR__;
58
+
59
+ require_once $baseDir . "/settings/paths.php";
60
+ require_once $baseDir . "/vendor/autoload.php";
61
+
62
+ $groupFolder = findGroupFolder($uri);
63
+ $filePath = $baseDir . '/src/app' . $groupFolder;
64
+
65
+ if (basename($filePath) === 'route.php' && file_exists($filePath)) {
66
+ require_once($filePath);
67
+ } else {
68
+ handleNotFound();
69
+ }
70
+
71
+ function uriExtractor(string $scriptUrl): string
72
+ {
73
+ $prismaPHPSettings = json_decode(file_get_contents("prisma-php.json"), true);
74
+ $projectName = $prismaPHPSettings['projectName'] ?? '';
75
+ if (empty($projectName)) {
76
+ return "/";
77
+ }
78
+
79
+ $escapedIdentifier = preg_quote($projectName, '/');
80
+ $pattern = "/(?:{$escapedIdentifier})(\/.+?)(?=\/{$escapedIdentifier}\/|$)/";
81
+
82
+ if (preg_match_all($pattern, $scriptUrl, $matches, PREG_SET_ORDER)) {
83
+ $lastMatch = end($matches);
84
+ if (!empty($lastMatch[1])) {
85
+ return $lastMatch[1];
86
+ }
87
+ }
88
+
89
+ return "/";
90
+ }
91
+
92
+ function handleNotFound()
93
+ {
94
+ header("HTTP/1.0 404 Not Found");
95
+ echo json_encode(['error' => 'Not Found', 'message' => 'The requested resource was not found.']);
96
+ exit;
97
+ }
98
+
99
+ function findGroupFolder($uri): string
100
+ {
101
+ $uriSegments = explode('/', $uri);
102
+ foreach ($uriSegments as $segment) {
103
+ if (!empty($segment)) {
104
+ if (isGroupIdentifier($segment)) {
105
+ return $segment;
106
+ }
107
+ }
108
+ }
109
+
110
+ $matchedGroupFolder = matchGroupFolder($uri);
111
+ if ($matchedGroupFolder) {
112
+ return $matchedGroupFolder;
113
+ } else {
114
+ return '';
115
+ }
116
+ }
117
+
118
+ function isGroupIdentifier($segment): bool
119
+ {
120
+ return preg_match('/^\(.*\)$/', $segment);
121
+ }
122
+
123
+ function matchGroupFolder($constructedPath): ?string
124
+ {
125
+ $routes = json_decode(file_get_contents(SETTINGS_PATH . "/files-list.json"), true);
126
+ $bestMatch = null;
127
+ $normalizedConstructedPath = ltrim(str_replace('\\', '/', $constructedPath), './');
128
+
129
+ $normalizedConstructedPath = "/$normalizedConstructedPath/route.php";
130
+
131
+ foreach ($routes as $route) {
132
+ $normalizedRoute = trim(str_replace('\\', '/', $route), '.');
133
+ $cleanedRoute = preg_replace('/\/\([^)]+\)/', '', $normalizedRoute);
134
+ if ($cleanedRoute === $normalizedConstructedPath) {
135
+ $bestMatch = $normalizedRoute;
136
+ break;
137
+ }
138
+ }
139
+
140
+ return $bestMatch;
141
+ }
@@ -7,7 +7,7 @@ if (session_status() == PHP_SESSION_NONE) {
7
7
  require_once __DIR__ . '/settings/paths.php';
8
8
  require_once __DIR__ . '/vendor/autoload.php';
9
9
 
10
- $metadata = include __DIR__ . '/src/app/metadata.php';
10
+ $metadata = require_once __DIR__ . '/src/app/metadata.php';
11
11
 
12
12
  function determineContentToInclude()
13
13
  {
@@ -40,13 +40,6 @@ function determineContentToInclude()
40
40
  }
41
41
  }
42
42
 
43
- if (substr($uri, -4) == '.php') {
44
- $path = $baseDir . '/' . $uri;
45
- if (file_exists($path)) {
46
- $includePath = $path;
47
- }
48
- }
49
-
50
43
  $currentPath = $baseDir;
51
44
  $getGroupFolder = getGroupFolder($groupFolder);
52
45
  $modifiedUri = $uri;
@@ -153,10 +146,7 @@ function matchGroupFolder($constructedPath): ?string
153
146
  $routes = json_decode(file_get_contents(SETTINGS_PATH . "/files-list.json"), true);
154
147
  $bestMatch = null;
155
148
  $normalizedConstructedPath = ltrim(str_replace('\\', '/', $constructedPath), './');
156
-
157
- if (substr($normalizedConstructedPath, -4) !== '.php') {
158
- $normalizedConstructedPath = "/$normalizedConstructedPath/index.php";
159
- }
149
+ $normalizedConstructedPath = "/$normalizedConstructedPath/index.php";
160
150
 
161
151
  foreach ($routes as $route) {
162
152
  $normalizedRoute = trim(str_replace('\\', '/', $route), '.');
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{execSync}from"child_process";import fs from"fs";import{fileURLToPath}from"url";import path from"path";import chalk from"chalk";import prompts from"prompts";import https from"https";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename);let updateAnswer=null;function configureBrowserSyncCommand(e,s){const t=s.PROJECT_ROOT_PATH.indexOf("\\htdocs\\");if(-1===t)return"";const n=s.PROJECT_ROOT_PATH.substring(0,t+"\\htdocs\\".length).replace(/\\/g,"\\\\"),i=s.PROJECT_ROOT_PATH.replace(new RegExp(`^${n}`),"").replace(/\\/g,"/");let c=`http://localhost/${i}`;c=c.endsWith("/")?c.slice(0,-1):c;const r=c.replace(/(?<!:)(\/\/+)/g,"/"),o=i.replace(/\/\/+/g,"/"),a=`\n const { createProxyMiddleware } = require("http-proxy-middleware");\n\n module.exports = {\n // First middleware: Set Cache-Control headers\n function (req, res, next) {\n res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");\n res.setHeader("Pragma", "no-cache");\n res.setHeader("Expires", "0");\n next();\n },\n // Use the 'middleware' option to create a proxy that masks the deep URL.\n middleware: [\n // This middleware intercepts requests to the root and proxies them to the deep path.\n createProxyMiddleware("/", {\n target:\n "${r}/",\n changeOrigin: true,\n pathRewrite: {\n "^/": "/${o.startsWith("/")?o.substring(1):o}/", // Rewrite the path.\n },\n }),\n ],\n proxy: "http://localhost:3000", // Proxy the BrowserSync server.\n files: "src/**/*.*",\n notify: false,\n open: false,\n ghostMode: false,\n };`,l=path.join(e,"settings","bs-config.cjs");return fs.writeFileSync(l,a,"utf8"),"browser-sync start --config settings/bs-config.cjs"}async function updatePackageJson(e,s,t){const n=path.join(e,"package.json");if(checkExcludeFiles(n))return;const i=JSON.parse(fs.readFileSync(n,"utf8")),c=configureBrowserSyncCommand(e,s);i.scripts=Object.assign(Object.assign({},i.scripts),{postinstall:"prisma generate"});let r=[];t.tailwindcss&&(i.scripts=Object.assign(Object.assign({},i.scripts),{tailwind:"postcss ./src/app/css/tailwind.css -o ./src/app/css/styles.css --watch"}),r.push("tailwind")),t.websocket&&(i.scripts=Object.assign(Object.assign({},i.scripts),{websocket:"node ./settings/restartWebsocket.cjs"}),r.push("websocket"));const o=Object.assign({},i.scripts);r.length>0&&(o["browser-sync"]=c),o.dev=r.length>0?`npm-run-all --parallel browser-sync ${r.join(" ")}`:c,i.scripts=o,i.type="module",i.prisma={seed:"node prisma/seed.js"},fs.writeFileSync(n,JSON.stringify(i,null,2))}async function updateComposerJson(e,s){if(!s.websocket)return;const t=path.join(e,"composer.json");if(checkExcludeFiles(t))return;let n;if(fs.existsSync(t)){{const e=fs.readFileSync(t,"utf8");n=JSON.parse(e)}s.websocket&&(n.require=Object.assign(Object.assign({},n.require),{"cboden/ratchet":"^0.4.4"})),fs.writeFileSync(t,JSON.stringify(n,null,2))}}async function updateIndexJsForWebSocket(e,s){if(!s.websocket)return;const t=path.join(e,"src","app","js","index.js");if(checkExcludeFiles(t))return;let n=fs.readFileSync(t,"utf8");n+='\n// WebSocket initialization\nconst ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(t,n,"utf8")}async function createUpdateGitignoreFile(e,s){const t=path.join(e,".gitignore");if(checkExcludeFiles(t))return;let n="";fs.existsSync(t)&&(n=fs.readFileSync(t,"utf8")),s.forEach((e=>{n.includes(e)||(n+=`\n${e}`)})),n=n.trimStart(),fs.writeFileSync(t,n)}function copyRecursiveSync(e,s){const t=fs.existsSync(e),n=t&&fs.statSync(e);if(t&&n&&n.isDirectory())fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((t=>{copyRecursiveSync(path.join(e,t),path.join(s,t))}));else{if(checkExcludeFiles(s))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s){s.forEach((({srcDir:s,destDir:t})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,t))}))}function createOrUpdateTailwindConfig(e){const s=path.join(e,"tailwind.config.js");if(checkExcludeFiles(s))return;let t=fs.readFileSync(s,"utf8");const n=["./src/app/**/*.{html,js,php}"].map((e=>` "${e}"`)).join(",\n");t=t.replace(/content: \[\],/g,`content: [\n${n}\n],`),fs.writeFileSync(s,t,{flag:"w"})}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,"export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n cssnano: {},\n },\n};",{flag:"w"})}function modifyLayoutPHP(e,s){const t=path.join(e,"src","app","layout.php");if(!checkExcludeFiles(t))try{let e=fs.readFileSync(t,"utf8");const n='\n <link href="<?php echo $baseUrl; ?>css/index.css" rel="stylesheet">\n <script src="<?php echo $baseUrl; ?>js/index.js"><\/script>\n <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">',i=s?` <link href="<?php echo $baseUrl; ?>css/styles.css" rel="stylesheet"> ${n}`:` <script src="https://cdn.tailwindcss.com"><\/script> ${n}`;e=e.replace("</head>",`${i}\n</head>`),fs.writeFileSync(t,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const t=path.join(e,".env");if(checkExcludeFiles(t))return;let n=fs.existsSync(t)?fs.readFileSync(t,"utf8"):"";n.includes(s)||(n+=`${""!==n?"\n\n":""}${s}`,fs.writeFileSync(t,n,{flag:"w"}))}function checkExcludeFiles(e){var s,t;return!!(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(null!==(t=null===(s=null==updateAnswer?void 0:updateAnswer.excludeFilePath)||void 0===s?void 0:s.includes(e.replace(/\\/g,"/")))&&void 0!==t&&t)}async function createDirectoryStructure(e,s,t){const n=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/../composer.json",dest:"/composer.json"}];(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(n.push({src:"/.env",dest:"/.env"},{src:"/tsconfig.json",dest:"/tsconfig.json"}),updateAnswer.tailwindcss&&n.push({src:"/postcss.config.js",dest:"/postcss.config.js"},{src:"/tailwind.config.js",dest:"/tailwind.config.js"}));n.forEach((({src:s,dest:t})=>{const n=path.join(__dirname,s),i=path.join(e,t);if(checkExcludeFiles(i))return;const c=fs.readFileSync(n,"utf8");fs.writeFileSync(i,c,{flag:"w"})})),await executeCopy(e,[{srcDir:"/settings",destDir:"/settings"},{srcDir:"/prisma",destDir:"/prisma"},{srcDir:"/src",destDir:"/src"}]),await updatePackageJson(e,t,s),await updateComposerJson(e,s),await updateIndexJsForWebSocket(e,s),s.tailwindcss?(createOrUpdateTailwindConfig(e),modifyLayoutPHP(e,!0),modifyPostcssConfig(e)):modifyLayoutPHP(e,!1);await createOrUpdateEnvFile(e,'# PHPMailer\n# SMTP_HOST=smtp.gmail.com or your SMTP host\n# SMTP_USERNAME=john.doe@gmail.com or your SMTP username\n# SMTP_PASSWORD=123456\n# SMTP_PORT=587 for TLS, 465 for SSL or your SMTP port\n# SMTP_ENCRYPTION=ssl or tls\n# MAIL_FROM=john.doe@gmail.com\n# MAIL_FROM_NAME="John Doe"'),await createUpdateGitignoreFile(e,["vendor"])}async function getAnswer(e={}){var s,t,n;const i=[];e.projectName||i.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.tailwindcss||i.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!0,active:"Yes",inactive:"No"}),e.websocket||i.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"});const c=i,r=()=>{process.exit(0)};try{const i=await prompts(c,{onCancel:r});return 0===Object.keys(i).length?null:{projectName:i.projectName?String(i.projectName).trim().replace(/ /g,"-"):null!==(s=e.projectName)&&void 0!==s?s:"my-app",tailwindcss:null!==(t=i.tailwindcss)&&void 0!==t?t:e.tailwindcss,websocket:null!==(n=i.websocket)&&void 0!==n?n:e.websocket}}catch(e){return null}}async function installDependencies(e,s,t=!1){fs.existsSync(path.join(e,"package.json"))||execSync("npm init -y",{stdio:"inherit",cwd:e}),s.forEach((e=>{}));const n=`npm install ${t?"--save-dev":""} ${s.join(" ")}`;execSync(n,{stdio:"inherit",cwd:e})}async function uninstallDependencies(e,s,t=!1){s.forEach((e=>{}));const n=`npm uninstall ${t?"--save-dev":"--save"} ${s.join(" ")}`;execSync(n,{stdio:"inherit",cwd:e})}function fetchPackageVersion(e){return new Promise(((s,t)=>{https.get(`https://registry.npmjs.org/${e}`,(e=>{let n="";e.on("data",(e=>n+=e)),e.on("end",(()=>{try{const e=JSON.parse(n);s(e["dist-tags"].latest)}catch(e){t(new Error("Failed to parse JSON response"))}}))})).on("error",(e=>t(e)))}))}const readJsonFile=e=>{const s=fs.readFileSync(e,"utf8");return JSON.parse(s)};async function main(){var e,s,t,n,i;try{const c=process.argv.slice(2);let r=c[0],o=null;if(r){const i={projectName:r,tailwindcss:c.includes("--tailwindcss"),websocket:c.includes("--websocket")};if(o=await getAnswer(i),null===o)return;const a=process.cwd(),l=path.join(a,"prisma-php.json"),p=readJsonFile(l);let d=[];null===(e=p.excludeFiles)||void 0===e||e.map((e=>{const s=path.join(a,e);fs.existsSync(s)&&d.push(s.replace(/\\/g,"/"))})),updateAnswer={projectName:r,tailwindcss:null!==(s=null==o?void 0:o.tailwindcss)&&void 0!==s&&s,websocket:null!==(t=null==o?void 0:o.websocket)&&void 0!==t&&t,isUpdate:!0,excludeFiles:null!==(n=p.excludeFiles)&&void 0!==n?n:[],excludeFilePath:null!=d?d:[],filePath:a}}else o=await getAnswer();if(null===o)return;execSync("npm install -g create-prisma-php-app",{stdio:"inherit"}),execSync("npm install -g browser-sync",{stdio:"inherit"}),r||fs.mkdirSync(o.projectName);const a=process.cwd();let l=r?a:path.join(a,o.projectName);r||process.chdir(o.projectName);const p=["prisma","@prisma/client","typescript","@types/node","ts-node","http-proxy-middleware@^2.0.6"];o.tailwindcss&&p.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano"),o.websocket&&p.push("chokidar-cli"),(o.tailwindcss||o.websocket)&&p.push("npm-run-all"),await installDependencies(l,p,!0),r||(execSync("npx prisma init",{stdio:"inherit"}),execSync("npx tsc --init",{stdio:"inherit"})),o.tailwindcss&&execSync("npx tailwindcss init -p",{stdio:"inherit"});const d={PROJECT_NAME:o.projectName,PROJECT_ROOT_PATH:l.replace(/\\/g,"\\\\"),PHP_ROOT_PATH_EXE:"D:\\\\xampp\\\\php\\\\php.exe",PHP_GENERATE_CLASS_PATH:"src/Lib/Prisma/Classes"};await createDirectoryStructure(l,o,d);const u=path.join(l,"settings","project-settings.js"),f=`export const projectSettings = {\n PROJECT_NAME: "${o.projectName}",\n PROJECT_ROOT_PATH: "${l.replace(/\\/g,"\\\\")}",\n PHP_ROOT_PATH_EXE: "D:\\\\xampp\\\\php\\\\php.exe",\n PHP_GENERATE_CLASS_PATH: "src/Lib/Prisma/Classes",\n };`;fs.writeFileSync(u,f,{flag:"w"});const h=path.join(l,"public");if(fs.existsSync(h)||fs.mkdirSync(h),!o.tailwindcss){const e=path.join(l,"src","app","css");["tailwind.css","styles.css"].forEach((s=>{const t=path.join(e,s);fs.existsSync(t)&&fs.unlinkSync(t)}))}if(!o.websocket){const e=path.join(l,"src","lib","websocket");fs.existsSync(e)&&fs.rmSync(e,{recursive:!0,force:!0});const s=path.join(l,"settings");["restartWebsocket.cjs","restart_websocket.bat"].forEach((e=>{const t=path.join(s,e);fs.existsSync(t)&&fs.unlinkSync(t)}))}if(null==updateAnswer?void 0:updateAnswer.isUpdate){const e=[];if(!updateAnswer.tailwindcss){["postcss.config.js","tailwind.config.js"].forEach((e=>{const s=path.join(l,e);fs.existsSync(s)&&fs.unlinkSync(s)})),e.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano")}updateAnswer.websocket||e.push("chokidar-cli"),e.length>0&&await uninstallDependencies(l,e,!0)}const w=await fetchPackageVersion("create-prisma-php-app"),y={projectName:o.projectName,tailwindcss:o.tailwindcss,websocket:o.websocket,version:w,excludeFiles:null!==(i=null==updateAnswer?void 0:updateAnswer.excludeFiles)&&void 0!==i?i:[]};fs.writeFileSync(path.join(l,"prisma-php.json"),JSON.stringify(y,null,2),{flag:"w"})}catch(e){process.exit(1)}}main();
2
+ import{execSync}from"child_process";import fs from"fs";import{fileURLToPath}from"url";import path from"path";import chalk from"chalk";import prompts from"prompts";import https from"https";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename);let updateAnswer=null;function bsConfigUrls(e){const s=e.PROJECT_ROOT_PATH.indexOf("\\htdocs\\");if(-1===s)return{bsTarget:"",bsPathRewrite:{}};const t=e.PROJECT_ROOT_PATH.substring(0,s+"\\htdocs\\".length).replace(/\\/g,"\\\\"),n=e.PROJECT_ROOT_PATH.replace(new RegExp(`^${t}`),"").replace(/\\/g,"/");let i=`http://localhost/${n}`;i=i.endsWith("/")?i.slice(0,-1):i;const c=i.replace(/(?<!:)(\/\/+)/g,"/"),r=n.replace(/\/\/+/g,"/");return{bsTarget:`${c}/`,bsPathRewrite:{"^/":`/${r.startsWith("/")?r.substring(1):r}/`}}}function configureBrowserSyncCommand(e,s){const t=path.join(e,"settings","bs-config.cjs");return fs.writeFileSync(t,'const { createProxyMiddleware } = require("http-proxy-middleware");\n const fs = require("fs");\n \n const jsonData = fs.readFileSync("prisma-php.json", "utf8");\n const config = JSON.parse(jsonData);\n \n module.exports = {\n // First middleware: Set Cache-Control headers\n function(req, res, next) {\n res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");\n res.setHeader("Pragma", "no-cache");\n res.setHeader("Expires", "0");\n next();\n },\n // Use the \'middleware\' option to create a proxy that masks the deep URL.\n middleware: [\n // This middleware intercepts requests to the root and proxies them to the deep path.\n createProxyMiddleware("/", {\n target: config.bsTarget,\n changeOrigin: true,\n pathRewrite: config.bsPathRewrite,\n }),\n ],\n proxy: "http://localhost:3000", // Proxy the BrowserSync server.\n files: "src/**/*.*",\n notify: false,\n open: false,\n ghostMode: false,\n };',"utf8"),"browser-sync start --config settings/bs-config.cjs"}async function updatePackageJson(e,s,t){const n=path.join(e,"package.json");if(checkExcludeFiles(n))return;const i=JSON.parse(fs.readFileSync(n,"utf8")),c=configureBrowserSyncCommand(e,s);i.scripts=Object.assign(Object.assign({},i.scripts),{postinstall:"prisma generate",projectName:"node settings/project-name.cjs"});let r=[];t.tailwindcss&&(i.scripts=Object.assign(Object.assign({},i.scripts),{tailwind:"postcss ./src/app/css/tailwind.css -o ./src/app/css/styles.css --watch"}),r.push("tailwind")),t.websocket&&(i.scripts=Object.assign(Object.assign({},i.scripts),{websocket:"node ./settings/restartWebsocket.cjs"}),r.push("websocket"));const o=Object.assign({},i.scripts);r.length>0&&(o["browser-sync"]=c),o.dev=r.length>0?`npm-run-all --parallel projectName browser-sync ${r.join(" ")}`:`npm run projectName && ${c}`,i.scripts=o,i.type="module",i.prisma={seed:"node prisma/seed.js"},fs.writeFileSync(n,JSON.stringify(i,null,2))}async function updateComposerJson(e,s){if(!s.websocket)return;const t=path.join(e,"composer.json");if(checkExcludeFiles(t))return;let n;if(fs.existsSync(t)){{const e=fs.readFileSync(t,"utf8");n=JSON.parse(e)}s.websocket&&(n.require=Object.assign(Object.assign({},n.require),{"cboden/ratchet":"^0.4.4"})),fs.writeFileSync(t,JSON.stringify(n,null,2))}}async function updateIndexJsForWebSocket(e,s){if(!s.websocket)return;const t=path.join(e,"src","app","js","index.js");if(checkExcludeFiles(t))return;let n=fs.readFileSync(t,"utf8");n+='\n// WebSocket initialization\nconst ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(t,n,"utf8")}async function createUpdateGitignoreFile(e,s){const t=path.join(e,".gitignore");if(checkExcludeFiles(t))return;let n="";fs.existsSync(t)&&(n=fs.readFileSync(t,"utf8")),s.forEach((e=>{n.includes(e)||(n+=`\n${e}`)})),n=n.trimStart(),fs.writeFileSync(t,n)}function copyRecursiveSync(e,s){const t=fs.existsSync(e),n=t&&fs.statSync(e);if(t&&n&&n.isDirectory())fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((t=>{copyRecursiveSync(path.join(e,t),path.join(s,t))}));else{if(checkExcludeFiles(s))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s){s.forEach((({srcDir:s,destDir:t})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,t))}))}function createOrUpdateTailwindConfig(e){const s=path.join(e,"tailwind.config.js");if(checkExcludeFiles(s))return;let t=fs.readFileSync(s,"utf8");const n=["./src/app/**/*.{html,js,php}"].map((e=>` "${e}"`)).join(",\n");t=t.replace(/content: \[\],/g,`content: [\n${n}\n],`),fs.writeFileSync(s,t,{flag:"w"})}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,"export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n cssnano: {},\n },\n};",{flag:"w"})}function modifyLayoutPHP(e,s){const t=path.join(e,"src","app","layout.php");if(!checkExcludeFiles(t))try{let e=fs.readFileSync(t,"utf8");const n='\n <link href="<?php echo $baseUrl; ?>css/index.css" rel="stylesheet">\n <script src="<?php echo $baseUrl; ?>js/index.js"><\/script>\n <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">',i=s?` <link href="<?php echo $baseUrl; ?>css/styles.css" rel="stylesheet"> ${n}`:` <script src="https://cdn.tailwindcss.com"><\/script> ${n}`;e=e.replace("</head>",`${i}\n</head>`),fs.writeFileSync(t,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const t=path.join(e,".env");if(checkExcludeFiles(t))return;let n=fs.existsSync(t)?fs.readFileSync(t,"utf8"):"";n.includes(s)||(n+=`${""!==n?"\n\n":""}${s}`,fs.writeFileSync(t,n,{flag:"w"}))}function checkExcludeFiles(e){var s,t;return!!(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(null!==(t=null===(s=null==updateAnswer?void 0:updateAnswer.excludeFilePath)||void 0===s?void 0:s.includes(e.replace(/\\/g,"/")))&&void 0!==t&&t)}async function createDirectoryStructure(e,s,t){const n=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/../composer.json",dest:"/composer.json"}];(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(n.push({src:"/.env",dest:"/.env"},{src:"/tsconfig.json",dest:"/tsconfig.json"}),updateAnswer.tailwindcss&&n.push({src:"/postcss.config.js",dest:"/postcss.config.js"},{src:"/tailwind.config.js",dest:"/tailwind.config.js"}));n.forEach((({src:s,dest:t})=>{const n=path.join(__dirname,s),i=path.join(e,t);if(checkExcludeFiles(i))return;const c=fs.readFileSync(n,"utf8");fs.writeFileSync(i,c,{flag:"w"})})),await executeCopy(e,[{srcDir:"/settings",destDir:"/settings"},{srcDir:"/prisma",destDir:"/prisma"},{srcDir:"/src",destDir:"/src"}]),await updatePackageJson(e,t,s),await updateComposerJson(e,s),await updateIndexJsForWebSocket(e,s),s.tailwindcss?(createOrUpdateTailwindConfig(e),modifyLayoutPHP(e,!0),modifyPostcssConfig(e)):modifyLayoutPHP(e,!1);await createOrUpdateEnvFile(e,'# PHPMailer\n# SMTP_HOST=smtp.gmail.com or your SMTP host\n# SMTP_USERNAME=john.doe@gmail.com or your SMTP username\n# SMTP_PASSWORD=123456\n# SMTP_PORT=587 for TLS, 465 for SSL or your SMTP port\n# SMTP_ENCRYPTION=ssl or tls\n# MAIL_FROM=john.doe@gmail.com\n# MAIL_FROM_NAME="John Doe"'),await createUpdateGitignoreFile(e,["vendor"])}async function getAnswer(e={}){var s,t,n;const i=[];e.projectName||i.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.tailwindcss||i.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!0,active:"Yes",inactive:"No"}),e.websocket||i.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"});const c=i,r=()=>{process.exit(0)};try{const i=await prompts(c,{onCancel:r});return 0===Object.keys(i).length?null:{projectName:i.projectName?String(i.projectName).trim().replace(/ /g,"-"):null!==(s=e.projectName)&&void 0!==s?s:"my-app",tailwindcss:null!==(t=i.tailwindcss)&&void 0!==t?t:e.tailwindcss,websocket:null!==(n=i.websocket)&&void 0!==n?n:e.websocket}}catch(e){return null}}async function installDependencies(e,s,t=!1){fs.existsSync(path.join(e,"package.json"))||execSync("npm init -y",{stdio:"inherit",cwd:e}),s.forEach((e=>{}));const n=`npm install ${t?"--save-dev":""} ${s.join(" ")}`;execSync(n,{stdio:"inherit",cwd:e})}async function uninstallDependencies(e,s,t=!1){s.forEach((e=>{}));const n=`npm uninstall ${t?"--save-dev":"--save"} ${s.join(" ")}`;execSync(n,{stdio:"inherit",cwd:e})}function fetchPackageVersion(e){return new Promise(((s,t)=>{https.get(`https://registry.npmjs.org/${e}`,(e=>{let n="";e.on("data",(e=>n+=e)),e.on("end",(()=>{try{const e=JSON.parse(n);s(e["dist-tags"].latest)}catch(e){t(new Error("Failed to parse JSON response"))}}))})).on("error",(e=>t(e)))}))}const readJsonFile=e=>{const s=fs.readFileSync(e,"utf8");return JSON.parse(s)};async function main(){var e,s,t,n,i;try{const c=process.argv.slice(2);let r=c[0],o=null;if(r){const i={projectName:r,tailwindcss:c.includes("--tailwindcss"),websocket:c.includes("--websocket")};if(o=await getAnswer(i),null===o)return;const a=process.cwd(),l=path.join(a,"prisma-php.json"),p=readJsonFile(l);let d=[];null===(e=p.excludeFiles)||void 0===e||e.map((e=>{const s=path.join(a,e);fs.existsSync(s)&&d.push(s.replace(/\\/g,"/"))})),updateAnswer={projectName:r,tailwindcss:null!==(s=null==o?void 0:o.tailwindcss)&&void 0!==s&&s,websocket:null!==(t=null==o?void 0:o.websocket)&&void 0!==t&&t,isUpdate:!0,excludeFiles:null!==(n=p.excludeFiles)&&void 0!==n?n:[],excludeFilePath:null!=d?d:[],filePath:a}}else o=await getAnswer();if(null===o)return;execSync("npm install -g create-prisma-php-app",{stdio:"inherit"}),execSync("npm install -g browser-sync",{stdio:"inherit"}),r||fs.mkdirSync(o.projectName);const a=process.cwd();let l=r?a:path.join(a,o.projectName);r||process.chdir(o.projectName);const p=["prisma","@prisma/client","typescript","@types/node","ts-node","http-proxy-middleware@^2.0.6"];o.tailwindcss&&p.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano"),o.websocket&&p.push("chokidar-cli"),(o.tailwindcss||o.websocket)&&p.push("npm-run-all"),await installDependencies(l,p,!0),r||(execSync("npx prisma init",{stdio:"inherit"}),execSync("npx tsc --init",{stdio:"inherit"})),o.tailwindcss&&execSync("npx tailwindcss init -p",{stdio:"inherit"});const d=l.replace(/\\/g,"\\"),u={PROJECT_NAME:o.projectName,PROJECT_ROOT_PATH:d,PHP_ROOT_PATH_EXE:"D:\\\\xampp\\\\php\\\\php.exe",PHP_GENERATE_CLASS_PATH:"src/Lib/Prisma/Classes"};await createDirectoryStructure(l,o,u);const f=path.join(l,"public");if(fs.existsSync(f)||fs.mkdirSync(f),!o.tailwindcss){const e=path.join(l,"src","app","css");["tailwind.css","styles.css"].forEach((s=>{const t=path.join(e,s);fs.existsSync(t)&&fs.unlinkSync(t)}))}if(!o.websocket){const e=path.join(l,"src","lib","websocket");fs.existsSync(e)&&fs.rmSync(e,{recursive:!0,force:!0});const s=path.join(l,"settings");["restartWebsocket.cjs","restart_websocket.bat"].forEach((e=>{const t=path.join(s,e);fs.existsSync(t)&&fs.unlinkSync(t)}))}if(null==updateAnswer?void 0:updateAnswer.isUpdate){const e=[];if(!updateAnswer.tailwindcss){["postcss.config.js","tailwind.config.js"].forEach((e=>{const s=path.join(l,e);fs.existsSync(s)&&fs.unlinkSync(s)})),e.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano")}updateAnswer.websocket||e.push("chokidar-cli"),e.length>0&&await uninstallDependencies(l,e,!0)}const h=await fetchPackageVersion("create-prisma-php-app"),w=bsConfigUrls(u),y={projectName:o.projectName,projectRootPath:d,phpRootPathExe:"D:\\xampp\\php\\php.exe",phpGenerateClassPath:"src/Lib/Prisma/Classes",bsTarget:w.bsTarget,bsPathRewrite:w.bsPathRewrite,tailwindcss:o.tailwindcss,websocket:o.websocket,version:h,excludeFiles:null!==(i=null==updateAnswer?void 0:updateAnswer.excludeFiles)&&void 0!==i?i:[]};fs.writeFileSync(path.join(l,"prisma-php.json"),JSON.stringify(y,null,2),{flag:"w"})}catch(e){process.exit(1)}}main();
@@ -1,15 +1,15 @@
1
- import*as fs from"fs";import{exec}from"child_process";import path from"path";import{fileURLToPath,pathToFileURL}from"url";import CryptoJS from"crypto-js";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename),getSecretKey=()=>{const t=fs.readFileSync(`${__dirname}/key.enc`,"utf8");if(t.length<400)throw new Error("File content is less than 400 characters.");return t.substring(247,289)},decryptData=(t,r)=>CryptoJS.AES.decrypt(t,r).toString(CryptoJS.enc.Utf8);
1
+ import*as fs from"fs";import{exec}from"child_process";import path from"path";import{fileURLToPath}from"url";import CryptoJS from"crypto-js";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename),getSecretKey=()=>{const r=fs.readFileSync(`${__dirname}/key.enc`,"utf8");if(r.length<400)throw new Error("File content is less than 400 characters.");return r.substring(247,289)},decryptData=(r,t)=>CryptoJS.AES.decrypt(r,t).toString(CryptoJS.enc.Utf8);
2
2
  const executePHP = (command) => {
3
- exec(command, (error, stdout, stderr) => {
4
- if (error) {
5
- console.error(`Execution error: ${error}`);
6
- return;
7
- }
8
- if (stderr) {
9
- console.error(`Standard error: ${stderr}`);
10
- return;
11
- }
12
- console.log(`Standard output...\n${stdout}`);
13
- });
3
+ exec(command, (error, stdout, stderr) => {
4
+ if (error) {
5
+ console.error(`Execution error: ${error}`);
6
+ return;
7
+ }
8
+ if (stderr) {
9
+ console.error(`Standard error: ${stderr}`);
10
+ return;
11
+ }
12
+ console.log(`Standard output...\n${stdout}`);
13
+ });
14
14
  };
15
- const main=async()=>{try{const e=process.cwd(),t=pathToFileURL(path.join(e,"settings","project-settings.js")),n=(await import(t.href)).projectSettings,c=n.PHP_GENERATE_CLASS_PATH,i=`${__dirname}/index.php`,a=`${__dirname}/index.enc`,s=getSecretKey(),r=fs.readFileSync(a,{encoding:"utf8"}),_=decryptData(r,s);fs.writeFileSync(`${__dirname}/index.php`,_);const p=`${n.PHP_ROOT_PATH_EXE} ${i} ${c}`;executePHP(p)}catch(e){}};main().catch((e=>{}));
15
+ const main=async()=>{try{const e=process.cwd(),n=path.join(e,"prisma-php.json"),a=fs.readFileSync(n,{encoding:"utf8"}),c=JSON.parse(a),t=c.phpGenerateClassPath,i=`${__dirname}/index.php`,p=`${__dirname}/index.enc`,s=getSecretKey(),r=fs.readFileSync(p,{encoding:"utf8"}),d=decryptData(r,s);fs.writeFileSync(`${__dirname}/index.php`,d);const h=`${c.phpRootPathExe} ${i} ${t}`;executePHP(h)}catch(e){}};main().catch((e=>{}));
@@ -0,0 +1,56 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ // Path to your JSON configuration file
5
+ const configFilePath = path.join(__dirname, "..", "prisma-php.json");
6
+
7
+ // Use the parent directory name as the new project name
8
+ const newProjectName = path.basename(path.join(__dirname, ".."));
9
+
10
+ // Function to update the project name and paths in the JSON config
11
+ function updateProjectNameInConfig(filePath, newProjectName) {
12
+ fs.readFile(filePath, "utf8", (err, data) => {
13
+ if (err) {
14
+ console.error("Error reading the JSON file:", err);
15
+ return;
16
+ }
17
+
18
+ let config = JSON.parse(data);
19
+
20
+ // Extract the old project name from the projectRootPath
21
+ const oldProjectNameMatch = /[^\\]*$/.exec(config.projectRootPath);
22
+ if (!oldProjectNameMatch) {
23
+ console.error(
24
+ "Could not extract the old project name from projectRootPath."
25
+ );
26
+ return;
27
+ }
28
+ const oldProjectName = oldProjectNameMatch[0];
29
+
30
+ // Update the projectName
31
+ config.projectName = newProjectName;
32
+
33
+ // Update paths containing the old project name
34
+ config.projectRootPath = config.projectRootPath.replace(
35
+ new RegExp(oldProjectName + "$"),
36
+ newProjectName
37
+ );
38
+ config.bsTarget = config.bsTarget.replace(oldProjectName, newProjectName);
39
+ config.bsPathRewrite["^/"] = config.bsPathRewrite["^/"].replace(
40
+ oldProjectName,
41
+ newProjectName
42
+ );
43
+
44
+ // Save the updated config back to the JSON file
45
+ fs.writeFile(filePath, JSON.stringify(config, null, 2), "utf8", (err) => {
46
+ if (err) {
47
+ console.error("Error writing the updated JSON file:", err);
48
+ return;
49
+ }
50
+ console.log("The project name and paths have been updated successfully.");
51
+ });
52
+ });
53
+ }
54
+
55
+ // Run the function with your config file path and the new project name
56
+ updateProjectNameInConfig(configFilePath, newProjectName);
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Description placeholder
2
+ * Debounces a function to limit the rate at which it is called.
3
3
  *
4
- * @param {*} func
5
- * @param {*} wait
6
- * @param {*} immediate
7
- * @returns {(...args: {}) => void}
4
+ * @param {Function} func - The function to debounce.
5
+ * @param {number} wait - The number of milliseconds to wait before invoking the function.
6
+ * @param {boolean} immediate - Whether to invoke the function immediately on the leading edge.
7
+ * @returns {Function} - The debounced function.
8
8
  */
9
9
  function debounce(func, wait, immediate) {
10
10
  let timeout;
@@ -21,50 +21,167 @@ function debounce(func, wait, immediate) {
21
21
  }
22
22
 
23
23
  /**
24
- * Description placeholder
25
- *
26
- * @async
27
- * @param {{ className: any; methodName: any; params?: {}; }} param0
28
- * @param {*} param0.className
29
- * @param {*} param0.methodName
30
- * @param {{}} [param0.params={}]
31
- * @returns {unknown}
24
+ * Represents a HTTP request.
32
25
  */
33
- async function fetchApi({ className, methodName, params = {} }) {
34
- // Construct the request body with provided parameters
35
- let requestBody = {
36
- className: className,
37
- methodName: methodName,
38
- params: JSON.stringify(params),
39
- };
26
+ class RequestApi {
27
+ static instance = null;
40
28
 
41
- // Return the fetch promise to the caller
42
- const response = await fetch(`${baseUrl}api/api.php`, {
43
- method: "POST",
44
- headers: {
45
- "Content-Type": "application/x-www-form-urlencoded",
46
- "X-Requested-With": "XMLHttpRequest",
47
- },
48
- body: new URLSearchParams(requestBody),
49
- });
50
- if (!response.ok) {
51
- // If the response is not ok, reject the promise
52
- throw new Error("Network response was not ok");
53
- }
54
- const data = await response.json();
55
- if (data.error) {
56
- // If the API returned an error, reject the promise
57
- throw new Error(data.error);
58
- }
59
- return data;
60
- // Note: No catch here, let the caller handle any errors
29
+ /**
30
+ * The constructor is now private. To ensure it's not accessible from outside,
31
+ * you can throw an error if someone tries to instantiate it directly
32
+ * (though JavaScript does not have true private constructors).
33
+ */
34
+ constructor(baseURL = window.location.origin) {
35
+ this.baseURL = baseURL;
36
+ }
37
+
38
+ /**
39
+ * Static method to get instance of RequestApi.
40
+ *
41
+ * @param {string} [baseURL=window.location.origin] - The base URL for the request.
42
+ * @returns {RequestApi} The singleton instance of the RequestApi.
43
+ */
44
+ static getInstance(baseURL = window.location.origin) {
45
+ if (!RequestApi.instance) {
46
+ RequestApi.instance = new RequestApi(baseURL);
47
+ }
48
+ return RequestApi.instance;
49
+ }
50
+
51
+ /**
52
+ * Sends a HTTP request.
53
+ *
54
+ * @async
55
+ * @param {string} method - The HTTP method.
56
+ * @param {string} url - The URL to send the request to.
57
+ * @param {*} [data=null] - The data to send with the request.
58
+ * @param {Object} [headers={}] - The headers to include in the request.
59
+ * @returns {Promise<unknown>} - A promise that resolves to the response data.
60
+ */
61
+ async request(method, url, data = null, headers = {}) {
62
+ let fullUrl = `${this.baseURL}${url}`;
63
+ const options = {
64
+ method,
65
+ headers: {
66
+ "Content-Type": "application/json",
67
+ "X-Requested-With": "XMLHttpRequest",
68
+ ...headers,
69
+ },
70
+ };
71
+
72
+ if (data) {
73
+ if (method === "GET") {
74
+ const params = new URLSearchParams(data).toString();
75
+ fullUrl += `?${params}`;
76
+ } else if (method !== "HEAD" && method !== "OPTIONS") {
77
+ options.body = JSON.stringify(data);
78
+ }
79
+ }
80
+
81
+ try {
82
+ const response = await fetch(fullUrl, options);
83
+ if (method === "HEAD") {
84
+ return response.headers;
85
+ }
86
+ const contentType = response.headers.get("content-type");
87
+ if (contentType && contentType.includes("application/json")) {
88
+ return await response.json();
89
+ } else {
90
+ return await response.text();
91
+ }
92
+ } catch (error) {
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Sends a GET request.
99
+ *
100
+ * @param {string} url - The URL to send the request to.
101
+ * @param {*} [params] - The parameters to include in the request.
102
+ * @param {Object} [headers={}] - The headers to include in the request.
103
+ * @returns {Promise<unknown>} - A promise that resolves to the response data.
104
+ */
105
+ get(url, params, headers) {
106
+ return this.request("GET", url, params, headers);
107
+ }
108
+
109
+ /**
110
+ * Sends a POST request.
111
+ *
112
+ * @param {string} url - The URL to send the request to.
113
+ * @param {*} data - The data to send with the request.
114
+ * @param {Object} [headers={}] - The headers to include in the request.
115
+ * @returns {Promise<unknown>} - A promise that resolves to the response data.
116
+ */
117
+ post(url, data, headers) {
118
+ return this.request("POST", url, data, headers);
119
+ }
120
+
121
+ /**
122
+ * Sends a PUT request.
123
+ *
124
+ * @param {string} url - The URL to send the request to.
125
+ * @param {*} data - The data to send with the request.
126
+ * @param {Object} [headers={}] - The headers to include in the request.
127
+ * @returns {Promise<unknown>} - A promise that resolves to the response data.
128
+ */
129
+ put(url, data, headers) {
130
+ return this.request("PUT", url, data, headers);
131
+ }
132
+
133
+ /**
134
+ * Sends a DELETE request.
135
+ *
136
+ * @param {string} url - The URL to send the request to.
137
+ * @param {*} data - The data to send with the request.
138
+ * @param {Object} [headers={}] - The headers to include in the request.
139
+ * @returns {Promise<unknown>} - A promise that resolves to the response data.
140
+ */
141
+ delete(url, data, headers) {
142
+ return this.request("DELETE", url, data, headers);
143
+ }
144
+
145
+ /**
146
+ * Sends a PATCH request.
147
+ *
148
+ * @param {string} url - The URL to send the request to.
149
+ * @param {*} data - The data to send with the request.
150
+ * @param {Object} [headers={}] - The headers to include in the request.
151
+ * @returns {Promise<unknown>} - A promise that resolves to the response data.
152
+ */
153
+ patch(url, data, headers) {
154
+ return this.request("PATCH", url, data, headers);
155
+ }
156
+
157
+ /**
158
+ * Sends a HEAD request.
159
+ *
160
+ * @param {string} url - The URL to send the request to.
161
+ * @param {Object} [headers={}] - The headers to include in the request.
162
+ * @returns {Promise<unknown>} - A promise that resolves to the response headers.
163
+ */
164
+ head(url, headers) {
165
+ return this.request("HEAD", url, null, headers);
166
+ }
167
+
168
+ /**
169
+ * Sends an OPTIONS request.
170
+ *
171
+ * @param {string} url - The URL to send the request to.
172
+ * @param {Object} [headers={}] - The headers to include in the request.
173
+ * @returns {Promise<unknown>} - A promise that resolves to the options available.
174
+ */
175
+ options(url, headers) {
176
+ return this.request("OPTIONS", url, null, headers);
177
+ }
61
178
  }
62
179
 
63
180
  /**
64
- * Description placeholder
181
+ * Copies text to the clipboard.
65
182
  *
66
- * @param {*} text
67
- * @param {*} btnElement
183
+ * @param {string} text - The text to copy.
184
+ * @param {HTMLElement} btnElement - The button element that triggered the copy action.
68
185
  */
69
186
  function copyToClipboard(text, btnElement) {
70
187
  navigator.clipboard.writeText(text).then(
@@ -89,9 +206,9 @@ function copyToClipboard(text, btnElement) {
89
206
  }
90
207
 
91
208
  /**
92
- * Description placeholder
209
+ * Copies code to the clipboard.
93
210
  *
94
- * @param {*} btnElement
211
+ * @param {HTMLElement} btnElement - The button element that triggered the copy action.
95
212
  */
96
213
  function copyCode(btnElement) {
97
214
  // Assuming your code block is uniquely identifiable close to your button
@@ -105,25 +222,27 @@ function copyCode(btnElement) {
105
222
  }
106
223
 
107
224
  /**
108
- * Description placeholder
109
- *
110
- * @class StateManager
111
- * @typedef {StateManager}
225
+ * Manages the application state.
112
226
  */
113
227
  class StateManager {
114
228
  static instance = null;
115
229
 
230
+ /**
231
+ * Creates a new StateManager instance.
232
+ *
233
+ * @param {{}} [initialState={}] - The initial state.
234
+ */
116
235
  constructor(initialState = {}) {
117
236
  this.state = initialState;
118
237
  this.listeners = [];
119
238
  }
120
239
 
121
240
  /**
122
- * Description placeholder
241
+ * Gets the singleton instance of StateManager.
123
242
  *
124
243
  * @static
125
- * @param {{}} [initialState={}]
126
- * @returns {*}
244
+ * @param {{}} [initialState={}] - The initial state.
245
+ * @returns {StateManager} - The StateManager instance.
127
246
  */
128
247
  static getInstance(initialState = {}) {
129
248
  if (!StateManager.instance) {
@@ -134,10 +253,10 @@ class StateManager {
134
253
  }
135
254
 
136
255
  /**
137
- * Description placeholder
256
+ * Sets the state.
138
257
  *
139
- * @param {*} update
140
- * @param {boolean} [saveToStorage=false]
258
+ * @param {*} update - The state update.
259
+ * @param {boolean} [saveToStorage=false] - Whether to save the state to localStorage.
141
260
  */
142
261
  setState(update, saveToStorage = false) {
143
262
  this.state = { ...this.state, ...update };
@@ -148,10 +267,10 @@ class StateManager {
148
267
  }
149
268
 
150
269
  /**
151
- * Description placeholder
270
+ * Subscribes to state changes.
152
271
  *
153
- * @param {*} listener
154
- * @returns {() => any}
272
+ * @param {*} listener - The listener function.
273
+ * @returns {Function} - A function to unsubscribe the listener.
155
274
  */
156
275
  subscribe(listener) {
157
276
  this.listeners.push(listener);
@@ -160,10 +279,16 @@ class StateManager {
160
279
  (this.listeners = this.listeners.filter((l) => l !== listener));
161
280
  }
162
281
 
282
+ /**
283
+ * Saves the state to localStorage.
284
+ */
163
285
  saveState() {
164
286
  localStorage.setItem("appState", JSON.stringify(this.state));
165
287
  }
166
288
 
289
+ /**
290
+ * Loads the state from localStorage.
291
+ */
167
292
  loadState() {
168
293
  const state = localStorage.getItem("appState");
169
294
  if (state) {
@@ -173,9 +298,9 @@ class StateManager {
173
298
  }
174
299
 
175
300
  /**
176
- * Description placeholder
177
- * Reset the state to its initial value and optionally clear it from localStorage
178
- * @param {boolean} [clearFromStorage=false]
301
+ * Resets the state to its initial value.
302
+ *
303
+ * @param {boolean} [clearFromStorage=false] - Whether to clear the state from localStorage.
179
304
  */
180
305
  resetState(clearFromStorage = false) {
181
306
  this.state = {}; // Reset the state to an empty object or a default state if you prefer
@@ -186,5 +311,5 @@ class StateManager {
186
311
  }
187
312
  }
188
313
 
189
- // This creates the instance and automatically loads the state if available
190
- const store = StateManager.getInstance({});
314
+ const store = StateManager.getInstance();
315
+ const api = RequestApi.getInstance();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-prisma-php-app",
3
- "version": "1.8.21",
3
+ "version": "1.9.1",
4
4
  "description": "Prisma-PHP: A Revolutionary Library Bridging PHP with Prisma ORM",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,6 +0,0 @@
1
- export const projectSettings = {
2
- PROJECT_NAME: "",
3
- PROJECT_ROOT_PATH: "",
4
- PHP_ROOT_PATH_EXE: "D:\\xampp\\php\\php.exe",
5
- PHP_GENERATE_CLASS_PATH: "src/app/classes/prisma",
6
- };
@@ -1,98 +0,0 @@
1
- <?php
2
-
3
- // CORS headers
4
- header('Access-Control-Allow-Origin: *');
5
- header('Access-Control-Allow-Methods: POST, OPTIONS');
6
- header('Access-Control-Allow-Headers: Content-Type, X-Requested-With, Accept, Origin, Authorization, X-CSRF-Token');
7
- header('Content-Type: application/json');
8
-
9
- // Preflight request handling
10
- if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
11
- exit(0);
12
- }
13
-
14
- // Check for valid POST request with XMLHttpRequest
15
- if ($_SERVER["REQUEST_METHOD"] !== "POST" || empty($_SERVER["HTTP_X_REQUESTED_WITH"]) || $_SERVER["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest") {
16
- http_response_code(400); // Bad Request
17
- echo json_encode(["error" => "Invalid request method or type."]);
18
- exit;
19
- }
20
-
21
- require_once __DIR__ . "/../../../settings/paths.php";
22
- require_once __DIR__ . "/../../../vendor/autoload.php";
23
-
24
- use Lib\Prisma\Classes\Prisma;
25
-
26
- // Initialize variables
27
- $className = $methodName = $paramsJson = "";
28
- $params = null;
29
-
30
- // Determine request content type
31
- $contentType = $_SERVER['CONTENT_TYPE'] ?? '';
32
-
33
- // Handle JSON content type
34
- if (stripos($contentType, 'application/json') !== false) {
35
- $inputJSON = file_get_contents('php://input');
36
- $input = json_decode($inputJSON, true);
37
- if (json_last_error() === JSON_ERROR_NONE) {
38
- $className = $input['className'] ?? '';
39
- $methodName = $input['methodName'] ?? '';
40
- // Directly assign $params without double decoding
41
- $params = $input['params'] ?? []; // Initialize as empty array if not set
42
- } else {
43
- echo json_encode(['error' => 'Error: Invalid JSON body!']);
44
- exit;
45
- }
46
- } else {
47
- // Handle form-urlencoded data
48
- $className = $_POST["className"] ?? "";
49
- $methodName = $_POST["methodName"] ?? "";
50
- $paramsJson = $_POST["params"] ?? "";
51
- if (!empty($paramsJson)) {
52
- $params = json_decode($paramsJson, true);
53
- if (json_last_error() !== JSON_ERROR_NONE) {
54
- echo json_encode(['error' => 'Error: Invalid JSON in params!']);
55
- exit;
56
- }
57
- } else {
58
- $params = []; // Initialize as empty array if not set
59
- }
60
- }
61
-
62
- // Construct the full class name and check for class and property existence
63
- $fullClassName = "Lib\\Prisma\\Classes\\" . pascalCase($className);
64
- if (!class_exists($fullClassName) || !property_exists(Prisma::class, camelCase($className))) {
65
- echo json_encode(['error' => "Error: Class $fullClassName not found or property $className not found in Prisma class!"]);
66
- exit;
67
- }
68
-
69
- // Create an instance of the class
70
- $instance = (new Prisma())->$className;
71
-
72
- // Check for method existence
73
- if (!method_exists($instance, $methodName)) {
74
- echo json_encode(['error' => "Error: Method $methodName not found in class $fullClassName!"]);
75
- exit;
76
- }
77
-
78
- try {
79
- $result = $instance->$methodName($params);
80
- echo json_encode(['result' => $result instanceof \stdClass ? (array)$result : $result]);
81
- } catch (\ArgumentCountError | \Exception $e) {
82
- echo json_encode(['error' => "Error: " . $e->getMessage()]);
83
- }
84
-
85
- function camelCase($string)
86
- {
87
- $string = ucwords($string, "_");
88
- $string = str_replace("_", "", $string);
89
- $string = lcfirst($string);
90
- return $string;
91
- }
92
-
93
- function pascalCase($string)
94
- {
95
- $string = ucwords($string, "_");
96
- $string = str_replace("_", "", $string);
97
- return $string;
98
- }