Partage
  • Partager sur Facebook
  • Partager sur Twitter

Upload image symfony

Sujet résolu
17 septembre 2019 à 15:30:44

Bonjour,

J'ai commencer depuis quelques jours un système d'upload d'images avec symfony 4, sans utilisé de Bundles, j'ai réussi a insérer en BDD l'image choisi via le bouton d'upload, je l'insère également dans le dossier public/avatar, la relation entre mes tables est bonnes, je met quelques screens au passage.

L'entity User:

<?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;

/**
 *
 * User

 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 * @UniqueEntity(fields= {"email"}, message= "L'email est déjà utilisé")
 * @UniqueEntity(fields= {"username"}, message= "Le nom d'utilisateur est déjà utilisé")
 */
class User implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     * @Assert\Regex(
     *     pattern="/^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/",
     *     message="L'email n'est pas valide")
     */
    private $email;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     */
    private $username;


    /**
     * @ORM\Column(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     * @Assert\Length(min="8", minMessage="Votre mot de passe doit contenir minimum 8 caractères")
     */
    private $password;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    public $created_at;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    public $visited_at;


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

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

    public function getUsername(): ?string
    {
        return $this->username;
    }


    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->created_at;
    }

    public function getVisitedAt(): ?\DateTimeInterface
    {
        return $this->visited_at;
    }

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

        return $this;
    }

    public function setUsername(string $username): self
    {
        $this->username = $username;

        return $this;
    }


    public function setCreatedAt(\DateTimeInterface $created_at): self
    {
        $this->created_at = $created_at;

        return $this;
    }

    public function setVisitedAt(\DateTimeInterface $visited_at): self
    {
        $this->visited_at = $visited_at;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string) $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getSalt()
    {
        // not needed when using the "bcrypt" algorithm in security.yaml
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

}

L'entity Profil :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\File\File;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ProfilRepository")
 */
class Profil
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\OneToOne(targetEntity="Image", cascade={"persist", "remove"})
     */
    private $image;

    /**
     * @ORM\OneToOne(targetEntity="User", cascade={"persist", "remove"})
     */
    private $user;


    public function getUser()
    {
        return $this->user;
    }

    public function setUser($user): void
    {
        $this->user = $user;
    }

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


    public function getImage(): ?Image
    {
        return $this->image;
    }


    public function setImage($image): void
    {
        $this->image = $image;
    }

}


L'entity Image :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ImageRepository")
 */
class Image
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $name;

    private $file;

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

    public function getName(): ?string
    {
        return $this->name;
    }

    public function getFile()
    {
        return $this->file;
    }

    public function setFile(UploadedFile $file): void
    {
        $this->file = $file;
    }

    public function setName(?string $name): self
    {
        $this->name = $name;

        return $this;
    }
}

Le formulaire est gérer via les forms de symfony, je ne trouve donc pas utile de les montrer sachant que tous fonctionne de ce côté la.

Côté BDD, j'ai ceci :

La table Profil:

La table Image : 


La relation de toutes mes tables :


Mes tables sont en relation OneToOne (Elle fonctionne bien)

Le problème est au niveau de la vue,

voici son contenu:

{% extends 'base.html.twig' %}

{% block title %}Profil de {{ user.username }}  {% endblock %}

{% block stylesheets %}
    <link rel="stylesheet" href="{{ asset('assets/css/profile.css') }}">
{% endblock %}

{% block body %}
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="info-pseudo text-center">

                    <img src="{{ asset('assets/avatar/')~profil.image.name }}" class="img z-depth-1 rounded-circle">
                    <div class="pseudo">
                        <h3 class="text-center">{{ user.username }}</h3>
                        {{ form_start(form) }}
                            {{ form_row(form.image) }}
                            <button type="submit" class="btn col-md-5 btn-primary hvr-effect">Envoyez</button>
                        {{ form_end(form) }}

                    </div>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

Et mon controller :

<?php

namespace App\Controller;

use App\Form\ProfilType;
use App\Entity\Profil;
use App\Entity\Image;
use App\Form\ImageType;
use App\Repository\ProfilRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use App\Entity\User;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpFoundation\Session\Session;

class ProfilController extends AbstractController
{
    /**
     * @Route("/profil/{username}", name="app_profil")
     */
    public function index(User $user, Request $request, ObjectManager $manager, Profil $profil, ProfilRepository $profilRepo)
    {
        // Afiche les infos utilisateur
        $user = $this->getDoctrine()
            ->getRepository(User::class)
            ->find($user->getId());

        $connectedUser = $this->getUser();
        

        $profil = new profil;

        $form = $this->createForm(ProfilType::class);
        $form->handleRequest($request);

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

            $profil = $form->getData();
            $image = $profil->getImage();

            $file =  $image->getFile();

            $name = md5(uniqid()).'.'.$file->guessExtension();
            $file->move('assets/avatar', $name);
            $image->setName($name);
            $profil->setUser($connectedUser);


            $manager->persist($profil);
            $manager->flush();


        }

        return $this->render('profil/index.html.twig', [
            'form' => $form->createView(), 'profil' => $profil, 'user' => $user, 'connectedUser' => $connectedUser
        ]);
    }


}



Maintenant que j'ai mis les fichiers pour que vous comprenez mieux le problème, le voici, dans ma vue, je fait 

<img src="{{ asset('assets/avatar/')~profil.image.name }}" class="img z-depth-1 rounded-circle">

Pour afficher l'image que l'utilisateur à choisi pour son avatar, et voici l'erreur obtenue: 

Impossible to access an attribute ("name") on a null variable.

 Avez vous des solutions ? 

merci à vous d'avoir pris le temps d'avoir lu ce long post.

  • Partager sur Facebook
  • Partager sur Twitter
30 avril 2020 à 12:43:27

Essayer plutot ceci .......<img src="assets/avatar/{{profil.image.name}}" style= "width:350px; height:500px" class="img z-depth-1 rounded-circle" />
  • Partager sur Facebook
  • Partager sur Twitter
30 avril 2020 à 15:23:44

@nikowest Bonjour, merci de ne pas déterrer d'ancien sujet résolu.

Déterrage

Citation des règles générales du forum :

Avant de poster un message, vérifiez la date du sujet dans lequel vous comptiez intervenir.

Si le dernier message sur le sujet date de plus de deux mois, mieux vaut ne pas répondre.
En effet, le déterrage d'un sujet nuit au bon fonctionnement du forum, et l'informatique pouvant grandement changer en quelques mois il n'est donc que rarement pertinent de déterrer un vieux sujet.

Au lieu de déterrer un sujet il est préférable :

  • soit de contacter directement le membre voulu par messagerie privée en cliquant sur son pseudonyme pour accéder à sa page profil, puis sur le lien "Ecrire un message"
  • soit de créer un nouveau sujet décrivant votre propre contexte
  • ne pas répondre à un déterrage et le signaler à la modération

Je ferme ce sujet. En cas de désaccord, me contacter par MP.

  • Partager sur Facebook
  • Partager sur Twitter