Implemented batch delete as in #129 and made #127 consistent with this implementation

This commit is contained in:
Maurits van der Schee 2016-11-10 02:37:38 +01:00
commit 7a8afb20bc
3 changed files with 68 additions and 45 deletions

View file

@ -349,12 +349,11 @@ Note that only fields that are specified in the request will be updated.
### Update (with JSON array)
Alternatively you can send a JSON array containing multiple JSON objects in the body. Each of the records must contain the primary key field.
The call returns an array of the rows affected.
Alternatively you can send a JSON array containing multiple JSON objects in the body. The call returns an array of the rows affected.
```
PUT http://localhost/api.php/categories
[{"id":"1","name":"Internet"},{"id":"2","name":"Programming"}]
PUT http://localhost/api.php/categories/1,2
[{"name":"Internet"},{""name":"Programming"}]
```
Output:
@ -363,6 +362,8 @@ Output:
[1,1]
```
The number of primary key values in the URL should match the number of elements in the JSON array.
This call uses a transaction and will either update all or no records. If the transaction fails it will return 'null'.
### Delete
@ -379,6 +380,22 @@ Output:
1
```
### Delete (multiple)
The DELETE verb can also be used to delete multiple records. The call returns the rows affected for each primary key value specified in the URL.
```
DELETE http://localhost/api.php/categories/1,2
```
Output:
```
[1,1]
```
This call uses a transaction and will either delete all or no records. If the transaction fails it will return 'null'.
## Relations
The explanation of this feature is based on the data structure from the ```blog.sql``` database file. This database is a very simple blog data structure with corresponding foreign key relations between the tables. These foreign key constraints are required as the relationship detection is based on them, not on column naming.

67
api.php
View file

@ -1078,8 +1078,8 @@ class PHP_CRUD_API {
return $fields;
}
protected function processKeyParameter($action,$key,$tables,$database) {
if ($action == 'list') return false;
protected function processKeyParameter($key,$tables,$database) {
if (!$key) return false;
$fields = $this->findPrimaryKeys($tables[0],$database);
if (count($fields)!=1) $this->exitWith404('1pk');
return array($key,$fields[0]);
@ -1254,13 +1254,8 @@ class PHP_CRUD_API {
$ids = array();
$this->db->beginTransaction();
foreach ($inputs as $input) {
$input = (array)$input;
$keys = implode(',',str_split(str_repeat('!', count($input))));
$values = implode(',',str_split(str_repeat('?', count($input))));
$params = array_merge(array_keys($input),array_values($input));
array_unshift($params, $tables[0]);
$result = $this->db->query('INSERT INTO ! ('.$keys.') VALUES ('.$values.')',$params);
if (!$result) {
$result = $this->createObject($input,$tables);
if ($result===null) {
$this->db->rollbackTransaction();
return null;
}
@ -1293,38 +1288,19 @@ class PHP_CRUD_API {
protected function updateObjects($key,$inputs,$filters,$tables) {
if (!$inputs) return false;
$keyField = $key[1];
$keys = array();
foreach ($inputs as $i=>$input) {
if (isset($input->$keyField)) {
$keys[$i] = $input->$keyField;
unset($inputs[$i]->$keyField);
} else {
$keys = explode(',',$key[0]);
if (count($inputs)!=count($keys)) {
$this->exitWith404('subject');
}
}
$rows = array();
$this->db->beginTransaction();
foreach ($inputs as $i=>$input) {
$input = (array)$input;
$table = $tables[0];
$sql = 'UPDATE ! SET ';
$params = array($table);
foreach (array_keys($input) as $j=>$k) {
if ($j) $sql .= ',';
$v = $input[$k];
$sql .= '!=?';
$params[] = $k;
$params[] = $v;
}
$newFilters = $filters;
$this->addFilter($newFilters,$table,'and',$keyField,'eq',$keys[$i]);
$this->addWhereFromFilters($newFilters[$table],$sql,$params);
$result = $this->db->query($sql,$params);
if (!$result) {
$result = $this->updateObject(array($keys[$i],$keyField),$input,$filters,$tables);
if ($result===null) {
$this->db->rollbackTransaction();
return null;
}
$rows[] = $this->db->affectedRows($result);
$rows[] = $result;
}
$this->db->commitTransaction();
return $rows;
@ -1341,6 +1317,23 @@ class PHP_CRUD_API {
return $this->db->affectedRows($result);
}
protected function deleteObjects($key,$filters,$tables) {
$keyField = $key[1];
$keys = explode(',',$key[0]);
$rows = array();
$this->db->beginTransaction();
foreach ($keys as $key) {
$result = $this->deleteObject(array($key,$keyField),$filters,$tables);
if ($result===null) {
$this->db->rollbackTransaction();
return null;
}
$rows[] = $result;
}
$this->db->commitTransaction();
return $rows;
}
protected function findRelations($tables,$database,$auto_include) {
$tableset = array();
$collect = array();
@ -1491,7 +1484,7 @@ class PHP_CRUD_API {
extract($settings);
$table = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
$key = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_'); // auto-increment or uuid
$key = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_,'); // auto-increment or uuid
$action = $this->mapMethodToAction($method,$key);
$include = $this->parseGetParameter($get, 'include', 'a-zA-Z0-9\-_,');
$page = $this->parseGetParameter($get, 'page', '0-9,');
@ -1502,7 +1495,7 @@ class PHP_CRUD_API {
$transform = $this->parseGetParameter($get, 'transform', 't1');
$tables = $this->processTableAndIncludeParameters($database,$table,$include,$action);
$key = $this->processKeyParameter($action,$key,$tables,$database);
$key = $this->processKeyParameter($key,$tables,$database);
$satisfy = $this->processSatisfyParameter($tables,$satisfy);
$filters = $this->processFiltersParameter($tables,$satisfy,$filters);
$page = $this->processPageParameter($page);
@ -1520,6 +1513,7 @@ class PHP_CRUD_API {
if ($tenancy_function) $this->applyTenancyFunction($tenancy_function,$action,$database,$fields,$filters);
if ($column_authorizer) $this->applyColumnAuthorizer($column_authorizer,$action,$database,$fields);
$multi = strpos($key[0],',')!==false;
if (strlen($post)) {
// input
$multi = $post[0]=='[';
@ -1703,7 +1697,8 @@ class PHP_CRUD_API {
protected function deleteCommand($parameters) {
extract($parameters);
$this->startOutput();
echo json_encode($this->deleteObject($key,$filters,$tables));
if ($multi) echo json_encode($this->deleteObjects($key,$filters,$tables));
else echo json_encode($this->deleteObject($key,$filters,$tables));
}
protected function listCommand($parameters) {

View file

@ -643,14 +643,14 @@ class PHP_CRUD_API_Test extends PHPUnit_Framework_TestCase
$test = new API($this);
$test->get('/tags?transform=1');
$test->expect('{"tags":[{"id":"1","name":"funny"},{"id":"2","name":"important"}]}');
$test->put('/tags','[{"id":"1","name":"funny"},{"id":"2","name":"important"}]');
$test->put('/tags/1,2','[{"name":"funny"},{"name":"important"}]');
$test->expect('[0,0]');
}
public function testUpdateMultipleTagsWithoutId()
public function testUpdateMultipleTagsTooManyIds()
{
$test = new API($this);
$test->put('/tags','[{"id":"1","name":"funny!!!"},{"name":"important"}]');
$test->put('/tags/1,2,3','[{"name":"funny!!!"},{"name":"important"}]');
$test->expect(false,'Not found (subject)');
$test->get('/tags?transform=1');
$test->expect('{"tags":[{"id":"1","name":"funny"},{"id":"2","name":"important"}]}');
@ -659,9 +659,20 @@ class PHP_CRUD_API_Test extends PHPUnit_Framework_TestCase
public function testUpdateMultipleTagsWithoutFields()
{
$test = new API($this);
$test->put('/tags','[{"id":"1","name":"funny!!!"},{"id":"2"}]');
$test->put('/tags/1,2','[{"name":"funny!!!"},{}]');
$test->expect('null');
$test->get('/tags?transform=1');
$test->expect('{"tags":[{"id":"1","name":"funny"},{"id":"2","name":"important"}]}');
}
public function testDeleteMultipleTags()
{
$test = new API($this);
$test->post('/tags','[{"name":"extra"},{"name":"more"}]');
$test->expect('[3,4]');
$test->delete('/tags/3,4');
$test->expect('[1,1]');
$test->get('/tags?transform=1');
$test->expect('{"tags":[{"id":"1","name":"funny"},{"id":"2","name":"important"}]}');
}
}