357 lines
9.2 KiB
PHP
357 lines
9.2 KiB
PHP
|
<?php
|
||
|
|
||
|
declare(strict_types=1);
|
||
|
|
||
|
namespace Grav\Plugin\FlexObjects\Controllers;
|
||
|
|
||
|
use Grav\Common\Config\Config;
|
||
|
use Grav\Common\Grav;
|
||
|
use Grav\Common\Inflector;
|
||
|
use Grav\Common\Language\Language;
|
||
|
use Grav\Common\Session;
|
||
|
use Grav\Common\Uri;
|
||
|
use Grav\Common\User\Interfaces\UserInterface;
|
||
|
use Grav\Common\Utils;
|
||
|
use Grav\Framework\Controller\Traits\ControllerResponseTrait;
|
||
|
use Grav\Framework\Flex\FlexDirectory;
|
||
|
use Grav\Framework\Flex\FlexForm;
|
||
|
use Grav\Framework\Flex\FlexFormFlash;
|
||
|
use Grav\Framework\Flex\Interfaces\FlexFormInterface;
|
||
|
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||
|
use Grav\Framework\Psr7\Response;
|
||
|
use Grav\Framework\RequestHandler\Exception\NotFoundException;
|
||
|
use Grav\Framework\RequestHandler\Exception\PageExpiredException;
|
||
|
use Grav\Framework\Route\Route;
|
||
|
use Grav\Plugin\FlexObjects\Flex;
|
||
|
use Psr\Http\Message\ResponseInterface;
|
||
|
use Psr\Http\Message\ServerRequestInterface;
|
||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||
|
use RocketTheme\Toolbox\Event\Event;
|
||
|
use RocketTheme\Toolbox\Session\Message;
|
||
|
use function in_array;
|
||
|
use function is_callable;
|
||
|
|
||
|
/**
|
||
|
* Class AbstractController
|
||
|
* @package Grav\Plugin\FlexObjects\Controllers
|
||
|
*/
|
||
|
abstract class AbstractController implements RequestHandlerInterface
|
||
|
{
|
||
|
use ControllerResponseTrait;
|
||
|
|
||
|
/** @var string */
|
||
|
protected $nonce_action = 'flex-object';
|
||
|
/** @var string */
|
||
|
protected $nonce_name = 'nonce';
|
||
|
/** @var ServerRequestInterface */
|
||
|
protected $request;
|
||
|
/** @var Grav */
|
||
|
protected $grav;
|
||
|
/** @var UserInterface|null */
|
||
|
protected $user;
|
||
|
/** @var string */
|
||
|
protected $type;
|
||
|
/** @var string */
|
||
|
protected $key;
|
||
|
/** @var FlexDirectory */
|
||
|
protected $directory;
|
||
|
/** @var FlexObjectInterface */
|
||
|
protected $object;
|
||
|
|
||
|
/**
|
||
|
* Handle request.
|
||
|
*
|
||
|
* Fires event: flex.[directory].[task|action].[command]
|
||
|
*
|
||
|
* @param ServerRequestInterface $request
|
||
|
* @return Response
|
||
|
*/
|
||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||
|
{
|
||
|
$attributes = $request->getAttributes();
|
||
|
$this->request = $request;
|
||
|
$this->grav = $attributes['grav'] ?? Grav::instance();
|
||
|
$this->type = $attributes['type'] ?? null;
|
||
|
$this->key = $attributes['key'] ?? null;
|
||
|
if ($this->type) {
|
||
|
$this->directory = $this->getFlex()->getDirectory($this->type);
|
||
|
$this->object = $attributes['object'] ?? null;
|
||
|
if (!$this->object && $this->key && $this->directory) {
|
||
|
$this->object = $this->directory->getObject($this->key) ?? $this->directory->createObject([], $this->key ?? '');
|
||
|
if (is_callable([$this->object, 'refresh'])) {
|
||
|
$this->object->refresh();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** @var Route $route */
|
||
|
$route = $attributes['route'];
|
||
|
$post = $this->getPost();
|
||
|
|
||
|
if ($this->isFormSubmit()) {
|
||
|
$form = $this->getForm();
|
||
|
$this->nonce_name = $attributes['nonce_name'] ?? $form->getNonceName();
|
||
|
$this->nonce_action = $attributes['nonce_action'] ?? $form->getNonceAction();
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
$task = $request->getAttribute('task') ?? $post['task'] ?? $route->getParam('task');
|
||
|
if ($task) {
|
||
|
if (empty($attributes['forwarded'])) {
|
||
|
$this->checkNonce($task);
|
||
|
}
|
||
|
$type = 'task';
|
||
|
$command = $task;
|
||
|
} else {
|
||
|
$type = 'action';
|
||
|
$command = $request->getAttribute('action') ?? $post['action'] ?? $route->getParam('action') ?? 'display';
|
||
|
}
|
||
|
$command = strtolower($command);
|
||
|
|
||
|
$event = new Event(
|
||
|
[
|
||
|
'controller' => $this,
|
||
|
'response' => null
|
||
|
]
|
||
|
);
|
||
|
|
||
|
$this->grav->fireEvent("flex.{$this->type}.{$type}.{$command}", $event);
|
||
|
|
||
|
$response = $event['response'];
|
||
|
if (!$response) {
|
||
|
/** @var Inflector $inflector */
|
||
|
$inflector = $this->grav['inflector'];
|
||
|
$method = $type . $inflector::camelize($command);
|
||
|
if ($method && method_exists($this, $method)) {
|
||
|
$response = $this->{$method}($request);
|
||
|
} else {
|
||
|
throw new NotFoundException($request);
|
||
|
}
|
||
|
}
|
||
|
} catch (\Exception $e) {
|
||
|
$response = $this->createErrorResponse($e);
|
||
|
}
|
||
|
|
||
|
if ($response instanceof Response) {
|
||
|
return $response;
|
||
|
}
|
||
|
|
||
|
return $this->createJsonResponse($response);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return ServerRequestInterface
|
||
|
*/
|
||
|
public function getRequest(): ServerRequestInterface
|
||
|
{
|
||
|
return $this->request;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string|null $name
|
||
|
* @param mixed $default
|
||
|
* @return mixed
|
||
|
*/
|
||
|
public function getPost(string $name = null, $default = null)
|
||
|
{
|
||
|
$body = $this->request->getParsedBody();
|
||
|
|
||
|
if ($name) {
|
||
|
return $body[$name] ?? $default;
|
||
|
}
|
||
|
|
||
|
return $body;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function isFormSubmit(): bool
|
||
|
{
|
||
|
return (bool)$this->getPost('__form-name__');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string|null $type
|
||
|
* @return FlexForm
|
||
|
*/
|
||
|
public function getForm(string $type = null): FlexFormInterface
|
||
|
{
|
||
|
$object = $this->getObject();
|
||
|
if (!$object) {
|
||
|
throw new \RuntimeException('Not Found', 404);
|
||
|
}
|
||
|
|
||
|
$formName = $this->getPost('__form-name__');
|
||
|
$uniqueId = $this->getPost('__unique_form_id__') ?: $formName;
|
||
|
|
||
|
$form = $object->getForm($type ?? 'edit');
|
||
|
if ($uniqueId) {
|
||
|
$form->setUniqueId($uniqueId);
|
||
|
}
|
||
|
|
||
|
return $form;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param FlexObjectInterface $object
|
||
|
* @param string $type
|
||
|
* @return FlexFormFlash
|
||
|
*/
|
||
|
protected function getFormFlash(FlexObjectInterface $object, string $type = '')
|
||
|
{
|
||
|
/** @var Uri $uri */
|
||
|
$uri = $this->grav['uri'];
|
||
|
$url = $uri->url;
|
||
|
|
||
|
$formName = $this->getPost('__form-name__');
|
||
|
if (!$formName) {
|
||
|
$form = $object->getForm($type);
|
||
|
$formName = $form->getName();
|
||
|
$uniqueId = $form->getUniqueId();
|
||
|
} else {
|
||
|
$uniqueId = $this->getPost('__unique_form_id__') ?: $formName ?: sha1($url);
|
||
|
}
|
||
|
|
||
|
/** @var Session $session */
|
||
|
$session = $this->grav['session'];
|
||
|
|
||
|
$config = [
|
||
|
'session_id' => $session->getId(),
|
||
|
'unique_id' => $uniqueId,
|
||
|
'form_name' => $formName,
|
||
|
];
|
||
|
$flash = new FlexFormFlash($config);
|
||
|
if (!$flash->exists()) {
|
||
|
$flash->setUrl($url)->setUser($this->grav['user']);
|
||
|
}
|
||
|
|
||
|
return $flash;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Grav
|
||
|
*/
|
||
|
public function getGrav(): Grav
|
||
|
{
|
||
|
return $this->grav;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Session
|
||
|
*/
|
||
|
public function getSession(): Session
|
||
|
{
|
||
|
return $this->grav['session'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Flex
|
||
|
*/
|
||
|
public function getFlex(): Flex
|
||
|
{
|
||
|
return $this->grav['flex_objects'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getDirectoryType(): string
|
||
|
{
|
||
|
return $this->type;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getObjectKey(): string
|
||
|
{
|
||
|
return $this->key;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return FlexDirectory|null
|
||
|
*/
|
||
|
public function getDirectory(): ?FlexDirectory
|
||
|
{
|
||
|
return $this->directory;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return FlexObjectInterface|null
|
||
|
*/
|
||
|
public function getObject(): ?FlexObjectInterface
|
||
|
{
|
||
|
return $this->object;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $string
|
||
|
* @return string
|
||
|
*/
|
||
|
public function translate(string $string): string
|
||
|
{
|
||
|
/** @var Language $language */
|
||
|
$language = $this->grav['language'];
|
||
|
|
||
|
return $language->translate($string);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $message
|
||
|
* @param string $type
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function setMessage(string $message, string $type = 'info'): self
|
||
|
{
|
||
|
/** @var Message $messages */
|
||
|
$messages = $this->grav['messages'];
|
||
|
$messages->add($message, $type);
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param UserInterface $user
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setUser(UserInterface $user): void
|
||
|
{
|
||
|
$this->user = $user;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Config
|
||
|
*/
|
||
|
protected function getConfig(): Config
|
||
|
{
|
||
|
return $this->grav['config'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $task
|
||
|
* @return void
|
||
|
* @throws PageExpiredException
|
||
|
*/
|
||
|
protected function checkNonce(string $task): void
|
||
|
{
|
||
|
$nonce = null;
|
||
|
|
||
|
if (in_array(strtoupper($this->request->getMethod()), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
||
|
$nonce = $this->getPost($this->nonce_name);
|
||
|
}
|
||
|
|
||
|
if (!$nonce) {
|
||
|
$nonce = $this->grav['uri']->param($this->nonce_name);
|
||
|
}
|
||
|
|
||
|
if (!$nonce) {
|
||
|
$nonce = $this->grav['uri']->query($this->nonce_name);
|
||
|
}
|
||
|
|
||
|
if (!$nonce || !Utils::verifyNonce($nonce, $this->nonce_action)) {
|
||
|
throw new PageExpiredException($this->request);
|
||
|
}
|
||
|
}
|
||
|
}
|