/** * The constructor for Cody requires a Debby database connection * @param Debby $DEB */ function __construct($DEB = "") { //check to see if we can get a database handle if (empty($DEB) && !empty(Ruth::getOBJECT("DEB"))) { $DEB = Ruth::getOBJECT("DEB"); } $this->DEB = $DEB; Ruth::addRoute(RUTH_POST, "/cody/form/{action}", function ($action) { $object = json_decode(rawurldecode(Ruth::getREQUEST("object"))); $record = json_decode(rawurldecode(Ruth::getREQUEST("record"))); if ($action !== "delete") { echo $this->createTableForm($action, $object, $record, Ruth::getREQUEST("db")); } else { if ($action === "delete") { $sql = $object[0]; if (!empty($object[5])) { $name = $object[5]; } else { $name = "grid"; } if (!empty($object[6])) { $tableInfo = $object[6]; $keyName = strtoupper($tableInfo->primarykey); $tableName = $tableInfo->table; } else { $keyName = key($record); //this is just a quess $sql = explode("from", $sql); $sql = explode($sql[1], " "); $tableName = $sql[0]; } $DEB = Ruth::getOBJECT(Ruth::getREQUEST("db")); $DEB->delete($tableName, [$keyName => $record->{$keyName}]); if (!empty(ONDELETE)) { $params = ["action" => $action, "table" => $tableName, $keyName => $record->{$keyName}, "session" => Ruth::getSESSION(), "request" => Ruth::getREQUEST()]; @call_user_func_array(ONINSERT, $params); } echo $this->bootStrapAlert("success", $caption = "Success", "Record deleted"); echo script('$table' . $name . '.bootstrapTable("refresh");'); } else { echo $this->bootStrapAlert("danger", $caption = "Failed {$action}", "This action is unknown!"); } } }); Ruth::addRoute(RUTH_POST, "/cody/form/{action}/post", function ($action) { $DEB = Ruth::getOBJECT(Ruth::getREQUEST("db")); $object = json_decode(rawurldecode(Ruth::getREQUEST("object"))); $record = json_decode(rawurldecode(Ruth::getREQUEST("record"))); $sql = $object[0]; $fieldInfo = $DEB->getFieldInfo($sql); $dateFields = []; //TODO: determine the password and date fields foreach ($fieldInfo as $fid => $field) { if ($field["type"] === "DATETIME" || $field["type"] === "DATE") { $dateFields[] = $field["name"]; } } $passwordFields = "passwd,password"; $dateFields = join(",", $dateFields); if (!empty($object[5])) { $name = $object[5]; } else { $name = "grid"; } if (!empty($object[6])) { $tableInfo = $object[6]; $keyName = strtoupper($tableInfo->primarykey); $tableName = $tableInfo->table; } else { $keyName = key($record); //this is just a quess $sql = explode("from", $sql); $sql = explode($sql[1], " "); $tableName = $sql[0]; } switch ($action) { case "insert": $sqlInsert = $DEB->getInsertSQL("txt", $tableName, $keyName, true, "{$action}{$name}", $passwordFields, $dateFields, true); if ($sqlInsert) { echo $this->bootStrapAlert("success", $caption = "Success", "Record was updated successfully"); echo script('$table' . $name . '.bootstrapTable("refresh");'); } else { echo $this->bootStrapAlert("danger", $caption = "Failure", "Record could not be updated"); } if (!empty(ONINSERT)) { $params = ["action" => $action, "table" => $tableName, $keyName => $_REQUEST["{$action}{$name}"], "session" => Ruth::getSESSION(), "request" => Ruth::getREQUEST()]; @call_user_func_array(ONINSERT, $params); } break; case "update": $sqlUpdate = $DEB->getUpdateSQL("txt", $tableName, $keyName, $record->{$keyName}, "{$action}{$name}", $passwordFields, $dateFields, true); if ($sqlUpdate) { echo $this->bootStrapAlert("success", $caption = "Success", "Record was updated successfully"); echo script('$table' . $name . '.bootstrapTable("refresh");'); } else { echo $this->bootStrapAlert("danger", $caption = "Failure", "Record could not be updated"); } if (!empty(ONUPDATE)) { $params = ["action" => $action, "table" => $tableName, $keyName => $record->{$keyName}, "session" => Ruth::getSESSION(), "request" => Ruth::getREQUEST()]; @call_user_func_array(ONUPDATE, $params); } break; default: echo $this->bootStrapAlert("danger", $caption = "Failed {$action}", "This action is unknown!"); break; } }); //Add the route for getting the ajax data Ruth::addRoute(RUTH_POST, "/cody/data/ajax/{db}", function ($db) { if (empty($db)) { $db = Ruth::getOBJECT("KIM"); } $DEB = Ruth::getOBJECT($db); $postData = json_decode(Ruth::getPOST_DATA()); if (empty($postData)) { exit; } $object = json_decode(rawurldecode($postData->object)); if (!empty($object[5])) { $name = $object[5]; } else { $name = "grid"; } if (!empty($postData->limit)) { $limit = $postData->limit; } else { $limit = $object[4]; } if (!empty($postData->offset)) { $offSet = $postData->offset; } else { $offSet = 0; } if (!empty($postData->sort)) { $sort = $postData->sort; } else { $sort = ""; } if (!empty($postData->order)) { $order = $postData->order; } else { $order = ""; } if (!empty($postData->search)) { $search = $postData->search; } else { $search = ""; } $orderBy = ""; if (!empty($sort)) { $orderBy = "order by upper({$sort}) {$order}"; } $sql = $object[0]; $buttons = $object[1]; if (!is_object($buttons)) { $tempButtons = explode(",", strtolower($buttons)); if (is_array($tempButtons)) { $buttons = script("var a{recordid}record = '{record}';"); foreach ($tempButtons as $bid => $button) { switch ($button) { case "insert": $buttons .= (new Cody())->bootStrapButton("btnInsert", "Add", "call{$name}Ajax('/cody/form/insert','{$name}Target', {object : a{$name}object, record: a{recordid}record, db: '{$db}' })", "btn btn-success", "", true); break; case "update": $buttons .= (new Cody())->bootStrapButton("btnEdit", "Edit", "call{$name}Ajax('/cody/form/update','{$name}Target', {object : a{$name}object, record: a{recordid}record, db: '{$db}' })", "btn btn-primary", "", true); break; case "delete": $buttons .= (new Cody())->bootStrapButton("btnDelete", "Del", "if (confirm('Are you sure you want to delete this record ?')) { call{$name}Ajax('/cody/form/delete','{$name}Target', {object : a{$name}object, record: a{recordid}record, db: '{$db}' }) }", "btn btn-danger", "", true); break; case "view": $buttons .= (new Cody())->bootStrapButton("btnInsert", "View", "call{$name}Ajax('/cody/form/view','{$name}Target', {object : a{$name}object, record: a{recordid}record, db: '{$db}' })", "btn btn-warning", "", true); break; } } } $buttons = div(["class" => "btn-group btn-group"], $buttons); } $hideColumns = $object[2]; $customFields = ""; if (!empty($object[4])) { $customFields = $object[4]; } if (!empty($object[15])) { $mtooltip = $object[15]; } else { $mtooltip = ""; } $hideColumns = explode(",", strtoupper($hideColumns)); $DEB->getRow("select first 1 * from ({$sql}) t"); $fieldInfo = $DEB->fieldinfo; $filter = ""; if (!empty($search)) { $filter = []; foreach ($fieldInfo as $cid => $field) { if ($field["type"] === "DATE") { $filter[] = "cast(\"{$field["alias"]}\" as varchar(20)) like '%" . strtoupper($search) . "%'"; } else { if ($field["type"] === "VARCHAR") { $filter[] = "upper({$field["alias"]}) like '" . strtoupper($search) . "%'"; } else { if (is_numeric($search)) { $filter[] = "\"{$field["alias"]}\" = '{$search}'"; } } } } $filter = join(" or ", $filter); $filter = "where ({$filter})"; } $data = $DEB->getRow("select count(*) as COUNTRECORDS from ({$sql}) t {$filter}"); $recordCount = $data->COUNTRECORDS; $sql = "select first {$limit} skip {$offSet} * from ({$sql}) t {$filter} {$orderBy}"; $records = $DEB->getRows($sql, DEB_ASSOC, true); $rows = []; $value = ""; $calcField = null; foreach ($records as $rid => $record) { $row = null; $rowButtons = $buttons . ""; foreach ($fieldInfo as $fid => $field) { if ($fid == 0) { $field["align"] = "left"; } if (!in_array(strtoupper($field["name"]), $hideColumns)) { $fieldName = strtoupper($field["name"]); $fid = strtoupper($field["name"]); if (isset($customFields->{$fieldName})) { $customField = $customFields->{$fieldName}; //Populate variables in URL path if (!empty($customField->url)) { $urlPath = $customField->url; foreach ($fieldInfo as $fid2 => $field2) { $urlPath = str_ireplace("{" . $field2["name"] . "}", $record[$field2["name"]], $urlPath); } } else { $urlPath = ""; } //Populate variables in Onclick event if (!empty($customField->onclick)) { $onClickEvent = $customField->onclick; foreach ($fieldInfo as $fid2 => $field2) { $onClickEvent = str_ireplace("{" . $field2["name"] . "}", $record[$field2["name"]], $onClickEvent); } } else { $onClickEvent = ""; } $uniq = ""; //Populate variables in Onclick event if (!empty($customField->id)) { $parsedId = $customField->id; foreach ($fieldInfo as $fid2 => $field2) { $parsedId = str_ireplace("{" . $field2["name"] . "}", $record[$field2["name"]], $parsedId); } $uniq = $parsedId; } else { $parsedId = ""; } //Populate variables in comment field if (!empty($customField->comment)) { $comment = $customField->comment; foreach ($fieldInfo as $fid2 => $field2) { $comment = str_ireplace("{" . $field2["name"] . "}", $record[$field2["name"]], $comment); } } else { $comment = ""; } //Populate variables in Dropdown SQL if (!empty($customField->lookup)) { $dropDownSql = $customField->lookup; foreach ($fieldInfo as $fid2 => $field2) { $dropDownSql = str_ireplace("{" . $field2["name"] . "}", $record[$field2["name"]], $dropDownSql); } } else { $dropDownSql = ""; } //check to see if we have a custom class and add it to the container if (empty($customField->class) ? $extraclass = "" : ($extraclass = $customField->class)) { } if (empty($customField->disabled)) { $customField->disabled = false; } if (!empty($customField->list)) { if (is_object($customField->list)) { $customField->list = get_object_vars($customField->list); } } if (empty($customField->type)) { $customField->type = "text"; } switch ($customField->type) { case "hidden": $row[$field["name"]] = $record[$fid]; break; case "lookup": if (!empty($customField->list[$record[$fid]])) { $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"] . " " . $extraclass], "" . $customField->list[$record[$fid]] . ""); } else { $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"] . " " . $extraclass], "Unknown Lookup"); } break; case "link": $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"] . " " . $extraclass], area(["id" => $parsedId, "href" => $urlPath, "onclick" => $onClickEvent], "" . $record[$fid] . "")); break; case "checkbox": $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"] . " " . $extraclass], "" . $record[$fid] . ""); break; case "calculated": eval('$value = ' . $customField->formula . ';'); $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"] . " " . $extraclass], "" . $value . ""); break; case "image": if (empty($customField->size)) { $customField->size = "100x100"; } $size = explode("x", $customField->size); $styleWidth = $size[0]; $styleHeight = $size[1]; $row[$field["name"]] = "" . img(["class" => "thumbnail", "style" => "height: {$styleHeight}px; width: {$styleWidth}px", "src" => $DEB->encodeImage($record[$fid], "/imagestore", $customField->size), "alt" => ucwords(str_replace("_", " ", strtolower($field["alias"])))]); //we need to make the record happy as well; $record[$fid] = "[image]"; break; case "dropdown": if (empty($uniq)) { $uniq = $customField["id"] . uniqid(); } $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"] . " " . $extraclass], div(["class" => "dropdown"], button(["class" => "btn btn-default dropdown-toggle", "style" => "width:100%", "type" => "button", "id" => $uniq, "data-toggle" => "dropdown", "aria-expanded" => "true"], "" . $record[$fid] . " " . span(["class" => "caret"])), ul(["class" => "dropdown-menu", "role" => "menu", "aria-labelledby" => "dropdownMenu1"], (new Cody($DEB))->populateDropDownItems($dropDownSql, $onClickEvent, $uniq)))); break; default: $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"] . " " . $extraclass], "" . $record[$fid] . ""); break; } } else { $row[$field["name"]] = "" . div(["class" => "text-" . $field["align"]], "" . $record[$fid] . ""); } } if ($rowButtons !== "") { $rowButtons = str_ireplace("{" . $field["name"] . "}", $record[strtoupper($field["name"])], $rowButtons . ""); } $rows[$rid] = $row; } if ($rowButtons !== "") { $rowButtons = str_replace("{record}", rawurlencode(json_encode($record)), $rowButtons); $rowButtons = str_replace("{recordid}", $rid, $rowButtons); } if ($rowButtons !== "") { $rows[$rid]["BUTTONS"] = "" . div($rowButtons); } } $result = ["total" => $recordCount, "rows" => $rows, "sql" => $sql]; echo json_encode($result); }); }
} new Cody(); /** * Build a phar file of the project */ Ruth::addRoute(RUTH_GET, "/build", function () { //call Phoebe with the name of the phar file, by default phoebe will build the web_root folder new Phoebe(TINA4_SESSION); }); /** * Include all the relevant paths */ Ruth::autoLoad($_TINA4_LOAD_PATHS . TINA4_INCLUDES, false); if (strpos(Ruth::getREQUEST_URI(), "/cody") !== false) { Ruth::addRoute(RUTH_GET, "/cody", function () { echo (new Cody())->codeBuilder(); }); Ruth::addRoute(RUTH_POST, "/cody/{action}", function ($action) { echo (new Cody())->codeHandler($action); }); } //We should check to see if we have a kim.db file to load routes from before parsing if (file_exists("kim.db")) { (new Kim())->loadDefines(); //these come from global settings (new Kim())->loadRoutes(); } /** * Parse all the routes, never delete this code below, you can pass a single variable through to fake the route for testing. */ Ruth::parseRoutes();
/** * Create a database connection for Kim to use. */ function __construct() { $this->createDB = false; if (!file_exists(realpath(__DIR__ . "/../") . "/kim.db")) { $this->createDB = true; } $this->KIM = new Debby(realpath(__DIR__ . "/../") . "/kim.db", $username = "", $password = "", $dbtype = "sqlite3", $outputdateformat = "YYYY-mm-dd", "KIM"); Ruth::setOBJECT("KIM", $this->KIM); /** * Check if we need to be creating the database for the menus */ if ($this->createDB) { $this->createDatabase(); } if (Ruth::getOBJECT("DEB")) { if (!file_exists(Ruth::getDOCUMENT_ROOT() . "/migrations/19000101100000 initial_kim_global_settings.sql") || !file_exists(Ruth::getDOCUMENT_ROOT() . "/migrations/19000101100001 initial_kim_content_table.sql")) { $sqlGlobalSettings = "create table global_setting (\n global_setting_id integer default 0 not null,\n global_name varchar (100) default 'ENVIRONMENT',\n global_value varchar (200) default 'Development',\n description text default '',\n created timestamp default 'now',\n updated timestamp default 'now',\n primary key (global_setting_id)\n );"; file_put_contents(Ruth::getDOCUMENT_ROOT() . "/migrations/19000101100000 initial_kim_global_settings.sql", $sqlGlobalSettings); $sqlContentTable = "create table content (\n content_id integer default 0 not null,\n title varchar (200) default '',\n description varchar (1000) default '',\n content blob,\n status varchar (20) default 'Active',\n order_index integer default 0,\n primary key (content_id)\n )"; file_put_contents(Ruth::getDOCUMENT_ROOT() . "/migrations/19000101100001 initial_kim_content_table.sql", $sqlContentTable); } } //Add the default routes for Kim Ruth::addRoute(RUTH_GET, "/kim/logout", function () { Ruth::setSESSION("KIM", ["loggedin" => 0]); Ruth::redirect("/kim/login"); }); Ruth::addRoute(RUTH_GET, "/kim/menu/get/{menuId}", function ($menuId) { echo (new Kim())->getMenuItemForm($menuId); }); Ruth::addRoute(RUTH_GET, "/kim/menu/{controller}", function ($controller) { switch ($controller) { case "menu_tree": echo (new Kim())->getMenuTree(); break; case "insert": echo (new Kim())->getInsertMenuItemForm(); break; default: echo "{$controller} not found"; break; } }); Ruth::addRoute(RUTH_POST, "/kim/menu/{controller}", function ($controller) { switch ($controller) { case "menu_list": echo (new Kim())->getMenuList(); break; case "insert": echo (new Kim())->insertMenuItem(); echo (new Kim())->getMenuTree(); break; case "delete": echo (new Kim())->deleteMenuItem(); break; case "update": echo (new Kim())->updateMenuItem(); echo (new Kim())->getMenuTree(); break; default: echo "{$controller} not found"; break; } }); Ruth::addRoute(RUTH_GET, "/kim/*", function () { (new Kim())->display(); }); Ruth::addRoute(RUTH_POST, "/kim/*", function () { (new Kim())->updatePOST(); }); }