<?php
 namespace TCMS\Gen;
 require_once "env-function.php";
 class TCMSGenModule {
 public function createModule($options) {
 if(isset($options['help'])) {
 $this->showHelpCreateModule();
 return true;
 }
 $moduleName = $this->formatModuleName($options);
 if(!$moduleName) {
 showLogError("Vui lòng nhập tên module.");
 showLogInfo("Nhập --help để xem hướng dẫn tạo module.");
 return false;
 }
 if(!isset($options['area'])) {
 showLogError("Vui lòng truyền area cho module cần tạo.");
 showLogInfo("Nhập --help để xem hướng dẫn tạo module.");
 return false;
 }
 $_appId = readAppId();
 $appConfig = include(ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $_appId . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'app.php');
 if(empty($appConfig['areas'][$options['area']])) {
 showLogError("area ". $options['area'] ." không tồn tại");
 return;
 }
 $namespaceName = $this->getNamespace($options, $moduleName);
 if(!$namespaceName) {
 showLogError("Không tìm thấy namespace của module");
 return false;
 }
 $areaNamespace = '';
 if($options['area'] != '*') {
 $areaNamespace = '\\' . $this->formatAppNamespace($options['area']);
 }
 $isAPI = $options['area'] == 'api';
 $isLayout = isset($options['layout']);
 $controllerName = $this->getController($options);
 if(!$controllerName) {
 showLogError("Không tìm thấy controller của module");
 return false;
 }
 if($isLayout) {
 $controllerName = 'LayoutController';
 }
 $appNameSpace = null;
 $isPrivate = false;
 if(isset($options['private'])) {
 $appId = $_appId;
 $appNameSpace = $this->formatAppNamespace($appId);
 $modulePath = ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $appId . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $options['area'];
 if(!file_exists($modulePath)) {
 mkdir($modulePath);
 }
 $modulePath .= DIRECTORY_SEPARATOR . $moduleName;
 $isPrivate = true;
 }
 else {
 $appId = false;
 $modulePath = ROOT_PATH . 'modules' . DIRECTORY_SEPARATOR . $options['area'];
 if(!file_exists($modulePath)) {
 mkdir($modulePath);
 }
 $modulePath .= DIRECTORY_SEPARATOR . $moduleName;
 }
 if(file_exists($modulePath)) {
 showLogError("Module $moduleName đã tồn tại");
 return false;
 }
 if(!defined('TCMS_VIEW_ENGINE')) {
 define('TCMS_VIEW_ENGINE', '.tcms');
 }
 $modelName = $this->getModel($options);
 $moduleModelName = $this->getModuleModel($options);
 $moduleNamepaceParent = $isPrivate ? ($this->formatAppNamespace($appId) . "\\Module") : "Module";
 $this->copyEmptyModule($modulePath);
 if($isAPI) {
 $viewF = $modulePath . DIRECTORY_SEPARATOR . 'views';
 if(file_exists($viewF)) {
 rmdir($viewF);
 }
 }
 $this->createModuleBootstrapFile($modulePath, $moduleName, $namespaceName, $moduleModelName, $modelName, $controllerName, $isLayout, $moduleNamepaceParent . $areaNamespace, $isAPI, $isPrivate, $appNameSpace);
 $this->createModuleController($modulePath, $controllerName, $namespaceName, $modelName, $moduleModelName, $moduleNamepaceParent . $areaNamespace, null, $isAPI,$isPrivate, $appNameSpace);
 if(!$isAPI) $this->createModuleView($modulePath, $controllerName, $moduleModelName, $modelName, $isLayout, null);
 showLogSuccess("Tạo thành công module $modulePath");
 $this->addToConfig($moduleNamepaceParent . $areaNamespace, $moduleName, $namespaceName, $isPrivate, $appId, $options['area']);
 }
 public function createController($options) {
 if(isset($options['help'])) {
 $this->showHelpCreateController();
 return true;
 }
 if(empty($options['make:controller'])) {
 showLogError("Vui lòng nhập tên controller.");
 showLogInfo("Nhập --help để xem hướng dẫn tạo controller.");
 return false;
 }
 $controllerName = $this->getController($options, 'make:controller');
 if(empty($options['module'])) {
 showLogError("Vui lòng nhập module để tạo controller.");
 showLogInfo("Nhập --help để xem hướng dẫn tạo controller.");
 return false;
 }
 $options['module'] = str_replace('/', DIRECTORY_SEPARATOR, $options['module']);
 $isAPI = strpos($options['module'], 'api' . DIRECTORY_SEPARATOR) === 0;
 $_appNameSpace = false;
 $modulePath = false;
 if(isset($options['private'])) {
 $appId = readAppId();
 $_appNameSpace = $this->formatAppNamespace($appId);
 $modulePath = ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $appId . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $options['module'] . DIRECTORY_SEPARATOR;
 }
 else {
 $appId = false;
 $modulePath = ROOT_PATH . 'modules' . DIRECTORY_SEPARATOR . $options['module'] . DIRECTORY_SEPARATOR;
 }
 if(!file_exists($modulePath)) {
 showLogError("Module " . $options['module'] . " không tồn tại.");
 return false;
 }
 $controllerPath = $modulePath . 'controllers' . DIRECTORY_SEPARATOR . $controllerName . '.php';
 if(file_exists($controllerPath)) {
 showLogError("Controller $controllerName đã tồn tại trong module " . $options['module']);
 return false;
 }
 if(!defined('TCMS_VIEW_ENGINE')) {
 define('TCMS_VIEW_ENGINE', '.tcms');
 }
 $lines = readConfigFile($modulePath . basename($options['module']) . '.php');
 $moduleNamespace = false;
 $moduleClassName = false;
 foreach($lines as $line) {
 $l = trim($line);
 if(strpos($l, "namespace") === 0) {
 $moduleNamespace = trim(substr($l, 9));
 $moduleNamespace = str_replace(";", "", $moduleNamespace);
 }
 if(strpos($l, "class") === 0 && strpos($l, "extends") !== false) {
 $endIndex = strpos($l, "extends");
 $moduleClassName = substr($l, 0, $endIndex);
 $moduleClassName = trim(substr($moduleClassName, 5));
 break;
 }
 }
 if(!$moduleNamespace) {
 showLogError("Không tìm thấy namespace trong file module " . $options['module'] . '.php');
 return false;
 }
 if(!$moduleClassName) {
 showLogError("Không tìm thấy module class name trong file module " . $options['module'] . '.php');
 return false;
 }
 $moduleNamepaceParent = $appId ? ($this->formatAppNamespace($appId) . $moduleNamespace) : $moduleNamespace;
 if(!empty($options['model']) || !empty($options['m-model'])) {
 $modelName = $this->getModel($options);
 $moduleModelName = $this->getModuleModel($options);
 $routeUrl = $this->getRouteUrl($modelName, $moduleModelName, $controllerName);
 $path = substr($modulePath, 0, strlen($modulePath) - 1);
 $this->createModuleController($path, $controllerName, $moduleClassName, $modelName, $moduleModelName, $moduleNamepaceParent, $routeUrl . '-', $isAPI, isset($options['private']), $_appNameSpace);
 if(!$isAPI) $this->createModuleView($path, $controllerName, $moduleModelName, $modelName, false, $routeUrl . '-');
 $routeContent = '';
 $routeContent .= "\n\t\tRoute::get('/$routeUrl', '$controllerName', 'index')->name('$routeUrl-index');\n";
 $routeContent .= "\t\tRoute::get('/$routeUrl/create', '$controllerName', 'create')->name('$routeUrl-create');\n";
 $routeContent .= "\t\tRoute::post('/$routeUrl/create', '$controllerName', 'postCreate');\n";
 $routeContent .= "\t\tRoute::get('/$routeUrl/update/{id}', '$controllerName', 'update')->name('$routeUrl-update');\n";
 $routeContent .= "\t\tRoute::post('/$routeUrl/update/{id}', '$controllerName', 'postUpdate');\n";
 $routeContent .= "\t\tRoute::post('/$routeUrl/delete/{id}', '$controllerName', 'postDelete')->name('$routeUrl-delete');";
 include(LIB_PATH . 'modules' . DIRECTORY_SEPARATOR . 'TCmsModule.php');
 include($modulePath . basename($options['module']) . '.php');
 $moduleCls = "\\" . $moduleNamespace . "\\" . $moduleClassName;
 $r = new \ReflectionClass($moduleCls);
 $m = $r->getMethod('registerRoutes');
 $endLineIndex = $m->getEndLine() - 1;
 $endLine = trim($lines[$endLineIndex]);
 if($endLine == '}') {
 $endLine = "\t\t$routeContent\n\t}\n";
 }
 else {
 $endLine = "\t\t" . substr($endLine, 0, strlen($endLine) - 1);
 $endLine .= "\n\t\t$routeContent\n\t}\n";
 }
 $lines[$endLineIndex] = $endLine;
 $content = '';
 foreach($lines as $line) {
 $content .= $line;
 }
 $fp2 = fopen($modulePath . basename($options['module']) . '.php', 'w');
 fwrite($fp2, $content);
 fclose($fp2);
 }
 else {
 $path = substr($modulePath, 0, strlen($modulePath) - 1);
 $this->createModuleController($path, $controllerName, $moduleClassName, null, null, $moduleNamepaceParent, null, $isAPI, isset($options['private']), $_appNameSpace);
 if(!$isAPI) $this->createModuleView($path, $controllerName, null, null, false, null);
 }
 showLogSuccess("Tạo thành công controller $controllerName cho ". $options['module']);
 }
 private function createModuleBootstrapFile($path, $moduleName, $namespaceName, $moduleModelName, $modelName, $controllerName, $isLayout, $moduleNamepaceParent, $isAPI, $isPPrivate, $appNameSpace) {
 $moduleContent = "<?php\n\n";
 $moduleContent .= "namespace $moduleNamepaceParent;\n";
 $moduleContent .= "use TCMS\Module;\n";
 $moduleContent .= "use Route;\n";
 if($moduleModelName || $modelName) {
 $moduleContent .= "use Model;\n";
 }
 $moduleContent .= "use LayoutData;\n\n";
 $moduleContent .= "class $namespaceName extends Module {\n\n";
 $moduleContent .= "\tprotected function initialize() {\n";
 if($isLayout) {
 $moduleContent .= "\t\t\$this->isLayout = true;\n";
 }
 else {
 $moduleContent .= "\n";
 }
 $moduleContent .= "\t}\n\n";
 $moduleContent .= "\t" . 'protected function registerRoutes() {' . "\n";
 if($moduleModelName || $modelName) {
 $routeUrl = $this->getRouteUrl($modelName, $moduleModelName, $controllerName);
 if($isAPI) {
 $moduleContent .= "\t\tRoute::get('/$routeUrl', '$controllerName', 'getList')->name('index');\n";
 $moduleContent .= "\t\tRoute::get('/$routeUrl/{id}', '$controllerName', 'detail')->name('find');\n";
 $moduleContent .= "\t\tRoute::post('/$routeUrl/create', '$controllerName', 'create')->name('create');\n";
 $moduleContent .= "\t\tRoute::post('/$routeUrl/update', '$controllerName', 'update')->name('update');\n";
 $moduleContent .= "\t\tRoute::post('/$routeUrl/delete/{id}', '$controllerName', 'delete')->name('delete');\n";
 }
 else {
 $moduleContent .= "\t\tRoute::get('/$routeUrl', '$controllerName', 'index')->name('index');\n";
 $moduleContent .= "\t\tRoute::get('/$routeUrl/create', '$controllerName', 'create')->name('create');\n";
 $moduleContent .= "\t\tRoute::post('/$routeUrl/create', '$controllerName', 'postCreate');\n";
 $moduleContent .= "\t\tRoute::get('/$routeUrl/update/{id}', '$controllerName', 'update')->name('update');\n";
 $moduleContent .= "\t\tRoute::post('/$routeUrl/update/{id}', '$controllerName', 'postUpdate');\n";
 $moduleContent .= "\t\tRoute::post('/$routeUrl/delete/{id}', '$controllerName', 'postDelete')->name('delete');\n";
 }
 }
 else {
 $moduleContent .= "\n";
 }
 $moduleContent .= "\t}\n\n";
 $moduleContent .= "\t" . 'public function registerComponent() {' . "\n";
 if($moduleModelName || $modelName) {
 if($moduleModelName) {
 if($isPPrivate) {
 $moduleContent .= "\t\tModel::add('$moduleModelName', \\$moduleNamepaceParent\\$moduleModelName::class, true);\n";
 }
 else {
 $moduleContent .= "\t\tModel::add('$moduleModelName', \\$moduleNamepaceParent\\$moduleModelName::class, dirname(__DIR__));\n";
 }
 }
 else {
 if($isPPrivate) {
 $moduleContent .= "\t\tModel::add('$modelName', \\$appNameSpace\\Model\\$modelName::class, true);\n";
 }
 else {
 $moduleContent .= "\t\tModel::add('$modelName');\n";
 }
 }
 }
 $moduleContent .= "\t}\n\n";
 $moduleContent .= "\t" . 'public function boot() {' . "\n\n";
 $moduleContent .= "\t}\n\n";
 $moduleContent .= "\t" . 'public function middleware(string $routeName, $auth) {' . "\n\n";
 $moduleContent .= "\t}\n\n";
 $moduleContent .= "}";
 $fp = fopen($path . DIRECTORY_SEPARATOR . $moduleName . '.php', 'w');
 fwrite($fp, $moduleContent);
 fclose($fp);
 }
 private function createModuleController($path, $controllerName, $namespaceName, $modelName, $moduleModelName, $moduleNamepaceParent, $routeUrl, $isAPI, $isPPrivate, $_appNameSpace) {
 $routeIndex = $routeUrl ? ($routeUrl . 'index') : 'index';
 $routeCreate = $routeUrl ? ($routeUrl . 'create') : 'create';
 $controllerContent = "<?php\n\n";
 $controllerContent .= "namespace $moduleNamepaceParent\\$namespaceName;\n";
 if($isAPI) $controllerContent .= "use TCMS\APIController;\n";
 else $controllerContent .= "use TCMS\Controller;\n";
 $controllerContent .= "use Model;\n";
 if($moduleModelName || $modelName) {
 if($moduleModelName) {
 $controllerContent .= "use $moduleNamepaceParent\\$moduleModelName;\n\n";
 }
 else if($modelName) {
 if($isPPrivate) {
 $controllerContent .= "use $_appNameSpace\\Model\\$modelName;\n\n";
 }
 else {
 $controllerContent .= "use Model\\$modelName;\n\n";
 }
 }
 }
 else {
 $controllerContent .= "\n";
 }
 if($isAPI) $controllerContent .= "class $controllerName extends APIController {\n\n";
 else $controllerContent .= "class $controllerName extends Controller {\n\n";
 if($isAPI) {
 if($moduleModelName || $modelName) {
 $_mName = $moduleModelName ? $moduleModelName : $modelName;
 $controllerContent .= "\tpublic function getList() {\n";
 $controllerContent .= "\t\t" . '$model = Model::load(\''. $_mName .'\');' . "\n";
 $controllerContent .= "\t\t" . '$data = $model->toList();' . "\n";
 $controllerContent .= "\t\t" . 'return $this->ok($data);' . "\n";
 $controllerContent .= "\t}\n\n";
 }
 else {
 $controllerContent .= "\tpublic function getList() {\n";
 $controllerContent .= "\t\t" . 'return $this->ok();' . "\n";
 $controllerContent .= "\t}\n\n";
 }
 }
 else {
 $controllerContent .= "\tpublic function index() {\n";
 $controllerContent .= "\t\t" . 'return view();' . "\n";
 $controllerContent .= "\t}\n\n";
 }
 if($moduleModelName || $modelName) {
 $modelName = $moduleModelName ? $moduleModelName : $modelName;
 if(!$isAPI) {
 $controllerContent .= "\tpublic function create() {\n";
 $controllerContent .= "\t\t" . 'return view();' . "\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function postCreate($modelName \$model) {\n";
 $controllerContent .= "\t\t" . 'if($model->isValid()) {' . "\n";
 $controllerContent .= "\t\t\t" . 'if($model->save())' . "\n";
 $controllerContent .= "\t\t\t\t" . 'return route_redirect(\''.$routeCreate.'\', \'Thêm thành công\');' . "\n";
 $controllerContent .= "\t\t\t" . 'view()->addFlashMessage(\'Thêm thất bại\', \'error\');' . "\n";
 $controllerContent .= "\t\t}\n";
 $controllerContent .= "\t\treturn view(\$model);\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function update(\$id) {\n";
 $controllerContent .= "\t\t" . "\$model = Model::load('$modelName');" . "\n";
 $controllerContent .= "\t\t" . "\$data = \$model->find(\$id);" . "\n";
 $controllerContent .= "\t\t" . "if(!\$data) return route_redirect('$routeIndex', 'Id không tồn tại', 'error');" . "\n";
 $controllerContent .= "\t\t" . 'return view($data);' . "\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function postUpdate($modelName \$model) {\n";
 $controllerContent .= "\t\t" . 'if($model->isValid()) {' . "\n";
 $controllerContent .= "\t\t\t" . 'if($model->save())' . "\n";
 $controllerContent .= "\t\t\t\t" . 'return route_redirect(\''.$routeIndex.'\', \'Cập nhật thành công\');' . "\n";
 $controllerContent .= "\t\t\t" . 'view()->addFlashMessage(\'Cập nhật thất bại\', \'error\');' . "\n";
 $controllerContent .= "\t\t}\n";
 $controllerContent .= "\t\treturn view(\$model);\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function postDelete(\$id) {\n";
 $controllerContent .= "\t\t" . "\$model = Model::load('$modelName');" . "\n";
 $controllerContent .= "\t\t" . "\$isSuccess = \$model->delete(\$id);" . "\n";
 $controllerContent .= "\t\t" . 'if(\Request::isAjax())' . "\n";
 $controllerContent .= "\t\t\t" . "return json(['success' => \$isSuccess, 'message' => \$isSuccess ? 'Xóa thành công' : 'Xóa thất bại']);" . "\n";
 $controllerContent .= "\t\t" . 'return route_redirect(\''.$routeIndex.'\', $isSuccess ? \'Xóa thành công\' : \'Xóa thất bại\');' . "\n";
 $controllerContent .= "\t}\n\n";
 }
 else {
 $controllerContent .= "\tpublic function detail(\$id) {\n";
 $controllerContent .= "\t\t" . "\$model = Model::load('$modelName');" . "\n";
 $controllerContent .= "\t\t" . "\$data = \$model->find(\$id);" . "\n";
 $controllerContent .= "\t\t" . 'if(!$data) ' . "\n";
 $controllerContent .= "\t\t\t" . 'return $this->notFound();' . "\n";
 $controllerContent .= "\t\treturn \$this->ok(\$data);\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function create($modelName \$model) {\n";
 $controllerContent .= "\t\t" . 'if($model->isValid()) {' . "\n";
 $controllerContent .= "\t\t\t" . '$saveRes = $model->save();' . "\n";
 $controllerContent .= "\t\t\t" . 'if($saveRes)' . "\n";
 $controllerContent .= "\t\t\t\t" . 'return $this->ok([\'success\' => true, \'message\' => $saveRes]);' . "\n";
 $controllerContent .= "\t\t\t" . 'return $this->badRequest(\'Lưu dữ liệu thất bại\');' . "\n";
 $controllerContent .= "\t\t}\n";
 $controllerContent .= "\t\treturn \$this->error(\$model->getErrors());\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function update($modelName \$model) {\n";
 $controllerContent .= "\t\t" . 'if($model->isValid()) {' . "\n";
 $controllerContent .= "\t\t\t" . 'if($model->save())' . "\n";
 $controllerContent .= "\t\t\t\t" . 'return $this->ok([\'success\' => true, \'message\' => \'Cập nhật thành công\']);' . "\n";
 $controllerContent .= "\t\t\t" . 'return $this->badRequest(\'Lưu dữ liệu thất bại\');' . "\n";
 $controllerContent .= "\t\t}\n";
 $controllerContent .= "\t\treturn \$this->error(\$model->getErrors());\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function delete(\$id) {\n";
 $controllerContent .= "\t\t" . "\$model = Model::load('$modelName');" . "\n";
 $controllerContent .= "\t\t" . 'if($model->delete($id))' . "\n";
 $controllerContent .= "\t\t\t" . "return \$this->ok(['success' => true, 'message' => 'Xóa thành công']);" . "\n";
 $controllerContent .= "\t\t" . 'return $this->badRequest(\'Xóa thất bại\');' . "\n";
 $controllerContent .= "\t}\n\n";
 }
 }
 $controllerContent .= "}";
 $fp2 = fopen($path . DIRECTORY_SEPARATOR . 'controllers' . DIRECTORY_SEPARATOR . $controllerName . '.php', 'w');
 fwrite($fp2, $controllerContent);
 fclose($fp2);
 }
 private function createModuleView($path, $controllerName, $moduleModelName, $modelName, $isLayout, $routeUrl) {
 $routeIndex = $routeUrl ? ($routeUrl . 'index') : 'index';
 $routeCreate = $routeUrl ? ($routeUrl . 'create') : 'create';
 $routeUpdate = $routeUrl ? ($routeUrl . 'update') : 'update';
 $dirName = $this->getModuleDirViewName($controllerName);
 $dirPath = $path . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $dirName;
 if(!file_exists($dirPath)) mkdir($dirPath);
 $dirPath .= DIRECTORY_SEPARATOR;
 $fp2 = fopen($dirPath . 'index'. TCMS_VIEW_ENGINE .'.php', 'w');
 if($moduleModelName || $modelName) {
 $modelName = $moduleModelName ? $moduleModelName : $modelName;
 $tableName = $this->getModelTableBindingName($modelName);
 $indexContent = "@yield('title', 'Trang danh sách')\n\n";
 $indexContent .= "@section('breadcrumb')\n";
 $indexContent .= "\t<h2>Trang danh sách</h2>\n\t";
 $indexContent .= '<h3><a href="{{ route(\''.$routeCreate.'\') }}">Thêm mới</a></h3>' . "\n";
 $indexContent .= "@endsection\n\n";
 $indexContent .= "@extension('message')\n\n@php\n";
 $indexContent .= "\t\$extensionOption = [\n";
 $indexContent .= "\t\t'name' => 'table-$tableName',\n";
 $indexContent .= "\t\t'title' => '$tableName',\n";
 $indexContent .= "\t\t'controller_url' => route('$routeIndex'),\n";
 $indexContent .= "\t];\n";
 $indexContent .= "@endphp\n\n";
 $indexContent .= "@extension('datatable', '$modelName', \$extensionOption)";
 fwrite($fp2, $indexContent);
 }
 else {
 if($isLayout) {
 $content = "<!DOCTYPE html>\n<html>\n";
 $content .= "<head>\n";
 $content .= "\t<meta charset=\"UTF-8\" />\n";
 $content .= "\t<title>@yield('title')</title>\n";
 $content .= "\t@style()\n";
 $content .= "</head>\n<body>\n\t<div>Nội dung trang layout</div>\n";
 $content .= "\t@body()\n\t<div>Footer Layout</div>\n\t@script()\n";
 $content .= "</body>\n</html>";
 fwrite($fp2, $content);
 }
 else {
 fwrite($fp2, 'Trang index');
 }
 }
 fclose($fp2);
 if($moduleModelName || $modelName) {
 $modelName = $moduleModelName ? $moduleModelName : $modelName;
 $fp3 = fopen($dirPath . 'create' . TCMS_VIEW_ENGINE . '.php', 'w');
 $createContent = "@yield('title', 'Thêm mới')\n\n@extension('message')\n@error()\n\n";
 $createContent .= "@section('breadcrumb')\n\t";
 $createContent .= '<h2><a href="{{ route(\''.$routeIndex.'\') }}">Tiêu đề</a></h2>' . "\n\t<span>Thêm mới</span>\n";
 $createContent .= "@endsection\n\n";
 $createContent .= '@beginForm(route(\''.$routeCreate.'\'))' . "\n";
 $createContent .= "\t@model('$modelName')\n";
 $createContent .= "@endForm";
 fwrite($fp3, $createContent);
 fclose($fp3);
 $fp4 = fopen($dirPath . 'update' . TCMS_VIEW_ENGINE . '.php', 'w');
 $updateContent = "@yield('title', 'Cập nhật')\n\n@extension('message')\n@error()\n\n";
 $updateContent .= "@section('breadcrumb')\n\t";
 $updateContent .= '<h2><a href="{{ route(\''.$routeIndex.'\') }}">Tiêu đề</a></h2>' . "\n\t<span>Cập nhật</span>\n";
 $updateContent .= "@endsection\n\n";
 $updateContent .= '@beginForm(route(\''.$routeUpdate.'\', [\'id\' => $this->id]))' . "\n";
 $updateContent .= "\t@model('$modelName', false)\n";
 $updateContent .= "@endForm";
 fwrite($fp4, $updateContent);
 fclose($fp4);
 }
 }
 private function addToConfig($namespaceName, $mName, $modelName, $isPrivate, $appId, $areaName) {
 if(!$appId) {
 $appId = readAppId();
 }
 $path = ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $appId . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . $areaName . '.module.php';
 if(!file_exists($path)) {
 $fp2 = fopen($path, 'w');
 fwrite($fp2, "<?php\nreturn [\n\n];");
 fclose($fp2);
 }
 $extPath = ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $appId . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . $areaName . '.extension.php';
 if(!file_exists($extPath)) {
 $fp2 = fopen($extPath, 'w');
 fwrite($fp2, "<?php\nreturn [\n\n];");
 fclose($fp2);
 }
 $modelContent = readConfigFile($path);
 if(!$modelContent) {
 showLogError("Không tìm thấy config module.php trong app " . $appId);
 return;
 }
 $lineIndex = -1;
 $lineIndex2 = -1;
 $len = count($modelContent);
 for ($i = $len - 1;
 $i >= 0;
 $i--) {
 if($lineIndex == -1) {
 if(strripos($modelContent[$i], "]") !== false) {
 $lineIndex = $i;
 }
 }
 else {
 if(strripos($modelContent[$i], "]") !== false) {
 $lineIndex2 = $i;
 break;
 }
 }
 }
 $contentFile = false;
 if ($lineIndex2 === -1) {
 $models = require_once($path);
 if (count($models) === 0) {
 $contentFile = "<?php\nreturn [\n";
 $contentFile .= "\t'$mName' => ";
 $contentFile .= "[\n";
 $contentFile .= "\t\t'namespace' => $namespaceName\\$modelName::class,\n";
 if($isPrivate) {
 $contentFile .= "\t\t'private' => true\n";
 }
 $contentFile .= "\t]\n";
 $contentFile .= "];";
 }
 }
 else {
 for ($i = 0;
 $i < $lineIndex2;
 $i++) {
 $contentFile .= $modelContent[$i];
 }
 $line = $modelContent[$lineIndex2];
 $startIndex = strripos($line, "]");
 $contentFile .= substr($line, 0, $startIndex) . "],\n";
 $contentFile .= "\t'$mName' => ";
 $contentFile .= "[\n";
 $contentFile .= "\t\t'namespace' => $namespaceName\\$modelName::class,\n";
 if($isPrivate) {
 $contentFile .= "\t\t'private' => true\n";
 }
 $contentFile .= "\t]";
 $contentFile .= "\n];";
 }
 if ($contentFile) {
 $fp2 = fopen($path, 'w');
 fwrite($fp2, $contentFile);
 fclose($fp2);
 }
 else {
 showLogError("Nội dung config module.php trong app " . $appId . " không hợp lệ");
 }
 }
 private function copyEmptyModule($dst) {
 mkdir($dst);
 mkdir($dst . DIRECTORY_SEPARATOR . 'controllers');
 mkdir($dst . DIRECTORY_SEPARATOR . 'langs');
 mkdir($dst . DIRECTORY_SEPARATOR . 'models');
 mkdir($dst . DIRECTORY_SEPARATOR . 'views');
 }
 private function formatModuleName($options) {
 if(!isset($options['make:module'])) {
 return false;
 }
 $moduleName = $options['make:module'];
 $moduleName = strtolower($moduleName);
 $moduleName = preg_replace('/[^a-z0-9]/i', '-', $moduleName);
 $moduleName = str_replace('--', '-', $moduleName);
 $moduleName = str_replace('--', '-', $moduleName);
 $moduleName = str_replace('.php', '', $moduleName);
 return $moduleName;
 }
 private function getNamespace($option, $moduleName) {
 if(isset($option['class'])) {
 return $option['class'];
 }
 $arr = explode('-', $moduleName);
 $namespaceName = '';
 foreach($arr as $v) {
 if($v != "" && $v != "-") {
 $namespaceName .= strtoupper(substr($v, 0, 1)) . substr($v, 1);
 }
 }
 return $namespaceName;
 }
 private function getController($options, $optionKey = 'controller') {
 $controllerName = isset($options[$optionKey]) ? $options[$optionKey] : 'IndexController';
 $controllerName = preg_replace('/[^a-zA-Z0-9]/i', '', $controllerName);
 if(strripos($controllerName, "Controller") === false) {
 $controllerName .= "Controller";
 }
 if(!$controllerName) {
 return false;
 }
 return strtoupper(substr($controllerName, 0, 1)) . substr($controllerName, 1);
 }
 private function getModelTableBindingName($modelName) {
 $endIndex = strripos($modelName, "Model");
 if($endIndex !== false) {
 $modelName = substr($modelName, 0, $endIndex);
 }
 $tableName = '';
 $arrChar = str_split($modelName);
 $length = count($arrChar);
 for ($i = 0;
 $i < $length;
 $i++) {
 if(ctype_upper($arrChar[$i])) {
 if($tableName) {
 $tableName .= '-' . strtolower($arrChar[$i]);
 }
 else {
 $tableName .= strtolower($arrChar[$i]);
 }
 }
 else {
 $tableName .= $arrChar[$i];
 }
 }
 return $tableName;
 }
 private function getControllerRouteUrl($modelName) {
 $endIndex = strripos($modelName, "Controller");
 if($endIndex !== false) {
 $modelName = substr($modelName, 0, $endIndex);
 }
 $tableName = '';
 $arrChar = str_split($modelName);
 $length = count($arrChar);
 for ($i = 0;
 $i < $length;
 $i++) {
 if(ctype_upper($arrChar[$i])) {
 if($tableName) {
 $tableName .= '-' . strtolower($arrChar[$i]);
 }
 else {
 $tableName .= strtolower($arrChar[$i]);
 }
 }
 else {
 $tableName .= $arrChar[$i];
 }
 }
 return $tableName;
 }
 private function getModuleDirViewName($controllerName) {
 $endIndex = strripos($controllerName, "Controller");
 if($endIndex !== false) {
 $controllerName = substr($controllerName, 0, $endIndex);
 }
 $dirName = '';
 $arrChar = str_split($controllerName);
 $length = count($arrChar);
 for ($i = 0;
 $i < $length;
 $i++) {
 if(ctype_upper($arrChar[$i])) {
 if($dirName) {
 $dirName .= '-' . strtolower($arrChar[$i]);
 }
 else {
 $dirName .= strtolower($arrChar[$i]);
 }
 }
 else {
 $dirName .= $arrChar[$i];
 }
 }
 return $dirName;
 }
 private function getModel($options) {
 if(isset($options['model'])) {
 $modelName = $options['model'];
 $modelName = preg_replace('/[^a-zA-Z0-9]/i', '', $modelName);
 if(strripos($modelName, "Model") === false) {
 $modelName .= "Model";
 }
 if(!$modelName) {
 return false;
 }
 return strtoupper(substr($modelName, 0, 1)) . substr($modelName, 1);
 }
 return false;
 }
 private function getModuleModel($options) {
 if(isset($options['m-model'])) {
 $modelName = $options['m-model'];
 $modelName = preg_replace('/[^a-zA-Z0-9]/i', '', $modelName);
 if(strripos($modelName, "Model") === false) {
 $modelName .= "Model";
 }
 if(!$modelName) {
 return false;
 }
 return strtoupper(substr($modelName, 0, 1)) . substr($modelName, 1);
 }
 return false;
 }
 private function formatAppNamespace($appId) {
 $arrItem = preg_split("/(_|-|\.| )+/", $appId);
 $namespaceName = "";
 foreach($arrItem as $v) {
 $a = strtolower($v);
 if($a !== "0" && !$a) {
 continue;
 }
 $namespaceName .= strtoupper(substr($a, 0, 1)) . substr($a, 1);
 }
 return $namespaceName;
 }
 private function getRouteUrl($modelName, $moduleModelName, $controllerName) {
 $m = $moduleModelName ? $moduleModelName : $modelName;
 if($controllerName == 'IndexController') $routeUrl = $this->getModelTableBindingName($m);
 else $routeUrl = $this->getControllerRouteUrl($controllerName);
 return $routeUrl;
 }
 public function showHelpCreateModule() {
 drawLine();
 echo "Description:\n";
 showLogInfo("  Tự động tạo một module mới");
 echo "\nFormat:\n";
 echo "  make:module [module-name] -a [area-name] [options]\n\n";
 echo "Required:\n";
 showHelpTextColor("[module-name]", "\tTên module cần tạo. VD: admin-category-default");
 showHelpTextColor("-a, --area", "Tên area của module này");
 echo "\nOptions:\n";
 showHelpTextColor("-c, --controller", "Tên controller muốn tạo cùng module.\n\t\t\tNếu không truyền sẽ tự động tạo IndexController\n");
 showHelpTextColor("-m, --model", "Tự binding model dùng chung vào controller\n\t\t\tSẽ tự động thêm các route và action create, update, delete, index\n");
 showHelpTextColor("--m-model", "Tự tạo model trong module và binding vào controller\n\t\t\tSẽ tự động thêm các route và action create, update, delete, index\n");
 showHelpTextColor("-l, --layout", "Tạo layout module\n");
 showHelpTextColor("-p, --private", "\tTạo private module cho app");
 drawLine();
 }
 public function showHelpCreateController() {
 drawLine();
 echo "Description:\n";
 showLogInfo("  Tự động tạo một controller mới");
 echo "\nFormat:\n";
 echo "  make:controller [controller-name] [options]\n\n";
 echo "Required:\n";
 showHelpTextColor("[controller-name]", "\tTên controller cần tạo. VD: UserController");
 showHelpTextColor("-mod, --module", "\tTạo controller này cho module nào? bao gồm cả area. VD: admin\\user-admin");
 echo "\nOptions:\n";
 showHelpTextColor("-m, --model", "\tTự binding model dùng chung vào controller\n\t\t\t\tSẽ tự động thêm các route và action create, update, delete, index\n");
 showHelpTextColor("--m-model", "\tTự binding model của module vào controller\n\t\t\t\tSẽ tự động thêm các route và action create, update, delete, index\n");
 showHelpTextColor("-p, --private", "\t\tNếu module là private thì truyền thông số này vào");
 drawLine();
 }
 }
 