diff --git a/README.md b/README.md index 63a998f..78efd0d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Issue Count](https://codeclimate.com/github/atk4/api/badges/issue_count.svg)](https://codeclimate.com/github/atk4/api/issues) [![License](https://poser.pugx.org/atk4/api/license)](https://packagist.org/packages/atk4/api) -[![GitHub release](https://img.shields.io/github/release/atk4/api.svg?maxAge=2592000)](https://packagist.org/packages/atk4/api) +[![GitHub release](https://img.shields.io/github/release/atk4/api.svg)](https://packagist.org/packages/atk4/api) End-to-end implementation for your RESTful API and RPC. Provides a very simple means for you to define API end-points for the application that already uses [Agile Data](https://github.com/atk4/data). @@ -26,7 +26,7 @@ $api->get('/ping', function() { }); // Methods can accept arguments, and everything is type-safe. -$api->get('/hello/:name', function (name) { +$api->get('/ping/:name', function (name) { return "Hello, $name"; }); ``` diff --git a/examples/test.php b/examples/test.php index 06093dd..0cafb49 100644 --- a/examples/test.php +++ b/examples/test.php @@ -3,52 +3,6 @@ include '../vendor/autoload.php'; $api = new \atk4\api\Api(); - -class Country extends \atk4\data\Model -{ - public $table = 'country'; - - public function init() - { - parent::init(); - $this->addField('name', ['actual'=>'nicename', 'required'=>true, 'type'=>'string']); - $this->addField('sys_name', ['actual'=>'name', 'system'=>true]); - - $this->addField('iso', ['caption'=>'ISO', 'required'=>true, 'type'=>'string']); - $this->addField('iso3', ['caption'=>'ISO3', 'required'=>true, 'type'=>'string']); - $this->addField('numcode', ['caption'=>'ISO Numeric Code', 'type'=>'number', 'required'=>true]); - $this->addField('phonecode', ['caption'=>'Phone Prefix', 'type'=>'number']); - - $this->addHook('beforeSave', function ($m) { - if (!$m['sys_name']) { - $m['sys_name'] = strtoupper($m['name']); - } - }); - } - - public function validate($intent = null) - { - $errors = parent::validate($intent); - - if (strlen($this['iso']) !== 2) { - $errors['iso'] = 'Must be exactly 2 characters'; - } - - if (strlen($this['iso3']) !== 3) { - $errors['iso3'] = 'Must be exactly 3 characters'; - } - - // look if name is unique - $c = clone $this; - $c->unload(); - $c->tryLoadBy('name', $this['name']); - if ($c->loaded() && $c->id != $this->id) { - $errors['name'] = 'Country name must be unique'; - } - - return $errors; - } -} session_start(); $db = new \atk4\data\Persistence_SQL('mysql:dbname=atk4;host=localhost', 'root', ''); @@ -59,4 +13,15 @@ public function validate($intent = null) return "Hello, $hello"; }); -$api->rest('/client', new Country($db)); +// Basic usage of REST client +$api->rest('/clients', new \atk4\api\tests\Country($db)); + +// Tweak our model accordingly +$api->rest('/clients2', function () use ($db) { + $c = new \atk4\api\tests\Country($db); + $c->setLimit(10); + $c->setOrder('name'); + $c->addCondition('id', '<', 100); + + return $c; +}); diff --git a/src/Api.php b/src/Api.php index 5318064..6aae97a 100644 --- a/src/Api.php +++ b/src/Api.php @@ -7,6 +7,8 @@ */ class Api { + use \atk4\core\AppScopeTrait; + /** @var \Zend\Diactoros\ServerRequest Request object */ public $request; @@ -404,6 +406,27 @@ public function rest($pattern, $model = null) $this->delete($pattern.'/:id', $f); } + public function prepareModel($model) + { + if (!$model) { + throw new Exception(['Model must be specified', 'model'=>$model]); + } + + if (is_callable($model)) { + $model = call_user_func($model); + } elseif (!is_object($model)) { + if ($this->api) { + return $this->api->factory($model); + } + } + + if (!$model) { + throw new Exception(['Model value is incorrect', 'model'=>$model]); + } + + return $model; + } + /** * Our own exception handling. * diff --git a/tests/Client.php b/tests/Client.php new file mode 100644 index 0000000..055be76 --- /dev/null +++ b/tests/Client.php @@ -0,0 +1,19 @@ +addField('name'); + + $this->hasMany('Invoices', new Invoice()); + + $this->hasMany('InvoicesDue', (new Invoice($this->persistence))->addCondition('is_paid', false)) + ->addField('total_due', ['aggregate'=>'sum', 'field'=>'total']); + } +} diff --git a/tests/Country.php b/tests/Country.php new file mode 100644 index 0000000..aba9c13 --- /dev/null +++ b/tests/Country.php @@ -0,0 +1,49 @@ +addField('name', ['actual'=>'nicename', 'required'=>true, 'type'=>'string']); + $this->addField('sys_name', ['actual'=>'name', 'system'=>true]); + + $this->addField('iso', ['caption'=>'ISO', 'required'=>true, 'type'=>'string']); + $this->addField('iso3', ['caption'=>'ISO3', 'required'=>true, 'type'=>'string']); + $this->addField('numcode', ['caption'=>'ISO Numeric Code', 'type'=>'number', 'required'=>true]); + $this->addField('phonecode', ['caption'=>'Phone Prefix', 'type'=>'number']); + + $this->addHook('beforeSave', function ($m) { + if (!$m['sys_name']) { + $m['sys_name'] = strtoupper($m['name']); + } + }); + } + + public function validate($intent = null) + { + $errors = parent::validate($intent); + + if (strlen($this['iso']) !== 2) { + $errors['iso'] = 'Must be exactly 2 characters'; + } + + if (strlen($this['iso3']) !== 3) { + $errors['iso3'] = 'Must be exactly 3 characters'; + } + + // look if name is unique + $c = clone $this; + $c->unload(); + $c->tryLoadBy('name', $this['name']); + if ($c->loaded() && $c->id != $this->id) { + $errors['name'] = 'Country name must be unique'; + } + + return $errors; + } +} diff --git a/tests/Invoice.php b/tests/Invoice.php new file mode 100644 index 0000000..59ea19a --- /dev/null +++ b/tests/Invoice.php @@ -0,0 +1,22 @@ +addField('ref_no'); + + $this->hasOne('client_id', new Client()); + $this->addField('is_paid', ['type'=>'boolean', 'default'=>false]); + $this->addField('is_shipped', ['type'=>'boolean', 'default'=>false]); + + $this->hasMany('Lines', new Line()) + ->addField('total', ['aggregate'=>'sum']); + } +} diff --git a/tests/Line.php b/tests/Line.php new file mode 100644 index 0000000..3d49f1f --- /dev/null +++ b/tests/Line.php @@ -0,0 +1,18 @@ +addField('ref_no'); + + $this->hasOne('client_id', new Client()); + $this->hasMany('Lines', new self()) + ->addField('total', ['aggregate'=>'sum']); + } +}