Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
Clubphp
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Clubphp
Commits
2e052b1f
Commit
2e052b1f
authored
Apr 07, 2026
by
Administrator
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update 4 files via Son of Anton
parent
a83fd794
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
262 additions
and
193 deletions
+262
-193
Controller.php
app/Core/Controller.php
+21
-36
Response.php
app/Core/Response.php
+48
-75
Template.php
app/Core/Template.php
+147
-71
alerts.php
app/Shared/Components/alerts.php
+46
-11
No files found.
app/Core/Controller.php
View file @
2e052b1f
...
@@ -6,33 +6,35 @@ namespace App\Core;
...
@@ -6,33 +6,35 @@ namespace App\Core;
abstract
class
Controller
abstract
class
Controller
{
{
protected
Request
$request
;
protected
Request
$request
;
protected
array
$middleware
=
[];
public
function
__construct
(
Request
$request
)
public
function
__construct
()
{
{
$this
->
request
=
$request
;
}
}
protected
function
view
(
string
$viewPath
,
array
$data
=
[])
:
Response
protected
function
view
(
string
$viewPath
,
array
$data
=
[])
:
Response
{
{
$template
=
new
Template
();
$template
=
new
Template
();
$html
=
$template
->
render
(
$viewPath
,
$data
);
$html
=
$template
->
render
(
$viewPath
,
$data
);
return
(
new
Response
())
->
html
(
$html
);
$response
=
new
Response
();
return
$response
->
html
(
$html
);
}
}
protected
function
json
(
$data
,
int
$status
=
200
)
:
Response
protected
function
json
(
$data
,
int
$status
=
200
)
:
Response
{
{
return
(
new
Response
())
->
json
(
$data
,
$status
);
$response
=
new
Response
();
return
$response
->
json
(
$data
,
$status
);
}
}
protected
function
redirect
(
string
$url
)
:
Response
protected
function
redirect
(
string
$url
)
:
Response
{
{
return
(
new
Response
())
->
redirect
(
$url
);
return
new
Response
(
$url
);
}
}
protected
function
back
()
:
Response
protected
function
back
()
:
Response
{
{
return
(
new
Response
())
->
back
();
$referer
=
$_SERVER
[
'HTTP_REFERER'
]
??
'/'
;
return
new
Response
(
$referer
);
}
}
protected
function
validate
(
array
$data
,
array
$rules
)
:
array
protected
function
validate
(
array
$data
,
array
$rules
)
:
array
...
@@ -41,46 +43,29 @@ abstract class Controller
...
@@ -41,46 +43,29 @@ abstract class Controller
$result
=
$validator
->
validate
(
$data
,
$rules
);
$result
=
$validator
->
validate
(
$data
,
$rules
);
if
(
$result
->
fails
())
{
if
(
$result
->
fails
())
{
if
(
$this
->
request
->
isAjax
()
||
$this
->
request
->
isJson
())
{
$session
=
App
::
getInstance
()
->
session
();
$response
=
(
new
Response
())
->
json
([
$session
->
flash
(
'_old_input'
,
$data
);
'success'
=>
false
,
$errors
=
$result
->
errors
();
'errors'
=>
$result
->
errors
(),
$alerts
=
[];
],
422
);
foreach
(
$errors
as
$field
=>
$fieldErrors
)
{
$response
->
send
();
foreach
(
$fieldErrors
as
$error
)
{
exit
;
$alerts
[]
=
[
'type'
=>
'error'
,
'message'
=>
$error
];
}
}
}
$session
->
flash
(
'_alerts'
,
$alerts
);
App
::
getInstance
()
->
session
()
->
flash
(
'_errors'
,
$result
->
errors
());
App
::
getInstance
()
->
session
()
->
flash
(
'_old_input'
,
$data
);
$referer
=
$_SERVER
[
'HTTP_REFERER'
]
??
'/'
;
$response
=
(
new
Response
())
->
redirect
(
$referer
);
$response
->
send
();
exit
;
}
}
return
$
result
->
validated
()
;
return
$
data
;
}
}
protected
function
authorize
(
string
$permission
)
:
void
protected
function
authorize
(
string
$permission
)
:
void
{
{
$employee
=
App
::
getInstance
()
->
currentEmployee
();
$employee
=
App
::
getInstance
()
->
currentEmployee
();
if
(
!
$employee
)
{
if
(
!
$employee
)
{
$response
=
(
new
Response
())
->
redirect
(
'/login'
);
throw
new
\RuntimeException
(
'Unauthorized'
,
401
);
$response
->
send
();
exit
;
}
}
if
(
method_exists
(
$employee
,
'hasPermission'
)
&&
!
$employee
->
hasPermission
(
$permission
))
{
if
(
method_exists
(
$employee
,
'hasPermission'
)
&&
!
$employee
->
hasPermission
(
$permission
))
{
$response
=
(
new
Response
())
->
html
(
throw
new
\RuntimeException
(
'Forbidden'
,
403
);
'<html dir="rtl" lang="ar"><head><meta charset="utf-8"><title>غير مصرح</title>'
.
'<style>body{font-family:Cairo,sans-serif;text-align:center;padding:60px;background:#f9fafb;}'
.
'h1{color:#DC2626;font-size:48px;}p{color:#6B7280;}</style></head>'
.
'<body><h1>403</h1><p>غير مصرح لك بالوصول لهذه الصفحة</p><a href="/">العودة للرئيسية</a></body></html>'
,
403
);
$response
->
send
();
exit
;
}
}
}
}
...
...
app/Core/Response.php
View file @
2e052b1f
...
@@ -5,93 +5,59 @@ namespace App\Core;
...
@@ -5,93 +5,59 @@ namespace App\Core;
final
class
Response
final
class
Response
{
{
private
string
$body
=
''
;
private
int
$statusCode
=
200
;
private
int
$statusCode
=
200
;
private
array
$headers
=
[];
private
array
$headers
=
[];
private
string
$body
=
''
;
private
?
string
$redirectUrl
=
null
;
private
bool
$sent
=
false
;
private
array
$flashData
=
[];
public
function
__construct
(
?
string
$redirectUrl
=
null
)
{
if
(
$redirectUrl
!==
null
)
{
$this
->
redirectUrl
=
$redirectUrl
;
$this
->
statusCode
=
302
;
}
}
public
function
html
(
string
$content
,
int
$status
=
200
)
:
self
public
function
html
(
string
$content
,
int
$status
=
200
)
:
self
{
{
$this
->
statusCode
=
$status
;
$this
->
headers
[
'Content-Type'
]
=
'text/html; charset=utf-8'
;
$this
->
body
=
$content
;
$this
->
body
=
$content
;
$this
->
statusCode
=
$status
;
$this
->
headers
[
'Content-Type'
]
=
'text/html; charset=UTF-8'
;
return
$this
;
return
$this
;
}
}
public
function
json
(
$data
,
int
$status
=
200
)
:
self
public
function
json
(
$data
,
int
$status
=
200
)
:
self
{
{
$this
->
statusCode
=
$status
;
$this
->
headers
[
'Content-Type'
]
=
'application/json; charset=utf-8'
;
$this
->
body
=
json_encode
(
$data
,
JSON_UNESCAPED_UNICODE
|
JSON_UNESCAPED_SLASHES
);
$this
->
body
=
json_encode
(
$data
,
JSON_UNESCAPED_UNICODE
|
JSON_UNESCAPED_SLASHES
);
$this
->
statusCode
=
$status
;
$this
->
headers
[
'Content-Type'
]
=
'application/json; charset=UTF-8'
;
return
$this
;
return
$this
;
}
}
public
function
redirect
(
string
$url
,
int
$status
=
302
)
:
self
public
function
redirect
(
string
$url
,
int
$status
=
302
)
:
self
{
{
$this
->
redirectUrl
=
$url
;
$this
->
statusCode
=
$status
;
$this
->
statusCode
=
$status
;
$this
->
headers
[
'Location'
]
=
$url
;
$this
->
body
=
''
;
return
$this
;
}
public
function
back
()
:
self
{
$referer
=
$_SERVER
[
'HTTP_REFERER'
]
??
'/'
;
return
$this
->
redirect
(
$referer
);
}
public
function
download
(
string
$filePath
,
string
$filename
)
:
self
{
if
(
!
file_exists
(
$filePath
))
{
return
$this
->
html
(
'File not found'
,
404
);
}
$this
->
statusCode
=
200
;
$this
->
headers
[
'Content-Type'
]
=
'application/octet-stream'
;
$this
->
headers
[
'Content-Disposition'
]
=
'attachment; filename="'
.
$filename
.
'"'
;
$this
->
headers
[
'Content-Length'
]
=
(
string
)
filesize
(
$filePath
);
$this
->
body
=
file_get_contents
(
$filePath
);
return
$this
;
}
public
function
withSession
(
string
$key
,
$value
)
:
self
{
App
::
getInstance
()
->
session
()
->
flash
(
$key
,
$value
);
return
$this
;
}
public
function
withError
(
string
$message
)
:
self
{
$session
=
App
::
getInstance
()
->
session
();
$alerts
=
$session
->
get
(
'_alerts'
,
[]);
$alerts
[]
=
[
'type'
=>
'error'
,
'message'
=>
$message
];
$session
->
flash
(
'_alerts'
,
$alerts
);
return
$this
;
return
$this
;
}
}
public
function
withSuccess
(
string
$message
)
:
self
public
function
withSuccess
(
string
$message
)
:
self
{
{
$session
=
App
::
getInstance
()
->
session
();
$session
=
App
::
getInstance
()
->
session
();
$alerts
=
$session
->
get
(
'_alerts'
,
[]);
$alerts
=
$session
->
get
(
'_flash._alerts'
,
[]);
if
(
!
is_array
(
$alerts
))
$alerts
=
[];
$alerts
[]
=
[
'type'
=>
'success'
,
'message'
=>
$message
];
$alerts
[]
=
[
'type'
=>
'success'
,
'message'
=>
$message
];
$session
->
flash
(
'_alerts'
,
$alerts
);
$session
->
flash
(
'_alerts'
,
$alerts
);
return
$this
;
return
$this
;
}
}
public
function
withWarning
(
string
$message
)
:
self
public
function
withError
(
string
$message
)
:
self
{
$session
=
App
::
getInstance
()
->
session
();
$alerts
=
$session
->
get
(
'_alerts'
,
[]);
$alerts
[]
=
[
'type'
=>
'warning'
,
'message'
=>
$message
];
$session
->
flash
(
'_alerts'
,
$alerts
);
return
$this
;
}
public
function
withInfo
(
string
$message
)
:
self
{
{
$session
=
App
::
getInstance
()
->
session
();
$session
=
App
::
getInstance
()
->
session
();
$alerts
=
$session
->
get
(
'_alerts'
,
[]);
$alerts
=
$session
->
get
(
'_flash._alerts'
,
[]);
$alerts
[]
=
[
'type'
=>
'info'
,
'message'
=>
$message
];
if
(
!
is_array
(
$alerts
))
$alerts
=
[];
$alerts
[]
=
[
'type'
=>
'error'
,
'message'
=>
$message
];
$session
->
flash
(
'_alerts'
,
$alerts
);
$session
->
flash
(
'_alerts'
,
$alerts
);
return
$this
;
return
$this
;
}
}
...
@@ -102,9 +68,13 @@ final class Response
...
@@ -102,9 +68,13 @@ final class Response
return
$this
;
return
$this
;
}
}
public
function
with
Errors
(
array
$errors
)
:
self
public
function
with
Warning
(
string
$message
)
:
self
{
{
App
::
getInstance
()
->
session
()
->
flash
(
'_errors'
,
$errors
);
$session
=
App
::
getInstance
()
->
session
();
$alerts
=
$session
->
get
(
'_flash._alerts'
,
[]);
if
(
!
is_array
(
$alerts
))
$alerts
=
[];
$alerts
[]
=
[
'type'
=>
'warning'
,
'message'
=>
$message
];
$session
->
flash
(
'_alerts'
,
$alerts
);
return
$this
;
return
$this
;
}
}
...
@@ -120,37 +90,40 @@ final class Response
...
@@ -120,37 +90,40 @@ final class Response
return
$this
;
return
$this
;
}
}
public
function
pdf
(
string
$html
)
:
self
public
function
download
(
string
$filePath
,
string
$filename
)
:
self
{
{
$this
->
statusCode
=
200
;
if
(
!
file_exists
(
$filePath
))
{
$this
->
headers
[
'Content-Type'
]
=
'text/html; charset=utf-8'
;
$this
->
statusCode
=
404
;
$this
->
body
=
$html
;
$this
->
body
=
'File not found'
;
return
$this
;
}
$this
->
headers
[
'Content-Type'
]
=
mime_content_type
(
$filePath
)
?:
'application/octet-stream'
;
$this
->
headers
[
'Content-Disposition'
]
=
'attachment; filename="'
.
$filename
.
'"'
;
$this
->
headers
[
'Content-Length'
]
=
(
string
)
filesize
(
$filePath
);
$this
->
body
=
file_get_contents
(
$filePath
);
return
$this
;
return
$this
;
}
}
public
function
send
()
:
void
public
function
send
()
:
void
{
{
if
(
$this
->
sent
)
{
// Handle redirect
return
;
if
(
$this
->
redirectUrl
!==
null
)
{
http_response_code
(
$this
->
statusCode
);
header
(
'Location: '
.
$this
->
redirectUrl
);
exit
;
}
}
// Set status code
http_response_code
(
$this
->
statusCode
);
http_response_code
(
$this
->
statusCode
);
// Set headers
foreach
(
$this
->
headers
as
$key
=>
$value
)
{
foreach
(
$this
->
headers
as
$key
=>
$value
)
{
header
(
"
{
$key
}
:
{
$value
}
"
);
header
(
"
{
$key
}
:
{
$value
}
"
);
}
}
// Output body
echo
$this
->
body
;
echo
$this
->
body
;
$this
->
sent
=
true
;
exit
;
}
public
function
getBody
()
:
string
{
return
$this
->
body
;
}
public
function
getStatusCode
()
:
int
{
return
$this
->
statusCode
;
}
}
}
}
\ No newline at end of file
app/Core/Template.php
View file @
2e052b1f
...
@@ -5,133 +5,209 @@ namespace App\Core;
...
@@ -5,133 +5,209 @@ namespace App\Core;
final
class
Template
final
class
Template
{
{
private
?
string
$layoutPath
=
null
;
private
string
$basePath
;
private
array
$sections
=
[];
private
array
$sections
=
[];
private
?
string
$currentSection
=
null
;
private
array
$sectionStack
=
[];
private
array
$stacks
=
[];
private
?
string
$layoutName
=
null
;
private
?
string
$currentStack
=
null
;
private
array
$layoutData
=
[];
private
array
$data
=
[];
public
function
__construct
()
{
$this
->
basePath
=
dirname
(
__DIR__
,
2
);
}
public
function
render
(
string
$viewPath
,
array
$data
=
[])
:
string
public
function
render
(
string
$viewPath
,
array
$data
=
[])
:
string
{
{
$file
=
$this
->
resolveViewPath
(
$viewPath
);
$this
->
data
=
$data
;
$this
->
sections
=
[];
$this
->
sectionStack
=
[];
$this
->
layoutName
=
null
;
$file
=
$this
->
resolvePath
(
$viewPath
);
if
(
!
file_exists
(
$file
))
{
if
(
!
file_exists
(
$file
))
{
throw
new
\RuntimeException
(
"View not found:
{
$viewPath
}
(looked
at
{
$file
}
)"
);
throw
new
\RuntimeException
(
"View not found:
{
$viewPath
}
(looked
in:
{
$file
}
)"
);
}
}
$data
[
'app'
]
=
App
::
getInstance
();
// Render the view (which may call layout() and section())
$
c
ontent
=
$this
->
renderFile
(
$file
,
$data
);
$
viewC
ontent
=
$this
->
renderFile
(
$file
,
$data
);
if
(
$this
->
layoutPath
!==
null
)
{
// If no layout was specified, return view content directly
$layoutFile
=
$this
->
resolveViewPath
(
$this
->
layoutPath
);
if
(
$this
->
layoutName
===
null
)
{
if
(
!
file_exists
(
$layoutFile
))
{
return
$viewContent
;
throw
new
\RuntimeException
(
"Layout not found:
{
$this
->
layoutPath
}
"
);
}
$this
->
sections
[
'__content__'
]
=
$content
;
$content
=
$this
->
renderFile
(
$layoutFile
,
$data
);
$this
->
layoutPath
=
null
;
}
}
return
$content
;
// Render the layout with sections
}
$layoutFile
=
$this
->
resolvePath
(
$this
->
layoutName
);
if
(
!
file_exists
(
$layoutFile
))
{
throw
new
\RuntimeException
(
"Layout not found:
{
$this
->
layoutName
}
(looked in:
{
$layoutFile
}
)"
);
}
private
function
renderFile
(
string
$file
,
array
$data
)
:
string
// Store any non-sectioned content as 'content' if not already set
{
$trimmed
=
trim
(
$viewContent
);
extract
(
$data
);
if
(
$trimmed
!==
''
&&
!
isset
(
$this
->
sections
[
'content'
]))
{
$__template
=
$this
;
$this
->
sections
[
'content'
]
=
$viewContent
;
ob_start
();
}
require
$file
;
return
ob_get_clean
(
);
return
$this
->
renderFile
(
$layoutFile
,
$data
);
}
}
private
function
re
solveViewPath
(
string
$path
)
:
string
private
function
re
nderFile
(
string
$file
,
array
$data
=
[]
)
:
string
{
{
$
base
=
Autoloader
::
basePath
()
.
'/app/'
;
$
__template
=
$this
;
$parts
=
explode
(
'.'
,
$path
);
extract
(
$data
,
EXTR_SKIP
);
if
(
$parts
[
0
]
===
'Shared'
||
$parts
[
0
]
===
'Layout'
)
{
ob_start
();
return
$base
.
'Shared/'
.
implode
(
'/'
,
$parts
)
.
'.php'
;
try
{
require
$file
;
}
catch
(
\Throwable
$e
)
{
ob_end_clean
();
throw
$e
;
}
}
return
ob_get_clean
();
return
$base
.
'Modules/'
.
implode
(
'/'
,
$parts
)
.
'.php'
;
}
}
public
function
layout
(
string
$layoutPath
)
:
void
/**
* Called by views to specify which layout to use.
*/
public
function
layout
(
string
$name
)
:
void
{
{
$this
->
layout
Path
=
$layoutPath
;
$this
->
layout
Name
=
$name
;
}
}
/**
* Start a named section.
*/
public
function
section
(
string
$name
)
:
void
public
function
section
(
string
$name
)
:
void
{
{
$this
->
currentSection
=
$name
;
$this
->
sectionStack
[]
=
$name
;
ob_start
();
ob_start
();
}
}
/**
* End the current section.
*/
public
function
endSection
()
:
void
public
function
endSection
()
:
void
{
{
if
(
$this
->
currentSection
!==
null
)
{
if
(
empty
(
$this
->
sectionStack
))
{
$this
->
sections
[
$this
->
currentSection
]
=
ob_get_clean
();
throw
new
\RuntimeException
(
'Cannot end section — no section started.'
);
$this
->
currentSection
=
null
;
}
}
$name
=
array_pop
(
$this
->
sectionStack
);
$content
=
ob_get_clean
();
$this
->
sections
[
$name
]
=
$content
;
}
}
/**
* Output a section's content (called by layouts).
* Returns the section content or default.
*/
public
function
yield
(
string
$name
,
string
$default
=
''
)
:
string
public
function
yield
(
string
$name
,
string
$default
=
''
)
:
string
{
{
return
$this
->
sections
[
$name
]
??
$default
;
return
$this
->
sections
[
$name
]
??
$default
;
}
}
/**
* Include a partial/component.
* Supports both module paths and shared paths.
*/
public
function
include
(
string
$path
,
array
$data
=
[])
:
void
public
function
include
(
string
$path
,
array
$data
=
[])
:
void
{
{
$file
=
$this
->
resolveViewPath
(
$path
);
$file
=
$this
->
resolvePath
(
$path
);
if
(
file_exists
(
$file
))
{
if
(
!
file_exists
(
$file
))
{
$data
[
'app'
]
=
App
::
getInstance
();
echo
"<!-- Include not found:
{
$path
}
→
{
$file
}
-->"
;
$data
[
'__template'
]
=
$this
;
return
;
extract
(
$data
);
require
$file
;
}
}
// Merge parent data with include-specific data
$mergedData
=
array_merge
(
$this
->
data
,
$data
);
$__template
=
$this
;
extract
(
$mergedData
,
EXTR_SKIP
);
require
$file
;
}
}
/**
* Include only if the file exists.
*/
public
function
includeIf
(
string
$path
,
array
$data
=
[])
:
void
public
function
includeIf
(
string
$path
,
array
$data
=
[])
:
void
{
{
$file
=
$this
->
resolve
View
Path
(
$path
);
$file
=
$this
->
resolvePath
(
$path
);
if
(
file_exists
(
$file
))
{
if
(
file_exists
(
$file
))
{
$this
->
include
(
$path
,
$data
);
$this
->
include
(
$path
,
$data
);
}
}
}
}
public
function
push
(
string
$name
)
:
void
/**
{
* Output data as JSON for embedding in script tags.
$this
->
currentStack
=
$name
;
*/
ob_start
();
public
function
json
(
$data
)
:
string
}
public
function
endPush
()
:
void
{
if
(
$this
->
currentStack
!==
null
)
{
$content
=
ob_get_clean
();
if
(
!
isset
(
$this
->
stacks
[
$this
->
currentStack
]))
{
$this
->
stacks
[
$this
->
currentStack
]
=
''
;
}
$this
->
stacks
[
$this
->
currentStack
]
.=
$content
;
$this
->
currentStack
=
null
;
}
}
public
function
stack
(
string
$name
)
:
string
{
{
return
$this
->
stacks
[
$name
]
??
''
;
return
htmlspecialchars
(
json_encode
(
$data
,
JSON_UNESCAPED_UNICODE
|
JSON_HEX_TAG
|
JSON_HEX_APOS
|
JSON_HEX_QUOT
),
ENT_QUOTES
,
'UTF-8'
);
}
}
/**
* Escape HTML.
*/
public
function
e
(
?
string
$value
)
:
string
public
function
e
(
?
string
$value
)
:
string
{
{
return
htmlspecialchars
(
$value
??
''
,
ENT_QUOTES
,
'UTF-8'
);
return
htmlspecialchars
(
$value
??
''
,
ENT_QUOTES
,
'UTF-8'
);
}
}
public
function
json
(
$data
)
:
string
/**
* Resolve a dot-notation path to an actual file path.
*
* Resolution order:
* 1. "Layout.main" → app/Shared/Layout/main.php
* 2. "Shared.Components.sidebar" → app/Shared/Components/sidebar.php
* 3. "Members.Views.index" → app/Modules/Members/Views/index.php
* 4. "Members.Views._partials.family-tab" → app/Modules/Members/Views/_partials/family-tab.php
*/
private
function
resolvePath
(
string
$dotPath
)
:
string
{
{
return
htmlspecialchars
(
$parts
=
explode
(
'.'
,
$dotPath
);
json_encode
(
$data
,
JSON_UNESCAPED_UNICODE
|
JSON_HEX_TAG
|
JSON_HEX_AMP
|
JSON_HEX_APOS
|
JSON_HEX_QUOT
),
$relativePath
=
implode
(
DIRECTORY_SEPARATOR
,
$parts
)
.
'.php'
;
ENT_QUOTES
,
'UTF-8'
// Check 1: Does it start with "Layout" → Shared/Layout
);
if
(
$parts
[
0
]
===
'Layout'
)
{
$file
=
$this
->
basePath
.
'/app/Shared/'
.
$relativePath
;
if
(
file_exists
(
$file
))
{
return
$file
;
}
}
// Check 2: Does it start with "Shared" → app/Shared/
if
(
$parts
[
0
]
===
'Shared'
)
{
$file
=
$this
->
basePath
.
'/app/'
.
$relativePath
;
if
(
file_exists
(
$file
))
{
return
$file
;
}
}
// Check 3: Module path → app/Modules/
$file
=
$this
->
basePath
.
'/app/Modules/'
.
$relativePath
;
if
(
file_exists
(
$file
))
{
return
$file
;
}
// Check 4: Direct path from app/
$file
=
$this
->
basePath
.
'/app/'
.
$relativePath
;
if
(
file_exists
(
$file
))
{
return
$file
;
}
// Check 5: Try from base path
$file
=
$this
->
basePath
.
'/'
.
$relativePath
;
if
(
file_exists
(
$file
))
{
return
$file
;
}
// Return the most likely path for error message
return
$this
->
basePath
.
'/app/Modules/'
.
$relativePath
;
}
}
}
}
\ No newline at end of file
app/Shared/Components/alerts.php
View file @
2e052b1f
<?php
<?php
$session
=
App
::
getInstance
()
->
session
();
/**
* Flash alert messages component.
*/
$session
=
\App\Core\App
::
getInstance
()
->
session
();
$alerts
=
$session
->
getAlerts
();
$alerts
=
$session
->
getAlerts
();
if
(
empty
(
$alerts
))
{
return
;
}
?>
?>
<?php
if
(
!
empty
(
$alerts
))
:
?>
<?php
foreach
(
$alerts
as
$alert
)
:
?>
<div
class=
"alerts-wrapper"
>
<?php
<?php
foreach
(
$alerts
as
$alert
)
:
?>
$type
=
$alert
[
'type'
]
??
'info'
;
<div
class=
"alert alert-
<?=
e
(
$alert
[
'type'
]
??
'info'
)
?>
"
data-auto-dismiss=
"5000"
>
$message
=
$alert
[
'message'
]
??
''
;
<span
class=
"alert-message"
>
<?=
e
(
$alert
[
'message'
]
??
''
)
?>
</span>
$bgColor
=
match
(
$type
)
{
<button
class=
"alert-close"
onclick=
"this.parentElement.remove()"
>
✕
</button>
'success'
=>
'#F0FDF4'
,
</div>
'error'
=>
'#FEF2F2'
,
<?php
endforeach
;
?>
'warning'
=>
'#FFF7ED'
,
</div>
'info'
=>
'#EFF6FF'
,
<?php
endif
;
?>
default
=>
'#F9FAFB'
,
\ No newline at end of file
};
$textColor
=
match
(
$type
)
{
'success'
=>
'#059669'
,
'error'
=>
'#DC2626'
,
'warning'
=>
'#D97706'
,
'info'
=>
'#0284C7'
,
default
=>
'#6B7280'
,
};
$borderColor
=
match
(
$type
)
{
'success'
=>
'#BBF7D0'
,
'error'
=>
'#FECACA'
,
'warning'
=>
'#FED7AA'
,
'info'
=>
'#BFDBFE'
,
default
=>
'#E5E7EB'
,
};
$icon
=
match
(
$type
)
{
'success'
=>
'✓'
,
'error'
=>
'✗'
,
'warning'
=>
'⚠'
,
'info'
=>
'ℹ'
,
default
=>
''
,
};
?>
<div
class=
"alert alert-
<?=
$type
?>
"
style=
"background:
<?=
$bgColor
?>
;color:
<?=
$textColor
?>
;border:1px solid
<?=
$borderColor
?>
;padding:12px 20px;border-radius:8px;margin:0 25px 15px;font-size:14px;display:flex;justify-content:space-between;align-items:center;"
>
<span>
<?=
$icon
?>
<?=
e
(
$message
)
?>
</span>
<button
onclick=
"this.parentElement.remove()"
style=
"background:none;border:none;cursor:pointer;font-size:18px;color:
<?=
$textColor
?>
;opacity:0.6;padding:0 5px;"
>
×
</button>
</div>
<?php
endforeach
;
?>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment