已解决 Symfony 6 / PropertyAccessor 需要对对象或数组进行操作,但在尝试遍历路径时发现类型“NULL”

问题描述 投票:0回答:1

我需要一些帮助,我一个月来就面临这个问题并尝试解决它(已经在很多论坛上搜索过,但没有任何效果)。 这里是my error screen

PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "NULL" while trying to traverse path "animal.nom" at property "nom".

我使用 Vich Uploader 和目录命名器,它似乎没有获取我的实体的值来获取路径。 仅当我删除实体的图像时才会出现该错误,但上传时没有问题。

这是我的EntityImage的实体文件(名为:AnimalImage)


namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use App\Repository\AnimalImageRepository;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

#[ORM\Entity(repositoryClass: AnimalImageRepository::class)]
#[Vich\Uploadable]
class AnimalImage
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(inversedBy: 'animalImages', cascade: ['persist'])]
    #[ORM\JoinColumn(nullable: false)]
    private ?Animal $animal = null;

    /**
    * NOTE: This is not a mapped field of entity metadata, just a simple property.
    */
    #[Vich\UploadableField(mapping: 'animal', fileNameProperty: 'imageName', size: 'imageSize')]
    private ?File $imageFile = null;

    #[ORM\Column(length: 500)]
    private ?string $imageName = null;

    #[ORM\Column(length: 500)]
    private ?string $imageSize = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $updatedAt = null;
    
    public function getId(): ?int
    {
        return $this->id;
    }

    public function getAnimal(): ?Animal
    {
        return $this->animal;
    }

    public function setAnimal(?Animal $animal): self
    {
        $this->animal = $animal;

        return $this;
    }

    public function getImageName(): ?string
    {
        return $this->imageName;
    }

    public function setImageName(string $imageName): self
    {
        $this->imageName = $imageName;

        return $this;
    }

    public function getImageSize(): ?int
    {
        return $this->imageSize;
    }

    public function setImageSize(int $imageSize): self
    {
        $this->imageSize = $imageSize;

        return $this;
    }

    public function getUpdatedAt(): ?\DateTimeImmutable
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(\DateTimeImmutable $updatedAt): self
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get the value of imageFile
     */ 
    public function getImageFile(): ?File
    {
        return $this->imageFile;
    }


    /**
     * Set the value of imageFile
     *
     * @return  self
     */ 
    public function setImageFile(?File $imageFile = null): void
    {
        $this->imageFile = $imageFile;

        if(null !== $imageFile){
            $this->updatedAt = new \DateTimeImmutable();
        }
    }
}

这是我的动物实体的表单类型


namespace App\Form;

use App\Entity\Race;
use App\Entity\Tags;
use App\Entity\Animal;
use App\Entity\Espece;
use App\Form\AnimalImageType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\AbstractType;
use Doctrine\ORM\EntityRepository;
use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\ChoiceList\ChoiceList;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;

class AnimalType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('nom', TextType::class, [
                "label"=>"Nom : ",
                "required"=>true
            ])
            ->add('genre', ChoiceType::class, [
                "choices"=> [
                    'Femelle'=>'Femelle',
                    'Mâle'=>'Male',
                ],
                "label"=>"Genre : ",
                "required"=>true,
                "expanded"=>true,
            ])
            ->add('entente_chien', ChoiceType::class, [
                "choices"=> [
                    'Oui'=>'1',
                    'Non'=>'0',
                    "N/A"=>"2",
                ],
                "label"=>"Entente avec les chiens : ",
                "required"=>true,
                // "expanded"=>true,
            ])
            ->add('entente_chat',  ChoiceType::class, [
                "choices"=> [
                    'Oui'=>'1',
                    'Non'=>'0',
                    "N/A"=>"2",
                ],
                "label"=>"Entente avec les chats : ",
                "required"=>true,
                // "expanded"=>true
            ])
            ->add('entente_enfant',  ChoiceType::class, [
                "choices"=> [
                    'Oui'=>'1',
                    'Non'=>'0',
                    "N/A"=>"2",
                ],
                "label"=>"Entente avec les enfants : ",
                "required"=>true,
                // "expanded"=>true
            ])
            ->add('titre', TextareaType::class, [
                "label"=>"Titre : ",
                "required"=>true,
            ])
            ->add('description', CKEditorType::class, [
                "label"=>'Description : ',
                "required"=>true,
            ])
            ->add('Espece', EntityType::class, [
                "class" => Espece::class,
                "label" => "Espèce : ",
                "required" => true,
                "choice_label" => "nom",
                "placeholder"=>"----",
                // "empty_data"=>null,
                // "by_reference" => false
            ])
            ->add('race', EntityType::class,[
                "class"=> Race::class,
                "label"=>"Race : ",
                "required"=>true,
                "choice_label" => 'nom',
                "choice_attr"=>ChoiceList::attr($this, function(?Race $race){
                    return $race ? ['data-espece'=>$race->getEspeceId()] : [];
                }),
                "placeholder"=>"----",
                // "empty_data"=>null,
            ])
            ->add('tags', EntityType::class, [
                'class' => Tags::class,
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('c');
                },
                'label' => 'Caractéristiques :',
                'expanded' => true,
                'multiple' => true,
                'choice_label' => 'caracteristique',
                'by_reference' => false,
                "required"=>true,
                "empty_data"=>null,
            ])
            ->add('age', ChoiceType::class, [
                "label"=>"Âge : ",
                "placeholder"=>"----",
                'choices'=> [...]
                ],
                "required"=>true,

            ])
            ->add('enteredAt', DateType::class, [
                'label'=>'Date d\'entrée : ',
                'widget'=>'choice',
                'input'=>'datetime_immutable',
                'format'=>'dd / MM / yyyy',
                'required'=>true,
            ]);

            // If the animal is not created
            $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
                // Récupère les données du formulaire si l'article est déjà rempli
                $animal = $event->getData();
                // Récupère le formulaire
                $form = $event->getForm();

                // Is the animal already exist
                if(!$animal || null === $animal->getId()){
                    $form->add('animalImages', CollectionType::class, [
                        'entry_type'=>AnimalImageType::class,
                        'allow_add'=>true,
                        'allow_delete'=>true,
                        'delete_empty'=>true,
                        'prototype'=>true,
                        'by_reference'=>false,
                        'mapped'=>false,
                    ]);
                } else {
                    $form->add('animalImages', CollectionType::class, [
                        'entry_type'=>AnimalImageType::class,
                        'allow_add'=>true,
                        'allow_delete'=>true,
                        'delete_empty'=>true,
                        'prototype'=>true,
                        'by_reference'=>false,
                    ]);
                }
            });
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Animal::class,
        ]);
    }

    public function preUpdate(object $animal): void
    {
        $this->animalManager->updateCanonicalFields($animal);
    }
    
}

以及我在 vich_uploader.yaml 上的映射

        animal:
            uri_prefix: /images/animaux
            upload_destination: "%kernel.project_dir%/public/images/animaux"
            directory_namer:
                service: vich_uploader.namer_directory_property
                options: { property: "animal.nom", transliterate: true }
            namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
            inject_on_load: false
            delete_on_update: true
            delete_on_remove: true

最后,我的实体文件(名为:Animal)

<?php

namespace App\Entity;

use App\Entity\AnimalImage;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\AnimalRepository;
use Vich\UploaderBundle\Entity\File;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\Validator\Constraints as Assert;


#[ORM\Entity(repositoryClass: AnimalRepository::class)]
class Animal
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(inversedBy: 'animals')]
    #[ORM\JoinColumn(nullable: false)]
    private ?Espece $espece = null;

    #[ORM\ManyToOne(inversedBy: 'animals')]
    #[ORM\JoinColumn(nullable: false)]
    private ?Race $race = null;

    #[ORM\Column(length: 50)]
    private ?string $nom = null;

    #[ORM\Column(length: 30)]
    private ?string $genre = null;

    #[ORM\Column(nullable: true)]
    private ?int $entente_chien = null;

    #[ORM\Column(nullable: true)]
    private ?int $entente_chat = null;

    #[ORM\Column(nullable: true)]
    private ?int $entente_enfant = null;

    #[ORM\Column(length: 200, nullable: true)]
    #[Assert\Length(
        max: 38,
        maxMessage: 'Le titre ne peut excéder {{limit}} caractères',
    )]
    private ?string $titre = null;

    #[ORM\Column(type: Types::TEXT)]
    private ?string $description = null;

    #[ORM\OneToMany(mappedBy: 'animal', targetEntity: AnimalImage::class, orphanRemoval: true, cascade: ['persist'])]
    private Collection $animalImages;

    #[ORM\Column(length: 100)]
    private ?string $age = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $enteredAt = null;

    #[ORM\ManyToMany(targetEntity: Tags::class, inversedBy: 'animals')]
    private Collection $tags;

    public function __construct()
    {
        $this->animalImages = new ArrayCollection();
        $this->tags = new ArrayCollection();
    }

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

    public function getEspece(): ?Espece
    {
        return $this->espece;
    }

    public function setEspece(?Espece $espece): self
    {
        $this->espece = $espece;

        return $this;
    }

    public function getRace(): ?race
    {
        return $this->race;
    }

    public function setRace(?race $race): self
    {
        $this->race = $race;

        return $this;
    }

    public function getNom(): ?string
    {
        return $this->nom;
    }

    public function setNom(string $nom): self
    {
        $this->nom = $nom;

        return $this;
    }

    public function getGenre(): ?string
    {
        return $this->genre;
    }

    public function setGenre(string $genre): self
    {
        $this->genre = $genre;

        return $this;
    }

    public function getEntenteChien(): ?int
    {
        return $this->entente_chien;
    }

    public function setEntenteChien(?int $entente_chien): self
    {
        $this->entente_chien = $entente_chien;

        return $this;
    }

    public function getEntenteChat(): ?int
    {
        return $this->entente_chat;
    }

    public function setEntenteChat(?int $entente_chat): self
    {
        $this->entente_chat = $entente_chat;

        return $this;
    }

    public function getEntenteEnfant(): ?int
    {
        return $this->entente_enfant;
    }

    public function setEntenteEnfant(?int $entente_enfant): self
    {
        $this->entente_enfant = $entente_enfant;

        return $this;
    }

    public function getTitre(): ?string
    {
        return $this->titre;
    }

    public function setTitre(?string $titre): self
    {
        $this->titre = $titre;

        return $this;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(?string $description): self
    {
        $this->description = $description;

        return $this;
    }

    /**
     * @return Collection<int, AnimalImage>
     */
    public function getAnimalImages(): Collection
    {
        return $this->animalImages;
    }

    /**
     * Set the value of animalImages
     *
     * @return  self
     */ 
    public function setAnimalImages(?File $animalImages = null): void
    {
        $this->animalImages = $animalImages;

        if(null!==$animalImages){
            $this->updatedAt = new \DateTimeImmutable();
        }
    }

    public function addAnimalImage(AnimalImage $animalImage): self
    {
        if (!$this->animalImages->contains($animalImage)) {
            $this->animalImages[] = $animalImage;
            $animalImage->setAnimal($this);
        }

        return $this;
    }

    public function removeAnimalImage(AnimalImage $animalImage): self
    {
        if ($this->animalImages->removeElement($animalImage)) {
            // set the owning side to null (unless already changed)
            if ($animalImage->getAnimal() === $this) {
                $animalImage->setAnimal(null);
            }
        }

        return $this;
    }

    public function getAge(): ?string
    {
        return $this->age;
    }

    public function setAge(string $age): self
    {
        $this->age = $age;

        return $this;
    }

    public function getEnteredAt(): ?\DateTimeImmutable
    {
        return $this->enteredAt;
    }

    public function setEnteredAt(\DateTimeImmutable $enteredAt): self
    {
        $this->enteredAt = $enteredAt;

        return $this;
    }

    /**
     * @return Collection<int, Tags>
     */
    public function getTags(): Collection
    {
        return $this->tags;
    }

    public function addTag(Tags $tag): self
    {
        if (!$this->tags->contains($tag)) {
            $this->tags->add($tag);
        }

        return $this;
    }

    public function removeTag(Tags $tag): self
    {
        $this->tags->removeElement($tag);

        return $this;
    }
}

提前感谢您提供任何解决方案和帮助,在这个项目上工作了 1 个月,并在漫长的日子里解决了这个错误:/

编辑:尝试了很多“解决方案”并评论了一行,现在它可以工作了。 这是我的解决方案

    {
        if ($this->animalImages->removeElement($animalImage)) {
            
            // set the owning side to null (unless already changed)
            if ($animalImage->getAnimal() === $this) {
                
                $fileName = $animalImage->getImageName();
                $filesystem = new Filesystem();
                $filesystem->remove('%kernel.project_dir%/public/images/animaux/'.$this->getNom().'/'. $fileName);

             // COMMENTING THIS LINE MADE THE THING WORKS
                // $animalImage->setAnimal(null);
            }
        }

        return $this;
    }
php symfony doctrine-orm vichuploaderbundle symfony6
1个回答
0
投票

我刚刚遇到了这个问题,问题是需要遍历路径的对象没有在构造函数中初始化

© www.soinside.com 2019 - 2024. All rights reserved.