From 2d85f3eb3670283ee80ff8dff0d161f1822a2ec8 Mon Sep 17 00:00:00 2001 From: PhilippGrashoff <33204878+PhilippGrashoff@users.noreply.github.com> Date: Tue, 21 May 2019 00:07:57 +0200 Subject: [PATCH 1/2] Fix data#403 This is supposed as proposal to fix https://github.com/atk4/data/issues/403 going with the solution @DarkSide666 proposed. This change routs all GET requests (single record and multiple record as well) through exportModel() function, with uses Model->export() while typecasting set to false. This way, date, time and datetime fields are not cast into PHP \DateTime objects, but the values are returned as stored in Persistence. The solution posted here works for the mentioned date/time fields, however I see some problems: 1) what about fields that should get casting? In the end, API should return usable values. E.g about type money? API should return them as formatted to display 2 digits after the dot, shouldnt it? Is this still done? 2) getting a single record should throw an Exception when the requested record is not found. For that, it has to be loaded(). export() in exportModel() loads again, causing an unneccessary DB request. --- src/Api.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Api.php b/src/Api.php index e917eb5..6a8a6ea 100644 --- a/src/Api.php +++ b/src/Api.php @@ -22,6 +22,14 @@ class Api /** @var string Request path */ public $path; + /** + * @var bool If set to true, the first array element of Model->export + * will be returned (GET single record) + * If not, the array will be returned as-is + */ + public $singleRecord = false; + + /** * Reads everything off globals. * @@ -178,7 +186,13 @@ protected function call($callable, $vars = []) */ protected function exportModel(\atk4\data\Model $m) { - return $m->export($this->getAllowedFields($m, 'read')); + //on single record request, return first array element if available or null + if($this->singleRecord) { + $records = $m->export($this->getAllowedFields($m, 'read'), null, false); + return $records ? reset($records) : null; + } + //else return array + return $m->export($this->getAllowedFields($m, 'read'), null, false); } /** @@ -407,9 +421,12 @@ public function rest($pattern, $model = null, $methods = null) // limit fields $model->onlyFields($this->getAllowedFields($model, 'read')); + $model->addCondition($model->id_field, $id); + $this->loadModelByValue($model, $id); + $this->singleRecord = true; // load model and get field values - return $this->loadModelByValue($model, $id)->get(); + return $model; }; $this->get($pattern.'/:id', $f); } From f97a75025fea96081da50f705b6693acbd500134 Mon Sep 17 00:00:00 2001 From: PhilippGrashoff <33204878+PhilippGrashoff@users.noreply.github.com> Date: Tue, 21 May 2019 00:26:42 +0200 Subject: [PATCH 2/2] Improve by using Field->toString() on singleRecord --- src/Api.php | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/Api.php b/src/Api.php index 6a8a6ea..f961e2f 100644 --- a/src/Api.php +++ b/src/Api.php @@ -22,13 +22,6 @@ class Api /** @var string Request path */ public $path; - /** - * @var bool If set to true, the first array element of Model->export - * will be returned (GET single record) - * If not, the array will be returned as-is - */ - public $singleRecord = false; - /** * Reads everything off globals. @@ -186,12 +179,6 @@ protected function call($callable, $vars = []) */ protected function exportModel(\atk4\data\Model $m) { - //on single record request, return first array element if available or null - if($this->singleRecord) { - $records = $m->export($this->getAllowedFields($m, 'read'), null, false); - return $records ? reset($records) : null; - } - //else return array return $m->export($this->getAllowedFields($m, 'read'), null, false); } @@ -419,15 +406,26 @@ public function rest($pattern, $model = null, $methods = null) $model = $this->call($model, $args); } - // limit fields - $model->onlyFields($this->getAllowedFields($model, 'read')); - $model->addCondition($model->id_field, $id); $this->loadModelByValue($model, $id); - $this->singleRecord = true; - // load model and get field values - return $model; + //calculate only once + $allowed_fields = $this->getAllowedFields($model, 'read'); + $data = []; + // get all field-elements + foreach ($model->elements as $field => $f) { + //only use allowed fields + if(!in_array($field, $allowed_fields)) { + continue; + } + + if ($f instanceof \atk4\data\Field) { + $data[$field] = $f->toString(); + } + } + + return $data; }; + $this->get($pattern.'/:id', $f); }