sitewide_alerts-1.0.0/src/Form/SiteAlertTweetForm.php
src/Form/SiteAlertTweetForm.php
<?php
namespace Drupal\sitewide_alerts\Form;
use Abraham\TwitterOAuth\TwitterOAuth;
use Abraham\TwitterOAuth\TwitterOAuthException;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Url;
use Drupal\key\KeyRepository;
use Drupal\sitewide_alerts\SiteAlertInterface;
use Drupal\sitewide_alerts\SiteAlertService;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a form for tweeting site alert.
*/
class SiteAlertTweetForm extends FormBase {
const TWEET_ALERT_DEFAULT_TEXT = 'New alert: @alert_link';
/**
* The site alert entity id.
*/
protected int $siteAlertId;
/**
* The site alert entity.
*/
protected SiteAlertInterface $siteAlert;
/**
* The site alert service.
*/
protected SiteAlertService $siteAlertService;
/**
* The language manager.
*/
protected LanguageManager $languageManager;
/**
* The current language code.
*/
protected string $language;
/**
* The key repository.
*/
protected KeyRepository $keyRepository;
/**
* The constructor.
*
* @param \Drupal\sitewide_alerts\SiteAlertService $site_alert_service
* The site alert service.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
* @param \Drupal\key\KeyRepository $key_repository
* The key repository.
*/
public function __construct(
SiteAlertService $site_alert_service,
LanguageManager $language_manager,
KeyRepository $key_repository
) {
$this->siteAlertService = $site_alert_service;
$this->languageManager = $language_manager;
$this->language = $language_manager->getCurrentLanguage()->getId();
$this->keyRepository = $key_repository;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('sitewide_alerts.site_alert_service'),
$container->get('language_manager'),
$container->get('key.repository')
);
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return "site_alert_tweet_form";
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $site_alert = NULL): array {
$disabled = FALSE;
// Check for site alert entity.
if (empty($site_alert)) {
$this->messenger()
->addError($this->t('Site alert is missing or not found. Unable to tweet alert.'));
$disabled = TRUE;
}
$this->siteAlertId = (int) $site_alert;
$this->siteAlert = $this->siteAlertService->getSiteAlert($this->siteAlertId);
$state_keys = [
'twitter_key_name.' . $this->language,
'twitter_access_token.' . $this->language,
'twitter_secret_token.' . $this->language,
];
$config = $this->siteAlertService->getStateConfig($state_keys);
// Twitter credentials key check.
$twitter_key_name = $config['twitter_key_name.' . $this->language] ?? NULL;
if (empty($twitter_key_name)) {
$this->messenger()
->addWarning($this->t('Twitter app key is not configured. Please configure key on <a href="@link">settings page</a>.', [
'@link' => Url::fromRoute('sitewide_alerts.twitter_config_form')
->toString(),
]));
$disabled = TRUE;
}
// Twitter account authorization check.
$twitter_access_token = $config['twitter_access_token.' . $this->language] ?? NULL;
$twitter_secret_token = $config['twitter_secret_token.' . $this->language] ?? NULL;
if (empty($twitter_access_token) || empty($twitter_secret_token)) {
$this->messenger()
->addWarning($this->t('Twitter account authorization has not been completed. Please <a href="@link">authorize account</a> now.', [
'@link' => Url::fromRoute('sitewide_alerts.twitter_authorize_form')
->toString(),
]));
$disabled = TRUE;
}
$form['twitter'] = [
'#type' => 'fieldset',
'#title' => $this->t('Twitter configuration'),
'#disabled' => $disabled,
];
$form['twitter']['language'] = [
'#markup' => '<p>' . $this->t('Language: %language', ['%language' => $this->languageManager->getCurrentLanguage()->getName()]) . '</p>',
];
$tweet = $this::TWEET_ALERT_DEFAULT_TEXT;
if (!empty($form_state->getValue('tweet'))) {
$tweet = $form_state->getValue('tweet');
}
$form['twitter']['tweet'] = [
'#type' => 'textarea',
'#title' => $this->t('Tweet message'),
'#description' => $this->t('Text that would be pushed for tweet.<br>The following placeholders are available: @alert_title, @alert_link, @alerts_link.'),
'#maxlength' => 280,
'#default_value' => $tweet,
'#required' => TRUE,
'#maxlength_js' => TRUE,
'#attributes' => [
'data-maxlength' => 280,
'class' => [
'maxlength',
'maxlength_js_enforce',
],
],
'#attached' => [
'library' => [
'maxlength/maxlength',
],
],
];
$form['twitter']['update_preview'] = [
'#type' => 'button',
'#value' => $this->t('Update preview'),
'#ajax' => [
'event' => 'click',
'callback' => '::updatePreviewCallback',
'wrapper' => 'tweet-preview',
],
];
$form['twitter']['preview'] = [
'#type' => 'fieldset',
'#title' => $this->t('Tweet preview'),
];
// Replace placeholders.
$tweet = $this->replacePlaceholders($tweet);
$form['twitter']['preview']['tweet_preview'] = [
'#markup' => sprintf('<div id="tweet-preview">%s</div>', $tweet),
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Push tweet'),
'#disabled' => $disabled,
];
return $form;
}
/**
* Update preview AJAX callback.
*
* @param array $form
* The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return array
* Returns the preview form element.
*/
public function updatePreviewCallback(array $form, FormStateInterface $form_state): array {
return $form['twitter']['preview']['tweet_preview'];
}
/**
* Replace tweet message placeholders.
*
* @param string $tweet
* The tweet message.
*
* @return string
* Returns the tweet message with placeholders replaced.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityMalformedException
*/
private function replacePlaceholders(string $tweet): string {
// Get site alert link.
$alert_link = $this->siteAlert->getAlertLink();
// Get default site alerts page/link.
$alerts_link = '';
$config = $this->siteAlertService->getConfig();
$alerts_page_nid = $config->get('default_alerts_page');
if (!empty($alerts_page_nid)) {
/** @var \Drupal\node\Entity\Node $node */
$node = $this->siteAlertService->getEntityTypeManager()->getStorage('node')
->load($alerts_page_nid);
// Get proper translation.
if ($node->isTranslatable() && $node->hasTranslation($this->language)) {
$node = $node->getTranslation($this->language);
}
if ($node) {
$options = [
'language' => $this->languageManager->getCurrentLanguage(),
'absolute' => TRUE,
];
$alerts_link = $node->toUrl()->setOptions($options)->toString();
}
}
// Get site alert title.
$alert_title = $this->siteAlert->label();
// Replace placeholders.
return str_replace(['@alert_link', '@alerts_link', '@alert_title'], [
$alert_link,
$alerts_link,
$alert_title,
], $tweet);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$tweet = $form_state->getValue('tweet');
if (empty($tweet)) {
$form_state->setErrorByName('tweet', $this->t('Tweet message is blank.'));
}
if (strlen($tweet) > 280) {
$form_state->setErrorByName('tweet', $this->t('Tweet message has exceeded 280 characters.'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Make sure we have site alert entity.
if (!empty($this->siteAlert)) {
// Get language and proper site alert translation to use.
if ($this->siteAlert->hasTranslation($this->language)) {
$this->siteAlert = $this->siteAlert->getTranslation($this->language);
}
// Get submitted tweet/text.
$tweet = $form_state->getValue('tweet');
// Replace placeholders.
$tweet = $this->replacePlaceholders($tweet);
// Make sure we have tweet/text and is valid.
if (!empty($tweet)) {
// Get current language and associated twitter configuration.
$state_keys = [
'twitter_key_name.' . $this->language,
'twitter_access_token.' . $this->language,
'twitter_secret_token.' . $this->language,
];
$config = $this->siteAlertService->getStateConfig($state_keys);
// Get twitter key name.
$twitter_key_name = $config['twitter_key_name.' . $this->language] ?? NULL;
if (!empty($twitter_key_name)) {
// Get key and credentials.
$twitter_credentials = parse_ini_string($this->keyRepository->getKey($twitter_key_name)->getKeyValue());
// Set twitter configuration vars.
$twitter_version = $twitter_credentials['version'] ?? NULL;
$twitter_consumer_key = $twitter_credentials['key'] ?? NULL;
$twitter_consumer_secret = $twitter_credentials['key_secret'] ?? NULL;
// Set access token.
$twitter_access_token = $twitter_credentials['access_token'] ?? NULL;
if (!empty($config['twitter_access_token.' . $this->language])) {
$twitter_access_token = $config['twitter_access_token.' . $this->language];
}
// Set secret token.
$twitter_access_token_secret = $twitter_credentials['access_token_secret'] ?? NULL;
if (!empty($config['twitter_secret_token.' . $this->language])) {
$twitter_access_token_secret = $config['twitter_secret_token.' . $this->language];
}
try {
// Attempt to tweet alert.
$connection = new TwitterOAuth($twitter_consumer_key, $twitter_consumer_secret, $twitter_access_token, $twitter_access_token_secret);
// Set version.
if (!empty($twitter_version)) {
$connection->setApiVersion($twitter_version);
}
// Adjust API call for specified version.
if ($twitter_version == 2) {
// Version 2 call.
$result = $connection->post('tweets', ['text' => $tweet], TRUE);
}
else {
// Version 1.1 call. Requires elevated access.
$result = $connection->post("statuses/update", ["status" => $tweet]);
}
// Check http code and display proper message.
if ($connection->getLastHttpCode() == 200 || $connection->getLastHttpCode() == 201) {
$this->messenger()
->addMessage($this->t('Tweet alert was successfully sent! "@message"', ['@message' => $tweet]));
}
else {
if (is_array($result)) {
$this->messenger()->addError($result->errors[0]->message);
}
else {
$this->messenger()
->addError($this->t('Failed to tweet alert. Please try again.'));
}
}
}
catch (TwitterOAuthException $exception) {
watchdog_exception('sitewide_alerts', $exception);
$this->messenger()->addError($exception->getMessage());
}
}
}
}
}
}
