loadInclude('upei_roblib_ill', 'inc', 'includes/sharepoint'); * $handler = new SharePointRequestHandler(); * $payload = $handler->buildPayload($form_state); * $response = $handler->submitRequest($payload); * @endcode */ class SharePointRequestHandler { /** * Drupal config object for upei_roblib_ill.settings. * * @var \Drupal\Core\Config\ImmutableConfig */ protected $config; /** * Constructs a new SharePointRequestHandler. */ public function __construct() { $this->config = \Drupal::config('upei_roblib_ill.settings'); } /** * Builds the webhook payload from the Drupal form state. * * Reads bibliographic data from form storage (step 1) and patron data * from the current form values (step 2). * * @param \Drupal\Core\Form\FormStateInterface $form_state * The current form state containing both steps of the ILL form. * * @return array * An associative array matching the Power Automate webhook payload schema. */ public function buildPayload(FormStateInterface $form_state): array { $storage = $form_state->getStorage(); $biblio = $storage['request'] ?? []; $patron = $form_state->getValues(); $genre = $biblio['Genre'] ?? 'article'; // Determine the author: use ArticleAuthor for articles/chapters, Author for books. $author = ''; if ($genre !== 'book' && !empty($biblio['ArticleAuthor'])) { $author = $biblio['ArticleAuthor']; } elseif (!empty($biblio['Author'])) { $author = $biblio['Author']; } // Combine DOI and ISBN into a single field. $doi_isbn_parts = []; if (!empty($biblio['doi'])) { $doi_isbn_parts[] = $biblio['doi']; } if (!empty($biblio['ISBN'])) { $doi_isbn_parts[] = $biblio['ISBN']; } if (!empty($biblio['ISSN'])) { $doi_isbn_parts[] = $biblio['ISSN']; } $doi_isbn = implode('; ', $doi_isbn_parts); // Build patron full name. $first_name = $patron['FirstName'] ?? ''; $surname = $patron['Surname'] ?? ''; $patron_name = trim("$first_name $surname"); // Build notes — pack all extra info that doesn't have its own schema field. $notes_parts = []; if (!empty($biblio['ArticleTitle'])) { $notes_parts[] = 'Article/Chapter: ' . $biblio['ArticleTitle']; } if (!empty($biblio['Volume'])) { $notes_parts[] = 'Vol: ' . $biblio['Volume']; } if (!empty($biblio['Issue'])) { $notes_parts[] = 'Issue: ' . $biblio['Issue']; } if (!empty($biblio['PagesRequested'])) { $notes_parts[] = 'Pages: ' . $biblio['PagesRequested']; } if (!empty($patron['patron_type'])) { $notes_parts[] = 'Patron Type: ' . $patron['patron_type']; } if (!empty($patron['Department'])) { $notes_parts[] = 'Dept: ' . $patron['Department']; } if (!empty($patron['notes'])) { $notes_parts[] = $patron['notes']; } // All values MUST be strings — Power Automate rejects the request // if any value type does not match the trigger's JSON schema. return [ 'title' => (string)($biblio['Title'] ?? ''), 'author' => (string)$author, 'year' => (string)($biblio['Date'] ?? ''), 'doi_isbn' => (string)$doi_isbn, 'format' => (string)$genre, 'patronName' => (string)$patron_name, 'patronEmail' => (string)($patron['DeliveryAddress'] ?? ''), 'patronBarcode' => (string)($patron['campus_id'] ?? ''), 'notes' => (string)implode(' | ', $notes_parts), 'submittedAt' => (string)gmdate('Y-m-d\TH:i:s') . '.000Z', ]; } /** * Submits the payload to the configured Power Automate webhook. * * @param array $payload * The payload array as built by buildPayload(). * * @return array * An associative array with at least a 'ConfirmMessage' key, and * optionally a 'RequestNumber' key on success. */ public function submitRequest(array $payload): array { \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/db'); $webhook_url = $this->config->get('sharepoint_webhook_url'); if (empty($webhook_url)) { \Drupal::logger('upei_roblib_ill')->error( 'SharePoint webhook URL is not configured. Please set it in the ILL settings.' ); $error_response = [ 'ConfirmMessage' => 'SharePoint integration is not configured. Please contact the library.', ]; upei_roblib_ill_log_request($payload, $error_response); return $error_response; } // Log the outgoing payload for debugging. \Drupal::logger('upei_roblib_ill')->notice( 'Submitting ILL request to SharePoint webhook. Payload: @payload', ['@payload' => json_encode($payload)] ); try { // Use 'json' option which handles JSON encoding and Content-Type automatically. $response = \Drupal::httpClient()->post($webhook_url, [ 'json' => $payload, 'timeout' => 30, ]); $status_code = $response->getStatusCode(); $body = (string)$response->getBody(); $response_data = json_decode($body, TRUE) ?: []; if ($status_code >= 200 && $status_code < 300) { $result = [ 'RequestNumber' => $response_data['request_number'] ?? date('YmdHis'), 'ConfirmMessage' => 'Your Interlibrary Loan request has been successfully submitted.', ]; } else { $message = $response_data['error'] ?? 'Unexpected response from SharePoint (HTTP ' . $status_code . ').'; $result = [ 'ConfirmMessage' => 'SharePoint could not process your request: ' . $message, ]; } } catch (\Exception $e) { \Drupal::logger('upei_roblib_ill')->error( 'SharePoint webhook request failed: @message', ['@message' => $e->getMessage()] ); $result = [ 'ConfirmMessage' => 'Error communicating with SharePoint: ' . $e->getMessage(), ]; } upei_roblib_ill_log_request($payload, $result); return $result; } }