|
- <?php
-
- declare(strict_types=1);
-
- namespace Grav\Plugin\FlexObjects\Controllers;
-
- use Grav\Common\Grav;
- use Grav\Framework\Flex\FlexForm;
- use Grav\Framework\Flex\FlexObject;
- use Grav\Framework\Flex\Interfaces\FlexAuthorizeInterface;
- use Grav\Framework\Route\Route;
- use Grav\Plugin\FlexObjects\Events\FlexTaskEvent;
- use Nyholm\Psr7\ServerRequest;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use RocketTheme\Toolbox\Event\Event;
- use RuntimeException;
-
- /**
- * Object controller is for the frontend.
- *
- * Currently following tasks are supported:
- *
- * - save (create or update)
- * - create
- * - update
- * - delete
- * - reset
- * - preview
- */
- class ObjectController extends AbstractController
- {
- /**
- * Save object.
- *
- * Forwards call to either create or update task.
- *
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskSave(ServerRequestInterface $request): ResponseInterface
- {
- $form = $this->getForm();
- $object = $form->getObject();
-
- return $object->exists() ? $this->taskUpdate($request) : $this->taskCreate($request);
- }
-
- /**
- * Create object.
- *
- * Task fails if object exists.
- *
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskCreate(ServerRequestInterface $request): ResponseInterface
- {
- $this->checkAuthorization('create');
-
- $form = $this->getForm();
- $callable = function (array $data, array $files, FlexObject $object) {
- if (method_exists($object, 'storeOriginal')) {
- $object->storeOriginal();
- }
- $object->update($data, $files);
- if (\is_callable([$object, 'check'])) {
- $object->check($this->user);
- }
-
- $event = new FlexTaskEvent($this, $object, 'create');
- $this->grav->dispatchEvent($event);
-
- $object->save();
- };
-
- $form->setSubmitMethod($callable);
- $form->handleRequest($request);
- if (!$form->isValid()) {
- $error = $form->getError();
- if ($error) {
- $this->setMessage($error, 'error');
- }
- $errors = $form->getErrors();
- foreach ($errors as $field) {
- foreach ($field as $error) {
- $this->setMessage($error, 'error');
- }
- }
-
- $data = $form->getData();
- if (null !== $data) {
- $object = $form->getObject();
- $flash = $form->getFlash();
- $flash->setObject($object);
- $flash->setData($data->toArray());
- $flash->save();
- }
-
- return $this->createDisplayResponse();
- }
-
- // FIXME: make it conditional
- $grav = $this->grav;
- $grav->fireEvent('gitsync');
-
- $this->object = $form->getObject();
- $event = new Event(
- [
- 'task' => 'create',
- 'controller' => $this,
- 'object' => $this->object,
- 'response' => null,
- 'message' => null,
- ]
- );
-
- $this->grav->fireEvent("flex.{$this->type}.task.create.after", $event);
-
- $this->setMessage($event['message'] ?? $this->translate('PLUGIN_FLEX_OBJECTS.STATE.CREATED_SUCCESSFULLY'), 'info');
-
- if ($event['response']) {
- return $event['response'];
- }
-
-
- $redirect = $request->getAttribute('redirect', (string)$request->getUri());
-
- return $this->createRedirectResponse($redirect, 303);
- }
-
- /**
- * Update object.
- *
- * Task fails if object does not exist.
- *
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskUpdate(ServerRequestInterface $request): ResponseInterface
- {
- $this->checkAuthorization('update');
-
- $form = $this->getForm();
- $callable = function (array $data, array $files, FlexObject $object) {
- if (method_exists($object, 'storeOriginal')) {
- $object->storeOriginal();
- }
- $object->update($data, $files);
- if (\is_callable([$object, 'check'])) {
- $object->check($this->user);
- }
-
- $event = new FlexTaskEvent($this, $object, 'update');
- $this->grav->dispatchEvent($event);
-
- $object->save();
- };
-
- $form->setSubmitMethod($callable);
- $form->handleRequest($request);
- if (!$form->isValid()) {
- $error = $form->getError();
- if ($error) {
- $this->setMessage($error, 'error');
- }
- $errors = $form->getErrors();
- foreach ($errors as $field) {
- foreach ($field as $error) {
- $this->setMessage($error, 'error');
- }
- }
-
- $data = $form->getData();
- if (null !== $data) {
- $object = $form->getObject();
- $flash = $form->getFlash();
- $flash->setObject($object);
- $flash->setData($data->toArray());
- $flash->save();
- }
-
- return $this->createDisplayResponse();
- }
-
- // FIXME: make it conditional
- $grav = $this->grav;
- $grav->fireEvent('gitsync');
-
- $this->object = $form->getObject();
- $event = new Event(
- [
- 'task' => 'update',
- 'controller' => $this,
- 'object' => $this->object,
- 'response' => null,
- 'message' => null,
- ]
- );
-
- $this->grav->fireEvent("flex.{$this->type}.task.update.after", $event);
-
- $this->setMessage($event['message'] ?? $this->translate('PLUGIN_FLEX_OBJECTS.STATE.UPDATED_SUCCESSFULLY'), 'info');
-
- if ($event['response']) {
- return $event['response'];
- }
-
- $redirect = $request->getAttribute('redirect', (string)$request->getUri()->getPath());
-
- return $this->createRedirectResponse($redirect, 303);
- }
-
- /**
- * Delete object.
- *
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskDelete(ServerRequestInterface $request): ResponseInterface
- {
- $this->checkAuthorization('delete');
-
- $object = $this->getObject();
- if (!$object) {
- throw new RuntimeException('Not Found', 404);
- }
-
- $event = new FlexTaskEvent($this, $object, 'delete');
- $this->grav->dispatchEvent($event);
-
- $object->delete();
-
- // FIXME: make it conditional
- $grav = $this->grav;
- $grav->fireEvent('gitsync');
-
- $event = new Event(
- [
- 'task' => 'delete',
- 'controller' => $this,
- 'object' => $object,
- 'response' => null,
- 'message' => null,
- ]
- );
-
- $this->grav->fireEvent("flex.{$this->type}.task.delete.after", $event);
-
- $this->setMessage($this->translate($event['message'] ?? 'PLUGIN_FLEX_OBJECTS.STATE.DELETED_SUCCESSFULLY'), 'info');
-
- if ($event['response']) {
- return $event['response'];
- }
-
- $redirect = $request->getAttribute('redirect', (string)$request->getUri()->getPath());
-
- return $this->createRedirectResponse($redirect, 303);
- }
-
- /**
- * Reset form to original values.
- *
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskReset(ServerRequestInterface $request): ResponseInterface
- {
- $this->checkAuthorization('save');
-
- $flash = $this->getForm()->getFlash();
- $flash->delete();
-
- $redirect = $request->getAttribute('redirect', (string)$request->getUri()->getPath());
-
- return $this->createRedirectResponse($redirect, 303);
- }
-
- /**
- * Preview object.
- *
- * Takes a form input and converts it to visible presentation of the object.
- *
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskPreview(ServerRequestInterface $request): ResponseInterface
- {
- $this->checkAuthorization('save');
-
- /** @var FlexForm $form */
- $form = $this->getForm('edit');
- $form->setRequest($request);
- if (!$form->validate()) {
- $error = $form->getError();
- if ($error) {
- $this->setMessage($error, 'error');
- }
- $errors = $form->getErrors();
- foreach ($errors as $field) {
- foreach ($field as $error) {
- $this->setMessage($error, 'error');
- }
- }
-
- return $this->createRedirectResponse((string)$request->getUri(), 303);
- }
-
- $this->object = $form->updateObject();
-
- return $this->actionDisplayPreview();
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskMediaList(ServerRequestInterface $request): ResponseInterface
- {
- $directory = $this->getDirectory();
- if (!$directory) {
- throw new RuntimeException('Not Found', 404);
- }
-
- return $this->forwardMediaTask('action', 'media.list');
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskMediaUpload(ServerRequestInterface $request): ResponseInterface
- {
- $directory = $this->getDirectory();
- if (!$directory) {
- throw new RuntimeException('Not Found', 404);
- }
-
- return $this->forwardMediaTask('task', 'media.upload');
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskMediaUploadMeta(ServerRequestInterface $request): ResponseInterface
- {
- $directory = $this->getDirectory();
- if (!$directory) {
- throw new RuntimeException('Not Found', 404);
- }
-
- return $this->forwardMediaTask('task', 'media.upload.meta');
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskMediaReorder(ServerRequestInterface $request): ResponseInterface
- {
- $directory = $this->getDirectory();
- if (!$directory) {
- throw new RuntimeException('Not Found', 404);
- }
-
- return $this->forwardMediaTask('task', 'media.reorder');
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskMediaDelete(ServerRequestInterface $request): ResponseInterface
- {
- $directory = $this->getDirectory();
- if (!$directory) {
- throw new RuntimeException('Not Found', 404);
- }
-
- return $this->forwardMediaTask('task', 'media.delete');
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- */
- public function taskGetFilesInFolder(ServerRequestInterface $request): ResponseInterface
- {
- $directory = $this->getDirectory();
- if (!$directory) {
- throw new RuntimeException('Not Found', 404);
- }
-
- return $this->forwardMediaTask('action', 'media.picker');
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- * @deprecated Do not use
- */
- public function taskFilesUpload(ServerRequestInterface $request): ResponseInterface
- {
- /** @var Route $route */
- $route = $this->grav['route'];
- if ($route->getParam('task') === 'media.upload') {
- return $this->taskMediaUpload($request);
- }
-
- throw new RuntimeException('Task filesUpload should not be called, please update form plugin!', 400);
- }
-
- /**
- * @param ServerRequestInterface $request
- * @return ResponseInterface
- * @deprecated Do not use
- */
- public function taskRemoveMedia(ServerRequestInterface $request): ResponseInterface
- {
- /** @var Route $route */
- $route = $this->grav['route'];
- if ($route->getParam('task') === 'media.delete') {
- return $this->taskMediaDelete($request);
- }
-
- throw new RuntimeException('Task removeMedia should not be called, please update form plugin!', 400);
- }
-
- /**
- * Display object preview.
- *
- * @return ResponseInterface
- */
- public function actionDisplayPreview(): ResponseInterface
- {
- $this->checkAuthorization('save');
- $this->checkAuthorization('read');
-
- $object = $this->getObject();
- if (!$object) {
- throw new RuntimeException('No object found!', 404);
- }
-
- $grav = Grav::instance();
-
- $grav['twig']->init();
- $grav['theme'];
- $content = [
- 'code' => 200,
- 'id' => $object->getKey(),
- 'exists' => $object->exists(),
- 'html' => (string)$object->render('preview', ['nocache' => []])
- ];
-
- $accept = $this->getAccept(['application/json', 'text/html']);
- if ($accept === 'text/html') {
- return $this->createHtmlResponse($content['html']);
- }
- if ($accept === 'application/json') {
- return $this->createJsonResponse($content);
- }
-
- throw new RuntimeException('Not found', 404);
- }
-
- /**
- * @param string $action
- * @param string|null $scope
- * @return void
- * @throws RuntimeException
- */
- public function checkAuthorization(string $action, string $scope = null): void
- {
- $object = $this->getObject();
-
- if (!$object) {
- throw new RuntimeException('Not Found', 404);
- }
-
- if ($object instanceof FlexAuthorizeInterface) {
- if (!$object->isAuthorized($action, $scope, $this->user)) {
- throw new RuntimeException('Forbidden', 403);
- }
- }
- }
-
-
- /**
- * @param string[] $actions
- * @return void
- * @throws RuntimeException
- */
- public function checkAuthorizations(array $actions): void
- {
- $object = $this->getObject();
-
- if (!$object) {
- throw new RuntimeException('Not Found', 404);
- }
-
- if ($object instanceof FlexAuthorizeInterface) {
- $test = false;
- foreach ($actions as $action) {
- $test |= $object->isAuthorized($action, null, $this->user);
- }
-
- if (!$test) {
- throw new RuntimeException('Forbidden', 403);
- }
- }
- }
-
- /**
- * @param string $type
- * @param string $name
- * @return ResponseInterface
- */
- protected function forwardMediaTask(string $type, string $name): ResponseInterface
- {
- /** @var Route $route */
- $route = $this->grav['route']->withGravParam('task', null)->withGravParam($type, $name);
- $object = $this->getObject();
-
- /** @var ServerRequest $request */
- $request = $this->grav['request'];
- $request = $request
- ->withAttribute($type, $name)
- ->withAttribute('type', $this->type)
- ->withAttribute('key', $this->key)
- ->withAttribute('storage_key', $object && $object->exists() ? $object->getStorageKey() : null)
- ->withAttribute('route', $route)
- ->withAttribute('forwarded', true)
- ->withAttribute('object', $object);
-
- $controller = new MediaController();
- if ($this->user) {
- $controller->setUser($this->user);
- }
-
- return $controller->handle($request);
- }
- }
|