This commit is contained in:
2025-05-27 14:28:47 +07:00
parent 170122ad32
commit 4fb79660b2
144 changed files with 5973 additions and 0 deletions

67
README.md Normal file
View File

@@ -0,0 +1,67 @@
<h1>Hướng dẫn</h1>
<p>Link thiết kế: <a href="https://www.figma.com/file/5Km584w3tlnwxOltV5KAjh/281123_HURA8?node-id=328%3A1204&mode=dev" target="_blank"> <strong>Giao diện Admin</strong> </a></p>
<p>Repo: <a href="https://repo.hurasoft.com/tieptk/bestpc_vn" target="_blank">https://repo.hurasoft.com/tieptk/bestpc_vn</a></p>
<p>Theo dõi tiến độ: <a href="https://docs.google.com/spreadsheets/d/1Po3ANsG00pm_Y3dnrwuV81cidTCCqepYmR3yPDlIq6c/edit#gid=0" target="_blank">https://docs.google.com/spreadsheets/d/1Po3ANsG00pm_Y3dnrwuV81cidTCCqepYmR3yPDlIq6c/edit#gid=0</a></p>
<h2>Cài đặt hệ thống</h2>
<p>Test và làm việc chính tại web: <a href="http://local.bestpc_vn/"> http://local.bestpc_vn/</a> </p>
<ul>
<li>Tải phần mềm XAMPP tại <a href="https://www.apachefriends.org/download.html" target="_blank">https://www.apachefriends.org/download.html</a> để chạy PHP</li>
<li>Chỉnh file hosts trong máy tính C:\Windows\System32\drivers\etc\hosts:
<pre><code>
127.0.0.1 local.bestpc_vn
</code></pre>
</li>
<li>
Cài đặt ../xampp/apache/conf/extra/httpd-vhosts.conf của apache trong XAMPP
<pre><code>
&lt;VirtualHost *:80&gt;
DocumentRoot "/thuc-muc-check-out/bestpc_vn"
ServerName local.bestpc_vn
&lt;Directory "/thuc-muc-check-out/bestpc_vn/"&gt;
Require all granted
&lt;/Directory&gt;
&lt;/VirtualHost&gt;
</code></pre>
</li>
<li>
Cài đặt ../xampp/apache/conf/httpd.conf của apache trong XAMPP
<pre><code>
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
# AllowOverride FileInfo AuthConfig Limit
AllowOverride All
</code></pre>
</li>
</ul>
<h2>Cấu trúc thư mục</h2>
<ul>
<li>/template: các file template html chia theo module/view</li>
<li>/pages: cung cấp dữ liệu cho template và hiển thị dữ liệu trên template qua code Liquid <a href="https://shopify.github.io/liquid/" target="_blank">https://shopify.github.io/liquid/</a></li>
<li>/public_html: Code public</li>
<li>/public_html/assets: lưu các file ảnh/css/js dùng cho giao diện</li>
<li>/package: thư viện code PHP hỗ trợ</li>
<li>/src: các code PHP hỗ trợ</li>
</ul>
<h2>Cài đặt Composer (dùng tải package của PHP)</h2>
<p>Xem hướng dẫn: <a href="https://getcomposer.org/doc/00-intro.md#installation-windows" target="_blank">https://getcomposer.org/doc/00-intro.md#installation-windows</a> </p>
<p>Sau khi cài đặt xong. Mở cmd của Windows và thao tác lệnh sau để cài các thư viện code PHP cần cho dự án này.</p>
<pre><code>
> cd /thuc-muc-check-out/bestpc_vn/package
> composer i
</code></pre>

9
config/constant.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
const IMAGE_FILE_SEPARATOR = "-";
define("CURRENT_TIME", time());
const STATIC_DOMAIN = "";
const ENABLE_DB_DEBUG = true;
const LANGUAGE = 'vi';
const IS_DEFAULT_LANGUAGE = true;

11
config/routing.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
return [
"/buildpc" => [
'module' => 'buildpc',
'view' => 'home',
'view_id'=> 0,
'query' => [],
'url' => '/buildpc',
],
];

8
package/composer.json Normal file
View File

@@ -0,0 +1,8 @@
{
"require": {
"liquid/liquid": "1.4.32",
"ext-json": "*",
"ext-mysqli": "*",
"ext-zip": "*"
}
}

7
public_html/.htaccess Normal file
View File

@@ -0,0 +1,7 @@
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/index.php
# prevent rewrite non-existent files
RewriteCond %{REQUEST_URI} !\.(jpg|png|gif|css|js|php|tiff|webp|jpeg|ico)$
RewriteRule ^(.*)$ /index.php [QSA,L]

13
public_html/_shared.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
define("ROOT_DIR", dirname(__DIR__));
const SRC_DIR = ROOT_DIR . '/src';
const CONFIG_DIR = ROOT_DIR . '/config';
include CONFIG_DIR."/constant.php";
include SRC_DIR."/inc/common.php";
include SRC_DIR."/inc/fun.db.php";
// start autoload
init_autoload();

7
public_html/ajax.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
include __DIR__."/_shared.php";

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,41 @@
@font-face {
font-family: "Shopee";
font-display: swap;
src: url(../font//FVHShopeeText-Bold.otf);
}
@font-face {
font-family: "Shopee Bold";
font-display: swap;
src: url(../font/ShopeeDisplay-Bold.ttf);
}
@font-face {
font-family: "Shopee Regular";
font-display: swap;
src: url(../font/ShopeeDisplay-Regular.ttf);
}
@font-face {
font-family: "Shopee Medium";
font-display: swap;
src: url(../font/ShopeeDisplay-Medium.ttf);
}
@font-face {
font-family: "Shopee Light";
font-display: swap;
src: url(../font/ShopeeDisplay-Light.ttf);
}
@font-face {
font-family: "Shopee ExtraBold";
font-display: swap;
src: url(../font/ShopeeDisplay-ExtraBold.ttf);
}
@font-face {
font-family: "Shopee Black";
font-display: swap;
src: url(../font/ShopeeDisplay-Black.ttf);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

15
public_html/index.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
use Hura\App;
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
const TEMPLATE_ASSET = '/assets';
include __DIR__."/_shared.php";
$objApp = new App();
$objApp->start();

211
src/Hura/App.php Normal file
View File

@@ -0,0 +1,211 @@
<?php
namespace Hura;
use Liquid\Liquid;
use Liquid\Template as LiquidTemplate;
class App
{
protected $tpl_path = ROOT_DIR . "/template";
protected $current_route_info = [
"module" => 'home',
"view" => 'home',
"url" => '/admin/product'
];
protected $data = [];
public function __construct()
{
}
// start the app
public function start() {
$this->getRouter();
$this->getData();
echo $this->renderModule();
}
protected function getRouter() {
/*$route = [
"module" => (isset($_REQUEST['module'])) ? $_REQUEST['module'] : 'home',
"view" => (isset($_REQUEST['view'])) ? $_REQUEST['view'] : 'home',
];*/
$objRouter = new Router();
$this->current_route_info = $objRouter->getRouting();
}
protected function getData() {
$module_file = $this->getModuleFile();
if(!file_exists($module_file)) {
// print_r($this->current_route_info);
die('Page '. $module_file .' not found!');
}
$data = include_once $module_file;
$global_data = [
"module" => $this->current_route_info['module'],
"view" => $this->current_route_info['view'],
"url" => $this->current_route_info['url'],
];
$this->data = array(
'global' => $global_data,
// module-specific data, just print {{ page }} to see all available data for the current page!!!
'page' => (is_array($data)) ? $data : [],
);
}
protected function getModuleFile(): string
{
return SRC_DIR . DIRECTORY_SEPARATOR . join(DIRECTORY_SEPARATOR, [
"pages",
$this->current_route_info["module"],
str_replace("-", "_", $this->current_route_info["view"]).".php"
]) ;
}
protected function renderModule() {
if(!$this->current_route_info['module'] || !$this->current_route_info['view']) {
die("Module not exist");
}
$template_file_path = $this->tpl_path ."/". $this->current_route_info['module'];
$template_file_name = str_replace("-", '_', $this->current_route_info['view']).".html";
$template_file_full_path = $template_file_path."/".$template_file_name;
//check exist
if(!@file_exists( $template_file_full_path)) {
// attempt to auto create first
// todo: this MUST BE TURNED OFF IN PRODUCTION, else many files will be created unintentionally
$module_file = $this->getModuleFile();
// only create if module file exist
if(file_exists($module_file) && !$this->autoCreateTplFile( $template_file_path, $template_file_name )) {
die("Please manually create template file at: ". $template_file_full_path);
}
}
$theme_file_path = $this->tpl_path ."/theme.html";
if( ! @file_exists( $theme_file_path)) {
die("Theme not exist (please create): " . $theme_file_path);
}
$theme_content = @file_get_contents( $theme_file_path );
$module_content = @file_get_contents( $template_file_full_path );
$page_content_to_parse = preg_replace([
"/{{(\s+)?page_content(\s+)?}}/"
], [
$module_content,
] , $theme_content );
return $this->parse(
$page_content_to_parse,
$template_file_path
);
}
protected function autoCreateTplFile($file_path, $file_name) : bool {
// create dir if not exist
if(!file_exists($file_path)) {
if(!mkdir($file_path, 0755, true)) {
return false;
}
if(!file_exists($file_path)) {
return false;
}
}
//create file
$file_full_path = $file_path . "/". $file_name;
@file_put_contents($file_full_path, $file_full_path);
return file_exists($file_full_path);
}
/*
* 2 ways to render a html template
* 1. Use $html_to_parse, which requires no dependencies
* Example:
* Template::parse(null, 'Age = {{age}}', ['age' => 21], '');
*
* 2. Use $template_file_path, which requires dependency $path
* Template::parse(Template::$setting_template_path, null, ['age' => 21], 'email/test');
* */
protected function parse($html_to_parse = null, $template_file_path = '') {
if(!$html_to_parse && !$template_file_path) {
return 'Nothing to parse';
}
//output to html
Liquid::set('INCLUDE_SUFFIX', 'html');
Liquid::set('INCLUDE_PREFIX', '');
//Liquid::set('INCLUDE_ALLOW_EXT', true);
Liquid::set('ESCAPE_BY_DEFAULT', false);
$enable_cache = false; // default = true, turn this on-off to disable cache while working on local mode
//$enable_cache = true;
//catch exception and print friendly notice
try {
$objLiquidTemplate = new LiquidTemplate( $this->tpl_path );
$objLiquidTemplate->registerFilter( TemplateFilter::class );
if($enable_cache) {
/*$objLiquidTemplate->setCache(new File([
'cache_dir' => self::$cache_dir
]));*/
}
if($html_to_parse) {
$objLiquidTemplate->parse($html_to_parse);
}elseif ($template_file_path) {
$objLiquidTemplate->parseFile($template_file_path);
}
return $objLiquidTemplate->render($this->data);
} catch (\Exception $e) {
$result = [];
do {
//printf("%s:%d %s (%d) [%s]\n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e));
//echo $e->getTraceAsString();
//$code = $e->getTrace()[0]['args'][0];
//if(is_array($code)) $code = serialize($code);
$result[] = sprintf(
"
Lỗi code trong file template html: <br />
- Chi tiết lỗi: %s<br />
- File template: %s<br />
- Hướng dẫn xử lý: Tách từng phần html để kiểm tra và nhấn F5 mỗi lần. Nếu không xuất hiện thông báo này nghĩa là phần đó không tạo lỗi
",
$e->getMessage(),
substr($template_file_path, strrpos($template_file_path, DIRECTORY_SEPARATOR) + 1 ),
//static::$cache_dir
);
} while($e = $e->getPrevious());
return join(" - ", $result);
}
}
}

78
src/Hura/Router.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
namespace Hura;
class Router {
private array $path_config = [];
public function __construct() {
$path_config_file = CONFIG_DIR . '/routing.php';
$this->path_config = require $path_config_file;
}
// url: asdas.php?para1=value1
public function getRouting(): array
{
$parsed = Url::parse($_SERVER['REQUEST_URI']); //abc/product?param1=12&param2=value2
//print_r($parsed);
// home
if($parsed['path'] == '/') {
return [
'module' => preg_replace("/[^a-z0-9_\-]/i","", getRequest('module', 'home')),
'view' => preg_replace("/[^a-z0-9_\-]/i","", getRequest('view', 'home')),
'view_id'=> 0,
'query' => $parsed['query'],
'url' => $_SERVER['REQUEST_URI'],
];
}
// check match pattern in $this->path_config
foreach ($this->path_config as $_config => $_route ) {
if(preg_match("{^".$_config."$}", $parsed['path'], $match )) {
if(isset($_route['query']) && is_array($_route['query'])) {
$_route['query'] = array_merge($_route['query'], $parsed['query']);
}else{
$_route['query'] = $parsed['query'];
}
return array_merge([
'path' => $parsed['path'],
'match' => $match,
], $_route);
}
}
// check database
// else error
return [
'module' => "error" ,
'view' => "error" ,
'view_id' => "not_found",
'query' => $parsed['query'],
'url' => $_SERVER['REQUEST_URI'],
];
// auto parse path base on convention: admin/module/view/view_id
/* $ele = explode("/", $parsed['path']);
$module = $ele[2] ?? 'home';
$view = isset($ele[3]) ? $ele[3] : getRequest('view', 'home');
$view_id = isset($ele[4]) ? $ele[4] : getRequest('id', 'view_id');
// else error
return [
'module' => preg_replace("/[^a-z0-9_\-]/i","", $module ) ,
'view' => preg_replace("/[^a-z0-9_\-]/i","", $view ) ,
'view_id' => preg_replace("/[^a-z0-9_]/i","", $view_id ),
'query' => $parsed['query'],
'url' => $_SERVER['REQUEST_URI'],
];*/
}
}

256
src/Hura/TemplateFilter.php Normal file
View File

@@ -0,0 +1,256 @@
<?php
namespace Hura;
/**
* Before attempting to make new filter, see built-in filters: https://shopify.github.io/liquid/
*/
class TemplateFilter
{
/**
*
* @param array $array
*
* @return string
*/
public static function to_json(array $array) {
return \json_encode($array);
}
/**
* create array of ['key' => '', 'value' => ] from [key1 => value1, key2=>value2, ...]
*
* @param array $key_values [key1 => value1, key2=>value2]
*
* @return array [['key' => 'key1', 'value' => value1], ['key' => 'key2', 'value' => value2]]
*/
public static function to_array(array $key_values) {
$result = [];
foreach ($key_values as $key => $value) {
$result[] = [
'key' => $key,
'value' => $value,
];
}
return $result;
}
/**
* split a s by line to create array
*
* @param string $txt
*
* @return array
*/
public static function get_line($txt) {
if(is_array($txt)) {
return $txt;
}
$txt = trim($txt);
if( ! $txt ) return [];
return preg_split("/\n/", $txt);
}
/**
* Implement strlen
*
* @param string $str
*
* @return int
*/
public static function length($str) {
return strlen(trim($str));
}
/**
* Make number easier to read: 1000 -> 1.000
*
* @param string $number
*
* @return string
*/
public static function format_number($number) {
if(!$number) return '';
$number = floatval($number);
$number = number_format($number, 0, ",", "."); //Vietnamese format with decimals by a coma
return $number;
}
public static function format_price($p_price, $currency = ''){
if(!$p_price) return '';
if(!$currency) $currency = (defined("DEFAULT_CURRENCY")) ? DEFAULT_CURRENCY : "vnd";
//if(is_string($p_price)) return 0;
if($currency == 'usd') {
return number_format($p_price,2,".",",");
}else {
return number_format($p_price,0,",",".");
}
}
/**
*
* Description: get the shop's full asset url for template's images/js/css
*
* //Returns the URL of a file in the "assets" folder of a theme.
// {{ 'shop.css' | asset_url : 'arg1', 'arg2' ...}} -> //cdn.shopify.com/s/files/1/0087/0462/t/394/assets/shop.css?28253
*
* @param string $file_name
*
* @return string
*/
public static function asset_url($file_name = '')
{
if( !$file_name ) return '';
$file_ext = strtolower(strrchr($file_name, "."));
// script tags
if(in_array($file_ext, ['.js', '.css'])) return TEMPLATE_ASSET . "/script/" . $file_name;
// default image
return TEMPLATE_ASSET . "/images/" . $file_name;
}
/**
*
* Description: construct a full html tag for images/js/css file
*
* @param string $file_path domain.com/static/style.css?v=3.1.1
*
* @return string
*/
public static function script_tag($file_path) {
if( ! $file_path ) return '';
//check for ?
if(strpos($file_path, "?") !== false) {
$file_ext = str_replace(strrchr($file_path, "?"), "", $file_path);
$file_ext = strtolower(strrchr($file_ext, "."));
} else {
$file_ext = strtolower(strrchr($file_path, "."));
}
$tag_config = [
".css" => "<link rel=\"stylesheet\" href=\"".$file_path."\" type=\"text/css\" />",
".js" => "<script src=\"".$file_path."\"></script>",
".jpg" => "<img src=\"".$file_path."\" alt=\"n\"/>",
".jpeg" => "<img src=\"".$file_path."\" alt=\"\"/>",
".gif" => "<img src=\"".$file_path."\" alt=\"\"/>",
".png" => "<img src=\"".$file_path."\" alt=\"\"/>",
];
return (isset($tag_config[$file_ext])) ? $tag_config[$file_ext] : '';
}
/**
* {{ product_info.main_image | img_url: '300x300' }} => https://cdn.shopify.com/s/files/1/1183/1048/products/boat-shoes_300x300.jpeg?1459175177
* @param string $full_path
* @param string $modifier
* $modifier:
* - must be in format: NumberxNumber or Numberx where Number must within 10 -> 9999
* - or be one of these: small | medium | large
* @return string
*/
public static function img_url($full_path, $modifier)
{
$clean_modifier = ($modifier) ? trim($modifier) : "";
// verify $modifier
// must be in format: NumberxNumber or Numberx where Number must within 10 -> 9999
if($clean_modifier
&& !preg_match("/^[0-9]{2,4}x([0-9]{2,4})?$/i", $clean_modifier)
&& !in_array($clean_modifier, ["small", "medium", "large"])
) {
$clean_modifier = "";
}
// return if no valid modifier
if( ! $clean_modifier ) {
return $full_path;
}
$last_dot_position = strrpos($full_path, ".");
if( ! $last_dot_position ) return $full_path . $clean_modifier;
return join("", [
substr($full_path, 0, $last_dot_position),
"_",
$clean_modifier,
substr($full_path, $last_dot_position)
]);
}
/**
* //Returns the URL of a file in the Files page of the admin.
//{{ 'size-chart.pdf' | file_url }} -> //cdn.shopify.com/s/files/1/0087/0462/files/size-chart.pdf?28261
*
* @param string $input
* @param string $string
*
* @return string
*/
public static function file_url($input, $string)
{
return strtoupper($input) . " = " . $string;
}
/**
* //Returns the asset URL of an image in the Files page of the admin. file_img_url accepts an image size parameter.
//{{ 'logo.png' | file_img_url: '1024x768' }} -> //cdn.shopify.com/s/files/1/0246/0527/files/logo_1024x768.png?42
*
* @param string $input
* @param string $string
*
* @return string
*/
public static function file_img_url($input, $string)
{
return '';
}
/**
* Show all content of a variable, useful for template development
*
* @param string
*
* @return string
*/
public static function print_r($input)
{
@ob_start();
print_r($input);
$content = ob_get_contents();
@ob_end_clean();
return join("\r", ['<!-- print_r debug content: ', $content, '-->']) ;
}
/**
* Show all content of a variable, useful for template development
*
* @param string
*
* @return string
*/
public static function show_var($input)
{
@ob_start();
print_r($input);
$content = ob_get_contents();
@ob_end_clean();
return join("\r", ['<textarea cols="80" rows="20">', $content, '</textarea>']) ;
}
}

47
src/Hura/Url.php Normal file
View File

@@ -0,0 +1,47 @@
<?php
namespace Hura;
class Url
{
public static function parse($url) {
$data = parse_url($url);
$default = [
'scheme' => '',
'host' => '',
'port' => '',
'user' => '',
'pass' => '',
'path' => '',
'query' => [],
'fragment' => '',
];
foreach ($data as $key => $value) {
if(isset($default[$key])) {
$default[$key] = ($key == 'query') ? self::parsedQuery($value) : $value;
}
}
return $default;
}
public static function parsedQuery($query = '') {
if(!$query) return [];
$result = [];
$parts = explode("&", $query);
foreach ($parts as $part) {
$el = explode("=", $part);
if(sizeof($el) != 2) continue;
$cleaned_key = preg_replace("/[^a-z0-9_\-\.]/i", '', $el[0]);
$cleaned_value = preg_replace("/[^a-z0-9_\.\-;&]/i", '', $el[1]);
$result[$cleaned_key] = $cleaned_value;
}
return $result;
}
}

45
src/inc/common.php Normal file
View File

@@ -0,0 +1,45 @@
<?php
function debug_var($input) {
@ob_start();
print_r($input);
$content = ob_get_contents();
@ob_end_clean();
echo join("\r", ['<textarea cols="80" rows="20">', $content, '</textarea>']) ;
}
function init_autoload(){
$classLoader = require_once ROOT_DIR . '/package/vendor/autoload.php';
$classLoader->add("Hura", ROOT_DIR . '/src' );
return $classLoader;
}
//get current paging id
function getPageId(){
return getRequestInt('page', 1);
}
function getPageSize($default=10){
return getRequestInt('pageSize', $default);
}
//Function to get the post value in submit
function getPost($var, $default="", $encode = false, $keep_tag=""){
return isset($_POST[$var]) ? $_POST[$var] : $default;
}
//Function to get the INTERGER request value of a variable
function getRequestInt($var, $min_value = 0){
$request = isset($_REQUEST[$var]) ? (int) $_REQUEST[$var] : (int) $min_value;
$request = ($request >= $min_value ) ? $request : $min_value; //if user tampers request parameter
return $request;
}
//Function to get the request value of a variable
function getRequest($var, $default=""){
return $_REQUEST[$var] ?? $default;
}

16
src/inc/fun.db.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
use Hura\Database\ConnectDB;
use Hura\Database\iConnectDB;
function create_bind_sql_parameter_from_value_list(array $value_list = [], $data_type = 'int') {
$parameterized_ids = join(",", array_map(function (){ return '?'; }, $value_list));
$bind_types = array_map(function () use ($data_type){ return ($data_type == 'int') ? 'd' : 's'; }, $value_list);
return [$parameterized_ids, $bind_types];
}
function get_db($db_id ='', $debug=false) : iConnectDB {
return ConnectDB::getInstance($db_id, $debug);
}

View File

@@ -0,0 +1,5 @@
<?php
return [
];

13
src/pages/home/home.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
return [
"tom_tat" => [
[
'id' => 1,
'title' => 'ĐƠN HÀNG MỚI',
'main_stat' => '1000000',
'time' => ' 24/11/2023 ',
],
],
];

View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1,108 @@
<?php
use Hura\Components\Product\AdminController\AProductCategoryController;
$objAProductCategoryController = new AProductCategoryController();
$category_collection = $objAProductCategoryController->getAllParent();
return [
'category_list' => get_category_list(0, getRequest("id"), $level=1, $prefix="", $category_collection )
];
function get_category_list($parentId=0, $currentCat="",$level=1, $prefix="", $category_collection = array()){
$categoryTree = "";
$extra_space = "";
for($i = 1; $i < $level; $i++){
$extra_space .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
}
$stt = 0;
if(isset($category_collection[$parentId])) {
foreach($category_collection[$parentId] as $index => $cat_info){
$cat_id = $cat_info['id'];
$stt ++;
$imgUrl = (strlen($cat_info["thumbnail"]) > 2) ? " <img src=\"".$cat_info["thumbnail"]."\" style=\"max-width:30px; max-height:30px;\" />" : "";
if($cat_info["status"]) $status = "<a href=\"javascript:update_status(".$cat_id.",'off')\" class='w-[30px] h-[30px] border-[1px] border-[#9E9E9E] rounded-[4px] text-center leading-[30px] flex items-center justify-center mr-[5px]'><i class='fa-regular fa-eye-slash text-[#9E9E9E]'></i></a>";
else $status = "<a href=\"javascript:update_status(".$cat_id.",'on')\" class='w-[30px] h-[30px] border-[1px] border-[#0041E8] rounded-[4px] text-center leading-[30px] flex items-center justify-center mr-[5px]'><i class='fa-regular fa-eye text-[#0041E8]'></i></a>";
$edit_link ="/admin/product/category-form?id=".$cat_id;
$hide_this = ($parentId > 0) ? "style='display: none;'" : '';
$show_category_name = $cat_info["title"];
if(!IS_DEFAULT_LANGUAGE && isset($cat_info["not_translated"]) && $cat_info["not_translated"]) {
$show_category_name = "<span style='color: red'>[Chưa dịch]</span> ".$cat_info["title"];
}
if($cat_info['is_parent']) {
$show_category_name = "<a href=\"javascript:;\" onclick=\"RowExpand.open_child('parent_".$cat_id."')\">".$show_category_name."</a>";
}
$categoryTree .= "
<tr id='row_".$cat_id."' class='parent_".$parentId." row' ". $hide_this ."
onmouseover=\"this.className='row-hover parent_".$parentId."'\" onmouseout=\"this.className='parent_".$parentId."'\">
<td>
<a name='cat_".$cat_id."'></a>
". $extra_space . $prefix . $stt.". ". $show_category_name . $imgUrl."
</td>
<td>
<a href='".$cat_info['request_path']."' title='Mở tại website' target='_blank'>Xem trang</a>
</td>
<td>".$cat_id."</td>
<td class='whitespace-nowrap'>413787</td>
<td><a href='/admin/product?category=".$cat_id."'>1292</a></td>
<td>
<input type=text id=order_".$cat_id." value='".$cat_info["ordering"]."' size=2 onchange=\"update_order(".$cat_id.",this.value)\" />
<span class='status-ordering-".$cat_id."'></span>
</td>
<td class='whitespace-nowrap'>
SP + Danh mục con
</td>
";
if(IS_DEFAULT_LANGUAGE) {
$categoryTree .= "
<td>
<a href='/admin/product/category-attribute?id=".$cat_id."&popup=1' class='pop-up'>Tổng</a> (".$cat_info['attribute_count'].")
</td>
<td>
<div class='list-btn flex items-center'>
<a href=\"".$edit_link."\" class='w-[32px] h-[32px] border-[1px] border-[#0041E8] rounded-[4px] text-center leading-[30px] flex items-center justify-center mr-[5px]'><i class='icons icon-edit'></i></a>
<a class='w-[32px] h-[32px] border-[1px] border-[#0041E8] rounded-[4px] text-center leading-[30px] flex items-center justify-center mr-[5px]' href='javascript:set_category_feature(.$cat_id.,'off')'><i class='icons icon-feature'></i></a>
<span id=status-".$cat_id.">".$status."</span>
<span class='status-delete-".$cat_id."'><a href=\"javascript:deleteThis(".$cat_id.")\" class='w-[32px] h-[32px] border-[1px] border-[#9E9E9E] rounded-[4px] text-center leading-[30px] flex items-center justify-center mr-[5px]'><i class='icons icon-delete'></i></a></span>
</div>
</td>
";
}else{
$categoryTree .= "
<td>
<a href=\"".$edit_link."\"><i class='icons icon-edit'></i></a>
</td>
";
}
$categoryTree .= "
</tr>
";
if($cat_info["is_parent"]) $categoryTree .= get_category_list($cat_id, $currentCat, $level + 1, $prefix . $stt.".", $category_collection);
}
}
return $categoryTree;
}

View File

@@ -0,0 +1,18 @@
<?php
use Hura\Components\Product\AdminController\AProductCategoryController;
$objAProductCategoryController = new AProductCategoryController();
$id = (int) getRequest("id");
$item_info = ($id > 0) ? $objAProductCategoryController->getFullInfo($id) : null;
if(!$item_info) $item_info = $objAProductCategoryController->getEmptyInfo([]);
return [
'item_info' => $item_info,
'categoryDropBox' => $objAProductCategoryController->getDropBox( $item_info['parent_id'], 0, 1),
'update_status' => getRequest("us"),
];

View File

@@ -0,0 +1 @@
<?php

Some files were not shown because too many files have changed in this diff Show More