View source
<?php
namespace Drupal\fillpdf\Form;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\fillpdf\Component\Utility\FillPdf;
use Drupal\fillpdf\Plugin\PdfBackendManager;
use Drupal\fillpdf\Service\FillPdfAdminFormHelper;
use Drupal\fillpdf\ShellManager;
use GuzzleHttp\Client;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Link;
use Drupal\fillpdf\Entity\FillPdfForm;
class FillPdfSettingsForm extends ConfigFormBase {
protected $fileSystem;
protected $definitions = [];
protected $adminFormHelper;
protected $httpClient;
protected $shellManager;
public function __construct(ConfigFactoryInterface $config_factory, FileSystemInterface $file_system, FillPdfAdminFormHelper $admin_form_helper, Client $http_client, ShellManager $shell_manager, PdfBackendManager $backend_manager) {
parent::__construct($config_factory);
$this->fileSystem = $file_system;
$this->adminFormHelper = $admin_form_helper;
$this->httpClient = $http_client;
$this->shellManager = $shell_manager;
$this->definitions = $backend_manager
->getDefinitions();
}
public static function create(ContainerInterface $container) {
return new static($container
->get('config.factory'), $container
->get('file_system'), $container
->get('fillpdf.admin_form_helper'), $container
->get('http_client'), $container
->get('fillpdf.shell_manager'), $container
->get('plugin.manager.fillpdf.pdf_backend'));
}
public function getFormId() {
return 'fillpdf_settings';
}
protected function getEditableConfigNames() {
return [
'fillpdf.settings',
];
}
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$config = $this
->config('fillpdf.settings');
$scheme_options = $this->adminFormHelper
->schemeOptions([
'public' => $this
->t('@scheme (discouraged)'),
'private' => $this
->t('@scheme (recommended)'),
]);
$form['allowed_schemes'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Allowed file storages'),
'#default_value' => array_intersect(array_keys($scheme_options), $config
->get('allowed_schemes')),
'#options' => $scheme_options,
'#description' => $this
->t("You may choose one or more file storages to be available for storing generated PDF files with actual entity data; note that %public does not provide any access control.<br />If you don't choose any file storage, generated PDFs may only be sent to the browser instead of being stored.", [
'%public' => $this
->t('Public files'),
]),
];
$form['advanced_storage'] = [
'#type' => 'details',
'#title' => $this
->t('Advanced storage settings'),
];
$file_default_scheme = $this
->config('system.file')
->get('default_scheme');
$template_scheme_options = $this->adminFormHelper
->schemeOptions([
$file_default_scheme => $this
->t('@scheme (site default)'),
]);
$template_scheme = $config
->get('template_scheme');
if ($template_scheme && !array_key_exists($template_scheme, $template_scheme_options)) {
$this
->messenger()
->addError($this
->t('Your previously used file storage %previous_scheme is no longer available on this Drupal site, see the %system_settings. Please reset your default to an existing file storage.', [
'%previous_scheme' => $template_scheme . '://',
'%system_settings' => Link::createFromRoute($this
->t('File system settings'), 'system.file_system_settings')
->toString(),
]));
$map = $this->adminFormHelper
->getFormsByTemplateScheme($template_scheme);
if ($count = count($map)) {
$forms = FillPdfForm::loadMultiple(array_keys($map));
$items = [];
foreach ($map as $form_id => $file_uri) {
$fillpdf_form = $forms[$form_id];
$admin_title = current($fillpdf_form
->get('admin_title')
->getValue());
$link = Link::fromTextAndUrl($admin_title ?: "FillPDF form {$fillpdf_form->id()}", $fillpdf_form
->toUrl());
$items[$form_id] = new FormattableMarkup("@fillpdf_form: {$file_uri}", [
'@fillpdf_form' => $link
->toString(),
]);
}
$error_message = [
'#prefix' => $this
->t('Nevertheless, the following FillPDF forms will not work until their respective PDF templates have been moved to an existing file scheme:'),
[
'#theme' => 'item_list',
'#items' => $items,
],
];
$this
->messenger()
->addError(\Drupal::service('renderer')
->renderPlain($error_message));
}
$this
->logger('fillpdf')
->critical('File storage %previous_scheme is no longer available.' . $count ? " {$count} FillPDF forms are defunct." : '', [
'%previous_scheme' => $template_scheme . '://',
]);
}
$form['advanced_storage']['template_scheme'] = [
'#type' => 'radios',
'#title' => $this
->t('Template storage'),
'#default_value' => array_key_exists($template_scheme, $template_scheme_options) ? $template_scheme : $file_default_scheme,
'#options' => $template_scheme_options,
'#description' => $this
->t('This setting is used as the storage for uploaded templates; note that the use of %public is more efficient, but does not provide any access control.<br />Changing this setting will require you to migrate associated files and data yourself and is not recommended after you have uploaded a template.', [
'%public' => t('Public files'),
]),
];
$form['backend'] = [
'#type' => 'radios',
'#title' => $this
->t('PDF-filling service'),
'#description' => $this
->t('This module requires the use of one of several external PDF manipulation tools. Choose the service you would like to use.'),
'#default_value' => $config
->get('backend') ?: 'fillpdf_service',
'#options' => [],
];
foreach ($this->definitions as $id => $definition) {
$label = $definition['label'];
$description = $definition['description'];
$form['backend']['#options'][$id] = "<strong>{$label}</strong>" . ($description ? ": {$description}" : '');
}
$form['fillpdf_service'] = [
'#type' => 'details',
'#title' => $this
->t('Configure %label', [
'%label' => $this->definitions['fillpdf_service']['label'],
]),
'#open' => TRUE,
'#states' => [
'visible' => [
':input[name="backend"]' => [
'value' => 'fillpdf_service',
],
],
],
];
$form['fillpdf_service']['remote_endpoint'] = [
'#type' => 'textfield',
'#title' => $this
->t('Server endpoint'),
'#default_value' => $config
->get('remote_endpoint'),
'#description' => $this
->t('The endpoint for the FillPDF Service instance. This does not usually need to be changed, but you may want to if you have, for example, a <a href="https://fillpdf.io/hosting">private server</a>. Do not include the protocol, as this is determined by the <em>Use HTTPS?</em> setting below.'),
];
$form['fillpdf_service']['fillpdf_service_api_key'] = [
'#type' => 'textfield',
'#title' => $this
->t('API Key'),
'#default_value' => $config
->get('fillpdf_service_api_key'),
'#description' => $this
->t('You need to sign up for an API key at <a href="@link">FillPDF Service</a>', [
'@link' => Url::fromUri('https://fillpdf.io')
->toString(),
]),
];
$form['fillpdf_service']['remote_protocol'] = [
'#type' => 'radios',
'#title' => $this
->t('Use HTTPS?'),
'#description' => $this
->t('It is recommended to select <em>Use HTTPS</em> for this option. Doing so will help prevent
sensitive information in your PDFs from being intercepted in transit between your server and the remote service. <strong>FillPDF Service will only work with HTTPS.</strong>'),
'#default_value' => $config
->get('remote_protocol'),
'#options' => [
'https' => $this
->t('Use HTTPS'),
'http' => $this
->t('Do not use HTTPS'),
],
];
$form['local_service'] = [
'#type' => 'details',
'#title' => $this
->t('Configure %label', [
'%label' => $this->definitions['local_service']['label'],
]),
'#open' => TRUE,
'#states' => [
'visible' => [
':input[name="backend"]' => [
'value' => 'local_service',
],
],
],
];
$form['local_service_endpoint'] = [
'#type' => 'textfield',
'#title' => $this
->t('Configure FillPdf LocalServer endpoint (address)'),
'#default_value' => $config
->get('local_service_endpoint'),
'#description' => $this
->t("Enter the network address of your FillPDF LocalServer installation. If you are running the Docker container on port 8085 locally, then the address is <em>http://127.0.0.1:8085</em>."),
'#group' => 'local_service',
];
$form['pdftk'] = [
'#type' => 'details',
'#title' => $this
->t('Configure %label', [
'%label' => $this->definitions['pdftk']['label'],
]),
'#open' => TRUE,
'#states' => [
'visible' => [
':input[name="backend"]' => [
'value' => 'pdftk',
],
],
],
];
$form['pdftk_path'] = [
'#type' => 'textfield',
'#title' => $this
->t('Configure path to pdftk'),
'#description' => $this
->t("If FillPDF is not detecting your pdftk installation, you can specify the full path to the program here. Include the program name as well. On many systems, <em>/usr/bin/pdftk</em> is a valid value. You can almost always leave this field blank. If you should set it, you'll probably know."),
'#default_value' => $config
->get('pdftk_path') ?: 'pdftk',
'#group' => 'pdftk',
];
$form['shell_locale'] = [
'#title' => $this
->t('Server locale'),
'#group' => 'pdftk',
];
if ($this->shellManager
->isWindows()) {
$form['shell_locale'] += [
'#type' => 'textfield',
'#description' => $this
->t("The locale to be used to prepare the command passed to executables. The default, <kbd>'@default'</kbd>, should work in most cases. If that is not available on the server, @op.", [
'@default' => '',
'@op' => $this
->t('enter another locale'),
]),
'#default_value' => $config
->get('shell_locale') ?: '',
];
}
else {
$locales = $this->shellManager
->getInstalledLocales();
$default = isset($locales['en_US.UTF-8']) ? 'en_US.UTF-8' : 'en_US.utf8';
$form['shell_locale'] += [
'#type' => 'select',
'#description' => $this
->t("The locale to be used to prepare the command passed to executables. The default, <kbd>'@default'</kbd>, should work in most cases. If that is not available on the server, @op.", [
'@default' => $default,
'@op' => $this
->t('choose another locale'),
]),
'#options' => $locales,
'#default_value' => $config
->get('shell_locale') ?: 'en_US.utf8',
];
$form['shell_locale']['#process'][] = [
'Drupal\\Core\\Render\\Element\\Select',
'processGroup',
];
$form['shell_locale']['#pre_render'][] = [
'Drupal\\Core\\Render\\Element\\Select',
'preRenderGroup',
];
}
return $form;
}
public function validateForm(array &$form, FormStateInterface $form_state) {
$values = $form_state
->getValues();
switch ($values['backend']) {
case 'fillpdf_service':
break;
case 'local_service':
$config = $this
->config('fillpdf.settings')
->set('local_service_endpoint', $values['local_service_endpoint']);
$status = FillPdf::checkLocalServiceEndpoint($this->httpClient, $config);
if ($status === FALSE) {
$error_message = $this
->t('FillPDF LocalService is not properly installed. Was unable to contact %endpoint', [
'%endpoint' => $values['local_service_endpoint'],
]);
$form_state
->setErrorByName('local_service_endpoint', $error_message);
}
break;
case 'pdftk':
$status = FillPdf::checkPdftkPath($values['pdftk_path']);
if ($status === FALSE) {
$error_message = $this
->t('The path you have entered for <em>pdftk</em> is invalid. Please enter a valid path.');
$form_state
->setErrorByName('pdftk_path', $error_message);
}
break;
}
$template_scheme = $values['template_scheme'];
$schemes_to_prepare = array_filter($values['allowed_schemes']) + [
$template_scheme => $template_scheme,
];
foreach ($schemes_to_prepare as $scheme) {
$uri = FillPdf::buildFileUri($scheme, 'fillpdf');
if (!$this->fileSystem
->prepareDirectory($uri, FileSystemInterface::CREATE_DIRECTORY + FileSystemInterface::MODIFY_PERMISSIONS)) {
$error_message = $this
->t('Could not automatically create the subdirectory %directory. Please check permissions before trying again.', [
'%directory' => $this->fileSystem
->realpath($uri),
]);
$form_state
->setErrorByName('template_scheme', $error_message);
}
}
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$values = $form_state
->getValues();
$config = $this
->config('fillpdf.settings');
$config
->set('allowed_schemes', array_keys(array_filter($values['allowed_schemes'])))
->set('template_scheme', $values['template_scheme'])
->set('backend', $values['backend']);
switch ($values['backend']) {
case 'fillpdf_service':
$config
->set('remote_endpoint', $values['remote_endpoint'])
->set('fillpdf_service_api_key', $values['fillpdf_service_api_key'])
->set('remote_protocol', $values['remote_protocol']);
break;
case 'local_service':
$config
->set('local_service_endpoint', $values['local_service_endpoint']);
break;
case 'pdftk':
$config
->set('pdftk_path', $form_state
->getValue('pdftk_path'))
->set('shell_locale', $values['shell_locale']);
break;
}
$config
->save();
parent::submitForm($form, $form_state);
}
}