create-prisma-php-app 2.0.0-alpha.1 → 2.0.0-alpha.10

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/README.md CHANGED
@@ -1,12 +1,24 @@
1
- # Create Prisma PHP App
1
+ # 🚀 Create Prisma PHP App
2
2
 
3
- 🚀 Launch Your Next-Level PHP Project with Prisma PHP
3
+ **Prisma PHP**: The Next-Gen Framework Merging PHP’s Power with Prisma's ORM Mastery
4
4
 
5
- **Prisma PHP**: A Cutting-Edge Framework Merging PHP's Power with Prisma's ORM Excellence
5
+ ---
6
6
 
7
- ## Introduction
7
+ ## **Introduction**
8
8
 
9
- `create-prisma-php-app` is a groundbreaking command-line tool designed to empower PHP developers with the modern ORM capabilities of Prisma. With this tool, you’ll be able to harness the full potential of PHP’s server-side robustness alongside Prisma’s cutting-edge database management. Whether you’re working on small-scale projects or building complex, enterprise-level applications, `create-prisma-php-app` offers unmatched flexibility and ease to elevate your development experience.
9
+ `create-prisma-php-app` is a game-changing command-line tool tailored for modern PHP developers. It seamlessly merges the power of PHP with Prisma's ORM excellence, delivering an unparalleled development experience. From blazing-fast routing to dynamic component-based integration, Prisma PHP revolutionizes how you build web applications—just like Next.js and React, but with PHP's unmatched server-side power.
10
+
11
+ ### **Why Choose Prisma PHP?**
12
+
13
+ - **Effortless Routing:** Manage complex routes with ease, supporting dynamic patterns and nested structures.
14
+ - **Component-Based Architecture:** Integrate reusable components effortlessly, just like React.
15
+ - **Flexible Integration:** Choose and integrate only the packages you need, such as:
16
+ - 🧁 **Tailwind CSS** for modern UI styling
17
+ - 📘 **Swagger Docs** for powerful API documentation
18
+ - 🔌 **WebSocket** for real-time interactions
19
+ - 🚀 **Prisma ORM** for robust database management
20
+ - **Out-of-the-Box Authentication:** Role-based sign-in and sign-out mechanisms ready to go.
21
+ - **Advanced Caching:** Supercharge performance with built-in caching options.
10
22
 
11
23
  ## Quick Start
12
24
 
package/dist/.htaccess CHANGED
@@ -1,11 +1,11 @@
1
1
  # Turn on rewrite engine
2
2
  RewriteEngine On
3
3
 
4
- # Deny access to .env file for security
5
- <Files .env>
4
+ # Prevent access to sensitive files
5
+ <FilesMatch "(^\.htaccess|\.git|\.env|composer\.(json|lock)|package(-lock)?\.json|phpunit\.xml)$">
6
6
  Order allow,deny
7
7
  Deny from all
8
- </Files>
8
+ </FilesMatch>
9
9
 
10
10
  # Allow cross-origin requests (CORS) for all routes
11
11
  <IfModule mod_headers.c>
@@ -14,11 +14,56 @@ RewriteEngine On
14
14
  Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"
15
15
  </IfModule>
16
16
 
17
+ # Set Content-Type with charset UTF-8 for HTML, CSS, and JS files
18
+ <IfModule mod_headers.c>
19
+ # For HTML files
20
+ <FilesMatch "\.(html|htm)$">
21
+ Header set Content-Type "text/html; charset=UTF-8"
22
+ </FilesMatch>
23
+
24
+ # For CSS files
25
+ <FilesMatch "\.(css)$">
26
+ Header set Content-Type "text/css; charset=UTF-8"
27
+ </FilesMatch>
28
+
29
+ # For JavaScript files
30
+ <FilesMatch "\.(js)$">
31
+ Header set Content-Type "application/javascript; charset=UTF-8"
32
+ </FilesMatch>
33
+ </IfModule>
34
+
35
+ # Add important security headers
36
+ <IfModule mod_headers.c>
37
+ # Enforce HTTPS and prevent protocol downgrade attacks
38
+ Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
39
+
40
+ # Protect against Cross-Site Scripting (XSS) attacks
41
+ Header set X-XSS-Protection "1; mode=block"
42
+
43
+ # Prevent MIME-type sniffing
44
+ Header set X-Content-Type-Options "nosniff"
45
+
46
+ # Clickjacking protection
47
+ Header always set X-Frame-Options "DENY"
48
+
49
+ # Implement a basic Content Security Policy (CSP)
50
+ Header set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:;"
51
+
52
+ # Restrict form submissions
53
+ Header set Content-Security-Policy "form-action 'self'"
54
+
55
+ # Set a strict Referrer Policy
56
+ Header set Referrer-Policy "strict-origin-when-cross-origin"
57
+
58
+ # Control browser permissions (optional but recommended)
59
+ Header set Permissions-Policy "geolocation=(), microphone=(), camera=(), autoplay=()"
60
+ </IfModule>
61
+
17
62
  # Exclude static files from being redirected
18
63
  RewriteCond %{REQUEST_URI} !\.(css|js|png|jpe?g|gif|svg|webp|woff2?|ttf|eot|ico|pdf|mp4|webm|mp3|ogg)$ [NC]
19
64
  RewriteCond %{REQUEST_URI} !^/bootstrap.php
20
65
  RewriteRule ^(.*)$ bootstrap.php [QSA,L]
21
66
 
22
- # Add this to ensure OPTIONS requests are handled correctly
67
+ # Ensure OPTIONS requests are handled correctly
23
68
  RewriteCond %{REQUEST_METHOD} OPTIONS
24
69
  RewriteRule ^ - [R=200,L]
@@ -863,12 +863,12 @@ try {
863
863
  ? Bootstrap::$parentLayoutPath
864
864
  : (Bootstrap::$layoutsToInclude[0] ?? '');
865
865
 
866
- $message = "The layout file does not contain <?= MainLayout::\$childLayoutChildren ?>\n<strong>$layoutPath</strong>";
867
- $htmlMessage = "<div class='error'>The layout file does not contain <?= MainLayout::\$childLayoutChildren ?><br><strong>$layoutPath</strong></div>";
866
+ $message = "The layout file does not contain &lt;?php echo MainLayout::\$childLayoutChildren; ?&gt; or &lt;?= MainLayout::\$childLayoutChildren ?&gt;\n<strong>$layoutPath</strong>";
867
+ $htmlMessage = "<div class='error'>The layout file does not contain &lt;?php echo MainLayout::\$childLayoutChildren; ?&gt; or &lt;?= MainLayout::\$childLayoutChildren ?&gt;<br><strong>$layoutPath</strong></div>";
868
868
 
869
869
  if (Bootstrap::$isContentIncluded) {
870
- $message = "The parent layout file does not contain <?= MainLayout::\$children ?> or <?= MainLayout::\$childLayoutChildren ?><br><strong>$layoutPath</strong>";
871
- $htmlMessage = "<div class='error'>The parent layout file does not contain <?= MainLayout::\$children ?> or <?= MainLayout::\$childLayoutChildren ?><br><strong>$layoutPath</strong></div>";
870
+ $message = "The parent layout file does not contain &lt;?php echo MainLayout::\$children; ?&gt; Or &lt;?= MainLayout::\$children ?&gt;<br><strong>$layoutPath</strong>";
871
+ $htmlMessage = "<div class='error'>The parent layout file does not contain &lt;?php echo MainLayout::\$children; ?&gt; Or &lt;?= MainLayout::\$children ?&gt;<br><strong>$layoutPath</strong></div>";
872
872
  }
873
873
 
874
874
  $errorDetails = Bootstrap::isAjaxOrXFileRequestOrRouteFile() ? $message : $htmlMessage;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
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";import{randomBytes}from"crypto";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename);let updateAnswer=null;const nonBackendFiles=["favicon.ico","\\src\\app\\index.php","metadata.php","not-found.php"],dockerFiles=[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"];function bsConfigUrls(e){const s=e.indexOf("\\htdocs\\");if(-1===s)return{bsTarget:"",bsPathRewrite:{}};const t=e.substring(0,s+"\\htdocs\\".length).replace(/\\/g,"\\\\"),n=e.replace(new RegExp(`^${t}`),"").replace(/\\/g,"/");let c=`http://localhost/${n}`;c=c.endsWith("/")?c.slice(0,-1):c;const i=c.replace(/(?<!:)(\/\/+)/g,"/"),o=n.replace(/\/\/+/g,"/");return{bsTarget:`${i}/`,bsPathRewrite:{"^/":`/${o.startsWith("/")?o.substring(1):o}/`}}}async function updatePackageJson(e,s){const t=path.join(e,"package.json");if(checkExcludeFiles(t))return;const n=JSON.parse(fs.readFileSync(t,"utf8"));n.scripts={...n.scripts,projectName:"tsx settings/project-name.ts"};let c=[];if(s.tailwindcss&&(n.scripts={...n.scripts,tailwind:"postcss src/app/css/tailwind.css -o src/app/css/styles.css --watch"},c.push("tailwind")),s.websocket&&(n.scripts={...n.scripts,websocket:"tsx settings/restart-websocket.ts"},c.push("websocket")),s.docker&&(n.scripts={...n.scripts,docker:"docker-compose up"},c.push("docker")),s.swaggerDocs){const e=s.prisma?"tsx settings/auto-swagger-docs.ts":"tsx settings/swagger-config.ts";n.scripts={...n.scripts,"create-swagger-docs":e}}let i={...n.scripts};i.browserSync="tsx settings/bs-config.ts",i.dev=`npm-run-all projectName -p browserSync ${c.join(" ")}`,n.scripts=i,n.type="module",s.prisma&&(n.prisma={seed:"tsx prisma/seed.ts"}),fs.writeFileSync(t,JSON.stringify(n,null,2))}async function updateComposerJson(e,s){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={...n.require,"cboden/ratchet":"^0.4.4"}),s.prisma&&(n.require={...n.require,"calicastle/cuid":"^2.0.0"}),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\nvar ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(t,n,"utf8")}function generateAuthSecret(){return randomBytes(33).toString("base64")}function generateLocalStoreKey(){return randomBytes(16).toString("hex")}function copyRecursiveSync(e,s,t){const n=fs.existsSync(e),c=n&&fs.statSync(e);if(n&&c&&c.isDirectory()){const n=s.toLowerCase();if(!t.websocket&&n.includes("src\\lib\\websocket"))return;if(!t.prisma&&n.includes("src\\lib\\prisma"))return;if(t.backendOnly&&n.includes("src\\app\\js")||t.backendOnly&&n.includes("src\\app\\css")||t.backendOnly&&n.includes("src\\app\\assets"))return;if(!t.swaggerDocs&&n.includes("src\\app\\swagger-docs"))return;const c=s.replace(/\\/g,"/");if(updateAnswer?.excludeFilePath?.includes(c))return;fs.existsSync(s)||fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((n=>{copyRecursiveSync(path.join(e,n),path.join(s,n),t)}))}else{if(checkExcludeFiles(s))return;if(!t.tailwindcss&&(s.includes("tailwind.css")||s.includes("styles.css")))return;if(!t.websocket&&(s.includes("restart-websocket.ts")||s.includes("restart-websocket.bat")))return;if(!t.docker&&dockerFiles.some((e=>s.includes(e))))return;if(t.backendOnly&&nonBackendFiles.some((e=>s.includes(e))))return;if(!t.backendOnly&&s.includes("route.php"))return;if(t.backendOnly&&!t.swaggerDocs&&s.includes("layout.php"))return;if(!t.swaggerDocs&&s.includes("swagger-config.ts"))return;if(t.tailwindcss&&s.includes("index.css"))return;if((!t.swaggerDocs||!t.prisma)&&(s.includes("auto-swagger-docs.ts")||s.includes("prisma-sdk.ts")||s.includes("prisma-schema-config.json")||s.includes("prisma-schema.json")))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s,t){s.forEach((({src:s,dest:n})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,n),t)}))}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,'export default {\n plugins: {\n "@tailwindcss/postcss": {},\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"),n="";s.backendOnly||(s.tailwindcss||(n='\n <link href="<?= Request::baseUrl; ?>/css/index.css" rel="stylesheet" />'),n+='\n <script src="<?= Request::baseUrl; ?>/js/json5.min.js"><\/script>\n <script src="<?= Request::baseUrl; ?>/js/index.js"><\/script>');let c="";s.backendOnly||(c=s.tailwindcss?` <link href="<?= Request::baseUrl; ?>/css/styles.css" rel="stylesheet" /> ${n}`:n);const i=c.length>0?"\n":"";e=e.replace("</head>",`${c}${i} \x3c!-- Dynamic Head --\x3e\n <?= MainLayout::outputHeadScripts() ?>\n</head>`),fs.writeFileSync(t,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const t=path.join(e,".env");checkExcludeFiles(t)||fs.writeFileSync(t,s,{flag:"w"})}function checkExcludeFiles(e){return!!updateAnswer?.isUpdate&&(updateAnswer?.excludeFilePath?.includes(e.replace(/\\/g,"/"))??!1)}async function createDirectoryStructure(e,s){const t=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/../composer.json",dest:"/composer.json"},{src:"/tsconfig.json",dest:"/tsconfig.json"},{src:"/app-gitignore",dest:"/.gitignore"}];s.tailwindcss&&t.push({src:"/postcss.config.js",dest:"/postcss.config.js"},{src:"/tailwind.config.js",dest:"/tailwind.config.js"});const n=[{src:"/settings",dest:"/settings"},{src:"/src",dest:"/src"}];s.prisma&&n.push({src:"/prisma",dest:"/prisma"}),s.docker&&n.push({src:"/.dockerignore",dest:"/.dockerignore"},{src:"/docker-compose.yml",dest:"/docker-compose.yml"},{src:"/Dockerfile",dest:"/Dockerfile"},{src:"/apache.conf",dest:"/apache.conf"}),t.forEach((({src:s,dest:t})=>{const n=path.join(__dirname,s),c=path.join(e,t);if(checkExcludeFiles(c))return;const i=fs.readFileSync(n,"utf8");fs.writeFileSync(c,i,{flag:"w"})})),await executeCopy(e,n,s),await updatePackageJson(e,s),await updateComposerJson(e,s),s.backendOnly||await updateIndexJsForWebSocket(e,s),s.tailwindcss&&modifyPostcssConfig(e),(s.tailwindcss||!s.backendOnly||s.swaggerDocs)&&modifyLayoutPHP(e,s);const c=`# Prisma PHP Auth Secret Key For development only - Change this in production\nAUTH_SECRET="${generateAuthSecret()}"\n\n# 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"\n\n# SHOW ERRORS - Set to true to show errors in the browser for development only - Change this in production to false\nSHOW_ERRORS="true"\n\n# APP TIMEZONE - Set your application timezone - Default is "UTC"\nAPP_TIMEZONE="UTC"\n\n# APP ENV - Set your application environment - Default is "development" - Change this in production to "production"\nAPP_ENV="development"\n\n# APP CACHE ENABLED - Set to true to enable caching - Default is false\nCACHE_ENABLED="false"\n# APP CACHE TTL - Set the cache time to live in seconds - Default is 600 seconds (10 minutes)\nCACHE_TTL="600"\n\n# LOCAL STORAGE KEY - Define a custom key for local storage.\n# If not set, it defaults to "pphp_local_store_59e13".\n# Spaces in the value will be replaced with underscores, and the key will be converted to lowercase automatically.\nLOCALSTORE_KEY="${generateLocalStoreKey()}"`;if(s.prisma){const s=`${'# Environment variables declared in this file are automatically made available to Prisma.\n# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema\n\n# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.\n# See the documentation for all the connection string options: https://pris.ly/d/connection-strings\n\nDATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"'}\n\n${c}`;await createOrUpdateEnvFile(e,s)}else await createOrUpdateEnvFile(e,c)}async function getAnswer(e={}){const s=[];e.projectName||s.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.backendOnly||s.push({type:"toggle",name:"backendOnly",message:`Would you like to create a ${chalk.blue("backend-only project")}?`,initial:!1,active:"Yes",inactive:"No"});const t=()=>{process.exit(0)},n=await prompts(s,{onCancel:t}),c=[];n.backendOnly||e.backendOnly?(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!0,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"})):(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.tailwindcss||c.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!1,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!1,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"}));const i=await prompts(c,{onCancel:t});return{projectName:n.projectName?String(n.projectName).trim().replace(/ /g,"-"):e.projectName??"my-app",backendOnly:n.backendOnly??e.backendOnly??!1,swaggerDocs:i.swaggerDocs??e.swaggerDocs??!1,tailwindcss:i.tailwindcss??e.tailwindcss??!1,websocket:i.websocket??e.websocket??!1,prisma:i.prisma??e.prisma??!1,docker:i.docker??e.docker??!1}}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)};function compareVersions(e,s){const t=e.split(".").map(Number),n=s.split(".").map(Number);for(let e=0;e<t.length;e++){if(t[e]>n[e])return 1;if(t[e]<n[e])return-1}return 0}function getInstalledPackageVersion(e){try{const s=execSync(`npm list -g ${e} --depth=0`).toString().match(new RegExp(`${e}@(\\d+\\.\\d+\\.\\d+)`));return s?s[1]:null}catch(e){return null}}
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";import{randomBytes}from"crypto";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename);let updateAnswer=null;const nonBackendFiles=["favicon.ico","\\src\\app\\index.php","metadata.php","not-found.php"],dockerFiles=[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"];function bsConfigUrls(e){const s=e.indexOf("\\htdocs\\");if(-1===s)return{bsTarget:"",bsPathRewrite:{}};const t=e.substring(0,s+"\\htdocs\\".length).replace(/\\/g,"\\\\"),n=e.replace(new RegExp(`^${t}`),"").replace(/\\/g,"/");let c=`http://localhost/${n}`;c=c.endsWith("/")?c.slice(0,-1):c;const i=c.replace(/(?<!:)(\/\/+)/g,"/"),o=n.replace(/\/\/+/g,"/");return{bsTarget:`${i}/`,bsPathRewrite:{"^/":`/${o.startsWith("/")?o.substring(1):o}/`}}}async function updatePackageJson(e,s){const t=path.join(e,"package.json");if(checkExcludeFiles(t))return;const n=JSON.parse(fs.readFileSync(t,"utf8"));n.scripts={...n.scripts,projectName:"tsx settings/project-name.ts"};let c=[];if(s.tailwindcss&&(n.scripts={...n.scripts,tailwind:"postcss src/app/css/tailwind.css -o src/app/css/styles.css --watch"},c.push("tailwind")),s.websocket&&(n.scripts={...n.scripts,websocket:"tsx settings/restart-websocket.ts"},c.push("websocket")),s.docker&&(n.scripts={...n.scripts,docker:"docker-compose up"},c.push("docker")),s.swaggerDocs){const e=s.prisma?"tsx settings/auto-swagger-docs.ts":"tsx settings/swagger-config.ts";n.scripts={...n.scripts,"create-swagger-docs":e}}let i={...n.scripts};i.browserSync="tsx settings/bs-config.ts",i.dev=`npm-run-all projectName -p browserSync ${c.join(" ")}`,n.scripts=i,n.type="module",s.prisma&&(n.prisma={seed:"tsx prisma/seed.ts"}),fs.writeFileSync(t,JSON.stringify(n,null,2))}async function updateComposerJson(e,s){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={...n.require,"cboden/ratchet":"^0.4.4"}),s.prisma&&(n.require={...n.require,"calicastle/cuid":"^2.0.0"}),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\nvar ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(t,n,"utf8")}function generateAuthSecret(){return randomBytes(33).toString("base64")}function generateLocalStoreKey(){return randomBytes(16).toString("hex")}function copyRecursiveSync(e,s,t){const n=fs.existsSync(e),c=n&&fs.statSync(e);if(n&&c&&c.isDirectory()){const n=s.toLowerCase();if(!t.websocket&&n.includes("src\\lib\\websocket"))return;if(t.backendOnly&&n.includes("src\\app\\js")||t.backendOnly&&n.includes("src\\app\\css")||t.backendOnly&&n.includes("src\\app\\assets"))return;if(!t.swaggerDocs&&n.includes("src\\app\\swagger-docs"))return;const c=s.replace(/\\/g,"/");if(updateAnswer?.excludeFilePath?.includes(c))return;fs.existsSync(s)||fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((n=>{copyRecursiveSync(path.join(e,n),path.join(s,n),t)}))}else{if(checkExcludeFiles(s))return;if(!t.tailwindcss&&(s.includes("tailwind.css")||s.includes("styles.css")))return;if(!t.websocket&&(s.includes("restart-websocket.ts")||s.includes("restart-websocket.bat")))return;if(!t.docker&&dockerFiles.some((e=>s.includes(e))))return;if(t.backendOnly&&nonBackendFiles.some((e=>s.includes(e))))return;if(!t.backendOnly&&s.includes("route.php"))return;if(t.backendOnly&&!t.swaggerDocs&&s.includes("layout.php"))return;if(!t.swaggerDocs&&s.includes("swagger-config.ts"))return;if(t.tailwindcss&&s.includes("index.css"))return;if((!t.swaggerDocs||!t.prisma)&&(s.includes("auto-swagger-docs.ts")||s.includes("prisma-schema-config.json")))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s,t){s.forEach((({src:s,dest:n})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,n),t)}))}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,'export default {\n plugins: {\n "@tailwindcss/postcss": {},\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"),n="";s.backendOnly||(s.tailwindcss||(n='\n <link href="<?= Request::baseUrl; ?>/css/index.css" rel="stylesheet" />'),n+='\n <script src="<?= Request::baseUrl; ?>/js/json5.min.js"><\/script>\n <script src="<?= Request::baseUrl; ?>/js/index.js"><\/script>');let c="";s.backendOnly||(c=s.tailwindcss?` <link href="<?= Request::baseUrl; ?>/css/styles.css" rel="stylesheet" /> ${n}`:n),e=e.replace("</head>",`${c}\n</head>`),fs.writeFileSync(t,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const t=path.join(e,".env");checkExcludeFiles(t)||fs.writeFileSync(t,s,{flag:"w"})}function checkExcludeFiles(e){return!!updateAnswer?.isUpdate&&(updateAnswer?.excludeFilePath?.includes(e.replace(/\\/g,"/"))??!1)}async function createDirectoryStructure(e,s){const t=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/../composer.json",dest:"/composer.json"},{src:"/tsconfig.json",dest:"/tsconfig.json"},{src:"/app-gitignore",dest:"/.gitignore"}];s.tailwindcss&&t.push({src:"/postcss.config.js",dest:"/postcss.config.js"});const n=[{src:"/settings",dest:"/settings"},{src:"/src",dest:"/src"}];s.docker&&n.push({src:"/.dockerignore",dest:"/.dockerignore"},{src:"/docker-compose.yml",dest:"/docker-compose.yml"},{src:"/Dockerfile",dest:"/Dockerfile"},{src:"/apache.conf",dest:"/apache.conf"}),t.forEach((({src:s,dest:t})=>{const n=path.join(__dirname,s),c=path.join(e,t);if(checkExcludeFiles(c))return;const i=fs.readFileSync(n,"utf8");fs.writeFileSync(c,i,{flag:"w"})})),await executeCopy(e,n,s),await updatePackageJson(e,s),await updateComposerJson(e,s),s.backendOnly||await updateIndexJsForWebSocket(e,s),s.tailwindcss&&modifyPostcssConfig(e),(s.tailwindcss||!s.backendOnly||s.swaggerDocs)&&modifyLayoutPHP(e,s);const c=`# Prisma PHP Auth Secret Key\nAUTH_SECRET="${generateAuthSecret()}"\n\n# 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"\n\n# SHOW ERRORS - Set to true to show errors in the browser for development only - Change this in production to false\nSHOW_ERRORS="true"\n\n# APP TIMEZONE - Set your application timezone - Default is "UTC"\nAPP_TIMEZONE="UTC"\n\n# APP ENV - Set your application environment - Default is "development" - Change this in production to "production"\nAPP_ENV="development"\n\n# APP CACHE ENABLED - Set to true to enable caching - Default is false\nCACHE_ENABLED="false"\n# APP CACHE TTL - Set the cache time to live in seconds - Default is 600 seconds (10 minutes)\nCACHE_TTL="600"\n\n# LOCAL STORAGE KEY - Define a custom key for local storage.\n# If not set, it defaults to "pphp_local_store_59e13".\n# Spaces in the value will be replaced with underscores, and the key will be converted to lowercase automatically.\nLOCALSTORE_KEY="${generateLocalStoreKey()}"`;if(s.prisma){const s=`${'# Environment variables declared in this file are automatically made available to Prisma.\n# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema\n\n# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.\n# See the documentation for all the connection string options: https://pris.ly/d/connection-strings\n\nDATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"'}\n\n${c}`;await createOrUpdateEnvFile(e,s)}else await createOrUpdateEnvFile(e,c)}async function getAnswer(e={}){const s=[];e.projectName||s.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.backendOnly||s.push({type:"toggle",name:"backendOnly",message:`Would you like to create a ${chalk.blue("backend-only project")}?`,initial:!1,active:"Yes",inactive:"No"});const t=()=>{process.exit(0)},n=await prompts(s,{onCancel:t}),c=[];n.backendOnly||e.backendOnly?(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!0,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"})):(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.tailwindcss||c.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!1,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!1,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"}));const i=await prompts(c,{onCancel:t});return{projectName:n.projectName?String(n.projectName).trim().replace(/ /g,"-"):e.projectName??"my-app",backendOnly:n.backendOnly??e.backendOnly??!1,swaggerDocs:i.swaggerDocs??e.swaggerDocs??!1,tailwindcss:i.tailwindcss??e.tailwindcss??!1,websocket:i.websocket??e.websocket??!1,prisma:i.prisma??e.prisma??!1,docker:i.docker??e.docker??!1}}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)};function compareVersions(e,s){const t=e.split(".").map(Number),n=s.split(".").map(Number);for(let e=0;e<t.length;e++){if(t[e]>n[e])return 1;if(t[e]<n[e])return-1}return 0}function getInstalledPackageVersion(e){try{const s=execSync(`npm list -g ${e} --depth=0`).toString().match(new RegExp(`${e}@(\\d+\\.\\d+\\.\\d+)`));return s?s[1]:null}catch(e){return null}}
3
3
  /**
4
4
  * Install dependencies in the specified directory.
5
5
  * @param {string} baseDir - The base directory where to install the dependencies.
@@ -32,11 +32,12 @@ async function installDependencies(baseDir, dependencies, isDev = false) {
32
32
  });
33
33
  }
34
34
  const pinnedVersions = {
35
- "@prisma/client": "^6.2.1",
35
+ "@prisma/client": "^6.4.1",
36
+ "@prisma/internals": "^6.4.1",
37
+ "@tailwindcss/postcss": "^4.0.8",
36
38
  "@types/browser-sync": "^2.29.0",
37
- "@types/node": "^22.10.7",
39
+ "@types/node": "^22.13.5",
38
40
  "@types/prompts": "^2.4.9",
39
- "@prisma/internals": "^6.2.1",
40
41
  autoprefixer: "^10.4.20",
41
42
  "browser-sync": "^3.0.3",
42
43
  chalk: "^5.4.1",
@@ -44,13 +45,12 @@ const pinnedVersions = {
44
45
  "http-proxy-middleware": "^3.0.3",
45
46
  "npm-run-all": "^4.1.5",
46
47
  "php-parser": "^3.2.2",
47
- prompts: "^2.4.2",
48
- postcss: "^8.5.1",
48
+ postcss: "^8.5.3",
49
49
  "postcss-cli": "^11.0.0",
50
- prisma: "^6.2.1",
51
- tailwindcss: "^4.0.0",
52
- "@tailwindcss/postcss": "^4.0.0",
53
- tsx: "^4.19.2",
50
+ prisma: "^6.4.1",
51
+ prompts: "^2.4.2",
52
+ tailwindcss: "^4.0.8",
53
+ tsx: "^4.19.3",
54
54
  typescript: "^5.7.3",
55
55
  };
56
56
  function pkg(name) {
@@ -84,26 +84,28 @@ async function main() {
84
84
  }
85
85
  const currentDir = process.cwd();
86
86
  const configPath = path.join(currentDir, "prisma-php.json");
87
- const localSettings = readJsonFile(configPath);
88
- let excludeFiles = [];
89
- localSettings.excludeFiles?.map((file) => {
90
- const filePath = path.join(currentDir, file);
91
- if (fs.existsSync(filePath))
92
- excludeFiles.push(filePath.replace(/\\/g, "/"));
93
- });
94
- updateAnswer = {
95
- projectName,
96
- backendOnly: answer?.backendOnly ?? false,
97
- swaggerDocs: answer?.swaggerDocs ?? false,
98
- tailwindcss: answer?.tailwindcss ?? false,
99
- websocket: answer?.websocket ?? false,
100
- prisma: answer?.prisma ?? false,
101
- docker: answer?.docker ?? false,
102
- isUpdate: true,
103
- excludeFiles: localSettings.excludeFiles ?? [],
104
- excludeFilePath: excludeFiles ?? [],
105
- filePath: currentDir,
106
- };
87
+ if (fs.existsSync(configPath)) {
88
+ const localSettings = readJsonFile(configPath);
89
+ let excludeFiles = [];
90
+ localSettings.excludeFiles?.map((file) => {
91
+ const filePath = path.join(currentDir, file);
92
+ if (fs.existsSync(filePath))
93
+ excludeFiles.push(filePath.replace(/\\/g, "/"));
94
+ });
95
+ updateAnswer = {
96
+ projectName,
97
+ backendOnly: answer?.backendOnly ?? false,
98
+ swaggerDocs: answer?.swaggerDocs ?? false,
99
+ tailwindcss: answer?.tailwindcss ?? false,
100
+ websocket: answer?.websocket ?? false,
101
+ prisma: answer?.prisma ?? false,
102
+ docker: answer?.docker ?? false,
103
+ isUpdate: true,
104
+ excludeFiles: localSettings.excludeFiles ?? [],
105
+ excludeFilePath: excludeFiles ?? [],
106
+ filePath: currentDir,
107
+ };
108
+ }
107
109
  } else {
108
110
  answer = await getAnswer();
109
111
  }
@@ -124,10 +126,10 @@ async function main() {
124
126
  latestVersionOfCreatePrismaPhpApp
125
127
  ) === -1
126
128
  ) {
127
- execSync(`npm uninstall -g create-prisma-php-app`, {
129
+ execSync("npm uninstall -g create-prisma-php-app", {
128
130
  stdio: "inherit",
129
131
  });
130
- execSync(`npm install -g create-prisma-php-app`, {
132
+ execSync("npm install -g create-prisma-php-app", {
131
133
  stdio: "inherit",
132
134
  });
133
135
  }
@@ -156,11 +158,7 @@ async function main() {
156
158
  dependencies.push(pkg("swagger-jsdoc"), pkg("@types/swagger-jsdoc"));
157
159
  }
158
160
  if (answer.swaggerDocs && answer.prisma) {
159
- dependencies.push(
160
- pkg("prompts"),
161
- pkg("@types/prompts"),
162
- pkg("@prisma/internals")
163
- );
161
+ dependencies.push(pkg("prompts"), pkg("@types/prompts"));
164
162
  }
165
163
  if (answer.tailwindcss) {
166
164
  dependencies.push(
@@ -174,18 +172,16 @@ async function main() {
174
172
  dependencies.push(pkg("chokidar-cli"));
175
173
  }
176
174
  if (answer.prisma) {
177
- dependencies.push(pkg("prisma"), pkg("@prisma/client"));
178
175
  execSync("npm install -g prisma-client-php", { stdio: "inherit" });
179
176
  }
180
177
  await installDependencies(projectPath, dependencies, true);
181
178
  if (!projectName) {
182
- execSync(`npx tsc --init`, { stdio: "inherit" });
179
+ execSync("npx tsc --init", { stdio: "inherit" });
183
180
  }
181
+ await createDirectoryStructure(projectPath, answer);
184
182
  if (answer.prisma) {
185
- if (!fs.existsSync(path.join(projectPath, "prisma")))
186
- execSync(`npx prisma init`, { stdio: "inherit" });
183
+ execSync("npx ppo init --prisma-php", { stdio: "inherit" });
187
184
  }
188
- await createDirectoryStructure(projectPath, answer);
189
185
  if (answer.swaggerDocs) {
190
186
  const swaggerDocsPath = path.join(
191
187
  projectPath,
@@ -260,8 +256,7 @@ async function main() {
260
256
  "swagger-jsdoc",
261
257
  "@types/swagger-jsdoc",
262
258
  "prompts",
263
- "@types/prompts",
264
- "@prisma/internals"
259
+ "@types/prompts"
265
260
  );
266
261
  }
267
262
  if (!updateAnswer.tailwindcss) {
@@ -309,7 +304,11 @@ async function main() {
309
304
  updateUninstallDependencies.push("chokidar-cli");
310
305
  }
311
306
  if (!updateAnswer.prisma) {
312
- updateUninstallDependencies.push("prisma", "@prisma/client");
307
+ updateUninstallDependencies.push(
308
+ "prisma",
309
+ "@prisma/client",
310
+ "@prisma/internals"
311
+ );
313
312
  }
314
313
  if (!updateAnswer.docker) {
315
314
  const dockerFiles = [
@@ -1,5 +1,5 @@
1
- export default {
2
- plugins: {
3
- "@tailwindcss/postcss": {},
4
- },
1
+ export default {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
5
  };
@@ -5,6 +5,9 @@ declare(strict_types=1);
5
5
  namespace Lib;
6
6
 
7
7
  use Lib\Headers\Boom;
8
+ use ArrayObject;
9
+ use stdClass;
10
+ use Lib\PrismaPHPSettings;
8
11
 
9
12
  class Request
10
13
  {
@@ -16,7 +19,7 @@ class Request
16
19
  public const baseUrl = '/src/app';
17
20
 
18
21
  /**
19
- * @var \stdClass $params A static property to hold request parameters.
22
+ * @var stdClass $params A static property to hold request parameters.
20
23
  *
21
24
  * This property is used to hold request parameters that are passed to the request.
22
25
  *
@@ -28,10 +31,10 @@ class Request
28
31
  * $id = Request::$params->id;
29
32
  * ```
30
33
  */
31
- public static \ArrayObject $params;
34
+ public static ArrayObject $params;
32
35
 
33
36
  /**
34
- * @var \stdClass $dynamicParams A static property to hold dynamic parameters.
37
+ * @var stdClass $dynamicParams A static property to hold dynamic parameters.
35
38
  *
36
39
  * This property is used to hold dynamic parameters that are passed to the request.
37
40
  *
@@ -53,10 +56,10 @@ class Request
53
56
  *
54
57
  * The above code will output the dynamic parameters as an array, which can be useful for debugging purposes.
55
58
  */
56
- public static \ArrayObject $dynamicParams;
59
+ public static ArrayObject $dynamicParams;
57
60
 
58
61
  /**
59
- * @var \stdClass $localStorage A static property to hold request parameters.
62
+ * @var stdClass $localStorage A static property to hold request parameters.
60
63
  *
61
64
  * This property is used to hold request parameters that are passed to the request.
62
65
  *
@@ -68,7 +71,7 @@ class Request
68
71
  * $id = Request::$localStorage->id;
69
72
  * ```
70
73
  */
71
- public static \ArrayObject $localStorage;
74
+ public static ArrayObject $localStorage;
72
75
 
73
76
  /**
74
77
  * @var mixed $data Holds request data (e.g., JSON body).
@@ -189,8 +192,8 @@ class Request
189
192
  */
190
193
  public static function init(): void
191
194
  {
192
- self::$params = new \ArrayObject([], \ArrayObject::ARRAY_AS_PROPS);
193
- self::$dynamicParams = new \ArrayObject([], \ArrayObject::ARRAY_AS_PROPS);
195
+ self::$params = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
196
+ self::$dynamicParams = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
194
197
 
195
198
  self::$referer = $_SERVER['HTTP_REFERER'] ?? 'Unknown';
196
199
  self::$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
@@ -286,15 +289,15 @@ class Request
286
289
  /**
287
290
  * Get the request parameters.
288
291
  *
289
- * @return \ArrayObject The request parameters as an \ArrayObject with properties.
292
+ * @return ArrayObject The request parameters as an ArrayObject with properties.
290
293
  */
291
- private static function getParams(): \ArrayObject
294
+ private static function getParams(): ArrayObject
292
295
  {
293
- $params = new \ArrayObject([], \ArrayObject::ARRAY_AS_PROPS);
296
+ $params = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
294
297
 
295
298
  switch (self::$method) {
296
299
  case 'GET':
297
- $params = new \ArrayObject($_GET, \ArrayObject::ARRAY_AS_PROPS);
300
+ $params = new ArrayObject($_GET, ArrayObject::ARRAY_AS_PROPS);
298
301
  break;
299
302
  default:
300
303
  // Handle JSON input with different variations (e.g., application/json, application/ld+json, etc.)
@@ -303,7 +306,7 @@ class Request
303
306
  if ($jsonInput !== false && !empty($jsonInput)) {
304
307
  self::$data = json_decode($jsonInput, true);
305
308
  if (json_last_error() === JSON_ERROR_NONE) {
306
- $params = new \ArrayObject(self::$data, \ArrayObject::ARRAY_AS_PROPS);
309
+ $params = new ArrayObject(self::$data, ArrayObject::ARRAY_AS_PROPS);
307
310
  } else {
308
311
  Boom::badRequest('Invalid JSON body')->toResponse();
309
312
  }
@@ -315,9 +318,9 @@ class Request
315
318
  $rawInput = file_get_contents('php://input');
316
319
  if ($rawInput !== false && !empty($rawInput)) {
317
320
  parse_str($rawInput, $parsedParams);
318
- $params = new \ArrayObject($parsedParams, \ArrayObject::ARRAY_AS_PROPS);
321
+ $params = new ArrayObject($parsedParams, ArrayObject::ARRAY_AS_PROPS);
319
322
  } else {
320
- $params = new \ArrayObject($_POST, \ArrayObject::ARRAY_AS_PROPS);
323
+ $params = new ArrayObject($_POST, ArrayObject::ARRAY_AS_PROPS);
321
324
  }
322
325
  }
323
326
  break;
@@ -330,28 +333,28 @@ class Request
330
333
  * Retrieves the local storage data from the session or initializes it if not present.
331
334
  *
332
335
  * This method checks if the local storage data is available in the static data array or the session.
333
- * If the data is found, it is decoded from JSON if necessary and returned as an \ArrayObject.
334
- * If the data is not found, an empty \ArrayObject is returned.
336
+ * If the data is found, it is decoded from JSON if necessary and returned as an ArrayObject.
337
+ * If the data is not found, an empty ArrayObject is returned.
335
338
  *
336
- * @return \ArrayObject The local storage data as an \ArrayObject.
339
+ * @return ArrayObject The local storage data as an ArrayObject.
337
340
  */
338
- private static function getLocalStorage(): \ArrayObject
341
+ private static function getLocalStorage(): ArrayObject
339
342
  {
340
- $sessionKey = 'appState_59E13';
341
- $localStorage = new \ArrayObject([], \ArrayObject::ARRAY_AS_PROPS);
343
+ $sessionKey = PrismaPHPSettings::$localStoreKey;
344
+ $localStorage = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
342
345
 
343
346
  if (isset(self::$data[$sessionKey])) {
344
347
  $data = self::$data[$sessionKey];
345
348
 
346
349
  if (is_array($data)) {
347
350
  $_SESSION[$sessionKey] = $data;
348
- $localStorage = new \ArrayObject($data, \ArrayObject::ARRAY_AS_PROPS);
351
+ $localStorage = new ArrayObject($data, ArrayObject::ARRAY_AS_PROPS);
349
352
  } else {
350
353
  $decodedData = json_decode($data, true);
351
354
 
352
355
  if (json_last_error() === JSON_ERROR_NONE) {
353
356
  $_SESSION[$sessionKey] = $data;
354
- $localStorage = new \ArrayObject($decodedData, \ArrayObject::ARRAY_AS_PROPS);
357
+ $localStorage = new ArrayObject($decodedData, ArrayObject::ARRAY_AS_PROPS);
355
358
  } else {
356
359
  Boom::badRequest('Invalid JSON body')->toResponse();
357
360
  }
@@ -361,12 +364,12 @@ class Request
361
364
  $sessionData = $_SESSION[$sessionKey];
362
365
 
363
366
  if (is_array($sessionData)) {
364
- $localStorage = new \ArrayObject($sessionData, \ArrayObject::ARRAY_AS_PROPS);
367
+ $localStorage = new ArrayObject($sessionData, ArrayObject::ARRAY_AS_PROPS);
365
368
  } else {
366
369
  $decodedData = json_decode($sessionData, true);
367
370
 
368
371
  if (json_last_error() === JSON_ERROR_NONE) {
369
- $localStorage = new \ArrayObject($decodedData, \ArrayObject::ARRAY_AS_PROPS);
372
+ $localStorage = new ArrayObject($decodedData, ArrayObject::ARRAY_AS_PROPS);
370
373
  }
371
374
  }
372
375
  }
@@ -436,24 +439,17 @@ class Request
436
439
  */
437
440
  public static function redirect(string $url, bool $replace = true, int $responseCode = 0): void
438
441
  {
439
- // Clean (discard) any previous output
440
442
  ob_clean();
441
-
442
- // Start a fresh output buffer
443
443
  ob_start();
444
444
 
445
445
  if (!self::$isWire && !self::$isAjax) {
446
- // Normal redirect for non-ajax/wire requests
447
- ob_end_clean(); // End the buffer, don't send it
448
- header("Location: $url", $replace, $responseCode); // Redirect using header
446
+ header("Location: $url", $replace, $responseCode);
449
447
  } else {
450
- // For ajax/wire requests, send the custom redirect response
451
- ob_clean(); // Clean any previous output
452
- echo "redirect_7F834=$url"; // Output the redirect message
453
- ob_end_flush(); // Flush and send the output buffer
448
+ ob_clean();
449
+ echo "redirect_7F834=$url";
450
+ ob_end_flush();
454
451
  }
455
452
 
456
- // Terminate the script to prevent any further output
457
453
  exit;
458
454
  }
459
455
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-prisma-php-app",
3
- "version": "2.0.0-alpha.1",
3
+ "version": "2.0.0-alpha.10",
4
4
  "description": "Prisma-PHP: A Revolutionary Library Bridging PHP with Prisma ORM",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,37 +0,0 @@
1
- // This is your Prisma schema file,
2
- // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
-
4
- // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5
- // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6
-
7
- generator client {
8
- provider = "prisma-client-js"
9
- }
10
-
11
- datasource db {
12
- provider = "postgresql"
13
- url = env("DATABASE_URL")
14
- }
15
-
16
- model User {
17
- id String @id @default(cuid())
18
- name String?
19
- email String? @unique
20
- password String?
21
- emailVerified DateTime?
22
- image String?
23
- createdAt DateTime @default(now())
24
- updatedAt DateTime @updatedAt
25
-
26
- roleId Int?
27
- userRole UserRole? @relation(fields: [roleId], references: [id])
28
-
29
- @@map("Users")
30
- }
31
-
32
- model UserRole {
33
- id Int @id @default(autoincrement())
34
- name String @unique
35
-
36
- user User[]
37
- }