Browse Source

Merged changes

Maurits van der Schee 8 years ago
parent
commit
bdad449c16
3 changed files with 16 additions and 388 deletions
  1. 5
    0
      README.md
  2. 11
    11
      api.php
  3. 0
    377
      ui.php

+ 5
- 0
README.md View File

@@ -5,6 +5,11 @@
5 5
 
6 6
 Single file PHP script that adds a REST API to a MySQL InnoDB database. Alternatively SQLite 3, PostgreSQL 9 and MS SQL Server 2012 are fully supported.
7 7
 
8
+Related projects:
9
+
10
+  - [PHP-SP-API](https://github.com/mevdschee/php-sp-api): Single file PHP script that adds a REST API to a SQL database.
11
+  - [PHP-CRUD-UI](https://github.com/mevdschee/php-crud-ui): Single file PHP script that adds a UI to a PHP-CRUD-API project.
12
+
8 13
 ## Requirements
9 14
 
10 15
   - PHP 5.3 or higher with MySQLi, libpq, SQLSRV or sqlite3 enabled

+ 11
- 11
api.php View File

@@ -949,24 +949,22 @@ class PHP_CRUD_API {
949 949
 		}
950 950
 	}
951 951
 
952
-	protected function findPrimaryKey($table,$database) {
953
-		$count = 0;
954
-		$field = false;
952
+	protected function findPrimaryKeys($table,$database) {
953
+		$fields = array();
955 954
 		if ($result = $this->db->query($this->db->getSql('reflect_pk'),array($table,$database))) {
956 955
 			while ($row = $this->db->fetchRow($result)) {
957
-				$count++;
958
-				$field = $row[0];
956
+				$fields[] = $row[0];
959 957
 			}
960 958
 			$this->db->close($result);
961 959
 		}
962
-		if ($count!=1 || $field==false) $this->exitWith404('1pk');
963
-		return $field;
960
+		return $fields;
964 961
 	}
965 962
 
966 963
 	protected function processKeyParameter($key,$tables,$database) {
967 964
 		if (!$key) return false;
968
-		$field = $this->findPrimaryKey($tables[0],$database);
969
-		return array($key,$field);
965
+		$fields = $this->findPrimaryKeys($tables[0],$database);
966
+		if (count($fields)!=1) $this->exitWith404('1pk');
967
+		return array($key,$fields[0]);
970 968
 	}
971 969
 
972 970
 	protected function processOrderParameter($order) {
@@ -1614,8 +1612,10 @@ class PHP_CRUD_API {
1614 1612
 				while ($row = $this->db->fetchRow($result)) {
1615 1613
 					$table_fields[$table['name']][$row[3]]->referenced[]=array($row[0],$row[1]);
1616 1614
 				}
1617
-				$primaryKey = $this->findPrimaryKey($table_list[0],$database);
1618
-				$table_fields[$table['name']][$primaryKey]->primaryKey = true;
1615
+				$primaryKeys = $this->findPrimaryKeys($table_list[0],$database);
1616
+				foreach ($primaryKeys as $primaryKey) {
1617
+					$table_fields[$table['name']][$primaryKey]->primaryKey = true;
1618
+				}
1619 1619
 			}
1620 1620
 			
1621 1621
 			foreach (array('root_actions','id_actions') as $path) {

+ 0
- 377
ui.php View File

@@ -1,377 +0,0 @@
1
-<?php
2
-
3
-class PHP_CRUD_UI {
4
-
5
-    protected $settings;
6
-    
7
-    function call($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 nav-stacked">';
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.= '</head><body><div class="container">';
54
-        $html.= '<div class="row">';
55
-        $html.= '<div class="col-md-4"><h3>PHP-CRUD-UI</h3></div>';
56
-        $html.= '</div>';
57
-        return $html;
58
-    }
59
-
60
-    function foot() {
61
-        $html = '</div></body></html>';
62
-        return $html;
63
-    }
64
-
65
-    function displayColumn($columns) {
66
-        // TODO: make configurable
67
-        $names = array('name','title','description','username');
68
-        foreach ($names as $name) {
69
-            if (isset($columns[$name])) return $columns[$name];
70
-        }
71
-        return false;
72
-    }
73
-
74
-
75
-    function referenceText($subject,$data,$field,$id,$definition) {
76
-        $properties = $this->properties($subject,$definition);
77
-        $references = $this->references($subject,$properties);
78
-        $referenced = $this->referenced($subject,$properties);
79
-        $primaryKey = $this->primaryKey($subject,$properties);
80
-        
81
-        $indices = array_flip($data[$subject]['columns']);
82
-        $displayColumn = $this->displayColumn($indices);
83
-        
84
-        $records = $data[$subject]['records'];
85
-        foreach ($records as $record) {
86
-            if ($record[$indices[$field]]==$id) {
87
-                if ($displayColumn===false) {
88
-                    $text = '';
89
-                    $first = true;
90
-                    foreach ($record as $i=>$value) {
91
-                        if (!$references[$i] && $i!=$primaryKey) {
92
-                            if (!$first) $text.= ' - ';
93
-                            $text.= $value;
94
-                            $first = false;
95
-                        }
96
-                    } 
97
-                    return $text;
98
-                } else {
99
-                    return $record[$displayColumn];
100
-                }
101
-            }
102
-        }
103
-        return false;
104
-    }
105
-
106
-    function listRecords($parameters) {
107
-        extract($parameters);
108
-        
109
-        $properties = $this->properties($subject,$definition);
110
-        $references = $this->references($subject,$properties);
111
-        $referenced = $this->referenced($subject,$properties);
112
-        $primaryKey = $this->primaryKey($subject,$properties);
113
-        
114
-        $related = !empty(array_filter($referenced));
115
-        
116
-        $args = array();
117
-        if ($field) {
118
-            $args['filter']=$field.',eq,'.$id; 
119
-        }
120
-        $include = implode(',',array_filter(array_map(function($v){ return $v[0]; },$references)));
121
-        if ($include) {
122
-            $args['include']=$include; 
123
-        }
124
-        $data = $this->call('GET',$url.'/'.$subject.'?'.http_build_query($args));
125
-        
126
-        $html = '<h4>'.$subject.': list</h4>';
127
-        if ($field) {
128
-            $html .= '<div class="alert alert-info" role="alert">Filtered where "'.$field.'" = "'.$id.'".';
129
-            $href = $this->url($base,$subject,'list');
130
-            $html .= '<div style="float:right;"><a href="'.$href.'">Show all</a></div></div>';
131
-        }    
132
-        $html.= '<table class="table">';
133
-        $html.= '<thead><tr>';
134
-        foreach ($data[$subject]['columns'] as $i=>$column) {
135
-            $html.= '<th>'.$column.'</th>';
136
-        }
137
-        if ($related) {
138
-            $html.= '<th>related</th>';
139
-        }
140
-        $html.= '<th>actions</th>';
141
-        $html.= '</tr></thead><tbody>';
142
-        foreach ($data[$subject]['records'] as $record) {
143
-            $html.= '<tr>';
144
-            foreach ($record as $i=>$value) {
145
-                if ($references[$i]) {
146
-                    $html.= '<td>';
147
-                    $href = $this->url($base,$references[$i][0],'list',$value,$references[$i][1]);
148
-                    $html.= '<a href="'.$href.'">';
149
-                    $html.= $this->referenceText($references[$i][0],$data,$references[$i][1],$value,$definition);
150
-                    $html.= '</a>';
151
-                    $html.= '</td>';
152
-                } else {
153
-                    $html.= '<td>'.$value.'</td>';
154
-                }
155
-            }
156
-            if ($related) {
157
-                $html.= '<td>';
158
-                foreach ($referenced as $i=>$relations) {
159
-                    $id = $record[$i];
160
-                    if ($relations) foreach ($relations as $j=>$relation) {
161
-                        if ($j) $html.= ', ';
162
-                        $href = $this->url($base,$relation[0],'list',$id,$relation[1]); 
163
-                        $html.= '<a href="'.$href.'">'.$relation[0].'</a>';
164
-                    }
165
-                }
166
-                $html.= '</td>';
167
-            }
168
-            $html.= '<td>';
169
-            $href = $this->url($base,$subject,'edit',$record[$primaryKey]);
170
-            $html.= '<a href="'.$href.'">edit</a>';
171
-            $html.= '</td>';
172
-            $html.= '</tr>';
173
-        }
174
-        $html.= '</tbody></table>';
175
-        return $html;
176
-    }
177
-
178
-    function selectSubject($url,$subject,$name,$value,$definition) {
179
-        $properties = $this->properties($subject,$definition);
180
-        $references = $this->references($subject,$properties);
181
-        $primaryKey = $this->primaryKey($subject,$properties);
182
-        
183
-        $data = $this->call('GET',$url.'/'.$subject);
184
-        
185
-        $indices = array_flip($data[$subject]['columns']);
186
-        $displayColumn = $this->displayColumn($indices);
187
-        
188
-        $html = '<select class="form-control">';
189
-        foreach ($data[$subject]['records'] as $record) {
190
-            $selected = $record[$primaryKey]==$value?' selected':'';
191
-            $html.= '<option value="'.$record[$primaryKey].'"'.$selected.'>';
192
-            if ($displayColumn===false) {
193
-                $text = '';
194
-                $first = true;
195
-                foreach ($record as $i=>$field) {
196
-                    if (!$references[$i] && $i!=$primaryKey) {
197
-                        if (!$first) $text.= ' - ';
198
-                        $text.= $field;
199
-                        $first = false;
200
-                    }
201
-                } 
202
-                $html.= $text;
203
-            } else {
204
-                $html.= $record[$displayColumn];
205
-            }
206
-            $html.= '</option>';
207
-        }
208
-        $html.= '</select>';
209
-        return $html;
210
-    }
211
-
212
-    function editRecord($parameters) {
213
-        extract($parameters);
214
-        
215
-        $properties = $this->properties($subject,$definition);
216
-        $references = $this->references($subject,$properties);
217
-        $referenced = $this->referenced($subject,$properties);
218
-        $primaryKey = $this->primaryKey($subject,$properties);
219
-        
220
-        $data = $this->call('GET',$url.'/'.$subject.'/'.$id);
221
-        $html = '<h4>'.$subject.': edit</h4>';
222
-        $html.= '<form>';
223
-        $i=0;
224
-        foreach ($data as $column=>$field) {
225
-            $html.= '<div class="form-group">';
226
-            $html.= '<label for="'.$column.'">'.$column.'</label>';
227
-            if ($references[$i]) {
228
-                $html.= $this->selectSubject($url,$references[$i][0],$column,$field,$definition);
229
-            } else {
230
-                $readonly = $i==$primaryKey?' readonly':'';
231
-                $html.= '<input class="form-control" id="'.$column.'" value="'.$field.'"'.$readonly.'/>';
232
-            }
233
-            $html.= '</div>';
234
-            $i++;
235
-        }
236
-        $html.= '</form>';
237
-        return $html;
238
-    }
239
-
240
-    function properties($subject,$definition) {
241
-        if (!$subject || !$definition) return false;
242
-        $path = '/'.$subject;
243
-        if (!isset($definition['paths'][$path])) {
244
-            $path = '/'.$subject.'/{id}';
245
-        }
246
-        $properties = false;
247
-        if (isset($definition['paths'][$path]['get']['responses']['200']['schema']['properties'])) {
248
-            $properties = $definition['paths'][$path]['get']['responses']['200']['schema']['properties'];
249
-        } elseif (isset($definition['paths'][$path]['get']['responses']['200']['schema']['items']['properties'])) {
250
-            $properties = $definition['paths'][$path]['get']['responses']['200']['schema']['items']['properties'];
251
-        }
252
-        return $properties;
253
-    }
254
-
255
-    function references($subject,$properties) {
256
-        if (!$subject || !$properties) return false;
257
-        $references = array();
258
-        foreach ($properties as $field=>$property) {
259
-            $references[] = isset($property['x-references'])?$property['x-references']:false;
260
-        }
261
-        return $references;
262
-    }
263
-
264
-    function referenced($subject,$properties) {
265
-        if (!$subject || !$properties) return false;
266
-        $referenced = array();
267
-        foreach ($properties as $field=>$property) {
268
-            $referenced[] = isset($property['x-referenced'])?$property['x-referenced']:false;
269
-        }
270
-        return $referenced;
271
-    }
272
-
273
-    function primaryKey($subject,$properties) {
274
-        if (!$subject || !$properties) return false;
275
-        $i = 0;
276
-        foreach ($properties as $field=>$property) {
277
-            if (isset($property['x-primary-key'])) return $i;
278
-            $i++;
279
-        }
280
-        return false;
281
-    }
282
-    
283
-    public function __construct($config) {
284
-        extract($config);
285
-        
286
-        // initialize
287
-        $url = isset($url)?$url:null;
288
-        
289
-        $base = isset($base)?$base:null;
290
-        $definition = isset($definition)?$definition:null;
291
-        $method = isset($method)?$method:null;
292
-        $request = isset($request)?$request:null;
293
-        $get = isset($get)?$get:null;
294
-        $post = isset($post)?$post:null;
295
-        
296
-        // defaults
297
-        if (!$definition) {
298
-            $definition = isset($_SESSION['definition'])?$_SESSION['definition']:null;
299
-            if (!$definition) {
300
-                $definition = $this->call('GET',$url);
301
-                $_SESSION['definition'] = $definition;
302
-            }
303
-        }
304
-        if (!$method) {
305
-            $method = $_SERVER['REQUEST_METHOD'];
306
-        }
307
-        if (!$request) {
308
-            $request = isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:'';
309
-            if (!$request) {
310
-                $request = isset($_SERVER['ORIG_PATH_INFO'])?$_SERVER['ORIG_PATH_INFO']:'';
311
-            }
312
-        }
313
-        if (!$get) {
314
-            $get = $_GET;
315
-        }
316
-        if (!$post) {
317
-            $post = 'php://input';
318
-        }
319
-                
320
-        $request = trim($request,'/');
321
-
322
-        if (!$base) {
323
-            $count = $request?(-1*strlen($request)):strlen($_SERVER['REQUEST_URI']);
324
-            $base = rtrim(substr($_SERVER['REQUEST_URI'],0,$count),'/').'/';
325
-        }
326
-        
327
-        $this->settings = compact('url', 'base', 'definition', 'method', 'request', 'get', 'post');
328
-    }
329
-    
330
-    protected function parseRequestParameter(&$request,$characters) {
331
-        if (!$request) return false;
332
-        $pos = strpos($request,'/');
333
-        $value = $pos?substr($request,0,$pos):$request;
334
-        $request = $pos?substr($request,$pos+1):'';
335
-        if (!$characters) return $value;
336
-        return preg_replace("/[^$characters]/",'',$value);
337
-    }
338
-    
339
-    protected function getParameters($settings) {
340
-        extract($settings);
341
-
342
-        $subject   = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
343
-        $action    = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
344
-        $id        = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
345
-        $field     = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
346
-
347
-        return compact('url','base','subject','action','id','field','definition');
348
-    }
349
-    
350
-    function executeCommand() {
351
-        $parameters = $this->getParameters($this->settings);
352
-        
353
-        $html = $this->head();
354
-        $html.= '<div class="row">';
355
-        $html.= '<div class="col-md-4">';
356
-        $html.= $this->menu($parameters);
357
-        $html.= '</div>';
358
-        
359
-        $html.= '<div class="col-md-8">';
360
-        switch($parameters['action']){
361
-            case '':     $html.= $this->home($parameters); break;
362
-            case 'list': $html.= $this->listRecords($parameters); break;
363
-            case 'edit': $html.= $this->editRecord($parameters); break;
364
-        }
365
-        $html.= '</div>';
366
-        
367
-        $html.= '</div>';
368
-        $html.= $this->foot();
369
-        return $html;
370
-    }
371
-}
372
-
373
-//session_start();
374
-//$ui = new PHP_CRUD_UI(array(
375
-//    'url' => 'http://localhost/api.php',
376
-//));
377
-//echo $ui->executeCommand();

Loading…
Cancel
Save