Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

ObjectController.php 16 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. <?php
  2. declare(strict_types=1);
  3. namespace Grav\Plugin\FlexObjects\Controllers;
  4. use Grav\Common\Grav;
  5. use Grav\Framework\Flex\FlexForm;
  6. use Grav\Framework\Flex\FlexObject;
  7. use Grav\Framework\Flex\Interfaces\FlexAuthorizeInterface;
  8. use Grav\Framework\Route\Route;
  9. use Grav\Plugin\FlexObjects\Events\FlexTaskEvent;
  10. use Nyholm\Psr7\ServerRequest;
  11. use Psr\Http\Message\ResponseInterface;
  12. use Psr\Http\Message\ServerRequestInterface;
  13. use RocketTheme\Toolbox\Event\Event;
  14. use RuntimeException;
  15. /**
  16. * Object controller is for the frontend.
  17. *
  18. * Currently following tasks are supported:
  19. *
  20. * - save (create or update)
  21. * - create
  22. * - update
  23. * - delete
  24. * - reset
  25. * - preview
  26. */
  27. class ObjectController extends AbstractController
  28. {
  29. /**
  30. * Save object.
  31. *
  32. * Forwards call to either create or update task.
  33. *
  34. * @param ServerRequestInterface $request
  35. * @return ResponseInterface
  36. */
  37. public function taskSave(ServerRequestInterface $request): ResponseInterface
  38. {
  39. $form = $this->getForm();
  40. $object = $form->getObject();
  41. return $object->exists() ? $this->taskUpdate($request) : $this->taskCreate($request);
  42. }
  43. /**
  44. * Create object.
  45. *
  46. * Task fails if object exists.
  47. *
  48. * @param ServerRequestInterface $request
  49. * @return ResponseInterface
  50. */
  51. public function taskCreate(ServerRequestInterface $request): ResponseInterface
  52. {
  53. $this->checkAuthorization('create');
  54. $form = $this->getForm();
  55. $callable = function (array $data, array $files, FlexObject $object) {
  56. if (method_exists($object, 'storeOriginal')) {
  57. $object->storeOriginal();
  58. }
  59. $object->update($data, $files);
  60. if (\is_callable([$object, 'check'])) {
  61. $object->check($this->user);
  62. }
  63. $event = new FlexTaskEvent($this, $object, 'create');
  64. $this->grav->dispatchEvent($event);
  65. $object->save();
  66. };
  67. $form->setSubmitMethod($callable);
  68. $form->handleRequest($request);
  69. if (!$form->isValid()) {
  70. $error = $form->getError();
  71. if ($error) {
  72. $this->setMessage($error, 'error');
  73. }
  74. $errors = $form->getErrors();
  75. foreach ($errors as $field) {
  76. foreach ($field as $error) {
  77. $this->setMessage($error, 'error');
  78. }
  79. }
  80. $data = $form->getData();
  81. if (null !== $data) {
  82. $object = $form->getObject();
  83. $flash = $form->getFlash();
  84. $flash->setObject($object);
  85. $flash->setData($data->toArray());
  86. $flash->save();
  87. }
  88. return $this->createDisplayResponse();
  89. }
  90. // FIXME: make it conditional
  91. $grav = $this->grav;
  92. $grav->fireEvent('gitsync');
  93. $this->object = $form->getObject();
  94. $event = new Event(
  95. [
  96. 'task' => 'create',
  97. 'controller' => $this,
  98. 'object' => $this->object,
  99. 'response' => null,
  100. 'message' => null,
  101. ]
  102. );
  103. $this->grav->fireEvent("flex.{$this->type}.task.create.after", $event);
  104. $this->setMessage($event['message'] ?? $this->translate('PLUGIN_FLEX_OBJECTS.STATE.CREATED_SUCCESSFULLY'), 'info');
  105. if ($event['response']) {
  106. return $event['response'];
  107. }
  108. $redirect = $request->getAttribute('redirect', (string)$request->getUri());
  109. return $this->createRedirectResponse($redirect, 303);
  110. }
  111. /**
  112. * Update object.
  113. *
  114. * Task fails if object does not exist.
  115. *
  116. * @param ServerRequestInterface $request
  117. * @return ResponseInterface
  118. */
  119. public function taskUpdate(ServerRequestInterface $request): ResponseInterface
  120. {
  121. $this->checkAuthorization('update');
  122. $form = $this->getForm();
  123. $callable = function (array $data, array $files, FlexObject $object) {
  124. if (method_exists($object, 'storeOriginal')) {
  125. $object->storeOriginal();
  126. }
  127. $object->update($data, $files);
  128. if (\is_callable([$object, 'check'])) {
  129. $object->check($this->user);
  130. }
  131. $event = new FlexTaskEvent($this, $object, 'update');
  132. $this->grav->dispatchEvent($event);
  133. $object->save();
  134. };
  135. $form->setSubmitMethod($callable);
  136. $form->handleRequest($request);
  137. if (!$form->isValid()) {
  138. $error = $form->getError();
  139. if ($error) {
  140. $this->setMessage($error, 'error');
  141. }
  142. $errors = $form->getErrors();
  143. foreach ($errors as $field) {
  144. foreach ($field as $error) {
  145. $this->setMessage($error, 'error');
  146. }
  147. }
  148. $data = $form->getData();
  149. if (null !== $data) {
  150. $object = $form->getObject();
  151. $flash = $form->getFlash();
  152. $flash->setObject($object);
  153. $flash->setData($data->toArray());
  154. $flash->save();
  155. }
  156. return $this->createDisplayResponse();
  157. }
  158. // FIXME: make it conditional
  159. $grav = $this->grav;
  160. $grav->fireEvent('gitsync');
  161. $this->object = $form->getObject();
  162. $event = new Event(
  163. [
  164. 'task' => 'update',
  165. 'controller' => $this,
  166. 'object' => $this->object,
  167. 'response' => null,
  168. 'message' => null,
  169. ]
  170. );
  171. $this->grav->fireEvent("flex.{$this->type}.task.update.after", $event);
  172. $this->setMessage($event['message'] ?? $this->translate('PLUGIN_FLEX_OBJECTS.STATE.UPDATED_SUCCESSFULLY'), 'info');
  173. if ($event['response']) {
  174. return $event['response'];
  175. }
  176. $redirect = $request->getAttribute('redirect', (string)$request->getUri()->getPath());
  177. return $this->createRedirectResponse($redirect, 303);
  178. }
  179. /**
  180. * Delete object.
  181. *
  182. * @param ServerRequestInterface $request
  183. * @return ResponseInterface
  184. */
  185. public function taskDelete(ServerRequestInterface $request): ResponseInterface
  186. {
  187. $this->checkAuthorization('delete');
  188. $object = $this->getObject();
  189. if (!$object) {
  190. throw new RuntimeException('Not Found', 404);
  191. }
  192. $event = new FlexTaskEvent($this, $object, 'delete');
  193. $this->grav->dispatchEvent($event);
  194. $object->delete();
  195. // FIXME: make it conditional
  196. $grav = $this->grav;
  197. $grav->fireEvent('gitsync');
  198. $event = new Event(
  199. [
  200. 'task' => 'delete',
  201. 'controller' => $this,
  202. 'object' => $object,
  203. 'response' => null,
  204. 'message' => null,
  205. ]
  206. );
  207. $this->grav->fireEvent("flex.{$this->type}.task.delete.after", $event);
  208. $this->setMessage($this->translate($event['message'] ?? 'PLUGIN_FLEX_OBJECTS.STATE.DELETED_SUCCESSFULLY'), 'info');
  209. if ($event['response']) {
  210. return $event['response'];
  211. }
  212. $redirect = $request->getAttribute('redirect', (string)$request->getUri()->getPath());
  213. return $this->createRedirectResponse($redirect, 303);
  214. }
  215. /**
  216. * Reset form to original values.
  217. *
  218. * @param ServerRequestInterface $request
  219. * @return ResponseInterface
  220. */
  221. public function taskReset(ServerRequestInterface $request): ResponseInterface
  222. {
  223. $this->checkAuthorization('save');
  224. $flash = $this->getForm()->getFlash();
  225. $flash->delete();
  226. $redirect = $request->getAttribute('redirect', (string)$request->getUri()->getPath());
  227. return $this->createRedirectResponse($redirect, 303);
  228. }
  229. /**
  230. * Preview object.
  231. *
  232. * Takes a form input and converts it to visible presentation of the object.
  233. *
  234. * @param ServerRequestInterface $request
  235. * @return ResponseInterface
  236. */
  237. public function taskPreview(ServerRequestInterface $request): ResponseInterface
  238. {
  239. $this->checkAuthorization('save');
  240. /** @var FlexForm $form */
  241. $form = $this->getForm('edit');
  242. $form->setRequest($request);
  243. if (!$form->validate()) {
  244. $error = $form->getError();
  245. if ($error) {
  246. $this->setMessage($error, 'error');
  247. }
  248. $errors = $form->getErrors();
  249. foreach ($errors as $field) {
  250. foreach ($field as $error) {
  251. $this->setMessage($error, 'error');
  252. }
  253. }
  254. return $this->createRedirectResponse((string)$request->getUri(), 303);
  255. }
  256. $this->object = $form->updateObject();
  257. return $this->actionDisplayPreview();
  258. }
  259. /**
  260. * @param ServerRequestInterface $request
  261. * @return ResponseInterface
  262. */
  263. public function taskMediaList(ServerRequestInterface $request): ResponseInterface
  264. {
  265. $directory = $this->getDirectory();
  266. if (!$directory) {
  267. throw new RuntimeException('Not Found', 404);
  268. }
  269. return $this->forwardMediaTask('action', 'media.list');
  270. }
  271. /**
  272. * @param ServerRequestInterface $request
  273. * @return ResponseInterface
  274. */
  275. public function taskMediaUpload(ServerRequestInterface $request): ResponseInterface
  276. {
  277. $directory = $this->getDirectory();
  278. if (!$directory) {
  279. throw new RuntimeException('Not Found', 404);
  280. }
  281. return $this->forwardMediaTask('task', 'media.upload');
  282. }
  283. /**
  284. * @param ServerRequestInterface $request
  285. * @return ResponseInterface
  286. */
  287. public function taskMediaUploadMeta(ServerRequestInterface $request): ResponseInterface
  288. {
  289. $directory = $this->getDirectory();
  290. if (!$directory) {
  291. throw new RuntimeException('Not Found', 404);
  292. }
  293. return $this->forwardMediaTask('task', 'media.upload.meta');
  294. }
  295. /**
  296. * @param ServerRequestInterface $request
  297. * @return ResponseInterface
  298. */
  299. public function taskMediaReorder(ServerRequestInterface $request): ResponseInterface
  300. {
  301. $directory = $this->getDirectory();
  302. if (!$directory) {
  303. throw new RuntimeException('Not Found', 404);
  304. }
  305. return $this->forwardMediaTask('task', 'media.reorder');
  306. }
  307. /**
  308. * @param ServerRequestInterface $request
  309. * @return ResponseInterface
  310. */
  311. public function taskMediaDelete(ServerRequestInterface $request): ResponseInterface
  312. {
  313. $directory = $this->getDirectory();
  314. if (!$directory) {
  315. throw new RuntimeException('Not Found', 404);
  316. }
  317. return $this->forwardMediaTask('task', 'media.delete');
  318. }
  319. /**
  320. * @param ServerRequestInterface $request
  321. * @return ResponseInterface
  322. */
  323. public function taskGetFilesInFolder(ServerRequestInterface $request): ResponseInterface
  324. {
  325. $directory = $this->getDirectory();
  326. if (!$directory) {
  327. throw new RuntimeException('Not Found', 404);
  328. }
  329. return $this->forwardMediaTask('action', 'media.picker');
  330. }
  331. /**
  332. * @param ServerRequestInterface $request
  333. * @return ResponseInterface
  334. * @deprecated Do not use
  335. */
  336. public function taskFilesUpload(ServerRequestInterface $request): ResponseInterface
  337. {
  338. /** @var Route $route */
  339. $route = $this->grav['route'];
  340. if ($route->getParam('task') === 'media.upload') {
  341. return $this->taskMediaUpload($request);
  342. }
  343. throw new RuntimeException('Task filesUpload should not be called, please update form plugin!', 400);
  344. }
  345. /**
  346. * @param ServerRequestInterface $request
  347. * @return ResponseInterface
  348. * @deprecated Do not use
  349. */
  350. public function taskRemoveMedia(ServerRequestInterface $request): ResponseInterface
  351. {
  352. /** @var Route $route */
  353. $route = $this->grav['route'];
  354. if ($route->getParam('task') === 'media.delete') {
  355. return $this->taskMediaDelete($request);
  356. }
  357. throw new RuntimeException('Task removeMedia should not be called, please update form plugin!', 400);
  358. }
  359. /**
  360. * Display object preview.
  361. *
  362. * @return ResponseInterface
  363. */
  364. public function actionDisplayPreview(): ResponseInterface
  365. {
  366. $this->checkAuthorization('save');
  367. $this->checkAuthorization('read');
  368. $object = $this->getObject();
  369. if (!$object) {
  370. throw new RuntimeException('No object found!', 404);
  371. }
  372. $grav = Grav::instance();
  373. $grav['twig']->init();
  374. $grav['theme'];
  375. $content = [
  376. 'code' => 200,
  377. 'id' => $object->getKey(),
  378. 'exists' => $object->exists(),
  379. 'html' => (string)$object->render('preview', ['nocache' => []])
  380. ];
  381. $accept = $this->getAccept(['application/json', 'text/html']);
  382. if ($accept === 'text/html') {
  383. return $this->createHtmlResponse($content['html']);
  384. }
  385. if ($accept === 'application/json') {
  386. return $this->createJsonResponse($content);
  387. }
  388. throw new RuntimeException('Not found', 404);
  389. }
  390. /**
  391. * @param string $action
  392. * @param string|null $scope
  393. * @return void
  394. * @throws RuntimeException
  395. */
  396. public function checkAuthorization(string $action, string $scope = null): void
  397. {
  398. $object = $this->getObject();
  399. if (!$object) {
  400. throw new RuntimeException('Not Found', 404);
  401. }
  402. if ($object instanceof FlexAuthorizeInterface) {
  403. if (!$object->isAuthorized($action, $scope, $this->user)) {
  404. throw new RuntimeException('Forbidden', 403);
  405. }
  406. }
  407. }
  408. /**
  409. * @param string[] $actions
  410. * @return void
  411. * @throws RuntimeException
  412. */
  413. public function checkAuthorizations(array $actions): void
  414. {
  415. $object = $this->getObject();
  416. if (!$object) {
  417. throw new RuntimeException('Not Found', 404);
  418. }
  419. if ($object instanceof FlexAuthorizeInterface) {
  420. $test = false;
  421. foreach ($actions as $action) {
  422. $test |= $object->isAuthorized($action, null, $this->user);
  423. }
  424. if (!$test) {
  425. throw new RuntimeException('Forbidden', 403);
  426. }
  427. }
  428. }
  429. /**
  430. * @param string $type
  431. * @param string $name
  432. * @return ResponseInterface
  433. */
  434. protected function forwardMediaTask(string $type, string $name): ResponseInterface
  435. {
  436. /** @var Route $route */
  437. $route = $this->grav['route']->withGravParam('task', null)->withGravParam($type, $name);
  438. $object = $this->getObject();
  439. /** @var ServerRequest $request */
  440. $request = $this->grav['request'];
  441. $request = $request
  442. ->withAttribute($type, $name)
  443. ->withAttribute('type', $this->type)
  444. ->withAttribute('key', $this->key)
  445. ->withAttribute('storage_key', $object && $object->exists() ? $object->getStorageKey() : null)
  446. ->withAttribute('route', $route)
  447. ->withAttribute('forwarded', true)
  448. ->withAttribute('object', $object);
  449. $controller = new MediaController();
  450. if ($this->user) {
  451. $controller->setUser($this->user);
  452. }
  453. return $controller->handle($request);
  454. }
  455. }