Skip to content

Commit 71485bd

Browse files
committed
initial rest controller, added possibility to specify valid http methods for controllers
1 parent e6e1416 commit 71485bd

File tree

9 files changed

+270
-5
lines changed

9 files changed

+270
-5
lines changed

app/base/abstracts/AdminPage.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ public function __construct(ContainerInterface $container)
5353
}
5454
}
5555

56+
/**
57+
* returns valid route HTTP verbs
58+
*
59+
* @return array
60+
*/
61+
public function getRouteVerbs()
62+
{
63+
return ['GET','POST'];
64+
}
65+
5666
/**
5767
* before render hook
5868
*
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
/**
3+
* SiteBase
4+
* PHP Version 7.0
5+
*
6+
* @category CMS / Framework
7+
* @package Degami\Sitebase
8+
* @author Mirko De Grandis <degami@github.com>
9+
* @license MIT https://opensource.org/licenses/mit-license.php
10+
* @link https://github.com/degami/sitebase
11+
*/
12+
namespace App\Base\Abstracts;
13+
14+
use \Psr\Container\ContainerInterface;
15+
use \App\App;
16+
use \App\Site\Routing\RouteInfo;
17+
use \Symfony\Component\HttpFoundation\Response;
18+
use \Symfony\Component\HttpFoundation\JsonResponse;
19+
use \Exception;
20+
21+
/**
22+
* Base for rest endopoints
23+
*/
24+
abstract class BaseRestPage extends BasePage
25+
{
26+
/**
27+
* {@inheritdocs}
28+
*
29+
* @param ContainerInterface $container
30+
*/
31+
public function __construct(ContainerInterface $container)
32+
{
33+
parent::__construct($container);
34+
$this->response = $this->getContainer()->get(JsonResponse::class);
35+
}
36+
37+
/**
38+
* returns valid route HTTP verbs
39+
*
40+
* @return array
41+
*/
42+
public function getRouteVerbs()
43+
{
44+
return ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'];
45+
}
46+
47+
/**
48+
* before render hook
49+
*
50+
* @return Response|self
51+
*/
52+
protected function beforeRender()
53+
{
54+
$return = parent::beforeRender();
55+
if ($return instanceof Response) {
56+
return $return;
57+
}
58+
59+
if ($this->getRequest()->getContentType() != 'application/json') {
60+
return $this->getUtils()->errorPage(403);
61+
}
62+
63+
return $this;
64+
}
65+
66+
/**
67+
* get Request HTTP verb
68+
*
69+
* @return string
70+
*/
71+
protected function getVerb()
72+
{
73+
return $this->getRequest()->getMethod();
74+
}
75+
76+
/**
77+
* loads object by id
78+
*
79+
* @param integer $id
80+
* @return \App\Base\Abstracts\Model
81+
*/
82+
protected function loadObject($id)
83+
{
84+
if (!is_subclass_of($this->getObjectClass(), \App\Base\Abstracts\Model::class)) {
85+
return null;
86+
}
87+
88+
return $this->getContainer()->call([$this->getObjectClass(), 'load'], [ 'id' => $id]);
89+
}
90+
91+
/**
92+
* {@inheritdocs}
93+
*
94+
* @param RouteInfo|null $route_info
95+
* @param array $route_data
96+
* @return Response
97+
*/
98+
public function process(RouteInfo $route_info = null, $route_data = [])
99+
{
100+
$return = parent::process($route_info, $route_data);
101+
102+
if (!empty($data = json_decode($this->getRequest()->getContent(), true))) {
103+
if (isset($data['id'])) {
104+
unset($data['id']);
105+
}
106+
}
107+
108+
$object = $this->getContainer()->call([$this->getObjectClass(), 'new']);
109+
if (in_array($this->getVerb(), ['GET', 'PUT', 'DELETE'])) {
110+
$object = $this->loadObject($route_data['id']);
111+
}
112+
113+
switch ($this->getVerb()) {
114+
case 'POST':
115+
case 'PUT':
116+
// Create
117+
// Update
118+
119+
$object->setData($data);
120+
$object->save();
121+
return $this
122+
->getResponse()
123+
->prepare($this->getRequest())
124+
->setData($object->getData());
125+
break;
126+
case 'GET':
127+
// Read
128+
return $this
129+
->getResponse()
130+
->prepare($this->getRequest())
131+
->setData($object->getData());
132+
break;
133+
case 'DELETE':
134+
// Delete
135+
$old_data = $object->getData();
136+
unset($old_data['id']);
137+
$object->delete();
138+
139+
return $this
140+
->getResponse()
141+
->prepare($this->getRequest())
142+
->setData($old_data);
143+
break;
144+
}
145+
146+
return $return;
147+
}
148+
149+
/**
150+
* gets object class name for method
151+
*
152+
* @return string
153+
*/
154+
abstract public static function getObjectClass();
155+
}

app/site/controllers/Frontend/ContactForm.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ public static function getRoutePath()
7070
return 'contact/{id:\d+}';
7171
}
7272

73+
/**
74+
* returns valid route HTTP verbs
75+
*
76+
* @return array
77+
*/
78+
public function getRouteVerbs()
79+
{
80+
return ['GET', 'POST'];
81+
}
82+
7383
/**
7484
* {@inheritdocs}
7585
*

app/site/controllers/Frontend/Links.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ public static function getRouteGroup()
3939
return '';
4040
}
4141

42+
/**
43+
* returns valid route HTTP verbs
44+
*
45+
* @return array
46+
*/
47+
public function getRouteVerbs()
48+
{
49+
return ['GET','POST'];
50+
}
51+
4252
/**
4353
* return route path
4454
*
@@ -153,7 +163,7 @@ public function formValidate(FAPI\Form $form, &$form_state)
153163
public function formSubmitted(FAPI\Form $form, &$form_state)
154164
{
155165
$values = $form->getValues();
156-
166+
157167
$link = $this->getContainer()->call([LinkExchange::class, 'new']);
158168
$link->url = $values->url;
159169
$link->email = $values->email;

app/site/controllers/Frontend/Login.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ public static function getRoutePath()
5252
return 'login';
5353
}
5454

55+
/**
56+
* returns valid route HTTP verbs
57+
*
58+
* @return array
59+
*/
60+
public function getRouteVerbs()
61+
{
62+
return ['GET','POST'];
63+
}
64+
5565
/**
5666
* {@inheritdocs}
5767
*

app/site/controllers/Frontend/NewsDetail.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ public static function getRoutePath()
3535
return 'news/{id:\d+}';
3636
}
3737

38+
/**
39+
* returns valid route HTTP verbs
40+
*
41+
* @return array
42+
*/
43+
public function getRouteVerbs()
44+
{
45+
return ['GET'];
46+
}
47+
3848
/**
3949
* {@inheritdocs}
4050
*

app/site/controllers/Frontend/Page.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ public static function getRoutePath()
3535
return 'page/{id:\d+}';
3636
}
3737

38+
/**
39+
* returns valid route HTTP verbs
40+
*
41+
* @return array
42+
*/
43+
public function getRouteVerbs()
44+
{
45+
return ['GET'];
46+
}
47+
3848
/**
3949
* {@inheritdocs}
4050
*

app/site/controllers/Frontend/Taxonomy.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ public static function getRoutePath()
3434
return 'taxonomy/{id:\d+}';
3535
}
3636

37+
/**
38+
* returns valid route HTTP verbs
39+
*
40+
* @return array
41+
*/
42+
public function getRouteVerbs()
43+
{
44+
return ['GET'];
45+
}
46+
3747
/**
3848
* {@inheritdocs}
3949
*

app/site/routing/Web.php

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
*/
2727
class Web extends ContainerAwareObject
2828
{
29+
const CLASS_METHOD = 'renderPage';
30+
const HTTP_VERBS = ['GET', 'POST'];
31+
2932
/**
3033
* @var Dispatcher dispatcher
3134
*/
@@ -57,6 +60,9 @@ public function __construct(ContainerInterface $container)
5760
$path = str_replace("app/site/controllers/", "", str_replace("\\", "/", strtolower($controllerClass)));
5861
$route_name = str_replace("/", ".", trim($path, "/"));
5962

63+
$classMethod = self::CLASS_METHOD;
64+
$verbs = self::HTTP_VERBS;
65+
6066
if (($tmp = explode("/", $path, 2)) && count($tmp) > 1) {
6167
$tmp = array_map(
6268
function ($el) {
@@ -78,14 +84,24 @@ function ($el) {
7884
$group = call_user_func([$controllerClass, 'getRouteGroup']) ?? $group;
7985
}
8086

87+
if (method_exists($controllerClass, 'getRouteVerbs')) {
88+
$verbs = call_user_func([$controllerClass, 'getRouteVerbs']) ?? $verbs;
89+
if (!is_array($verbs)) {
90+
$verbs = [$verbs];
91+
}
92+
if (!empty($errors = $this->checkRouteVerbs($verbs))) {
93+
throw new InvalidValueException(implode(',', $errors).": Invalid route verbs", 1);
94+
}
95+
}
96+
8197
if (method_exists($controllerClass, 'getRoutePath')) {
8298
$path = call_user_func([$controllerClass, 'getRoutePath']) ?? $path;
8399
if (!$this->checkRouteParameters($path)) {
84100
throw new InvalidValueException("'{$path}': Invalid route string", 1);
85101
}
86102
}
87103

88-
$this->addRoute($group, $route_name, "/".ltrim($path, "/ "), $controllerClass);
104+
$this->addRoute($group, $route_name, "/".ltrim($path, "/ "), $controllerClass, $classMethod, $verbs);
89105
}
90106
}
91107

@@ -123,6 +139,24 @@ protected function checkRouteParameters($route)
123139
return true;
124140
}
125141

142+
/**
143+
* checks route http verbs
144+
*
145+
* @param array $verbs
146+
* @return array
147+
*/
148+
protected function checkRouteVerbs($verbs)
149+
{
150+
if (!is_array($verbs)) {
151+
$verbs = [$verbs];
152+
}
153+
154+
return array_diff(
155+
array_filter(array_map('strtoupper', array_map('trim', $verbs))),
156+
['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT']
157+
);
158+
}
159+
126160
/**
127161
* adds routes
128162
*
@@ -148,7 +182,7 @@ private function _insertRoutes(RouteCollector $r, array $paths)
148182
*/
149183
private function _insertRoute(RouteCollector $r, array $p)
150184
{
151-
$r->addRoute(['GET','POST'], $p['path'], [$p['class'], $p['method']]);
185+
$r->addRoute($p['verbs'], $p['path'], [$p['class'], $p['method']]);
152186

153187
return $this;
154188
}
@@ -185,9 +219,15 @@ function ($el) use ($class) {
185219
* @param string $class
186220
* @param string $method
187221
*/
188-
public function addRoute($group, $name, $path, $class, $method = 'renderPage')
222+
public function addRoute($group, $name, $path, $class, $method = 'renderPage', $verbs = ['GET', 'POST'])
189223
{
190-
$this->routes[$group][] = ['path' => $path, 'class' => $class, 'method' => $method, 'name' => $name];
224+
$this->routes[$group][] = [
225+
'path' => $path,
226+
'class' => $class,
227+
'method' => $method,
228+
'name' => $name,
229+
'verbs' => $verbs
230+
];
191231
return $this;
192232
}
193233

0 commit comments

Comments
 (0)