4

I have a problem with VichUploaderBundle, I followed all the instructions and I could make it upload an image, now I don't know how to render the images using twig. I have a Product entity which has a OneToOne relation with Photo (I use entity photo with VichUploaderBundle).

My html.twig file

{% for product in products %}

 <img src="{{ vich_uploader_asset(product, 'image')   }}" alt="{{ product.nombre }}" />
{% endfor %}

This gives me the following error,

 An exception has been thrown during the rendering of a template ("Impossible to determine the class name. Either specify it explicitly or give an object") in products/list_all_products.html.twig at line 9.

So I added to the img tag the following

  <img src="{{ vich_uploader_asset(product, 'image','AppBundle\Entity\Product') }}" alt="{{ product.nombre }}" />

and throws me this error

An exception has been thrown during the rendering of a template ("Class AppBundleEntityProduct does not exist") in products/list_all_products.html.twig at line 9.

My entities are stored in AppBundle\Entity\ * and also it removes the slashes.

I also tried to add this with no success.

<img src="{{ vich_uploader_asset(product.photo, 'image','AppBundle\Entity\Product') }}" alt="{{ product.nombre }}" />

My Photo entity (It's a copy & paste from the instructions of the bundle)

<?php 
 //src/AppBundle/Entity/Photo.php

 namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collection\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

 /**
  * @ORM\Entity
  * @ORM\Table(name="photo")
  * @Vich\Uploadable
  */

/*
This class represents the images 
*/


 class Photo 
 {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

/**
* @Vich\UploadableField(mapping="product_image", fileNameProperty="imageName") 
* 
* @var File $imageFile
*/
protected $imageFile;

/**
 * @ORM\Column(type="string", length=255, name="image_name")
 *
 * @var string $imageName
 */
protected $imageName;

/**
 * @ORM\Column(type="datetime")
 *
 * @var \DateTime $updatedAt
 */
protected $updatedAt;

/**
 * If manually uploading a file (i.e. not using Symfony Form) ensure an instance
 * of 'UploadedFile' is injected into this setter to trigger the  update. If this
 * bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
 * must be able to accept an instance of 'File' as the bundle will inject one here
 * during Doctrine hydration.
 *
 * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
 */
public function setImageFile(File $image = null)
{
    $this->imageFile = $image;

    if ($image) {
        // It is required that at least one field changes if you are using doctrine
        // otherwise the event listeners won't be called and the file is lost
        $this->updatedAt = new \DateTime('now');
    }
}

/**
 * @return File
 */
public function getImageFile()
{
    return $this->imageFile;
}

/**
 * @param string $imageName
 */
public function setImageName($imageName)
{
    $this->imageName = $imageName;
}

/**
 * @return string
 */
public function getImageName()
{
    return $this->imageName;
}
}

And here's my Product entity

<?php
 //src/AppBundle/Entity/Product.php

 /*
  This class represents a product, for instance, we'll be using
  only product.
 */

 namespace AppBundle\Entity;

 use Doctrine\ORM\Mapping as ORM;
 use Doctrine\Common\Collections\ArrayCollection;

/**
  * @ORM\Entity
  * @ORM\Table(name="product")
* ORM\Entity(repositoryClass="AppBundle\Repositories\ProductRepository")
*/

 //extends objComercio has been removed for simplicity.
class Product
{

public function __construct()
{

    $this->photos = new ArrayCollection();
}

/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @ORM\Column(type="string",length=255, nullable=false)
*/
protected $nombre;

/**
* @ORM\Column(type="string",length=255, nullable=false)
*/
protected $descripcion;

/**
* @ORM\Column(type="integer",nullable=false)
*/
protected $precio;

/**
* @ORM\Column(type="string",length=255, nullable=false)
*/
protected $empresa;

/**
* @ORM\OneToOne(targetEntity="Photo", cascade={"persist"})
*/
protected $photo; 

/**
* @ORM\ManyToOne(targetEntity="Store",inversedBy="products")
*/
protected $store_product;


public function getPhoto()
{
    return $this->photo;
}
public function setPhoto(\AppBundle\Entity\Photo $photo)
{
    $this->photo = $photo;
}
public function getPrecio()
{
    return $this->precio;
}
public function setPrecio($aPrice)
{
    $this->precio = $aPrice;
}
public function getEmpresa()
{
    return $this->empresa;
}
public function setEmpresa($anEnterprise)
{
    $this->empresa = $anEnterprise;
}




/**
 * Set store_product
 *
 * @param \AppBundle\Entity\Store $storeProduct
 * @return Product
 */
public function setStoreProduct(\AppBundle\Entity\Store $storeProduct = null)
{
    $this->store_product = $storeProduct;

    return $this;
}

/**
 * Get store_product
 *
 * @return \AppBundle\Entity\Store 
 */
public function getStoreProduct()
{
    return $this->store_product;
}

/**
 * Get id
 *
 * @return integer 
 */
public function getId()
{
    return $this->id;
}

/**
 * Set nombre
 *
 * @param string $nombre
 * @return Product
 */
public function setNombre($nombre)
{
    $this->nombre = $nombre;

    return $this;
}

/**
 * Get nombre
 *
 * @return string 
 */
public function getNombre()
{
    return $this->nombre;
}

/**
 * Set descripcion
 *
 * @param string $descripcion
 * @return Product
 */
public function setDescripcion($descripcion)
{
    $this->descripcion = $descripcion;

    return $this;
}

/**
 * Get descripcion
 *
 * @return string 
 */
public function getDescripcion()
{
    return $this->descripcion;
}
}

I printed everything using {{}}, and it's all working fine.

I don't what else to do.

Thanks in advance!

Mauro Alvarez
  • 550
  • 6
  • 27

5 Answers5

2

I know this is really old, but for Google is still pretty relevant. I think this should work:

  • put 'imageFile' instead of 'image';
  • double the slashes for the className;

    {{ vich_uploader_asset(product, 'imageFile', 'AppBundle\\Entity\\Product') }}

StefanNch
  • 2,569
  • 24
  • 31
2

This is an old question but this confused me as well as someone new to Symfony, Doctrine and VichUploaderBundle, and this question is most relevant in Google. A common Twig error if you get this all wrong is Mapping not found for field which I'm including for Google reasons!

Doctrine returns an array of Product objects, with one Photo object as a subobject of each Product. It's this Photo subobject that vich_uploader_asset needs to render an image. So use dot to access the photo subobject of each product object: product.photo, not just product

The second paramter of vich_uploader_asset is the field name used in your Photo entity where you added the UploadableField annotation/configuration. In your example above, that's imageFile, not image. In the vich_uploader_asset documentation, image is the field name, so that's probably where you just copied that code from.

And the 3rd parameter to vich_uploader_asset is to specify the class name of the uploadable entity, which again, is not Product but Photo. But you actually don't need it as vich will figure it out as long as you specify product.photo. But if you DID need it, you need to include 2 backslashes as @StefanNch points out.

So here's the line you need:

<img src="{{ vich_uploader_asset(product.photo, 'imageFile') }}" alt="{{ product.nombre }}" />
georgiecasey
  • 21,793
  • 11
  • 65
  • 74
0

I think you have to display your photo depending of your photo entity config:

<img src="{{ vich_uploader_asset(product.photo, 'image') }}" alt="{{ product.nombre }}" />

or

<img src="{{ vich_uploader_asset(product.photo, 'file') }}" alt="{{ product.nombre }}" />
Smashou
  • 378
  • 1
  • 12
0

I finally managed to make it work. I've written some angularjs code (I'm also using that on my site). Here's what I've done

My main.js

 $http.get('/get-products-by-user').success(function(data){
    $scope.products = data;
})

routing.yml

get_products_by_user:
  path: /get-products-by-user
  defaults: { _controller: AppBundle:Product:getAllProductsByUser}

productController:getAllProductsByUser

 public function getAllProductsByUserAction()
{
    $products = $this->getDoctrine()
        ->getRepository('AppBundle:Product')
        ->findAllProductsByUser($this->getUser()->getId());

    return new Response(json_encode($products),200);
}

My list-all-products.html.twig line where I render the image

<div ng-repeat="product in products | filter: query" >
   <img ng-src="/images/products/{[{product.photo.imageName }]}" class="img-responsive img-thumbnail size-img" alt="{[{ product.nombre }]}"/></div>

My config.yml, vich uploader section

 mappings:
    product_image:
        uri_prefix: /images/products
        upload_destination: %kernel.root_dir%/../web/images/products

I don't know if this is a good way of using the bundle (It just works), I'm just using vichUploader for uploading the image, then I do a query in order to get all my products including the file name, Once I got that I use the uri_prefix/{[{product.imageName}]} to render the image.

({[{}]}, I'm using both angularjs and twig template engine, that's why I use that syntax )

Mauro Alvarez
  • 550
  • 6
  • 27
0

try this where date is your object

<img src="{{ path ~ vich_uploader_asset(data, 'imageFile', 'App\\Entity\\Crente') }}" style="margin-top: -20px" />
Sam
  • 51
  • 1
  • 4