knowledge-8.x-1.x-dev/src/KnowledgeForm.php
src/KnowledgeForm.php
<?php
namespace Drupal\knowledge;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityConstraintViolationListInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Base handler for knowledge forms.
*
* @internal
*/
class KnowledgeForm extends ContentEntityForm {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.repository'),
$container->get('current_user'),
$container->get('renderer'),
$container->get('entity_type.bundle.info'),
$container->get('datetime.time'),
$container->get('entity_field.manager')
);
}
/**
* Constructs a new KnowledgeForm.
*
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
* The entity type bundle service.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager service.
*/
public function __construct(EntityRepositoryInterface $entity_repository, AccountInterface $current_user, RendererInterface $renderer, ?EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, ?TimeInterface $time = NULL, ?EntityFieldManagerInterface $entity_field_manager = NULL) {
parent::__construct($entity_repository, $entity_type_bundle_info, $time);
$this->currentUser = $current_user;
$this->renderer = $renderer;
$this->entityFieldManager = $entity_field_manager;
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
/** @var \Drupal\knowledge\KnowledgeInterface $knowledge */
$knowledge = $this->entity;
$entity = $this->entityTypeManager->getStorage($knowledge->getKnowledgeedEntityTypeId())->load($knowledge->getKnowledgeedEntityId());
$field_name = $knowledge->getFieldName();
$field_definition = $this->entityFieldManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle())[$knowledge->getFieldName()];
$config = $this->config('user.settings');
// In several places within this function, we vary $form on:
// - The current user's permissions.
// - Whether the current user is authenticated or anonymous.
// - The 'user.settings' configuration.
// - The knowledge field's definition.
$form['#cache']['contexts'][] = 'user.permissions';
$form['#cache']['contexts'][] = 'user.roles:authenticated';
$this->renderer->addCacheableDependency($form, $config);
$this->renderer->addCacheableDependency($form, $field_definition->getConfig($entity->bundle()));
// Use #knowledge-form as unique jump target, regardless of entity type.
$form['#id'] = Html::getUniqueId('knowledge_form');
$form['#theme'] = [
'knowledge_form__' . $entity->getEntityTypeId() . '__' . $entity->bundle() . '__' . $field_name,
'knowledge_form',
];
$anonymous_contact = $field_definition->getSetting('anonymous');
$is_admin = $knowledge->id() && $this->currentUser->hasPermission('administer knowledge');
if (!$this->currentUser->isAuthenticated() && $anonymous_contact != KnowledgeInterface::ANONYMOUS_MAYNOT_CONTACT) {
$form['#attached']['library'][] = 'core/drupal.form';
$form['#attributes']['data-user-info-from-browser'] = TRUE;
}
$knowledge_preview = $form_state->get('knowledge_preview');
if (isset($knowledge_preview)) {
$form += $knowledge_preview;
}
$form['author'] = [];
// Display author information in a details element for knowledge moderators.
if ($is_admin) {
$form['author'] += [
'#type' => 'details',
'#title' => $this->t('Administration'),
];
}
// Prepare default values for form elements.
if ($is_admin) {
$status = $knowledge->isPublished() ? KnowledgeInterface::PUBLISHED : KnowledgeInterface::NOT_PUBLISHED;
if (empty($knowledge_preview)) {
$form['#title'] = $this->t('Edit knowledge %title', [
'%title' => $knowledge->label(),
]);
}
}
else {
$status = ($this->currentUser->hasPermission('skip knowledge approval') ? KnowledgeInterface::PUBLISHED : KnowledgeInterface::NOT_PUBLISHED);
}
$date = '';
if ($knowledge->id()) {
$date = !empty($knowledge->date) ? $knowledge->date : DrupalDateTime::createFromTimestamp($knowledge->getCreatedTime());
}
// The uid field is only displayed when a user with the permission
// 'administer knowledge' is editing an existing knowledge from an
// authenticated user.
$owner = $knowledge->getOwner();
$form['author']['uid'] = [
'#type' => 'entity_autocomplete',
'#target_type' => 'user',
'#default_value' => $owner->isAnonymous() ? NULL : $owner,
// A knowledge can be made anonymous by leaving this field empty therefore
// there is no need to list them in the autocomplete.
'#selection_settings' => ['include_anonymous' => FALSE],
'#title' => $this->t('Authored by'),
'#description' => $this->t('Leave blank for %anonymous.', ['%anonymous' => $config->get('anonymous')]),
'#access' => $is_admin,
];
// Add administrative knowledge publishing options.
$form['author']['date'] = [
'#type' => 'datetime',
'#title' => $this->t('Authored on'),
'#default_value' => $date,
'#size' => 20,
'#access' => $is_admin,
];
$form['author']['status'] = [
'#type' => 'radios',
'#title' => $this->t('Status'),
'#default_value' => $status,
'#options' => [
KnowledgeInterface::PUBLISHED => $this->t('Published'),
KnowledgeInterface::NOT_PUBLISHED => $this->t('Not published'),
],
'#access' => $is_admin,
];
$form = parent::form($form, $form_state);
$form['revision_log_message']['#access'] = !$knowledge->isNew();
return $form;
}
/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
$element = parent::actions($form, $form_state);
/** @var \Drupal\knowledge\KnowledgeInterface $knowledge */
$knowledge = $this->entity;
$entity = $knowledge->getKnowledgeedEntity();
$field_definition = $this->entityFieldManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle())[$knowledge->getFieldName()];
$preview_mode = $field_definition->getSetting('preview');
// No delete action on the knowledge form.
unset($element['delete']);
// Mark the submit action as the primary action, when it appears.
$element['submit']['#button_type'] = 'primary';
// Only show the save button if knowledge previews are optional or if we are
// already previewing the submission.
$element['submit']['#access'] = ($knowledge->id() && $this->currentUser->hasPermission('administer knowledge')) || $preview_mode != DRUPAL_REQUIRED || $form_state->get('knowledge_preview');
$element['preview'] = [
'#type' => 'submit',
'#value' => $this->t('Preview'),
'#access' => $preview_mode != DRUPAL_DISABLED,
'#submit' => ['::submitForm', '::preview'],
];
return $element;
}
/**
* {@inheritdoc}
*/
public function buildEntity(array $form, FormStateInterface $form_state) {
/** @var \Drupal\knowledge\KnowledgeInterface $knowledge */
$knowledge = parent::buildEntity($form, $form_state);
if (!$form_state->isValueEmpty('date') && $form_state->getValue('date') instanceof DrupalDateTime) {
$knowledge->setCreatedTime($form_state->getValue('date')->getTimestamp());
}
else {
$knowledge->setCreatedTime($this->time->getRequestTime());
}
// Empty author ID should revert to anonymous.
$author_id = $form_state->getValue('uid');
if ($knowledge->id() && $this->currentUser->hasPermission('administer knowledge')) {
// Admin can leave the author ID blank to revert to anonymous.
$author_id = $author_id ?: 0;
}
if (is_null($author_id)) {
$author_id = $this->currentUser->id();
}
$knowledge->setOwnerId($author_id);
$incident_type_id = $knowledge->knowledge_type[0]->entity->getIncidentEntityTypeId();
$knowledge->incident_type = $incident_type_id;
return $knowledge;
}
/**
* {@inheritdoc}
*/
protected function getEditedFieldNames(FormStateInterface $form_state) {
return array_merge(['created'], parent::getEditedFieldNames($form_state));
}
/**
* {@inheritdoc}
*/
protected function flagViolations(EntityConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
// Manually flag violations of fields not handled by the form display.
foreach ($violations->getByField('created') as $violation) {
$form_state->setErrorByName('date', $violation->getMessage());
}
foreach ($violations->getByField('name') as $violation) {
$form_state->setErrorByName('name', $violation->getMessage());
}
parent::flagViolations($violations, $form, $form_state);
}
/**
* Form submission handler for the 'preview' action.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function preview(array &$form, FormStateInterface $form_state) {
$knowledge_preview = knowledge_preview($this->entity, $form_state);
$knowledge_preview['#title'] = $this->t('Preview knowledge');
$form_state->set('knowledge_preview', $knowledge_preview);
$form_state->setRebuild();
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
/** @var \Drupal\knowledge\KnowledgeInterface $knowledge */
$knowledge = $this->entity;
$knowledge->setNewRevision(TRUE);
$entity = $knowledge->getKnowledgeedEntity();
$field_name = $knowledge->getFieldName();
$uri = $entity->toUrl();
$logger = $this->logger('knowledge');
$status = 0;
if ($this->currentUser->hasPermission('post knowledge')
&& ($this->currentUser->hasPermission('administer knowledge') || $entity->{$field_name}->status == KnowledgeItemInterface::OPEN)) {
$status = $knowledge->save();
$form_state->setValue('kid', $knowledge->id());
// Add a log entry.
$logger->notice('Knowledge posted: %subject.', [
'%subject' => $knowledge->label(),
'link' => Link::fromTextAndUrl($this->t('View'), $knowledge->toUrl()->setOption('fragment', 'knowledge-' . $knowledge->id()))->toString(),
]);
// Explain the approval queue if necessary.
if (!$knowledge->isPublished()) {
if (!$this->currentUser->hasPermission('administer knowledge')) {
$this->messenger()->addStatus($this->t('Your knowledge has been queued for review by site administrators and will be published after approval.'));
}
}
else {
$this->messenger()->addStatus($this->t('Your knowledge has been posted.'));
}
$query = [];
// Find the current display page for this knowledge.
$field_definition = $this->entityFieldManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle())[$field_name];
/** @var \Drupal\knowledge\KnowledgeStorageInterface $knowledge_storage */
$knowledge_storage = $this->entityTypeManager->getStorage('knowledge');
$page = $knowledge_storage->getDisplayOrdinal($knowledge, $field_definition->getSetting('default_mode'), $field_definition->getSetting('per_page'));
if ($page > 0) {
$query['page'] = $page;
}
// Redirect to the newly posted knowledge.
$uri->setOption('query', $query);
$uri->setOption('fragment', 'knowledge-' . $knowledge->id());
}
else {
$logger->warning('Knowledge: unauthorized knowledge submitted or knowledge submitted to a closed post %subject.', ['%subject' => $knowledge->label()]);
$this->messenger()->addError($this->t('Knowledge: unauthorized knowledge submitted or knowledge submitted to a closed post %subject.', ['%subject' => $knowledge->label()]));
// Redirect the user to the entity they are linking on.
}
$form_state->setRedirectUrl($uri);
return $status;
}
}
