4

我从 buildForm 函数创建了一个自定义表单。在这种形式中,我想添加一个图像字段。

我可以通过以下代码做到这一点:

$form['main']['image'] = array(
    '#type' => 'text_format',
    '#title' => t('image'),
    '#default_value' => array(10),
);

我可以从表单中上传和删除图像。但是,当我上传图片时,我没有这个预览。我的意思是,当我通过 Drupal UI 创建内容时。我可以添加一个预配置的“图像”字段。当我通过这个“图像”字段上传图像时,我可以预览图像。

在这里,当我以编程方式创建字段元素时,我上传她时没有预览图像。当我通过“图像”字段上传她时,如何使用 api Drupal 来预览图像?

4

5 回答 5

11

所以这就是我如何让我的表单显示缩略图。我基本上所做的是将 ImageWidget::process 中的代码放入主题预处理器并将元素的#theme 属性设置为 image_widget。

表单类中的图像元素应如下所示:

$form['profile_image'] = [
   '#type' => 'managed_file',
   '#title' => t('Profile Picture'),
   '#upload_validators' => array(
       'file_validate_extensions' => array('gif png jpg jpeg'),
       'file_validate_size' => array(25600000),
   ),
   **'#theme' => 'image_widget',**
   **'#preview_image_style' => 'medium',**
   '#upload_location' => 'public://profile-pictures',
   '#required' => TRUE,
];

在您的 name_of_default_theme.theme 文件中,您需要以下内容:

function name_of_default_theme_preprocess_image_widget(&$variables) {
    $element = $variables['element'];

    $variables['attributes'] = array('class' => array('image-widget', 'js-form-managed-file', 'form-managed-file', 'clearfix'));

    if (!empty($element['fids']['#value'])) {
        $file = reset($element['#files']);
        $element['file_' . $file->id()]['filename']['#suffix'] = ' <span class="file-size">(' . format_size($file->getSize()) . ')</span> ';
        $file_variables = array(
            'style_name' => $element['#preview_image_style'],
            'uri' => $file->getFileUri(),
        );

        // Determine image dimensions.
        if (isset($element['#value']['width']) && isset($element['#value']['height'])) {
            $file_variables['width'] = $element['#value']['width'];
            $file_variables['height'] = $element['#value']['height'];
        } else {
            $image = \Drupal::service('image.factory')->get($file->getFileUri());
            if ($image->isValid()) {
                $file_variables['width'] = $image->getWidth();
                $file_variables['height'] = $image->getHeight();
            }
            else {
                $file_variables['width'] = $file_variables['height'] = NULL;
            }
        }

        $element['preview'] = array(
            '#weight' => -10,
            '#theme' => 'image_style',
            '#width' => $file_variables['width'],
            '#height' => $file_variables['height'],
            '#style_name' => $file_variables['style_name'],
            '#uri' => $file_variables['uri'],
        );

        // Store the dimensions in the form so the file doesn't have to be
        // accessed again. This is important for remote files.
        $element['width'] = array(
            '#type' => 'hidden',
            '#value' => $file_variables['width'],
        );
        $element['height'] = array(
            '#type' => 'hidden',
            '#value' => $file_variables['height'],
        );
    }

    $variables['data'] = array();
    foreach (Element::children($element) as $child) {
        $variables['data'][$child] = $element[$child];
    }
}

该解决方案运行良好,但图像模块缺少带有 @FormElement 注释的类。这就是为什么元素没有正确渲染的原因。

于 2016-07-08T13:59:49.177 回答
3

您可以尝试使用 managed_file 类型吗?

'#type' => 'managed_file'
于 2016-02-01T10:56:44.213 回答
0

不错的答案 thx,我要做的唯一更改是使用 Token 作为上传位置,使用 Bytes 作为文件上传大小,尽管我猜这取决于用例。像下面这样的东西(为了简单起见,去掉了大部分代码。

namespace Drupal\my_module\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Component\Utility\Bytes;
use Drupal\Core\Utility\Token;

class SampleForm extends FormBase
{

  protected $currentUser;

  protected $token;


  public function __construct(AccountProxyInterface $current_user, Token $token) {
    $this->currentUser = $current_user;
    $this->token = $token;
  }


  public static function create(ContainerInterface $container)
  {
    return new static(
      $container->get('current_user'),
      $container->get('token')
    );
  }


  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['sample_image'] = [
        '#type' => 'managed_file',
        '#title' => t('Profile Picture'),
        '#upload_validators' => array(
          'file_validate_extensions' => array('gif png jpg jpeg'),
          'file_validate_size' => file_upload_max_size() / pow(Bytes::KILOBYTE, 2) . 'M',
        ),
      '#theme' => 'image_widget',
      '#preview_image_style' => 'medium',
      '#upload_location' => $this->token->replace('private://[date:custom:Y]-[date:custom:m]'),
      '#required' => TRUE,
    ];

    return $form;
  }
}
于 2019-01-03T21:28:12.833 回答
0

主题它适用于多个文件上传。来自@Je Suis Alrick 上面的回答。

    function themename_preprocess_image_widget(&$variables) {
    $element = $variables['element'];

    $variables['attributes'] = array('class' => array('image-widget', 'js-form-managed-file', 'form-managed-file', 'clearfix'));
   
    if (!empty($element['fids']['#value'])) {

        foreach ($element['#files'] as $file) {
         
            $element['file_' . $file->id()]['filename']['#suffix'] = ' <span class="file-size">(' . format_size($file->getSize()) . ')</span> ';
            $file_variables = array(
                'style_name' => $element['#preview_image_style'],
                'uri' => $file->getFileUri(),
            );

            // Determine image dimensions.
            if (isset($element['#value']['width']) && isset($element['#value']['height'])) {
                $file_variables['width'] = $element['#value']['width'];
                $file_variables['height'] = $element['#value']['height'];
            } else {
                $image = \Drupal::service('image.factory')->get($file->getFileUri());
                if ($image->isValid()) {
                    $file_variables['width'] = $image->getWidth();
                    $file_variables['height'] = $image->getHeight();
                }
                else {
                    $file_variables['width'] = $file_variables['height'] = NULL;
                }
            }

            $element['preview'][] = array(
                '#weight' => -10,
                '#theme' => 'image_style',
                '#width' => $file_variables['width'],
                '#height' => $file_variables['height'],
                '#style_name' => $file_variables['style_name'],
                '#uri' => $file_variables['uri'],
            );

            // Store the dimensions in the form so the file doesn't have to be
            // accessed again. This is important for remote files.
            $element['width'] = array(
                '#type' => 'hidden',
                '#value' => $file_variables['width'],
            );
            $element['height'] = array(
                '#type' => 'hidden',
                '#value' => $file_variables['height'],
            );
        }
    }


    $variables['data'] = array();
    foreach (\Drupal\Core\Render\Element::children($element) as $child) {
        $variables['data'][$child] = $element[$child];
    }
}
于 2021-07-22T19:23:19.677 回答
0

首先是一些澄清,然后是一些观察,然后是对我有用的代码。

说明:

  1. 我正在使用 Drupal 9,但下面提出的解决方案可能也适用于 Drupal 8。
  2. “默认临时目录”是指以下设置中定义的目录

文件

[DrupalrootDirectory]/sites/default/settings.php

使用

$settings['file_temp_path'] = '/The/Absolute/Path/To/Your/Temporary/Directory'; 

或由您的操作系统定义,您可以在 Drupal 管理菜单中查看:

[YourSiteWebAddress]/admin/config/media/file-system
  1. 当在方括号 [] 中写入某些内容时,例如 [DrupalrootDirectory],这意味着您应该将其替换为系统中的实际名称、Drupal 安装或自定义模块/文件,不带方括号。

观察:

  1. 无需在默认临时目录中创建任何目录。它们将自动创建。
  2. 当您单击“删除”按钮(在您上传自定义表单中的文件后会自动出现)时,图像文件和缩略图文件将从默认临时目录中删除。
  3. 如果您在默认站点位置定义默认临时目录,则无关紧要,

例如,

[DrupalrootDirectory]/sites/default/files

或在它之外,例如,

[DrupalrootDirectory]/sites/other/files

就我而言,我将其定义为:

[DrupalrootDirectory]/sites/default/files/temp
  1. 无需更改默认临时目录中的 .htaccess(在 Apache 服务器中)文件或

里面

[DrupalrootDirectory]/sites/default/files

保留它们,就像 Drupal 创建它们一样。

  1. 无需将默认临时目录中的文件权限更改为“777”,“775”就足够了。

  2. 检查您的 Drupal 安装是否确实为使用

管理菜单:

 [YourSiteWebAddress]/admin/content/media 

使用“添加媒体”链接时

[YourSiteWebAddress]/media/add/image
  1. 无需在 Drupal 设置中进行任何其他更改

文件

[DrupalrootDirectory]/sites/default/settings.php

对我有用的代码:

它基于上面由“Je Suis Alrick”发布的代码。但是他的代码对我不起作用,我也找不到缩略图实际上是在他的代码的哪一部分创建的。在我的搜索中,这篇文章帮助了

使用 Drupal 8 以编程方式生成图像样式

所以,这是最终的代码:

  1. 在您的自定义模块中,在自定义表单文件中,很可能位于

在:

[DrupalrootDirectory]/modules/custom/[NameOfYourCustomModule]/src/Form/[NameOfYourCustomForm].php

您添加要用于上传图像文件的元素:

$form['profile_image'] = [
   '#type' => 'managed_file',
   '#title' => t('Profile Picture'),
   '#upload_validators' => array(
       'file_validate_extensions' => array('gif png jpg jpeg'),
       'file_validate_size' => array(25600000),
   ),
  '#theme' => 'image_widget',
  '#preview_image_style' => 'medium',

   '#required' => TRUE,
];

到目前为止,与“Je Suis Alrick”的代码相同,只是我删除了“#upload_location”的定义,因此将使用默认的临时目录以避免安全投诉。

这里的重要部分是:

  • “#theme”的定义,可以是任何名称,但在本例中是“image_widget”;
  • 以及“#preview_image_style”的定义,它必须是您的 Drupal 安装中定义的一种图像样式的机器名称,您可以在管理中检查

菜单

[YourSiteWebAddress]/admin/config/media/image-styles

在这种情况下,将使用样式“medium”,这是 Drupal 默认创建的图像样式之一。

  1. 然后,在您的自定义模块的模块文件中,名为 [NameOfYourCustomModule].module 并且很可能位于

在:

[DrupalrootDirectory]/modules/custom/[NameOfYourCustomModule]/

您将需要粘贴以下代码:

<?php

use Drupal\image\Entity\ImageStyle;

function [NameOfYourCustomModule]_preprocess_image_widget(&$variables) {
    $element = $variables['element'];

    $variables['attributes'] = array('class' => array('image-widget', 'js-form-managed-file', 'form-managed-file', 'clearfix'));

    if (!empty($element['fids']['#value'])) {
      $file = reset($element['#files']);
      $element['file_' . $file->id()]['filename']['#suffix'] = ' <span class="file-size">(' . format_size($file->getSize()) . ')</span> ';
      $file_variables = array(
        'style_name' => $element['#preview_image_style'],
        'uri' => $file->getFileUri(),
      );

      // Determine image dimensions.
      if (isset($element['width']['#value']) && isset($element['height']['#value'])) {
        $file_variables['width'] = $element['width']['#value'];
        $file_variables['height'] = $element['height']['#value'];
      } else {
        $image = \Drupal::service('image.factory')->get($file->getFileUri());
        
        if ($image->isValid()) {
          $file_variables['width'] = $image->getWidth();
          $file_variables['height'] = $image->getHeight();
          $style = ImageStyle::load($file_variables['style_name']);
          $image_uri = $file->getFileUri();
          $destination = $style->buildUri($image_uri);
          $style->createDerivative($image_uri, $destination);
        }
        else {
          $file_variables['width'] = $file_variables['height'] = NULL;
        }
      }

      $element['preview'] = array(
        '#weight' => -10,
        '#theme' => 'image_style',
        '#width' => $file_variables['width'],
        '#height' => $file_variables['height'],
        '#style_name' => $file_variables['style_name'],
        '#uri' => $file_variables['uri'],
      );

      // Store the dimensions in the form so the file doesn't have to be
      // accessed again. This is important for remote files.
      $element['width'] = array(
        '#type' => 'hidden',
        '#value' => $file_variables['width'],
      );
      $element['height'] = array(
        '#type' => 'hidden',
        '#value' => $file_variables['height'],
      );
    }

    $variables['data'] = array();
    foreach (\Drupal\Core\Render\Element::children($element) as $child) {
      $variables['data'][$child] = $element[$child];
    }
}

您应该注意,在函数名称的末尾,包含主题“image_widget”的名称,它告诉 Drupal 使用上面定义的函数处理您的表单元素:[NameOfYourCustomModule]_preprocess_image_widget

我添加了什么?

  • 线在

最佳:

 use Drupal\image\Entity\ImageStyle;
  • 以下四行实际在默认临时目录中创建图像缩略图:

            $style = ImageStyle::load($file_variables['style_name']);
            $image_uri = $file->getFileUri();
            $destination = $style->buildUri($image_uri);
            $style->createDerivative($image_uri, $destination);
    

加上这五行,我得到了它的工作!

于 2021-09-27T13:47:52.080 回答