Symfony4/Twig/AbstractTypeExtension:无法覆盖文件小部件以显示存储在实体和数据库中的图片

Symfony4/Twig/AbstractTypeExtension:无法覆盖文件小部件以显示存储在实体和数据库中的图片,symfony,twig,containers,symfony-forms,symfony4,Symfony,Twig,Containers,Symfony Forms,Symfony4,我有一个存储在mysql数据库中的“member”实体,里面有一个配置文件图片(不是图像的路径) 当我在“索引”操作和“显示”操作中显示图片时,它会工作,但当我要编辑它时,我希望显示存储的当前图片,就像对其他实体数据所做的那样 我遵循了Symfony docs中的howto:但它不起作用 还尝试了此解决方案: 我包括以下代码: src/Entity/Member.php <?php namespace App\Entity; use Doctrine\Common\Collection

我有一个存储在mysql数据库中的“member”实体,里面有一个配置文件图片(不是图像的路径)

当我在“索引”操作和“显示”操作中显示图片时,它会工作,但当我要编辑它时,我希望显示存储的当前图片,就像对其他实体数据所做的那样

我遵循了Symfony docs中的howto:但它不起作用

还尝试了此解决方案:

我包括以下代码:

src/Entity/Member.php

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * Member
 *
 * @ORM\Table(name="members", uniqueConstraints={@ORM\UniqueConstraint(name="ix_first_name_last_name", columns={"first_name","last_name"})})
 * @ORM\Entity(repositoryClass="App\Repository\MemberRepository")
 * @UniqueEntity(fields="email", message="Email already taken")
 * @UniqueEntity(fields="username", message="Username already taken")
 * @ORM\HasLifecycleCallbacks()
 */
class Member implements UserInterface, \Serializable
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $firstName;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $lastName;

    /**
     * @ORM\Column(type="blob", nullable=true)
     */
    private $pictureProfile;

    /**
     * @ORM\Column(type="string", length=255, unique=true)
     * @Assert\NotBlank()
     * @Assert\Email()
     */
    private $email;


    public function getId()
    {
        return $this->id;
    }

    public function getFirstName(): ?string
    {
        return $this->firstName;
    }

    public function setFirstName(string $firstName): self
    {
        $this->firstName = $firstName;

        return $this;
    }

    public function getLastName(): ?string
    {
        return $this->lastName;
    }

    public function setLastName(string $lastName): self
    {
        $this->lastName = $lastName;

        return $this;
    }

    public function getPictureProfile()
    {
        if ($this->pictureProfile != null) {
            $image = base64_encode(stream_get_contents($this->pictureProfile));
        } else {
            $image = null;
        }
        return $image;
    }

    public function setPictureProfile($pictureProfile): self
    {
        $this->pictureProfile = $pictureProfile;

        return $this;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(?string $email): self
    {
        $this->email = $email;

        return $this;
    }

}
<?php

namespace App\Controller;

use App\Entity\Member;
use App\Form\MemberType;
use App\Repository\MemberRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * @Route("/member")
 */
class MemberController extends Controller
{

    /**
     * @Route("/", name="member_index", methods="GET")
     */
    public function index(MemberRepository $memberRepository): Response
    {
        return $this->render('member/index.html.twig', ['members' => $memberRepository->findAll()]);
    }

    /**
     * @Route("/new", name="member_new", methods="GET|POST")
     */
    public function new(Request $request, UserPasswordEncoderInterface $passwordEncoder): Response
    {
        $member = new Member();
        $form = $this->createForm(MemberType::class, $member);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {

            if ($_FILES['member']['size']['pictureProfile'] > 0) {
                $image = fread(fopen($_FILES['member']['tmp_name']['pictureProfile'], 'r'), filesize($_FILES['member']['tmp_name']['pictureProfile']));
                $member->setPictureProfile($image);
            }

            $em = $this->getDoctrine()->getManager();
            $em->persist($member);
            $em->flush();

            return $this->redirectToRoute('member_index');
        }

        return $this->render('member/new.html.twig', [
            'member' => $member,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="member_show", methods="GET")
     */
    public function show(Member $member): Response
    {
        return $this->render('member/show.html.twig', ['member' => $member]);
    }

    /**
     * @Route("/{id}/edit", name="member_edit", methods="GET|POST")
     */
    public function edit(Request $request, Member $member, UserPasswordEncoderInterface $passwordEncoder): Response
    {
        $form = $this->createForm(MemberType::class, $member);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            if ($_FILES['member']['size']['pictureProfile'] > 0) {
                $image = fread(fopen($_FILES['member']['tmp_name']['pictureProfile'], 'r'), filesize($_FILES['member']['tmp_name']['pictureProfile']));

                $member->setPictureProfile($image);
            }

            $this->getDoctrine()->getManager()->flush();

            return $this->redirectToRoute('member_index');
        }

        return $this->render('member/edit.html.twig', [
            'member' => $member,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="member_delete", methods="DELETE")
     */
    public function delete(Request $request, Member $member): Response
    {
        if ($this->isCsrfTokenValid('delete' . $member->getId(), $request->request->get('_token'))) {
            $em = $this->getDoctrine()->getManager();
            $em->remove($member);
            $em->flush();
        }

        return $this->redirectToRoute('member_index');
    }
}
<?php

namespace App\Form;
use App\Entity\Member;
use App\Entity\ResearchProject;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class MemberType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('firstName', TextType::class, array('attr' => array('class' => 'form-control')))
            ->add('lastName', TextType::class, array('attr' => array('class' => 'form-control')))
            ->add('pictureProfile', FileType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'pictureProfile'))
            ->add('email', EmailType::class, array('attr' => array('class' => 'form-control')))
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Member::class,
        ]);
    }
}
<?php

namespace App\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;

class ImageTypeExtension extends AbstractTypeExtension
{
    public function getExtendedType()
    {
        return FileType::class;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
// makes it legal for FileType fields to have an image_property option
        $resolver->setDefined(array('image_property'));
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        if (isset($options['image_property'])) {
// this will be whatever class/entity is bound to your form (e.g. Media)
            $parentData = $form->getParent()->getData();

            $imageData = null;
            if (null !== $parentData) {
                $accessor = PropertyAccess::createPropertyAccessor();
                $imageData = $accessor->getValue($parentData, $options['image_property']);
            }
            else{
                $imageData = "Didn't load anything";
            }

// sets an "image_data" variable that will be available when rendering this field
            $view->vars['image_data'] = $imageData;
        }
    }

}
在所有这些代码之后,我知道问题的关键在于
MemberType.php
,因为这行代码:

->add('pictureProfile', FileType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'pictureProfile'))
我得到这个呈现的html(请注意
src
属性):

我得到(再次注意
src
property):


图片简介
所以数据被接收到了! 为什么它不接收图像?? 我已经在那行中直接尝试了
getPictureProfile
方法,但没有成功


非常感谢。

没有进行任何测试,看起来您使用了错误的类型扩展

您已经麻烦地创建了一个扩展
FileType
ImageTypeExtension
,但是您仍然在表单配置中使用
FileType

->add('pictureProfile', FileType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'firstName'))
这不应该是这样的吗

->add('pictureProfile', ImageType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'firstName'))

很抱歉,但根据这个说法:那是不对的。或者这就是我所理解的。另一方面,我尝试了你的建议,但没有成功;我得到
无法加载类型“App\Form\ImageType”:类不存在。
错误。或者,如果我将
文件类型
更改为
ImageTypeExtension
,我得到
无法加载类型“App\Form\Extension\ImageTypeExtension”:类未实现“Symfony\Component\Form\FormTypeInterface”
错误。无论如何,谢谢。@PepeAlvarez我的错误,没有意识到您使用扩展类型来覆盖而不是扩展。否则,我不确定bar是否会将其创建为一个新类型,而不是覆盖现有的
文件类型
{% extends 'base.html.twig' %}

{% block title %}Member index{% endblock %}

{% block body %}
    <h1>Member index</h1>

    <table class="table table-hover">
        <thead>
            <tr>
                <!-- <th scope="col">Id</th> -->
                <th scope="col">First Name</th>
                <th scope="col">Last Name</th>
                <th scope="col">Picture Profile</th>
                <th>Email</th>
                <th scope="col">Actions</th>
            </tr>
        </thead>
        <tbody>
        {% for key, member in members %}
            <tr>
                <td>{{ member.firstName }}</td>
                <td>{{ member.lastName }}</td>
                <td><img height="80" alt="No Image" src="data:image/png;base64,{{ member.pictureProfile }}" class="img img-responsive img-preview thumbnail"/></td>
                <td>{{ member.email }}</td>
                <td>
                    <a href="{{ path('member_show', {'id': member.id}) }}">show</a>
                    <a href="{{ path('member_edit', {'id': member.id}) }}">edit</a>
                </td>
            </tr>
        {% else %}
            <tr>
                <td colspan="29">no records found</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

    <a href="{{ path('member_new') }}">Create new</a>
{% endblock %}
services:
    # ...

    App\Form\Extension\ImageTypeExtension:
        tags:
            - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FileType }
->add('pictureProfile', FileType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'pictureProfile'))
<div>
<label for="member_pictureProfile" class="required">Picture profile</label>
<input id="member_pictureProfile" name="member[pictureProfile]" required="required" class="form-control" type="file">
<img alt="No Image" src="data:image/png;base64," class="img img-responsive img-preview thumbnail" height="80">
</div>
->add('pictureProfile', FileType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'firstName'))
<div>
<label for="member_pictureProfile" class="required">Picture profile</label>
<input id="member_pictureProfile" name="member[pictureProfile]" required="required" class="form-control" type="file">
<img alt="No Image" src="data:image/png;base64,John" class="img img-responsive img-preview thumbnail" height="80">
</div>
->add('pictureProfile', FileType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'firstName'))
->add('pictureProfile', ImageType::class, array(
                'data_class' => null,
                'attr' => array('class' => 'form-control'),
                'image_property' => 'firstName'))