From 4dfb8d0c39b861b63c1877a9ef696bc93fdec91b Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Wed, 26 Oct 2016 16:03:26 +0100 Subject: [PATCH] more changes --- src/AppBundle/Controller/ApiController.php | 18 +---- src/AppBundle/Model/BaseModel.php | 87 ++++++++++++++++++++++ src/AppBundle/Model/Change.php | 47 +++++++++++- tests/BaseTestCase.php | 6 +- tests/Model/ChangeTest.php | 39 ++++++++++ tests/setup.php | 2 +- 6 files changed, 176 insertions(+), 23 deletions(-) diff --git a/src/AppBundle/Controller/ApiController.php b/src/AppBundle/Controller/ApiController.php index 2f5bab7098..887531c67e 100644 --- a/src/AppBundle/Controller/ApiController.php +++ b/src/AppBundle/Controller/ApiController.php @@ -113,24 +113,8 @@ abstract class ApiController extends Controller { } } - static private function serializeResponse($data) { - $output = $data; - - if ($output instanceof Collection) $output = $output->all(); - - if ($output instanceof BaseModel) { - $output = $output->toPublicArray(); - } else if (is_array($output)) { - foreach ($output as $k => $v) { - $output[$k] = self::serializeResponse($v); - } - } - - return $output; - } - static protected function successResponse($data = null) { - $output = self::serializeResponse($data); + $output = BaseModel::anythingToPublicArray($data); return new JsonResponse($output); } diff --git a/src/AppBundle/Model/BaseModel.php b/src/AppBundle/Model/BaseModel.php index efd8f24371..9f534aa1ba 100644 --- a/src/AppBundle/Model/BaseModel.php +++ b/src/AppBundle/Model/BaseModel.php @@ -4,6 +4,7 @@ namespace AppBundle\Model; use \Illuminate\Database\Eloquent\Model; use \Illuminate\Support\Facades\DB; +use \Illuminate\Database\Eloquent\Collection; class BaseModel extends \Illuminate\Database\Eloquent\Model { @@ -39,6 +40,92 @@ class BaseModel extends \Illuminate\Database\Eloquent\Model { return self::$clientId; } + static public function anythingToAsciiTable($data, $fields = null) { + $data = self::anythingToPublicArray($data); + if (!count($data)) return ''; + $header = array(); + $r = $data[0]; + foreach ($r as $k => $v) { + $header[] = $k; + } + + $lengths = array(); + foreach ($header as $f) { + $lengths[$f] = max(strlen($f), self::fieldMaxLength($f, $data)); + } + + if (!$fields) { + $fields = $header; + } else { + $header = $fields; + } + + $rows = array(); + + $dividers = array(); + $row = array(); + foreach ($header as $k) { + $row[] = str_pad($k, $lengths[$k]); + } + $rows[] = $row; + $dividers[] = ' | '; + + $row = array(); + foreach ($header as $k) { + $row[] = str_repeat('-', $lengths[$k]); + } + $rows[] = $row; + $dividers[] = '-|-'; + + foreach ($data as $r) { + $row = array(); + foreach ($r as $k => $v) { + if (!in_array($k, $fields)) continue; + $row[$k] = str_pad($v, $lengths[$k]); + } + $rows[] = $row; + $dividers[] = ' | '; + } + + $i = 0; + $output = ''; + foreach ($rows as $row) { + $line = ''; + foreach ($row as $v) { + if ($line != '') $line .= $dividers[$i]; + $line .= $v; + } + $output .= $line . "\n"; + $i++; + } + + return $output; + } + + static private function fieldMaxLength($field, $data) { + $s = 0; + foreach ($data as $row) { + $s = max(strlen($row[$field]), $s); + } + return $s; + } + + static public function anythingToPublicArray($data) { + $output = $data; + + if ($output instanceof Collection) $output = $output->all(); + + if ($output instanceof BaseModel) { + $output = $output->toPublicArray(); + } else if (is_array($output)) { + foreach ($output as $k => $v) { + $output[$k] = self::anythingToPublicArray($v); + } + } + + return $output; + } + public function fromPublicArray($array) { foreach ($array as $k => $v) { if ($k == 'rev_id') { diff --git a/src/AppBundle/Model/Change.php b/src/AppBundle/Model/Change.php index 639fdf12c0..a3c9e0cd68 100644 --- a/src/AppBundle/Model/Change.php +++ b/src/AppBundle/Model/Change.php @@ -11,19 +11,58 @@ class Change extends BaseModel { ); static public function changesDoneAfterId($userId, $clientId, $changeId) { + // Simplification: + // + // - If create, update, delete => return nothing + // - If create, update => return last, and set type as 'create' + // - If update, update, delete, update => return 'delete' only + // - If update, update, update => return last + $limit = 100; - $items = self::where('id', '>', $changeId) + $changes = self::where('id', '>', $changeId) ->where('user_id', '=', $userId) ->where('client_id', '!=', $clientId) ->orderBy('id') ->limit($limit + 1) ->get(); - $hasMore = $limit < count($items); - if ($hasMore) array_pop($items); + + $hasMore = $limit < count($changes); + if ($hasMore) array_pop($changes); + + $itemIdToChange = array(); + $createdItems = array(); + $deletedItems = array(); + foreach ($changes as $change) { + if ($change->type == Change::enumId('type', 'create')) { + $createdItems[] = $change->item_id; + } else if ($change->type == Change::enumId('type', 'delete')) { + $deletedItems[] = $change->item_id; + } + + $itemIdToChange[$change->item_id] = $change; + } + + $output = array(); + foreach ($itemIdToChange as $itemId => $change) { + if (in_array($itemId, $createdItems) && in_array($itemId, $deletedItems)) { + // Item both created then deleted - skip + continue; + } + + if (in_array($itemId, $deletedItems)) { + // Item was deleted at some point - just return one 'delete' event + $change->type = Change::enumId('type', 'delete'); + } else if (in_array($itemId, $createdItems)) { + // Item was created then updated - just return one 'create' event with the latest changes + $change->type = Change::enumId('type', 'create'); + } + + $output[] = $change; + } return array( 'has_more' => $hasMore, - 'items' => $items, + 'items' => $output, ); } diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index c258d5f760..db344ab31c 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -26,8 +26,12 @@ class BaseTestCase extends TestCase { return $this->createModelId('client', $num); } + protected function userId($num = 1) { + return $this->createModelId('user', $num); + } + protected function user($num = 1) { - $id = $this->createModelId('user', $num); + $id = $this->userId($num); $user = User::find($id); if ($user) return $user; diff --git a/tests/Model/ChangeTest.php b/tests/Model/ChangeTest.php index 7abfe869b5..48c69d9dba 100644 --- a/tests/Model/ChangeTest.php +++ b/tests/Model/ChangeTest.php @@ -128,5 +128,44 @@ class ChangeTest extends BaseTestCase { $d = $n->toPublicArray(); $this->assertEquals(2, $d['rev_id']); } + + public function testListChanges() { + $n1 = new Note(); + $n1->fromPublicArray(array('body' => 'test')); + $n1->owner_id = $this->userId(); + $n1->save(); + + $n1->fromPublicArray(array('body' => 'test change')); + $n1->save(); + + $r = Change::changesDoneAfterId($this->userId(), $this->clientId(1), 0); + + $this->assertCount(2, $r); + $this->assertFalse($r['has_more']); + $this->assertCount(0, $r['items']); // Since client 1 is the one that made the changes, no sync data needs to be returned + + $r = Change::changesDoneAfterId($this->userId(), $this->clientId(2), 0); + + $this->assertCount(1, $r['items']); + + $n2 = new Note(); + $n2->fromPublicArray(array('body' => 'second note')); + $n2->owner_id = $this->userId(); + $n2->save(); + + $r = Change::changesDoneAfterId($this->userId(), $this->clientId(2), 0); + + $this->assertCount(2, $r['items']); + + $r = Change::changesDoneAfterId($this->userId(), $this->clientId(2), $r['items'][0]['id']); + + $this->assertCount(1, $r['items']); + + $n1->delete(); + + $r = Change::changesDoneAfterId($this->userId(), $this->clientId(2), 0); + + $this->assertCount(1, $r['items']); + } } \ No newline at end of file diff --git a/tests/setup.php b/tests/setup.php index 999458e8da..2adcca94c7 100644 --- a/tests/setup.php +++ b/tests/setup.php @@ -16,7 +16,7 @@ $capsule = new \Illuminate\Database\Capsule\Manager(); $capsule->addConnection([ 'driver' => 'mysql', 'host' => 'localhost', - 'database' => 'notes_test', + 'database' => $dbName, 'username' => 'root', 'password' => 'pass', 'charset' => 'utf8',