Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Commit 14955c3

Browse files
committed
support custom parameter naming for model ID
1 parent 665b773 commit 14955c3

File tree

11 files changed

+248
-27
lines changed

11 files changed

+248
-27
lines changed

src/generator/ApiGenerator.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ protected function generateUrls()
349349
$action = [];
350350
$params = false;
351351
$actionParams = [];
352+
$idParam = null;
352353
foreach ($parts as $p => $part) {
353354
if (preg_match('/\{(.*)\}/', $part, $m)) {
354355
$params = true;
@@ -358,6 +359,9 @@ protected function generateUrls()
358359
} else {
359360
$actionParams[$m[1]] = null;
360361
}
362+
if ($idParam === null && preg_match('/\bid\b/i', Inflector::camel2id($m[1]))) {
363+
$idParam = $m[1];
364+
}
361365
// TODO add regex to param based on openAPI type
362366
} elseif ($params) {
363367
$action[] = $part;
@@ -395,6 +399,7 @@ protected function generateUrls()
395399
'pattern' => $pattern,
396400
'route' => "$controller/$a$action",
397401
'actionParams' => $actionParams,
402+
'idParam' => $idParam,
398403
'openApiOperation' => $operation,
399404
'modelClass' => $modelClass !== null ? $this->modelNamespace . '\\' . $modelClass : null,
400405
'responseWrapper' => $responseWrapper,
@@ -566,6 +571,7 @@ protected function generateControllers()
566571
$c[$parts[0]][] = [
567572
'id' => $parts[1],
568573
'params' => array_keys($url['actionParams']),
574+
'idParam' => $url['idParam'] ?? null,
569575
'modelClass' => $url['modelClass'],
570576
'responseWrapper' => $url['responseWrapper'],
571577
];

src/generator/default/controller.php

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,49 @@
11
<?php echo '<?php';
22

33
$modelActions = [
4-
'index' => yii\rest\IndexAction::class,
5-
'view' => yii\rest\ViewAction::class,
6-
'create' => yii\rest\CreateAction::class,
7-
'update' => yii\rest\UpdateAction::class,
8-
'delete' => yii\rest\UpdateAction::class,
4+
'index' => [
5+
'class' => yii\rest\IndexAction::class,
6+
],
7+
'view' => [
8+
'class' => yii\rest\ViewAction::class,
9+
'implementation' => <<<'PHP'
10+
$model = $this->findModel($id);
11+
$this->checkAccess(ACTION_ID, $model);
12+
return $model;
13+
PHP
14+
],
15+
'create' => [
16+
'class' => yii\rest\CreateAction::class,
17+
],
18+
'update' => [
19+
'class' => yii\rest\UpdateAction::class,
20+
'implementation' => <<<'PHP'
21+
$model = $this->findModel($id);
22+
$this->checkAccess(ACTION_ID, $model);
23+
24+
$model->load(Yii::$app->getRequest()->getBodyParams(), '');
25+
if ($model->save() === false && !$model->hasErrors()) {
26+
throw new ServerErrorHttpException('Failed to update the object for unknown reason.');
27+
}
28+
29+
return $model;
30+
PHP
31+
],
32+
'delete' => [
33+
'class' => yii\rest\DeleteAction::class,
34+
'implementation' => <<<'PHP'
35+
$model = $this->findModel($id);
36+
$this->checkAccess(ACTION_ID, $model);
37+
38+
if ($model->delete() === false) {
39+
throw new ServerErrorHttpException('Failed to delete the object for unknown reason.');
40+
}
41+
42+
\Yii::$app->response->setStatusCode(204);
43+
PHP
44+
],
945
];
46+
$findModel = [];
1047

1148
?>
1249

@@ -21,9 +58,9 @@ public function actions()
2158
<?php
2259

2360
foreach ($actions as $action):
24-
if (isset($modelActions[$action['id']], $action['modelClass'])): ?>
61+
if (isset($modelActions[$action['id']], $action['modelClass']) && ($action['idParam'] === null || $action['idParam'] === 'id')): ?>
2562
<?= var_export($action['id'], true) ?> => [
26-
'class' => \<?= $modelActions[$action['id']] ?>::class,
63+
'class' => \<?= $modelActions[$action['id']]['class'] ?>::class,
2764
'modelClass' => <?= '\\' . $action['modelClass'] . '::class' ?>,
2865
'checkAccess' => [$this, 'checkAccess'],
2966
],
@@ -84,23 +121,49 @@ public function checkAccess($action, $model = null, $params = [])
84121
{
85122
// TODO implement checkAccess
86123
}
87-
88124
<?php
89125
foreach ($actions as $action):
90126
if (isset($modelActions[$action['id']], $action['modelClass'])) {
91-
continue;
127+
if ($action['idParam'] === null || $action['idParam'] === 'id') {
128+
continue;
129+
}
130+
if (isset($modelActions[$action['id']]['implementation'])) {
131+
$implementation = $modelActions[$action['id']]['implementation'];
132+
$findModel[$action['modelClass']] = 'find' . \yii\helpers\StringHelper::basename($action['modelClass']) . 'Model';
133+
$implementation = str_replace('findModel', $findModel[$action['modelClass']], $implementation);
134+
$implementation = str_replace('$id', '$'.$action['idParam'], $implementation);
135+
$implementation = str_replace('ACTION_ID', var_export($action['id'], true), $implementation);
136+
}
92137
}
93138

94139
$actionName = 'action' . \yii\helpers\Inflector::id2camel($action['id']);
95140
$actionParams = implode(', ', array_map(function ($p) {
96141
return "\$$p";
97142
}, $action['params']));
98143
?>
144+
99145
public function <?= $actionName ?>(<?= $actionParams ?>)
100146
{
101-
// TODO implement <?= $actionName ?>
147+
<?= $implementation ?? ' // TODO implement ' . $actionName ?>
102148

103149
}
150+
<?php endforeach; ?>
151+
<?php foreach($findModel as $modelName => $methodName): ?>
104152

153+
/**
154+
* Returns the <?= \yii\helpers\StringHelper::basename($modelName) ?> model based on the primary key given.
155+
* If the data model is not found, a 404 HTTP exception will be raised.
156+
* @param string $id the ID of the model to be loaded.
157+
* @return \<?= $modelName ?> the model found
158+
* @throws NotFoundHttpException if the model cannot be found.
159+
*/
160+
public function <?= $methodName ?>($id)
161+
{
162+
$model = \<?= $modelName ?>::findOne($id);
163+
if ($model !== null) {
164+
return $model;
165+
}
166+
throw new NotFoundHttpException("Object not found: $id");
167+
}
105168
<?php endforeach; ?>
106169
}

tests/specs/petstore.yaml

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ paths:
5353
application/json:
5454
schema:
5555
$ref: "#/components/schemas/Error"
56-
/pets/{petId}:
56+
/pets/{id}:
5757
get:
5858
summary: Info for a specific pet
5959
operationId: showPetById
6060
tags:
6161
- pets
6262
parameters:
63-
- name: petId
63+
- name: id
6464
in: path
6565
required: true
6666
description: The id of the pet to retrieve
@@ -79,6 +79,41 @@ paths:
7979
application/json:
8080
schema:
8181
$ref: "#/components/schemas/Error"
82+
patch:
83+
summary: update a specific pet
84+
operationId: updatePetById
85+
tags:
86+
- pets
87+
parameters:
88+
- name: id
89+
in: path
90+
required: true
91+
description: The id of the pet to update
92+
schema:
93+
type: string
94+
responses:
95+
'200':
96+
description: The updated pet
97+
content:
98+
application/json:
99+
schema:
100+
$ref: "#/components/schemas/Pet"
101+
delete:
102+
summary: delete a specific pet
103+
operationId: deletePetById
104+
tags:
105+
- pets
106+
parameters:
107+
- name: id
108+
in: path
109+
required: true
110+
description: The id of the pet to delete
111+
schema:
112+
type: string
113+
responses:
114+
'204':
115+
description: successfully deleted pet
116+
82117
components:
83118
schemas:
84119
Pet:

tests/specs/petstore/config/urls.rest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@
77
return array (
88
'GET pets' => 'pet/index',
99
'POST pets' => 'pet/create',
10-
'GET pets/<petId>' => 'pet/view',
10+
'GET pets/<id>' => 'pet/view',
11+
'DELETE pets/<id>' => 'pet/delete',
12+
'PATCH pets/<id>' => 'pet/update',
1113
);

tests/specs/petstore/controllers/PetController.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ public function actions()
2222
'modelClass' => \app\models\Pet::class,
2323
'checkAccess' => [$this, 'checkAccess'],
2424
],
25+
'delete' => [
26+
'class' => \yii\rest\DeleteAction::class,
27+
'modelClass' => \app\models\Pet::class,
28+
'checkAccess' => [$this, 'checkAccess'],
29+
],
30+
'update' => [
31+
'class' => \yii\rest\UpdateAction::class,
32+
'modelClass' => \app\models\Pet::class,
33+
'checkAccess' => [$this, 'checkAccess'],
34+
],
2535
'options' => [
2636
'class' => \yii\rest\OptionsAction::class,
2737
],
@@ -44,5 +54,4 @@ public function checkAccess($action, $model = null, $params = [])
4454
{
4555
// TODO implement checkAccess
4656
}
47-
4857
}

tests/specs/petstore_arrayref.yaml

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ paths:
3030
schema:
3131
type: string
3232
content:
33-
application/json:
33+
application/json:
3434
schema:
3535
$ref: "#/components/schemas/Pets"
3636
default:
@@ -75,6 +75,40 @@ paths:
7575
application/json:
7676
schema:
7777
$ref: "#/components/schemas/Error"
78+
patch:
79+
summary: update a specific pet
80+
operationId: updatePetById
81+
tags:
82+
- pets
83+
parameters:
84+
- name: petId
85+
in: path
86+
required: true
87+
description: The id of the pet to update
88+
schema:
89+
type: string
90+
responses:
91+
'200':
92+
description: The updated pet
93+
content:
94+
application/json:
95+
schema:
96+
$ref: "#/components/schemas/Pet"
97+
delete:
98+
summary: delete a specific pet
99+
operationId: deletePetById
100+
tags:
101+
- pets
102+
parameters:
103+
- name: petId
104+
in: path
105+
required: true
106+
description: The id of the pet to delete
107+
schema:
108+
type: string
109+
responses:
110+
'204':
111+
description: successfully deleted pet
78112
components:
79113
schemas:
80114
Pet:

tests/specs/petstore_arrayref/config/urls.rest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88
'GET pets' => 'pet/index',
99
'POST pets' => 'pet/create',
1010
'GET pets/<petId>' => 'pet/view',
11+
'DELETE pets/<petId>' => 'pet/delete',
12+
'PATCH pets/<petId>' => 'pet/update',
1113
);

tests/specs/petstore_arrayref/controllers/PetController.php

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ public function actions()
1717
'modelClass' => \app\models\Pet::class,
1818
'checkAccess' => [$this, 'checkAccess'],
1919
],
20-
'view' => [
21-
'class' => \yii\rest\ViewAction::class,
22-
'modelClass' => \app\models\Pet::class,
23-
'checkAccess' => [$this, 'checkAccess'],
24-
],
2520
'options' => [
2621
'class' => \yii\rest\OptionsAction::class,
2722
],
@@ -45,4 +40,51 @@ public function checkAccess($action, $model = null, $params = [])
4540
// TODO implement checkAccess
4641
}
4742

43+
public function actionView($petId)
44+
{
45+
$model = $this->findPetModel($petId);
46+
$this->checkAccess('view', $model);
47+
return $model;
48+
}
49+
50+
public function actionDelete($petId)
51+
{
52+
$model = $this->findPetModel($petId);
53+
$this->checkAccess('delete', $model);
54+
55+
if ($model->delete() === false) {
56+
throw new ServerErrorHttpException('Failed to delete the object for unknown reason.');
57+
}
58+
59+
\Yii::$app->response->setStatusCode(204);
60+
}
61+
62+
public function actionUpdate($petId)
63+
{
64+
$model = $this->findPetModel($petId);
65+
$this->checkAccess('update', $model);
66+
67+
$model->load(Yii::$app->getRequest()->getBodyParams(), '');
68+
if ($model->save() === false && !$model->hasErrors()) {
69+
throw new ServerErrorHttpException('Failed to update the object for unknown reason.');
70+
}
71+
72+
return $model;
73+
}
74+
75+
/**
76+
* Returns the Pet model based on the primary key given.
77+
* If the data model is not found, a 404 HTTP exception will be raised.
78+
* @param string $id the ID of the model to be loaded.
79+
* @return \app\models\Pet the model found
80+
* @throws NotFoundHttpException if the model cannot be found.
81+
*/
82+
public function findPetModel($id)
83+
{
84+
$model = \app\models\Pet::findOne($id);
85+
if ($model !== null) {
86+
return $model;
87+
}
88+
throw new NotFoundHttpException("Object not found: $id");
89+
}
4890
}

tests/specs/petstore_namespace/config/rest-urls.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@
77
return array (
88
'GET pets' => 'pet/index',
99
'POST pets' => 'pet/create',
10-
'GET pets/<petId>' => 'pet/view',
10+
'GET pets/<id>' => 'pet/view',
11+
'DELETE pets/<id>' => 'pet/delete',
12+
'PATCH pets/<id>' => 'pet/update',
1113
);

tests/specs/petstore_namespace/mycontrollers/PetController.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ public function actions()
2222
'modelClass' => \app\mymodels\Pet::class,
2323
'checkAccess' => [$this, 'checkAccess'],
2424
],
25+
'delete' => [
26+
'class' => \yii\rest\DeleteAction::class,
27+
'modelClass' => \app\mymodels\Pet::class,
28+
'checkAccess' => [$this, 'checkAccess'],
29+
],
30+
'update' => [
31+
'class' => \yii\rest\UpdateAction::class,
32+
'modelClass' => \app\mymodels\Pet::class,
33+
'checkAccess' => [$this, 'checkAccess'],
34+
],
2535
'options' => [
2636
'class' => \yii\rest\OptionsAction::class,
2737
],
@@ -44,5 +54,4 @@ public function checkAccess($action, $model = null, $params = [])
4454
{
4555
// TODO implement checkAccess
4656
}
47-
4857
}

0 commit comments

Comments
 (0)