Skip to content
Snippets Groups Projects
Commit 4234a8c1 authored by Kevin Kaland's avatar Kevin Kaland
Browse files

Issue #2359213: WIP port private file support.

Works for FillPDF forms now but not for generated PDFs.
parent f996fe35
No related branches found
No related tags found
No related merge requests found
<?php
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\fillpdf\Service\FillPdfAdminFormHelper;
/**
* Add scheme field to FillPdfForm.
*/
function fillpdf_update_8101() {
$edum = \Drupal::entityDefinitionUpdateManager();
$scheme_field = BaseFieldDefinition::create('string')
->setLabel('Storage system for generated PDFs')
->setDescription(t('This setting is used as the storage/download method for generated PDFs. The use of public files is more efficient, but does not provide any access control. Changing this setting will require you to migrate associated files and data yourself and is not recommended after you have uploaded a template.'))
->setDisplayOptions('form', array(
'type' => 'radios',
'options' => FillPdfAdminFormHelper::schemeOptions(),
));
$edum->installFieldStorageDefinition('scheme', 'fillpdf_form', 'fillpdf_form', $scheme_field);
}
......@@ -45,4 +45,12 @@ class FillPdf {
return $view->preview($display_id, $args);
}
/**
* Constructs a URI to FillPDF's default files location given a relative path.
*/
public static function buildFileUri($scheme, $path) {
$uri = $scheme . '://' . $path;
return file_stream_wrapper_uri_normalize($uri);
}
}
......@@ -99,18 +99,34 @@ class FillPdfForm extends ContentEntityBase implements FillPdfFormInterface {
directly to the browser for download. Enter a path here to change this behavior (tokens allowed).
<strong>Warning! Unless you include the &download=1 flag in the FillPDF URL, PDFs will only
be saved to disk <em>and won't</em> be sent to the browser as well.</strong></p><p>The path
you specify must be in one of the following two formats:<br />
you specify must be in the following format:<br />
<ul>
<li><em>path/to/directory</em> (path will be treated as relative to
your <em>files</em> directory)</li>
<li><em>/absolute/path/to/directory</em> (path will be treated as relative to your entire
<li><code>path/to/directory</code> (path will be treated as relative to
your <em>fillpdf</em> files subdirectory)</li>
filesystem)</li>
</ul>
Note that, in both cases, you are responsible for ensuring that the user under which PHP is running can write to this path. Do not include a trailing slash.</p>"))
->setDisplayOptions('form', array(
Note that you are responsible for ensuring that the user under which PHP is running can write to this path. Do not include a trailing slash.</p>"))
->setDisplayOptions('form', [
'type' => 'string',
'weight' => 20,
));
]);
// @todo: add post_save_redirect field for where to send the browser by default after they generate a PDF
$fields['scheme'] = BaseFieldDefinition::create('list_string')
->setLabel('Storage system for generated PDFs')
->setDescription(t('This setting is used as the storage/download method for generated PDFs. The use of public files is more efficient, but does not provide any access control. Changing this setting will require you to migrate associated files and data yourself and is not recommended after you have uploaded a template.'))
->setSettings([
'allowed_values' => FillPdfAdminFormHelper::schemeOptions(),
])
->setRequired(TRUE)
->setDisplayOptions('form', [
'type' => 'options_buttons',
'weight' => 25,
'settings' => [
'options' => FillPdfAdminFormHelper::schemeOptions(),
],
]);
$fields['destination_redirect'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Redirect browser directly to saved PDF'))
......
......@@ -10,11 +10,27 @@ use Drupal\Core\Entity\ContentEntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
use Drupal\file\FileUsage\FileUsageInterface;
use Drupal\fillpdf\FillPdfFormInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FillPdfFormDeleteForm extends ContentEntityConfirmFormBase {
use StringTranslationTrait;
/** @var \Drupal\file\FileUsage\FileUsageInterface $fileUsage */
protected $fileUsage;
public function __construct(FileUsageInterface $file_usage) {
$this->fileUsage = $file_usage;
}
public static function create(ContainerInterface $container) {
return new static($container->get('file.usage'));
}
/**
* {@inheritdoc}
*/
......@@ -34,7 +50,13 @@ class FillPdfFormDeleteForm extends ContentEntityConfirmFormBase {
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->getEntity()->delete();
/** @var FillPdfFormInterface $fillpdf_form */
$fillpdf_form = $this->getEntity();
/** @var FileInterface $file */
$file = File::load($fillpdf_form->get('file')->first()->target_id);
$this->fileUsage->delete($file, 'fillpdf', 'fillpdf_form', $fillpdf_form->id());
$fillpdf_form->delete();
drupal_set_message($this->t('FillPDF form deleted.'));
......
......@@ -140,6 +140,7 @@ class FillPdfFormForm extends ContentEntityForm {
);
$form['destination_path']['#group'] = 'additional_settings';
$form['scheme']['#group'] = 'additional_settings';
$form['destination_redirect']['#group'] = 'additional_settings';
$form['fillpdf_fields'] = FillPdf::embedView('fillpdf_form_fields',
......
......@@ -8,16 +8,20 @@ namespace Drupal\fillpdf\Form;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\String;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\file\FileUsage\FileUsageInterface;
use Drupal\fillpdf\Component\Utility\FillPdf;
use Drupal\fillpdf\Entity\FillPdfForm;
use Drupal\fillpdf\Entity\FillPdfFormField;
use Drupal\fillpdf\FillPdfBackendManager;
use Drupal\fillpdf\FillPdfBackendPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FillPdfOverviewForm extends FillPdfAdminFormBase {
/**
......@@ -33,9 +37,12 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
/** @var AccountInterface $current_user */
protected $currentUser;
/** @var \Drupal\Core\Entity\Query\QueryFactory $entityQuery */
/** @var QueryFactory $entityQuery */
protected $entityQuery;
/** @var FileSystemInterface $fileSystem */
protected $fileSystem;
/**
* Returns a unique string identifying the form.
*
......@@ -46,12 +53,14 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
return 'fillpdf_forms_admin';
}
public function __construct(ModuleHandlerInterface $module_handler, FillPdfBackendManager $backend_manager, AccountInterface $current_user, QueryFactory $entity_query) {
public function __construct(ModuleHandlerInterface $module_handler, FillPdfBackendManager $backend_manager, AccountInterface $current_user, QueryFactory $entity_query, FileSystemInterface $file_system, FileUsageInterface $file_usage) {
parent::__construct();
$this->backendManager = $backend_manager;
$this->moduleHandler = $module_handler;
$this->currentUser = $current_user;
$this->entityQuery = $entity_query;
$this->fileSystem = $file_system;
$this->fileUsage = $file_usage;
}
/**
......@@ -63,7 +72,9 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
// Load the plugin manager.
$container->get('plugin.manager.fillpdf_backend'),
$container->get('current_user'),
$container->get('entity.query')
$container->get('entity.query'),
$container->get('file_system'),
$container->get('file.usage')
);
}
......@@ -115,7 +126,7 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
public function validateForm(array &$form, FormStateInterface $form_state) {
$file_upload = $this->getRequest()->files->get('files[upload_pdf]', NULL, TRUE);
/**
* @var $file_upload \Symfony\Component\HttpFoundation\File\UploadedFile
* @var $file_upload UploadedFile
*/
if ($file_upload && $file_upload->isValid()) {
// Move it to somewhere we know.
......@@ -123,21 +134,22 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
// Ensure the destination is unique; we deliberately use managed files,
// but they are keyed on file URI, so we can't save the same one twice.
$destination = file_destination(file_build_uri('fillpdf/' . $uploaded_filename), FILE_EXISTS_RENAME);
$scheme = $this->config('fillpdf.settings')->get('scheme');
$destination = file_destination(FillPdf::buildFileUri($scheme, 'fillpdf/' . $uploaded_filename), FILE_EXISTS_RENAME);
// Ensure our directory exists.
$fillpdf_directory = file_build_uri('fillpdf');
$fillpdf_directory = FillPdf::buildFileUri($scheme, 'fillpdf');
$directory_exists = file_prepare_directory($fillpdf_directory, FILE_CREATE_DIRECTORY + FILE_MODIFY_PERMISSIONS);
if ($directory_exists) {
$file_moved = drupal_move_uploaded_file($file_upload->getRealPath(), $destination);
$file_moved = $this->fileSystem->moveUploadedFile($file_upload->getRealPath(), $destination);
if ($file_moved) {
// Create a File object from the uploaded file.
$new_file = File::create(array(
$new_file = File::create([
'uri' => $destination,
'uid' => $this->currentUser()->id(),
));
]);
$errors = file_validate_extensions($new_file, 'pdf');
......@@ -177,14 +189,17 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
$file->setPermanent();
$file->save(); // Save the file so we can get an fid
$fillpdf_form = FillPdfForm::create(array(
$fillpdf_form = FillPdfForm::create([
'file' => $file,
'title' => $file->filename,
));
'scheme' => $this->config('fillpdf.settings')->get('scheme'),
]);
// Save PDF configuration before parsing. We'll add a button to let them attempt
// re-parsing if it fails.
$fillpdf_form->save();
$fid = $fillpdf_form->id();
$this->fileUsage->add($file, 'fillpdf', 'fillpdf_form', $fid);
$config = $this->config('fillpdf.settings');
$fillpdf_service = $config->get('backend');
......
......@@ -5,20 +5,50 @@
* Contains \Drupal\fillpdf\Form\FillPdfSettingsForm.
*/
namespace Drupal\fillpdf\Form;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\fillpdf\Component\Utility\FillPdf;
use Drupal\fillpdf\Service\FillPdfAdminFormHelper;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FillPdfSettingsForm extends ConfigFormBase {
/** @var FillPdfAdminFormHelper $adminFormHelper */
protected $adminFormHelper;
public function getFormId() {
return 'fillpdf_settings';
}
public function __construct(ConfigFactoryInterface $config_factory, FillPdfAdminFormHelper $admin_form_helper) {
$this->adminFormHelper = $admin_form_helper;
parent::__construct($config_factory);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('config.factory'), $container->get('fillpdf.admin_form_helper'));
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('fillpdf.settings');
$fillpdf_service = $config->get('fillpdf_service_backend');
$scheme_options = FillPdfAdminFormHelper::schemeOptions();
$form['scheme'] = array(
'#type' => 'radios',
'#title' => $this->t('Template download method'),
'#default_value' => $config->get('scheme'),
'#options' => $scheme_options,
'#description' => $this->t('This setting is used as the download method for uploaded templates. The use of public files is more efficient, but does not provide any access control. Changing this setting will require you to migrate associated files and data yourself and is not recommended after you have uploaded a template.'),
);
$fillpdf_service = $config->get('backend');
// Assemble service options. Warning messages will be added next as needed.
$options = array(
......
......@@ -22,11 +22,25 @@ class FillPdfAdminFormHelper implements FillPdfAdminFormHelperInterface {
* {@inheritdoc}
*/
public function getAdminTokenForm() {
return array(
return [
'#theme' => 'token_tree',
'#token_types' => 'all',
'#global_types' => TRUE,
);
];
}
/**
* Returns acceptable file scheme options.
*
* Suitable for use with FAPI radio buttons.
*
* @return array
*/
public static function schemeOptions() {
return [
'private' => t('Private files'),
'public' => t('Public files'),
];
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment