FormHelper.php 18.1 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
  /**
63
   * @var array
64
   */
65
  protected $settings;
66 67 68 69

  /**
   * @var array
   */
70
  protected static $allowedFormOperations = [
71 72 73
    'default',
    'edit',
    'add',
gbyte.co's avatar
gbyte.co committed
74
    'register',
75 76
  ];

77 78 79
  /**
   * @var array
   */
80
  protected static $changefreqValues = [
81 82 83 84 85 86 87 88 89
    'always',
    'hourly',
    'daily',
    'weekly',
    'monthly',
    'yearly',
    'never',
  ];

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

106
  /**
gbyte.co's avatar
gbyte.co committed
107 108
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   * @return bool
109 110 111
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   *
112
   */
gbyte.co's avatar
gbyte.co committed
113
  public function processForm(FormStateInterface $form_state) {
114
    $this->formState = $form_state;
115
    $this->cleanUpFormInfo();
116
    $this->getEntityDataFromFormEntity();
117
    $this->negotiateSettings();
118

gbyte.co's avatar
gbyte.co committed
119
    return $this->supports();
120 121
  }

122
  /**
gbyte.co's avatar
gbyte.co committed
123
   * @param string $entity_category
124 125
   * @return $this
   */
126 127
  public function setEntityCategory($entity_category) {
    $this->entityCategory = $entity_category;
128
    return $this;
129 130
  }

131
  /**
132
   * @return null|string
133
   */
134 135 136 137 138 139 140 141
  public function getEntityCategory() {
    return $this->entityCategory;
  }

  /**
 * @param string $entity_type_id
 * @return $this
 */
142 143
  public function setEntityTypeId($entity_type_id) {
    $this->entityTypeId = $entity_type_id;
144

145
    return $this;
146 147
  }

148 149 150 151 152 153 154
  /**
   * @return string
   */
  public function getEntityTypeId() {
    return $this->entityTypeId;
  }

155
  /**
gbyte.co's avatar
gbyte.co committed
156
   * @param string $bundle_name
157 158
   * @return $this
   */
159 160
  public function setBundleName($bundle_name) {
    $this->bundleName = $bundle_name;
161

162
    return $this;
163 164
  }

165 166 167 168 169 170 171
  /**
   * @return string
   */
  public function getBundleName() {
    return $this->bundleName;
  }

172
  /**
gbyte.co's avatar
gbyte.co committed
173
   * @param string $instance_id
174 175
   * @return $this
   */
176 177
  public function setInstanceId($instance_id) {
    $this->instanceId = $instance_id;
178

179
    return $this;
180 181
  }

182 183 184 185 186 187 188
  /**
   * @return string
   */
  public function getInstanceId() {
    return $this->instanceId;
  }

gbyte.co's avatar
gbyte.co committed
189
  /**
gbyte.co's avatar
gbyte.co committed
190
   * @return bool
gbyte.co's avatar
gbyte.co committed
191
   */
gbyte.co's avatar
gbyte.co committed
192
  protected function supports() {
gbyte.co's avatar
gbyte.co committed
193 194

    // Do not alter the form if user lacks certain permissions.
gbyte.co's avatar
gbyte.co committed
195
    if (!$this->currentUser->hasPermission('administer sitemap settings')) {
gbyte.co's avatar
gbyte.co committed
196
      return FALSE;
gbyte.co's avatar
gbyte.co committed
197
    }
gbyte.co's avatar
gbyte.co committed
198 199

    // Do not alter the form if it is irrelevant to sitemap generation.
200
    elseif (empty($this->getEntityCategory())) {
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

    // Do not alter the form if entity is not enabled in sitemap settings.
205
    elseif (!$this->generator->entityTypeIsEnabled($this->getEntityTypeId())) {
gbyte.co's avatar
gbyte.co committed
206
      return FALSE;
gbyte.co's avatar
gbyte.co committed
207
    }
gbyte.co's avatar
gbyte.co committed
208

gbyte.co's avatar
gbyte.co committed
209
    return TRUE;
gbyte.co's avatar
gbyte.co committed
210 211
  }

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

    return $this;
228
  }
229

230 231
  /**
   * @return $this
232 233
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
234
   */
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
  public function negotiateSettings() {

    $this->settings = $this->generator->setVariants(TRUE)
      ->getBundleSettings($this->getEntityTypeId(), $this->getBundleName(), TRUE, TRUE);
    if ($this->getEntityCategory() === 'instance') {

      //todo Should spit out variant => settings and not just settings; to do this, alter getEntityInstanceSettings() to include 'multiple variants' option.
      foreach ($this->settings as $variant_name => $settings) {
        if (NULL !== $instance_id = $this->getInstanceId()) {
          $this->settings[$variant_name] = $this->generator->setVariants($variant_name)
            ->getEntityInstanceSettings($this->getEntityTypeId(), $instance_id);
        }
        $this->settings[$variant_name]['bundle_settings'] = $settings;
      }
    }
250 251

    return $this;
252 253
  }

254
  /**
255
   * @param $form_fragment
256 257
   * @return $this
   */
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
  public function displayEntitySettings(&$form_fragment) {
    $bundle_name = !empty($this->getBundleName())
      ? $this->entityHelper->getBundleLabel($this->getEntityTypeId(), $this->getBundleName())
      : $this->t('undefined');

    $variants = $this->generator->getSitemapManager()->getSitemapVariants(NULL, FALSE);
    $form_fragment['settings']['#markup'] = empty($variants)
      ? $this->t('At least one sitemap variants needs to be defined for a bundle to be indexable.<br>Variants can be configured <a href="@url">here</a>.', ['@url' => $GLOBALS['base_url'] . '/admin/config/search/simplesitemap/variants'])
      : '<strong>' . $this->t('Sitemap variants') . '</strong>';

    foreach ($variants as $variant => $definition) {
      $form_fragment['settings'][$variant] = [
        '#type' => 'details',
        '#title' => '<em>' . $this->t($definition['label']) . '</em>',
        '#open' => !empty($this->settings[$variant]['index']),
      ];
gbyte.co's avatar
gbyte.co committed
274

275 276
      // Disable fields of entity instance whose bundle is not indexed.
      $form_fragment['settings'][$variant]['#disabled'] = $this->getEntityCategory() === 'instance' && empty($this->settings[$variant]['bundle_settings']['index']);
277

278 279
      // Index
      $form_fragment['settings'][$variant]['index_' . $variant . '_' . $this->getEntityTypeId() . '_settings'] = [
280
        '#type' => 'radios',
281
        '#default_value' => (int) $this->settings[$variant]['index'],
282
        '#options' => [
283 284 285 286 287 288
          $this->getEntityCategory() === 'instance'
            ? $this->t('Do not index this <em>@bundle</em> entity in variant <em>@variant_label</em>', ['@bundle' => $bundle_name, '@variant_label' => $this->t($variants[$variant]['label'])])
            : $this->t('Do not index entities of type <em>@bundle</em> in variant <em>@variant_label</em>', ['@bundle' => $bundle_name, '@variant_label' => $this->t($variants[$variant]['label'])]),
          $this->getEntityCategory() === 'instance'
            ? $this->t('Index this <em>@bundle entity</em> in variant <em>@variant_label</em>', ['@bundle' => $bundle_name, '@variant_label' => $this->t($variants[$variant]['label'])])
            : $this->t('Index entities of type <em>@bundle</em> in variant <em>@variant_label</em>', ['@bundle' => $bundle_name, '@variant_label' => $this->t($variants[$variant]['label'])]),
gbyte.co's avatar
gbyte.co committed
289
        ],
290
        '#attributes' => ['class' => ['enabled-for-variant', $variant]],
291
      ];
gbyte.co's avatar
gbyte.co committed
292

293 294
      if ($this->getEntityCategory() === 'instance' && isset($this->settings[$variant]['bundle_settings']['index'])) {
        $form_fragment['settings'][$variant]['index_' . $variant . '_' . $this->getEntityTypeId() . '_settings']['#options'][(int) $this->settings[$variant]['bundle_settings']['index']] .= ' <em>(' . $this->t('default') . ')</em>';
295
      }
296

297 298 299 300 301 302 303 304 305 306 307 308 309
      // Priority
      $form_fragment['settings'][$variant]['priority_' . $variant . '_' . $this->getEntityTypeId() . '_settings'] = [
        '#type' => 'select',
        '#title' => $this->t('Priority'),
        '#description' => $this->getEntityCategory() === 'instance'
          ? $this->t('The priority this <em>@bundle</em> entity will have in the eyes of search engine bots.', ['@bundle' => $bundle_name])
          : $this->t('The priority entities of this type will have in the eyes of search engine bots.'),
        '#default_value' => $this->settings[$variant]['priority'],
        '#options' => $this->getPrioritySelectValues(),
        '#states' => [
          'visible' => [':input[name="index_' . $variant . '_' . $this->getEntityTypeId() . '_settings"]' => ['value' => 1]],
        ],
      ];
310

311 312 313
      if ($this->getEntityCategory() === 'instance' && isset($this->settings[$variant]['bundle_settings']['priority'])) {
        $form_fragment['settings'][$variant]['priority_' . $variant . '_' . $this->getEntityTypeId() . '_settings']['#options'][$this->formatPriority($this->settings[$variant]['bundle_settings']['priority'])] .= ' (' . $this->t('default') . ')';
      }
314

315 316 317 318 319 320 321 322 323 324 325 326 327
      // Changefreq
      $form_fragment['settings'][$variant]['changefreq_' . $variant . '_' . $this->getEntityTypeId() . '_settings'] = [
        '#type' => 'select',
        '#title' => $this->t('Change frequency'),
        '#description' => $this->getEntityCategory() === 'instance'
          ? $this->t('The frequency with which this <em>@bundle</em> entity changes. Search engine bots may take this as an indication of how often to index it.', ['@bundle' => $bundle_name])
          : $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.'),
        '#default_value' => $this->settings[$variant]['changefreq'],
        '#options' => $this->getChangefreqSelectValues(),
        '#states' => [
          'visible' => [':input[name="index_' . $variant . '_' . $this->getEntityTypeId() . '_settings"]' => ['value' => 1]],
        ],
      ];
328

329 330 331
      if ($this->getEntityCategory() === 'instance' && isset($this->settings[$variant]['bundle_settings']['changefreq'])) {
        $form_fragment['settings'][$variant]['changefreq_' . $variant . '_' . $this->getEntityTypeId() . '_settings']['#options'][$this->settings[$variant]['bundle_settings']['changefreq']] .= ' (' . $this->t('default') . ')';
      }
332

333 334 335 336 337 338 339 340 341 342 343 344 345
      // Images
      $form_fragment['settings'][$variant]['include_images_' . $variant . '_' . $this->getEntityTypeId() . '_settings'] = [
        '#type' => 'select',
        '#title' => $this->t('Include images'),
        '#description' => $this->getEntityCategory() === 'instance'
          ? $this->t('Determines if images referenced by this <em>@bundle</em> entity should be included in the sitemap.', ['@bundle' => $bundle_name])
          : $this->t('Determines if images referenced by entities of this type should be included in the sitemap.'),
        '#default_value' => (int) $this->settings[$variant]['include_images'],
        '#options' => [$this->t('No'), $this->t('Yes')],
        '#states' => [
          'visible' => [':input[name="index_' . $variant . '_' . $this->getEntityTypeId() . '_settings"]' => ['value' => 1]],
        ],
      ];
346

347 348 349
      if ($this->getEntityCategory() === 'instance' && isset($this->settings[$variant]['bundle_settings']['include_images'])) {
        $form_fragment['settings'][$variant]['include_images_' . $variant . '_' . $this->getEntityTypeId() . '_settings']['#options'][(int) $this->settings[$variant]['bundle_settings']['include_images']] .= ' (' . $this->t('default') . ')';
      }
350 351
    }

352
    return $this;
353 354 355 356 357 358 359
  }

  /**
   * 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
360
   *   TRUE if this is a bundle or bundle instance form, FALSE otherwise.
361
   */
362
  protected function getEntityDataFromFormEntity() {
gbyte.co's avatar
gbyte.co committed
363
    if (!$form_entity = $this->getFormEntity()) {
gbyte.co's avatar
gbyte.co committed
364 365
      return FALSE;
    }
366

gbyte.co's avatar
gbyte.co committed
367 368 369 370 371 372
    $entity_type_id = $form_entity->getEntityTypeId();
    $sitemap_entity_types = $this->entityHelper->getSupportedEntityTypes();
    if (isset($sitemap_entity_types[$entity_type_id])) {
      $this->setEntityCategory('instance');
    }
    else {
373
      /** @var \Drupal\Core\Entity\EntityType $sitemap_entity_type */
gbyte.co's avatar
gbyte.co committed
374 375 376
      foreach ($sitemap_entity_types as $sitemap_entity_type) {
        if ($sitemap_entity_type->getBundleEntityType() === $entity_type_id) {
          $this->setEntityCategory('bundle');
377
          break;
gbyte.co's avatar
gbyte.co committed
378
        }
379
      }
380
    }
gbyte.co's avatar
gbyte.co committed
381 382

    // Menu fix.
gbyte.co's avatar
gbyte.co committed
383
    $this->setEntityCategory(NULL === $this->getEntityCategory() && $entity_type_id === 'menu' ? 'bundle' : $this->getEntityCategory());
gbyte.co's avatar
gbyte.co committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402

    switch ($this->getEntityCategory()) {
      case 'bundle':
        $this->setEntityTypeId($this->entityHelper->getBundleEntityTypeId($form_entity));
        $this->setBundleName($form_entity->id());
        $this->setInstanceId(NULL);
        break;

      case 'instance':
        $this->setEntityTypeId($entity_type_id);
        $this->setBundleName($this->entityHelper->getEntityInstanceBundleName($form_entity));
        // New menu link's id is '' instead of NULL, hence checking for empty.
        $this->setInstanceId(!empty($form_entity->id()) ? $form_entity->id() : NULL);
        break;

      default:
        return FALSE;
    }
    return TRUE;
403 404 405 406 407
  }

  /**
   * Gets the object entity of the form if available.
   *
gbyte.co's avatar
gbyte.co committed
408
   * @return \Drupal\Core\Entity\Entity|false
gbyte.co's avatar
gbyte.co committed
409 410
   *   Entity or FALSE if non-existent or if form operation is
   *   'delete'.
411
   */
412
  protected function getFormEntity() {
413
    $form_object = $this->formState->getFormObject();
414
    if (NULL !== $form_object
415
      && method_exists($form_object, 'getOperation')
416
      && method_exists($form_object, 'getEntity')
417
      && in_array($form_object->getOperation(), self::$allowedFormOperations)) {
418 419 420 421 422
      return $form_object->getEntity();
    }
    return FALSE;
  }

423 424 425 426 427
  /**
   * Removes gathered form information from service object.
   *
   * Needed because this service may contain form info from the previous
   * operation when revived from the container.
428 429
   *
   * @return $this
430
   */
431
  public function cleanUpFormInfo() {
432 433 434 435
    $this->entityCategory = NULL;
    $this->entityTypeId = NULL;
    $this->bundleName = NULL;
    $this->instanceId = NULL;
436
    $this->settings = NULL;
437 438

    return $this;
439 440
  }

441 442 443 444
  /**
   * Gets new entity Id after entity creation.
   * To be used in an entity form submit.
   *
gbyte.co's avatar
gbyte.co committed
445
   * @return int
gbyte.co's avatar
gbyte.co committed
446
   *   Entity ID.
447
   */
448 449
  public function getFormEntityId() {
    return $this->formState->getFormObject()->getEntity()->id();
450 451 452 453 454 455
  }

  /**
   * Checks if simple_sitemap values have been changed after submitting the form.
   * To be used in an entity form submit.
   *
456
   * @param $form
457
   * @param array $values
gbyte.co's avatar
gbyte.co committed
458
   *
459
   * @return bool
gbyte.co's avatar
gbyte.co committed
460
   *   TRUE if simple_sitemap form values have been altered by the user.
461
   */
462
  public function valuesChanged($form, array $values) {
463 464 465 466 467 468 469 470 471 472 473
//    foreach (self::$valuesToCheck as $field_name) {
//      if (!isset($form['simple_sitemap'][$field_name]['#default_value'])
//        || (isset($values[$field_name]) && $values[$field_name] != $form['simple_sitemap'][$field_name]['#default_value'])) {
//        return TRUE;
//      }
//    }
//
//    return FALSE;

    //todo
    return TRUE;
474
  }
gbyte.co's avatar
gbyte.co committed
475

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
  /**
   * Gets the values needed to display the variant dropdown setting.
   *
   * @return array
   */
  public function getVariantSelectValues() {
    return array_map(
      function($variant) { return $this->t($variant['label']); },
      $this->generator->getSitemapManager()->getSitemapVariants(NULL, FALSE)
    );
  }

  /**
   * Returns correct default value for variant select list.
   *
   * If only one variant is available, return it, otherwise check if a default
   * variant is provided and return it.
   *
   * @param string|null $default_value
   *  Actual default value from the database.
   *
   * @return string|null
   *  Value to be set on form.
   */
  public function getVariantSelectValuesDefault($default_value) {
    $options = $this->getVariantSelectValues();
    return NULL === $default_value
      ? (1 === count($options)
        ? array_keys($options)[0]
        : (!empty($default = $this->generator->getSetting('default_variant'))
          ? $default
          : $default_value
        )
      )
      : $default_value;
  }

gbyte.co's avatar
gbyte.co committed
513 514 515
  /**
   * Gets the values needed to display the priority dropdown setting.
   *
516
   * @return array
gbyte.co's avatar
gbyte.co committed
517
   */
518
  public function getPrioritySelectValues() {
519
    $options = [];
gbyte.co's avatar
gbyte.co committed
520
    foreach (range(0, self::PRIORITY_HIGHEST) as $value) {
521
      $value = $this->formatPriority($value / self::PRIORITY_DIVIDER);
522
      $options[$value] = $value;
gbyte.co's avatar
gbyte.co committed
523
    }
524

gbyte.co's avatar
gbyte.co committed
525 526
    return $options;
  }
527

528 529 530 531 532 533
  /**
   * Gets the values needed to display the changefreq dropdown setting.
   *
   * @return array
   */
  public function getChangefreqSelectValues() {
gbyte.co's avatar
gbyte.co committed
534
    $options = ['' => $this->t('- Not specified -')];
gbyte.co's avatar
gbyte.co committed
535
    foreach (self::getChangefreqOptions() as $setting) {
gbyte.co's avatar
gbyte.co committed
536
      $options[$setting] = $this->t($setting);
537
    }
538

539 540 541 542 543 544 545
    return $options;
  }

  /**
   * @return array
   */
  public static function getChangefreqOptions() {
546
    return self::$changefreqValues;
547 548
  }

549
  /**
550
   * @param string $priority
551 552 553
   * @return string
   */
  public function formatPriority($priority) {
gbyte.co's avatar
gbyte.co committed
554
    return number_format((float) $priority, 1, '.', '');
555 556
  }

557
  /**
558
   * @param string|int $priority
559 560
   * @return bool
   */
561
  public static function isValidPriority($priority) {
562
    return is_numeric($priority) && $priority >= 0 && $priority <= 1;
563
  }
564 565 566 567 568 569

  /**
   * @param string $changefreq
   * @return bool
   */
  public static function isValidChangefreq($changefreq) {
570
    return in_array($changefreq, self::$changefreqValues);
571
  }
572
}