Browse Source

PHP-CRUD-UI added

Maurits van der Schee 8 years ago
parent
commit
db93379f1f
1 changed files with 359 additions and 0 deletions
  1. 359
    0
      ui.php

+ 359
- 0
ui.php View File

@@ -0,0 +1,359 @@
1
+<?php
2
+
3
+class PHP_CRUD_UI {
4
+
5
+    protected $settings;
6
+    
7
+    function apiCall($method, $url, $data = false) {
8
+        $ch = curl_init();
9
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
10
+        curl_setopt($ch, CURLOPT_URL, $url);
11
+        if ($data) {
12
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
13
+            $headers = array();
14
+            $headers[] = 'Content-Type: application/json';
15
+            $headers[] = 'Content-Length: ' . strlen($data);
16
+            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
17
+        }
18
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
19
+        $response = curl_exec($ch);
20
+        curl_close($ch);
21
+        return json_decode($response,true);
22
+    }
23
+
24
+    function url($base,$subject,$action,$id='',$field='') {
25
+        return $base.trim("$subject/$action/$id/$field",'/');
26
+    }
27
+
28
+    function menu($parameters) {
29
+        extract($parameters);
30
+        
31
+        $html= '<ul class="nav nav-pills">';
32
+        foreach ($definition['tags'] as $tag) {
33
+            $active = $tag['name']==$subject?' class="active"':'';
34
+            $html.= '<li'.$active.'><a href="'.$this->url($base,$tag['name'],'list').'">'.$tag['name'].'</a></li>';
35
+        }
36
+        $html.= '</ul>';
37
+        return $html;
38
+    }
39
+
40
+    function home($parameters) {
41
+        extract($parameters);
42
+        
43
+        $html = 'Nothing';
44
+        return $html;
45
+    }
46
+
47
+    function head() {
48
+        $html = '<!DOCTYPE html><html lang="en">';
49
+        $html.= '<head><title>PHP-CRUD-UI</title>';
50
+        $html.= '<meta name="viewport" content="width=device-width, initial-scale=1">';
51
+        $html.= '<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">';
52
+        $html.= '<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet">';
53
+        $html.= '<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>';
54
+        $html.= '</head><body>';
55
+        return $html;
56
+    }
57
+
58
+    function displayColumn($columns) {
59
+        // TODO: make configurable
60
+        $names = array('name','title','description','username');
61
+        foreach ($names as $name) {
62
+            if (isset($columns[$name])) return $columns[$name];
63
+        }
64
+        return false;
65
+    }
66
+
67
+
68
+    function referenceText($subject,$data,$field,$id,$definition) {
69
+        $properties = $this->properties($subject,$definition);
70
+        $references = $this->references($subject,$properties);
71
+        $referenced = $this->referenced($subject,$properties);
72
+        $primaryKey = $this->primaryKey($subject,$properties);
73
+        
74
+        $indices = array_flip($data[$subject]['columns']);
75
+        $displayColumn = $this->displayColumn($indices);
76
+        
77
+        $records = $data[$subject]['records'];
78
+        foreach ($records as $record) {
79
+            if ($record[$indices[$field]]==$id) {
80
+                if ($displayColumn===false) {
81
+                    $text = '';
82
+                    $first = true;
83
+                    foreach ($record as $i=>$value) {
84
+                        if (!$references[$i] && $i!=$primaryKey) {
85
+                            if (!$first) $text.= ' - ';
86
+                            $text.= $value;
87
+                            $first = false;
88
+                        }
89
+                    } 
90
+                    return $text;
91
+                } else {
92
+                    return $record[$displayColumn];
93
+                }
94
+            }
95
+        }
96
+        return false;
97
+    }
98
+
99
+    function listRecords($parameters) {
100
+        extract($parameters);
101
+        
102
+        $properties = $this->properties($subject,$definition);
103
+        $references = $this->references($subject,$properties);
104
+        $referenced = $this->referenced($subject,$properties);
105
+        $primaryKey = $this->primaryKey($subject,$properties);
106
+        
107
+        $args = array();
108
+        if ($field) {
109
+            $args['filter']=$field.',eq,'.$id; 
110
+        }
111
+        $include = implode(',',array_filter(array_map(function($v){ return $v[0]; },$references)));
112
+        if ($include) {
113
+            $args['include']=$include; 
114
+        }
115
+        $data = $this->apiCall('GET',$url.'/'.$subject.'?'.http_build_query($args));
116
+        
117
+        $html = '';
118
+        if ($field) {
119
+            $html .= '<p>filtered where "'.$field.'" = "'.$id.'".';
120
+            $href = $this->url($base,$subject,'list');
121
+            $html .= ' <a href="'.$href.'">remove</a></p>';
122
+        }    
123
+        $html.= '<table class="table">';
124
+        $html.= '<tr>';
125
+        foreach ($data[$subject]['columns'] as $i=>$column) {
126
+            $html.= '<th>'.$column.'</th>';
127
+        }
128
+        $html.= '<th>has many</th>';
129
+        $html.= '<th>actions</th>';
130
+        $html.= '</tr>';
131
+        foreach ($data[$subject]['records'] as $record) {
132
+            $html.= '<tr>';
133
+            foreach ($record as $i=>$value) {
134
+                if ($references[$i]) {
135
+                    $html.= '<td>';
136
+                    $href = $this->url($base,$references[$i][0],'list',$value,$references[$i][1]);
137
+                    $html.= '<a href="'.$href.'">';
138
+                    $html.= $this->referenceText($references[$i][0],$data,$references[$i][1],$value,$definition);
139
+                    $html.= '</a>';
140
+                    $html.= '</td>';
141
+                } else {
142
+                    $html.= '<td>'.$value.'</td>';
143
+                }
144
+            }
145
+            $html.= '<td>';
146
+            foreach ($referenced as $i=>$relations) {
147
+                $id = $record[$i];
148
+                if ($relations) foreach ($relations as $j=>$relation) {
149
+                    if ($j) $html.= ', ';
150
+                    $href = $this->url($base,$relation[0],'list',$id,$relation[1]); 
151
+                    $html.= '<a href="'.$href.'">'.$relation[0].'</a>';
152
+                }
153
+            }
154
+            $html.= '</td>';
155
+            $html.= '<td>';
156
+            $href = $this->url($base,$subject,'edit',$record[$primaryKey]);
157
+            $html.= '<a href="'.$href.'">edit</a>';
158
+            $html.= '</td>';
159
+            $html.= '</tr>';
160
+        }
161
+        $html.= '</table>';
162
+        return $html;
163
+    }
164
+
165
+    function selectSubject($url,$subject,$name,$value,$definition) {
166
+        $properties = $this->properties($subject,$definition);
167
+        $references = $this->references($subject,$properties);
168
+        $primaryKey = $this->primaryKey($subject,$properties);
169
+        
170
+        $data = $this->apiCall('GET',$url.'/'.$subject);
171
+        
172
+        $indices = array_flip($data[$subject]['columns']);
173
+        $displayColumn = $this->displayColumn($indices);
174
+        
175
+        $html = '<select class="form-control">';
176
+        foreach ($data[$subject]['records'] as $record) {
177
+            if ($displayColumn===false) {
178
+                $text = '';
179
+                $first = true;
180
+                foreach ($record as $i=>$field) {
181
+                    if (!$references[$i] && $i!=$primaryKey) {
182
+                        if (!$first) $text.= ' - ';
183
+                        $text.= $field;
184
+                        $first = false;
185
+                    }
186
+                } 
187
+                $html.= '<option value="'.$record[$primaryKey].'">'.$text.'</option>';
188
+            } else {
189
+                $html.= '<option value="'.$record[$primaryKey].'">'.$record[$displayColumn].'</option>';
190
+            }
191
+        }
192
+        $html.= '</select>';
193
+        return $html;
194
+    }
195
+
196
+    function editRecord($parameters) {
197
+        extract($parameters);
198
+        
199
+        $properties = $this->properties($subject,$definition);
200
+        $references = $this->references($subject,$properties);
201
+        $referenced = $this->referenced($subject,$properties);
202
+        $primaryKey = $this->primaryKey($subject,$properties);
203
+        
204
+        $data = $this->apiCall('GET',$url.'/'.$subject.'/'.$id);
205
+        $html = '<form>';
206
+        $i=0;
207
+        foreach ($data as $column=>$field) {
208
+            $html.= '<div class="form-group">';
209
+            $html.= '<label for="'.$column.'">'.$column.'</label>';
210
+            if ($references[$i]) {
211
+                $html.= $this->selectSubject($url,$references[$i][0],$column,$field,$definition);
212
+            } else {
213
+                $readonly = $i==$primaryKey?' readonly':'';
214
+                $html.= '<input class="form-control" id="'.$column.'" value="'.$field.'"'.$readonly.'/>';
215
+            }
216
+            $html.= '</div>';
217
+            $i++;
218
+        }
219
+        $html.= '</form>';
220
+        return $html;
221
+    }
222
+
223
+    function properties($subject,$definition) {
224
+        if (!$subject || !$definition) return false;
225
+        $path = '/'.$subject;
226
+        if (!isset($definition['paths'][$path])) {
227
+            $path = '/'.$subject.'/{id}';
228
+        }
229
+        $properties = false;
230
+        if (isset($definition['paths'][$path]['get']['responses']['200']['schema']['properties'])) {
231
+            $properties = $definition['paths'][$path]['get']['responses']['200']['schema']['properties'];
232
+        } elseif (isset($definition['paths'][$path]['get']['responses']['200']['schema']['items']['properties'])) {
233
+            $properties = $definition['paths'][$path]['get']['responses']['200']['schema']['items']['properties'];
234
+        }
235
+        return $properties;
236
+    }
237
+
238
+    function references($subject,$properties) {
239
+        if (!$subject || !$properties) return false;
240
+        $references = array();
241
+        foreach ($properties as $field=>$property) {
242
+            $references[] = isset($property['x-references'])?$property['x-references']:false;
243
+        }
244
+        return $references;
245
+    }
246
+
247
+    function referenced($subject,$properties) {
248
+        if (!$subject || !$properties) return false;
249
+        $referenced = array();
250
+        foreach ($properties as $field=>$property) {
251
+            $referenced[] = isset($property['x-referenced'])?$property['x-referenced']:false;
252
+        }
253
+        return $referenced;
254
+    }
255
+
256
+    function primaryKey($subject,$properties) {
257
+        if (!$subject || !$properties) return false;
258
+        $i = 0;
259
+        foreach ($properties as $field=>$property) {
260
+            if (isset($property['x-primary-key'])) return $i;
261
+            $i++;
262
+        }
263
+        return false;
264
+    }
265
+    
266
+    public function __construct($config) {
267
+        extract($config);
268
+        
269
+        // initialize
270
+        $url = isset($url)?$url:null;
271
+        
272
+        $base = isset($base)?$base:null;
273
+        $definition = isset($definition)?$definition:null;
274
+        $method = isset($method)?$method:null;
275
+        $request = isset($request)?$request:null;
276
+        $get = isset($get)?$get:null;
277
+        $post = isset($post)?$post:null;
278
+        
279
+        // defaults
280
+        if (!$definition) {
281
+            $definition = isset($_SESSION['definition'])?$_SESSION['definition']:null;
282
+            if (!$definition) {
283
+                $definition = $this->apiCall('GET',$url);
284
+                $_SESSION['definition'] = $definition;
285
+            }
286
+        }
287
+        if (!$method) {
288
+            $method = $_SERVER['REQUEST_METHOD'];
289
+        }
290
+        if (!$request) {
291
+            $request = isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:'';
292
+            if (!$request) {
293
+                $request = isset($_SERVER['ORIG_PATH_INFO'])?$_SERVER['ORIG_PATH_INFO']:'';
294
+            }
295
+        }
296
+        if (!$get) {
297
+            $get = $_GET;
298
+        }
299
+        if (!$post) {
300
+            $post = 'php://input';
301
+        }
302
+                
303
+        $request = trim($request,'/');
304
+
305
+        if (!$base) {
306
+            $count = $request?(-1*strlen($request)):strlen($_SERVER['REQUEST_URI']);
307
+            $base = rtrim(substr($_SERVER['REQUEST_URI'],0,$count),'/').'/';
308
+        }
309
+        
310
+        $this->settings = compact('url', 'base', 'definition', 'method', 'request', 'get', 'post');
311
+    }
312
+    
313
+    protected function parseRequestParameter(&$request,$characters) {
314
+        if (!$request) return false;
315
+        $pos = strpos($request,'/');
316
+        $value = $pos?substr($request,0,$pos):$request;
317
+        $request = $pos?substr($request,$pos+1):'';
318
+        if (!$characters) return $value;
319
+        return preg_replace("/[^$characters]/",'',$value);
320
+    }
321
+    
322
+    protected function getParameters($settings) {
323
+        extract($settings);
324
+
325
+        $subject   = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
326
+        $action    = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
327
+        $id        = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
328
+        $field     = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
329
+
330
+        return compact('url','base','subject','action','id','field','definition');
331
+    }
332
+    
333
+    function executeCommand() {
334
+        $parameters = $this->getParameters($this->settings);
335
+        
336
+        $html = $this->head();
337
+        $html.= '<div class="container-fluid">';
338
+        $html.= '<div class="row">';
339
+        $html.= $this->menu($parameters);
340
+        $html.= '</div>';
341
+        $html.= '<div class="row">';
342
+
343
+        switch($parameters['action']){
344
+            case '':     $html.= $this->home($parameters); break;
345
+            case 'list': $html.= $this->listRecords($parameters); break;
346
+            case 'edit': $html.= $this->editRecord($parameters); break;
347
+        }
348
+        
349
+        $html.= '</div>';
350
+        $html.= '</div>';
351
+        return $html;
352
+    }
353
+}
354
+
355
+session_start();
356
+$ui = new PHP_CRUD_UI(array(
357
+    'url' => 'http://localhost:8001/blog.php',
358
+));
359
+echo $ui->executeCommand();

Loading…
Cancel
Save