Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

362 lines
9.5 KiB

  1. <?php
  2. declare(strict_types=1);
  3. namespace Grav\Plugin\FlexObjects\Controllers;
  4. use Grav\Common\Config\Config;
  5. use Grav\Common\Grav;
  6. use Grav\Common\Inflector;
  7. use Grav\Common\Language\Language;
  8. use Grav\Common\Session;
  9. use Grav\Common\Uri;
  10. use Grav\Common\User\Interfaces\UserInterface;
  11. use Grav\Common\Utils;
  12. use Grav\Framework\Controller\Traits\ControllerResponseTrait;
  13. use Grav\Framework\Flex\FlexDirectory;
  14. use Grav\Framework\Flex\FlexForm;
  15. use Grav\Framework\Flex\FlexFormFlash;
  16. use Grav\Framework\Flex\Interfaces\FlexFormInterface;
  17. use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
  18. use Grav\Framework\Psr7\Response;
  19. use Grav\Framework\RequestHandler\Exception\NotFoundException;
  20. use Grav\Framework\RequestHandler\Exception\PageExpiredException;
  21. use Grav\Framework\Route\Route;
  22. use Grav\Plugin\FlexObjects\Flex;
  23. use Grav\Plugin\Form\Forms;
  24. use Psr\Http\Message\ResponseInterface;
  25. use Psr\Http\Message\ServerRequestInterface;
  26. use Psr\Http\Server\RequestHandlerInterface;
  27. use RocketTheme\Toolbox\Event\Event;
  28. use RocketTheme\Toolbox\Session\Message;
  29. use function in_array;
  30. use function is_callable;
  31. /**
  32. * Class AbstractController
  33. * @package Grav\Plugin\FlexObjects\Controllers
  34. */
  35. abstract class AbstractController implements RequestHandlerInterface
  36. {
  37. use ControllerResponseTrait;
  38. /** @var string */
  39. protected $nonce_action = 'flex-object';
  40. /** @var string */
  41. protected $nonce_name = 'nonce';
  42. /** @var ServerRequestInterface */
  43. protected $request;
  44. /** @var Grav */
  45. protected $grav;
  46. /** @var UserInterface|null */
  47. protected $user;
  48. /** @var string */
  49. protected $type;
  50. /** @var string */
  51. protected $key;
  52. /** @var FlexDirectory */
  53. protected $directory;
  54. /** @var FlexObjectInterface */
  55. protected $object;
  56. /**
  57. * Handle request.
  58. *
  59. * Fires event: flex.[directory].[task|action].[command]
  60. *
  61. * @param ServerRequestInterface $request
  62. * @return Response
  63. */
  64. public function handle(ServerRequestInterface $request): ResponseInterface
  65. {
  66. $attributes = $request->getAttributes();
  67. $this->request = $request;
  68. $this->grav = $attributes['grav'] ?? Grav::instance();
  69. $this->type = $attributes['type'] ?? null;
  70. $this->key = $attributes['key'] ?? null;
  71. if ($this->type) {
  72. $this->directory = $this->getFlex()->getDirectory($this->type);
  73. $this->object = $attributes['object'] ?? null;
  74. if (!$this->object && $this->key && $this->directory) {
  75. $this->object = $this->directory->getObject($this->key) ?? $this->directory->createObject([], $this->key ?? '');
  76. if (is_callable([$this->object, 'refresh'])) {
  77. $this->object->refresh();
  78. }
  79. }
  80. }
  81. /** @var Route $route */
  82. $route = $attributes['route'];
  83. $post = $this->getPost();
  84. if ($this->isFormSubmit()) {
  85. $form = $this->getForm();
  86. $this->nonce_name = $attributes['nonce_name'] ?? $form->getNonceName();
  87. $this->nonce_action = $attributes['nonce_action'] ?? $form->getNonceAction();
  88. }
  89. try {
  90. $task = $request->getAttribute('task') ?? $post['task'] ?? $route->getParam('task');
  91. if ($task) {
  92. if (empty($attributes['forwarded'])) {
  93. $this->checkNonce($task);
  94. }
  95. $type = 'task';
  96. $command = $task;
  97. } else {
  98. $type = 'action';
  99. $command = $request->getAttribute('action') ?? $post['action'] ?? $route->getParam('action') ?? 'display';
  100. }
  101. $command = strtolower($command);
  102. $event = new Event(
  103. [
  104. 'controller' => $this,
  105. 'response' => null
  106. ]
  107. );
  108. $this->grav->fireEvent("flex.{$this->type}.{$type}.{$command}", $event);
  109. $response = $event['response'];
  110. if (!$response) {
  111. /** @var Inflector $inflector */
  112. $inflector = $this->grav['inflector'];
  113. $method = $type . $inflector::camelize($command);
  114. if ($method && method_exists($this, $method)) {
  115. $response = $this->{$method}($request);
  116. } else {
  117. throw new NotFoundException($request);
  118. }
  119. }
  120. } catch (\Exception $e) {
  121. $response = $this->createErrorResponse($e);
  122. }
  123. if ($response instanceof Response) {
  124. return $response;
  125. }
  126. return $this->createJsonResponse($response);
  127. }
  128. /**
  129. * @return ServerRequestInterface
  130. */
  131. public function getRequest(): ServerRequestInterface
  132. {
  133. return $this->request;
  134. }
  135. /**
  136. * @param string|null $name
  137. * @param mixed $default
  138. * @return mixed
  139. */
  140. public function getPost(string $name = null, $default = null)
  141. {
  142. $body = $this->request->getParsedBody();
  143. if ($name) {
  144. return $body[$name] ?? $default;
  145. }
  146. return $body;
  147. }
  148. /**
  149. * @return bool
  150. */
  151. public function isFormSubmit(): bool
  152. {
  153. return (bool)$this->getPost('__form-name__');
  154. }
  155. /**
  156. * @param string|null $type
  157. * @return FlexForm
  158. */
  159. public function getForm(string $type = null): FlexFormInterface
  160. {
  161. $object = $this->getObject();
  162. if (!$object) {
  163. throw new \RuntimeException('Not Found', 404);
  164. }
  165. $formName = $this->getPost('__form-name__');
  166. if ($formName) {
  167. /** @var Forms $forms */
  168. $forms = $this->getGrav()['forms'];
  169. $form = $forms->getActiveForm();
  170. if ($form instanceof FlexForm && $form->getName() === $formName && $form->getObject()->getFlexKey() === $object->getFlexKey()) {
  171. return $form;
  172. }
  173. }
  174. return $object->getForm($type ?? 'edit');
  175. }
  176. /**
  177. * @param FlexObjectInterface $object
  178. * @param string $type
  179. * @return FlexFormFlash
  180. */
  181. protected function getFormFlash(FlexObjectInterface $object, string $type = '')
  182. {
  183. /** @var Uri $uri */
  184. $uri = $this->grav['uri'];
  185. $url = $uri->url;
  186. $formName = $this->getPost('__form-name__');
  187. if (!$formName) {
  188. $form = $object->getForm($type);
  189. $formName = $form->getName();
  190. $uniqueId = $form->getUniqueId();
  191. } else {
  192. $uniqueId = $this->getPost('__unique_form_id__') ?: $formName ?: sha1($url);
  193. }
  194. /** @var Session $session */
  195. $session = $this->grav['session'];
  196. $config = [
  197. 'session_id' => $session->getId(),
  198. 'unique_id' => $uniqueId,
  199. 'form_name' => $formName,
  200. ];
  201. $flash = new FlexFormFlash($config);
  202. if (!$flash->exists()) {
  203. $flash->setUrl($url)->setUser($this->grav['user']);
  204. }
  205. return $flash;
  206. }
  207. /**
  208. * @return Grav
  209. */
  210. public function getGrav(): Grav
  211. {
  212. return $this->grav;
  213. }
  214. /**
  215. * @return Session
  216. */
  217. public function getSession(): Session
  218. {
  219. return $this->grav['session'];
  220. }
  221. /**
  222. * @return Flex
  223. */
  224. public function getFlex(): Flex
  225. {
  226. return $this->grav['flex_objects'];
  227. }
  228. /**
  229. * @return string
  230. */
  231. public function getDirectoryType(): string
  232. {
  233. return $this->type;
  234. }
  235. /**
  236. * @return string
  237. */
  238. public function getObjectKey(): string
  239. {
  240. return $this->key;
  241. }
  242. /**
  243. * @return FlexDirectory|null
  244. */
  245. public function getDirectory(): ?FlexDirectory
  246. {
  247. return $this->directory;
  248. }
  249. /**
  250. * @return FlexObjectInterface|null
  251. */
  252. public function getObject(): ?FlexObjectInterface
  253. {
  254. return $this->object;
  255. }
  256. /**
  257. * @param string $string
  258. * @param array $args
  259. * @return string
  260. */
  261. public function translate(string $string, ...$args): string
  262. {
  263. /** @var Language $language */
  264. $language = $this->grav['language'];
  265. array_unshift($args, $string);
  266. return $language->translate($args);
  267. }
  268. /**
  269. * @param string $message
  270. * @param string $type
  271. * @return $this
  272. */
  273. public function setMessage(string $message, string $type = 'info'): self
  274. {
  275. /** @var Message $messages */
  276. $messages = $this->grav['messages'];
  277. $messages->add($message, $type);
  278. return $this;
  279. }
  280. /**
  281. * @param UserInterface $user
  282. * @return void
  283. */
  284. public function setUser(UserInterface $user): void
  285. {
  286. $this->user = $user;
  287. }
  288. /**
  289. * @return Config
  290. */
  291. protected function getConfig(): Config
  292. {
  293. return $this->grav['config'];
  294. }
  295. /**
  296. * @param string $task
  297. * @return void
  298. * @throws PageExpiredException
  299. */
  300. protected function checkNonce(string $task): void
  301. {
  302. $nonce = null;
  303. if (in_array(strtoupper($this->request->getMethod()), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
  304. $nonce = $this->getPost($this->nonce_name);
  305. }
  306. if (!$nonce) {
  307. $nonce = $this->grav['uri']->param($this->nonce_name);
  308. }
  309. if (!$nonce) {
  310. $nonce = $this->grav['uri']->query($this->nonce_name);
  311. }
  312. if (!$nonce || !Utils::verifyNonce($nonce, $this->nonce_action)) {
  313. throw new PageExpiredException($this->request);
  314. }
  315. }
  316. }