vais_promos-1.0.0-beta2/src/Form/VaisImportXmlForm.php
src/Form/VaisImportXmlForm.php
<?php
namespace Drupal\vais_promos\Form;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\search\SearchPageRepositoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form to import promotions from an XML file.
*/
class VaisImportXmlForm extends FormBase {
/**
* The messenger object.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* The search page repository object.
*
* @var \Drupal\search\SearchPageRepositoryInterface
*/
protected $searchPageRepo;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxy
*/
protected $currentUser;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The constructor for the XML import form.
*
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger object.
* @param \Drupal\search\SearchPageRepositoryInterface $searchPageRepo
* The search page repository object.
* @param \Drupal\Core\Database\Connection $database
* The database connection.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
* @param \Drupal\Core\Session\AccountProxyInterface $currentUser
* The current user.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
* The module handler.
*/
public function __construct(MessengerInterface $messenger, SearchPageRepositoryInterface $searchPageRepo, Connection $database, EntityTypeManagerInterface $entityTypeManager, AccountProxyInterface $currentUser, ModuleHandlerInterface $moduleHandler) {
$this->messenger = $messenger;
$this->searchPageRepo = $searchPageRepo;
$this->database = $database;
$this->entityTypeManager = $entityTypeManager;
$this->currentUser = $currentUser;
$this->moduleHandler = $moduleHandler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('messenger'),
$container->get('search.search_page_repository'),
$container->get('database'),
$container->get('entity_type.manager'),
$container->get('current_user'),
$container->get('module_handler'),
);
}
/**
* Returns a unique string identifying the form.
*
* @return string
* The unique string identifying the form.
*/
public function getFormId(): string {
return 'vais_promo_import_xml';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['description'] = [
'#markup' => 'The importer will try and match the promotion URL with existing content, and only creates internal linked promotions.',
];
// Get list of available Vertex AI search pages.
$searchPageOptions = [];
$activeSearchPages = $this->searchPageRepo->getActiveSearchPages();
foreach ($this->searchPageRepo->sortSearchPages($activeSearchPages) as $entity) {
if ($entity->get('plugin') === 'vertex_ai_search') {
$searchPageOptions[$entity->id()] = $entity->label();
}
}
$form['promo_search_page'] = [
'#type' => 'select',
'#title' => $this->t('Vertex AI Search Page'),
'#description' => $this->t('The Vertex AI Search Page on which this Promotion will appear.'),
'#options' => $searchPageOptions,
'#required' => TRUE,
];
if (count($searchPageOptions) === 1) {
$form['promo_search_page']['#default_value'] = implode(",", array_keys($searchPageOptions));
}
$form['import_xml'] = [
'#type' => 'file',
'#required' => TRUE,
'#title' => $this->t('XML file'),
'#description' => $this->t('Upload a .xml file that was exported from <a href="@link">Google Programmable Search</a>.',
[
'@link' => 'https://developers.google.com/custom-search/docs/promotions',
]
),
];
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#name' => 'vais_promo_import_xml',
'#value' => $this->t('Import'),
'#button_type' => 'primary',
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$files = file_save_upload('import_xml', ['file_validate_extensions' => ['xml']]);
$xml_file = $files[0];
if (!$files || empty($xml_file)) {
$this->messenger->addError("There was an error uploading the file.");
}
else {
$xml_data = file_get_contents($xml_file->getFileUri());
$xml_object = simplexml_load_string($xml_data);
$total_added = $total_external = 0;
foreach ($xml_object->Promotion as $promo) {
// Get an entity_id from the URL.
$nid = NULL;
$url = $promo->attributes()->url[0];
$url_parts = parse_url($url);
$alias = $url_parts['path'];
$pathParts = explode('/', trim($alias, " /"));
$promoType = 'internal';
if ($pathParts[0] == 'node' && is_numeric($pathParts[1])) {
// Check if nid is explicitly in a 'node/nid' path.
$nid = $pathParts[1];
}
if ((!$nid || !is_numeric($nid)) &&
$this->moduleHandler->moduleExists('redirect')) {
// Check for a redirect, and trim the leading slash from the alias.
$query = $this->database->select('redirect', 'r');
$query->addExpression("REPLACE(r.redirect_redirect__uri, 'internal:/node/', '')", 'nid');
$query->condition('r.redirect_source__path', trim($alias, " /"), '=');
$nid = $query->execute()->fetchField();
}
if (!$nid || !is_numeric($nid)) {
// Now look for the node ID by alias.
$query = $this->database->select('path_alias', 'p');
$query->addExpression("REPLACE(p.path, '/node/', ''), 'path'");
$query->condition('p.alias', $alias, '=');
$nid = $query->execute()->fetchField();
}
// If none exists, treat promo link as external.
if (!$nid || !is_numeric($nid)) {
$total_external++;
$promoType = 'external';
}
$options = [
'promo_search_page' => $form_state->getValue('promo_search_page'),
'promo_trigger' => implode(",", (array) $promo->Query),
'promo_type' => $promoType,
'promo_content' => $nid ?? NULL,
'promo_link' => empty($nid) ? $url : NULL,
'promo_title_override' => (string) $promo->attributes()->title[0],
'promo_description' => ((string) $promo->attributes()->description) ?: NULL,
'user_id' => $this->currentUser->id(),
];
try {
$new_promo = $this->entityTypeManager->getStorage('vais_promo')->create($options);
$new_promo->save();
}
catch (\Exception $e) {
$this->messenger->addError($e->getMessage());
}
$total_added++;
}
if ($total_external > 0) {
$this->messenger->addMessage("Imported $total_added promotions, $total_external link to external resources.");
}
else {
$this->messenger->addMessage("Imported $total_added promotions");
}
}
}
}
