我正在使用 Drupal 开发自定义模块。用户上传一个 .zip 文件(该 zip 文件包含许多 .docx 文件),解压 .zip 文件并创建节点。
对于每个 .docx 文件,都会使用文件内容创建一个节点,并将实际文件作为附件。
我可以成功上传 .zip、解压 .zip、读取每个 .docx、使用 .docx 的内容创建节点,但我唯一不知道的是如何将 .docx 添加为附件。
这里有相当多的代码,你不需要深入查看所有代码,我已经在代码的每个“块”中添加了注释,说明它的作用,重要的部分我已经简要解释了.
我的代码的小指南:
在此函数中,我基本上创建了一个表单,以便用户可以上传 zip 文件。这里没有问题。
public function buildForm(array $form, FormStateInterface $form_state) {
$form['zip_file'] = [
'#type' => 'managed_file',
'#title' => $this->t('Upload Zip File'),
'#description' => $this->t('Upload a zip file containing Word documents.'),
'#upload_validators' => [
'file_validate_extensions' => ['zip'],
],
'#required' => TRUE,
'#upload_location' => 'temporary://word_document_import', // Custom upload location
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
];
return $form;
}
在下一个函数中,我基本上获取 .zip,将其解压,然后使用解压的文件作为节点创建的参数进行传递。
在这里,我认为可能有一些可能,以便可以将
\Drupal\file\Entity\File
实体传递到函数中,而不是我现在拥有的 SplFileInfo
实体。
更具体地说,当我检查传递给
createDecisionNode()
的内容时,这里:$this->createDecisionNode($file_entity, $docx_file, $form_state);
,我可以看到 $docx_file
=
SplFileInfo {#1336 ▼
path: "/var/www/html/tmp/word_document_import/Files"
filename: "file-sample_100kB.docx"
basename: "file-sample_100kB.docx"
pathname: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
extension: "docx"
realPath: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
aTime: 2024-04-23 13:03:25
mTime: 2024-04-23 12:17:02
cTime: 2024-04-23 13:03:25
inode: 8269895
size: 111303
perms: 0100644
owner: 1000
group: 1000
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
因此,我当前获得的格式并不是真正可以在节点中用作附件的文件。
public function submitForm(array &$form, FormStateInterface $form_state) {
/* GET THE UPLOADED .ZIP */
$file = $form_state->getValue('zip_file')[0];
$file_entity = \Drupal\file\Entity\File::load($file);
if (!$file_entity) {
$form_state->setError($form['zip_file'], $this->t('Unable to load the uploaded zip file.'));
return;
}
/* EXTRACT THE FILES FROM THE .ZIP */
$file_path = \Drupal::service('file_system')->realpath($file_entity->getFileUri());
$temp_dir = 'temporary://word_document_import';
$temp_dir = \Drupal::service('file_system')->realpath($temp_dir);
if (!file_exists($temp_dir)) {
\Drupal::service('file_system')->mkdir($temp_dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
ksm("FILE DOES NOT EXIST");
}
$zip = new ZipArchive();
if ($zip->open($file_path) === TRUE) {
$zip->extractTo($temp_dir);
$zip->close();
} else {
$form_state->setError($form['zip_file'], $this->t('Failed to extract the zip file.'));
return;
}
$original_filename = $file_entity->getFilename();
$zip_filename = pathinfo($original_filename, PATHINFO_FILENAME);
$zip_filename = preg_replace('/_\d+$/', '', $zip_filename);
$temp_dir_without_suffix = $temp_dir . '/' . $zip_filename; // the folder here with the extracted files
if (!file_exists($temp_dir_without_suffix)) {
$temp_dir_with_suffix = $temp_dir . '/' . $original_filename;
if (file_exists($temp_dir_with_suffix) && is_dir($temp_dir_with_suffix)) {
$temp_dir_without_suffix = $temp_dir_with_suffix;
}
}
/* GET THE EXTRACTED FILES */
$docx_files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($temp_dir_without_suffix));
/* CREATE NODES USING .DOCX FILES */
foreach ($docx_files as $docx_file) {
if ($docx_file->isFile() && $docx_file->getExtension() === 'docx') {
$this->createDecisionNode($file_entity, $docx_file, $form_state);
}
}
/* DELETE THE TEMORARY DIRECTORY */
if (file_exists($temp_dir_without_suffix) && is_dir($temp_dir_without_suffix)) {
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($temp_dir_without_suffix, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $file) {
if ($file->isDir()){
rmdir($file->getRealPath());
} else {
unlink($file->getRealPath());
}
}
rmdir($temp_dir_without_suffix);
}
/* REDIRECT TO CONTENTS PAGE */
$form_state->setRedirect('system.admin_content');
}
转到
createDecisionNode()
,我正在使用之前传递的$file_entity
。问题是 $file_entity
不是 .docx 文件,而是 .zip 文件。因此,所有正在创建的节点都不会获得与其内容相对应的 .docx,而是获得从表单上传的 .zip。
protected function createDecisionNode($file_entity, $docx_file, FormStateInterface $form_state) {
$text_content = $this->readDocxFile($docx_file->getPathname());
$filename = pathinfo($docx_file->getFilename(), PATHINFO_FILENAME);
$file = \Drupal\file\Entity\File::load($file_entity->id());
$node = Node::create([
'type' => 'decision',
'title' => $filename,
'field_attachment' => [
'target_id' => $file->id(),
],
'field_decision_text' => [
'value' => $text_content,
'format' => 'full_html',
],
]);
$node->save();
}
现在我基本上正在尝试做的事情,因为我已将所有这些信息传递给我的
createDecisionNode()
:
SplFileInfo {#1336 ▼
path: "/var/www/html/tmp/word_document_import/Files"
filename: "file-sample_100kB.docx"
basename: "file-sample_100kB.docx"
pathname: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
extension: "docx"
realPath: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
aTime: 2024-04-23 13:03:25
mTime: 2024-04-23 12:17:02
cTime: 2024-04-23 13:03:25
inode: 8269895
size: 111303
perms: 0100644
owner: 1000
group: 1000
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
有没有办法使用文件的路径(因为我已经有了它),并从那里获取文件,以便可以在 Node 字段中传递它?
或者也许有其他更好的方法来做到这一点?如有任何帮助,我们将不胜感激。
首先,您应该将 .docx 文件保存在永久路径上,然后再删除临时文件夹。
之后,您应该使用此保存的文件作为您的
createDecisionNode
方法的参数。
无需将
$file_entity
传递给创建方法,因为您应该使用 .docx 文件 ID 作为 field_attachment => target_id
的值。