active_form-8.x-1.x-dev/src/Plugin/ActiveForm/BaseForm.php
src/Plugin/ActiveForm/BaseForm.php
<?php
namespace Drupal\active_form\Plugin\ActiveForm;
use Drupal\active_form\BaseException;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Cache\UnchangingCacheableDependencyTrait;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
abstract class BaseForm extends PluginBase implements RenderableInterface, CacheableDependencyInterface, ActiveFormInterface {
use UnchangingCacheableDependencyTrait;
protected $permission = '';
/**
* @param $plugin_id
* @param string $configuration
*
* @return array
*/
static public function lazyBuild($plugin_id, $configuration = NULL): array {
/** @var BaseForm $form */
$form = \Drupal::service('plugin.manager.active_form')
->createInstance($plugin_id, \GuzzleHttp\json_decode($configuration ?? '[]', TRUE));
return $form->buildLazyProps();
}
/**
* @return array
*/
protected function buildLazyProps(): array {
return [
[
'#type' => 'html_tag',
'#tag' => 'script',
'#attributes' => ['type' => 'application/json'],
'#value' => json_encode($this->getLazyProps()),
],
];
}
/**
* @return string
*/
protected function getCsrfToken(): string {
return \Drupal::csrfToken()->get();
}
/**
* @return array
*/
protected function build(): array {
$json = \GuzzleHttp\json_encode($this->configuration);
$placeholder = $this->getPluginId() . '--' . $json;
$output = [
'#type' => 'html_tag',
'#tag' => 'form',
'#value' => $placeholder,
'#attributes' => $this->getHtmlAttributes(),
'#attached' => ['library' => [$this->getLibraryName()]],
];
$output['#attached']['placeholders'][$placeholder] = [
'#lazy_builder' => [
static::class . '::lazyBuild',
[
$this->getPluginId(),
$json,
],
],
];
return $output;
}
/**
* @return string|null
*/
protected function getType(): ?string {
return NULL;
}
/**
* @return array
*/
protected function getHtmlAttributes(): array {
$attributes = ['class' => ['active-form--' . $this->pluginId], 'is' => $this->getComponentName()];
if ($type = $this->getType()) {
$attributes['class'][] = 'active-form--' . $this->pluginId . '--' . $type;
}
return $attributes + $this->propsToAttrs($this->getProps());
}
/**
* @param array $props
*
* @return array
*/
public function propsToAttrs(array $props): array {
foreach ($props as $key => $value) {
if (!is_scalar($value)) {
$props[$key] = json_encode($value);
}
}
return $props;
}
/**
* @return array
*/
protected function getProps(): array {
$storage_json = \GuzzleHttp\json_encode($this->configuration);
return [
'action' => Url::fromRoute('activeform')->toString(),
'method' => 'POST',
'storage_json' => $storage_json,
'storage_token' => $this->getStorageToken($storage_json),
];
}
/**
* @return array
*/
protected function getLazyProps(): array {
return [
'csrf_token' => $this->getCsrfToken(),
];
}
/**
* @return string
*/
protected function getComponentName(): string {
return 'active-form--' . $this->pluginId . ($this->getType() ? "--{$this->getType()}" : '');
}
/**
* @return string
*/
protected function getLibraryName(): string {
return $this->pluginDefinition['provider'] . '/' . $this->pluginId . ($this->getType() ? "--{$this->getType()}" : '');
}
/**
* @return array
*/
public function toRenderable(): array {
return $this->build() +
[
'#cache' => [
'contexts' => $this->getCacheContexts(),
'tags' => $this->getCacheTags(),
'max-age' => $this->getCacheMaxAge(),
],
];
}
/**
* @param string $storage_json
*
* @return string
*/
protected function getStorageToken(string $storage_json): string {
$data = $this->pluginId . ':' . $storage_json;
return Crypt::hmacBase64($data, Settings::getHashSalt());
}
/**
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
final public function handle(Request $request): JsonResponse {
try {
$method = $request->request->get('op');
$this->validate($request, $method);
return new JsonResponse($this->$method($request));
} catch (BaseException $e) {
return new JsonResponse([
'status' => 'error',
'message' => $e->getMessage(),
'error' => $e->getData(),
], $e->getCode());
}
}
/**
* @param string|null $csrf_token
*
* @throws \Drupal\active_form\BaseException
*/
protected function checkCsrfToken(?string $csrf_token) {
if ($csrf_token !== $this->getCsrfToken()) {
throw new BaseException('invalid csrf token', 403);
}
}
/**
* @param string $storage_token
* @param string $storage_json
*
* @throws BaseException
*/
protected function checkStorageToken(string $storage_token, string $storage_json) {
if ($storage_token !== $this->getStorageToken($storage_json)) {
throw new BaseException('invalid storage token', 403);
}
}
/**
* @throws BaseException
*/
protected function checkPermission() {
if ($this->permission && !\Drupal::currentUser()
->hasPermission($this->permission)) {
throw new BaseException('has not permission', 403);
}
}
/**
* @param string $method
*
* @throws \Drupal\active_form\BaseException
*/
protected function checkMethod(string $method) {
if (!method_exists($this, $method)) {
throw (new BaseException('method not exist', 501))->addValue('method', $method);
}
}
/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @param string|null $method
*
* @throws \Drupal\active_form\BaseException
*/
function validate(Request $request, ?string $method = NULL) {
$this->checkCsrfToken($request->request->get('csrf_token'));
$this->checkPermission();
$this->checkMethod($method);
$this->checkStorageToken($request->request->get('storage_token', ''), $request->request->get('storage_json', ''));
}
}
