vp-1.0.x-dev/vp.module

vp.module
<?php

/**
 * @file
 * Primary module hooks for VP module.
 */

use Drupal\Component\Serialization\Json;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\user\UserInterface;

/**
 * Prepares variables for virtual patient templates.
 *
 * Default template: virtual-patient.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - elements: An associative array containing the virtual patient
 *   - information and any fields attached to the entity.
 *   - attributes: HTML attributes for the containing element.
 */
function template_preprocess_virtual_patient(array &$variables) {
  $variables['view_mode'] = $variables['elements']['#view_mode'];
  foreach (Element::children($variables['elements']) as $key) {
    $variables['content'][$key] = $variables['elements'][$key];
  }
}

/**
 * Implements hook_user_cancel().
 */
function vp_user_cancel($edit, UserInterface $account, $method) {
  switch ($method) {
    case 'user_cancel_block_unpublish':
      // Unpublish virtual patients.
      $storage = \Drupal::entityTypeManager()->getStorage('virtual_patient');
      $virtual_patient_ids = $storage->getQuery()
        ->condition('uid', $account->id())
        ->condition('status', 1)
        ->accessCheck(FALSE)
        ->execute();
      foreach ($storage->loadMultiple($virtual_patient_ids) as $virtual_patient) {
        $virtual_patient->set('status', FALSE);
        $virtual_patient->save();
      }
      break;

    case 'user_cancel_reassign':
      // Anonymize virtual patients.
      $storage = \Drupal::entityTypeManager()->getStorage('virtual_patient');
      $virtual_patient_ids = $storage->getQuery()
        ->condition('uid', $account->id())
        ->execute();
      foreach ($storage->loadMultiple($virtual_patient_ids) as $virtual_patient) {
        $virtual_patient->setOwnerId(0);
        $virtual_patient->save();
      }
      break;
  }
}

/**
 * Implements hook_ENTITY_TYPE_predelete() for user entities.
 */
function vp_user_predelete(UserInterface $account) {
  // Delete virtual patients.
  $storage = \Drupal::entityTypeManager()->getStorage('virtual_patient');
  $virtual_patient_ids = $storage->getQuery()
    ->condition('uid', $account->id())
    ->accessCheck(FALSE)
    ->execute();
  $virtual_patients = $storage->loadMultiple($virtual_patient_ids);
  $storage->delete($virtual_patients);
}

/**
 * Implements hook_ENTITY_TYPE_predelete().
 */
function vp_virtual_patient_predelete(EntityInterface $entity) {
  // Delete virtual patients.
  $storage = \Drupal::entityTypeManager()->getStorage('vp_node');
  $virtual_patient_node_ids = $storage->getQuery()
    ->condition('field_parent', $entity->id())
    ->accessCheck(FALSE)
    ->execute();
  $virtual_patient_nodes = $storage->loadMultiple($virtual_patient_node_ids);
  $storage->delete($virtual_patient_nodes);
}

/**
 * Implements hook_FORM_ID_alter().
 */
function vp_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $service = \Drupal::service('vp.service');

  $language = \Drupal::languageManager()->getCurrentLanguage();
  $langcode = $language->getId();

  // @todo Use some more general method here
  $content_language = $service->getContentLangcode();

  if ($form_id == 'vp_node_edit_form') {
    $form_object = $form_state->getFormObject();
    if ($form_object) {
      $node = $form_object->getEntity();
      if ($node) {
        $original = $node->getUntranslated()->language()->getId();
        if ($content_language && $original !== $content_language) {
          $form['field_options']['#disabled'] = TRUE;
        }
      }
    }
  }

  if ($form_id == 'vp_node_add_form' || $form_id == 'vp_node_edit_form') {

    $form_object = $form_state->getFormObject();
    $entity = $form_object->getEntity();
    if (!$entity) {
      return;
    }

    $original = $entity->getUntranslated()->language()->getId();
    $form['field_options']['#states'] = [
      'disabled' => [
        ':input[name="field_terminal_node[value]"]' => ['checked' => TRUE],
      ],
    ];

    if ($content_language && $original !== $content_language) {
      $form['field_options']['#attributes']['class'][] = 'input-disabled';
    }

    $form['langcode']['#disabled'] = TRUE;
    $form['#attached']['library'][] = 'vp/vp';
    $form['status']['#access'] = FALSE;
    $form['created']['#access'] = FALSE;
    $form['uid']['#access'] = FALSE;

    $form['actions']['delete']['#access'] = FALSE;
    $form['actions']['submit']['#submit'][] = '_vp_node_submit_handler';

    $form['field_parent']['#access'] = FALSE;
    $form['field_parent']['widget'][0]['#attributes'] = ['disabled' => TRUE];

    $form['field_root_node']['#access'] = FALSE;

    $form['field_subtitle']['widget'][0]['value']['#description'] = t('If subtitle exists, the node page will show this instead of the title.');

    $parent = \Drupal::request()->query->get('nid');
    if ($parent && $form_id == 'vp_node_add_form') {
      $storage = \Drupal::entityTypeManager()->getStorage('virtual_patient');
      $parent = $storage->load($parent);
      if ($parent) {
        $form['info'] = [
          '#type' => 'item',
          '#markup' => Markup::create('<div class="vp-label"><em><strong>' . $parent->label() . '</strong></em></div>'),
          '#weight' => -99,
        ];
        $form['field_parent']['widget'][0]['target_id']['#default_value'] = $parent;
      }
    }
  }
}

/**
 * {@inheritdoc}
 */
function _vp_node_submit_handler(array &$form, FormStateInterface $form_state) {
  $form_object = $form_state->getFormObject();
  if ($form_object) {
    $entity = $form_object->getEntity();
    /** @var \Drupal\vp\Entity\VirtualPatientNode $entity .*/
    $parent = $entity ? $entity->field_parent->entity : NULL;
    if ($parent) {
      $url = $parent->toUrl('edit-form');
      $form_state->setRedirectUrl($url);
    }
  }
}

/**
 * Implements hook_entity_type_insert().
 */
function vp_vp_node_insert(EntityInterface $entity) {
  /** @var \Drupal\vp\Entity\VirtualPatientNode $entity */
  $parent = $entity->field_parent->entity;
  if ($parent) {
    $parent->field_vp_nodes[] = ['target_id' => $entity->id()];
    $parent->save();
  }
}

/**
 * Implements hook_FORM_ID_alter().
 */
function vp_form_virtual_patient_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#attached']['library'][] = 'vp/vp';
  $form['created']['#access'] = FALSE;
  $form['uid']['#access'] = FALSE;
  $form['actions']['submit']['#value'] = t('Create new virtual patient');

  // Disabled this by default.
  $form['status']['widget']['value']['#default_value'] = FALSE;
  $form['status']['#access'] = FALSE;
}

/**
 * Implements hook_FORM_ID_alter().
 */
function vp_form_virtual_patient_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  $form['status']['widget']['value']['#title'] = t('Published');
  $form['field_description']['#weight'] = -99;
  $form['status']['#weight'] = 99;
  $form['uid']['#access'] = FALSE;
  $form['created']['#access'] = FALSE;

  $language = \Drupal::languageManager()->getCurrentLanguage();
  $langcode = $language->getId();
  $service = \Drupal::service('vp.service');

  $form['#attached']['library'][] = 'vp/vp';
  $header = [
    'id' => t('ID'),
    'label' => t('Label'),
    'paths' => t('Paths'),
    'root' => t('Root'),
    'terminal' => t('Terminal'),
    'actions' => t('Actions'),
    'warnings' => '',
  ];
  $rows = [];

  /** @var \Drupal\Core\Entity\EntityForm $form_object */
  $form_object = $form_state->getFormObject();
  $entity = $form_object ? $form_object->getEntity() : NULL;

  if (!$entity) {
    return;
  }
  $entity = $entity->getUntranslated();
  $vp_original_langcode = $entity->language()->getId();
  $content_language = $service->getContentLangcode();

  $nodes = $entity->field_vp_nodes->referencedEntities();
  foreach ($nodes as $node) {
    $current_path = \Drupal::service('path.current')->getPath();
    $original_langcode = $node->getUntranslated()->language()->getId();

    $options = ['language' => $language];

    $add_translation_url = $node->toUrl('drupal:content-translation-add', $options)
      ->setRouteParameter('source', $original_langcode)
      ->setRouteParameter('target', $content_language);

    $edit_translation_url = $node->toUrl('drupal:content-translation-edit', $options)
      ->setRouteParameter('language', $content_language);
    $delete_translation_url = $node->toUrl('drupal:content-translation-delete', $options)
      ->setRouteParameter('language', $content_language);

    $paths_count = count($node->field_options->referencedEntities());

    $row['id'] = $node->id();
    $label_translated = $node->hasTranslation($content_language) ? $node->getTranslation($content_language)->label() : $node->label();
    $row['label'] = $label_translated;
    $tooltip = '';
    if ($paths_count) {
      foreach ($node->field_options->referencedEntities() as $option) {

        if ($content_language && $option->hasTranslation($content_language)) {
          $option = $option->getTranslation($content_language);
        }

        $ellipsis = strlen($option->label()) > 145 ? '...' : '';
        $tooltip .= '• ' . substr($option->label(), 0, 145) . $ellipsis . '<br />';
      }
      $row['paths'] = Markup::create("<span class='hover-text'><i class='bi bi-shuffle'></i> <strong>{$paths_count}</strong><span class='tooltip-text-options'>{$tooltip}</span></span>");
    }
    else {
      $row['paths'] = '-';
    }

    $row['root'] = $node->field_root_node->value ? '✅' : '-';
    $row['terminal'] = $node->field_terminal_node->value ? '✅' : '-';

    $operations = [];

    if ($node->access('update') && $node->hasLinkTemplate('edit-form')) {
      if ($content_language && $original_langcode != $content_language) {
        $current_path = $current_path . "?language_content_entity=" . $content_language;
      }

      if ($content_language && !$node->hasTranslation($content_language)) {
        $operations['translate'] = [
          'title' => t('Add translation'),
          'weight' => 0,
          'attributes' => [
            'class' => [
              'use-ajax',
            ],
            'data-dialog-type' => 'modal',
            'data-dialog-options' => Json::encode([
              'width' => 880,
            ]),
          ],
          'url' => $add_translation_url->setOption('query', [
            'language_content_entity' => $content_language,
            'nid' => $entity->id(),
            'destination' => $current_path,
          ]),
        ];
      }
      else {
        $label = t('Edit');
        $url = $node->toUrl('edit-form')->setOption('query', [
          'language_content_entity' => $content_language,
          'nid' => $entity->id(),
          'destination' => $current_path,
        ]);
        if ($content_language && $original_langcode !== $content_language) {
          $label = t('Edit translation');
          $url = $node->toUrl('edit-form')->setOption('query', [
            'language_content_entity' => $content_language,
            'nid' => $entity->id(),
            'destination' => $current_path,
          ]);
        }
        $operations['edit'] = [
          'title' => $label,
          'weight' => 1,
          'attributes' => [
            'class' => [
              'use-ajax',
            ],
            'data-dialog-type' => 'modal',
            'data-dialog-options' => Json::encode([
              'width' => 880,
            ]),
          ],
          'url' => $url,
        ];
      }
    }

    if ($node->access('delete') && $node->hasLinkTemplate('delete-form')) {

      $label = t('Delete');
      $url = $node->toUrl('delete-form')->setOption('query', [
        'nid' => $entity->id(),
        'destination' => $current_path,
      ]);
      if ($content_language && $langcode !== $content_language) {
        $label = t('Delete translation');
        $url = $node->toUrl('delete-form')->setOption('query', [
          'destination' => $current_path,
          'nid' => $entity->id(),
          'language_content_entity' => $content_language,
        ]);
      }

      $operations['delete'] = [
        'title' => $label,
        'weight' => 5,
        'attributes' => [
          'class' => [
            'use-ajax',
          ],
          'data-dialog-type' => 'modal',
          'data-dialog-options' => Json::encode([
            'width' => 880,
          ]),
        ],
        'url' => $url,
      ];
    }

    $row['actions'] = [
      'data' => [
        '#type' => 'operations',
        '#links' => $operations,
      ],
    ];

    $terminal_check_pass = (int) $node->field_terminal_node->value === 0 ? $paths_count > 0 : TRUE;

    // @todo
    $tooltip = t('You need either to have options or define the node as terminal');
    $row['warnings'] = $terminal_check_pass ?
      Markup::create('<i class="bi bi-check" style="color: darkgreen"></i>') :
      Markup::create("<span class='hover-text'><i class='bi bi-exclamation-triangle' style='color: orange'></i><span class='tooltip-text'>{$tooltip}</span></span>");

    $rows[] = $row;
  }

  $form['vp_nodes_root'] = [
    '#type' => 'details',
    '#title' => t('Root node'),
    '#open' => TRUE,
    '#weight' => 1,
  ];

  $root_node = $service->getRootNode($entity);

  if (!$root_node) {
    $warning = "<p style='color:orange'> <i class='bi bi-exclamation-triangle-fill'></i> WARNING: <em>" . t("You don't have a root node defined.") . "</em></p>";
    $form['vp_nodes_root']['warning'] = [
      '#type' => 'markup',
      '#markup' => Markup::create($warning),
    ];
  }

  if ($root_node) {
    $root_label = $root_node->label();
    if ($root_node->hasTranslation($content_language)) {
      $translated_root_node = $root_node->getTranslation($content_language);
      $root_label = $translated_root_node->label();
    }

    $form['vp_nodes_root']['title'] = [
      '#type' => 'markup',
      '#markup' => Markup::create("<p style='margin: 18px'><li> {$root_label}  (ID: {$root_node->id()})</li></p>"),
    ];
  }

  $add_root['vp_root_add'] = [
    'title' => $root_node ? t('Select root node') : t('Add root node'),
    'attributes' => [
      'class' => [
        'use-ajax button button--primary js-form-submit form-submit',
      ],
      'data-dialog-type' => 'modal',
      'data-dialog-options' => Json::encode([
        'width' => 880,
      ]),
    ],
    'url' => Url::fromRoute('vp.add.root.node', ['virtual_patient' => $entity->id()]),
  ];

  $form['vp_nodes_root']['vp_nodes_root_add'] = [
    '#type' => 'operations',
    '#links' => $add_root,
  ];

  $form['vp_nodes'] = [
    '#type' => 'details',
    '#title' => t('Nodes List'),
    '#open' => TRUE,
    '#weight' => 2,
  ];

  if ($entity && $vp_original_langcode == $content_language) {
    $add['vp'] = [
      'title' => t('Create new'),
      'attributes' => [
        'class' => [
          'use-ajax button button--primary js-form-submit form-submit',
        ],
        'data-dialog-type' => 'modal',
        'data-dialog-options' => Json::encode([
          'width' => 880,
        ]),
      ],
      'url' => Url::fromRoute('entity.vp_node.add_form')->setOption('query', [
        'destination' => $current_path,
        'nid' => $entity->id(),
      ]),
    ];

    $form['vp_nodes']['continue_button'] = [
      '#type' => 'operations',
      '#links' => $add,
    ];
  }
  else {
    $form['vp_nodes']['info_vp_nodes'] = [
      '#type' => 'markup',
      '#markup' => Markup::create(t('<em>You can create nodes in the original language only (@label)</em>', [
        '@label' => strtoupper($entity->getUntranslated()->language()->getName()),
      ])),
    ];
  }

  $form['vp_nodes']['vp_list'] = [
    '#title' => t('Nodes list'),
    '#type' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('Currently, there are no VP nodes.'),
  ];
}

/**
 * Implements hook_ENTITY_VIEW_alter().
 */
function vp_virtual_patient_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {

  // Hide vp nodes, we want a clean view.
  unset($build['field_vp_nodes']);

  /** @var \Drupal\vp\Entity\VirtualPatient $entity */
  $build['created']['#access'] = FALSE;
  $build['field_description']['#access'] = FALSE;
  $build['field_vp_image']['#access'] = FALSE;
  $build['uid']['#access'] = FALSE;

  $build['#attached']['library'][] = 'vp/preview';

  $build['preview'] = [
    '#type' => 'markup',
    '#markup' => "<div class='vp-preview'><div class='vp-preview-content'>Preview</div></div>",
  ];

  $status = (boolean) $entity->status->value;
  $config = \Drupal::service('config.factory')->getEditable('vp.settings');
  $player_url = $config->get('player_url');
  $uuid = $entity->uuid->value;
  $uid = \Drupal::currentUser()->id();
  $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
  $content_langcode = \Drupal::service('vp.service')->getContentLangcode();

  $preview_url = "{$player_url}/play?uuid={$uuid}&lang={$content_langcode}&uid={$uid}&preview=true";

  $translated = $entity->getTranslation($langcode);
  $translation_published = $translated->status->value;
  if (empty($player_url)) {
    $warning_message = Markup::create(t('<div class="warning-message--player"><strong><a href="@link">Add a player URL</a></strong> <br />to preview the virtual patient.</div>', [
      '@link' => Url::fromRoute('vp.settings_form')->toString(),
    ]));
    $build['preview'] = [
      '#type' => 'markup',
      '#markup' => "<div class='vp-preview'><div class='vp-preview-content'>{$warning_message}</div></div>",
    ];
  }
  else {
    $build['preview'] = [
      '#type' => 'inline_template',
      '#template' => '<div class="vp-preview"><iframe class="vp-preview-content" src="' . $preview_url . '" frameborder="0"></iframe></div>',
    ];
  }

  $build['status'] = [
    '#type' => 'details',
    '#title' => t('Published status'),
    '#open' => TRUE,
    '#attributes' => [
      'class' => [
        'container-right',
      ],
    ],
  ];

  $build['status']['info'] = [
    '#type' => 'markup',
    '#markup' => $status ? Markup::create("<p><i class='bi bi-check-square' style='color: green'></i> This content is <strong>published</strong></p>") : Markup::create("<p>This content is <strong>not published</strong></p>"),
  ];
  $build['status']['translation_info'] = [
    '#type' => 'markup',
    '#markup' => $translation_published ?
    Markup::create("<p><i class='bi bi-check-square' style='color: green'></i> This translation of this content is <strong>published</strong></p>") :
    Markup::create("<p>This translation of the content is <strong>not published</strong></p>"),
  ];

  $build['status']['publish'] = [
    '#type' => 'link',
    '#title' => $status ? t('Unpublish (all languages)') : ('Publish (all languages)'),
    '#url' => Url::fromRoute('vp.settings_form'),
    '#attributes' => [
      'class' => [
        'button button--primary js-form-submit form-submit',
      ],
    ],
    '#ajax' => [
      'dialogType' => 'modal',
      'dialog' => ['height' => 400, 'width' => 700],
    ],
  ];

}

/**
 * Implements hook_module_implements_alter().
 */
function vp_module_implements_alter(&$implementations, $hook) {
  switch ($hook) {
    case 'form_virtual_patient_edit_form_alter':
      $group = $implementations['vp'];
      unset($implementations['vp']);
      $implementations['vp'] = $group;
      break;
  }
}

/**
 * Implements hook_entity_type_translation_delete().
 */
function vp_virtual_patient_translation_delete(EntityInterface $translation) {
  $langcode = $translation->language()->getId();
  $nodes = $translation->field_vp_nodes->referencedEntities();
  foreach ($nodes as $node) {
    if ($node->hasTranslation($langcode)) {
      $untranslated_node = $node->getUntranslated();
      $untranslated_node->removeTranslation($langcode);
      $untranslated_node->save();
    }
  }
}

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

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