如何在SonataAdminBundle中显示当前图片在上传字段上方?

19
我正在使用带有Doctrine2 ORM的SonataAdminBundle,并且已经成功地向我的Picture模型添加了文件上传功能。
我想在“显示”和“编辑”页面上,在相关的表单字段上方显示一个简单的<img src="{{ picture.url }} alt="{{ picture.title }} />标记,以便用户可以看到当前照片,并决定是否更改它(当然,前提是正在编辑的Picture不是新建的)。
经过数小时的研究,我一直无法弄清楚如何实现。我想我需要覆盖一些模板,但我有点迷失了…… 能有人给我一条提示吗?
这是我的PictureAdmin类的相关部分。
protected function configureFormFields(FormMapper $formMapper)
{
    $formMapper
        ->add('category', NULL, ['label' => 'Catégorie'])
        ->add('title', NULL, ['label' => 'Titre'])
        ->add('file', 'file', ['required' => false, 'label' => 'Fichier']) // Add picture near this field
        ->add('creation_date', NULL, ['label' => 'Date d\'ajout'])
        ->add('visible', NULL, ['required' => false, 'label' => 'Visible'])
        ->add('position', NULL, ['label' => 'Position']);
}

protected function configureShowFields(ShowMapper $showMapper)
{
    $showMapper
        ->add('id', NULL, ['label' => 'ID'])
        ->add('category', NULL, ['label' => 'Catégorie'])
        ->add('title', NULL, ['label' => 'Titre'])
        ->add('slug', NULL, ['label' => 'Titre (URL)'])
        ->add('creation_date', NULL, ['label' => 'Date d\'ajout'])
        ->add('visible', NULL, ['label' => 'Visible'])
        ->add('position', NULL, ['label' => 'Position']);
        // Add picture somewhere
}


备选方案:http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html - DonCallisto
7个回答

14
我已经成功将图像放置在编辑表单字段上方。但是我的解决方案有点特殊,因为我使用Vich Uploader Bundle来处理上传,所以由于bundle helpers的帮助,生成图像url变得更加容易。
让我们看一下我的示例,一个电影实体中的电影海报字段。 这是我的管理类的一部分:
//MyCompany/MyBundle/Admin/FilmAdmin.php

class FilmAdmin extends Admin {

protected function configureFormFields(FormMapper $formMapper)
{
 $formMapper
     ->add('title')
 ....
     ->add('poster', 'mybundle_admin_image', array(
                'required' => false,
                ))
}

mybundle_admin_image由自定义字段类型处理,这个类型只是通过设置它的getParent方法作为文件类型的子项而被创建的:(别忘了将你的类型类注册为服务)

//MyCompany/MyBundle/Form/Type/MyBundleAdminImageType.php

public function getParent()
{
    return 'file';
}

接下来我有一个模板,扩展了Sonata的默认样式,并将其包含在管理类中:

//MyCompany/MyBundle/Admin/FilmAdmin.php

public function getFormTheme() {
    return array('MyCompanyMyBundle:Form:mycompany_admin_fields.html.twig');
}

最后,我有一个用于扩展基本文件类型的自定义图像类型的代码块:

//MyCompany/MyBundle/Resources/views/Form/mycompany_admin_fields.html.twig

{% block mybundle_admin_image_widget %}
{% spaceless %}
    {% set subject =  form.parent.vars.value %}
    {% if subject.id and attribute(subject, name) %}
        <a href="{{ asset(vich_uploader_asset(subject, name)) }}" target="_blank">
            <img src="{{ asset(vich_uploader_asset(subject, name)) }}" width="200" />
        </a><br/>
    {% endif %}
    {% set type = type|default('file') %}
    <input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock %}

这会导致在上传字段上方显示一个宽度为200像素的图像预览(如果存在),该预览链接到其完整大小版本,在新选项卡中打开。您可以根据需要自定义它,例如添加灯箱插件。


11

您可以通过编辑页面的助手(FormMapper->setHelps)或在FormMapper中传递"help"选项来轻松完成此操作。

protected function configureFormFields(FormMapper $formMapper) {
    $options = array('required' => false);
    if (($subject = $this->getSubject()) && $subject->getPhoto()) {
        $path = $subject->getPhotoWebPath();
        $options['help'] = '<img src="' . $path . '" />';
    }

    $formMapper
        ->add('title')
        ->add('description')
        ->add('createdAt', null, array('data' => new \DateTime()))
        ->add('photoFile', 'file', $options)
    ;
}

这个方法在与 PictureAdmin 类一起使用时非常好,但是有没有想法如何在 PictureAdmin 嵌入到另一个管理类中时让它工作,例如从 PageAdmin::configureFormFields() 中使用 "$formMapper->add('linkedPicture', 'sonata_type_admin')"? - caponica
@caponica 你弄明白怎么做了吗...??我也卡在同样的情况下了.. - GBRocks
是的,我搞定了。我已经有一段时间没有看这段代码了,但基本上你需要检测字段是否嵌入,然后在你的ImageAdmin类中使用类似http://pastebin.com/rvh65viG的东西。 - caponica

9
你可以通过在展示页面上传递$showmapper模板属性轻松完成此操作。
->add('picture', NULL, array(
    'template' => 'MyProjectBundle:Project:mytemplate.html.twig'
);

在您的模板中,您可以获取当前对象并调用get方法以提取图像路径。
<th>{% block name %}{{ admin.trans(field_description.label) }}{% endblock %}</th>
<td>
    <img src="{{ object.getFile }}" title="{{ object.getTitle }}" />
    </br>
    {% block field %}{{ value|nl2br }}{% endblock %}
</td>

要在编辑模式下显示图像,您需要覆盖fileType或在fileType之上创建自己的customType。

还有一些捆绑软件具有此类功能, 请查看GenemuFormBundle


2
这适用于展示页面,但是否有办法按照问题将图像放在字段上方? - Steve

4

Symfony3的解决方案

@kkochanski提供的答案是我目前发现的最干净的方法。这里有一个转移到Symfony3的版本。我还修复了一些错误。

为你的新表单类型创建一个新的模板image.html.twig(完整路径:src/AppBundle/Resources/views/Form/image.html.twig):

{% block image_widget %}
    {% spaceless %}
        {% set type = type|default('file') %}
        <input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
        {% if image_web_path is not empty %}
            <img src="{{ image_web_path }}" alt="image_photo"/>
        {% endif %}
    {% endspaceless %}
{% endblock %}

config.yml中注册新的表单类型模板:

twig:
    form_themes:
        - AppBundle::Form/image.html.twig

创建一个新的表单类型,并将其保存为 ImageType.php(完整路径:src/AppBundle/Form/Type/ImageType.php):
<?php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;

/**
 * Class ImageType
 *
 * @package AppBundle\Form\Type
*/
class ImageType extends AbstractType
{
    /**
     * @return string
     */
    public function getParent()
    {
        return 'file';
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'image';
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'image_web_path' => ''
        ));
    }

    /**
     * @param FormView $view
     * @param FormInterface $form
     * @param array $options
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['image_web_path'] = $options['image_web_path'];
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->setAttribute('image_web_path', $options['image_web_path'])
        ;
    }
}

如果您已经完成了这个步骤,您只需要在实体管理类中导入新的ImageType即可:
use AppBundle\Form\Type\ImageType

最后,在configureFormFields中使用新的表单类型,不需要任何内联HTML或样板代码:

$formMapper
    ->add('imageFile', ImageType::class, ['image_web_path' => $image->getImagePath()])
;

不要使用$image->getImagePath(),而是调用您自己的方法返回图像的URL。

截图

使用Sonata管理创建新的图像实体:

输入图像描述

使用Sonata管理编辑图像实体:

输入图像描述


我在Symfony 3.2中遇到了问题:“无法加载类型“file”” 500内部服务器错误 - InvalidArgumentException位于vendor/symfony/symfony/src/Symfony/Component/Form/FormRegistry.php的第87行 在FormRegistry->getType('file')处 位于vendor/symfony/symfony/src/Symfony/Component/Form/FormRegistry.php的第121行 - Heroes84

2
您可以通过这种方式简单地完成。
    $image = $this->getSubject();
    $imageSmall = '';

    if($image){
        $container = $this->getConfigurationPool()->getContainer();
        $media = $container->get('sonata.media.twig.extension');
        $format = 'small';
        if($webPath = $image->getImageSmall()){
            $imageSmall = '<img src="'.$media->path($image->getImageSmall(), $format).'" class="admin-preview" />';
        }
    }

   $formMapper->add('imageSmall', 'sonata_media_type', array(
      'provider' => 'sonata.media.provider.image',
      'context' => 'default',
      'help' => $imageSmall
   ));

快速,但不太规范。 :D - revengeance

0

有一种简单的方法 - 但是您将在上传按钮下面看到图片。 SonataAdmin允许将原始HTML放入任何给定表单字段的“帮助”选项中。 您可以使用此功能嵌入图像标记:

protected function configureFormFields(FormMapper $formMapper) {

    $object = $this->getSubject();

    $container = $this->getConfigurationPool()->getContainer();

    $fullPath =     $container->get('request')->getBasePath().'/'.$object->getWebPath();


    $formMapper->add('file', 'file', array('help' => is_file($object->getAbsolutePath() . $object->getPlanPath()) ? '<img src="' . $fullPath . $object->getPlanPath() . '" class="admin-preview" />' : 'Picture is not avialable')

}

0

Teo.sk编写了使用VichUploader显示图像的方法。我发现一种选项可以让您在没有此bundle的情况下显示图像。

首先,我们需要创建自己的form_type。这里有一个教程:symfony_tutorial

在主要的Admin类中:

namespace Your\Bundle;

//.....//

class ApplicationsAdmin extends Admin {

//...//

public function getFormTheme() {
    return array_merge(
        parent::getFormTheme(),
        array('YourBundle:Form:image_type.html.twig') //your path to form_type template
    );

protected function configureFormFields(FormMapper $formMapper)
{
     $formMapper->add('file_photo', 'image', array(
            'data_class' => 'Symfony\Component\HttpFoundation\File\File',
            'label' => 'Photo',
            'image_web_path' => $this->getRequest()->getBasePath().'/'.$subject->getWebPathPhoto()// it's a my name of common getWebPath method
        ))
        //....//
        ;
}

}

下一部分是来自ImageType类的代码。

namespace Your\Bundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;


class ImageType extends AbstractType
{

    public function getParent()
    {
        return 'file';
    }

    public function getName()
    {
        return 'image';
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'image_web_path'         => ''
        ));
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['image_web_path'] = $options['image_web_path'];
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
             ->setAttribute('image_web_path', $options['image_web_path'])
        ;
    }
}

关于 image_type Twig 模板的结束时间。

{% block image_widget %}
{% spaceless %}
    {% set type = type|default('file') %}
    <input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
    <img src="{{ image_web_path }}" alt="image_photo"/>
{% endspaceless %}
{% endblock %}

对我来说它是有效的!我也使用雪崩捆绑包来调整图像大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接