openquestions-1.0.x-dev/src/Form/AddVoteForm.php

src/Form/AddVoteForm.php
<?php

namespace Drupal\openquestions\Form;

use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\OpenModalDialogCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\openquestions\Service\VoteDataFactoryInterface;

/**
 * Implements the AddVoteForm form controller.
 *
 * @see \Drupal\Core\Form\FormBase
 */
class AddVoteForm extends FormBase {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManager
   */
  protected $entityTypeManager;

  /**
   * The vote data factory.
   *
   * @var \Drupal\openquestions\Service\VoteDataFactoryInterface
   */
  protected $voteDataFactory;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    // Create a new form object and inject its services.
    $form = new static();
    $form->setRequestStack($container->get('request_stack'));
    $form->setStringTranslation($container->get('string_translation'));
    $form->setMessenger($container->get('messenger'));
    $form->setEntityTypeManager($container->get('entity_type.manager'));
    $form->setVoteDataFactory($container->get('openquestions.oq_vote_data_factory'));
    return $form;
  }

  /**
   * Sets the entity type manager.
   */
  public function setEntityTypeManager(EntityTypeManager $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * Sets the vote data factory.
   */
  public function setVoteDataFactory(VoteDataFactoryInterface $voteDataFactory) {
    $this->voteDataFactory = $voteDataFactory;
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'add_oq_vote_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $oq_item_id = NULL, $oq_question_id = NULL, $uid = NULL, $nojs = NULL) {
    $form_state->set('already_voted', FALSE);

    $item = $this->entityTypeManager->getStorage('oq_item')->load($oq_item_id);
    $question = $this->entityTypeManager->getStorage('oq_question')->load($oq_question_id);
    $account = $this->entityTypeManager->getStorage('user')->load($uid);
    if (!$item || !$question || !$account ||
        $account->id() != $this->currentUser()->id() || !$account->hasPermission('vote on oq item')) {
      $form['error'] = [
        '#type' => 'item',
        '#markup' => $this->getGenericErrorMessage(),
      ];

      return $form;
    }

    $form_state->set('oq_item_id', $oq_item_id);
    $form_state->set('oq_question_id', $oq_question_id);
    $form_state->set('uid', $uid);

    // Add the core AJAX library.
    $form['#attached']['library'][] = 'core/drupal.ajax';

    $form['description'] = [
      '#type' => 'item',
      '#markup' => $this->t('Enter your vote for the question <span class="oq-question-quote">@question</span> on the item <a class="oq-item-quote" href=":item_url">"@item"</a>.', [
        '@item' => $item->label(),
        '@question' => $question->label(),
        ':item_url' => $item->toUrl()->toString(),
      ]),
    ];

    $form['vote_value'] = [
      '#type' => 'radios',
      '#title' => 'Vote value',
      '#required' => TRUE,
      '#options' => $question->getOptions(),
    ];

    // This element is responsible for displaying form errors in the AJAX
    // dialog.
    if ($nojs == 'ajax') {
      $form['status_messages'] = [
        '#type' => 'status_messages',
        '#weight' => -999,
      ];
    }

    $form['rationale'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Enter the reason for your vote'),
      '#description' => $this->t('Enter at least 10 words'),
      '#required' => TRUE,
      '#attributes' => [
        'class' => ['js-text-counter'],
      ],
    ];

    // Group submit handlers in an actions element with a key of "actions" so
    // that it gets styled correctly, and so that other modules may add actions
    // to the form.
    $form['actions'] = [
      '#type' => 'actions',
    ];

    // Add a submit button that handles the submission of the form.
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save vote'),
      '#ajax' => [
        'callback' => '::ajaxSubmitForm',
        'event' => 'click',
      ],
    ];

    $form['#attached']['library'][] = 'openquestions/jquery_textcounter';
    $form['#attached']['library'][] = 'openquestions/openquestions_voting';

    // Set the form to not use AJAX if we're on a nojs path. When this form is
    // within the modal dialog, Drupal will make sure we're using an AJAX path
    // instead of a nojs one.
    if ($nojs == 'nojs') {
      unset($form['actions']['submit']['#ajax']);
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    if ($form_state->get('already_voted')) {
      return;
    }

    $voteValue = $form_state->getValue('vote_value');
    $rationale = $form_state->getValue('rationale');
    $oq_item_id = $form_state->get('oq_item_id');
    $oq_question_id = $form_state->get('oq_question_id');
    $uid = $form_state->get('uid');

    $message = $this->createVote($oq_item_id, $oq_question_id, $uid, $voteValue, $rationale);
    $form_state->set('already_voted', TRUE);

    $message = $message ? $message : $this->t('Your vote has been saved.');

    $this->messenger()->addMessage($message);
  }

  /**
   * Implements the submit handler for the modal dialog AJAX call.
   *
   * @param array $form
   *   Render array representing from.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Current form state.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   Array of AJAX commands to execute on submit of the modal form.
   */
  public function ajaxSubmitForm(array &$form, FormStateInterface $form_state) {
    $title = $this->t('Success');
    $content = [
      '#type' => 'item',
      '#markup' => $this->t('Your vote has been saved.'),
    ];

    // We begin building a new ajax reponse.
    $response = new AjaxResponse();

    if ($form_state->get('already_voted')) {
      $oq_item_id = $form_state->get('oq_item_id');
      $oq_question_id = $form_state->get('oq_question_id');
      $uid = $form_state->get('uid');

      $voteData = $this->voteDataFactory->createVoteDataForItem($oq_item_id);
      $votes = $voteData->getVotesForQuestionIdAndAccountId($oq_question_id, $uid);
      if ($votes && count($votes) > 0) {
        $vote = array_shift($votes);
        if ($vote && $vote->get('status')->value) {
          $question = $this->entityTypeManager->getStorage('oq_question')->load($oq_question_id);
          $selector = '#votelink-item' . intval($oq_item_id) . '-question' . intval($oq_question_id) . '-uid' . intval($uid);

          $replacement = [
            '#type' => 'link',
            '#title' => $question->getOptionName($vote->get('vote_value')->value),
            '#attributes' => ['class' => ['oq_vote']],
            '#url' => $vote->toUrl(),
          ];

          $response->addCommand(new ReplaceCommand($selector, $replacement));
        }
      }

      $response->addCommand(new OpenModalDialogCommand($title, $content, $this->getDataDialogOptions()));

      return $response;
    }

    // If the user submitted the form and there are errors, show them the
    // input dialog again with error messages. Since the title element is
    // required, the empty string wont't validate and there will be an error.
    if ($form_state->getErrors()) {
      // If there are errors, we can show the form again with the errors in
      // the status_messages section.
      $form['status_messages'] = [
        '#type' => 'status_messages',
        '#weight' => -10,
      ];
      $response->addCommand(new OpenModalDialogCommand($this->t('Errors'), $form, $this->getDataDialogOptions()));
    }
    // If there are no errors, show the output dialog.
    else {
      // We don't want any messages that were added by submitForm().
      $this->messenger()->deleteAll();

      $oq_item_id = $form_state->get('oq_item_id');
      $oq_question_id = $form_state->get('oq_question_id');
      $uid = $form_state->get('uid');
      $voteValue = $form_state->getValue('vote_value');
      $rationale = $form_state->getValue('rationale');

      $message = $this->createVote($oq_item_id, $oq_question_id, $uid, $voteValue, $rationale);
      $form_state->set('already_voted', TRUE);

      if ($message) {
        $title = $this->t('An error occured');
        $content = [
          '#type' => 'item',
          '#markup' => $message,
        ];
      }

      // Add the OpenModalDialogCommand to the response. This will cause Drupal
      // AJAX to show the modal dialog. The user can click the little X to close
      // the dialog.
      $response->addCommand(new OpenModalDialogCommand($title, $content, $this->getDataDialogOptions()));
    }

    // Finally return our response.
    return $response;
  }

  /**
   * Create a vote from the given parameters.
   */
  protected function createVote($oq_item_id, $oq_question_id, $uid, $voteValue, $rationale) {
    $item = $this->entityTypeManager->getStorage('oq_item')->load($oq_item_id);
    $question = $this->entityTypeManager->getStorage('oq_question')->load($oq_question_id);
    $account = $this->entityTypeManager->getStorage('user')->load($uid);
    if (!$item || !$question || !$account ||
        $account->id() != $this->currentUser()->id() || !$account->hasPermission('vote on oq item')) {
      return $this->getGenericErrorMessage();
    }

    $options = $question->getOptions();
    if (empty($options[$voteValue])) {
      return $this->getGenericErrorMessage();
    }

    $voteData = $this->voteDataFactory->createVoteDataForItem($oq_item_id);
    $votes = $voteData->getVotesForQuestionIdAndAccountId($oq_question_id, $uid);
    if ($votes && count($votes) > 0 && $votes[0]->get('status')->value) {
      return $this->getAlreadyVotedMessage();
    }

    $label = $this->t('Vote on item @oq_item_id, question @oq_question_id by uid @uid', [
      '@oq_item_id' => $oq_item_id,
      '@oq_question_id' => $oq_question_id,
      '@uid' => $uid,
    ]);

    $data = [
      'label' => $label,
      'status' => TRUE,
      'description' => $rationale,
      'uid' => $account,
      'vote_value' => $voteValue,
      'item' => $item,
      'question' => $question,
    ];

    $vote = $this->entityTypeManager->getStorage('oq_vote')->create($data);
    $vote->save();

    return NULL;
  }

  /**
   * Returns a message.
   */
  protected function getGenericErrorMessage() {
    return $this->t('An error occured. Please reload the page and try again. If the problem persists, contact an administrator');
  }

  /**
   * Returns a message.
   */
  protected function getAlreadyVotedMessage() {
    return $this->t('You appear to have already voted on this item & question. If that is in error, please reload the page and try again. If the problem persists, contact an administrator');
  }

  /**
   * Helper method so we can have consistent dialog options.
   *
   * @return string[]
   *   An array of jQuery UI elements to pass on to our dialog form.
   */
  protected function getDataDialogOptions() {
    return [
      'width' => '50%',
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc