View source
<?php
namespace Drupal\xbbcode\Form;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\xbbcode\Parser\Processor\CallbackTagProcessor;
use Drupal\xbbcode\Parser\XBBCodeParser;
use Drupal\xbbcode\Plugin\XBBCode\EntityTagPlugin;
use Drupal\xbbcode\TagPluginManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Throwable;
use Twig\Error\Error as TwigError;
class TagForm extends TagFormBase {
protected $storage;
protected $manager;
public function __construct(TwigEnvironment $twig, EntityStorageInterface $storage, TagPluginManager $manager) {
parent::__construct($twig);
$this->storage = $storage;
$this->manager = $manager;
}
public static function create(ContainerInterface $container) : self {
return new static($container
->get('twig'), $container
->get('entity_type.manager')
->getStorage('xbbcode_tag'), $container
->get('plugin.manager.xbbcode'));
}
public function form(array $form, FormStateInterface $form_state) : array {
$form = parent::form($form, $form_state);
$form['name']['#attached']['library'] = [
'xbbcode/tag-form',
];
$form['preview']['code'] += [
'#prefix' => '<div id="ajax-preview">',
'#suffix' => '</div>',
];
$form['sample']['#ajax'] = $form['template_code']['#ajax'] = [
'wrapper' => 'ajax-preview',
'callback' => [
$this,
'ajaxPreview',
],
'disable-refocus' => TRUE,
'event' => 'change',
];
$form['preview']['#attached']['library'] = [
'classy/messages',
];
return $form;
}
public function ajaxPreview(array $form) : array {
return $form['preview']['code'];
}
protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) : void {
parent::copyFormValuesToEntity($entity, $form, $form_state);
$name = $entity
->getName();
if (!preg_match('/^\\w+$/', $name)) {
return;
}
$expression = '/(\\[\\/?)' . $name . '([\\s\\]=])/';
$replace = '\\1{{ name }}\\2';
$sample = preg_replace($expression, $replace, $form_state
->getValue('sample'));
$entity
->set('sample', $sample);
}
public function validateForm(array &$form, FormStateInterface $form_state) : void {
parent::validateForm($form, $form_state);
$tag = $this->entity;
$called = FALSE;
$processor = new CallbackTagProcessor(static function () use (&$called) {
$called = TRUE;
});
$parser = new XBBCodeParser([
$tag
->getName() => $processor,
]);
$sample = str_replace('{{ name }}', $tag
->getName(), $tag
->getSample());
$tree = $parser
->parse($sample);
try {
$template = $this->twig
->load(EntityTagPlugin::TEMPLATE_PREFIX . $tag
->getTemplateCode());
$processor
->setProcess(static function ($tag) use ($template, &$called) {
$called = TRUE;
return $template
->render([
'tag' => $tag,
]);
});
} catch (TwigError $exception) {
$error = str_replace(EntityTagPlugin::TEMPLATE_PREFIX, '', $exception
->getMessage());
$form_state
->setError($form['template_code'], $this
->t('The template could not be compiled: @error', [
'@error' => $error,
]));
}
try {
$tree
->render();
} catch (Throwable $exception) {
$form_state
->setError($form['template_code'], $this
->t('An error occurred while rendering the template: @error', [
'@error' => $exception
->getMessage(),
]));
}
if (!$called) {
$form_state
->setError($form['sample'], $this
->t('The sample code should contain a valid example of the tag.'));
}
}
public function exists($tag_id) : bool {
return (bool) $this->storage
->getQuery()
->condition('id', $tag_id)
->execute();
}
public function save(array $form, FormStateInterface $form_state) : int {
$result = parent::save($form, $form_state);
if ($result === SAVED_NEW) {
$this
->messenger()
->addStatus($this
->t('The BBCode tag %tag has been created.', [
'%tag' => $this->entity
->label(),
]));
}
elseif ($result === SAVED_UPDATED) {
$this
->messenger()
->addStatus($this
->t('The BBCode tag %tag has been updated.', [
'%tag' => $this->entity
->label(),
]));
}
$form_state
->setRedirectUrl($this->entity
->toUrl('collection'));
return $result;
}
protected function actions(array $form, FormStateInterface $form_state) : array {
$actions = parent::actions($form, $form_state);
if (isset($actions['copy'])) {
$actions['copy']['#title'] = $this
->t('Copy (discard unsaved changes)');
}
return $actions;
}
}