Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update models & filter #466

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 41 additions & 0 deletions adminer/filter.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
$TABLE = $_GET["filter"];
$name = $_GET["name"];
$row = (array) filter($name, $TABLE);

if ($_POST) {
if (!$error && $_POST["Name"] && $_POST["Filter"]) {
if ($_POST["drop"]) {
$location = ME . "table=" . urlencode($TABLE);
filter_drop($TABLE, $name);
redirect($location, lang('Filter has been dropped.'));
} else {
if ($name != "") {
filter_save($TABLE, $name, $_POST["Name"], $_POST["Filter"]);
$location = ME . "filter=" . urlencode($TABLE) . '&name=' . urlencode($_POST["Name"]);
redirect($location, lang('Filter has been updated.'));
}
}
}
$row = $_POST;
}

page_header(($name != "" ? lang('Alter filter') . ": " . h($name) : lang('Create filter')), $error, ["table" => $TABLE]);
?>

<form action="" method="post" id="form" style="width:60rem;">
<p><?php echo lang('Name'); ?>: <input
name="Name"
value="<?php echo h($row["Name"]); ?>"
data-maxlength="64" autocapitalize="off">
<?php echo script("qs('#form')['Timing'].onchange();"); ?>
<p><?php monaco("Filter", $row["Filter"], 25, 60, "sql"); ?></p>
<p>
<input type="submit"
value="<?php echo lang('Save'); ?>">
<?php if ($name != "") { ?><input
type="submit" name="drop"
value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?><?php } ?>
<input type="hidden" name="token"
value="<?php echo $token; ?>">
</form>
14 changes: 14 additions & 0 deletions adminer/include/adminer.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ function csp() {
function head() {
?>
<link rel="stylesheet" type="text/css" href="../externals/jush/jush.css">
<link rel="stylesheet" data-name="vs/editor/editor.main" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs/editor/editor.main.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs/loader.min.js"></script>
<script>
window.monacoEditor = new Promise((resolve) => {
// on load content
window.addEventListener('load', function() {
// require is provided by loader.min.js.
require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs' }});
require(["vs/editor/editor.main"], () => {
resolve(monaco);
});
});
});
</script>
<?php
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion adminer/include/design.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function page_headers() {
function csp() {
return array(
array(
"script-src" => "'self' 'unsafe-inline' 'nonce-" . get_nonce() . "' 'strict-dynamic'", // 'self' is a fallback for browsers not supporting 'strict-dynamic', 'unsafe-inline' is a fallback for browsers not supporting 'nonce-'
// "script-src" => "'self' 'unsafe-inline' 'nonce-" . get_nonce() . "' 'strict-dynamic'", // 'self' is a fallback for browsers not supporting 'strict-dynamic', 'unsafe-inline' is a fallback for browsers not supporting 'nonce-'
"connect-src" => "'self'",
"frame-src" => "https://www.adminer.org",
"object-src" => "'none'",
Expand Down
38 changes: 38 additions & 0 deletions adminer/include/editing.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,44 @@ function textarea($name, $value, $rows = 10, $cols = 80) {
echo "</textarea>";
}

/** Print SQL <textarea> tag
* @param string
* @param string or array in which case [0] of every element is used
* @param int
* @param int
* @return null
*/
function monaco($name, $value, $rows = 10, $cols = 80, $language = 'json') {
global $jush;
echo '<div id="monaco_' . $name .
'" style="height:' . ($rows/7.5*10) . 'em;border:1px solid black;"></div>';
echo "<textarea style='display:none;' name='" . h($name) . "' rows='$rows' cols='$cols' class='sqlarea jush-$jush' spellcheck='false' wrap='off'>";
if (is_array($value)) {
foreach ($value as $val) { // not implode() to save memory
echo h($val[0]) . "\n\n\n"; // $val == array($query, $time, $elapsed)
}
} else {
echo h($value);
}
echo "</textarea>";
echo "<script>monacoEditor.then(monaco => {
const editor = monaco.editor.create(document.getElementById('monaco_" . $name . "'), {
value: " . json_encode($value, JSON_UNESCAPED_UNICODE) . ",
language: '" . $language . "',
automaticLayout: true,
minimap: {
enabled: false
},
});
editor.onDidChangeModelContent(() => {
form['" . $name . "'].value = editor.getValue();
});
window.monaco_" . $name . " = editor;
});
</script>";
}


/** Print table columns for type edit
* @param string
* @param array
Expand Down
215 changes: 215 additions & 0 deletions adminer/include/functions.inc.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,219 @@
<?php
$ob_path = getenv('OB_PATH') ?: '/home/david/projects/ob3/microservices';
function ob_parse_class($file)
{
$dir = __DIR__;
$res = (array) json_decode(exec("php {$dir}/load_class.php {$file}"), true);
$res['instance'] = (object) $res['instance'];
return $res;

global $ob_path;
static $loaded;
// clear file cache
clearstatcache();
if (!isset($loaded[$file])) {
$cwd = getcwd();
chdir($ob_path);
$loaded[$file] = eval('?>' . file_get_contents($file));
chdir($cwd);
}
$class = $loaded[$file];
if (is_string($class) && class_exists($class)) {
$instance = new $class;
return [
'class' => $class,
'instance' => $instance,
];
} else {
return false;
}
}
function ob_save_class($file, $model)
{
$class = $model['class'];
$instance = $model['instance'];
$code = <<<EOT
<?php

class $class
{\n
EOT;
foreach ($instance as $key => $value) {
$value = var_export2($value, 1);
$code .= <<<EOT
public \${$key} = $value;\n
EOT;
}
$code .= <<<EOT
}

return {$class}::class;\n
EOT;
file_put_contents($file, str_replace("\t", ' ', $code));
}
function dd(...$args) {
var_dump(...$args);
die;
}
/**
* Get filters from project.
*/
function filters($table) {
global $ob_path;
$model = ob_parse_class("{$ob_path}/{$table}.php");
return $model['instance']->filters ?? [];
}
function filter($name, $table) {
global $ob_path;
$model = ob_parse_class("{$ob_path}/{$table}.php");
return [
'Name' => $name,
'Filter' => $model['instance']->filters[$name] ?? '',
];
}
function filter_drop($table, $name) {
global $ob_path;
$file = "{$ob_path}/{$table}.php";
$model = ob_parse_class($file);
unset($model['instance']->filters[$name]);
ob_save_class($file, $model);
}
function filter_save($table, $name, $new_name, $filter) {
global $ob_path;
$file = "{$ob_path}/{$table}.php";
$model = ob_parse_class($file);
unset($model['instance']->filters[$name]);
$model['instance']->filters[$new_name] = $filter;
ob_save_class($file, $model);
}
function model_save($model_name, $new_model_name, $instance) {
global $ob_path;
if ($model_name !== $new_model_name) {
unlink("{$ob_path}/{$model_name}.php");
}
$class = ucfirst(camel_case($new_model_name));
$model = [
'class' => $class,
'instance' => $instance,
];
$file = "{$ob_path}/{$new_model_name}.php";
ob_save_class($file, $model);
}
function camel_case($str) {
$str = str_replace(' ', '', ucwords($str, " \t\r\n\f\v_"));
$str[0] = strtolower($str[0]);
return $str;
}
function var_export2($value, $indent = 0) {
$indent = str_repeat("\t", $indent);
if (is_array($value)) {
$code = "[\n";
foreach ($value as $key => $val) {
if (is_numeric($key)) {
$code .= $indent . "\t" . var_export2($val, $indent + 1) . ",\n";
} else {
$code .= $indent . "\t" . var_export($key, true) . " => " . var_export2($val, $indent + 1) . ",\n";
}
}
$code .= $indent . "]";
} else {
$code = var_export($value, true);
}
return $code;
}
function get_table_models($table) {
global $ob_path;
$find = "{$ob_path}/*.php";
$files = glob($find);
$models = [];
foreach ($files as $file) {
$model = ob_parse_class($file);
if (!$model) {
continue;
}
$name = basename($file, '.php');
if ($model['instance']->table == $table) {
$models[$name] = $model;
}
}
return $models;
}
function model($model) {
global $ob_path;
$m = ob_parse_class("{$ob_path}/{$model}.php");
return [
'Name' => $model,
'Class' => $m['class'],
'Model' => json_encode($m['instance'], JSON_PRETTY_PRINT),
];
}
function model_from_table($table, $model = '') {
global $ob_path;
$tables = [$table];
if ($model) {
$m = ob_parse_class("{$ob_path}/{$model}.php");
if (isset($m['instance']->join)) {
// get tables in join
if (preg_match_all('/join\s+([a-z0-9_]+)/i', $m['instance']->join, $matches)) {
$tables = array_merge($tables, $matches[1]);
$tables = array_unique($tables);
}
}
}
// Find field with primary key or auto_increment
$primary = null;
$fields = fields($table);
foreach ($fields as $field) {
$attributes[$field['field']] = $field['field'];
if ($field['primary'] || $field['auto_increment']) {
$primary = $field['field'];
break;
}
}
// If no primary key found find by index
if (!$primary) {
$indexes = indexes($table);
foreach ($indexes as $index) {
if ($index['type'] == 'PRIMARY') {
$primary = $index['columns'][0];
break;
}
}
}
// Prepare attributes
$attributes = [];
$multiple = count($tables) > 1;
foreach ($tables as $t) {
$fields = fields($t);
foreach ($fields as $field) {
if (isset($attributes[$field['field']])) {
continue;
}
$attributes[$field['field']] = $multiple ? "{$t}.{$field['field']}" : $field['field'];
}
}
$create = [];
foreach ($attributes as $key => $val) {
if ($key == $primary) {
continue;
}
$create[$val] = ":$key";
}
$update = [];
foreach ($attributes as $key => $val) {
if ($key == $primary) {
continue;
}
$update[$val] = ":$key";
}
return [
'table' => $table,
'id' => $primary,
'attributes' => $attributes,
'create' => $create,
'update' => $update,
];
}
/** Get database connection
* @return Min_DB
*/
Expand Down
21 changes: 21 additions & 0 deletions adminer/include/load_class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
// get path from first argument
$file = $argv[1];
error_log("Loading file: $file");
$path = dirname($file);

// clear file cache
clearstatcache();
$cwd = getcwd();
chdir($path);
$class = eval('?>' . file_get_contents($file));
chdir($cwd);
if (is_string($class) && class_exists($class)) {
$instance = new $class;
echo json_encode([
'class' => $class,
'instance' => $instance,
]);
} else {
echo 'false';
}
4 changes: 4 additions & 0 deletions adminer/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
include "./type.inc.php";
} elseif (isset($_GET["trigger"])) {
include "./trigger.inc.php";
} elseif (isset($_GET["filter"])) {
include "./filter.inc.php";
} elseif (isset($_GET["model"])) {
include "./model.inc.php";
} elseif (isset($_GET["user"])) {
include "./user.inc.php";
} elseif (isset($_GET["processlist"])) {
Expand Down