FormHelper.php 13.3 KB
Newer Older
1 2
<?php

3
namespace Drupal\simple_sitemap\Form;
4

gbyte.co's avatar
gbyte.co committed
5
use Drupal\Core\Form\FormStateInterface;
6
use Drupal\Core\StringTranslation\StringTranslationTrait;
7
use Drupal\simple_sitemap\EntityHelper;
gbyte.co's avatar
gbyte.co committed
8 9
use Drupal\simple_sitemap\Simplesitemap;
use Drupal\Core\Session\AccountProxyInterface;
10

11
/**
gbyte.co's avatar
gbyte.co committed
12
 * Class FormHelper
13
 * @package Drupal\simple_sitemap\Form
14
 */
15
class FormHelper {
16
  use StringTranslationTrait;
17

gbyte.co's avatar
gbyte.co committed
18 19 20 21
  const PRIORITY_DEFAULT = 0.5;
  const PRIORITY_HIGHEST = 10;
  const PRIORITY_DIVIDER = 10;

gbyte.co's avatar
gbyte.co committed
22 23 24
  /**
   * @var \Drupal\simple_sitemap\Simplesitemap
   */
25
  protected $generator;
gbyte.co's avatar
gbyte.co committed
26 27 28 29

  /**
   * @var \Drupal\simple_sitemap\EntityHelper
   */
30
  protected $entityHelper;
gbyte.co's avatar
gbyte.co committed
31 32 33 34

  /**
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
35
  protected $currentUser;
gbyte.co's avatar
gbyte.co committed
36 37 38 39

  /**
   * @var \Drupal\Core\Form\FormState
   */
40
  protected $formState;
41

gbyte.co's avatar
gbyte.co committed
42 43 44
  /**
   * @var string|null
   */
gbyte.co's avatar
gbyte.co committed
45
  protected $entityCategory;
gbyte.co's avatar
gbyte.co committed
46 47 48 49

  /**
   * @var string
   */
50
  protected $entityTypeId;
gbyte.co's avatar
gbyte.co committed
51 52 53 54

  /**
   * @var string
   */
55
  protected $bundleName;
gbyte.co's avatar
gbyte.co committed
56 57 58 59

  /**
   * @var string
   */
60
  protected $instanceId;
61

62
  protected static $allowedFormOperations = [
63 64 65
    'default',
    'edit',
    'add',
gbyte.co's avatar
gbyte.co committed
66
    'register',
67 68
  ];

69 70 71 72 73 74 75 76 77 78
  protected static $changefreqSelectValues = [
    'always',
    'hourly',
    'daily',
    'weekly',
    'monthly',
    'yearly',
    'never',
  ];

79
  protected static $valuesToCheck = [
80 81
    'simple_sitemap_index_content',
    'simple_sitemap_priority',
82
    'simple_sitemap_changefreq',
gbyte.co's avatar
gbyte.co committed
83
    'simple_sitemap_regenerate_now',
84
  ];
85

86
  /**
87 88 89 90
   * FormHelper constructor.
   * @param \Drupal\simple_sitemap\Simplesitemap $generator
   * @param \Drupal\simple_sitemap\EntityHelper $entityHelper
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
91
   */
gbyte.co's avatar
gbyte.co committed
92 93
  public function __construct(
    Simplesitemap $generator,
94
    EntityHelper $entityHelper,
gbyte.co's avatar
gbyte.co committed
95 96
    AccountProxyInterface $current_user
  ) {
97
    $this->generator = $generator;
98
    $this->entityHelper = $entityHelper;
99
    $this->currentUser = $current_user;
100
  }
101

102
  /**
gbyte.co's avatar
gbyte.co committed
103 104
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   * @return bool
105
   */
gbyte.co's avatar
gbyte.co committed
106
  public function processForm(FormStateInterface $form_state) {
107
    $this->formState = $form_state;
108
    $this->cleanUpFormInfo();
109
    $this->getEntityDataFromFormEntity();
gbyte.co's avatar
gbyte.co committed
110
    return $this->supports();
111 112
  }

113
  /**
gbyte.co's avatar
gbyte.co committed
114
   * @param string $entity_category
115 116
   * @return $this
   */
117 118
  public function setEntityCategory($entity_category) {
    $this->entityCategory = $entity_category;
119
    return $this;
120 121
  }

122
  /**
123
   * @return null|string
124
   */
125 126 127 128 129 130 131 132
  public function getEntityCategory() {
    return $this->entityCategory;
  }

  /**
 * @param string $entity_type_id
 * @return $this
 */
133 134
  public function setEntityTypeId($entity_type_id) {
    $this->entityTypeId = $entity_type_id;
135
    return $this;
136 137
  }

138 139 140 141 142 143 144
  /**
   * @return string
   */
  public function getEntityTypeId() {
    return $this->entityTypeId;
  }

145
  /**
gbyte.co's avatar
gbyte.co committed
146
   * @param string $bundle_name
147 148
   * @return $this
   */
149 150
  public function setBundleName($bundle_name) {
    $this->bundleName = $bundle_name;
151
    return $this;
152 153
  }

154 155 156 157 158 159 160
  /**
   * @return string
   */
  public function getBundleName() {
    return $this->bundleName;
  }

161
  /**
gbyte.co's avatar
gbyte.co committed
162
   * @param string $instance_id
163 164
   * @return $this
   */
165 166
  public function setInstanceId($instance_id) {
    $this->instanceId = $instance_id;
167
    return $this;
168 169
  }

170 171 172 173 174 175 176
  /**
   * @return string
   */
  public function getInstanceId() {
    return $this->instanceId;
  }

gbyte.co's avatar
gbyte.co committed
177
  /**
gbyte.co's avatar
gbyte.co committed
178
   * @return bool
gbyte.co's avatar
gbyte.co committed
179
   */
gbyte.co's avatar
gbyte.co committed
180
  protected function supports() {
gbyte.co's avatar
gbyte.co committed
181 182

    // Do not alter the form if user lacks certain permissions.
gbyte.co's avatar
gbyte.co committed
183
    if (!$this->currentUser->hasPermission('administer sitemap settings')) {
gbyte.co's avatar
gbyte.co committed
184
      return FALSE;
gbyte.co's avatar
gbyte.co committed
185
    }
gbyte.co's avatar
gbyte.co committed
186 187

    // Do not alter the form if it is irrelevant to sitemap generation.
188
    elseif (empty($this->getEntityCategory())) {
gbyte.co's avatar
gbyte.co committed
189
      return FALSE;
gbyte.co's avatar
gbyte.co committed
190
    }
gbyte.co's avatar
gbyte.co committed
191 192

    // Do not alter the form if entity is not enabled in sitemap settings.
193
    elseif (!$this->generator->entityTypeIsEnabled($this->getEntityTypeId())) {
gbyte.co's avatar
gbyte.co committed
194
      return FALSE;
gbyte.co's avatar
gbyte.co committed
195
    }
gbyte.co's avatar
gbyte.co committed
196 197 198

    // Do not alter the form, if sitemap is disabled for the entity type of this
    // entity instance.
199 200
    elseif ($this->getEntityCategory() == 'instance'
      && !$this->generator->bundleIsIndexed($this->getEntityTypeId(), $this->getBundleName())) {
gbyte.co's avatar
gbyte.co committed
201
      return FALSE;
gbyte.co's avatar
gbyte.co committed
202
    }
gbyte.co's avatar
gbyte.co committed
203 204

    return TRUE;
gbyte.co's avatar
gbyte.co committed
205 206
  }

207
  /**
gbyte.co's avatar
gbyte.co committed
208
   * @param array $form_fragment
209
   */
gbyte.co's avatar
gbyte.co committed
210
  public function displayRegenerateNow(&$form_fragment) {
211
    $form_fragment['simple_sitemap_regenerate_now'] = [
212
      '#type' => 'checkbox',
213 214
      '#title' => $this->t('Regenerate sitemap after hitting <em>Save</em>'),
      '#description' => $this->t('This setting will regenerate the whole sitemap including the above changes.'),
215
      '#default_value' => FALSE,
216
    ];
217
    if ($this->generator->getSetting('cron_generate')) {
218
      $form_fragment['simple_sitemap_regenerate_now']['#description'] .= '</br>' . $this->t('Otherwise the sitemap will be regenerated during a future cron run.');
219 220
    }
  }
221 222

  /**
223
   * @param array $form_fragment
224 225 226
   * @param bool $multiple
   * @return $this
   */
227
  public function displayEntitySettings(&$form_fragment, $multiple = FALSE) {
228
    $prefix = $multiple ? $this->getEntityTypeId() . '_' : '';
229

230 231 232
    if ($this->getEntityCategory() == 'instance') {
      $bundle_settings = $this->generator->getBundleSettings($this->getEntityTypeId(), $this->getBundleName());
      $settings = NULL !== $this->getInstanceId() ? $this->generator->getEntityInstanceSettings($this->getEntityTypeId(), $this->getInstanceId()) : $bundle_settings;
233
    }
234
    else {
235
      $settings = $this->generator->getBundleSettings($this->getEntityTypeId(), $this->getBundleName());
236 237 238
    }
    $index = isset($settings['index']) ? $settings['index'] : 0;
    $priority = isset($settings['priority']) ? $settings['priority'] : self::PRIORITY_DEFAULT;
239
    $changefreq = !empty($settings['changefreq']) ? $settings['changefreq'] : '';
240
    $bundle_name = !empty($this->getBundleName()) ? $this->getBundleName() : $this->t('undefined');
241 242 243 244 245 246

    if (!$multiple) {
      $form_fragment[$prefix . 'simple_sitemap_index_content'] = [
        '#type' => 'radios',
        '#default_value' => $index,
        '#options' => [
247 248
          0 => $this->getEntityCategory() == 'instance' ? $this->t('Do not index this @bundle entity', ['@bundle' => $bundle_name]) : $this->t('Do not index entities of this type'),
          1 => $this->getEntityCategory() == 'instance' ? $this->t('Index this @bundle entity', ['@bundle' => $bundle_name]) : $this->t('Index entities of this type'),
gbyte.co's avatar
gbyte.co committed
249
        ],
250
      ];
251
      if ($this->getEntityCategory() == 'instance' && isset($bundle_settings['index'])) {
252
        $form_fragment[$prefix . 'simple_sitemap_index_content']['#options'][$bundle_settings['index']] .= ' <em>(' . $this->t('Default') . ')</em>';
253 254 255
      }
    }

256
    if ($this->getEntityCategory() == 'instance') {
257
      $priority_description = $this->t('The priority this @bundle entity will have in the eyes of search engine bots.', ['@bundle' => $bundle_name]);
258
      $changefreq_description = $this->t('The frequency with which this @bundle entity changes. Search engine bots may take this as an indication of how often to index it.', ['@bundle' => $bundle_name]);
gbyte.co's avatar
gbyte.co committed
259 260
    }
    else {
261
      $priority_description = $this->t('The priority entities of this type will have in the eyes of search engine bots.');
262
      $changefreq_description = $this->t('The frequency with which entities of this type change. Search engine bots may take this as an indication of how often to index them.');
gbyte.co's avatar
gbyte.co committed
263
    }
264

265 266
    $form_fragment[$prefix . 'simple_sitemap_priority'] = [
      '#type' => 'select',
267
      '#title' => $this->t('Priority'),
268 269
      '#description' => $priority_description,
      '#default_value' => $priority,
270
      '#options' => $this->getPrioritySelectValues(),
271
    ];
272

273
    if ($this->getEntityCategory() == 'instance' && isset($bundle_settings['priority'])) {
274
      $form_fragment[$prefix . 'simple_sitemap_priority']['#options'][$this->formatPriority($bundle_settings['priority'])] .= ' (' . $this->t('Default') . ')';
275
    }
276 277 278 279 280 281 282 283 284 285 286 287 288

    $form_fragment[$prefix . 'simple_sitemap_changefreq'] = [
      '#type' => 'select',
      '#title' => $this->t('Change frequency'),
      '#description' => $changefreq_description,
      '#default_value' => $changefreq,
      '#options' => $this->getChangefreqSelectValues(),
    ];

    if ($this->getEntityCategory() == 'instance' && isset($bundle_settings['changefreq'])) {
      $form_fragment[$prefix . 'simple_sitemap_changefreq']['#options'][$bundle_settings['changefreq']] .= ' (' . $this->t('Default') . ')';
    }

289
    return $this;
290 291 292 293 294 295 296
  }

  /**
   * Checks if this particular form is a bundle form, or a bundle instance form
   * and gathers sitemap settings from the database.
   *
   * @return bool
gbyte.co's avatar
gbyte.co committed
297
   *   TRUE if this is a bundle or bundle instance form, FALSE otherwise.
298
   */
299
  protected function getEntityDataFromFormEntity() {
300 301
    $form_entity = $this->getFormEntity();
    if ($form_entity !== FALSE) {
302
      $entity_type_id = $form_entity->getEntityTypeId();
gbyte.co's avatar
gbyte.co committed
303
      $sitemap_entity_types = $this->entityHelper->getSupportedEntityTypes();
304
      if (isset($sitemap_entity_types[$entity_type_id])) {
305
        $this->setEntityCategory('instance');
306 307
      }
      else {
gbyte.co's avatar
gbyte.co committed
308 309 310 311 312
        /**
         * @var \Drupal\Core\Entity\EntityType $sitemap_entity_type
         */
        foreach ($sitemap_entity_types as $sitemap_entity_type) {
          if ($sitemap_entity_type->getBundleEntityType() == $entity_type_id) {
313
            $this->setEntityCategory('bundle');
314
            break;
315 316 317
          }
        }
      }
318

319
      // Menu fix.
320
      $this->setEntityCategory(NULL === $this->getEntityCategory() && $entity_type_id == 'menu' ? 'bundle' : $this->getEntityCategory());
321

322
      switch ($this->getEntityCategory()) {
323
        case 'bundle':
324 325 326
          $this->setEntityTypeId($this->entityHelper->getBundleEntityTypeId($form_entity));
          $this->setBundleName($form_entity->id());
          $this->setInstanceId(NULL);
327 328 329
          break;

        case 'instance':
330 331
          $this->setEntityTypeId($entity_type_id);
          $this->setBundleName($this->entityHelper->getEntityInstanceBundleName($form_entity));
gbyte.co's avatar
gbyte.co committed
332
          // New menu link's id is '' instead of NULL, hence checking for empty.
333
          $this->setInstanceId(!empty($form_entity->id()) ? $form_entity->id() : NULL);
334 335 336 337 338 339
          break;

        default:
          return FALSE;
      }
      return TRUE;
340 341 342 343 344 345 346
    }
    return FALSE;
  }

  /**
   * Gets the object entity of the form if available.
   *
gbyte.co's avatar
gbyte.co committed
347
   * @return \Drupal\Core\Entity\Entity|false
gbyte.co's avatar
gbyte.co committed
348 349
   *   Entity or FALSE if non-existent or if form operation is
   *   'delete'.
350
   */
351
  protected function getFormEntity() {
352
    $form_object = $this->formState->getFormObject();
353
    if (NULL !== $form_object
354
      && method_exists($form_object, 'getOperation')
355
      && method_exists($form_object, 'getEntity')
356
      && in_array($form_object->getOperation(), self::$allowedFormOperations)) {
357 358 359 360 361
      return $form_object->getEntity();
    }
    return FALSE;
  }

362 363 364 365 366 367 368 369 370 371 372 373 374
  /**
   * Removes gathered form information from service object.
   *
   * Needed because this service may contain form info from the previous
   * operation when revived from the container.
   */
  protected function cleanUpFormInfo() {
    $this->entityCategory = NULL;
    $this->entityTypeId = NULL;
    $this->bundleName = NULL;
    $this->instanceId = NULL;
  }

375 376 377 378
  /**
   * Gets new entity Id after entity creation.
   * To be used in an entity form submit.
   *
gbyte.co's avatar
gbyte.co committed
379
   * @return int
gbyte.co's avatar
gbyte.co committed
380
   *   Entity ID.
381
   */
382 383
  public function getFormEntityId() {
    return $this->formState->getFormObject()->getEntity()->id();
384 385 386 387 388 389
  }

  /**
   * Checks if simple_sitemap values have been changed after submitting the form.
   * To be used in an entity form submit.
   *
390
   * @param $form
391
   * @param array $values
gbyte.co's avatar
gbyte.co committed
392
   *
393
   * @return bool
gbyte.co's avatar
gbyte.co committed
394
   *   TRUE if simple_sitemap form values have been altered by the user.
395
   */
396
  public function valuesChanged($form, array $values) {
397
    foreach (self::$valuesToCheck as $field_name) {
398
      if (isset($values[$field_name]) && $values[$field_name] != $form['simple_sitemap'][$field_name]['#default_value']) {
399 400 401 402 403
        return TRUE;
      }
    }
    return FALSE;
  }
gbyte.co's avatar
gbyte.co committed
404 405 406 407

  /**
   * Gets the values needed to display the priority dropdown setting.
   *
408
   * @return array
409
   *   Select options.
gbyte.co's avatar
gbyte.co committed
410
   */
411
  public function getPrioritySelectValues() {
412
    $options = [];
gbyte.co's avatar
gbyte.co committed
413
    foreach (range(0, self::PRIORITY_HIGHEST) as $value) {
414
      $value = $this->formatPriority($value / self::PRIORITY_DIVIDER);
415
      $options[$value] = $value;
gbyte.co's avatar
gbyte.co committed
416 417 418
    }
    return $options;
  }
419

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
  /**
   * Gets the values needed to display the changefreq dropdown setting.
   *
   * @return array
   *   Select options.
   */
  public function getChangefreqSelectValues() {
    $options = ['' => t('- Not specified -')];
    foreach (self::$changefreqSelectValues as $setting) {
      $options[$setting] = t($setting);
    }
    return $options;
  }

  /**
   * @return array
   */
  public static function getChangefreqOptions() {
    return self::$changefreqSelectValues;
  }

441
  /**
442
   * @param string $priority
443 444 445
   * @return string
   */
  public function formatPriority($priority) {
gbyte.co's avatar
gbyte.co committed
446
    return number_format((float) $priority, 1, '.', '');
447 448
  }

449
  /**
450
   * @param string|int $priority
451 452
   * @return bool
   */
453
  public static function isValidPriority($priority) {
454
    return is_numeric($priority) && $priority >= 0 && $priority <= 1;
455
  }
456 457 458 459 460 461 462 463

  /**
   * @param string $changefreq
   * @return bool
   */
  public static function isValidChangefreq($changefreq) {
    return in_array($changefreq, self::$changefreqSelectValues);
  }
464
}