I have the field "image" in entities. But depends of action I want to show not original image, but image's preview (which I make in LiipImagineBundle). The one solution which I can imagine:
public function cgetAction(Request $request)
{
$events = $this->container->get('gc.event_manager')->getEvents();
foreach ($events as &$event) {
$previewURL = $this->getPreview($event->getPhoto());
$event->setPhoto($previewURL);
}
$event = false;
return array(
'events' => $events,
);
}
But I don't like it, because if an entity has deep children's entities the code will be very confusing.
How to do it correctly?
Common problem when you want to return absolute url through API while using LiipImagine and FOSRest
Change EE\TYSBundle to your own, code taken from https://github.com/EE/TellYourStoryBundle/tree/develop
JMSSerializer Handler Service with injected Cache Manager to get correct prefix
ee_tys.serializer.filename_handler:
class: EE\TYSBundle\Handler\FilenameHandler
arguments:
- "#liip_imagine.cache.manager"
tags:
- { name: 'jms_serializer.handler', type: Filename, format: json}
Handler for custom Filename type
EE\TYSBundle\Handler\FilenameHandler.php
<?php
namespace EE\TYSBundle\Handler;
use EE\TYSBundle\Entity\Filename;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\VisitorInterface;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
class FilenameHandler implements SubscribingHandlerInterface
{
function __construct(CacheManager $manager)
{
$this->manager = $manager;
}
public static function getSubscribingMethods()
{
return array(
array(
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => 'Filename',
'method' => 'serializeFilenameToJson',
),
);
}
public function serializeFilenameToJson(VisitorInterface $visitor, Filename $filename, array $type)
{
// `tile` is a name of Imagine filter you want to apply
return $this->manager->getBrowserPath($filename, 'tile', true);
}
}
EE\TYSBundle\Entity\Filename
<?php
namespace EE\TYSBundle\Entity;
/**
* Class Filename
* #package EE\TYSBundle\Entity
*/
class Filename {
/**
* #var string
*/
public $name;
/**
* #var string
*/
public $extension;
public function __construct($filename)
{
$parts = explode(".", $filename);
$this->setName($parts[0]);
$this->setExtension($parts[1]);
}
/**
* #param mixed $extension
* #return Media
*/
public function setExtension($extension)
{
$this->extension = $extension;
return $this;
}
/**
* #return mixed
*/
public function getExtension()
{
return $this->extension;
}
/**
* #param mixed $name
* #return Filename
*/
public function setName($name)
{
$this->name = $name;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #return string filename
*/
public function __toString()
{
return join(".", array($this->name, $this->extension));
}
}
usage of custom Filename type
/**
* #var string|null
*
* #ORM\Column(name="background_filename", type="string", length=255, nullable=true)
*
* #Serializer\Expose
* #Serializer\Type("Filename")
* #Serializer\SerializedName("background_uri")
*/
private $backgroundFilename;
From now on you will get background_uri with absolute url to your preview Image
One possible solution is to define Handler.
Handlers allow you to change the serialization, or deserialization
process for a single type/format combination.
Something like
class ImageHandler
{
public function serialize(VisitorInterface $visitor, \FQCN\Image $image, array $type, Context $context)
{
// do some stuff
return ...;
}
}
And register it in services.yml
serializer.handler.image_handler:
class: FQCN\Handler\ImageHandler
arguments: []
tags:
- { name: "jms_serializer.handler", type: FQCN\AdvertImage, format: json, method: serialize }
If i understand your question well, you need change value for correct before serialisation, i think manual can help #Accessor
class User
{
private $id;
/** #Accessor(getter="getTrimmedName",setter="setName") */
private $name;
// ...
public function getTrimmedName()
{
return trim($this->name);
}
public function setName($name)
{
$this->name = $name;
}
}
Related
I am actually working on a Symfony 4.4 project, on which I need to be able to update Twig template translations from an admin interface.
This is the first time I try to implement a database based translation system, so I followed this tutorial: https://medium.com/#andrew72ru/store-translation-messages-in-database-in-symfony-3f12e579df74
At this time, I made a simple class which loads a MessageCatalogue from my database:
<?php
namespace App\Service;
use App\Entity\Translation;
use App\Repository\TranslationRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ObjectRepository;
use Symfony\Component\Translation\Loader\LoaderInterface;
use Symfony\Component\Translation\MessageCatalogue;
class DatabaseTranslationManager implements LoaderInterface
{
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $doctrine)
{
$this->entityManager = $doctrine;
}
/**
* #param mixed $resource
* #param string $locale
* #param string $domain
*/
public function load($resource, $locale, $domain = 'messages'): MessageCatalogue
{
$translationRepository = $this->getRepository();
if (false === $translationRepository instanceof TranslationRepository) {
return new MessageCatalogue($locale);
}
$messages = $translationRepository->findByDomainAndLocale($domain, $locale);
$values = array_map(
static function (Translation $entity) {
return $entity->getTranslation();
},
$messages
);
return new MessageCatalogue(
$locale, [
$domain => $values,
]
);
}
/**
* #return ObjectRepository<Translation>
*/
public function getRepository(): ObjectRepository
{
return $this->entityManager->getRepository(Translation::class);
}
}
Which is registered in my services:
translation.loader.db:
class: App\Service\DatabaseTranslationManager
arguments:
- '#doctrine.orm.entity_manager'
tags:
- { name: translation.loader, alias: db }
The associated Translation entity is quite straightforward:
<?php
namespace App\Entity;
use App\Repository\TranslationRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=TranslationRepository::class)
*/
class Translation
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private ?int $id = null;
/**
* #ORM\Column(type="string", length=255)
*/
private string $domain;
/**
* #ORM\Column(type="string", length=2)
*/
private string $locale;
/**
* #ORM\Column(type="string", length=255)
*/
private string $key;
/**
* #ORM\Column(type="text")
*/
private string $translation;
public function __construct(string $domain, string $locale, string $key, string $translation)
{
$this->domain = $domain;
$this->locale = $locale;
$this->key = $key;
$this->translation = $translation;
}
public function getId(): ?int
{
return $this->id;
}
public function getDomain(): string
{
return $this->domain;
}
public function setDomain(string $domain): self
{
$this->domain = $domain;
return $this;
}
public function getLocale(): string
{
return $this->locale;
}
public function setLocale(string $locale): self
{
$this->locale = $locale;
return $this;
}
public function getKey(): string
{
return $this->key;
}
public function setKey(string $key): self
{
$this->key = $key;
return $this;
}
public function getTranslation(): string
{
return $this->translation;
}
public function setTranslation(string $translation): self
{
$this->translation = $translation;
return $this;
}
}
It works quite well at this point, but I'm still facing some issues:
I need to create empty <domain>.<locale>.db files so that the custom translation loader is triggered, which is ok but not ideal
it looks like I need to clear the Symfony cache each time I change a translation in the database. This is an issue as I need translations to be updated anytime by admin users with no access to the console
I will lose all my translations each time I reset the database. The best option for me would be to load my <domain>.<locale>.yaml files as a fallback if a translation does not exist in the database.
As I could not find any better solution at this time, I'm looking for recommendations on how to achieve such a translation system.
I'm currently working with one of my friends on making a portfolio for all of his projects and as strangely as it seems, I cannot manage to make setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Class Namespace') working on his code while it is working on my projects.
Here is the error returned by PHP :
!(https://cdn.discordapp.com/attachments/525023910698156034/583938068311179265/unknown.png)
Here is the class Entity which contains the __construct() function and the hydration() function :
<?php
namespace App\Entity;
class Entity {
public function __construct(array $array) {
$this->hydrate($array);
}
public function hydrate($array) {
foreach ($array as $key => $value) {
$setter = 'set' . ucfirst($key);
if (method_exists($this, $setter)) {
$this->$setter($value);
}
}
}
}
Then, here is the Project Class which implements the class Entity :
<?php
namespace App\Entity;
class Project extends Entity implements \JsonSerializable {
private $_title;
private $_description;
private $_imagePath;
private $_link;
private $_repoLink;
private $_creationDate;
public function jsonSerialize() {
return [
'title' => $this->_title,
'description' => $this->_description,
'imagePath' => $this->_imagePath,
'link' => $this->_link,
'repoLink' => $this->_repoLink,
'creationDate' => $this->_creationDate,
];
}
/
* #return string
*/
public function getTitle(): string {
return $this->_title;
}
/
* #param string $title
*/
public function setTitle(string $title) {
$this->_title = $title;
}
/
* #return string
*/
public function getDescription(): string {
return $this->_description;
}
/
* #param string $description
*/
public function setDescription(string $description) {
$this->_description = $description;
}
/
* #return string
*/
public function getImagePath(): string {
return $this->_imagePath;
}
/
* #param string $imagePath
*/
public function setImagePath(string $imagePath) {
$this->_imagePath = $imagePath;
}
/
* #return string
*/
public function getLink(): string {
return $this->_link;
}
/
* #param string $link
*/
public function setLink(string $link) {
$this->_link = $link;
}
/
* #return string
*/
public function getRepoLink(): string {
return $this->_repoLink;
}
/
* #param string $repoLink
*/
public function setRepoLink(string $repoLink) {
$this->_repoLink = $repoLink;
}
/
* #return \DateTime
*/
public function getCreationDate(): \DateTime {
return $this->_creationDate;
}
/
* #param string $creationDate
*/
public function setCreationDate(string $creationDate) {
$this->_creationDate = new \DateTime($creationDate);
}
}
And finally, here is the SQL request :
<?php
namespace App\Model;
class ProjectManager extends Manager {
/**
* return a collection of Project objects
* #return Project[]
* #throws \Exception
*/
public function getProjects() {
$db = $this->getDb();
$q = $db->query(
'SELECT id,
title,
description,
image_path AS imagePath,
link,
repo_link AS repoLink,
creation_date AS creationDate
FROM my_website_projects
ORDER BY creationDate'
);
$q->setFetchMode(\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE, 'App\Entity\Project');
$projects = $q->fetchAll();
return $projects;
}
}
The only thing that seems to work is to add PDO::FETCH_ASSOC in the fetchAll() but then it doesn't return an object but an array....
Your help would be much appreciated on this problem ! :)
As far as I know, there is no solution to this problem. There is no fetch mode that creates an object passing the returned row as a constructor parameter.
So I would change the code to this a bit clumsy but working solution
public function getProjects() {
$db = $this->getDb();
$q = $db->query(
'SELECT id,
title,
description,
image_path AS imagePath,
link,
repo_link AS repoLink,
creation_date AS creationDate
FROM my_website_projects
ORDER BY creationDate'
);
$projects = [];
while($row = $q->fetch(PDO::FETCH_ASSOC)) {
$projects[] = new App\Entity\Project($row);
}
return $projects;
}
Your mistake is that you slightly confused the way PDO creates objects.
This way is rather blunt, PDO just takes an object and fills it properties, the process is not much different from filling an associative array.
So now you can tell how did your other code work:
first, the constructor parameter in your other class is optional, it means PHP won't complain for it.
second, in your other class properties are spelled equal to column names in the database, and PDO happily fills them as described above.
So, as another solution you can fix these 2 issues: make the constructor parameter optional and remove the underscore from the property names.
Some time ago I wrote an article on fetching obejects with PDO, you may find it useful.
I'm creating a small API, mostly for learning purposes, but, I might implement it into a project I'm working on. So far, I have installed the zend expressive skeleton application and set up my models and entities. I'm able to query the database and get results, but, when I return the results as a JSON Response, I can only see a list of empty arrays for each result. I would like to be able to return the actual objects that are being returned from the database instead of converting them to arrays.
HomePageHandler.php
<?php
declare(strict_types=1);
namespace App\Handler;
use App\Entity\Product;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Expressive\Router;
use Zend\Expressive\Template\TemplateRendererInterface;
use App\Model\ProductModel;
class HomePageHandler implements RequestHandlerInterface
{
/** #var string */
private $containerName;
/** #var Router\RouterInterface */
private $router;
/** #var null|TemplateRendererInterface */
private $template;
private $productModel;
public function __construct(
string $containerName,
Router\RouterInterface $router,
?TemplateRendererInterface $template = null,
ProductModel $productModel
) {
$this->containerName = $containerName;
$this->router = $router;
$this->template = $template;
$this->productModel = $productModel;
}
public function handle(ServerRequestInterface $request) : ResponseInterface
{
$data = $this->productModel->fetchAllProducts();
return new JsonResponse([$data]);
//return new HtmlResponse($this->template->render('app::home-page', $data));
}
}
I'm expecting a JSON Response returned with a list of 18 "Product" entities. My results look like.
[[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]]
Let me know if there is any other code you would like to see.
Thanks in advance!
Edited with Product.php code
<?php
/**
* Created by PhpStorm.
* User: Brock H. Caldwell
* Date: 3/14/2019
* Time: 4:04 PM
*/
namespace App\Entity;
class Product
{
protected $id;
protected $picture;
protected $shortDescription;
protected $longDescription;
protected $dimensions;
protected $price;
protected $sold;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return mixed
*/
public function getPicture()
{
return $this->picture;
}
/**
* #param mixed $picture
*/
public function setPicture($picture)
{
$this->picture = $picture;
}
/**
* #return mixed
*/
public function getShortDescription()
{
return $this->shortDescription;
}
/**
* #param mixed $shortDescription
*/
public function setShortDescription($shortDescription)
{
$this->shortDescription = $shortDescription;
}
/**
* #return mixed
*/
public function getLongDescription()
{
return $this->longDescription;
}
/**
* #param mixed $longDescription
*/
public function setLongDescription($longDescription)
{
$this->longDescription = $longDescription;
}
/**
* #return mixed
*/
public function getDimensions()
{
return $this->dimensions;
}
/**
* #param mixed $dimensions
*/
public function setDimensions($dimensions)
{
$this->dimensions = $dimensions;
}
/**
* #return mixed
*/
public function getPrice()
{
return $this->price;
}
/**
* #param mixed $price
*/
public function setPrice($price)
{
$this->price = $price;
}
/**
* #return mixed
*/
public function getSold()
{
return $this->sold;
}
/**
* #param mixed $sold
*/
public function setSold($sold)
{
$this->sold = $sold;
}
public function exchangeArray($data)
{
$this->id = (!empty($data['id'])) ? $data['id'] : null;
$this->picture = (!empty($data['picture'])) ? $data['picture'] : null;
$this->shortDescription = (!empty($data['shortDescription'])) ? $data['shortDescription'] : null;
$this->longDescription = (!empty($data['longDescription'])) ? $data['longDescription'] : null;
$this->dimensions = (!empty($data['dimensions'])) ? $data['dimensions'] : null;
$this->price = (!empty($data['price'])) ? $data['price'] : null;
$this->sold = (!empty($data['sold'])) ? $data['sold'] : null;
}
}
You need to either make the properties public, or implement the JsonSerializable interface in your Product entity. All of its properties are protected, which is fine, but that means they aren't exposed when the object is JSON encoded.
Here are some brief examples:
class Example1 { protected $a = 1; }
class Example2 { public $b = 2; }
class Example3 implements JsonSerializable {
protected $c = 3;
public function jsonSerialize() {
return ['c' => $this->c];
}
}
echo json_encode([new Example1, new Example2, new Example3]);
The result:
[{},{"b":2},{"c":3}]
If you choose to implement JsonSerializable, exactly how you do it is up to you, but you just need a jsonSerialize() method that returns the properties you want in the JSON result in a format accessible to json_encode (an object with public properties or an array).
I'm using Sonata Admin bundle and basically, when a user uploads an image for the carousel ( I have an upload widget ) I want the "filename" column of my table to be automatically filled in with the filenames name. So if its, "image_001.jpg" I want the filename column to automatically say "image_001.jpg" once the file has been uploaded. How would I go about achieving this ?
Also if you have any tips of whether theres anything better I could do that would be great! I feel like my table should have a url column as well but I'm not sure as images for the carousel will always be uploaded to the path in the code below.
Here's my YAML file:
Example\CmsBundle\Entity\Carousel:
type: entity
table: carousel
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
filename:
type: string
length: 100
updated:
type: datetime
nullable: true
lifecycleCallbacks:
prePersist: [ lifecycleFileUpload ]
preUpdate: [ lifecycleFileUpload ]
My entity file:
/**
* Carousel
*/
class Carousel
{
const SERVER_PATH_TO_IMAGE_FOLDER = 'bundles/examplecompany/images/carousel';
/**
* #var integer
*/
private $id;
/**
* #var stringß
*/
private $filename;
/**
* #var \DateTime
*/
private $updated;
/**
* Unmapped property to handle file uploads
*/
private $file;
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* Manages the copying of the file to the relevant place on the server
*/
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
// we use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and target filename as params
$this->getFile()->move(
Carousel::SERVER_PATH_TO_IMAGE_FOLDER,
$this->getFile()->getClientOriginalName()
);
// set the path property to the filename where you've saved the file
$this->filename = $this->getFile()->getClientOriginalName();
// clean up the file property as you won't need it anymore
$this->setFile(null);
}
/**
* Lifecycle callback to upload the file to the server
*/
public function lifecycleFileUpload() {
$this->upload();
}
/**
* Updates the hash value to force the preUpdate and postUpdate events to fire
*/
public function refreshUpdated() {
$this->setUpdated(new \DateTime("now"));
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set filename
*
* #param string $filename
* #return Carousel
*/
public function setFilename($filename)
{
$this->filename = $filename;
return $this;
}
/**
* Get filename
*
* #return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* Set updated
*
* #param \DateTime $updated
* #return Carousel
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* #ORM\PrePersist
*/
/*public function lifecycleFileUpload()
{
// Add your code here
}*/
}
EDIT:
Carousel Admin Code:
class CarouselAdmin extends Admin
{
// setup the default sort column and order
protected $datagridValues = array(
'_sort_order' => 'ASC',
'_sort_by' => 'updated_at'
);
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('file', 'file', array('required' => false))
->add('filename')
->add('text_block')
;
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('filename')
->add('updated_at')
;
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('')
->addIdentifier('filename')
->add('text_block')
->add('updated_at')
// add custom action links
->add('_action', 'actions', array(
'actions' => array(
'edit' => array(),
'delete' => array(),
)
))
;
}
protected function configureRoutes(RouteCollection $collection)
{
// remove the "Add New" button
//$collection->remove('create');
}
public function prePersist($image) {
$this->manageFileUpload($image);
}
public function preUpdate($image) {
$this->manageFileUpload($image);
}
private function manageFileUpload($image) {
if ($image->getFile()) {
$image->refreshUpdated();
}
}
}
I'm creating a ticket system for practice purposes.
Right now I'm having a problem with uploading files.
The idea is that a ticket can have multiple attachments, so I created a many-to-one relationship between the ticket and the upload tables.
class Ticket {
// snip
/**
* #ORM\OneToMany(targetEntity="Ticket", mappedBy="ticket")
*/
protected $uploads;
// snip
}
The upload entity class contains the upload functionality, which I took from this tutorial:
<?php
namespace Sytzeandreae\TicketsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* #ORM\Entity(repositoryClass="Sytzeandreae\TicketsBundle\Repository\UploadRepository")
* #ORM\Table(name="upload")
* #ORM\HasLifecycleCallbacks
*/
class Upload
{
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
private $temp;
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Ticket", inversedBy="upload")
* #ORM\JoinColumn(name="ticket_id", referencedColumnName="id")
*/
protected $ticket;
/**
* #ORM\Column(type="string")
*/
protected $title;
/**
* #ORM\Column(type="string")
*/
protected $src;
public function getAbsolutePath()
{
return null === $this->src
? null
: $this->getUploadRootDir().'/'.$this->src;
}
public function getWebPath()
{
return null === $this->src
? null
: $this->getUploadDir().'/'.$this->src;
}
public function getUploadRootDir()
{
// The absolute directory path where uplaoded documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function getUploadDir()
{
// Get rid of the __DIR__ so it doesn/t screw up when displaying uploaded doc/img in the view
return 'uploads/documents';
}
/**
* Sets file
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
if (isset($this->path)) {
// store the old name to delete after the update
$this->temp = $this->path;
$this->path = null;
} else {
$this->path = 'initial';
}
}
/**
* Get file
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set src
*
* #param string $src
*/
public function setSrc($src)
{
$this->src = $src;
}
/**
* Get src
*
* #return string
*/
public function getSrc()
{
return $this->src;
}
/**
* Set ticket
*
* #param Sytzeandreae\TicketsBundle\Entity\Ticket $ticket
*/
public function setTicket(\Sytzeandreae\TicketsBundle\Entity\Ticket $ticket)
{
$this->ticket = $ticket;
}
/**
* Get ticket
*
* #return Sytzeandreae\TicketsBundle\Entity\Ticket
*/
public function getTicket()
{
return $this->ticket;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
// do whatever you want to generate a unique name
$filename = sha1(uniqid(mt_rand(), true));
$this->src = $filename.'.'.$this->getFile()->guessExtension();
}
}
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
// move takes the target directory and then the target filename to move to
$this->getFile()->move(
$this->getUploadRootDir(),
$this->src
);
// check if we have an old image
if (isset($this->temp)) {
// delete the old image
unlink($this->getUploadRootDir().'/'.$this->temp);
// clear the temp image path
$this->temp = null;
}
// clean up the file property as you won't need it anymore
$this->file = null;
}
/**
* #ORM\PostRemove
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
}
The form is build as follows:
class TicketType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('title')
->add('description')
->add('priority')
->add('uploads', new UploadType())
}
Where UploadType looks like this:
class UploadType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options) {
$builder->add('file', 'file', array(
'label' => 'Attachments',
'required' => FALSE,
'attr' => array (
'accept' => 'image/*',
'multiple' => 'multiple'
)
));
}
This part seems to work fine, I do get presented a form which contains a file uploader.
Once I put this line in the Ticket entity's constuctor:
$this->uploads = new \Doctrine\Common\Collections\ArrayCollection();
It throws me the following error:
Neither property "file" nor method "getFile()" nor method "isFile()"
exists in class "Doctrine\Common\Collections\ArrayCollection"
If I leave this line out, and upload a file, it throws me the following error:
"Sytzeandreae\TicketsBundle\Entity\Ticket". Maybe you should create
the method "setUploads()"?
So next thing I did was creating this method, try an upload again and now it throws me:
Class Symfony\Component\HttpFoundation\File\UploadedFile is not a
valid entity or mapped super class.
This is where I am really stuck. I fail to see what, at what stage, I did wrong and am hoping for some help :)
Thanks!
You can either add a collection field-type of UploadType() to your form. Notice that you can't use the multiple option with your current Upload entity ... but it's the quickest solution.
Or adapt your Ticket entity to be able to handle multiple files in an ArrayCollection and looping over them.