客户的文件很多,也很大,按照特定的目录进行管理,比如一个期刊下面有很多个PDF文件。如果把所有文件都放到Drupal的文件系统中的话,关联导入都不大方便。
为了解决客户的文件管理,我们只管理某一个期刊的目录,目录下面的文件的下载,展示都通过程序来控制。这个功能在Drupal8下面没有现成的模块。
我们经过讨论,帮助客户定制了一个私有文件的下载管理模块。
需求:
客户自己维护一个私有文件目录,里面的目录结构元信息,整理成csv文件。
只管理目录的信息,一个期刊对应一个目录,这个目录列出期刊的所有可用pdf。
用户查看期刊的时候,可以查看这个期刊下面的所有文件,
点击需要的文件可以下载。下载需要支持统计。
关键代码:
/**
* Download list page.
*/
public function downloadList($resource_type, $resource_id) {
//注意需要修改directory属性,如果设置的不一样,需要修改j_resource,如果不一致。
$resurce = '';
$resource = \Drupal::entityManager()->getStorage($resource_type)->load($resource_id);
if(empty($resource)){
return [
'#markup' => '<p>' .t('No content.') . '</p>',
];
}
$directory = 'private://' . $resource->directory->value;
$render_array['content']['files'] = [
'#type' => 'table',
'#header' => [
t('Name'),
t('Download'),
],
];
$rows = [];
$files = file_scan_directory($directory, '/.*/');
$key = 0;
foreach ($files as $file) {
$rows[$key]['name'] = $file->filename;
$rows[$key]['download'] = new Link(t('download'), Url::fromRoute("mydownload.download", ["resource_type" => $resource_type, "resource_id" => $resource_id, "filename" => $file->filename]));;
$key++;
}
$render_array['content']['files']['#rows'] = $rows;
return $render_array;
}
这个函数用来列出期刊的文件。
/**
* A custom access check.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
*/
public function access(AccountInterface $account) {
// Check permissions and combine that with any custom access checking needed. Pass forward
// parameters from the route and/or request as needed.
$has_permission = $account->hasPermission('access download page');
$ip = \Drupal::request()->getClientIp();
//if(mydownload_ip_allowed($ip)){
// drupal_set_message('true:' .$ip);
//}else{
// drupal_set_message('false:' .$ip);
//}
//drupal_set_message('id:' .$ip);
if($has_permission || mydownload_ip_allowed($ip)){
return AccessResult::allowed();
}
return AccessResult::forbidden();
}
这个函数用来检查access控制权限,只有有权限的用户,或者特定IP的才可以查看下载。
通过代码控制下载:
/**
* Downloads a tarball of the site configuration.
*/
public function download($resource_type, $resource_id, $filename) {
//注意需要修改directory属性,如果设置的不一样,需要修改j_resource,如果不一致。
$resource = \Drupal::entityManager()->getStorage($resource_type)->load($resource_id);
if(empty($resource)){
return [
'#markup' => '<p>' .t('No content.') . '</p>',
];
}
//$directory = 'private://' . $resource->directory->value;
$name = $resource->directory->value . '/' . $filename;
$download = \Drupal::entityTypeManager()->getStorage('download')->create(['filename' => $filename,]);
//$download->filename->value = '';
$download->resource_type->value = $resource_type;
$download->resource_id->value = $resource_id;
$download->resource_name->value = $resource->label();
//$download->rid->target_id = $rid;
$download->ip->value = \Drupal::request()->getClientIp();
$download->uid->target_id = \Drupal::currentUser()->id();
$download->timestamp->value = \Drupal::time()->getRequestTime();
$download->save();
db_merge('mydownload_count')
//->key('id', $rid)
->keys(['id' => $resource_id, 'type' => $resource_type,])
->fields([
'count' => 1,
'last_timestamp' => \Drupal::time()->getRequestTime(),
])
->expression('count', 'count + 1')
->execute();
$request = new Request(['file' => $name]);
return $this->fileDownloadController->download($request, 'private');
}
这里使用了use Drupal\system\FileDownloadController;管理下载,下载时,统计了哪个用户IP,下载了哪个资源,在什么时间,还对一个资源被下载了多少次进行了计算。
这段代码到这里是不工作的。还需要实现这个钩子函数:
/**
* Implements hook_file_download().
*/
function mydownload_file_download($uri) {
$scheme = file_uri_scheme($uri);
$filename = drupal_basename($uri);
if ($scheme == 'private') {
//$filename = $target;
$disposition = 'attachment; filename="' . $filename . '"';
return [
'Content-disposition' => $disposition,
];
//return -1;
}
}
加上这段关键的代码,就搞定