Symfony2 Upload / Cannot save to the folder - symfony

Could you help me resolve this issue?
I tried this tutorial: Symfony Upload
It works fine(stored to the database path to img), but don't store or move image to the folder.
Entity:
<?php
namespace DbBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class File
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank
*/
public $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $path;
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
private $temp;
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
// check if we have an old image path
if (isset($this->path)) {
// store the old name to delete after the update
$this->temp = $this->path;
$this->path = null;
} else {
$this->path = 'initial';
}
}
/**
* #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->path = $filename.'.'.$this->getFile()->guessExtension();
}
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->getFile()->move($this->getUploadRootDir(), $this->path);
// 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;
}
$this->file = null;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
$file = $this->getAbsolutePath();
if ($file) {
unlink($file);
}
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/documents';
}
}
Controller:
public function uploadAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$document = new File();
$form = $this->createFormBuilder($document)
->add('name')
->add('file')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$em->persist($document);
$em->flush();
return $this->redirectToRoute('web_portal_file');
}
return $this->render('WebPortalBundle:Default:file.html.twig',array('file_form' => $form->createView()));
}
EDIT: Twig:
<form action="{{ path('web_portal_file') }}" method="post" {{ form_enctype(file_form) }}>
{{ form_widget(file_form.file) }}
{{ form_rest(file_form) }}
<input type="submit"/>
</form>
I don't know what to do to make this work. Every time path is saved to the database, but folder is empty ...

Remember to upload files will be put in the form tag data encryption: PHP method uploads
In Symfony2, with Twig would be:
form class="" action="" method="post" {{ form_enctype(file_form) }}
{{ form_widget(file_form) }}
/form

The problem may be here. On Controller. When you are persisting the entity you call the upload() method
if($form->isValid()) {
$em->persist($document);
$em->flush();
return $this->redirectToRoute('web_portal_file');
}
In CookBook says:
The previous controller will automatically persist the Document entity with the submitted name, but it will do nothing about the file and the path property will be blank.
An easy way to handle the file upload is to move it just before the entity is persisted and then set the path property accordingly. Start by calling a new upload() method on the Document class, which you'll create in a moment to handle the file upload:
Now
if($form->isValid()) {
$document->upload();
$em->persist($document);
$em->flush();
return $this->redirectToRoute('web_portal_file');
}

The following code works:
protected function getUploadRootDir() {
// the absolute directory path where uploaded
// documents should be saved
return __DIR__ . '/../../../web/' . $this->getUploadDir();
}

Related

Symfony The annotation does not exist, or could not be auto-loaded - Symfony Validation with Doctrine

We have a legacy app which is not based on symfony. Doctrine is in use and now we would like to add validation to the models. Seems that the Annotations never get autoloaded, even when "use" statements are in use.
[Semantical Error] The annotation "#Symfony\Component\Validator\Constraints\NotBlank" in property Test\Stackoverflow\User::$Username does not exist, or could not be auto-loaded.
Wrote a small demo application to showcase the problem and how we create the entity manager and validation instance.
composer.json:
{
"require": {
"symfony/validator" : "~3.1"
, "doctrine/orm" : "~2.6.1"
}
}
index.php
require_once ('vendor/autoload.php');
// Load Entities, would normally be done over composer since they reside in a package
require_once('test/User.php');
require_once('MyAnnotationTestApp.php');
// create test app
$app = new MyAnnotationsTestApp();
$app->initEntityManager('localhost', 'annotation_test', 'root', 'mysql', 3306);
if(key_exists('test', $_GET)){
// Create entity and validate it
$entity = new \Test\Stackoverflow\User();
$entity->setUsername('StackoverflowUser');
if($app->testAnnotationWithoutLoading($entity)){
print "Seems the validation was working without preloading the asserts\n<br>";
}
if($app->testAnnotationWithLoading($entity)){
print "Seems the validation was working because we loaded the required class ourself.\n<br>";
}
print "\n<br><br>The question is why the required annotation classes never get autoloaded?";
}else{
// Load the validator class otherwise the annotation throws an exception
$notBlankValidator = new \Symfony\Component\Validator\Constraints\NotBlank();
print "We have cerated the tables but also had to load the validator class ourself.\n<br>\n<br>";
// create tables and
$app->updateDatabaseSchema();
print sprintf('Now lets run the test', $_SERVER['REQUEST_URI']);
}
Doctrine user Entity
<?php
namespace Test\Stackoverflow;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity()
* #ORM\Table(name="users")
*
*/
class User{
/**
* #ORM\Id
* #ORM\Column(name="Id",type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $Id;
public function getId(){
return $this->Id;
}
/**
* #ORM\Column(type="text", length=80, nullable=false)
* #Assert\NotBlank()
*/
protected $Username;
/**
* #return string
*/
public function getUsername()
{
return $this->Username;
}
/**
* #param string $Username
*/
public function setUsername($Username)
{
$this->Username = $Username;
}
}
Demo App with doctrine/validator initialisation:
<?php
final class MyAnnotationsTestApp {
/**
* #var \Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* #param string $host
* #param string $database
* #param string $username
* #param string $password
* #param integer $port
* #param array $options
* #return \Doctrine\ORM\EntityManager
*/
public function initEntityManager($host, $database, $username, $password, $port, array $options=null){
if($this->entityManager){
return $this->entityManager;
}
$connectionString = sprintf('mysql://%3$s:%4$s#%1$s/%2$s', $host, $database, $username, $password, $port);
$isDevMode = true;
$dbParams = array(
'url' => $connectionString
, 'driver' => 'pdo_mysql'
, 'driverOptions' => array(
1002 => "SET NAMES utf8mb4"
)
);
$cacheDriver = null;
$config = \Doctrine\ORM\Tools\Setup::createAnnotationMetadataConfiguration(array(), $isDevMode, '.cache/', $cacheDriver, false);
if($cacheDriver){
$config->setMetadataCacheImpl($cacheDriver);
$config->setQueryCacheImpl($cacheDriver);
$config->setResultCacheImpl($cacheDriver);
}
$this->entityManager = \Doctrine\ORM\EntityManager::create($dbParams, $config);
return $this->entityManager;
}
/**
* #return \Doctrine\ORM\EntityManager
*/
public function getEntityManager(){
return $this->entityManager;
}
public function updateDatabaseSchema(){
$metaData = array();
$usedEntities = array(
'Test\Stackoverflow\User'
);
foreach($usedEntities as $entity){
$metaData[] = $this->entityManager->getClassMetadata($entity);
}
$tool = new \Doctrine\ORM\Tools\SchemaTool($this->entityManager);
$tool->updateSchema($metaData);
$this->generateProxies($metaData);
}
/**
* Generate all the proxy classes for orm in the correct directory.
* Proxy dir can be configured over application configuration
*
*
* #throws \Exception
*/
final public function generateProxies($metaData)
{
$em = $this->getEntityManager();
$destPath = $em->getConfiguration()->getProxyDir();
if (!is_dir($destPath)) {
mkdir($destPath, 0777, true);
}
$destPath = realpath($destPath);
if (!file_exists($destPath)) {
throw new \Exception("Proxy destination directory could not be created " . $em->getConfiguration()->getProxyDir());
}
if (!is_writable($destPath)) {
throw new \Exception(
sprintf("Proxies destination directory '<info>%s</info>' does not have write permissions.", $destPath)
);
}
if (count($metaData)) {
// Generating Proxies
$em->getProxyFactory()->generateProxyClasses($metaData, $destPath);
}
}
/**
* #var \Symfony\Component\Validator\Validator\ValidatorInterface
*/
protected $validator;
/**
* #return \Symfony\Component\Validator\Validator\ValidatorInterface
*/
final protected function getValidator(){
if($this->validator){
return $this->validator;
}
$this->validator = \Symfony\Component\Validator\Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
return $this->validator;
}
/**
* #param \Test\Stackoverflow\User $entity
* #return bool
*/
final public function testAnnotationWithoutLoading(\Test\Stackoverflow\User $entity){
try {
print "test to validate the entity without preloading the Assert classes\n<br>";
$this->getValidator()->validate($entity);
return true;
} catch(\Exception $e){
print "<strong>Does not work since the Asserts classes never get loaded: </strong> Exception-message: ".$e->getMessage()."\n<br>";
return false;
}
}
/**
* #param \Test\Stackoverflow\User $entity
* #return bool
*/
final public function testAnnotationWithLoading(\Test\Stackoverflow\User $entity){
// Here we force the autoloader to require the class
$notBlankValidator = new \Symfony\Component\Validator\Constraints\NotBlank();
try {
print "Loaded the validator manually, will test of it fails now\n<br>";
$this->getValidator()->validate($entity);
return true;
} catch(\Exception $e){
print "<strong>Was not working: </strong> Exception-message: ".$e->getMessage()."\n<br>";
print sprintf("<strong>Even when we autoload the class it is not working. Type of assert: %s</strong>\n<br>", get_class($notBlankValidator));
return false;
}
}
}
If you are using the Symfony Standard Edition, you must update your
autoload.php file by adding the following code [1]
How are these annotations loaded? From looking at the code you could
guess that the ORM Mapping, Assert Validation and the fully qualified
annotation can just be loaded using the defined PHP autoloaders. This
is not the case however: For error handling reasons every check for
class existence inside the AnnotationReader sets the second parameter
$autoload of class_exists($name, $autoload) to false. To work
flawlessly the AnnotationReader requires silent autoloaders which many
autoloaders are not. Silent autoloading is NOT part of the PSR-0
specification for autoloading. [2]
// at the top of the file
use Doctrine\Common\Annotations\AnnotationRegistry;
// at the end of the file
AnnotationRegistry::registerLoader(function($class) use ($loader) {
$loader->loadClass($class);
return class_exists($class, false);
});
[1] https://symfony.com/blog/symfony2-2-0-rc4-released
[2] https://www.doctrine-project.org/projects/doctrine-annotations/en/1.6/annotations.html

Upload multiple files for each entity

I am using doctrine2 with symfony2.
This is my entity to upload the file.
First, it call the setFile() and put the path to $this->temp,
then,preUpload is called ,upload called.
It is OK for uploading onefile for each entity,however, I would like to upload multiple files for each entity.
How can I handle this ?
Do you have any samples for this purpose?
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $path = "nophoto.jpeg";
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
// check if we have an old image path
if (is_file($this->getAbsolutePath())) {
// store the old name to delete after the update
$this->temp = $this->getAbsolutePath();
} else {
$this->path = 'initial';
}
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
$this->path = $this->getId().'.'.$this->getFile()->guessExtension();
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile1()) {return;}
if (isset($this->temp)) {
// delete the old image
unlink($this->temp);
// clear the temp image path
$this->temp = null;
}
// you must throw an exception here if the file cannot be moved
// so that the entity is not persisted to the database
// which the UploadedFile move() method does
$this->getFile()->move(
$this->getUploadRootDir(),
$this->getId().'.'.$this->getFile()->guessExtension()
);
$this->setFile(null);
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir().'/'.$this->getId().'.'.$this->path;
}
public function getFile1()
{
return $this->file;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/documents';
}
You need new entity which will represent uploaded file with many-to-one (or many-to-many) association to your entity. This is most universal approach.
Alternatively you can store file names in array but that will complicate your validation and forms.

Symfony2: do not update a form field if not provided

I have a form for my "Team" entity. This entity has an "image" field. This field is required on creation process, but not required on edit process. But right now, during edit process, if I don't provide any image in the file input, the empty input is still persisted, and so my database field is emptied during the process.
How can I do to avoid persistence of this field, if nothing is provided in the form file input? So the entity keeps its old value for this field. Of course, if a file is provided, I want him to erase the old one.
My controller looks like this:
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em->persist($team);
$em->flush();
...
}
}
and part of my entity, dealing with image (I'm pretty sure I have to do something in here, but don't know what exactly):
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function uploadImage() {
// the file property can be empty if the field is not required
if (null === $this->image) {
return;
}
if(!$this->id){
$this->image->move($this->getTmpUploadRootDir(), $this->image->getClientOriginalName());
}else{
$this->image->move($this->getUploadRootDir(), $this->image->getClientOriginalName());
}
$this->setImage($this->image->getClientOriginalName());
}
EDIT
Ok, I did some changes to this answer's code code, because apparently the event listener asks for a FormEvent instance in his callback, not a FormInterface instance.
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
// Retrieve submitted data
$form = $event->getForm();
$item = $event->getData();
// Test if upload image is null (maybe adapt it to work with your code)
if (null !== $form->get('image')->getData()) {
var_dump($form->get('image')->getData());
die('image provided');
$item->setImage($form->get('image')->getData());
}
});
When I provide an image, the script goes into the test, and die(), as expected. When I do not provide any file, the script doesn't go into the test if(), but my field in the database is still erased with an empty value. Any idea?
And as asked below, here is the Form
// src/Van/TeamsBundle/Form/TeamEditType.php
namespace Van\TeamsBundle\Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class TeamEditType extends TeamType // Ici, on hérite de ArticleType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// On fait appel à la méthode buildForm du parent, qui va ajouter tous les champs à $builder
parent::buildForm($builder, $options);
// On supprime celui qu'on ne veut pas dans le formulaire de modification
$builder->remove('image')
->add('image', 'file', array(
'data_class' => null,
'required' => false
))
;
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
// Retrieve submitted data
$form = $event->getForm();
$item = $event->getData();
// Test if upload image is null (maybe adapt it to work with your code)
if (null !== $form->get('image')->getData()) {
var_dump($form->get('image')->getData());
die('image provided');
$item->setImage($form->get('image')->getData());
}
});
}
// On modifie cette méthode car les deux formulaires doivent avoir un nom différent
public function getName()
{
return 'van_teamsbundle_teamedittype';
}
}
and the whole Team entity:
<?php
namespace Van\TeamsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Team
*
* #ORM\Table()
* #ORM\HasLifecycleCallbacks
* #ORM\Entity
* #ORM\Entity(repositoryClass="Van\TeamsBundle\Entity\TeamRepository") #ORM\Table(name="van_teams")
*/
class Team
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="countryCode", type="string", length=2)
*/
private $countryCode;
/**
* #ORM\ManyToOne(targetEntity="Van\TeamsBundle\Entity\Game")
* #ORM\JoinColumn(nullable=false)
*/
private $game;
/**
* #ORM\ManyToOne(targetEntity="Van\TeamsBundle\Entity\Statut")
* #ORM\JoinColumn(nullable=false)
*/
private $statut;
/**
* #var string $image
* #Assert\File( maxSize = "1024k", mimeTypesMessage = "Please upload a valid Image")
* #ORM\Column(name="image", type="string", length=255)
*/
private $image;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Team
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set countryCode
*
* #param string $countryCode
* #return Team
*/
public function setCountryCode($countryCode)
{
$this->countryCode = $countryCode;
return $this;
}
/**
* Get countryCode
*
* #return string
*/
public function getCountryCode()
{
return $this->countryCode;
}
/**
* Set image
*
* #param string $image
* #return Team
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return string
*/
public function getImage()
{
return $this->image;
}
/**
* Set game
*
* #param \Van\TeamsBundle\Entity\Game $game
* #return Team
*/
public function setGame(\Van\TeamsBundle\Entity\Game $game)
{
$this->game = $game;
return $this;
}
/**
* Get game
*
* #return \Van\TeamsBundle\Entity\Game
*/
public function getGame()
{
return $this->game;
}
/**
* Set statut
*
* #param \Van\TeamsBundle\Entity\Statut $statut
* #return Team
*/
public function setStatut(\Van\TeamsBundle\Entity\Statut $statut)
{
$this->statut = $statut;
return $this;
}
/**
* Get statut
*
* #return \Van\TeamsBundle\Entity\Statut
*/
public function getStatut()
{
return $this->statut;
}
public function getFullImagePath() {
return null === $this->image ? null : $this->getUploadRootDir(). $this->image;
}
protected function getUploadRootDir() {
// the absolute directory path where uploaded documents should be saved
// return $this->getTmpUploadRootDir();
return __DIR__ . '/../../../../web/uploads/';
}
protected function getTmpUploadRootDir() {
// the absolute directory path where uploaded documents should be saved
return __DIR__ . '/../../../../web/uploads_tmp/';
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function uploadImage() {
// the file property can be empty if the field is not required
if (null === $this->image) {
return;
}
if(!$this->id){
$this->image->move($this->getTmpUploadRootDir(), $this->image->getClientOriginalName());
}else{
$this->image->move($this->getUploadRootDir(), $this->image->getClientOriginalName());
}
$this->setImage($this->image->getClientOriginalName());
}
/**
* #ORM\PostPersist()
*/
public function moveImage()
{
if (null === $this->image) {
return;
}
if(!is_dir($this->getUploadRootDir())){
mkdir($this->getUploadRootDir());
}
copy($this->getTmpUploadRootDir().$this->image, $this->getFullImagePath());
unlink($this->getTmpUploadRootDir().$this->image);
}
/**
* #ORM\PreRemove()
*/
public function removeImage()
{
unlink($this->getFullImagePath());
rmdir($this->getUploadRootDir());
}
}
EDIT 2
I did that. When I provide an image, it is saved in the image field in the database and redirection to my index page occurs. When I don't provide any image, redirection doesn't occur, and the following message appears above my file input in my form: "The file could not be found." In my TeamEditType class, I did the following, so the image should not be required.
$builder->remove('image')
->add('image', 'file', array(
'data_class' => null,
'required' => false
))
;
As of Symfony 2.3, you can simply use the PATCH http method, as documented here.
$form = $this->createForm(FooType::class, $foo, array(
'action' => $this->generateUrl('foo_update', array('id' => $foo->getId())),
'method' => 'PATCH',
));
It's an easy way to make a partial update of an entity using your main form, without rendering all the fields.
One approach in Symfony 2.4 (further information in Symfony2 coockbook) :
public function buildForm(FormBuilderInterface $builder, array $options)
{
// $builder->add() ...
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormInterface $form) {
// Retrieve submitted data
$form = $event->getForm();
$image = $form->getData();
// Test if upload image is null (maybe adapt it to work with your code)
if (null !== $form->get('uploadImage')->getData()) {
$image->setUploadImage($form->get('uploadImage')->getData());
}
});
}
Edit
It seems that you already test your prepersit data. Try the following :
public function setImage($image)
{
if($image !== null) {
$this->image = $image;
return $this;
}
}
I'm using symfony 3.3 and faced the same issue, below is the solution how I overcome it.
You need to create a extra property for image uploading in your entity other than image property, something like $file;
Product.php
/**
* #var string
*
* #ORM\Column(name="image", type="string")
*
*/
private $image;
/**
*
* #Assert\File(mimeTypes={ "image/jpeg", "image/jpg", "image/png" })
*/
private $file;
public function setFile($file)
{
$this->file = $file;
return $this;
}
public function getFile()
{
return $this->file;
}
// other code i.e image setter getter
...
ProductType.php
$builder->add('file', FileType::class, array(
'data_class' => null,
'required'=>false,
'label' => 'Upload Image (jpg, jpeg, png file)')
);
Form.html.twig
<div class="form-group">
{{ form_label(form.file) }}
{{ form_widget(form.file, {'attr': {'class': 'form-control'}}) }}
</div>
Finally ProductController.php
...
if ($form->isSubmitted() && $form->isValid()) {
$file = $item->getFile();
if($file instanceof UploadedFile) {
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move(
$this->getParameter('upload_directory'),
$fileName
);
$item->setImage($fileName);
}
...
}
...
Little more about upload_directory
app/config/config.html
parameters:
upload_directory: '%kernel.project_dir%/web/uploads'
Create a uploads directory in web dir.
I resolved this issue by using PHP Reflection API. My approach was to browse the attributes of the entity class and replace the values not provided in the query with those already saved.
/**
* #param \ReflectionClass $reflectionClass
* #param $entity
* #param Request $request
* #return Request
*/
public function formatRequest($class, $entity, Request $request){
$reflectionClass = new \ReflectionClass('AppBundle\Entity\\'.$class);
foreach ($reflectionClass->getProperties() as $attribut)
{
$attribut->setAccessible(true); // to avoid fatal error when trying to access a non-public attribute
if($request->request->get($attribut->getName()) == null) { // if the attribute value is not provided in the request
$request->request->set($attribut->getName(), $attribut->getValue($entity));
}
}
return $request;
}
And then I use it like this :
$request = $this->formatRequest("EntityName", $entity, $request);
This is really generic.

How to edit the upload file field while updating the value in sonata admin bundle?

while i upload the file from sonata admin bundle the file is uploaded but while i edit the file the file field also ask for the upload the new file.. please help me for the edit option for the file upload.
class Adds {
use Symfony\Component\Config\Definition\IntegerNode;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
const SERVER_PATH_TO_IMAGE_FOLDER = 'uploads/';
..........
/**
* #var string
*
* #ORM\Column(name="file", type="string", length=255)
* #Assert\File(maxSize="5000000")
*/
private $file;
public function getFile() {
return $this->file;
}
public function setFile($file) {
$this->file = $file;
}
,............
public function upload() {
if (null === $this->getFile()) {
return;
}
$this->getFile()->move(
self::SERVER_PATH_TO_IMAGE_FOLDER, $this->getFile()->getClientOriginalName());
$this->filename = $this->getFile()->getClientOriginalName();
$this->setFile(null);
}
/**
* 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($file) {
if (null === $file->getFile()) {
return;
}
$file->getFile()->move(
self::SERVER_PATH_TO_IMAGE_FOLDER, date('YmdHis') . $file->getFile()->getClientOriginalName());
$file->filename = $file->getFile()->getClientOriginalName();
$file->filename = date('YmdHis') . $file->filename;
$this->setFile($file->filename);
}
?>
And the adAdmin file is
<?php
...............
................
class AddsAdmin extends Admin {
............
protected function configureFormFields(FormMapper $formMapper) {
$formMapper->add('file', 'file', array('label' => 'File :', 'data_class' => null))
->end();
}
public function prePersist($ad) {
$this->manageFileUpload($ad);
if ($this->userLevel == Organization::LEVEL_CLIENT) {
$user = $this->securityContext->getToken()->getUser();
$ad->setOrganization($user->getOrganization());
}
}
public function preUpdate($ad) {
$this->manageFileUpload($ad);
}
private function manageFileUpload($ad) {
if ($ad->getFile()) {
$ad->refreshUpdated($ad);
}
}
Just check the type of field;
SO for preUpdate/prePersist call your handle:
public function preUpdate($object)
{
$this->handleUploads($object);
}
public function prePersist($object)
{
$this->handleUploads($object);
}
and in handle just check:
if ($file->getFile() instanceof UploadedFile && $file->getFile()->isValid()) {
$targetFilename = md5(rand() . time()) . '.' . $file->getFile()->getClientOriginalExtension();
$file->getFile()->move($uploadDirectory, $targetFilename);
$file->setFile('uploads/' . $targetFilename);
}

how to get the uploded filenames of a form in the controller

i used the following code in the controller inorder to get the filenames of the uploaded files
My controller is
class uploadController extends Controller
{
public function uploadAction(Request $request)
{
$id= $_GET['id'];
$user = new attachments();
$form = $this->createFormBuilder($user)->add('files','file',array("data_class" => null,"attr"=>array("multiple" =>"multiple",)))->getForm();
$formView = $form->createView();
$formView->getChild('files')->set('full_name','files[]');
if ($request->getMethod() == 'POST')
{
$em = $this->getDoctrine()->getManager();
$data = $form["files"]->getData();
}
}
when i print the $data it is not giving the filenames of uploaded files it is returning the null values
my entity is:
use Symfony\Component\HttpFoundation\File\UploadedFile;
class attachments
{
private $id;
/**
* #var integer
* #ORM\Column(name="user", type="integer", nullable=false)
* #ORM\ManyToOne(targetEntity="users", inversedBy="annotations")
*/
protected $userId;
/**
* #var string
*
* #Assert\File(maxSize="6000000")
* #ORM\Column(name="files", type="array", length=255, nullable=true)
*/
public $files=array();
public function __construct()
{
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set userId
*
* #param integer $userId
* #return attachments
*/
public function setUserId($userId)
{
$this->userId = $userId;
return $this;
}
/**
* Set files
* #param object $files
*
* #return attachments
*/
public function setFiles($files)
{
$this->files = $files;
}
/**
* Get files
*
* #return object
*/
public function getFiles()
{
return $this->files;
}
public function uploadFiles()
{
// the files property can be empty if the field is not required
if (null === $this->files)
{
return;
}
else
{
$this->files->move($this->getUploadRootDir(), $this->files->getClientOriginalName());
}
$this->setFiles($this->files->getClientOriginalName());
}
/**
* Get userId
*
* #return integer
*/
public function getUserId()
{
return $this->userId;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir() . DIRECTORY_SEPARATOR . $this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir() . DIRECTORY_SEPARATOR . $this->path;
}
protected function getUploadRootDir()
{
return __DIR__ . '/../../../../web/'. $this->getUploadDir();
}
protected function getUploadDir()
{
return 'uploads/';
}
}
Uploaded Files in Symfony2 are of type Symfony/Component/HttpFoundation/File/UploadedFile.
You can get the original client name ( php will rename files when putting them into php_upload_tmp_dir ) with:
$file->getClientOriginalName();
... move the file to a new location with:
$file->move('path/to/your_file', 'new_name.jpg');
You can not use the assert File Constraint for an array.
* #Assert\File(maxSize="6000000")
*/
protected $files = array();
Therefore you need the All constraint.
Furthermore you can't just call the move method on an array or collection... you will have to loop over the collection/array.
$this->files->move('..') // this is never going to work...
Use an array collection and create a property for your uploaded files if thats what you want.
protected $files;
protected $uploadedFiles;
public function __construct()
{
$this->files = new ArrayCollection;
$this->uploadedFiles = new Array();
}
If you want to transform your Doctrine Collection of UploadedFile entities into an Array do the following:
$collection = $entity->getFiles();
$array = $collection->toArray();
But whatever you're trying to do ... better use OOP instead of arrays like you're attempting here.

Resources